Class: Squeel::Visitors::PredicateVisitor

Inherits:
Base
  • Object
show all
Defined in:
lib/squeel/visitors/predicate_visitor.rb

Instance Attribute Summary

Attributes inherited from Base

#context

Instance Method Summary collapse

Methods inherited from Base

#accept, #can_accept?, can_accept?, #initialize

Constructor Details

This class inherits a constructor from Squeel::Visitors::Base

Instance Method Details

#arel_predicate_for(attribute, value, parent) ⇒ Object



170
171
172
173
174
175
176
177
# File 'lib/squeel/visitors/predicate_visitor.rb', line 170

def arel_predicate_for(attribute, value, parent)
  if [Array, Range, Arel::SelectManager].include?(value.class)
    attribute.in(value)
  else
    value = can_accept?(value) ? accept(value, parent) : value
    attribute.eq(value)
  end
end

#implies_context_change?(v) ⇒ Boolean

Returns:

  • (Boolean)


114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/squeel/visitors/predicate_visitor.rb', line 114

def implies_context_change?(v)
  case v
  when Hash, Nodes::Predicate, Nodes::Unary, Nodes::Binary, Nodes::Nary
    true
  when Nodes::KeyPath
    can_accept?(v.endpoint) && !(Nodes::Stub === v.endpoint)
  when Array
    (!v.empty? && v.all? {|val| can_accept?(val)})
  else
    false
  end
end

#visit_ActiveRecord_Relation(o, parent) ⇒ Object



69
70
71
# File 'lib/squeel/visitors/predicate_visitor.rb', line 69

def visit_ActiveRecord_Relation(o, parent)
  o.arel
end

#visit_Array(o, parent) ⇒ Object



25
26
27
# File 'lib/squeel/visitors/predicate_visitor.rb', line 25

def visit_Array(o, parent)
  o.map { |v| can_accept?(v) ? accept(v, parent) : v }.flatten
end

#visit_Hash(o, parent) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/squeel/visitors/predicate_visitor.rb', line 7

def visit_Hash(o, parent)
  predicates = 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

  predicates.flatten!

  if predicates.size > 1
    Arel::Nodes::Grouping.new(Arel::Nodes::And.new predicates)
  else
    predicates.first
  end
end

#visit_Squeel_Nodes_And(o, parent) ⇒ Object



102
103
104
# File 'lib/squeel/visitors/predicate_visitor.rb', line 102

def visit_Squeel_Nodes_And(o, parent)
  Arel::Nodes::Grouping.new(Arel::Nodes::And.new(accept(o.children, parent)))
end

#visit_Squeel_Nodes_Function(o, parent) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/squeel/visitors/predicate_visitor.rb', line 53

def visit_Squeel_Nodes_Function(o, parent)
  args = o.args.map do |arg|
    case arg
    when Nodes::Function
      accept(arg, parent)
    when Nodes::KeyPath
      can_accept?(arg.endpoint) ? accept(arg, parent) : contextualize(traverse(arg, parent))[arg.endpoint.to_sym]
    when Symbol, Nodes::Stub
      Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym])
    else
      quoted?(arg) ? Arel.sql(arel_visitor.accept arg) : arg
    end
  end
  Arel::Nodes::NamedFunction.new(o.name, args, o.alias)
end

#visit_Squeel_Nodes_KeyPath(o, parent) ⇒ Object



29
30
31
32
33
# File 'lib/squeel/visitors/predicate_visitor.rb', line 29

def visit_Squeel_Nodes_KeyPath(o, parent)
  parent = traverse(o, parent)

  accept(o.endpoint, parent)
end

#visit_Squeel_Nodes_Not(o, parent) ⇒ Object



110
111
112
# File 'lib/squeel/visitors/predicate_visitor.rb', line 110

def visit_Squeel_Nodes_Not(o, parent)
  accept(o.expr, parent).not
end

#visit_Squeel_Nodes_Operation(o, parent) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/squeel/visitors/predicate_visitor.rb', line 73

def visit_Squeel_Nodes_Operation(o, parent)
  args = o.args.map do |arg|
    case arg
    when Nodes::Function
      accept(arg, parent)
    when Nodes::KeyPath
      can_accept?(arg.endpoint) ? accept(arg, parent) : contextualize(traverse(arg, parent))[arg.endpoint.to_sym]
    when Symbol, Nodes::Stub
      Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym])
    else
      quoted?(arg) ? Arel.sql(arel_visitor.accept arg) : 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::Nodes::InfixOperation(o.operator, args[0], args[1])
  end
  o.alias ? op.as(o.alias) : op
end

#visit_Squeel_Nodes_Or(o, parent) ⇒ Object



106
107
108
# File 'lib/squeel/visitors/predicate_visitor.rb', line 106

def visit_Squeel_Nodes_Or(o, parent)
  accept(o.left, parent).or(accept(o.right, parent))
end

#visit_Squeel_Nodes_Predicate(o, parent) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/squeel/visitors/predicate_visitor.rb', line 39

def visit_Squeel_Nodes_Predicate(o, parent)
  value = o.value
  if Nodes::KeyPath === value
    value = can_accept?(value.endpoint) ? accept(value, parent) : contextualize(traverse(value, parent))[value.endpoint.to_sym]
  else
    value = accept(value, parent) if can_accept?(value)
  end
  if Nodes::Function === o.expr
    accept(o.expr, parent).send(o.method_name, value)
  else
    contextualize(parent)[o.expr].send(o.method_name, value)
  end
end

#visit_Squeel_Nodes_Stub(o, parent) ⇒ Object



35
36
37
# File 'lib/squeel/visitors/predicate_visitor.rb', line 35

def visit_Squeel_Nodes_Stub(o, parent)
  contextualize(parent)[o.symbol]
end

#visit_with_context_change(k, v, parent) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/squeel/visitors/predicate_visitor.rb', line 127

def visit_with_context_change(k, v, parent)
  parent = case k
    when Nodes::KeyPath
      traverse(k, parent, true)
    else
      find(k, parent)
    end

  case v
  when Hash, Nodes::KeyPath, Nodes::Predicate, Nodes::Unary, Nodes::Binary, Nodes::Nary
    accept(v, parent || k)
  when Array
    v.map {|val| accept(val, parent || k)}
  else
    raise ArgumentError, <<-END
    Hashes, Predicates, and arrays of visitables as values imply that their
    corresponding keys are a parent. This didn't work out so well in the case
    of key = #{k} and value = #{v}"
    END
  end
end

#visit_without_context_change(k, v, parent) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/squeel/visitors/predicate_visitor.rb', line 149

def visit_without_context_change(k, v, parent)
  case v
  when Nodes::Stub, Symbol
    v = contextualize(parent)[v.to_sym]
  when Nodes::KeyPath # If we could accept the endpoint, we wouldn't be here
    v = contextualize(traverse(v, parent))[v.endpoint.to_sym]
  end

  case k
  when Nodes::Predicate
    accept(k % v, parent)
  when Nodes::Function
    arel_predicate_for(accept(k, parent), v, parent)
  when Nodes::KeyPath
    accept(k % v, parent)
  else
    attribute = contextualize(parent)[k.to_sym]
    arel_predicate_for(attribute, v, parent)
  end
end