Class: Squeel::Visitors::AttributeVisitor
- Defined in:
- lib/squeel/visitors/attribute_visitor.rb
Overview
A visitor that tries to convert visited nodes into Arel::Attributes or other nodes that can be used for grouping, ordering, and the like.
Constant Summary
Constants inherited from Visitor
Instance Attribute Summary
Attributes inherited from Visitor
Instance Method Summary collapse
-
#implies_hash_context_shift?(v) ⇒ Boolean
private
Whether the given value implies a context change.
-
#visit_ActiveRecord_Relation(o, parent) ⇒ Arel::SelectManager
private
Visit an ActiveRecord Relation, returning an Arel::SelectManager.
-
#visit_Hash(o, parent) ⇒ Array
private
Visit a Hash.
-
#visit_Squeel_Nodes_As(o, parent) ⇒ Arel::Nodes::As
private
Visit a Squeel As node, resulting in am ARel As node.
-
#visit_Squeel_Nodes_Function(o, parent) ⇒ Object
private
Visit a Function node.
-
#visit_Squeel_Nodes_Grouping(o, parent) ⇒ Arel::Nodes::Grouping
private
Visit a Squeel Grouping node, resulting in am ARel Grouping node.
-
#visit_Squeel_Nodes_KeyPath(o, parent) ⇒ Object
private
Visit a keypath.
-
#visit_Squeel_Nodes_Literal(o, parent) ⇒ Arel::Nodes::SqlLiteral
private
Visit a Literal by converting it to an ARel SqlLiteral.
-
#visit_Squeel_Nodes_Operation(o, parent) ⇒ Object
private
Visit an Operation node.
-
#visit_Squeel_Nodes_Order(o, parent) ⇒ Arel::Nodes::Ordering
private
Visit an Order node.
-
#visit_Squeel_Nodes_Stub(o, parent) ⇒ Arel::Attribute
private
Visit a stub.
-
#visit_Symbol(o, parent) ⇒ Arel::Attribute
private
Visit a symbol.
-
#visit_with_hash_context_shift(k, v, parent) ⇒ Object
private
Change context (by setting the new parent to the result of a #find or #traverse on the key), then accept the given value.
-
#visit_without_hash_context_shift(k, v, parent) ⇒ Object
private
If there is no context change, we’ll just return the value unchanged, currently.
Methods inherited from Visitor
#accept, #can_visit?, can_visit?, #hash_context_shifted?, #initialize, #quote, #quoted?, #visit, #visit_Array, #visit_passthrough
Constructor Details
This class inherits a constructor from Squeel::Visitors::Visitor
Instance Method Details
#implies_hash_context_shift?(v) ⇒ Boolean (private)
Returns Whether the given value implies a context change.
169 170 171 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 169 def implies_hash_context_shift?(v) can_visit?(v) end |
#visit_ActiveRecord_Relation(o, parent) ⇒ Arel::SelectManager (private)
Visit an ActiveRecord Relation, returning an Arel::SelectManager
163 164 165 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 163 def visit_ActiveRecord_Relation(o, parent) o.arel end |
#visit_Hash(o, parent) ⇒ Array (private)
Visit a Hash. This entails iterating through each key and value and visiting each value in turn.
17 18 19 20 21 22 23 24 25 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 17 def visit_Hash(o, parent) o.map do |k, v| if implies_hash_context_shift?(v) visit_with_hash_context_shift(k, v, parent) else visit_without_hash_context_shift(k, v, parent) end end.flatten end |
#visit_Squeel_Nodes_As(o, parent) ⇒ Arel::Nodes::As (private)
Visit a Squeel As node, resulting in am ARel As node.
154 155 156 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 154 def visit_Squeel_Nodes_As(o, parent) visit(o.left, parent).as(o.right) end |
#visit_Squeel_Nodes_Function(o, parent) ⇒ Object (private)
Visit a Function node. Each function argument will be visiteded or contextualized if appropriate. Keep in mind that this occurs with the current parent within the context.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 91 def visit_Squeel_Nodes_Function(o, parent) args = o.args.map do |arg| case arg when Nodes::Function, Nodes::KeyPath, Nodes::As, Nodes::Literal, Nodes::Grouping visit(arg, parent) when Symbol, Nodes::Stub Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_s]) else quote arg end end func = Arel::Nodes::NamedFunction.new(o.name, args) o.alias ? func.as(o.alias) : func end |
#visit_Squeel_Nodes_Grouping(o, parent) ⇒ Arel::Nodes::Grouping (private)
Visit a Squeel Grouping node, resulting in am ARel Grouping node.
145 146 147 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 145 def visit_Squeel_Nodes_Grouping(o, parent) Arel::Nodes::Grouping.new(visit(o.expr, parent)) end |
#visit_Squeel_Nodes_KeyPath(o, parent) ⇒ Object (private)
Visit a keypath. This will traverse the keypath’s “path”, setting a new parent as though the keypath’s endpoint was in a deeply-nested hash, then visit the endpoint with the new parent.
63 64 65 66 67 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 63 def visit_Squeel_Nodes_KeyPath(o, parent) parent = traverse(o, parent) visit(o.endpoint, parent) end |
#visit_Squeel_Nodes_Literal(o, parent) ⇒ Arel::Nodes::SqlLiteral (private)
Visit a Literal by converting it to an ARel SqlLiteral
52 53 54 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 52 def visit_Squeel_Nodes_Literal(o, parent) Arel.sql(o.expr) end |
#visit_Squeel_Nodes_Operation(o, parent) ⇒ Object (private)
Visit an Operation node. Each operand will be accepted or contextualized if appropriate. Keep in mind that this occurs with the current parent within the context.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 113 def visit_Squeel_Nodes_Operation(o, parent) args = o.args.map do |arg| case arg when Nodes::Function, Nodes::KeyPath, Nodes::As, Nodes::Literal, Nodes::Grouping visit(arg, parent) when Symbol, Nodes::Stub Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_s]) else quote arg end end op = case o.operator when :+ Arel::Nodes::Addition.new(args[0], args[1]) when :- Arel::Nodes::Subtraction.new(args[0], args[1]) when :* Arel::Nodes::Multiplication.new(args[0], args[1]) when :/ Arel::Nodes::Division.new(args[0], args[1]) else Arel.sql("#{arel_visitor.accept(args[0])} #{o.operator} #{arel_visitor.accept(args[1])}") end o.alias ? op.as(o.alias) : op end |
#visit_Squeel_Nodes_Order(o, parent) ⇒ Arel::Nodes::Ordering (private)
Visit an Order node.
74 75 76 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 74 def visit_Squeel_Nodes_Order(o, parent) visit(o.expr, parent).send(o.descending? ? :desc : :asc) end |
#visit_Squeel_Nodes_Stub(o, parent) ⇒ Arel::Attribute (private)
Visit a stub. This will return an attribute named after the stub against the current parent’s contextualized table.
43 44 45 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 43 def visit_Squeel_Nodes_Stub(o, parent) contextualize(parent)[o.to_s] end |
#visit_Symbol(o, parent) ⇒ Arel::Attribute (private)
Visit a symbol. This will return an attribute named after the symbol against the current parent’s contextualized table.
33 34 35 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 33 def visit_Symbol(o, parent) contextualize(parent)[o] end |
#visit_with_hash_context_shift(k, v, parent) ⇒ Object (private)
Change context (by setting the new parent to the result of a #find or #traverse on the key), then accept the given value.
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 180 def visit_with_hash_context_shift(k, v, parent) @hash_context_depth += 1 parent = case k when Nodes::KeyPath traverse(k, parent, true) else find(k, parent) end if Array === v v.map {|val| visit(val, parent || k)} else can_visit?(v) ? visit(v, parent || k) : v end ensure @hash_context_depth -= 1 end |
#visit_without_hash_context_shift(k, v, parent) ⇒ Object (private)
If there is no context change, we’ll just return the value unchanged, currently. Is this really the right behavior? I don’t think so, but it works in this case.
208 209 210 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 208 def visit_without_hash_context_shift(k, v, parent) v end |