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.
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