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 Base
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
-
#implies_context_change?(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_Array(o, parent) ⇒ Array
private
Visit elements of an array that it’s possible to visit – leave other elements untouched.
-
#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_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_context_change(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_context_change(k, v, parent) ⇒ Object
private
If there is no context change, we’ll just return the value unchanged, currently.
Methods inherited from Base
#accept, #can_visit?, can_visit?, #initialize, #quote, #quoted?, #visit
Constructor Details
This class inherits a constructor from Squeel::Visitors::Base
Instance Method Details
#implies_context_change?(v) ⇒ Boolean (private)
Returns Whether the given value implies a context change.
170 171 172 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 170 def implies_context_change?(v) can_visit?(v) end |
#visit_ActiveRecord_Relation(o, parent) ⇒ Arel::SelectManager (private)
Visit an ActiveRecord Relation, returning an Arel::SelectManager
164 165 166 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 164 def visit_ActiveRecord_Relation(o, parent) o.arel end |
#visit_Array(o, parent) ⇒ Array (private)
Visit elements of an array that it’s possible to visit – leave other elements untouched.
33 34 35 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 33 def visit_Array(o, parent) o.map { |v| can_visit?(v) ? visit(v, parent) : v }.flatten 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_context_change?(v) visit_with_context_change(k, v, parent) else visit_without_context_change(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.
155 156 157 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 155 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.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 101 def visit_Squeel_Nodes_Function(o, parent) args = o.args.map do |arg| case arg when Nodes::Function, Nodes::KeyPath, Nodes::As, Nodes::Literal visit(arg, parent) when Symbol, Nodes::Stub Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym]) else quote arg end end func = Arel::Nodes::NamedFunction.new(o.name, args) o.alias ? func.as(o.alias) : func 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.
73 74 75 76 77 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 73 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
62 63 64 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 62 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.
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 123 def visit_Squeel_Nodes_Operation(o, parent) args = o.args.map do |arg| case arg when Nodes::Function, Nodes::KeyPath, Nodes::As, Nodes::Literal visit(arg, parent) when Symbol, Nodes::Stub Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym]) 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.
84 85 86 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 84 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.
53 54 55 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 53 def visit_Squeel_Nodes_Stub(o, parent) contextualize(parent)[o.symbol] 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.
43 44 45 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 43 def visit_Symbol(o, parent) contextualize(parent)[o] end |
#visit_with_context_change(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.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 181 def visit_with_context_change(k, v, parent) 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 end |
#visit_without_context_change(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.
205 206 207 |
# File 'lib/squeel/visitors/attribute_visitor.rb', line 205 def visit_without_context_change(k, v, parent) v end |