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