arel 8.0.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d63929355e39f8b80a24e91781752eb2b152ff56
4
- data.tar.gz: 5c67efb970c72f38f5d43619c52492f77af5f107
3
+ metadata.gz: dc3719172683caa3fb2bd15ce6ef3ed477a8b2ef
4
+ data.tar.gz: 74b4f1d7d44871db56c62907ed1c4ba51040bf6e
5
5
  SHA512:
6
- metadata.gz: 690294ba02d8416fa6204ec94a2a35d822aa3533d7767e5477da68572ca233cda12eae57eb6d1b4d619afc08e0ff29fc4f09b93a79fae8b83d4778cb351fbc3e
7
- data.tar.gz: 6bb11f371d17dfc7ffb400e98b49ddad92b80f7095d8e4ff7e72a9c8555c0335f3da6ae08df96cc3641cd8784ea2fea11daaf5fc4b1c860df43eb011023ef18f
6
+ metadata.gz: bedb8b1701ee99fca067c4a52f92d096648d25d67d4809408ede3eeb40298b3fc83a9fdccf1f4195c32f871ee430eba29f11dedd19b12032639a8b03bc7ec54c
7
+ data.tar.gz: 97a3b3155db8b0c57ca4616598d45d8aad7592c56a6882e0e7f5369eeac221802cae5cd60b4d72a92d755eb13be4b39aedc9ea967e1c6faac28953a3414d1f39
@@ -1,3 +1,9 @@
1
+ === 9.0.0 / 2017-11-14
2
+
3
+ * Enhancements
4
+ * `InsertManager#insert` is now chainable
5
+ * Support multiple inserts
6
+
1
7
  === 8.0.0 / 2017-02-21
2
8
 
3
9
  * Enhancements
data/README.md CHANGED
@@ -150,7 +150,14 @@ The `OR` operator works like this:
150
150
  users.where(users[:name].eq('bob').or(users[:age].lt(25)))
151
151
  ```
152
152
 
153
- The `AND` operator behaves similarly.
153
+ The `AND` operator behaves similarly. Here is an example of the `DISTINCT` operator:
154
+
155
+ ```ruby
156
+ posts = Arel::Table.new(:posts)
157
+ posts.project(posts[:title])
158
+ posts.distinct
159
+ posts.to_sql # => 'SELECT DISTINCT "posts"."title" FROM "posts"'
160
+ ```
154
161
 
155
162
  Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`:
156
163
 
@@ -181,7 +188,7 @@ users.project(users[:age].average.as("mean_age"))
181
188
  # => SELECT AVG(users.age) AS mean_age FROM users
182
189
  ```
183
190
 
184
- ### The Crazy Features
191
+ ### The Advanced Features
185
192
 
186
193
  The examples above are fairly simple and other libraries match or come close to matching the expressiveness of Arel (e.g. `Sequel` in Ruby).
187
194
 
@@ -208,6 +215,7 @@ products.
208
215
 
209
216
  #### Complex Joins
210
217
 
218
+ ##### Alias
211
219
  Where Arel really shines is in its ability to handle complex joins and aggregations. As a first example, let's consider an "adjacency list", a tree represented in a table. Suppose we have a table `comments`, representing a threaded discussion:
212
220
 
213
221
  ```ruby
@@ -233,6 +241,7 @@ comments_with_replies = \
233
241
 
234
242
  This will return the reply for the first comment.
235
243
 
244
+ ##### CTE
236
245
  [Common Table Expressions (CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via:
237
246
 
238
247
  Create a `CTE`
@@ -255,6 +264,7 @@ users.
255
264
  # FROM users INNER JOIN cte_table ON users.id = cte_table.user_id
256
265
  ```
257
266
 
267
+ #### Write SQL strings
258
268
  When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`:
259
269
 
260
270
  ```ruby
@@ -24,7 +24,7 @@ require 'arel/delete_manager'
24
24
  require 'arel/nodes'
25
25
 
26
26
  module Arel
27
- VERSION = '8.0.0'
27
+ VERSION = '9.0.0'
28
28
 
29
29
  def self.sql raw_sql
30
30
  Arel::Nodes::SqlLiteral.new raw_sql
@@ -1,36 +1,23 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Arel
3
4
  module Collectors
4
5
  class Bind
5
6
  def initialize
6
- @parts = []
7
+ @binds = []
7
8
  end
8
9
 
9
10
  def << str
10
- @parts << str
11
11
  self
12
12
  end
13
13
 
14
14
  def add_bind bind
15
- @parts << bind
15
+ @binds << bind
16
16
  self
17
17
  end
18
18
 
19
- def value; @parts; end
20
-
21
- def substitute_binds bvs
22
- bvs = bvs.dup
23
- @parts.map do |val|
24
- if Arel::Nodes::BindParam === val
25
- bvs.shift
26
- else
27
- val
28
- end
29
- end
30
- end
31
-
32
- def compile bvs
33
- substitute_binds(bvs).join
19
+ def value
20
+ @binds
34
21
  end
35
22
  end
36
23
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel
4
+ module Collectors
5
+ class Composite
6
+ def initialize(left, right)
7
+ @left = left
8
+ @right = right
9
+ end
10
+
11
+ def << str
12
+ left << str
13
+ right << str
14
+ self
15
+ end
16
+
17
+ def add_bind bind, &block
18
+ left.add_bind bind, &block
19
+ right.add_bind bind, &block
20
+ self
21
+ end
22
+
23
+ def value
24
+ [left.value, right.value]
25
+ end
26
+
27
+ protected
28
+
29
+ attr_reader :left, :right
30
+ end
31
+ end
32
+ end
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require 'arel/collectors/plain_string'
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ module Arel
3
+ module Collectors
4
+ class SubstituteBinds
5
+ def initialize(quoter, delegate_collector)
6
+ @quoter = quoter
7
+ @delegate = delegate_collector
8
+ end
9
+
10
+ def << str
11
+ delegate << str
12
+ self
13
+ end
14
+
15
+ def add_bind bind
16
+ self << quoter.quote(bind)
17
+ end
18
+
19
+ def value
20
+ delegate.value
21
+ end
22
+
23
+ protected
24
+
25
+ attr_reader :quoter, :delegate
26
+ end
27
+ end
28
+ end
@@ -34,10 +34,15 @@ module Arel
34
34
  end
35
35
  @ast.values = create_values values, @ast.columns
36
36
  end
37
+ self
37
38
  end
38
39
 
39
40
  def create_values values, columns
40
41
  Nodes::Values.new values, columns
41
42
  end
43
+
44
+ def create_values_list(rows)
45
+ Nodes::ValuesList.new(rows)
46
+ end
42
47
  end
43
48
  end
@@ -44,6 +44,7 @@ require 'arel/nodes/function'
44
44
  require 'arel/nodes/count'
45
45
  require 'arel/nodes/extract'
46
46
  require 'arel/nodes/values'
47
+ require 'arel/nodes/values_list'
47
48
  require 'arel/nodes/named_function'
48
49
 
49
50
  # windows
@@ -2,8 +2,25 @@
2
2
  module Arel
3
3
  module Nodes
4
4
  class BindParam < Node
5
- def ==(other)
6
- other.is_a?(BindParam)
5
+ attr_accessor :value
6
+
7
+ def initialize(value)
8
+ @value = value
9
+ super()
10
+ end
11
+
12
+ def hash
13
+ [self.class, self.value].hash
14
+ end
15
+
16
+ def eql?(other)
17
+ other.is_a?(BindParam) &&
18
+ value == other.value
19
+ end
20
+ alias :== :eql?
21
+
22
+ def nil?
23
+ value.nil?
7
24
  end
8
25
  end
9
26
  end
@@ -30,7 +30,7 @@ module Arel
30
30
 
31
31
  def self.build_quoted other, attribute = nil
32
32
  case other
33
- when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted
33
+ when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted, Arel::Nodes::SqlLiteral
34
34
  other
35
35
  else
36
36
  case attribute
@@ -2,6 +2,8 @@
2
2
  module Arel
3
3
  module Nodes
4
4
  class Count < Arel::Nodes::Function
5
+ include Math
6
+
5
7
  def initialize expr, distinct = false, aliaz = nil
6
8
  super(expr, aliaz)
7
9
  @distinct = distinct
@@ -9,6 +9,7 @@ module Arel
9
9
  def eql? other
10
10
  self.class == other.class
11
11
  end
12
+ alias :== :eql?
12
13
  end
13
14
  end
14
15
  end
@@ -29,6 +29,8 @@ module Arel
29
29
  self.alias == other.alias &&
30
30
  self.distinct == other.distinct
31
31
  end
32
+ alias :== :eql?
33
+
32
34
  end
33
35
 
34
36
  %w{
@@ -9,6 +9,7 @@ module Arel
9
9
  def eql? other
10
10
  self.class == other.class
11
11
  end
12
+ alias :== :eql?
12
13
  end
13
14
  end
14
15
  end
@@ -9,6 +9,7 @@ module Arel
9
9
  def eql? other
10
10
  self.class == other.class
11
11
  end
12
+ alias :== :eql?
12
13
  end
13
14
  end
14
15
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ module Arel
3
+ module Nodes
4
+ class ValuesList < Node
5
+ attr_reader :rows
6
+
7
+ def initialize(rows)
8
+ @rows = rows
9
+ super()
10
+ end
11
+
12
+ def hash
13
+ @rows.hash
14
+ end
15
+
16
+ def eql? other
17
+ self.class == other.class &&
18
+ self.rows == other.rows
19
+ end
20
+ alias :== :eql?
21
+ end
22
+ end
23
+ end
@@ -107,6 +107,7 @@ module Arel
107
107
  def eql? other
108
108
  self.class == other.class
109
109
  end
110
+ alias :== :eql?
110
111
  end
111
112
 
112
113
  class Preceding < Unary
@@ -5,13 +5,10 @@ module Arel
5
5
  class TreeManager
6
6
  include Arel::FactoryMethods
7
7
 
8
- attr_reader :ast, :engine
9
-
10
- attr_accessor :bind_values
8
+ attr_reader :ast
11
9
 
12
10
  def initialize
13
- @ctx = nil
14
- @bind_values = []
11
+ @ctx = nil
15
12
  end
16
13
 
17
14
  def to_dot
@@ -18,9 +18,7 @@ module Arel
18
18
  end
19
19
  def visit_Arel_Nodes_SelectCore o, collector
20
20
  collector = inject_join o.projections, collector, ", "
21
- froms = false
22
21
  if o.source && !o.source.empty?
23
- froms = true
24
22
  collector << " FROM "
25
23
  collector = visit o.source, collector
26
24
  end
@@ -29,12 +29,12 @@ module Arel
29
29
  collector = super(o, collector)
30
30
 
31
31
  if offset.expr.is_a? Nodes::BindParam
32
- offset_bind = nil
33
32
  collector << ') raw_sql_ WHERE rownum <= ('
34
- collector.add_bind(offset.expr) { |i| offset_bind = ":a#{i}" }
33
+ collector = visit offset.expr, collector
35
34
  collector << ' + '
36
- collector.add_bind(limit) { |i| ":a#{i}" }
37
- collector << ") ) WHERE raw_rnum_ > #{offset_bind}"
35
+ collector = visit limit, collector
36
+ collector << ") ) WHERE raw_rnum_ > "
37
+ collector = visit offset.expr, collector
38
38
  return collector
39
39
  else
40
40
  collector << ") raw_sql_
@@ -145,7 +145,7 @@ module Arel
145
145
  end
146
146
 
147
147
  def visit_Arel_Nodes_BindParam o, collector
148
- collector.add_bind(o) { |i| ":a#{i}" }
148
+ collector.add_bind(o.value) { |i| ":a#{i}" }
149
149
  end
150
150
 
151
151
  end
@@ -53,7 +53,7 @@ module Arel
53
53
  end
54
54
 
55
55
  def visit_Arel_Nodes_BindParam o, collector
56
- collector.add_bind(o) { |i| ":a#{i}" }
56
+ collector.add_bind(o.value) { |i| ":a#{i}" }
57
57
  end
58
58
  end
59
59
  end
@@ -46,7 +46,7 @@ module Arel
46
46
  end
47
47
 
48
48
  def visit_Arel_Nodes_BindParam o, collector
49
- collector.add_bind(o) { |i| "$#{i}" }
49
+ collector.add_bind(o.value) { |i| "$#{i}" }
50
50
  end
51
51
 
52
52
  def visit_Arel_Nodes_GroupingElement o, collector
@@ -11,9 +11,10 @@ module Arel
11
11
  private
12
12
 
13
13
  def visit object, collector
14
- send dispatch[object.class], object, collector
14
+ dispatch_method = dispatch[object.class]
15
+ send dispatch_method, object, collector
15
16
  rescue NoMethodError => e
16
- raise e if respond_to?(dispatch[object.class], true)
17
+ raise e if respond_to?(dispatch_method, true)
17
18
  superklass = object.class.ancestors.find { |klass|
18
19
  respond_to?(dispatch[klass], true)
19
20
  }
@@ -166,6 +166,28 @@ module Arel
166
166
  collector << "FALSE"
167
167
  end
168
168
 
169
+ def visit_Arel_Nodes_ValuesList o, collector
170
+ collector << "VALUES "
171
+
172
+ len = o.rows.length - 1
173
+ o.rows.each_with_index { |row, i|
174
+ collector << '('
175
+ row_len = row.length - 1
176
+ row.each_with_index do |value, k|
177
+ case value
178
+ when Nodes::SqlLiteral, Nodes::BindParam
179
+ collector = visit(value, collector)
180
+ else
181
+ collector << quote(value)
182
+ end
183
+ collector << COMMA unless k == row_len
184
+ end
185
+ collector << ')'
186
+ collector << COMMA unless i == len
187
+ }
188
+ collector
189
+ end
190
+
169
191
  def visit_Arel_Nodes_Values o, collector
170
192
  collector << "VALUES ("
171
193
 
@@ -405,7 +427,8 @@ module Arel
405
427
  end
406
428
 
407
429
  def visit_Arel_SelectManager o, collector
408
- collector << "(#{o.to_sql.rstrip})"
430
+ collector << '('
431
+ visit(o.ast, collector) << ')'
409
432
  end
410
433
 
411
434
  def visit_Arel_Nodes_Ascending o, collector
@@ -715,7 +738,7 @@ module Arel
715
738
  def literal o, collector; collector << o.to_s; end
716
739
 
717
740
  def visit_Arel_Nodes_BindParam o, collector
718
- collector.add_bind(o) { "?" }
741
+ collector.add_bind(o.value) { "?" }
719
742
  end
720
743
 
721
744
  alias :visit_Arel_Nodes_SqlLiteral :literal
@@ -27,9 +27,10 @@ module Arel
27
27
  end
28
28
 
29
29
  def visit object
30
- send dispatch[object.class], object
30
+ dispatch_method = dispatch[object.class]
31
+ send dispatch_method, object
31
32
  rescue NoMethodError => e
32
- raise e if respond_to?(dispatch[object.class], true)
33
+ raise e if respond_to?(dispatch_method, true)
33
34
  superklass = object.class.ancestors.find { |klass|
34
35
  respond_to?(dispatch[klass], true)
35
36
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arel
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.0
4
+ version: 9.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Patterson
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-02-21 00:00:00.000000000 Z
14
+ date: 2017-11-14 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: minitest
@@ -55,6 +55,20 @@ dependencies:
55
55
  - - ">="
56
56
  - !ruby/object:Gem::Version
57
57
  version: '0'
58
+ - !ruby/object:Gem::Dependency
59
+ name: concurrent-ruby
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - "~>"
63
+ - !ruby/object:Gem::Version
64
+ version: '1.0'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '1.0'
58
72
  description: |-
59
73
  Arel Really Exasperates Logicians
60
74
 
@@ -85,8 +99,10 @@ files:
85
99
  - lib/arel/attributes.rb
86
100
  - lib/arel/attributes/attribute.rb
87
101
  - lib/arel/collectors/bind.rb
102
+ - lib/arel/collectors/composite.rb
88
103
  - lib/arel/collectors/plain_string.rb
89
104
  - lib/arel/collectors/sql_string.rb
105
+ - lib/arel/collectors/substitute_binds.rb
90
106
  - lib/arel/compatibility/wheres.rb
91
107
  - lib/arel/crud.rb
92
108
  - lib/arel/delete_manager.rb
@@ -135,6 +151,7 @@ files:
135
151
  - lib/arel/nodes/unqualified_column.rb
136
152
  - lib/arel/nodes/update_statement.rb
137
153
  - lib/arel/nodes/values.rb
154
+ - lib/arel/nodes/values_list.rb
138
155
  - lib/arel/nodes/window.rb
139
156
  - lib/arel/nodes/with.rb
140
157
  - lib/arel/order_predications.rb
@@ -144,8 +161,6 @@ files:
144
161
  - lib/arel/tree_manager.rb
145
162
  - lib/arel/update_manager.rb
146
163
  - lib/arel/visitors.rb
147
- - lib/arel/visitors/bind_substitute.rb
148
- - lib/arel/visitors/bind_visitor.rb
149
164
  - lib/arel/visitors/depth_first.rb
150
165
  - lib/arel/visitors/dot.rb
151
166
  - lib/arel/visitors/ibm_db.rb
@@ -175,7 +190,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
175
190
  requirements:
176
191
  - - ">="
177
192
  - !ruby/object:Gem::Version
178
- version: '0'
193
+ version: 2.2.2
179
194
  required_rubygems_version: !ruby/object:Gem::Requirement
180
195
  requirements:
181
196
  - - ">="
@@ -183,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
198
  version: '0'
184
199
  requirements: []
185
200
  rubyforge_project:
186
- rubygems_version: 2.6.10
201
+ rubygems_version: 2.6.12
187
202
  signing_key:
188
203
  specification_version: 4
189
204
  summary: Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
- module Arel
3
- module Visitors
4
- class BindSubstitute
5
- def initialize delegate
6
- @delegate = delegate
7
- end
8
- end
9
- end
10
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
- module Arel
3
- module Visitors
4
- module BindVisitor
5
- def initialize target
6
- @block = nil
7
- super
8
- end
9
-
10
- def accept node, collector, &block
11
- @block = block if block_given?
12
- super
13
- end
14
-
15
- private
16
-
17
- def visit_Arel_Nodes_Assignment o, collector
18
- if o.right.is_a? Arel::Nodes::BindParam
19
- collector = visit o.left, collector
20
- collector << " = "
21
- visit o.right, collector
22
- else
23
- super
24
- end
25
- end
26
-
27
- def visit_Arel_Nodes_BindParam o, collector
28
- if @block
29
- val = @block.call
30
- if String === val
31
- collector << val
32
- end
33
- else
34
- super
35
- end
36
- end
37
-
38
- end
39
- end
40
- end