arel 6.0.4 → 7.1.4
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 +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
|
|