arel 8.0.0 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
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