squeel 1.0.9 → 1.0.11

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