Module: Squeel::Visitors::PredicateVisitation
- Included in:
- OrderVisitor, PredicateVisitor, SelectVisitor
- Defined in:
- lib/squeel/visitors/predicate_visitation.rb
Constant Summary collapse
- EXPAND_BELONGS_TO_METHODS =
[:eq, :not_eq]
- TRUE_SQL =
Arel.sql('1=1').freeze
- FALSE_SQL =
Arel.sql('1=0').freeze
Instance Method Summary collapse
-
#arel_predicate_for(attribute, value, parent) ⇒ Arel::Nodes::Node
private
Determine whether to use IN or equality testing for a predicate, based on its value class, then return the appropriate predicate.
- #attribute_in_array(attribute, array) ⇒ Object private
- #attribute_not_in_array(attribute, array) ⇒ Object private
-
#quote_for_node(node, v) ⇒ Object
private
Certain nodes require us to do the quoting before the Arel visitor gets a chance to try, because we want to avoid having our values quoted as a type of the last visited column.
-
#visit_Squeel_Nodes_Predicate(o, parent) ⇒ Object
private
Visit a Squeel predicate, converting it into an Arel predicate.
-
#visit_Squeel_Nodes_Sifter(o, parent) ⇒ Object
private
Visit a Squeel sifter by executing its corresponding constraint block in the parent’s class, with its given arguments, then visiting the result.
Instance Method Details
#arel_predicate_for(attribute, value, parent) ⇒ Arel::Nodes::Node (private)
Determine whether to use IN or equality testing for a predicate, based on its value class, then return the appropriate predicate.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/squeel/visitors/predicate_visitation.rb', line 77 def arel_predicate_for(attribute, value, parent) if ActiveRecord::Relation === value && value.select_values.empty? value = visit(value.select(value.klass.arel_table[value.klass.primary_key]), parent) else value = can_visit?(value) ? visit(value, parent) : value end case value when Array attribute_in_array(attribute, value) when Range, Arel::SelectManager attribute.in(value) else attribute.eq(value) end end |
#attribute_in_array(attribute, array) ⇒ Object (private)
94 95 96 97 98 99 100 101 102 103 |
# File 'lib/squeel/visitors/predicate_visitation.rb', line 94 def attribute_in_array(attribute, array) if array.empty? FALSE_SQL elsif array.include? nil array = array.compact array.empty? ? attribute.eq(nil) : attribute.in(array).or(attribute.eq nil) else attribute.in array end end |
#attribute_not_in_array(attribute, array) ⇒ Object (private)
105 106 107 108 109 110 111 112 113 114 |
# File 'lib/squeel/visitors/predicate_visitation.rb', line 105 def attribute_not_in_array(attribute, array) if array.empty? TRUE_SQL elsif array.include? nil array = array.compact array.empty? ? attribute.not_eq(nil) : attribute.not_in(array).and(attribute.not_eq nil) else attribute.not_in array end end |
#quote_for_node(node, v) ⇒ Object (private)
Certain nodes require us to do the quoting before the Arel visitor gets a chance to try, because we want to avoid having our values quoted as a type of the last visited column. Otherwise, we can end up with annoyances like having “joe” quoted to 0, if the last visited column was of an integer type.
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/squeel/visitors/predicate_visitation.rb', line 124 def quote_for_node(node, v) case node when Nodes::Function, Nodes::Literal quote(v) when Nodes::Predicate quote_for_node(node.expr, v) else v end end |
#visit_Squeel_Nodes_Predicate(o, parent) ⇒ Object (private)
Visit a Squeel predicate, converting it into an Arel predicate
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/squeel/visitors/predicate_visitation.rb', line 29 def visit_Squeel_Nodes_Predicate(o, parent) value = o.value # Short-circuit for stuff like `where{ author.eq User.first }` # This filthy hack emulates similar behavior in AR PredicateBuilder if ActiveRecord::Base === value && EXPAND_BELONGS_TO_METHODS.include?(o.method_name) && association = classify(parent).reflect_on_association( symbolify(o.expr) ) return (o, parent, association) end case value when Nodes::KeyPath value = can_visit?(value.endpoint) ? visit(value, parent) : contextualize(traverse(value, parent))[value.endpoint.to_s] when ActiveRecord::Relation value = visit( value.select_values.empty? ? value.select(value.klass.arel_table[value.klass.primary_key]) : value, parent ) else value = visit(value, parent) if can_visit?(value) end value = quote_for_node(o.expr, value) attribute = case o.expr when Nodes::Stub, Nodes::Function, Nodes::Literal, Nodes::Grouping visit(o.expr, parent) else contextualize(parent)[o.expr] end if Array === value && [:in, :not_in].include?(o.method_name) o.method_name == :in ? attribute_in_array(attribute, value) : attribute_not_in_array(attribute, value) else attribute.send(o.method_name, value) end end |
#visit_Squeel_Nodes_Sifter(o, parent) ⇒ Object (private)
Visit a Squeel sifter by executing its corresponding constraint block in the parent’s class, with its given arguments, then visiting the result.
18 19 20 21 |
# File 'lib/squeel/visitors/predicate_visitation.rb', line 18 def visit_Squeel_Nodes_Sifter(o, parent) klass = classify(parent) visit(klass.send("sifter_#{o.name}", *o.args), parent) end |