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 +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
|