arel 2.0.10 → 2.1.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.
- data/History.txt +51 -4
- data/Manifest.txt +15 -31
- data/README.markdown +27 -3
- data/Rakefile +0 -2
- data/arel.gemspec +20 -19
- data/lib/arel.rb +9 -1
- data/lib/arel/alias_predication.rb +7 -0
- data/lib/arel/attributes/attribute.rb +10 -1
- data/lib/arel/crud.rb +43 -8
- data/lib/arel/expression.rb +1 -0
- data/lib/arel/factory_methods.rb +35 -0
- data/lib/arel/insert_manager.rb +5 -1
- data/lib/arel/math.rb +19 -0
- data/lib/arel/nodes.rb +32 -42
- data/lib/arel/nodes/and.rb +18 -1
- data/lib/arel/nodes/binary.rb +28 -0
- data/lib/arel/nodes/count.rb +0 -3
- data/lib/arel/nodes/function.rb +13 -2
- data/lib/arel/nodes/infix_operation.rb +43 -0
- data/lib/arel/nodes/join_source.rb +14 -0
- data/lib/arel/nodes/named_function.rb +14 -0
- data/lib/arel/nodes/node.rb +5 -2
- data/lib/arel/nodes/select_core.rb +24 -10
- data/lib/arel/nodes/select_statement.rb +8 -6
- data/lib/arel/nodes/sql_literal.rb +2 -0
- data/lib/arel/nodes/string_join.rb +2 -4
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/{as.rb → terminal.rb} +1 -1
- data/lib/arel/nodes/unary.rb +17 -0
- data/lib/arel/nodes/unqualified_column.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes/with.rb +10 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +6 -24
- data/lib/arel/select_manager.rb +95 -40
- data/lib/arel/table.rb +32 -19
- data/lib/arel/tree_manager.rb +1 -0
- data/lib/arel/update_manager.rb +4 -0
- data/lib/arel/visitors.rb +2 -0
- data/lib/arel/visitors/depth_first.rb +19 -9
- data/lib/arel/visitors/dot.rb +42 -25
- data/lib/arel/visitors/ibm_db.rb +12 -0
- data/lib/arel/visitors/join_sql.rb +2 -23
- data/lib/arel/visitors/mssql.rb +7 -0
- data/lib/arel/visitors/mysql.rb +4 -0
- data/lib/arel/visitors/oracle.rb +2 -2
- data/lib/arel/visitors/postgresql.rb +2 -38
- data/lib/arel/visitors/to_sql.rb +148 -67
- data/test/attributes/test_attribute.rb +3 -3
- data/test/helper.rb +1 -1
- data/test/nodes/test_as.rb +6 -0
- data/test/nodes/test_bin.rb +23 -0
- data/test/nodes/test_named_function.rb +30 -0
- data/test/nodes/test_node.rb +10 -0
- data/test/nodes/test_not.rb +4 -7
- data/test/nodes/test_select_core.rb +23 -14
- data/test/support/fake_record.rb +21 -4
- data/test/test_attributes.rb +8 -0
- data/test/test_crud.rb +6 -12
- data/test/test_factory_methods.rb +34 -0
- data/test/test_insert_manager.rb +19 -0
- data/test/test_select_manager.rb +343 -64
- data/test/test_table.rb +36 -45
- data/test/visitors/test_depth_first.rb +29 -11
- data/test/visitors/test_dot.rb +47 -0
- data/test/visitors/test_ibm_db.rb +27 -0
- data/test/visitors/test_join_sql.rb +14 -7
- data/test/visitors/test_mssql.rb +9 -0
- data/test/visitors/test_oracle.rb +11 -10
- data/test/visitors/test_postgres.rb +12 -0
- data/test/visitors/test_to_sql.rb +80 -17
- metadata +80 -101
- data/lib/arel/nodes/assignment.rb +0 -6
- data/lib/arel/nodes/avg.rb +0 -6
- data/lib/arel/nodes/between.rb +0 -6
- data/lib/arel/nodes/does_not_match.rb +0 -6
- data/lib/arel/nodes/except.rb +0 -7
- data/lib/arel/nodes/exists.rb +0 -7
- data/lib/arel/nodes/greater_than.rb +0 -6
- data/lib/arel/nodes/greater_than_or_equal.rb +0 -6
- data/lib/arel/nodes/group.rb +0 -6
- data/lib/arel/nodes/grouping.rb +0 -6
- data/lib/arel/nodes/having.rb +0 -6
- data/lib/arel/nodes/intersect.rb +0 -7
- data/lib/arel/nodes/join.rb +0 -13
- data/lib/arel/nodes/less_than.rb +0 -6
- data/lib/arel/nodes/less_than_or_equal.rb +0 -6
- data/lib/arel/nodes/limit.rb +0 -7
- data/lib/arel/nodes/lock.rb +0 -6
- data/lib/arel/nodes/matches.rb +0 -6
- data/lib/arel/nodes/max.rb +0 -6
- data/lib/arel/nodes/min.rb +0 -6
- data/lib/arel/nodes/not.rb +0 -6
- data/lib/arel/nodes/not_equal.rb +0 -6
- data/lib/arel/nodes/not_in.rb +0 -6
- data/lib/arel/nodes/offset.rb +0 -7
- data/lib/arel/nodes/on.rb +0 -6
- data/lib/arel/nodes/or.rb +0 -6
- data/lib/arel/nodes/sum.rb +0 -6
- data/lib/arel/nodes/top.rb +0 -6
- data/lib/arel/nodes/union.rb +0 -7
- data/lib/arel/nodes/union_all.rb +0 -7
data/lib/arel/nodes/unary.rb
CHANGED
@@ -2,10 +2,27 @@ module Arel
|
|
2
2
|
module Nodes
|
3
3
|
class Unary < Arel::Nodes::Node
|
4
4
|
attr_accessor :expr
|
5
|
+
alias :value :expr
|
5
6
|
|
6
7
|
def initialize expr
|
7
8
|
@expr = expr
|
8
9
|
end
|
9
10
|
end
|
11
|
+
|
12
|
+
%w{
|
13
|
+
Bin
|
14
|
+
Group
|
15
|
+
Grouping
|
16
|
+
Having
|
17
|
+
Limit
|
18
|
+
Not
|
19
|
+
Offset
|
20
|
+
On
|
21
|
+
Top
|
22
|
+
Lock
|
23
|
+
DistinctOn
|
24
|
+
}.each do |name|
|
25
|
+
const_set(name, Class.new(Unary))
|
26
|
+
end
|
10
27
|
end
|
11
28
|
end
|
@@ -2,13 +2,15 @@ module Arel
|
|
2
2
|
module Nodes
|
3
3
|
class UpdateStatement < Arel::Nodes::Node
|
4
4
|
attr_accessor :relation, :wheres, :values, :orders, :limit
|
5
|
+
attr_accessor :key
|
5
6
|
|
6
7
|
def initialize
|
7
8
|
@relation = nil
|
8
9
|
@wheres = []
|
9
10
|
@values = []
|
10
|
-
@orders
|
11
|
-
@limit
|
11
|
+
@orders = []
|
12
|
+
@limit = nil
|
13
|
+
@key = nil
|
12
14
|
end
|
13
15
|
|
14
16
|
def initialize_copy other
|
data/lib/arel/predications.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
module Arel
|
2
2
|
module Predications
|
3
|
-
def as other
|
4
|
-
Nodes::As.new self, other
|
5
|
-
end
|
6
3
|
|
7
4
|
def not_eq other
|
8
5
|
Nodes::NotEqual.new self, other
|
@@ -36,9 +33,9 @@ module Arel
|
|
36
33
|
if other.exclude_end?
|
37
34
|
left = Nodes::GreaterThanOrEqual.new(self, other.begin)
|
38
35
|
right = Nodes::LessThan.new(self, other.end)
|
39
|
-
Nodes::And.new left, right
|
36
|
+
Nodes::And.new [left, right]
|
40
37
|
else
|
41
|
-
Nodes::Between.new(self, Nodes::And.new(other.begin, other.end))
|
38
|
+
Nodes::Between.new(self, Nodes::And.new([other.begin, other.end]))
|
42
39
|
end
|
43
40
|
else
|
44
41
|
Nodes::In.new self, other
|
@@ -152,32 +149,17 @@ module Arel
|
|
152
149
|
grouping_all :lteq, others
|
153
150
|
end
|
154
151
|
|
155
|
-
def asc
|
156
|
-
Nodes::Ordering.new self, :asc
|
157
|
-
end
|
158
|
-
|
159
|
-
def desc
|
160
|
-
Nodes::Ordering.new self, :desc
|
161
|
-
end
|
162
|
-
|
163
152
|
private
|
164
153
|
|
165
154
|
def grouping_any method_id, others
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
Nodes::Grouping.new others.inject(first) { |memo,expr|
|
170
|
-
Nodes::Or.new(memo, send(method_id, expr))
|
155
|
+
nodes = others.map {|expr| send(method_id, expr)}
|
156
|
+
Nodes::Grouping.new nodes.inject { |memo,node|
|
157
|
+
Nodes::Or.new(memo, node)
|
171
158
|
}
|
172
159
|
end
|
173
160
|
|
174
161
|
def grouping_all method_id, others
|
175
|
-
others
|
176
|
-
first = send method_id, others.shift
|
177
|
-
|
178
|
-
Nodes::Grouping.new others.inject(first) { |memo,expr|
|
179
|
-
Nodes::And.new(memo, send(method_id, expr))
|
180
|
-
}
|
162
|
+
Nodes::Grouping.new Nodes::And.new(others.map {|expr| send(method_id, expr)})
|
181
163
|
end
|
182
164
|
end
|
183
165
|
end
|
data/lib/arel/select_manager.rb
CHANGED
@@ -9,18 +9,33 @@ module Arel
|
|
9
9
|
from table
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def initialize_copy other
|
13
|
+
super
|
14
|
+
@ctx = @ast.cores.last
|
15
|
+
end
|
16
|
+
|
17
|
+
def limit
|
13
18
|
@ast.limit && @ast.limit.expr
|
14
19
|
end
|
20
|
+
alias :taken :limit
|
15
21
|
|
16
22
|
def constraints
|
17
23
|
@ctx.wheres
|
18
24
|
end
|
19
25
|
|
26
|
+
def offset
|
27
|
+
@ast.offset && @ast.offset.expr
|
28
|
+
end
|
29
|
+
|
20
30
|
def skip amount
|
21
|
-
|
31
|
+
if amount
|
32
|
+
@ast.offset = Nodes::Offset.new(amount)
|
33
|
+
else
|
34
|
+
@ast.offset = nil
|
35
|
+
end
|
22
36
|
self
|
23
37
|
end
|
38
|
+
alias :offset= :skip
|
24
39
|
|
25
40
|
###
|
26
41
|
# Produces an Arel::Nodes::Exists node
|
@@ -28,8 +43,14 @@ module Arel
|
|
28
43
|
Arel::Nodes::Exists.new @ast
|
29
44
|
end
|
30
45
|
|
46
|
+
def as other
|
47
|
+
create_table_alias grouping(@ast), Nodes::SqlLiteral.new(other)
|
48
|
+
end
|
49
|
+
|
31
50
|
def where_clauses
|
32
|
-
|
51
|
+
if $VERBOSE
|
52
|
+
warn "(#{caller.first}) where_clauses is deprecated and will be removed in arel 3.0.0 with no replacement"
|
53
|
+
end
|
33
54
|
to_sql = Visitors::ToSql.new @engine
|
34
55
|
@ctx.wheres.map { |c| to_sql.accept c }
|
35
56
|
end
|
@@ -52,7 +73,7 @@ module Arel
|
|
52
73
|
end
|
53
74
|
|
54
75
|
def on *exprs
|
55
|
-
@ctx.
|
76
|
+
@ctx.source.right.last.right = Nodes::On.new(collapse(exprs))
|
56
77
|
self
|
57
78
|
end
|
58
79
|
|
@@ -72,35 +93,36 @@ module Arel
|
|
72
93
|
# FIXME: this is a hack to support
|
73
94
|
# test_with_two_tables_in_from_without_getting_double_quoted
|
74
95
|
# from the AR tests.
|
75
|
-
if @ctx.froms
|
76
|
-
source = @ctx.froms
|
77
96
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
97
|
+
case table
|
98
|
+
when Nodes::Join
|
99
|
+
@ctx.source.right << table
|
100
|
+
else
|
101
|
+
@ctx.source.left = table
|
82
102
|
end
|
83
103
|
|
84
|
-
@ctx.froms = table
|
85
104
|
self
|
86
105
|
end
|
87
106
|
|
107
|
+
def froms
|
108
|
+
@ast.cores.map { |x| x.from }.compact
|
109
|
+
end
|
110
|
+
|
88
111
|
def join relation, klass = Nodes::InnerJoin
|
89
112
|
return self unless relation
|
90
113
|
|
91
114
|
case relation
|
92
115
|
when String, Nodes::SqlLiteral
|
93
116
|
raise if relation.blank?
|
94
|
-
|
95
|
-
else
|
96
|
-
from klass.new(@ctx.froms, relation, nil)
|
117
|
+
klass = Nodes::StringJoin
|
97
118
|
end
|
98
|
-
end
|
99
119
|
|
100
|
-
|
101
|
-
|
120
|
+
@ctx.source.right << create_join(relation, nil, klass)
|
121
|
+
self
|
122
|
+
end
|
102
123
|
|
103
|
-
|
124
|
+
def having *exprs
|
125
|
+
@ctx.having = Nodes::Having.new(collapse(exprs, @ctx.having))
|
104
126
|
self
|
105
127
|
end
|
106
128
|
|
@@ -126,6 +148,7 @@ module Arel
|
|
126
148
|
end
|
127
149
|
|
128
150
|
def wheres
|
151
|
+
warn "#{caller[0]}: SelectManager#wheres is deprecated and will be removed in ARel 3.0.0 with no replacement"
|
129
152
|
Compatibility::Wheres.new @engine, @ctx.wheres
|
130
153
|
end
|
131
154
|
|
@@ -156,17 +179,34 @@ module Arel
|
|
156
179
|
end
|
157
180
|
alias :minus :except
|
158
181
|
|
182
|
+
def with *subqueries
|
183
|
+
if subqueries.first.is_a? Symbol
|
184
|
+
node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}")
|
185
|
+
else
|
186
|
+
node_class = Nodes::With
|
187
|
+
end
|
188
|
+
@ast.with = node_class.new(subqueries.flatten)
|
189
|
+
|
190
|
+
self
|
191
|
+
end
|
192
|
+
|
159
193
|
def take limit
|
160
|
-
|
161
|
-
|
194
|
+
if limit
|
195
|
+
@ast.limit = Nodes::Limit.new(limit)
|
196
|
+
@ctx.top = Nodes::Top.new(limit)
|
197
|
+
else
|
198
|
+
@ast.limit = nil
|
199
|
+
@ctx.top = nil
|
200
|
+
end
|
162
201
|
self
|
163
202
|
end
|
203
|
+
alias limit= take
|
164
204
|
|
165
205
|
def join_sql
|
166
|
-
return nil
|
206
|
+
return nil if @ctx.source.right.empty?
|
167
207
|
|
168
|
-
|
169
|
-
Nodes::SqlLiteral.new
|
208
|
+
sql = @visitor.dup.extend(Visitors::JoinSql).accept @ctx
|
209
|
+
Nodes::SqlLiteral.new sql
|
170
210
|
end
|
171
211
|
|
172
212
|
def order_clauses
|
@@ -175,9 +215,13 @@ module Arel
|
|
175
215
|
}
|
176
216
|
end
|
177
217
|
|
218
|
+
def join_sources
|
219
|
+
@ctx.source.right
|
220
|
+
end
|
221
|
+
|
178
222
|
def joins manager
|
179
223
|
if $VERBOSE
|
180
|
-
warn "joins is deprecated and will be removed in
|
224
|
+
warn "joins is deprecated and will be removed in 3.0.0"
|
181
225
|
warn "please remove your call to joins from #{caller.first}"
|
182
226
|
end
|
183
227
|
manager.join_sql
|
@@ -203,13 +247,22 @@ module Arel
|
|
203
247
|
|
204
248
|
# FIXME: this method should go away
|
205
249
|
def insert values
|
206
|
-
|
250
|
+
if $VERBOSE
|
251
|
+
warn <<-eowarn
|
252
|
+
insert (#{caller.first}) is deprecated and will be removed in ARel 3.0.0. Please
|
253
|
+
switch to `compile_insert`
|
254
|
+
eowarn
|
255
|
+
end
|
256
|
+
|
257
|
+
im = compile_insert(values)
|
207
258
|
table = @ctx.froms
|
208
|
-
|
259
|
+
|
260
|
+
primary_key = table.primary_key
|
261
|
+
primary_key_name = primary_key.name if primary_key
|
262
|
+
|
209
263
|
# FIXME: in AR tests values sometimes were Array and not Hash therefore is_a?(Hash) check is added
|
210
264
|
primary_key_value = primary_key && values.is_a?(Hash) && values[primary_key]
|
211
265
|
im.into table
|
212
|
-
im.insert values
|
213
266
|
# Oracle adapter needs primary key name to generate RETURNING ... INTO ... clause
|
214
267
|
# for tables which assign primary key value using trigger.
|
215
268
|
# RETURNING ... INTO ... clause will be added only if primary_key_value is nil
|
@@ -218,20 +271,22 @@ module Arel
|
|
218
271
|
end
|
219
272
|
|
220
273
|
private
|
221
|
-
def collapse exprs
|
222
|
-
exprs
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
right = Nodes::And.new left, right
|
232
|
-
exprs.reverse.inject(right) { |memo,expr|
|
233
|
-
Nodes::And.new(expr, memo)
|
274
|
+
def collapse exprs, existing = nil
|
275
|
+
exprs = exprs.unshift(existing.expr) if existing
|
276
|
+
exprs = exprs.compact.map { |expr|
|
277
|
+
if String === expr
|
278
|
+
# FIXME: Don't do this automatically
|
279
|
+
Arel.sql(expr)
|
280
|
+
else
|
281
|
+
expr
|
282
|
+
end
|
234
283
|
}
|
284
|
+
|
285
|
+
if exprs.length == 1
|
286
|
+
exprs.first
|
287
|
+
else
|
288
|
+
create_and exprs
|
289
|
+
end
|
235
290
|
end
|
236
291
|
end
|
237
292
|
end
|
data/lib/arel/table.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
module Arel
|
2
2
|
class Table
|
3
3
|
include Arel::Crud
|
4
|
+
include Arel::FactoryMethods
|
4
5
|
|
5
6
|
@engine = nil
|
6
7
|
class << self; attr_accessor :engine; end
|
7
8
|
|
8
9
|
attr_accessor :name, :engine, :aliases, :table_alias
|
9
10
|
|
11
|
+
# TableAlias and Table both have a #table_name which is the name of the underlying table
|
12
|
+
alias :table_name :name
|
13
|
+
|
10
14
|
def initialize name, engine = Table.engine
|
11
15
|
@name = name.to_s
|
12
16
|
@engine = engine
|
@@ -17,7 +21,6 @@ module Arel
|
|
17
21
|
|
18
22
|
if Hash === engine
|
19
23
|
@engine = engine[:engine] || Table.engine
|
20
|
-
@columns = attributes_for engine[:columns]
|
21
24
|
|
22
25
|
# Sometime AR sends an :as parameter to table, to let the table know
|
23
26
|
# that it is an Alias. We may want to override new, and return a
|
@@ -27,6 +30,11 @@ module Arel
|
|
27
30
|
end
|
28
31
|
|
29
32
|
def primary_key
|
33
|
+
if $VERBOSE
|
34
|
+
warn <<-eowarn
|
35
|
+
primary_key (#{caller.first}) is deprecated and will be removed in ARel 3.0.0
|
36
|
+
eowarn
|
37
|
+
end
|
30
38
|
@primary_key ||= begin
|
31
39
|
primary_key_name = @engine.connection.primary_key(name)
|
32
40
|
# some tables might be without primary key
|
@@ -35,7 +43,7 @@ module Arel
|
|
35
43
|
end
|
36
44
|
|
37
45
|
def alias name = "#{self.name}_2"
|
38
|
-
Nodes::TableAlias.new(
|
46
|
+
Nodes::TableAlias.new(self, name).tap do |node|
|
39
47
|
@aliases << node
|
40
48
|
end
|
41
49
|
end
|
@@ -46,7 +54,7 @@ module Arel
|
|
46
54
|
|
47
55
|
def joins manager
|
48
56
|
if $VERBOSE
|
49
|
-
warn "joins is deprecated and will be removed in
|
57
|
+
warn "joins is deprecated and will be removed in 3.0.0"
|
50
58
|
warn "please remove your call to joins from #{caller.first}"
|
51
59
|
end
|
52
60
|
nil
|
@@ -58,10 +66,10 @@ module Arel
|
|
58
66
|
case relation
|
59
67
|
when String, Nodes::SqlLiteral
|
60
68
|
raise if relation.blank?
|
61
|
-
|
62
|
-
else
|
63
|
-
from klass.new(self, relation, nil)
|
69
|
+
klass = Nodes::StringJoin
|
64
70
|
end
|
71
|
+
|
72
|
+
from(self).join(relation, klass)
|
65
73
|
end
|
66
74
|
|
67
75
|
def group *columns
|
@@ -93,41 +101,46 @@ module Arel
|
|
93
101
|
end
|
94
102
|
|
95
103
|
def columns
|
104
|
+
if $VERBOSE
|
105
|
+
warn <<-eowarn
|
106
|
+
(#{caller.first}) Arel::Table#columns is deprecated and will be removed in
|
107
|
+
Arel 3.0.0 with no replacement. PEW PEW PEW!!!
|
108
|
+
eowarn
|
109
|
+
end
|
96
110
|
@columns ||=
|
97
111
|
attributes_for @engine.connection.columns(@name, "#{@name} Columns")
|
98
112
|
end
|
99
113
|
|
100
114
|
def [] name
|
101
|
-
|
102
|
-
|
103
|
-
name = name.to_sym
|
104
|
-
columns.find { |column| column.name == name }
|
115
|
+
::Arel::Attribute.new self, name
|
105
116
|
end
|
106
117
|
|
107
118
|
def select_manager
|
108
119
|
SelectManager.new(@engine)
|
109
120
|
end
|
110
121
|
|
122
|
+
def insert_manager
|
123
|
+
InsertManager.new(@engine)
|
124
|
+
end
|
125
|
+
|
111
126
|
private
|
112
127
|
|
113
128
|
def attributes_for columns
|
114
129
|
return nil unless columns
|
115
130
|
|
116
131
|
columns.map do |column|
|
117
|
-
Attributes.for(column).new self, column.name.to_sym
|
132
|
+
Attributes.for(column).new self, column.name.to_sym
|
118
133
|
end
|
119
134
|
end
|
120
135
|
|
121
|
-
def table_exists?
|
122
|
-
@table_exists ||= tables.key?(@name) || engine.connection.table_exists?(name)
|
123
|
-
end
|
124
|
-
|
125
|
-
def tables
|
126
|
-
self.class.table_cache(@engine)
|
127
|
-
end
|
128
|
-
|
129
136
|
@@table_cache = nil
|
130
137
|
def self.table_cache engine # :nodoc:
|
138
|
+
if $VERBOSE
|
139
|
+
warn <<-eowarn
|
140
|
+
(#{caller.first}) Arel::Table.table_cache is deprecated and will be removed in
|
141
|
+
Arel 3.0.0 with no replacement. PEW PEW PEW!!!
|
142
|
+
eowarn
|
143
|
+
end
|
131
144
|
@@table_cache ||= Hash[engine.connection.tables.map { |x| [x,true] }]
|
132
145
|
end
|
133
146
|
end
|