arel 6.0.4 → 7.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.txt +31 -12
- data/MIT-LICENSE.txt +2 -1
- data/{README.markdown → README.md} +88 -31
- data/lib/arel.rb +1 -1
- data/lib/arel/attributes/attribute.rb +8 -0
- data/lib/arel/crud.rb +4 -3
- data/lib/arel/delete_manager.rb +6 -1
- data/lib/arel/insert_manager.rb +1 -1
- data/lib/arel/math.rb +24 -0
- data/lib/arel/nodes.rb +6 -38
- data/lib/arel/nodes/binary.rb +0 -2
- data/lib/arel/nodes/bind_param.rb +3 -0
- data/lib/arel/nodes/case.rb +57 -0
- data/lib/arel/nodes/casted.rb +44 -0
- data/lib/arel/nodes/delete_statement.rb +2 -0
- data/lib/arel/nodes/infix_operation.rb +36 -1
- data/lib/arel/nodes/matches.rb +3 -1
- data/lib/arel/nodes/regexp.rb +14 -0
- data/lib/arel/nodes/select_core.rb +5 -5
- data/lib/arel/nodes/table_alias.rb +6 -2
- data/lib/arel/nodes/unary.rb +6 -3
- data/lib/arel/nodes/unary_operation.rb +25 -0
- data/lib/arel/predications.rb +38 -14
- data/lib/arel/select_manager.rb +6 -6
- data/lib/arel/table.rb +34 -59
- data/lib/arel/tree_manager.rb +3 -8
- data/lib/arel/update_manager.rb +1 -1
- data/lib/arel/visitors.rb +1 -23
- data/lib/arel/visitors/depth_first.rb +14 -2
- data/lib/arel/visitors/dot.rb +12 -1
- data/lib/arel/visitors/informix.rb +6 -1
- data/lib/arel/visitors/mssql.rb +35 -3
- data/lib/arel/visitors/mysql.rb +8 -0
- data/lib/arel/visitors/oracle.rb +13 -2
- data/lib/arel/visitors/oracle12.rb +59 -0
- data/lib/arel/visitors/postgresql.rb +56 -4
- data/lib/arel/visitors/sqlite.rb +9 -0
- data/lib/arel/visitors/to_sql.rb +94 -52
- data/lib/arel/visitors/where_sql.rb +10 -1
- metadata +11 -6
data/lib/arel/nodes/binary.rb
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Arel
|
2
|
+
module Nodes
|
3
|
+
class Case < Arel::Nodes::Node
|
4
|
+
include Arel::OrderPredications
|
5
|
+
include Arel::Predications
|
6
|
+
include Arel::AliasPredication
|
7
|
+
|
8
|
+
attr_accessor :case, :conditions, :default
|
9
|
+
|
10
|
+
def initialize expression = nil, default = nil
|
11
|
+
@case = expression
|
12
|
+
@conditions = []
|
13
|
+
@default = default
|
14
|
+
end
|
15
|
+
|
16
|
+
def when condition, expression = nil
|
17
|
+
@conditions << When.new(Nodes.build_quoted(condition), expression)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def then expression
|
22
|
+
@conditions.last.right = Nodes.build_quoted(expression)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def else expression
|
27
|
+
@default = Else.new Nodes.build_quoted(expression)
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize_copy other
|
32
|
+
super
|
33
|
+
@case = @case.clone if @case
|
34
|
+
@conditions = @conditions.map { |x| x.clone }
|
35
|
+
@default = @default.clone if @default
|
36
|
+
end
|
37
|
+
|
38
|
+
def hash
|
39
|
+
[@case, @conditions, @default].hash
|
40
|
+
end
|
41
|
+
|
42
|
+
def eql? other
|
43
|
+
self.class == other.class &&
|
44
|
+
self.case == other.case &&
|
45
|
+
self.conditions == other.conditions &&
|
46
|
+
self.default == other.default
|
47
|
+
end
|
48
|
+
alias :== :eql?
|
49
|
+
end
|
50
|
+
|
51
|
+
class When < Binary # :nodoc:
|
52
|
+
end
|
53
|
+
|
54
|
+
class Else < Unary # :nodoc:
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Arel
|
2
|
+
module Nodes
|
3
|
+
class Casted < Arel::Nodes::Node # :nodoc:
|
4
|
+
attr_reader :val, :attribute
|
5
|
+
def initialize val, attribute
|
6
|
+
@val = val
|
7
|
+
@attribute = attribute
|
8
|
+
super()
|
9
|
+
end
|
10
|
+
|
11
|
+
def nil?; @val.nil?; end
|
12
|
+
|
13
|
+
def hash
|
14
|
+
[self.class, val, attribute].hash
|
15
|
+
end
|
16
|
+
|
17
|
+
def eql? other
|
18
|
+
self.class == other.class &&
|
19
|
+
self.val == other.val &&
|
20
|
+
self.attribute == other.attribute
|
21
|
+
end
|
22
|
+
alias :== :eql?
|
23
|
+
end
|
24
|
+
|
25
|
+
class Quoted < Arel::Nodes::Unary # :nodoc:
|
26
|
+
alias :val :value
|
27
|
+
def nil?; val.nil?; end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.build_quoted other, attribute = nil
|
31
|
+
case other
|
32
|
+
when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted
|
33
|
+
other
|
34
|
+
else
|
35
|
+
case attribute
|
36
|
+
when Arel::Attributes::Attribute
|
37
|
+
Casted.new other, attribute
|
38
|
+
else
|
39
|
+
Quoted.new other
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -40,5 +40,40 @@ module Arel
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
class Concat < InfixOperation
|
44
|
+
def initialize left, right
|
45
|
+
super('||', left, right)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class BitwiseAnd < InfixOperation
|
50
|
+
def initialize left, right
|
51
|
+
super(:&, left, right)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class BitwiseOr < InfixOperation
|
56
|
+
def initialize left, right
|
57
|
+
super(:|, left, right)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class BitwiseXor < InfixOperation
|
62
|
+
def initialize left, right
|
63
|
+
super(:^, left, right)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class BitwiseShiftLeft < InfixOperation
|
68
|
+
def initialize left, right
|
69
|
+
super(:<<, left, right)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class BitwiseShiftRight < InfixOperation
|
74
|
+
def initialize left, right
|
75
|
+
super(:>>, left, right)
|
76
|
+
end
|
77
|
+
end
|
43
78
|
end
|
44
|
-
end
|
79
|
+
end
|
data/lib/arel/nodes/matches.rb
CHANGED
@@ -2,10 +2,12 @@ module Arel
|
|
2
2
|
module Nodes
|
3
3
|
class Matches < Binary
|
4
4
|
attr_reader :escape
|
5
|
+
attr_accessor :case_sensitive
|
5
6
|
|
6
|
-
def initialize(left, right, escape = nil)
|
7
|
+
def initialize(left, right, escape = nil, case_sensitive = false)
|
7
8
|
super(left, right)
|
8
9
|
@escape = escape && Nodes.build_quoted(escape)
|
10
|
+
@case_sensitive = case_sensitive
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Arel
|
2
|
+
module Nodes
|
3
|
+
class Regexp < Binary
|
4
|
+
attr_accessor :case_sensitive
|
5
|
+
|
6
|
+
def initialize(left, right, case_sensitive = true)
|
7
|
+
super(left, right)
|
8
|
+
@case_sensitive = case_sensitive
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class NotRegexp < Regexp; end
|
13
|
+
end
|
14
|
+
end
|
@@ -2,7 +2,7 @@ module Arel
|
|
2
2
|
module Nodes
|
3
3
|
class SelectCore < Arel::Nodes::Node
|
4
4
|
attr_accessor :top, :projections, :wheres, :groups, :windows
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :havings, :source, :set_quantifier
|
6
6
|
|
7
7
|
def initialize
|
8
8
|
super()
|
@@ -14,7 +14,7 @@ module Arel
|
|
14
14
|
@projections = []
|
15
15
|
@wheres = []
|
16
16
|
@groups = []
|
17
|
-
@
|
17
|
+
@havings = []
|
18
18
|
@windows = []
|
19
19
|
end
|
20
20
|
|
@@ -35,14 +35,14 @@ module Arel
|
|
35
35
|
@projections = @projections.clone
|
36
36
|
@wheres = @wheres.clone
|
37
37
|
@groups = @groups.clone
|
38
|
-
@
|
38
|
+
@havings = @havings.clone
|
39
39
|
@windows = @windows.clone
|
40
40
|
end
|
41
41
|
|
42
42
|
def hash
|
43
43
|
[
|
44
44
|
@source, @top, @set_quantifier, @projections,
|
45
|
-
@wheres, @groups, @
|
45
|
+
@wheres, @groups, @havings, @windows
|
46
46
|
].hash
|
47
47
|
end
|
48
48
|
|
@@ -54,7 +54,7 @@ module Arel
|
|
54
54
|
self.projections == other.projections &&
|
55
55
|
self.wheres == other.wheres &&
|
56
56
|
self.groups == other.groups &&
|
57
|
-
self.
|
57
|
+
self.havings == other.havings &&
|
58
58
|
self.windows == other.windows
|
59
59
|
end
|
60
60
|
alias :== :eql?
|
@@ -13,8 +13,12 @@ module Arel
|
|
13
13
|
relation.respond_to?(:name) ? relation.name : name
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
relation.
|
16
|
+
def type_cast_for_database(*args)
|
17
|
+
relation.type_cast_for_database(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def able_to_type_cast?
|
21
|
+
relation.respond_to?(:able_to_type_cast?) && relation.able_to_type_cast?
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
data/lib/arel/nodes/unary.rb
CHANGED
@@ -22,16 +22,19 @@ module Arel
|
|
22
22
|
|
23
23
|
%w{
|
24
24
|
Bin
|
25
|
+
Cube
|
26
|
+
DistinctOn
|
25
27
|
Group
|
26
|
-
|
28
|
+
GroupingElement
|
29
|
+
GroupingSet
|
27
30
|
Limit
|
31
|
+
Lock
|
28
32
|
Not
|
29
33
|
Offset
|
30
34
|
On
|
31
35
|
Ordering
|
36
|
+
RollUp
|
32
37
|
Top
|
33
|
-
Lock
|
34
|
-
DistinctOn
|
35
38
|
}.each do |name|
|
36
39
|
const_set(name, Class.new(Unary))
|
37
40
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Arel
|
2
|
+
module Nodes
|
3
|
+
|
4
|
+
class UnaryOperation < Unary
|
5
|
+
include Arel::Expressions
|
6
|
+
include Arel::Predications
|
7
|
+
include Arel::OrderPredications
|
8
|
+
include Arel::AliasPredication
|
9
|
+
include Arel::Math
|
10
|
+
|
11
|
+
attr_reader :operator
|
12
|
+
|
13
|
+
def initialize operator, operand
|
14
|
+
super(operand)
|
15
|
+
@operator = operator
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class BitwiseNot < UnaryOperation
|
20
|
+
def initialize operand
|
21
|
+
super(:~, operand)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/arel/predications.rb
CHANGED
@@ -25,15 +25,15 @@ module Arel
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def between other
|
28
|
-
if other.begin
|
29
|
-
if other.end
|
28
|
+
if equals_quoted?(other.begin, -Float::INFINITY)
|
29
|
+
if equals_quoted?(other.end, Float::INFINITY)
|
30
30
|
not_in([])
|
31
31
|
elsif other.exclude_end?
|
32
32
|
lt(other.end)
|
33
33
|
else
|
34
34
|
lteq(other.end)
|
35
35
|
end
|
36
|
-
elsif other.end
|
36
|
+
elsif equals_quoted?(other.end, Float::INFINITY)
|
37
37
|
gteq(other.begin)
|
38
38
|
elsif other.exclude_end?
|
39
39
|
gteq(other.begin).and(lt(other.end))
|
@@ -71,15 +71,15 @@ Passing a range to `#in` is deprecated. Call `#between`, instead.
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def not_between other
|
74
|
-
if other.begin
|
75
|
-
if other.end
|
74
|
+
if equals_quoted?(other.begin, -Float::INFINITY)
|
75
|
+
if equals_quoted?(other.end, Float::INFINITY)
|
76
76
|
self.in([])
|
77
77
|
elsif other.exclude_end?
|
78
78
|
gteq(other.end)
|
79
79
|
else
|
80
80
|
gt(other.end)
|
81
81
|
end
|
82
|
-
elsif other.end
|
82
|
+
elsif equals_quoted?(other.end, Float::INFINITY)
|
83
83
|
lt(other.begin)
|
84
84
|
else
|
85
85
|
left = lt(other.begin)
|
@@ -118,20 +118,28 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
|
|
118
118
|
grouping_all :not_in, others
|
119
119
|
end
|
120
120
|
|
121
|
-
def matches other, escape = nil
|
122
|
-
Nodes::Matches.new self, quoted_node(other), escape
|
121
|
+
def matches other, escape = nil, case_sensitive = false
|
122
|
+
Nodes::Matches.new self, quoted_node(other), escape, case_sensitive
|
123
123
|
end
|
124
124
|
|
125
|
-
def
|
126
|
-
|
125
|
+
def matches_regexp other, case_sensitive = true
|
126
|
+
Nodes::Regexp.new self, quoted_node(other), case_sensitive
|
127
127
|
end
|
128
128
|
|
129
|
-
def
|
130
|
-
|
129
|
+
def matches_any others, escape = nil, case_sensitive = false
|
130
|
+
grouping_any :matches, others, escape, case_sensitive
|
131
131
|
end
|
132
132
|
|
133
|
-
def
|
134
|
-
|
133
|
+
def matches_all others, escape = nil, case_sensitive = false
|
134
|
+
grouping_all :matches, others, escape, case_sensitive
|
135
|
+
end
|
136
|
+
|
137
|
+
def does_not_match other, escape = nil, case_sensitive = false
|
138
|
+
Nodes::DoesNotMatch.new self, quoted_node(other), escape, case_sensitive
|
139
|
+
end
|
140
|
+
|
141
|
+
def does_not_match_regexp other, case_sensitive = true
|
142
|
+
Nodes::NotRegexp.new self, quoted_node(other), case_sensitive
|
135
143
|
end
|
136
144
|
|
137
145
|
def does_not_match_any others, escape = nil
|
@@ -190,6 +198,14 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
|
|
190
198
|
grouping_all :lteq, others
|
191
199
|
end
|
192
200
|
|
201
|
+
def when right
|
202
|
+
Nodes::Case.new(self).when quoted_node(right)
|
203
|
+
end
|
204
|
+
|
205
|
+
def concat other
|
206
|
+
Nodes::Concat.new self, other
|
207
|
+
end
|
208
|
+
|
193
209
|
private
|
194
210
|
|
195
211
|
def grouping_any method_id, others, *extras
|
@@ -211,5 +227,13 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
|
|
211
227
|
def quoted_array(others)
|
212
228
|
others.map { |v| quoted_node(v) }
|
213
229
|
end
|
230
|
+
|
231
|
+
def equals_quoted?(maybe_quoted, value)
|
232
|
+
if maybe_quoted.is_a?(Nodes::Quoted)
|
233
|
+
maybe_quoted.val == value
|
234
|
+
else
|
235
|
+
maybe_quoted == value
|
236
|
+
end
|
237
|
+
end
|
214
238
|
end
|
215
239
|
end
|
data/lib/arel/select_manager.rb
CHANGED
@@ -6,8 +6,8 @@ module Arel
|
|
6
6
|
|
7
7
|
STRING_OR_SYMBOL_CLASS = [Symbol, String]
|
8
8
|
|
9
|
-
def initialize
|
10
|
-
super(
|
9
|
+
def initialize table = nil
|
10
|
+
super()
|
11
11
|
@ast = Nodes::SelectStatement.new
|
12
12
|
@ctx = @ast.cores.last
|
13
13
|
from table
|
@@ -118,8 +118,8 @@ module Arel
|
|
118
118
|
join(relation, Nodes::OuterJoin)
|
119
119
|
end
|
120
120
|
|
121
|
-
def having
|
122
|
-
@ctx.
|
121
|
+
def having expr
|
122
|
+
@ctx.havings << expr
|
123
123
|
self
|
124
124
|
end
|
125
125
|
|
@@ -176,10 +176,10 @@ module Arel
|
|
176
176
|
@ast.orders
|
177
177
|
end
|
178
178
|
|
179
|
-
def where_sql
|
179
|
+
def where_sql engine = Table.engine
|
180
180
|
return if @ctx.wheres.empty?
|
181
181
|
|
182
|
-
viz = Visitors::WhereSql.new
|
182
|
+
viz = Visitors::WhereSql.new(engine.connection.visitor, engine.connection)
|
183
183
|
Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value
|
184
184
|
end
|
185
185
|
|