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 +4 -4
- data/History.txt +6 -0
- data/README.md +12 -2
- data/lib/arel.rb +1 -1
- data/lib/arel/collectors/bind.rb +5 -18
- data/lib/arel/collectors/composite.rb +32 -0
- data/lib/arel/collectors/sql_string.rb +0 -1
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/insert_manager.rb +5 -0
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/nodes/bind_param.rb +19 -2
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -0
- data/lib/arel/nodes/false.rb +1 -0
- data/lib/arel/nodes/function.rb +2 -0
- data/lib/arel/nodes/terminal.rb +1 -0
- data/lib/arel/nodes/true.rb +1 -0
- data/lib/arel/nodes/values_list.rb +23 -0
- data/lib/arel/nodes/window.rb +1 -0
- data/lib/arel/tree_manager.rb +2 -5
- data/lib/arel/visitors/informix.rb +0 -2
- data/lib/arel/visitors/oracle.rb +5 -5
- data/lib/arel/visitors/oracle12.rb +1 -1
- data/lib/arel/visitors/postgresql.rb +1 -1
- data/lib/arel/visitors/reduce.rb +3 -2
- data/lib/arel/visitors/to_sql.rb +25 -2
- data/lib/arel/visitors/visitor.rb +3 -2
- metadata +21 -6
- data/lib/arel/visitors/bind_substitute.rb +0 -10
- data/lib/arel/visitors/bind_visitor.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc3719172683caa3fb2bd15ce6ef3ed477a8b2ef
|
4
|
+
data.tar.gz: 74b4f1d7d44871db56c62907ed1c4ba51040bf6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bedb8b1701ee99fca067c4a52f92d096648d25d67d4809408ede3eeb40298b3fc83a9fdccf1f4195c32f871ee430eba29f11dedd19b12032639a8b03bc7ec54c
|
7
|
+
data.tar.gz: 97a3b3155db8b0c57ca4616598d45d8aad7592c56a6882e0e7f5369eeac221802cae5cd60b4d72a92d755eb13be4b39aedc9ea967e1c6faac28953a3414d1f39
|
data/History.txt
CHANGED
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
|
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
|
data/lib/arel.rb
CHANGED
data/lib/arel/collectors/bind.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
@
|
15
|
+
@binds << bind
|
16
16
|
self
|
17
17
|
end
|
18
18
|
|
19
|
-
def value
|
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
|
@@ -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
|
data/lib/arel/insert_manager.rb
CHANGED
@@ -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
|
data/lib/arel/nodes.rb
CHANGED
@@ -2,8 +2,25 @@
|
|
2
2
|
module Arel
|
3
3
|
module Nodes
|
4
4
|
class BindParam < Node
|
5
|
-
|
6
|
-
|
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
|
data/lib/arel/nodes/casted.rb
CHANGED
@@ -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
|
data/lib/arel/nodes/count.rb
CHANGED
data/lib/arel/nodes/false.rb
CHANGED
data/lib/arel/nodes/function.rb
CHANGED
data/lib/arel/nodes/terminal.rb
CHANGED
data/lib/arel/nodes/true.rb
CHANGED
@@ -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
|
data/lib/arel/nodes/window.rb
CHANGED
data/lib/arel/tree_manager.rb
CHANGED
@@ -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
|
data/lib/arel/visitors/oracle.rb
CHANGED
@@ -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
|
33
|
+
collector = visit offset.expr, collector
|
35
34
|
collector << ' + '
|
36
|
-
collector
|
37
|
-
collector << ") ) WHERE raw_rnum_ >
|
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
|
data/lib/arel/visitors/reduce.rb
CHANGED
@@ -11,9 +11,10 @@ module Arel
|
|
11
11
|
private
|
12
12
|
|
13
13
|
def visit object, collector
|
14
|
-
|
14
|
+
dispatch_method = dispatch[object.class]
|
15
|
+
send dispatch_method, object, collector
|
15
16
|
rescue NoMethodError => e
|
16
|
-
raise e if respond_to?(
|
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
|
}
|
data/lib/arel/visitors/to_sql.rb
CHANGED
@@ -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 <<
|
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
|
-
|
30
|
+
dispatch_method = dispatch[object.class]
|
31
|
+
send dispatch_method, object
|
31
32
|
rescue NoMethodError => e
|
32
|
-
raise e if respond_to?(
|
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:
|
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-
|
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:
|
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.
|
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,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
|