arel 3.0.3 → 4.0.0.beta1
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 +7 -0
- data/.travis.yml +2 -2
- data/Gemfile +3 -4
- data/History.txt +0 -51
- data/Manifest.txt +8 -2
- data/README.markdown +1 -1
- data/Rakefile +1 -1
- data/arel.gemspec +21 -29
- data/lib/arel.rb +1 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/nodes/and.rb +10 -0
- data/lib/arel/nodes/binary.rb +11 -0
- data/lib/arel/nodes/extract.rb +11 -0
- data/lib/arel/nodes/false.rb +7 -0
- data/lib/arel/nodes/function.rb +11 -0
- data/lib/arel/nodes/grouping.rb +7 -0
- data/lib/arel/nodes/insert_statement.rb +12 -0
- data/lib/arel/nodes/named_function.rb +9 -0
- data/lib/arel/nodes/select_core.rb +20 -0
- data/lib/arel/nodes/select_statement.rb +15 -1
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/terminal.rb +7 -0
- data/lib/arel/nodes/true.rb +7 -0
- data/lib/arel/nodes/unary.rb +10 -1
- data/lib/arel/nodes/update_statement.rb +15 -0
- data/lib/arel/nodes/window.rb +30 -3
- data/lib/arel/select_manager.rb +4 -0
- data/lib/arel/table.rb +13 -0
- data/lib/arel/tree_manager.rb +0 -2
- data/lib/arel/visitors/bind_visitor.rb +10 -0
- data/lib/arel/visitors/dot.rb +1 -1
- data/lib/arel/visitors/oracle.rb +1 -2
- data/lib/arel/visitors/to_sql.rb +138 -27
- data/test/nodes/test_and.rb +20 -0
- data/test/nodes/test_as.rb +12 -0
- data/test/nodes/test_ascending.rb +10 -0
- data/test/nodes/test_bin.rb +10 -0
- data/test/nodes/test_count.rb +12 -0
- data/test/nodes/test_delete_statement.rb +20 -0
- data/test/nodes/test_descending.rb +10 -0
- data/test/nodes/test_distinct.rb +20 -0
- data/test/nodes/test_equality.rb +10 -0
- data/test/nodes/test_extract.rb +14 -0
- data/test/nodes/test_false.rb +20 -0
- data/test/nodes/test_grouping.rb +25 -0
- data/test/nodes/test_infix_operation.rb +10 -0
- data/test/nodes/test_insert_statement.rb +24 -0
- data/test/nodes/test_named_function.rb +16 -0
- data/test/nodes/test_not.rb +12 -0
- data/test/nodes/test_or.rb +12 -0
- data/test/nodes/test_over.rb +18 -0
- data/test/nodes/test_select_core.rb +38 -0
- data/test/nodes/test_select_statement.rb +36 -0
- data/test/nodes/test_sql_literal.rb +10 -0
- data/test/nodes/test_sum.rb +12 -0
- data/test/nodes/test_table_alias.rb +36 -0
- data/test/nodes/test_true.rb +21 -0
- data/test/nodes/test_update_statement.rb +40 -0
- data/test/nodes/test_window.rb +73 -0
- data/test/test_attributes.rb +12 -0
- data/test/test_insert_manager.rb +0 -2
- data/test/test_select_manager.rb +10 -5
- data/test/test_table.rb +24 -0
- data/test/test_update_manager.rb +8 -0
- data/test/visitors/test_bind_visitor.rb +20 -1
- data/test/visitors/test_oracle.rb +1 -2
- data/test/visitors/test_to_sql.rb +44 -0
- metadata +76 -86
- data/lib/arel/nodes/ordering.rb +0 -6
- data/lib/arel/relation.rb +0 -6
data/lib/arel/nodes/terminal.rb
CHANGED
data/lib/arel/nodes/true.rb
CHANGED
data/lib/arel/nodes/unary.rb
CHANGED
@@ -7,12 +7,21 @@ module Arel
|
|
7
7
|
def initialize expr
|
8
8
|
@expr = expr
|
9
9
|
end
|
10
|
+
|
11
|
+
def hash
|
12
|
+
@expr.hash
|
13
|
+
end
|
14
|
+
|
15
|
+
def eql? other
|
16
|
+
self.class == other.class &&
|
17
|
+
self.expr == other.expr
|
18
|
+
end
|
19
|
+
alias :== :eql?
|
10
20
|
end
|
11
21
|
|
12
22
|
%w{
|
13
23
|
Bin
|
14
24
|
Group
|
15
|
-
Grouping
|
16
25
|
Having
|
17
26
|
Limit
|
18
27
|
Not
|
@@ -18,6 +18,21 @@ module Arel
|
|
18
18
|
@wheres = @wheres.clone
|
19
19
|
@values = @values.clone
|
20
20
|
end
|
21
|
+
|
22
|
+
def hash
|
23
|
+
[@relation, @wheres, @values, @orders, @limit, @key].hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def eql? other
|
27
|
+
self.class == other.class &&
|
28
|
+
self.relation == other.relation &&
|
29
|
+
self.wheres == other.wheres &&
|
30
|
+
self.values == other.values &&
|
31
|
+
self.orders == other.orders &&
|
32
|
+
self.limit == other.limit &&
|
33
|
+
self.key == other.key
|
34
|
+
end
|
35
|
+
alias :== :eql?
|
21
36
|
end
|
22
37
|
end
|
23
38
|
end
|
data/lib/arel/nodes/window.rb
CHANGED
@@ -17,7 +17,6 @@ module Arel
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def frame(expr)
|
20
|
-
raise ArgumentError, "Window frame cannot be set more than once" if @frame
|
21
20
|
@framing = expr
|
22
21
|
end
|
23
22
|
|
@@ -33,6 +32,17 @@ module Arel
|
|
33
32
|
super
|
34
33
|
@orders = @orders.map { |x| x.clone }
|
35
34
|
end
|
35
|
+
|
36
|
+
def hash
|
37
|
+
[@orders, @framing].hash
|
38
|
+
end
|
39
|
+
|
40
|
+
def eql? other
|
41
|
+
self.class == other.class &&
|
42
|
+
self.orders == other.orders &&
|
43
|
+
self.framing == other.framing
|
44
|
+
end
|
45
|
+
alias :== :eql?
|
36
46
|
end
|
37
47
|
|
38
48
|
class NamedWindow < Window
|
@@ -47,6 +57,15 @@ module Arel
|
|
47
57
|
super
|
48
58
|
@name = other.name.clone
|
49
59
|
end
|
60
|
+
|
61
|
+
def hash
|
62
|
+
super ^ @name.hash
|
63
|
+
end
|
64
|
+
|
65
|
+
def eql? other
|
66
|
+
super && self.name == other.name
|
67
|
+
end
|
68
|
+
alias :== :eql?
|
50
69
|
end
|
51
70
|
|
52
71
|
class Rows < Unary
|
@@ -61,7 +80,15 @@ module Arel
|
|
61
80
|
end
|
62
81
|
end
|
63
82
|
|
64
|
-
class CurrentRow <
|
83
|
+
class CurrentRow < Node
|
84
|
+
def hash
|
85
|
+
self.class.hash
|
86
|
+
end
|
87
|
+
|
88
|
+
def eql? other
|
89
|
+
self.class == other.class
|
90
|
+
end
|
91
|
+
end
|
65
92
|
|
66
93
|
class Preceding < Unary
|
67
94
|
def initialize(expr = nil)
|
@@ -75,4 +102,4 @@ module Arel
|
|
75
102
|
end
|
76
103
|
end
|
77
104
|
end
|
78
|
-
end
|
105
|
+
end
|
data/lib/arel/select_manager.rb
CHANGED
data/lib/arel/table.rb
CHANGED
@@ -123,6 +123,19 @@ Arel 4.0.0 with no replacement. PEW PEW PEW!!!
|
|
123
123
|
InsertManager.new(@engine)
|
124
124
|
end
|
125
125
|
|
126
|
+
def hash
|
127
|
+
[@name, @engine, @aliases, @table_alias].hash
|
128
|
+
end
|
129
|
+
|
130
|
+
def eql? other
|
131
|
+
self.class == other.class &&
|
132
|
+
self.name == other.name &&
|
133
|
+
self.engine == other.engine &&
|
134
|
+
self.aliases == other.aliases &&
|
135
|
+
self.table_alias == other.table_alias
|
136
|
+
end
|
137
|
+
alias :== :eql?
|
138
|
+
|
126
139
|
private
|
127
140
|
|
128
141
|
def attributes_for columns
|
data/lib/arel/tree_manager.rb
CHANGED
@@ -12,6 +12,15 @@ module Arel
|
|
12
12
|
end
|
13
13
|
|
14
14
|
private
|
15
|
+
|
16
|
+
def visit_Arel_Nodes_Assignment o
|
17
|
+
if o.right.is_a? Arel::Nodes::BindParam
|
18
|
+
"#{visit o.left} = #{visit o.right}"
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
15
24
|
def visit_Arel_Nodes_BindParam o
|
16
25
|
if @block
|
17
26
|
@block.call
|
@@ -19,6 +28,7 @@ module Arel
|
|
19
28
|
super
|
20
29
|
end
|
21
30
|
end
|
31
|
+
|
22
32
|
end
|
23
33
|
end
|
24
34
|
end
|
data/lib/arel/visitors/dot.rb
CHANGED
@@ -65,7 +65,6 @@ module Arel
|
|
65
65
|
visit_edge o, "expr"
|
66
66
|
end
|
67
67
|
alias :visit_Arel_Nodes_Group :unary
|
68
|
-
alias :visit_Arel_Nodes_BindParam :unary
|
69
68
|
alias :visit_Arel_Nodes_Grouping :unary
|
70
69
|
alias :visit_Arel_Nodes_Having :unary
|
71
70
|
alias :visit_Arel_Nodes_Limit :unary
|
@@ -195,6 +194,7 @@ module Arel
|
|
195
194
|
alias :visit_TrueClass :visit_String
|
196
195
|
alias :visit_FalseClass :visit_String
|
197
196
|
alias :visit_Arel_SqlLiteral :visit_String
|
197
|
+
alias :visit_Arel_Nodes_BindParam :visit_String
|
198
198
|
alias :visit_Fixnum :visit_String
|
199
199
|
alias :visit_BigDecimal :visit_String
|
200
200
|
alias :visit_Float :visit_String
|
data/lib/arel/visitors/oracle.rb
CHANGED
@@ -25,9 +25,8 @@ module Arel
|
|
25
25
|
SELECT * FROM (
|
26
26
|
SELECT raw_sql_.*, rownum raw_rnum_
|
27
27
|
FROM (#{sql}) raw_sql_
|
28
|
-
WHERE rownum <= #{offset.expr.to_i + limit}
|
29
28
|
)
|
30
|
-
WHERE #{
|
29
|
+
WHERE raw_rnum_ >= #{offset.expr.to_i + 1 } and rownum <= #{limit}
|
31
30
|
eosql
|
32
31
|
end
|
33
32
|
|
data/lib/arel/visitors/to_sql.rb
CHANGED
@@ -4,6 +4,55 @@ require 'date'
|
|
4
4
|
module Arel
|
5
5
|
module Visitors
|
6
6
|
class ToSql < Arel::Visitors::Visitor
|
7
|
+
##
|
8
|
+
# This is some roflscale crazy stuff. I'm roflscaling this because
|
9
|
+
# building SQL queries is a hotspot. I will explain the roflscale so that
|
10
|
+
# others will not rm this code.
|
11
|
+
#
|
12
|
+
# In YARV, string literals in a method body will get duped when the byte
|
13
|
+
# code is executed. Let's take a look:
|
14
|
+
#
|
15
|
+
# > puts RubyVM::InstructionSequence.new('def foo; "bar"; end').disasm
|
16
|
+
#
|
17
|
+
# == disasm: <RubyVM::InstructionSequence:foo@<compiled>>=====
|
18
|
+
# 0000 trace 8
|
19
|
+
# 0002 trace 1
|
20
|
+
# 0004 putstring "bar"
|
21
|
+
# 0006 trace 16
|
22
|
+
# 0008 leave
|
23
|
+
#
|
24
|
+
# The `putstring` bytecode will dup the string and push it on the stack.
|
25
|
+
# In many cases in our SQL visitor, that string is never mutated, so there
|
26
|
+
# is no need to dup the literal.
|
27
|
+
#
|
28
|
+
# If we change to a constant lookup, the string will not be duped, and we
|
29
|
+
# can reduce the objects in our system:
|
30
|
+
#
|
31
|
+
# > puts RubyVM::InstructionSequence.new('BAR = "bar"; def foo; BAR; end').disasm
|
32
|
+
#
|
33
|
+
# == disasm: <RubyVM::InstructionSequence:foo@<compiled>>========
|
34
|
+
# 0000 trace 8
|
35
|
+
# 0002 trace 1
|
36
|
+
# 0004 getinlinecache 11, <ic:0>
|
37
|
+
# 0007 getconstant :BAR
|
38
|
+
# 0009 setinlinecache <ic:0>
|
39
|
+
# 0011 trace 16
|
40
|
+
# 0013 leave
|
41
|
+
#
|
42
|
+
# `getconstant` should be a hash lookup, and no object is duped when the
|
43
|
+
# value of the constant is pushed on the stack. Hence the crazy
|
44
|
+
# constants below.
|
45
|
+
|
46
|
+
WHERE = ' WHERE ' # :nodoc:
|
47
|
+
SPACE = ' ' # :nodoc:
|
48
|
+
COMMA = ', ' # :nodoc:
|
49
|
+
GROUP_BY = ' GROUP BY ' # :nodoc:
|
50
|
+
ORDER_BY = ' ORDER BY ' # :nodoc:
|
51
|
+
WINDOW = ' WINDOW ' # :nodoc:
|
52
|
+
AND = ' AND ' # :nodoc:
|
53
|
+
|
54
|
+
DISTINCT = 'DISTINCT' # :nodoc:
|
55
|
+
|
7
56
|
attr_accessor :last_column
|
8
57
|
|
9
58
|
def initialize connection
|
@@ -23,7 +72,7 @@ module Arel
|
|
23
72
|
def visit_Arel_Nodes_DeleteStatement o
|
24
73
|
[
|
25
74
|
"DELETE FROM #{visit o.relation}",
|
26
|
-
("WHERE #{o.wheres.map { |x| visit x }.join
|
75
|
+
("WHERE #{o.wheres.map { |x| visit x }.join AND}" unless o.wheres.empty?)
|
27
76
|
].compact.join ' '
|
28
77
|
end
|
29
78
|
|
@@ -116,28 +165,80 @@ key on UpdateManager using UpdateManager#key=
|
|
116
165
|
end
|
117
166
|
|
118
167
|
def visit_Arel_Nodes_SelectStatement o
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
168
|
+
str = ''
|
169
|
+
|
170
|
+
if o.with
|
171
|
+
str << visit(o.with)
|
172
|
+
str << SPACE
|
173
|
+
end
|
174
|
+
|
175
|
+
o.cores.each { |x| str << visit_Arel_Nodes_SelectCore(x) }
|
176
|
+
|
177
|
+
unless o.orders.empty?
|
178
|
+
str << SPACE
|
179
|
+
str << ORDER_BY
|
180
|
+
len = o.orders.length - 1
|
181
|
+
o.orders.each_with_index { |x, i|
|
182
|
+
str << visit(x)
|
183
|
+
str << COMMA unless len == i
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
str << " #{visit(o.limit)}" if o.limit
|
188
|
+
str << " #{visit(o.offset)}" if o.offset
|
189
|
+
str << " #{visit(o.lock)}" if o.lock
|
190
|
+
|
191
|
+
str.strip!
|
192
|
+
str
|
127
193
|
end
|
128
194
|
|
129
195
|
def visit_Arel_Nodes_SelectCore o
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
196
|
+
str = "SELECT"
|
197
|
+
|
198
|
+
str << " #{visit(o.top)}" if o.top
|
199
|
+
str << " #{visit(o.set_quantifier)}" if o.set_quantifier
|
200
|
+
|
201
|
+
unless o.projections.empty?
|
202
|
+
str << SPACE
|
203
|
+
len = o.projections.length - 1
|
204
|
+
o.projections.each_with_index do |x, i|
|
205
|
+
str << visit(x)
|
206
|
+
str << COMMA unless len == i
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
str << " FROM #{visit(o.source)}" if o.source && !o.source.empty?
|
211
|
+
|
212
|
+
unless o.wheres.empty?
|
213
|
+
str << WHERE
|
214
|
+
len = o.wheres.length - 1
|
215
|
+
o.wheres.each_with_index do |x, i|
|
216
|
+
str << visit(x)
|
217
|
+
str << AND unless len == i
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
unless o.groups.empty?
|
222
|
+
str << GROUP_BY
|
223
|
+
len = o.groups.length - 1
|
224
|
+
o.groups.each_with_index do |x, i|
|
225
|
+
str << visit(x)
|
226
|
+
str << COMMA unless len == i
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
str << " #{visit(o.having)}" if o.having
|
231
|
+
|
232
|
+
unless o.windows.empty?
|
233
|
+
str << WINDOW
|
234
|
+
len = o.windows.length - 1
|
235
|
+
o.windows.each_with_index do |x, i|
|
236
|
+
str << visit(x)
|
237
|
+
str << COMMA unless len == i
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
str
|
141
242
|
end
|
142
243
|
|
143
244
|
def visit_Arel_Nodes_Bin o
|
@@ -145,7 +246,7 @@ key on UpdateManager using UpdateManager#key=
|
|
145
246
|
end
|
146
247
|
|
147
248
|
def visit_Arel_Nodes_Distinct o
|
148
|
-
|
249
|
+
DISTINCT
|
149
250
|
end
|
150
251
|
|
151
252
|
def visit_Arel_Nodes_DistinctOn o
|
@@ -254,6 +355,10 @@ key on UpdateManager using UpdateManager#key=
|
|
254
355
|
"(#{visit o.expr})"
|
255
356
|
end
|
256
357
|
|
358
|
+
def visit_Arel_SelectManager o
|
359
|
+
"(#{o.to_sql.rstrip})"
|
360
|
+
end
|
361
|
+
|
257
362
|
def visit_Arel_Nodes_Ascending o
|
258
363
|
"#{visit o.expr} ASC"
|
259
364
|
end
|
@@ -283,22 +388,22 @@ key on UpdateManager using UpdateManager#key=
|
|
283
388
|
end
|
284
389
|
|
285
390
|
def visit_Arel_Nodes_Sum o
|
286
|
-
"SUM(#{o.expressions.map { |x|
|
391
|
+
"SUM(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
|
287
392
|
visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
|
288
393
|
end
|
289
394
|
|
290
395
|
def visit_Arel_Nodes_Max o
|
291
|
-
"MAX(#{o.expressions.map { |x|
|
396
|
+
"MAX(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
|
292
397
|
visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
|
293
398
|
end
|
294
399
|
|
295
400
|
def visit_Arel_Nodes_Min o
|
296
|
-
"MIN(#{o.expressions.map { |x|
|
401
|
+
"MIN(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
|
297
402
|
visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
|
298
403
|
end
|
299
404
|
|
300
405
|
def visit_Arel_Nodes_Avg o
|
301
|
-
"AVG(#{o.expressions.map { |x|
|
406
|
+
"AVG(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
|
302
407
|
visit x }.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
|
303
408
|
end
|
304
409
|
|
@@ -350,7 +455,12 @@ key on UpdateManager using UpdateManager#key=
|
|
350
455
|
end
|
351
456
|
|
352
457
|
def visit_Arel_Nodes_InnerJoin o
|
353
|
-
"INNER JOIN #{visit o.left}
|
458
|
+
s = "INNER JOIN #{visit o.left}"
|
459
|
+
if o.right
|
460
|
+
s << SPACE
|
461
|
+
s << visit(o.right)
|
462
|
+
end
|
463
|
+
s
|
354
464
|
end
|
355
465
|
|
356
466
|
def visit_Arel_Nodes_On o
|
@@ -475,10 +585,11 @@ key on UpdateManager using UpdateManager#key=
|
|
475
585
|
alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation
|
476
586
|
|
477
587
|
def visit_Array o
|
478
|
-
o.
|
588
|
+
o.map { |x| visit x }.join(', ')
|
479
589
|
end
|
480
590
|
|
481
591
|
def quote value, column = nil
|
592
|
+
return value if Arel::Nodes::SqlLiteral === value
|
482
593
|
@connection.quote value, column
|
483
594
|
end
|
484
595
|
|