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.
- data/CHANGELOG.md +20 -0
- data/README.md +1 -1
- data/lib/squeel.rb +1 -2
- data/lib/squeel/adapters/active_record.rb +3 -1
- data/lib/squeel/adapters/active_record/3.0/compat.rb +5 -1
- data/lib/squeel/adapters/active_record/3.0/context.rb +2 -2
- data/lib/squeel/adapters/active_record/3.1/compat.rb +22 -0
- data/lib/squeel/adapters/active_record/3.1/context.rb +2 -2
- data/lib/squeel/adapters/active_record/compat.rb +22 -0
- data/lib/squeel/adapters/active_record/join_dependency_extensions.rb +2 -2
- data/lib/squeel/configuration.rb +2 -2
- data/lib/squeel/core_ext/symbol.rb +3 -13
- data/lib/squeel/dsl.rb +10 -1
- data/lib/squeel/nodes.rb +9 -1
- data/lib/squeel/nodes/aliasing.rb +2 -2
- data/lib/squeel/nodes/as.rb +1 -1
- data/lib/squeel/nodes/binary.rb +1 -4
- data/lib/squeel/nodes/function.rb +1 -10
- data/lib/squeel/nodes/grouping.rb +35 -0
- data/lib/squeel/nodes/join.rb +3 -3
- data/lib/squeel/nodes/key_path.rb +26 -24
- data/lib/squeel/nodes/literal.rb +2 -17
- data/lib/squeel/nodes/nary.rb +1 -2
- data/lib/squeel/nodes/ordering.rb +21 -0
- data/lib/squeel/nodes/predicate.rb +1 -4
- data/lib/squeel/nodes/predicate_methods.rb +16 -0
- data/lib/squeel/nodes/stub.rb +11 -21
- data/lib/squeel/nodes/unary.rb +1 -4
- data/lib/squeel/version.rb +1 -1
- data/lib/squeel/visitors/attribute_visitor.rb +12 -13
- data/lib/squeel/visitors/predicate_visitor.rb +38 -15
- data/lib/squeel/visitors/symbol_visitor.rb +2 -6
- data/lib/squeel/visitors/visitor.rb +24 -1
- data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +6 -1
- data/spec/squeel/dsl_spec.rb +9 -1
- data/spec/squeel/nodes/grouping_spec.rb +177 -0
- data/spec/squeel/nodes/join_spec.rb +4 -5
- data/spec/squeel/nodes/key_path_spec.rb +3 -5
- data/spec/squeel/nodes/operators_spec.rb +3 -3
- data/spec/squeel/nodes/stub_spec.rb +6 -7
- data/spec/squeel/visitors/attribute_visitor_spec.rb +6 -1
- data/spec/squeel/visitors/predicate_visitor_spec.rb +28 -0
- metadata +62 -22
- data/lib/squeel/predicate_methods.rb +0 -14
data/lib/squeel/nodes/literal.rb
CHANGED
@@ -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
|
data/lib/squeel/nodes/nary.rb
CHANGED
@@ -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
|
data/lib/squeel/nodes/stub.rb
CHANGED
@@ -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 [],
|
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
|
data/lib/squeel/nodes/unary.rb
CHANGED
@@ -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
|
data/lib/squeel/version.rb
CHANGED
@@ -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)
|
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.
|
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
|
data/spec/squeel/dsl_spec.rb
CHANGED
@@ -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
|