squeel 1.1.1 → 1.2.1

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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +36 -4
  5. data/CHANGELOG.md +15 -0
  6. data/Gemfile +1 -1
  7. data/README.md +47 -6
  8. data/Rakefile +14 -2
  9. data/lib/squeel.rb +9 -1
  10. data/lib/squeel/adapters/active_record.rb +0 -1
  11. data/lib/squeel/adapters/active_record/3.0/join_dependency_extensions.rb +1 -0
  12. data/lib/squeel/adapters/active_record/3.0/relation_extensions.rb +12 -1
  13. data/lib/squeel/adapters/active_record/3.1/join_dependency_extensions.rb +1 -0
  14. data/lib/squeel/adapters/active_record/3.2/join_dependency_extensions.rb +1 -0
  15. data/lib/squeel/adapters/active_record/4.0/join_dependency_extensions.rb +1 -0
  16. data/lib/squeel/adapters/active_record/4.0/relation_extensions.rb +92 -0
  17. data/lib/squeel/adapters/active_record/4.1/compat.rb +15 -0
  18. data/lib/squeel/adapters/active_record/4.1/context.rb +88 -0
  19. data/lib/squeel/adapters/active_record/4.1/preloader_extensions.rb +31 -0
  20. data/lib/squeel/adapters/active_record/4.1/reflection_extensions.rb +37 -0
  21. data/lib/squeel/adapters/active_record/4.1/relation_extensions.rb +307 -0
  22. data/lib/squeel/adapters/active_record/4.2/compat.rb +1 -0
  23. data/lib/squeel/adapters/active_record/4.2/context.rb +1 -0
  24. data/lib/squeel/adapters/active_record/4.2/preloader_extensions.rb +1 -0
  25. data/lib/squeel/adapters/active_record/4.2/relation_extensions.rb +108 -0
  26. data/lib/squeel/adapters/active_record/context.rb +7 -7
  27. data/lib/squeel/adapters/active_record/join_dependency_extensions.rb +9 -13
  28. data/lib/squeel/adapters/active_record/relation_extensions.rb +38 -8
  29. data/lib/squeel/core_ext/symbol.rb +3 -3
  30. data/lib/squeel/dsl.rb +1 -1
  31. data/lib/squeel/nodes.rb +1 -0
  32. data/lib/squeel/nodes/as.rb +12 -0
  33. data/lib/squeel/nodes/join.rb +8 -4
  34. data/lib/squeel/nodes/key_path.rb +10 -1
  35. data/lib/squeel/nodes/node.rb +21 -0
  36. data/lib/squeel/nodes/stub.rb +8 -4
  37. data/lib/squeel/nodes/subquery_join.rb +44 -0
  38. data/lib/squeel/version.rb +1 -1
  39. data/lib/squeel/visitors.rb +2 -0
  40. data/lib/squeel/visitors/enumeration_visitor.rb +101 -0
  41. data/lib/squeel/visitors/order_visitor.rb +9 -2
  42. data/lib/squeel/visitors/predicate_visitor.rb +11 -0
  43. data/lib/squeel/visitors/preload_visitor.rb +12 -0
  44. data/lib/squeel/visitors/visitor.rb +89 -13
  45. data/spec/config.travis.yml +13 -0
  46. data/spec/config.yml +12 -0
  47. data/spec/console.rb +3 -12
  48. data/spec/core_ext/symbol_spec.rb +3 -3
  49. data/spec/helpers/squeel_helper.rb +8 -5
  50. data/spec/spec_helper.rb +4 -16
  51. data/spec/squeel/adapters/active_record/context_spec.rb +8 -4
  52. data/spec/squeel/adapters/active_record/join_dependency_extensions_spec.rb +123 -38
  53. data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +350 -124
  54. data/spec/squeel/core_ext/symbol_spec.rb +3 -3
  55. data/spec/squeel/nodes/join_spec.rb +4 -4
  56. data/spec/squeel/nodes/stub_spec.rb +3 -3
  57. data/spec/squeel/nodes/subquery_join_spec.rb +46 -0
  58. data/spec/squeel/visitors/order_visitor_spec.rb +3 -3
  59. data/spec/squeel/visitors/predicate_visitor_spec.rb +69 -36
  60. data/spec/squeel/visitors/select_visitor_spec.rb +1 -1
  61. data/spec/squeel/visitors/visitor_spec.rb +7 -6
  62. data/spec/support/models.rb +99 -15
  63. data/spec/support/schema.rb +109 -4
  64. data/squeel.gemspec +8 -6
  65. metadata +89 -107
  66. data/.ruby-gemset +0 -1
  67. data/.ruby-version +0 -1
  68. data/spec/blueprints/articles.rb +0 -5
  69. data/spec/blueprints/comments.rb +0 -5
  70. data/spec/blueprints/notes.rb +0 -3
  71. data/spec/blueprints/people.rb +0 -4
  72. data/spec/blueprints/tags.rb +0 -3
@@ -3,6 +3,12 @@ require 'squeel/context'
3
3
  module Squeel
4
4
  module Adapters
5
5
  module ActiveRecord
6
+ JoinPart = if defined?(::ActiveRecord::Associations::JoinDependency::JoinPart)
7
+ ::ActiveRecord::Associations::JoinDependency::JoinPart
8
+ elsif defined?(::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase)
9
+ ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase
10
+ end
11
+
6
12
  class Context < ::Squeel::Context
7
13
 
8
14
  def initialize(object)
@@ -23,7 +29,7 @@ module Squeel
23
29
  }
24
30
  when Nodes::Join
25
31
  @object.join_associations.detect { |j|
26
- j.reflection.name == object.name && j.parent == parent &&
32
+ j.reflection.name == object._name && j.parent == parent &&
27
33
  (object.polymorphic? ? j.reflection.klass == object._klass : true)
28
34
  }
29
35
  else
@@ -73,12 +79,6 @@ module Squeel
73
79
  end
74
80
 
75
81
  end
76
-
77
- if defined?(::ActiveRecord::Associations::JoinDependency::JoinPart)
78
- JoinPart = ::ActiveRecord::Associations::JoinDependency::JoinPart
79
- elsif defined?(::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase)
80
- JoinPart = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase
81
- end
82
82
  end
83
83
  end
84
84
  end
@@ -1,17 +1,22 @@
1
- require 'polyamorous'
2
-
3
1
  module Squeel
4
2
  module Adapters
5
3
  module ActiveRecord
6
- module JoinDependencyExtensions
4
+ if defined?(::ActiveRecord::Associations::JoinDependency)
5
+ JoinAssociation = ::ActiveRecord::Associations::JoinDependency::JoinAssociation
6
+ JoinDependency = ::ActiveRecord::Associations::JoinDependency
7
+ elsif defined?(::ActiveRecord::Associations::ClassMethods::JoinDependency)
8
+ JoinAssociation = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation
9
+ JoinDependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency
10
+ end
7
11
 
12
+ module JoinDependencyExtensions
8
13
  def self.included(base)
9
14
  base.class_eval do
10
15
  alias_method_chain :build, :squeel
11
16
  end
12
17
  end
13
18
 
14
- def build_with_squeel(associations, parent = nil, join_type = Arel::InnerJoin)
19
+ def build_with_squeel(associations, parent = nil, join_type = InnerJoin)
15
20
  case associations
16
21
  when Nodes::Stub
17
22
  associations = associations.symbol
@@ -29,15 +34,6 @@ module Squeel
29
34
  build_without_squeel(associations, parent, join_type)
30
35
  end
31
36
  end
32
-
33
- end
34
-
35
- if defined?(::ActiveRecord::Associations::JoinDependency)
36
- JoinAssociation = ::ActiveRecord::Associations::JoinDependency::JoinAssociation
37
- JoinDependency = ::ActiveRecord::Associations::JoinDependency
38
- elsif defined?(::ActiveRecord::Associations::ClassMethods::JoinDependency)
39
- JoinAssociation = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation
40
- JoinDependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency
41
37
  end
42
38
 
43
39
  JoinDependency.send :include, Adapters::ActiveRecord::JoinDependencyExtensions
@@ -45,7 +45,6 @@ module Squeel
45
45
  merge_resolving_duplicate_squeel_equalities(r)
46
46
  end
47
47
  else
48
- puts r.inspect if r.is_a?(Proc)
49
48
  super(r)
50
49
  end
51
50
  end
@@ -115,6 +114,8 @@ module Squeel
115
114
  :stashed_join
116
115
  when Arel::Nodes::Join
117
116
  :join_node
117
+ when Nodes::SubqueryJoin
118
+ :subquery_join
118
119
  else
119
120
  raise 'unknown class: %s' % join.class.name
120
121
  end
@@ -123,6 +124,7 @@ module Squeel
123
124
  association_joins = buckets[:association_join] || []
124
125
  stashed_association_joins = buckets[:stashed_join] || []
125
126
  join_nodes = (buckets[:join_node] || []).uniq
127
+ subquery_joins = (buckets[:subquery_join] || []).uniq
126
128
  string_joins = (buckets[:string_join] || []).map { |x|
127
129
  x.strip
128
130
  }.uniq
@@ -144,11 +146,12 @@ module Squeel
144
146
  association.join_to(manager)
145
147
  end
146
148
 
147
- manager.join_sources.concat join_list
149
+ manager.join_sources.concat(join_list)
150
+ manager.join_sources.concat(build_join_from_subquery(subquery_joins))
148
151
 
149
152
  manager
150
153
  end
151
- # For 4.x adapters
154
+ # For 4.0 adapters
152
155
  alias :build_joins :build_join_dependency
153
156
 
154
157
  def includes(*args)
@@ -279,12 +282,12 @@ module Squeel
279
282
  end
280
283
  end
281
284
 
282
- def find_equality_predicates(nodes)
285
+ def find_equality_predicates(nodes, relation_table_name = table_name)
283
286
  nodes.map { |node|
284
287
  case node
285
288
  when Arel::Nodes::Equality
286
289
  if node.left.respond_to?(:relation) &&
287
- node.left.relation.name == table_name
290
+ node.left.relation.name == relation_table_name
288
291
  node
289
292
  end
290
293
  when Arel::Nodes::Grouping
@@ -395,9 +398,8 @@ module Squeel
395
398
  # your model's default scope. We hijack it in order to dig down into
396
399
  # And and Grouping nodes, which are equivalent to seeing top-level
397
400
  # Equality nodes in stock AR terms.
398
- def where_values_hash_with_squeel
399
- equalities = find_equality_predicates(where_visit(with_default_scope.where_values))
400
-
401
+ def where_values_hash_with_squeel(relation_table_name = table_name)
402
+ equalities = find_equality_predicates(where_visit(with_default_scope.where_values), relation_table_name)
401
403
  binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
402
404
 
403
405
  Hash[equalities.map { |where|
@@ -406,6 +408,34 @@ module Squeel
406
408
  }]
407
409
  end
408
410
 
411
+ def build_join_from_subquery(subquery_joins)
412
+ subquery_joins.map do |join|
413
+ join.type.new(
414
+ Arel::Nodes::TableAlias.new(
415
+ Arel::Nodes::Grouping.new(join.subquery.left.arel.ast),
416
+ join.subquery.right),
417
+ Arel::Nodes::On.new(where_visit(join.constraints))
418
+ )
419
+ end
420
+ end
421
+
422
+ def preprocess_attrs_with_ar(attributes)
423
+ attributes.map do |key, value|
424
+ case key
425
+ when Squeel::Nodes::Node
426
+ {key => value}
427
+ when Symbol
428
+ if value.is_a?(Hash)
429
+ {key => value}
430
+ else
431
+ ::ActiveRecord::PredicateBuilder.build_from_hash(klass, {key => value}, table)
432
+ end
433
+ else
434
+ ::ActiveRecord::PredicateBuilder.build_from_hash(klass, {key => value}, table)
435
+ end
436
+ end
437
+ end
438
+
409
439
  end
410
440
  end
411
441
  end
@@ -15,15 +15,15 @@ class Symbol
15
15
  end
16
16
 
17
17
  def inner
18
- Squeel::Nodes::Join.new(self, Arel::InnerJoin)
18
+ Squeel::Nodes::Join.new(self, Squeel::InnerJoin)
19
19
  end
20
20
 
21
21
  def outer
22
- Squeel::Nodes::Join.new(self, Arel::OuterJoin)
22
+ Squeel::Nodes::Join.new(self, Squeel::OuterJoin)
23
23
  end
24
24
 
25
25
  def of_class(klass)
26
- Squeel::Nodes::Join.new(self, Arel::InnerJoin, klass)
26
+ Squeel::Nodes::Join.new(self, Squeel::InnerJoin, klass)
27
27
  end
28
28
 
29
29
  end
@@ -110,7 +110,7 @@ module Squeel
110
110
  if args.empty?
111
111
  Nodes::Stub.new method_id
112
112
  elsif (args.size == 1) && (Class === args[0])
113
- Nodes::Join.new(method_id, Arel::InnerJoin, args[0])
113
+ Nodes::Join.new(method_id, InnerJoin, args[0])
114
114
  else
115
115
  Nodes::Function.new method_id, args
116
116
  end
@@ -27,3 +27,4 @@ require 'squeel/nodes/as'
27
27
  require 'squeel/nodes/not'
28
28
  require 'squeel/nodes/join'
29
29
  require 'squeel/nodes/grouping'
30
+ require 'squeel/nodes/subquery_join'
@@ -12,6 +12,18 @@ module Squeel
12
12
  def initialize(left, right)
13
13
  @left, @right = left, right
14
14
  end
15
+
16
+ def on(*args)
17
+ raise "only can convert ActiveRecord::Relation to a join node" unless left.is_a?(ActiveRecord::Relation)
18
+ proc =
19
+ if block_given?
20
+ DSL.eval(&Proc.new)
21
+ else
22
+ args
23
+ end
24
+
25
+ SubqueryJoin.new(self, proc)
26
+ end
15
27
  end
16
28
  end
17
29
  end
@@ -14,21 +14,21 @@ module Squeel
14
14
  # @param [Symbol] name The association name
15
15
  # @param [Arel::InnerJoin, Arel::OuterJoin] type The Arel join class
16
16
  # @param [Class, String, Symbol] klass The polymorphic belongs_to class or class name
17
- def initialize(name, type = Arel::InnerJoin, klass = nil)
17
+ def initialize(name, type = InnerJoin, klass = nil)
18
18
  @_join = Polyamorous::Join.new(name, type, klass)
19
19
  end
20
20
 
21
21
  # Set the join type to an inner join
22
22
  # @return [Join] The join, with an updated join type.
23
23
  def inner
24
- self._type = Arel::InnerJoin
24
+ self._type = InnerJoin
25
25
  self
26
26
  end
27
27
 
28
28
  # Set the join type to an outer join
29
29
  # @return [Join] The join, with an updated join type.
30
30
  def outer
31
- self._type = Arel::OuterJoin
31
+ self._type = OuterJoin
32
32
  self
33
33
  end
34
34
 
@@ -61,7 +61,7 @@ module Squeel
61
61
  def method_missing(method_id, *args)
62
62
  super if method_id == :to_ary
63
63
  if (args.size == 1) && (Class === args[0])
64
- KeyPath.new([self, Join.new(method_id, Arel::InnerJoin, args[0])])
64
+ KeyPath.new([self, Join.new(method_id, InnerJoin, args[0])])
65
65
  else
66
66
  KeyPath.new([self, method_id])
67
67
  end
@@ -83,6 +83,10 @@ module Squeel
83
83
  nil
84
84
  end
85
85
 
86
+ def add_to_tree(hash)
87
+ hash[_join] ||= {}
88
+ end
89
+
86
90
  end
87
91
  end
88
92
  end
@@ -177,6 +177,10 @@ module Squeel
177
177
  end
178
178
  alias :to_str :to_s
179
179
 
180
+ def add_to_tree(hash)
181
+ walk_through_path(path.dup, hash)
182
+ end
183
+
180
184
  # Appends to the KeyPath or delegates to the endpoint, as appropriate
181
185
  # @return [KeyPath] The updated KeyPath
182
186
  def method_missing(method_id, *args, &block)
@@ -194,7 +198,7 @@ module Squeel
194
198
  if args.empty?
195
199
  @path << Stub.new(method_id)
196
200
  elsif (args.size == 1) && (Class === args[0])
197
- @path << Join.new(method_id, Arel::InnerJoin, args[0])
201
+ @path << Join.new(method_id, InnerJoin, args[0])
198
202
  else
199
203
  @path << Nodes::Function.new(method_id, args)
200
204
  end
@@ -213,6 +217,11 @@ module Squeel
213
217
  @path = @path.dup
214
218
  end
215
219
 
220
+ def walk_through_path(path, hash)
221
+ cache = path.shift.add_to_tree(hash)
222
+ path.empty? ? cache : walk_through_path(path, cache)
223
+ end
224
+
216
225
  # Raises a NoMethodError manually, bypassing #method_missing.
217
226
  # Used by special-case operator overrides.
218
227
  def no_method_error(method_id)
@@ -1,6 +1,27 @@
1
+ require 'polyamorous/tree_node'
2
+
1
3
  module Squeel
2
4
  module Nodes
3
5
  class Node
6
+ include ::Polyamorous::TreeNode
7
+
8
+ def each(&block)
9
+ return enum_for(:each) unless block_given?
10
+
11
+ Visitors::EnumerationVisitor.new(block).accept(self)
12
+ end
13
+
14
+ # We don't want the full Enumerable method list, because it will mess
15
+ # with stuff like KeyPath
16
+ def grep(object, &block)
17
+ if block_given?
18
+ each { |value| yield value if object === value }
19
+ else
20
+ [].tap do |results|
21
+ each { |value| results << value if object === value }
22
+ end
23
+ end
24
+ end
4
25
  end
5
26
  end
6
27
  end
@@ -79,7 +79,7 @@ module Squeel
79
79
  if args.empty?
80
80
  KeyPath.new([self, method_id])
81
81
  elsif (args.size == 1) && (Class === args[0])
82
- KeyPath.new([self, Join.new(method_id, Arel::InnerJoin, args[0])])
82
+ KeyPath.new([self, Join.new(method_id, InnerJoin, args[0])])
83
83
  else
84
84
  KeyPath.new([self, Nodes::Function.new(method_id, args)])
85
85
  end
@@ -102,7 +102,7 @@ module Squeel
102
102
  # Create an inner Join node for the association named by this Stub
103
103
  # @return [Join] The new inner Join node
104
104
  def inner
105
- Join.new(self.symbol, Arel::InnerJoin)
105
+ Join.new(self.symbol, InnerJoin)
106
106
  end
107
107
 
108
108
  # Create a keypath with a sifter as its endpoint
@@ -114,14 +114,18 @@ module Squeel
114
114
  # Create an outer Join node for the association named by this Stub
115
115
  # @return [Join] The new outer Join node
116
116
  def outer
117
- Join.new(self.symbol, Arel::OuterJoin)
117
+ Join.new(self.symbol, OuterJoin)
118
118
  end
119
119
 
120
120
  # Create a polymorphic Join node for the association named by this Stub,
121
121
  # @param [Class] klass The polymorphic belongs_to class for this Join
122
122
  # @return [Join] The new polymorphic Join node
123
123
  def of_class(klass)
124
- Join.new(self.symbol, Arel::InnerJoin, klass)
124
+ Join.new(self.symbol, InnerJoin, klass)
125
+ end
126
+
127
+ def add_to_tree(hash)
128
+ hash[symbol] ||= {}
125
129
  end
126
130
 
127
131
  end
@@ -0,0 +1,44 @@
1
+ module Squeel
2
+ module Nodes
3
+ class SubqueryJoin < Node
4
+ attr_accessor :subquery, :type, :constraints
5
+
6
+ def initialize(subquery, constraints, type = Squeel::InnerJoin)
7
+ raise ArgumentError,
8
+ "subquery(#{subquery}) isn't an Squeel::Nodes::As" unless subquery.is_a?(As)
9
+
10
+ raise ArgumentError,
11
+ "constraints(#{constraints}) isn't a Squeel::Nodes::Node" unless constraints.is_a?(Node)
12
+
13
+ self.subquery = subquery
14
+ self.constraints = constraints
15
+ self.type = type
16
+ end
17
+
18
+ # Implemented for equality testing
19
+ def hash
20
+ [subquery, type, constraints].hash
21
+ end
22
+
23
+ def inner
24
+ self.type = Squeel::InnerJoin
25
+ self
26
+ end
27
+
28
+ def outer
29
+ self.type = Squeel::OuterJoin
30
+ self
31
+ end
32
+
33
+ # Compare with other objects
34
+ def eql?(other)
35
+ self.class.eql?(other.class) &&
36
+ self.subquery.eql?(other.subquery) &&
37
+ self.type.eql?(other.type) &&
38
+ self.constraints.eql?(other.constraints)
39
+ end
40
+ alias :== :eql?
41
+
42
+ end
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  module Squeel
2
- VERSION = '1.1.1'
2
+ VERSION = '1.2.1'
3
3
  end
@@ -8,3 +8,5 @@ require 'squeel/visitors/order_visitor'
8
8
  require 'squeel/visitors/select_visitor'
9
9
  require 'squeel/visitors/from_visitor'
10
10
  require 'squeel/visitors/preload_visitor'
11
+
12
+ require 'squeel/visitors/enumeration_visitor'
@@ -0,0 +1,101 @@
1
+ require 'active_support/core_ext/module'
2
+ require 'squeel/nodes'
3
+
4
+ module Squeel
5
+ module Visitors
6
+ # The Enumeration visitor class, used to implement Node#each
7
+ class EnumerationVisitor
8
+
9
+ # Create a new EnumerationVisitor.
10
+ #
11
+ # @param [Proc] block The block to execute against each node.
12
+ def initialize(block = Proc.new)
13
+ @block = block
14
+ end
15
+
16
+ # Accept an object.
17
+ #
18
+ # @param object The object to visit
19
+ # @return The results of the node visitation, which will be the last
20
+ # call to the @block
21
+ def accept(object)
22
+ visit(object)
23
+ end
24
+
25
+ private
26
+ # A hash that caches the method name to use for a visitor for a given
27
+ # class
28
+ DISPATCH = Hash.new do |hash, klass|
29
+ hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}"
30
+ end
31
+
32
+ # Visit the object.
33
+ #
34
+ # @param object The object to visit
35
+ def visit(object)
36
+ send(DISPATCH[object.class], object)
37
+ @block.call(object)
38
+ rescue NoMethodError => e
39
+ raise e if respond_to?(DISPATCH[object.class], true)
40
+
41
+ superklass = object.class.ancestors.find { |klass|
42
+ respond_to?(DISPATCH[klass], true)
43
+ }
44
+ raise(TypeError, "Cannot visit #{object.class}") unless superklass
45
+ DISPATCH[object.class] = DISPATCH[superklass]
46
+ retry
47
+ end
48
+
49
+ def visit_terminal(o)
50
+ end
51
+ alias :visit_Object :visit_terminal
52
+
53
+ def visit_Array(o)
54
+ o.map { |v| visit(v) }
55
+ end
56
+
57
+ def visit_Hash(o)
58
+ o.each { |k, v| visit(k); visit(v) }
59
+ end
60
+
61
+ def visit_Squeel_Nodes_Nary(o)
62
+ visit(o.children)
63
+ end
64
+
65
+ def visit_Squeel_Nodes_Binary(o)
66
+ visit(o.left)
67
+ visit(o.right)
68
+ end
69
+
70
+ def visit_Squeel_Nodes_Unary(o)
71
+ visit(o.expr)
72
+ end
73
+
74
+ def visit_Squeel_Nodes_Order(o)
75
+ visit(o.expr)
76
+ end
77
+
78
+ def visit_Squeel_Nodes_Function(o)
79
+ visit(o.args)
80
+ end
81
+
82
+ def visit_Squeel_Nodes_Predicate(o)
83
+ visit(o.expr)
84
+ visit(o.value)
85
+ end
86
+
87
+ def visit_Squeel_Nodes_KeyPath(o)
88
+ visit(o.path)
89
+ end
90
+
91
+ def visit_Squeel_Nodes_Join(o)
92
+ visit(o._join)
93
+ end
94
+
95
+ def visit_Squeel_Nodes_Literal(o)
96
+ visit(o.expr)
97
+ end
98
+
99
+ end
100
+ end
101
+ end