squeel 1.0.9 → 1.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CHANGELOG.md +10 -0
  2. data/lib/squeel.rb +5 -0
  3. data/lib/squeel/adapters/active_record/3.0/association_preload_extensions.rb +2 -2
  4. data/lib/squeel/adapters/active_record/3.0/relation_extensions.rb +98 -46
  5. data/lib/squeel/adapters/active_record/3.1/preloader_extensions.rb +2 -2
  6. data/lib/squeel/adapters/active_record/3.1/relation_extensions.rb +71 -85
  7. data/lib/squeel/adapters/active_record/base_extensions.rb +0 -19
  8. data/lib/squeel/adapters/active_record/relation_extensions.rb +6 -9
  9. data/lib/squeel/nodes/binary.rb +4 -0
  10. data/lib/squeel/nodes/function.rb +10 -0
  11. data/lib/squeel/nodes/nary.rb +1 -1
  12. data/lib/squeel/nodes/order.rb +11 -1
  13. data/lib/squeel/nodes/predicate.rb +2 -2
  14. data/lib/squeel/nodes/stub.rb +2 -0
  15. data/lib/squeel/nodes/unary.rb +4 -0
  16. data/lib/squeel/version.rb +1 -1
  17. data/lib/squeel/visitors.rb +10 -3
  18. data/lib/squeel/visitors/from_visitor.rb +6 -0
  19. data/lib/squeel/visitors/group_visitor.rb +6 -0
  20. data/lib/squeel/visitors/having_visitor.rb +9 -0
  21. data/lib/squeel/visitors/order_visitor.rb +20 -0
  22. data/lib/squeel/visitors/predicate_visitation.rb +126 -0
  23. data/lib/squeel/visitors/predicate_visitor.rb +3 -326
  24. data/lib/squeel/visitors/{symbol_visitor.rb → preload_visitor.rb} +4 -4
  25. data/lib/squeel/visitors/select_visitor.rb +7 -0
  26. data/lib/squeel/visitors/visitor.rb +244 -12
  27. data/lib/squeel/visitors/where_visitor.rb +8 -0
  28. data/spec/helpers/squeel_helper.rb +14 -1
  29. data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +65 -49
  30. data/spec/squeel/nodes/as_spec.rb +20 -0
  31. data/spec/squeel/nodes/function_spec.rb +6 -0
  32. data/spec/squeel/nodes/grouping_spec.rb +6 -0
  33. data/spec/squeel/nodes/key_path_spec.rb +3 -3
  34. data/spec/squeel/nodes/operation_spec.rb +6 -0
  35. data/spec/squeel/nodes/order_spec.rb +6 -1
  36. data/spec/squeel/nodes/predicate_operators_spec.rb +1 -1
  37. data/spec/squeel/nodes/predicate_spec.rb +14 -1
  38. data/spec/squeel/nodes/sifter_spec.rb +2 -1
  39. data/spec/squeel/nodes/stub_spec.rb +4 -0
  40. data/spec/squeel/visitors/order_visitor_spec.rb +36 -0
  41. data/spec/squeel/visitors/{symbol_visitor_spec.rb → preload_visitor_spec.rb} +4 -3
  42. data/spec/squeel/visitors/select_visitor_spec.rb +26 -0
  43. data/spec/squeel/visitors/{attribute_visitor_spec.rb → visitor_spec.rb} +23 -37
  44. data/spec/support/models.rb +4 -0
  45. metadata +22 -10
  46. data/lib/squeel/visitors/attribute_visitor.rb +0 -214
@@ -16,25 +16,6 @@ module Squeel
16
16
  end
17
17
  end
18
18
 
19
- def build_default_scope_with_squeel #:nodoc:
20
- if defined?(::ActiveRecord::Scoping) &&
21
- method(:default_scope).owner != ::ActiveRecord::Scoping::Default::ClassMethods
22
- evaluate_default_scope { default_scope }
23
- elsif default_scopes.any?
24
- evaluate_default_scope do
25
- default_scopes.inject(relation) do |default_scope, scope|
26
- if scope.is_a?(Hash)
27
- default_scope.apply_finder_options(scope)
28
- elsif !scope.is_a?(::ActiveRecord::Relation) && scope.respond_to?(:call)
29
- default_scope.merge(scope.call, true)
30
- else
31
- default_scope.merge(scope, true)
32
- end
33
- end
34
- end
35
- end
36
- end
37
-
38
19
  end
39
20
  end
40
21
  end
@@ -10,26 +10,23 @@ module Squeel
10
10
 
11
11
  build_join_dependency(arel, @joins_values) unless @joins_values.empty?
12
12
 
13
- predicate_viz = predicate_visitor
14
- attribute_viz = attribute_visitor
13
+ collapse_wheres(arel, where_visit((@where_values - ['']).uniq))
15
14
 
16
- collapse_wheres(arel, predicate_viz.accept((@where_values - ['']).uniq))
17
-
18
- arel.having(*predicate_viz.accept(@having_values.uniq.reject{|h| h.blank?})) unless @having_values.empty?
15
+ arel.having(*having_visit(@having_values.uniq.reject{|h| h.blank?})) unless @having_values.empty?
19
16
 
20
17
  arel.take(connection.sanitize_limit(@limit_value)) if @limit_value
21
18
  arel.skip(@offset_value) if @offset_value
22
19
 
23
- arel.group(*attribute_viz.accept(@group_values.uniq.reject{|g| g.blank?})) unless @group_values.empty?
20
+ arel.group(*group_visit(@group_values.uniq.reject{|g| g.blank?})) unless @group_values.empty?
24
21
 
25
- order = attribute_viz.accept(@order_values)
22
+ order = order_visit(@order_values)
26
23
  order = reverse_sql_order(attrs_to_orderings(order)) if @reverse_order_value
27
24
  arel.order(*order.uniq.reject{|o| o.blank?}) unless order.empty?
28
25
 
29
- build_select(arel, attribute_viz.accept(@select_values.uniq))
26
+ build_select(arel, select_visit(@select_values.uniq))
30
27
 
31
28
  arel.distinct(@uniq_value)
32
- arel.from(@from_value) if @from_value
29
+ arel.from(from_visit(@from_value)) if @from_value
33
30
  arel.lock(@lock_value) if @lock_value
34
31
 
35
32
  arel
@@ -17,6 +17,10 @@ module Squeel
17
17
  @left, @right = left, right
18
18
  end
19
19
 
20
+ def hash
21
+ [@left, @right].hash
22
+ end
23
+
20
24
  # Comparison with other nodes
21
25
  def eql?(other)
22
26
  self.class.eql?(other.class) &&
@@ -42,6 +42,16 @@ module Squeel
42
42
  nil
43
43
  end
44
44
 
45
+ def hash
46
+ [@name, @args].hash
47
+ end
48
+
49
+ def eql?(other)
50
+ self.class == other.class &&
51
+ self.name.eql?(other.name) &&
52
+ self.args.eql?(other.args)
53
+ end
54
+
45
55
  end
46
56
  end
47
57
  end
@@ -35,7 +35,7 @@ module Squeel
35
35
 
36
36
  # Implemented for equality testing
37
37
  def hash
38
- [self.class].concat(self.children).hash
38
+ @children.hash
39
39
  end
40
40
 
41
41
  # Object comparison
@@ -48,6 +48,16 @@ module Squeel
48
48
  @direction = - @direction
49
49
  self
50
50
  end
51
+
52
+ def hash
53
+ [@expr, @direction].hash
54
+ end
55
+
56
+ def eql?(other)
57
+ self.class.eql?(other.class) &&
58
+ self.expr.eql?(other.expr) &&
59
+ self.direction.eql?(other.direction)
60
+ end
51
61
  end
52
62
  end
53
- end
63
+ end
@@ -8,6 +8,7 @@ module Squeel
8
8
  class Predicate
9
9
 
10
10
  include PredicateOperators
11
+ include Aliasing
11
12
 
12
13
  # @return The right-hand value being considered in this predicate.
13
14
  attr_accessor :value
@@ -34,11 +35,10 @@ module Squeel
34
35
  self.method_name.eql?(other.method_name) &&
35
36
  self.value.eql?(other.value)
36
37
  end
37
- alias :== :eql?
38
38
 
39
39
  # Implemented for equality testing
40
40
  def hash
41
- [self.class, expr, method_name, value].hash
41
+ [@expr, @method_name, @value].hash
42
42
  end
43
43
 
44
44
  # Whether the value has been assigned yet.
@@ -39,6 +39,8 @@ module Squeel
39
39
 
40
40
  # Object comparison
41
41
  def eql?(other)
42
+ # Should we maybe allow a stub to equal a symbol?
43
+ # I can see not doing to leading to confusion, but I don't like it. :(
42
44
  self.class.eql?(other.class) &&
43
45
  self.symbol.eql?(other.symbol)
44
46
  end
@@ -14,6 +14,10 @@ module Squeel
14
14
  @expr = expr
15
15
  end
16
16
 
17
+ def hash
18
+ @expr.hash
19
+ end
20
+
17
21
  # Object comparison
18
22
  def eql?(other)
19
23
  self.class.eql?(other.class) &&
@@ -1,3 +1,3 @@
1
1
  module Squeel
2
- VERSION = "1.0.9"
2
+ VERSION = "1.0.11"
3
3
  end
@@ -1,3 +1,10 @@
1
- require 'squeel/visitors/predicate_visitor'
2
- require 'squeel/visitors/attribute_visitor'
3
- require 'squeel/visitors/symbol_visitor'
1
+ require 'squeel/visitors/visitor'
2
+ require 'squeel/visitors/predicate_visitation'
3
+
4
+ require 'squeel/visitors/where_visitor'
5
+ require 'squeel/visitors/having_visitor'
6
+ require 'squeel/visitors/group_visitor'
7
+ require 'squeel/visitors/order_visitor'
8
+ require 'squeel/visitors/select_visitor'
9
+ require 'squeel/visitors/from_visitor'
10
+ require 'squeel/visitors/preload_visitor'
@@ -0,0 +1,6 @@
1
+ module Squeel
2
+ module Visitors
3
+ class FromVisitor < Visitor
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Squeel
2
+ module Visitors
3
+ class GroupVisitor < Visitor
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ require 'squeel/visitors/predicate_visitor'
2
+
3
+ module Squeel
4
+ module Visitors
5
+ class HavingVisitor < PredicateVisitor
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,20 @@
1
+ module Squeel
2
+ module Visitors
3
+ class OrderVisitor < Visitor
4
+ include PredicateVisitation
5
+
6
+ private
7
+
8
+ # Visit an Order node.
9
+ #
10
+ # @param [Nodes::Order] o The order node to visit
11
+ # @param parent The node's parent within the context
12
+ # @return [Arel::Nodes::Ordering] An ascending or desending ordering
13
+ def visit_Squeel_Nodes_Order(o, parent)
14
+ visit(o.expr, parent).send(o.descending? ? :desc : :asc)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,126 @@
1
+ module Squeel
2
+ module Visitors
3
+ module PredicateVisitation
4
+
5
+ private
6
+
7
+ TRUE_SQL = Arel.sql('1=1').freeze
8
+ FALSE_SQL = Arel.sql('1=0').freeze
9
+
10
+ # Visit a Squeel sifter by executing its corresponding constraint block
11
+ # in the parent's class, with its given arguments, then visiting the
12
+ # result.
13
+ #
14
+ # @param [Nodes::Sifter] o The Sifter to visit
15
+ # @param parent The parent object in the context
16
+ # @return The result of visiting the executed block's return value
17
+ def visit_Squeel_Nodes_Sifter(o, parent)
18
+ klass = classify(parent)
19
+ visit(klass.send(o.name, *o.args), parent)
20
+ end
21
+
22
+ # Visit a Squeel predicate, converting it into an ARel predicate
23
+ #
24
+ # @param [Nodes::Predicate] o The predicate to visit
25
+ # @param parent The parent object in the context
26
+ # @return An ARel predicate node
27
+ # (Arel::Nodes::Equality, Arel::Nodes::Matches, etc)
28
+ def visit_Squeel_Nodes_Predicate(o, parent)
29
+ value = o.value
30
+
31
+ case value
32
+ when Nodes::KeyPath
33
+ value = can_visit?(value.endpoint) ? visit(value, parent) : contextualize(traverse(value, parent))[value.endpoint.to_s]
34
+ when ActiveRecord::Relation
35
+ value = visit(
36
+ value.select_values.empty? ? value.select(value.klass.arel_table[value.klass.primary_key]) : value,
37
+ parent
38
+ )
39
+ else
40
+ value = visit(value, parent) if can_visit?(value)
41
+ end
42
+
43
+ value = quote_for_node(o.expr, value)
44
+
45
+ attribute = case o.expr
46
+ when Nodes::Stub, Nodes::Function, Nodes::Literal, Nodes::Grouping
47
+ visit(o.expr, parent)
48
+ else
49
+ contextualize(parent)[o.expr]
50
+ end
51
+
52
+ if Array === value && [:in, :not_in].include?(o.method_name)
53
+ o.method_name == :in ? attribute_in_array(attribute, value) : attribute_not_in_array(attribute, value)
54
+ else
55
+ attribute.send(o.method_name, value)
56
+ end
57
+ end
58
+
59
+ # Determine whether to use IN or equality testing for a predicate,
60
+ # based on its value class, then return the appropriate predicate.
61
+ #
62
+ # @param attribute The ARel attribute (or function/operation) the
63
+ # predicate will be created for
64
+ # @param value The value to be compared against
65
+ # @return [Arel::Nodes::Node] An ARel predicate node
66
+ def arel_predicate_for(attribute, value, parent)
67
+ if ActiveRecord::Relation === value && value.select_values.empty?
68
+ value = visit(value.select(value.klass.arel_table[value.klass.primary_key]), parent)
69
+ else
70
+ value = can_visit?(value) ? visit(value, parent) : value
71
+ end
72
+
73
+ case value
74
+ when Array
75
+ attribute_in_array(attribute, value)
76
+ when Range, Arel::SelectManager
77
+ attribute.in(value)
78
+ else
79
+ attribute.eq(value)
80
+ end
81
+ end
82
+
83
+ def attribute_in_array(attribute, array)
84
+ if array.empty?
85
+ FALSE_SQL
86
+ elsif array.include? nil
87
+ array = array.compact
88
+ array.empty? ? attribute.eq(nil) : attribute.in(array).or(attribute.eq nil)
89
+ else
90
+ attribute.in array
91
+ end
92
+ end
93
+
94
+ def attribute_not_in_array(attribute, array)
95
+ if array.empty?
96
+ TRUE_SQL
97
+ elsif array.include? nil
98
+ array = array.compact
99
+ array.empty? ? attribute.not_eq(nil) : attribute.not_in(array).and(attribute.not_eq nil)
100
+ else
101
+ attribute.not_in array
102
+ end
103
+ end
104
+
105
+ # Certain nodes require us to do the quoting before the ARel
106
+ # visitor gets a chance to try, because we want to avoid having our
107
+ # values quoted as a type of the last visited column. Otherwise, we
108
+ # can end up with annoyances like having "joe" quoted to 0, if the
109
+ # last visited column was of an integer type.
110
+ #
111
+ # @param node The node we (might) be quoting for
112
+ # @param v The value to (possibly) quote
113
+ def quote_for_node(node, v)
114
+ case node
115
+ when Nodes::Function, Nodes::Literal
116
+ quote(v)
117
+ when Nodes::Predicate
118
+ quote_for_node(node.expr, v)
119
+ else
120
+ v
121
+ end
122
+ end
123
+
124
+ end
125
+ end
126
+ end
@@ -1,11 +1,10 @@
1
1
  require 'squeel/visitors/visitor'
2
+ require 'squeel/visitors/predicate_visitation'
2
3
 
3
4
  module Squeel
4
5
  module Visitors
5
6
  class PredicateVisitor < Visitor
6
-
7
- TRUE_SQL = Arel.sql('1=1').freeze
8
- FALSE_SQL = Arel.sql('1=0').freeze
7
+ include PredicateVisitation
9
8
 
10
9
  private
11
10
 
@@ -16,15 +15,7 @@ module Squeel
16
15
  # @param parent The current parent object in the context
17
16
  # @return [Array] An array of values for use in a where or having clause
18
17
  def visit_Hash(o, parent)
19
- predicates = o.map do |k, v|
20
- if implies_hash_context_shift?(v)
21
- visit_with_hash_context_shift(k, v, parent)
22
- else
23
- visit_without_hash_context_shift(k, v, parent)
24
- end
25
- end
26
-
27
- predicates.flatten!
18
+ predicates = super
28
19
 
29
20
  if predicates.size > 1
30
21
  Arel::Nodes::Grouping.new(Arel::Nodes::And.new predicates)
@@ -33,222 +24,6 @@ module Squeel
33
24
  end
34
25
  end
35
26
 
36
- # Visit ActiveRecord::Base objects. These should be converted to their
37
- # id before being used in a comparison.
38
- #
39
- # @param [ActiveRecord::Base] o The AR::Base object to visit
40
- # @param parent The current parent object in the context
41
- # @return [Fixnum] The id of the object
42
- def visit_ActiveRecord_Base(o, parent)
43
- o.id
44
- end
45
-
46
- # Visit a KeyPath by traversing the path and then visiting the endpoint.
47
- #
48
- # @param [Nodes::KeyPath] o The KeyPath to visit
49
- # @param parent The parent object in the context
50
- # @return The visited endpoint, in the context of the KeyPath's path
51
- def visit_Squeel_Nodes_KeyPath(o, parent)
52
- parent = traverse(o, parent)
53
-
54
- visit(o.endpoint, parent)
55
- end
56
-
57
- # Visit a symbol. This will return an attribute named after the symbol against
58
- # the current parent's contextualized table.
59
- #
60
- # @param [Symbol] o The symbol to visit
61
- # @param parent The symbol's parent within the context
62
- # @return [Arel::Attribute] An attribute on the contextualized parent table
63
- def visit_Symbol(o, parent)
64
- contextualize(parent)[o]
65
- end
66
-
67
- # Visit a Stub by converting it to an ARel attribute
68
- #
69
- # @param [Nodes::Stub] o The Stub to visit
70
- # @param parent The parent object in the context
71
- # @return [Arel::Attribute] An attribute of the parent table with the
72
- # Stub's column
73
- def visit_Squeel_Nodes_Stub(o, parent)
74
- contextualize(parent)[o.to_s]
75
- end
76
-
77
- # Visit a Literal by converting it to an ARel SqlLiteral
78
- #
79
- # @param [Nodes::Literal] o The Literal to visit
80
- # @param parent The parent object in the context (unused)
81
- # @return [Arel::Nodes::SqlLiteral] An SqlLiteral
82
- def visit_Squeel_Nodes_Literal(o, parent)
83
- Arel.sql(o.expr)
84
- end
85
-
86
- # Visit a Squeel sifter by executing its corresponding constraint block
87
- # in the parent's class, with its given arguments, then visiting the result.
88
- #
89
- # @param [Nodes::Sifter] o The Sifter to visit
90
- # @param parent The parent object in the context
91
- # @return The result of visiting the executed block's return value
92
- def visit_Squeel_Nodes_Sifter(o, parent)
93
- klass = classify(parent)
94
- visit(klass.send(o.name, *o.args), parent)
95
- end
96
-
97
- # Visit a Squeel predicate, converting it into an ARel predicate
98
- #
99
- # @param [Nodes::Predicate] o The predicate to visit
100
- # @param parent The parent object in the context
101
- # @return An ARel predicate node
102
- # (Arel::Nodes::Equality, Arel::Nodes::Matches, etc)
103
- def visit_Squeel_Nodes_Predicate(o, parent)
104
- value = o.value
105
-
106
- case value
107
- when Nodes::KeyPath
108
- value = can_visit?(value.endpoint) ? visit(value, parent) : contextualize(traverse(value, parent))[value.endpoint.to_s]
109
- when ActiveRecord::Relation
110
- value = visit(
111
- value.select_values.empty? ? value.select(value.klass.arel_table[value.klass.primary_key]) : value,
112
- parent
113
- )
114
- else
115
- value = visit(value, parent) if can_visit?(value)
116
- end
117
-
118
- value = quote_for_node(o.expr, value)
119
-
120
- attribute = case o.expr
121
- when Nodes::Stub, Nodes::Function, Nodes::Literal, Nodes::Grouping
122
- visit(o.expr, parent)
123
- else
124
- contextualize(parent)[o.expr]
125
- end
126
-
127
- if Array === value && [:in, :not_in].include?(o.method_name)
128
- o.method_name == :in ? attribute_in_array(attribute, value) : attribute_not_in_array(attribute, value)
129
- else
130
- attribute.send(o.method_name, value)
131
- end
132
- end
133
-
134
- # Visit a Squeel function, returning an ARel NamedFunction node.
135
- #
136
- # @param [Nodes::Function] o The function node to visit
137
- # @param parent The parent object in the context
138
- # @return [Arel::Nodes::NamedFunction] A named function node. Function
139
- # arguments are visited, if necessary, before being passed to the NamedFunction.
140
- def visit_Squeel_Nodes_Function(o, parent)
141
- args = o.args.map do |arg|
142
- case arg
143
- when Nodes::Function, Nodes::As, Nodes::Literal, Nodes::Grouping
144
- visit(arg, parent)
145
- when ActiveRecord::Relation
146
- arg.arel.ast
147
- when Nodes::KeyPath
148
- can_visit?(arg.endpoint) ? visit(arg, parent) : contextualize(traverse(arg, parent))[arg.endpoint.to_s]
149
- when Symbol, Nodes::Stub
150
- Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_s])
151
- else
152
- quote arg
153
- end
154
- end
155
-
156
- Arel::Nodes::NamedFunction.new(o.name, args)
157
- end
158
-
159
- # Visit an ActiveRecord Relation, returning an Arel::SelectManager
160
- # @param [ActiveRecord::Relation] o The Relation to visit
161
- # @param parent The parent object in the context
162
- # @return [Arel::SelectManager] The ARel select manager that represents
163
- # the relation's query
164
- def visit_ActiveRecord_Relation(o, parent)
165
- o.arel
166
- end
167
-
168
- # Visit a Squeel operation node, convering it to an ARel InfixOperation
169
- # (or subclass, as appropriate)
170
- #
171
- # @param [Nodes::Operation] o The Operation node to visit
172
- # @param parent The parent object in the context
173
- # @return [Arel::Nodes::InfixOperation] The InfixOperation (or Addition,
174
- # Multiplication, etc) node, with both operands visited, if needed.
175
- def visit_Squeel_Nodes_Operation(o, parent)
176
- args = o.args.map do |arg|
177
- case arg
178
- when Nodes::Function, Nodes::As, Nodes::Literal, Nodes::Grouping
179
- visit(arg, parent)
180
- when Nodes::KeyPath
181
- can_visit?(arg.endpoint) ? visit(arg, parent) : contextualize(traverse(arg, parent))[arg.endpoint.to_s]
182
- when Symbol, Nodes::Stub
183
- Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_s])
184
- else
185
- quote arg
186
- end
187
- end
188
-
189
- op = case o.operator
190
- when :+
191
- Arel::Nodes::Addition.new(args[0], args[1])
192
- when :-
193
- Arel::Nodes::Subtraction.new(args[0], args[1])
194
- when :*
195
- Arel::Nodes::Multiplication.new(args[0], args[1])
196
- when :/
197
- Arel::Nodes::Division.new(args[0], args[1])
198
- else
199
- Arel::Nodes::InfixOperation.new(o.operator, args[0], args[1])
200
- end
201
-
202
- op
203
- end
204
-
205
- # Visit a Squeel And node, returning an ARel Grouping containing an
206
- # ARel And node.
207
- #
208
- # @param [Nodes::And] o The And node to visit
209
- # @param parent The parent object in the context
210
- # @return [Arel::Nodes::Grouping] A grouping node, containnig an ARel
211
- # And node as its expression. All children will be visited before
212
- # being passed to the And.
213
- def visit_Squeel_Nodes_And(o, parent)
214
- Arel::Nodes::Grouping.new(Arel::Nodes::And.new(visit(o.children, parent)))
215
- end
216
-
217
- # Visit a Squeel Or node, returning an ARel Or node.
218
- #
219
- # @param [Nodes::Or] o The Or node to visit
220
- # @param parent The parent object in the context
221
- # @return [Arel::Nodes::Or] An ARel Or node, with left and right sides visited
222
- def visit_Squeel_Nodes_Or(o, parent)
223
- Arel::Nodes::Grouping.new(Arel::Nodes::Or.new(visit(o.left, parent), (visit(o.right, parent))))
224
- end
225
-
226
- # Visit a Squeel Not node, returning an ARel Not node.
227
- #
228
- # @param [Nodes::Not] o The Not node to visit
229
- # @param parent The parent object in the context
230
- # @return [Arel::Nodes::Not] An ARel Not node, with expression visited
231
- def visit_Squeel_Nodes_Not(o, parent)
232
- Arel::Nodes::Not.new(visit(o.expr, parent))
233
- end
234
-
235
- # Visit a Squeel Grouping node, returning an ARel Grouping node.
236
- #
237
- # @param [Nodes::Grouping] o The Grouping node to visit
238
- # @param parent The parent object in the context
239
- # @return [Arel::Nodes::Grouping] An ARel Grouping node, with expression visited
240
- def visit_Squeel_Nodes_Grouping(o, parent)
241
- Arel::Nodes::Grouping.new(visit(o.expr, parent))
242
- end
243
-
244
- # Visit a Squeel As node, resulting in am ARel As node.
245
- #
246
- # @param [Nodes::As] The As node to visit
247
- # @param parent The parent object in the context
248
- # @return [Arel::Nodes::As] The resulting as node.
249
- def visit_Squeel_Nodes_As(o, parent)
250
- visit(o.left, parent).as(o.right)
251
- end
252
27
 
253
28
  # @return [Boolean] Whether the given value implies a context change
254
29
  # @param v The value to consider
@@ -263,39 +38,6 @@ module Squeel
263
38
  end
264
39
  end
265
40
 
266
- # Change context (by setting the new parent to the result of a #find or
267
- # #traverse on the key), then accept the given value.
268
- #
269
- # @param k The hash key
270
- # @param v The hash value
271
- # @param parent The current parent object in the context
272
- # @return The visited value
273
- def visit_with_hash_context_shift(k, v, parent)
274
- @hash_context_depth += 1
275
-
276
- parent = case k
277
- when Nodes::KeyPath
278
- traverse(k, parent, true)
279
- else
280
- find(k, parent)
281
- end
282
-
283
- case v
284
- when Hash, Nodes::KeyPath, Nodes::Predicate, Nodes::Unary, Nodes::Binary, Nodes::Nary, Nodes::Sifter
285
- visit(v, parent || k)
286
- when Array
287
- v.map {|val| visit(val, parent || k)}
288
- else
289
- raise ArgumentError, <<-END
290
- Hashes, Predicates, and arrays of visitables as values imply that their
291
- corresponding keys are a parent. This didn't work out so well in the case
292
- of key = #{k} and value = #{v}"
293
- END
294
- end
295
- ensure
296
- @hash_context_depth -= 1
297
- end
298
-
299
41
  # Create a predicate for a given key/value pair. If the value is
300
42
  # a Symbol, Stub, or KeyPath, it's converted to a table.column for
301
43
  # the predicate value.
@@ -331,71 +73,6 @@ module Squeel
331
73
  end
332
74
  end
333
75
 
334
- # Determine whether to use IN or equality testing for a predicate,
335
- # based on its value class, then return the appropriate predicate.
336
- #
337
- # @param attribute The ARel attribute (or function/operation) the
338
- # predicate will be created for
339
- # @param value The value to be compared against
340
- # @return [Arel::Nodes::Node] An ARel predicate node
341
- def arel_predicate_for(attribute, value, parent)
342
- if ActiveRecord::Relation === value && value.select_values.empty?
343
- value = visit(value.select(value.klass.arel_table[value.klass.primary_key]), parent)
344
- else
345
- value = can_visit?(value) ? visit(value, parent) : value
346
- end
347
-
348
- case value
349
- when Array
350
- attribute_in_array(attribute, value)
351
- when Range, Arel::SelectManager
352
- attribute.in(value)
353
- else
354
- attribute.eq(value)
355
- end
356
- end
357
-
358
- def attribute_in_array(attribute, array)
359
- if array.empty?
360
- FALSE_SQL
361
- elsif array.include? nil
362
- array = array.compact
363
- array.empty? ? attribute.eq(nil) : attribute.in(array).or(attribute.eq nil)
364
- else
365
- attribute.in array
366
- end
367
- end
368
-
369
- def attribute_not_in_array(attribute, array)
370
- if array.empty?
371
- TRUE_SQL
372
- elsif array.include? nil
373
- array = array.compact
374
- array.empty? ? attribute.not_eq(nil) : attribute.not_in(array).and(attribute.not_eq nil)
375
- else
376
- attribute.not_in array
377
- end
378
- end
379
-
380
- # Certain nodes require us to do the quoting before the ARel
381
- # visitor gets a chance to try, because we want to avoid having our
382
- # values quoted as a type of the last visited column. Otherwise, we
383
- # can end up with annoyances like having "joe" quoted to 0, if the
384
- # last visited column was of an integer type.
385
- #
386
- # @param node The node we (might) be quoting for
387
- # @param v The value to (possibly) quote
388
- def quote_for_node(node, v)
389
- case node
390
- when Nodes::Function, Nodes::Literal
391
- quote(v)
392
- when Nodes::Predicate
393
- quote_for_node(node.expr, v)
394
- else
395
- v
396
- end
397
- end
398
-
399
76
  end
400
77
  end
401
78
  end