squeel 1.0.1 → 1.0.2

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 (44) hide show
  1. data/CHANGELOG.md +20 -0
  2. data/README.md +1 -1
  3. data/lib/squeel.rb +1 -2
  4. data/lib/squeel/adapters/active_record.rb +3 -1
  5. data/lib/squeel/adapters/active_record/3.0/compat.rb +5 -1
  6. data/lib/squeel/adapters/active_record/3.0/context.rb +2 -2
  7. data/lib/squeel/adapters/active_record/3.1/compat.rb +22 -0
  8. data/lib/squeel/adapters/active_record/3.1/context.rb +2 -2
  9. data/lib/squeel/adapters/active_record/compat.rb +22 -0
  10. data/lib/squeel/adapters/active_record/join_dependency_extensions.rb +2 -2
  11. data/lib/squeel/configuration.rb +2 -2
  12. data/lib/squeel/core_ext/symbol.rb +3 -13
  13. data/lib/squeel/dsl.rb +10 -1
  14. data/lib/squeel/nodes.rb +9 -1
  15. data/lib/squeel/nodes/aliasing.rb +2 -2
  16. data/lib/squeel/nodes/as.rb +1 -1
  17. data/lib/squeel/nodes/binary.rb +1 -4
  18. data/lib/squeel/nodes/function.rb +1 -10
  19. data/lib/squeel/nodes/grouping.rb +35 -0
  20. data/lib/squeel/nodes/join.rb +3 -3
  21. data/lib/squeel/nodes/key_path.rb +26 -24
  22. data/lib/squeel/nodes/literal.rb +2 -17
  23. data/lib/squeel/nodes/nary.rb +1 -2
  24. data/lib/squeel/nodes/ordering.rb +21 -0
  25. data/lib/squeel/nodes/predicate.rb +1 -4
  26. data/lib/squeel/nodes/predicate_methods.rb +16 -0
  27. data/lib/squeel/nodes/stub.rb +11 -21
  28. data/lib/squeel/nodes/unary.rb +1 -4
  29. data/lib/squeel/version.rb +1 -1
  30. data/lib/squeel/visitors/attribute_visitor.rb +12 -13
  31. data/lib/squeel/visitors/predicate_visitor.rb +38 -15
  32. data/lib/squeel/visitors/symbol_visitor.rb +2 -6
  33. data/lib/squeel/visitors/visitor.rb +24 -1
  34. data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +6 -1
  35. data/spec/squeel/dsl_spec.rb +9 -1
  36. data/spec/squeel/nodes/grouping_spec.rb +177 -0
  37. data/spec/squeel/nodes/join_spec.rb +4 -5
  38. data/spec/squeel/nodes/key_path_spec.rb +3 -5
  39. data/spec/squeel/nodes/operators_spec.rb +3 -3
  40. data/spec/squeel/nodes/stub_spec.rb +6 -7
  41. data/spec/squeel/visitors/attribute_visitor_spec.rb +6 -1
  42. data/spec/squeel/visitors/predicate_visitor_spec.rb +28 -0
  43. metadata +62 -22
  44. data/lib/squeel/predicate_methods.rb +0 -14
@@ -1,7 +1,3 @@
1
- require 'squeel/predicate_methods'
2
- require 'squeel/nodes/operators'
3
- require 'squeel/nodes/aliasing'
4
-
5
1
  module Squeel
6
2
  module Nodes
7
3
  # Literal nodes are a container for raw SQL.
@@ -10,6 +6,7 @@ module Squeel
10
6
  include PredicateOperators
11
7
  include Operators
12
8
  include Aliasing
9
+ include Ordering
13
10
 
14
11
  attr_reader :expr
15
12
 
@@ -29,18 +26,6 @@ module Squeel
29
26
  alias :< :lt
30
27
  alias :<= :lteq
31
28
 
32
- # Create an ascending Order node with this Literal as its expression
33
- # @return [Order] The new Order node
34
- def asc
35
- Order.new self, 1
36
- end
37
-
38
- # Create a descending Order node with this Literal as its expression
39
- # @return [Order] The new Order node
40
- def desc
41
- Order.new self, -1
42
- end
43
-
44
29
  # Object comparison
45
30
  def eql?(other)
46
31
  self.class.eql?(other.class) &&
@@ -68,4 +53,4 @@ module Squeel
68
53
 
69
54
  end
70
55
  end
71
- end
56
+ end
@@ -43,8 +43,7 @@ module Squeel
43
43
  self.class.eql?(other.class) &&
44
44
  self.children.eql?(other.children)
45
45
  end
46
- alias :== :eql?
47
46
 
48
47
  end
49
48
  end
50
- end
49
+ end
@@ -0,0 +1,21 @@
1
+ require 'squeel/nodes/order'
2
+
3
+ module Squeel
4
+ module Nodes
5
+ module Ordering
6
+
7
+ # Create an ascending Order node with this Node as its expression
8
+ # @return [Order] The new Order node
9
+ def asc
10
+ Order.new self, 1
11
+ end
12
+
13
+ # Create a descending Order node with this Node as its expression
14
+ # @return [Order] The new Order node
15
+ def desc
16
+ Order.new self, -1
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,3 @@
1
- require 'squeel/predicate_methods'
2
- require 'squeel/nodes/predicate_operators'
3
-
4
1
  module Squeel
5
2
  module Nodes
6
3
  # This node is essentially a container that will result in ARel predicate nodes
@@ -68,4 +65,4 @@ module Squeel
68
65
 
69
66
  end
70
67
  end
71
- end
68
+ end
@@ -0,0 +1,16 @@
1
+ module Squeel
2
+ module Nodes
3
+ # Defines Predicate factories named for each of the ARel predication methods
4
+ module PredicateMethods
5
+
6
+ Constants::PREDICATES.each do |method_name|
7
+ class_eval <<-RUBY
8
+ def #{method_name}(value = :__undefined__)
9
+ Nodes::Predicate.new self, :#{method_name}, value
10
+ end
11
+ RUBY
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -1,7 +1,3 @@
1
- require 'squeel/predicate_methods'
2
- require 'squeel/nodes/operators'
3
- require 'squeel/nodes/aliasing'
4
-
5
1
  module Squeel
6
2
  module Nodes
7
3
  # Stub nodes are basically a container for a Symbol that can have handy predicate
@@ -11,6 +7,7 @@ module Squeel
11
7
  include PredicateMethods
12
8
  include Operators
13
9
  include Aliasing
10
+ include Ordering
14
11
 
15
12
  alias :== :eq
16
13
  alias :'^' :not_eq
@@ -62,6 +59,11 @@ module Squeel
62
59
  end
63
60
  alias :to_str :to_s
64
61
 
62
+ # @return [Array] An array with a copy of this Stub as the only element.
63
+ def to_a
64
+ [dup]
65
+ end
66
+
65
67
  # Create a KeyPath when any undefined method is called on a Stub.
66
68
  # @overload node_name
67
69
  # Creates a new KeyPath with this Stub as the base and the method_name as the endpoint
@@ -73,11 +75,11 @@ module Squeel
73
75
  def method_missing(method_id, *args)
74
76
  super if method_id == :to_ary
75
77
  if args.empty?
76
- KeyPath.new(self, method_id)
78
+ KeyPath.new([self, method_id])
77
79
  elsif (args.size == 1) && (Class === args[0])
78
- KeyPath.new(self, Join.new(method_id, Arel::InnerJoin, args[0]))
80
+ KeyPath.new([self, Join.new(method_id, Arel::InnerJoin, args[0])])
79
81
  else
80
- KeyPath.new(self, Nodes::Function.new(method_id, args))
82
+ KeyPath.new([self, Nodes::Function.new(method_id, args)])
81
83
  end
82
84
  end
83
85
 
@@ -86,19 +88,7 @@ module Squeel
86
88
  # DSL is likely to think of them as such.
87
89
  # @return [KeyPath] An absolute KeyPath, containing only this Stub
88
90
  def ~
89
- KeyPath.new [], self, true
90
- end
91
-
92
- # Create an ascending Order node with this Stub's symbol as its expression
93
- # @return [Order] The new Order node
94
- def asc
95
- Order.new self.symbol, 1
96
- end
97
-
98
- # Create a descending Order node with this Stub's symbol as its expression
99
- # @return [Order] The new Order node
100
- def desc
101
- Order.new self.symbol, -1
91
+ KeyPath.new [self], true
102
92
  end
103
93
 
104
94
  # Create a Function node for a function named the same as this Stub and with the given arguments
@@ -116,7 +106,7 @@ module Squeel
116
106
  # Create a keypath with a sifter as its endpoint
117
107
  # @return [KeyPath] The new KeyPath
118
108
  def sift(name, *args)
119
- KeyPath.new(self, Sifter.new(name, args))
109
+ KeyPath.new([self, Sifter.new(name, args)])
120
110
  end
121
111
 
122
112
  # Create an outer Join node for the association named by this Stub
@@ -1,5 +1,3 @@
1
- require 'squeel/nodes/predicate_operators'
2
-
3
1
  module Squeel
4
2
  module Nodes
5
3
  # A node that contains a single expression.
@@ -21,8 +19,7 @@ module Squeel
21
19
  self.class.eql?(other.class) &&
22
20
  self.expr.eql?(other.expr)
23
21
  end
24
- alias :== :eql?
25
22
 
26
23
  end
27
24
  end
28
- end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module Squeel
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
@@ -24,16 +24,6 @@ module Squeel
24
24
  end.flatten
25
25
  end
26
26
 
27
- # Visit elements of an array that it's possible to visit -- leave other
28
- # elements untouched.
29
- #
30
- # @param [Array] o The array to visit
31
- # @param parent The array's parent within the context
32
- # @return [Array] The flattened array with elements visited
33
- def visit_Array(o, parent)
34
- o.map { |v| can_visit?(v) ? visit(v, parent) : v }.flatten
35
- end
36
-
37
27
  # Visit a symbol. This will return an attribute named after the symbol against
38
28
  # the current parent's contextualized table.
39
29
  #
@@ -101,7 +91,7 @@ module Squeel
101
91
  def visit_Squeel_Nodes_Function(o, parent)
102
92
  args = o.args.map do |arg|
103
93
  case arg
104
- when Nodes::Function, Nodes::KeyPath, Nodes::As, Nodes::Literal
94
+ when Nodes::Function, Nodes::KeyPath, Nodes::As, Nodes::Literal, Nodes::Grouping
105
95
  visit(arg, parent)
106
96
  when Symbol, Nodes::Stub
107
97
  Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym])
@@ -123,7 +113,7 @@ module Squeel
123
113
  def visit_Squeel_Nodes_Operation(o, parent)
124
114
  args = o.args.map do |arg|
125
115
  case arg
126
- when Nodes::Function, Nodes::KeyPath, Nodes::As, Nodes::Literal
116
+ when Nodes::Function, Nodes::KeyPath, Nodes::As, Nodes::Literal, Nodes::Grouping
127
117
  visit(arg, parent)
128
118
  when Symbol, Nodes::Stub
129
119
  Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym])
@@ -147,6 +137,15 @@ module Squeel
147
137
  o.alias ? op.as(o.alias) : op
148
138
  end
149
139
 
140
+ # Visit a Squeel Grouping node, resulting in am ARel Grouping node.
141
+ #
142
+ # @param [Nodes::Grouping] The Grouping node to visit
143
+ # @param parent The parent object in the context
144
+ # @return [Arel::Nodes::Grouping] The resulting grouping node.
145
+ def visit_Squeel_Nodes_Grouping(o, parent)
146
+ Arel::Nodes::Grouping.new(visit(o.expr, parent))
147
+ end
148
+
150
149
  # Visit a Squeel As node, resulting in am ARel As node.
151
150
  #
152
151
  # @param [Nodes::As] The As node to visit
@@ -208,4 +207,4 @@ module Squeel
208
207
 
209
208
  end
210
209
  end
211
- end
210
+ end
@@ -33,16 +33,6 @@ module Squeel
33
33
  end
34
34
  end
35
35
 
36
- # Visit an array, which involves accepting any values we know how to
37
- # accept, and skipping the rest.
38
- #
39
- # @param [Array] o The Array to visit
40
- # @param parent The current parent object in the context
41
- # @return [Array] The visited array
42
- def visit_Array(o, parent)
43
- o.map { |v| can_visit?(v) ? visit(v, parent) : v }.flatten
44
- end
45
-
46
36
  # Visit ActiveRecord::Base objects. These should be converted to their
47
37
  # id before being used in a comparison.
48
38
  #
@@ -64,6 +54,16 @@ module Squeel
64
54
  visit(o.endpoint, parent)
65
55
  end
66
56
 
57
+ # Visit a symbol. This will return an attribute named after the symbol against
58
+ # the current parent's contextualized table.
59
+ #
60
+ # @param [Symbol] o The symbol to visit
61
+ # @param parent The symbol's parent within the context
62
+ # @return [Arel::Attribute] An attribute on the contextualized parent table
63
+ def visit_Symbol(o, parent)
64
+ contextualize(parent)[o]
65
+ end
66
+
67
67
  # Visit a Stub by converting it to an ARel attribute
68
68
  #
69
69
  # @param [Nodes::Stub] o The Stub to visit
@@ -118,7 +118,7 @@ module Squeel
118
118
  value = quote_for_node(o.expr, value)
119
119
 
120
120
  attribute = case o.expr
121
- when Nodes::Stub, Nodes::Function, Nodes::Literal
121
+ when Nodes::Stub, Nodes::Function, Nodes::Literal, Nodes::Grouping
122
122
  visit(o.expr, parent)
123
123
  else
124
124
  contextualize(parent)[o.expr]
@@ -140,7 +140,7 @@ module Squeel
140
140
  def visit_Squeel_Nodes_Function(o, parent)
141
141
  args = o.args.map do |arg|
142
142
  case arg
143
- when Nodes::Function, Nodes::As, Nodes::Literal
143
+ when Nodes::Function, Nodes::As, Nodes::Literal, Nodes::Grouping
144
144
  visit(arg, parent)
145
145
  when ActiveRecord::Relation
146
146
  arg.arel.ast
@@ -176,7 +176,7 @@ module Squeel
176
176
  def visit_Squeel_Nodes_Operation(o, parent)
177
177
  args = o.args.map do |arg|
178
178
  case arg
179
- when Nodes::Function, Nodes::As, Nodes::Literal
179
+ when Nodes::Function, Nodes::As, Nodes::Literal, Nodes::Grouping
180
180
  visit(arg, parent)
181
181
  when Nodes::KeyPath
182
182
  can_visit?(arg.endpoint) ? visit(arg, parent) : contextualize(traverse(arg, parent))[arg.endpoint.to_sym]
@@ -223,8 +223,31 @@ module Squeel
223
223
  Arel::Nodes::Grouping.new(Arel::Nodes::Or.new(visit(o.left, parent), (visit(o.right, parent))))
224
224
  end
225
225
 
226
+ # Visit a Squeel Not node, returning an ARel Not node.
227
+ #
228
+ # @param [Nodes::Not] o The Not node to visit
229
+ # @param parent The parent object in the context
230
+ # @return [Arel::Nodes::Not] An ARel Not node, with expression visited
226
231
  def visit_Squeel_Nodes_Not(o, parent)
227
- visit(o.expr, parent).not
232
+ Arel::Nodes::Not.new(visit(o.expr, parent))
233
+ end
234
+
235
+ # Visit a Squeel Grouping node, returning an ARel Grouping node.
236
+ #
237
+ # @param [Nodes::Grouping] o The Grouping node to visit
238
+ # @param parent The parent object in the context
239
+ # @return [Arel::Nodes::Grouping] An ARel Grouping node, with expression visited
240
+ def visit_Squeel_Nodes_Grouping(o, parent)
241
+ Arel::Nodes::Grouping.new(visit(o.expr, parent))
242
+ end
243
+
244
+ # Visit a Squeel As node, resulting in am ARel As node.
245
+ #
246
+ # @param [Nodes::As] The As node to visit
247
+ # @param parent The parent object in the context
248
+ # @return [Arel::Nodes::As] The resulting as node.
249
+ def visit_Squeel_Nodes_As(o, parent)
250
+ visit(o.left, parent).as(o.right)
228
251
  end
229
252
 
230
253
  # @return [Boolean] Whether the given value implies a context change
@@ -371,4 +394,4 @@ module Squeel
371
394
 
372
395
  end
373
396
  end
374
- end
397
+ end
@@ -13,10 +13,6 @@ module Squeel
13
13
 
14
14
  private
15
15
 
16
- def visit_Array(o, parent)
17
- o.map {|e| visit(e, parent)}.flatten
18
- end
19
-
20
16
  def visit_Hash(o, parent)
21
17
  {}.tap do |hash|
22
18
  o.each do |key, value|
@@ -34,7 +30,7 @@ module Squeel
34
30
  end
35
31
 
36
32
  def visit_Squeel_Nodes_KeyPath(o, parent)
37
- o.path_with_endpoint.reverse.map(&:to_sym).inject do |hash, key|
33
+ o.path.reverse.map(&:to_sym).inject do |hash, key|
38
34
  {key => hash}
39
35
  end
40
36
  end
@@ -45,4 +41,4 @@ module Squeel
45
41
 
46
42
  end
47
43
  end
48
- end
44
+ end
@@ -106,6 +106,29 @@ module Squeel
106
106
  retry
107
107
  end
108
108
 
109
+ # Visit an array, which involves accepting any values we know how to
110
+ # accept, and skipping the rest.
111
+ #
112
+ # @param [Array] o The Array to visit
113
+ # @param parent The current parent object in the context
114
+ # @return [Array] The visited array
115
+ def visit_Array(o, parent)
116
+ o.map { |v| can_visit?(v) ? visit(v, parent) : v }.flatten
117
+ end
118
+
119
+ # Pass an object through the visitor unmodified. This is
120
+ # in order to allow objects that don't require modification
121
+ # to be handled by ARel directly.
122
+ #
123
+ # @param object The object to visit
124
+ # @param parent The object's parent within the context
125
+ # @return The object, unmodified
126
+ def visit_passthrough(object, parent)
127
+ object
128
+ end
129
+ alias :visit_Fixnum :visit_passthrough
130
+ alias :visit_Bignum :visit_passthrough
131
+
109
132
  end
110
133
  end
111
- end
134
+ end
@@ -97,7 +97,7 @@ module Squeel
97
97
  relation.join_dependency.join_associations.should have(6).items
98
98
  arel.to_sql.should match /INNER JOIN "people" "parents_people_3" ON "parents_people_3"."id" = "children_people_3"."parent_id"/
99
99
  end
100
-
100
+
101
101
  it 'respects :uniq option on associations' do
102
102
  Article.first.uniq_commenters.length.should eq Article.first.uniq_commenters.count
103
103
  end
@@ -468,6 +468,11 @@ module Squeel
468
468
  old_and_busted.to_a.should eq new_hotness.to_a
469
469
  end
470
470
 
471
+ it "doesn't break #count if wheres contain InfixOperations" do
472
+ first_name = Person.first.name
473
+ Person.where{name.op('=', first_name)}.count.should eq 1
474
+ end
475
+
471
476
  end
472
477
 
473
478
  describe '#joins' do
@@ -110,5 +110,13 @@ module Squeel
110
110
  end
111
111
  end
112
112
 
113
+ describe '#_' do
114
+ it 'creates a Grouping' do
115
+ result = dsl{_(id + 1)}
116
+ result.should be_a Nodes::Grouping
117
+ result.expr.should eq Nodes::Operation.new(:+, Nodes::Stub.new(:id), 1)
118
+ end
119
+ end
120
+
113
121
  end
114
- end
122
+ end