arel 6.0.4 → 7.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +31 -12
  3. data/MIT-LICENSE.txt +2 -1
  4. data/{README.markdown → README.md} +88 -31
  5. data/lib/arel.rb +1 -1
  6. data/lib/arel/attributes/attribute.rb +8 -0
  7. data/lib/arel/crud.rb +4 -3
  8. data/lib/arel/delete_manager.rb +6 -1
  9. data/lib/arel/insert_manager.rb +1 -1
  10. data/lib/arel/math.rb +24 -0
  11. data/lib/arel/nodes.rb +6 -38
  12. data/lib/arel/nodes/binary.rb +0 -2
  13. data/lib/arel/nodes/bind_param.rb +3 -0
  14. data/lib/arel/nodes/case.rb +57 -0
  15. data/lib/arel/nodes/casted.rb +44 -0
  16. data/lib/arel/nodes/delete_statement.rb +2 -0
  17. data/lib/arel/nodes/infix_operation.rb +36 -1
  18. data/lib/arel/nodes/matches.rb +3 -1
  19. data/lib/arel/nodes/regexp.rb +14 -0
  20. data/lib/arel/nodes/select_core.rb +5 -5
  21. data/lib/arel/nodes/table_alias.rb +6 -2
  22. data/lib/arel/nodes/unary.rb +6 -3
  23. data/lib/arel/nodes/unary_operation.rb +25 -0
  24. data/lib/arel/predications.rb +38 -14
  25. data/lib/arel/select_manager.rb +6 -6
  26. data/lib/arel/table.rb +34 -59
  27. data/lib/arel/tree_manager.rb +3 -8
  28. data/lib/arel/update_manager.rb +1 -1
  29. data/lib/arel/visitors.rb +1 -23
  30. data/lib/arel/visitors/depth_first.rb +14 -2
  31. data/lib/arel/visitors/dot.rb +12 -1
  32. data/lib/arel/visitors/informix.rb +6 -1
  33. data/lib/arel/visitors/mssql.rb +35 -3
  34. data/lib/arel/visitors/mysql.rb +8 -0
  35. data/lib/arel/visitors/oracle.rb +13 -2
  36. data/lib/arel/visitors/oracle12.rb +59 -0
  37. data/lib/arel/visitors/postgresql.rb +56 -4
  38. data/lib/arel/visitors/sqlite.rb +9 -0
  39. data/lib/arel/visitors/to_sql.rb +94 -52
  40. data/lib/arel/visitors/where_sql.rb +10 -1
  41. metadata +11 -6
@@ -38,9 +38,7 @@ module Arel
38
38
  LessThanOrEqual
39
39
  NotEqual
40
40
  NotIn
41
- NotRegexp
42
41
  Or
43
- Regexp
44
42
  Union
45
43
  UnionAll
46
44
  Intersect
@@ -1,6 +1,9 @@
1
1
  module Arel
2
2
  module Nodes
3
3
  class BindParam < Node
4
+ def ==(other)
5
+ other.is_a?(BindParam)
6
+ end
4
7
  end
5
8
  end
6
9
  end
@@ -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
@@ -1,6 +1,8 @@
1
1
  module Arel
2
2
  module Nodes
3
3
  class DeleteStatement < Arel::Nodes::Binary
4
+ attr_accessor :limit
5
+
4
6
  alias :relation :left
5
7
  alias :relation= :left=
6
8
  alias :wheres :right
@@ -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
@@ -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 :having, :source, :set_quantifier
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
- @having = nil
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
- @having = @having.clone if @having
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, @having, @windows
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.having == other.having &&
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 engine
17
- relation.engine
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
@@ -22,16 +22,19 @@ module Arel
22
22
 
23
23
  %w{
24
24
  Bin
25
+ Cube
26
+ DistinctOn
25
27
  Group
26
- Having
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
@@ -25,15 +25,15 @@ module Arel
25
25
  end
26
26
 
27
27
  def between other
28
- if other.begin == -Float::INFINITY
29
- if other.end == Float::INFINITY
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 == Float::INFINITY
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 == -Float::INFINITY # The range begins with negative infinity
75
- if other.end == Float::INFINITY
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 == Float::INFINITY
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 matches_any others, escape = nil
126
- grouping_any :matches, others, escape
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 matches_all others, escape = nil
130
- grouping_all :matches, others, escape
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 does_not_match other, escape = nil
134
- Nodes::DoesNotMatch.new self, quoted_node(other), escape
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
@@ -6,8 +6,8 @@ module Arel
6
6
 
7
7
  STRING_OR_SYMBOL_CLASS = [Symbol, String]
8
8
 
9
- def initialize engine, table = nil
10
- super(engine)
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 *exprs
122
- @ctx.having = Nodes::Having.new(collapse(exprs, @ctx.having))
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 @engine.connection
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