squeel 1.0.18 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +2 -7
- data/CHANGELOG.md +9 -0
- data/Gemfile +2 -2
- data/README.md +223 -147
- data/lib/generators/templates/squeel.rb +1 -1
- data/lib/squeel/adapters/active_record.rb +1 -1
- data/lib/squeel/adapters/active_record/4.0/compat.rb +17 -0
- data/lib/squeel/adapters/active_record/4.0/context.rb +1 -0
- data/lib/squeel/adapters/active_record/4.0/preloader_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/4.0/relation_extensions.rb +126 -0
- data/lib/squeel/adapters/active_record/base_extensions.rb +1 -1
- data/lib/squeel/adapters/active_record/context.rb +10 -10
- data/lib/squeel/adapters/active_record/relation_extensions.rb +24 -16
- data/lib/squeel/configuration.rb +1 -0
- data/lib/squeel/constants.rb +2 -2
- data/lib/squeel/context.rb +2 -2
- data/lib/squeel/dsl.rb +1 -1
- data/lib/squeel/nodes.rb +2 -0
- data/lib/squeel/nodes/binary.rb +1 -1
- data/lib/squeel/nodes/function.rb +5 -5
- data/lib/squeel/nodes/join.rb +2 -2
- data/lib/squeel/nodes/key_path.rb +10 -5
- data/lib/squeel/nodes/literal.rb +1 -1
- data/lib/squeel/nodes/nary.rb +5 -7
- data/lib/squeel/nodes/node.rb +6 -0
- data/lib/squeel/nodes/operation.rb +1 -1
- data/lib/squeel/nodes/order.rb +1 -1
- data/lib/squeel/nodes/predicate.rb +5 -5
- data/lib/squeel/nodes/predicate_methods.rb +11 -2
- data/lib/squeel/nodes/sifter.rb +2 -2
- data/lib/squeel/nodes/stub.rb +2 -2
- data/lib/squeel/nodes/unary.rb +1 -1
- data/lib/squeel/version.rb +1 -1
- data/lib/squeel/visitors/predicate_visitation.rb +6 -6
- data/lib/squeel/visitors/predicate_visitor.rb +1 -1
- data/lib/squeel/visitors/visitor.rb +20 -20
- data/spec/spec_helper.rb +6 -4
- data/spec/squeel/adapters/active_record/base_extensions_spec.rb +6 -6
- data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +55 -24
- data/spec/squeel/core_ext/symbol_spec.rb +2 -2
- data/spec/squeel/nodes/key_path_spec.rb +3 -3
- data/spec/squeel/nodes/predicate_operators_spec.rb +4 -4
- data/spec/squeel/visitors/predicate_visitor_spec.rb +11 -11
- data/spec/squeel/visitors/visitor_spec.rb +9 -9
- data/spec/support/models.rb +25 -7
- data/spec/support/schema.rb +1 -1
- data/squeel.gemspec +4 -4
- metadata +19 -12
data/lib/squeel/nodes/literal.rb
CHANGED
data/lib/squeel/nodes/nary.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Squeel
|
2
2
|
module Nodes
|
3
3
|
# A node containing multiple children. Just the And node for now.
|
4
|
-
class Nary
|
4
|
+
class Nary < Node
|
5
5
|
include PredicateOperators
|
6
6
|
|
7
7
|
# @return [Array] This node's children
|
@@ -17,20 +17,18 @@ module Squeel
|
|
17
17
|
@children = children
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
20
|
+
# Returns a new Nary node, with an additional child.
|
21
21
|
# @param other A new child node
|
22
22
|
# @return [Nary] This node, with its updated children.
|
23
23
|
def &(other)
|
24
|
-
@children
|
25
|
-
self
|
24
|
+
self.class.new(@children + [other])
|
26
25
|
end
|
27
26
|
|
28
|
-
#
|
27
|
+
# Returns a new Nary node, with an additional (negated) child.
|
29
28
|
# @param other A new child node
|
30
29
|
# @return [Nary] This node, with its new, negated child
|
31
30
|
def -(other)
|
32
|
-
@children
|
33
|
-
self
|
31
|
+
self.class.new(@children + [Not.new(other)])
|
34
32
|
end
|
35
33
|
|
36
34
|
# Implemented for equality testing
|
data/lib/squeel/nodes/order.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
module Squeel
|
2
2
|
module Nodes
|
3
|
-
# This node is essentially a container that will result in
|
3
|
+
# This node is essentially a container that will result in Arel predicate nodes
|
4
4
|
# once visited. It stores the expression (normally an attribute name, function, or
|
5
|
-
# operation), the
|
5
|
+
# operation), the Arel predicate method name, and a value. these are then interpreted
|
6
6
|
# when visited by the PredicateVisitor to generate a condition against the appropriate
|
7
7
|
# columns.
|
8
|
-
class Predicate
|
8
|
+
class Predicate < Node
|
9
9
|
|
10
10
|
include PredicateOperators
|
11
11
|
include Aliasing
|
@@ -16,12 +16,12 @@ module Squeel
|
|
16
16
|
# @return The expression on the left side of this predicate.
|
17
17
|
attr_reader :expr
|
18
18
|
|
19
|
-
# @return [Symbol] The
|
19
|
+
# @return [Symbol] The Arel "predication" method name, such as eq, matches, etc.
|
20
20
|
attr_reader :method_name
|
21
21
|
|
22
22
|
# Create a new Predicate node with the given expression, method name, and value
|
23
23
|
# @param expr The expression for the left hand side of the predicate.
|
24
|
-
# @param [Symbol] method_name The
|
24
|
+
# @param [Symbol] method_name The Arel predication method
|
25
25
|
# @param value An optional value. If not given, one will need to be supplied
|
26
26
|
# before the node can be visited properly.
|
27
27
|
def initialize(expr, method_name = :eq, value = :__undefined__)
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Squeel
|
2
2
|
module Nodes
|
3
|
-
# Defines Predicate factories named for each of the
|
3
|
+
# Defines Predicate factories named for each of the Arel predication methods
|
4
4
|
module PredicateMethods
|
5
5
|
|
6
|
-
Constants::PREDICATES.each do |method_name|
|
6
|
+
(Constants::PREDICATES - [:eq]).each do |method_name|
|
7
7
|
class_eval <<-RUBY
|
8
8
|
def #{method_name}(value = :__undefined__)
|
9
9
|
Nodes::Predicate.new self, :#{method_name}, value
|
@@ -11,6 +11,15 @@ module Squeel
|
|
11
11
|
RUBY
|
12
12
|
end
|
13
13
|
|
14
|
+
# YAY WHERECHAIN
|
15
|
+
def eq(value = :__undefined__)
|
16
|
+
if :chain == value
|
17
|
+
false
|
18
|
+
else
|
19
|
+
Nodes::Predicate.new self, :eq, value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
end
|
15
24
|
end
|
16
25
|
end
|
data/lib/squeel/nodes/sifter.rb
CHANGED
data/lib/squeel/nodes/stub.rb
CHANGED
@@ -3,7 +3,7 @@ module Squeel
|
|
3
3
|
# Stub nodes are basically a container for a Symbol that can have handy predicate
|
4
4
|
# methods and operators defined on it since doing so on Symbol will incur the
|
5
5
|
# nerdrage of many.
|
6
|
-
class Stub
|
6
|
+
class Stub < Node
|
7
7
|
include PredicateMethods
|
8
8
|
include Operators
|
9
9
|
include Aliasing
|
@@ -21,7 +21,7 @@ module Squeel
|
|
21
21
|
alias :< :lt
|
22
22
|
alias :<= :lteq
|
23
23
|
|
24
|
-
# We
|
24
|
+
# We don't want these default Object methods, because if we're
|
25
25
|
# calling them we are probably talking about a column name
|
26
26
|
[:id, :type].each do |column_method|
|
27
27
|
undef_method column_method if method_defined?(column_method) ||
|
data/lib/squeel/nodes/unary.rb
CHANGED
data/lib/squeel/version.rb
CHANGED
@@ -16,14 +16,14 @@ module Squeel
|
|
16
16
|
# @return The result of visiting the executed block's return value
|
17
17
|
def visit_Squeel_Nodes_Sifter(o, parent)
|
18
18
|
klass = classify(parent)
|
19
|
-
visit(klass.send(o.name, *o.args), parent)
|
19
|
+
visit(klass.send("sifter_#{o.name}", *o.args), parent)
|
20
20
|
end
|
21
21
|
|
22
|
-
# Visit a Squeel predicate, converting it into an
|
22
|
+
# Visit a Squeel predicate, converting it into an Arel predicate
|
23
23
|
#
|
24
24
|
# @param [Nodes::Predicate] o The predicate to visit
|
25
25
|
# @param parent The parent object in the context
|
26
|
-
# @return An
|
26
|
+
# @return An Arel predicate node
|
27
27
|
# (Arel::Nodes::Equality, Arel::Nodes::Matches, etc)
|
28
28
|
def visit_Squeel_Nodes_Predicate(o, parent)
|
29
29
|
value = o.value
|
@@ -59,10 +59,10 @@ module Squeel
|
|
59
59
|
# Determine whether to use IN or equality testing for a predicate,
|
60
60
|
# based on its value class, then return the appropriate predicate.
|
61
61
|
#
|
62
|
-
# @param attribute The
|
62
|
+
# @param attribute The Arel attribute (or function/operation) the
|
63
63
|
# predicate will be created for
|
64
64
|
# @param value The value to be compared against
|
65
|
-
# @return [Arel::Nodes::Node] An
|
65
|
+
# @return [Arel::Nodes::Node] An Arel predicate node
|
66
66
|
def arel_predicate_for(attribute, value, parent)
|
67
67
|
if ActiveRecord::Relation === value && value.select_values.empty?
|
68
68
|
value = visit(value.select(value.klass.arel_table[value.klass.primary_key]), parent)
|
@@ -102,7 +102,7 @@ module Squeel
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
-
# Certain nodes require us to do the quoting before the
|
105
|
+
# Certain nodes require us to do the quoting before the Arel
|
106
106
|
# visitor gets a chance to try, because we want to avoid having our
|
107
107
|
# values quoted as a type of the last visited column. Otherwise, we
|
108
108
|
# can end up with annoyances like having "joe" quoted to 0, if the
|
@@ -45,7 +45,7 @@ module Squeel
|
|
45
45
|
# @param k The hash key
|
46
46
|
# @param v The hash value
|
47
47
|
# @param parent The current parent object in the context
|
48
|
-
# @return An
|
48
|
+
# @return An Arel predicate
|
49
49
|
def visit_without_hash_context_shift(k, v, parent)
|
50
50
|
case v
|
51
51
|
when Nodes::Stub, Symbol
|
@@ -22,7 +22,7 @@ module Squeel
|
|
22
22
|
# @param object The object to visit
|
23
23
|
# @param parent The parent of this object, to track the object's place in
|
24
24
|
# any association hierarchy.
|
25
|
-
# @return The results of the node visitation, typically an
|
25
|
+
# @return The results of the node visitation, typically an Arel object of some kind.
|
26
26
|
def accept(object, parent = context.base)
|
27
27
|
visit(object, parent)
|
28
28
|
end
|
@@ -100,13 +100,13 @@ module Squeel
|
|
100
100
|
v
|
101
101
|
end
|
102
102
|
|
103
|
-
# Important to avoid accidentally allowing the default
|
103
|
+
# Important to avoid accidentally allowing the default Arel visitor's
|
104
104
|
# last_column quoting behavior (where a value is quoted as though it
|
105
105
|
# is of the type of the last visited column). This can wreak havoc with
|
106
106
|
# Functions and Operations.
|
107
107
|
#
|
108
108
|
# @param object The object to check
|
109
|
-
# @return [Boolean] Whether or not the
|
109
|
+
# @return [Boolean] Whether or not the Arel visitor will try to quote the
|
110
110
|
# object if not passed as an SqlLiteral.
|
111
111
|
def quoted?(object)
|
112
112
|
case object
|
@@ -119,7 +119,7 @@ module Squeel
|
|
119
119
|
end
|
120
120
|
|
121
121
|
# Quote a value based on its type, not on the last column used by the
|
122
|
-
#
|
122
|
+
# Arel visitor. This is occasionally necessary to avoid having Arel
|
123
123
|
# quote a value according to an integer column, converting 'My String' to 0.
|
124
124
|
#
|
125
125
|
# @param value The value to quote
|
@@ -159,7 +159,7 @@ module Squeel
|
|
159
159
|
|
160
160
|
# Pass an object through the visitor unmodified. This is
|
161
161
|
# in order to allow objects that don't require modification
|
162
|
-
# to be handled by
|
162
|
+
# to be handled by Arel directly.
|
163
163
|
#
|
164
164
|
# @param object The object to visit
|
165
165
|
# @param parent The object's parent within the context
|
@@ -231,7 +231,7 @@ module Squeel
|
|
231
231
|
visit(o.endpoint, parent)
|
232
232
|
end
|
233
233
|
|
234
|
-
# Visit a Literal by converting it to an
|
234
|
+
# Visit a Literal by converting it to an Arel SqlLiteral
|
235
235
|
#
|
236
236
|
# @param [Nodes::Literal] o The Literal to visit
|
237
237
|
# @param parent The parent object in the context (unused)
|
@@ -240,7 +240,7 @@ module Squeel
|
|
240
240
|
Arel.sql(o.expr)
|
241
241
|
end
|
242
242
|
|
243
|
-
# Visit a Squeel As node, resulting in am
|
243
|
+
# Visit a Squeel As node, resulting in am Arel As node.
|
244
244
|
#
|
245
245
|
# @param [Nodes::As] The As node to visit
|
246
246
|
# @param parent The parent object in the context
|
@@ -256,46 +256,46 @@ module Squeel
|
|
256
256
|
end
|
257
257
|
end
|
258
258
|
|
259
|
-
# Visit a Squeel And node, returning an
|
260
|
-
#
|
259
|
+
# Visit a Squeel And node, returning an Arel Grouping containing an
|
260
|
+
# Arel And node.
|
261
261
|
#
|
262
262
|
# @param [Nodes::And] o The And node to visit
|
263
263
|
# @param parent The parent object in the context
|
264
|
-
# @return [Arel::Nodes::Grouping] A grouping node, containnig an
|
264
|
+
# @return [Arel::Nodes::Grouping] A grouping node, containnig an Arel
|
265
265
|
# And node as its expression. All children will be visited before
|
266
266
|
# being passed to the And.
|
267
267
|
def visit_Squeel_Nodes_And(o, parent)
|
268
268
|
Arel::Nodes::Grouping.new(Arel::Nodes::And.new(visit(o.children, parent)))
|
269
269
|
end
|
270
270
|
|
271
|
-
# Visit a Squeel Or node, returning an
|
271
|
+
# Visit a Squeel Or node, returning an Arel Or node.
|
272
272
|
#
|
273
273
|
# @param [Nodes::Or] o The Or node to visit
|
274
274
|
# @param parent The parent object in the context
|
275
|
-
# @return [Arel::Nodes::Or] An
|
275
|
+
# @return [Arel::Nodes::Or] An Arel Or node, with left and right sides visited
|
276
276
|
def visit_Squeel_Nodes_Or(o, parent)
|
277
277
|
Arel::Nodes::Grouping.new(Arel::Nodes::Or.new(visit(o.left, parent), (visit(o.right, parent))))
|
278
278
|
end
|
279
279
|
|
280
|
-
# Visit a Squeel Not node, returning an
|
280
|
+
# Visit a Squeel Not node, returning an Arel Not node.
|
281
281
|
#
|
282
282
|
# @param [Nodes::Not] o The Not node to visit
|
283
283
|
# @param parent The parent object in the context
|
284
|
-
# @return [Arel::Nodes::Not] An
|
284
|
+
# @return [Arel::Nodes::Not] An Arel Not node, with expression visited
|
285
285
|
def visit_Squeel_Nodes_Not(o, parent)
|
286
286
|
Arel::Nodes::Not.new(visit(o.expr, parent))
|
287
287
|
end
|
288
288
|
|
289
|
-
# Visit a Squeel Grouping node, returning an
|
289
|
+
# Visit a Squeel Grouping node, returning an Arel Grouping node.
|
290
290
|
#
|
291
291
|
# @param [Nodes::Grouping] o The Grouping node to visit
|
292
292
|
# @param parent The parent object in the context
|
293
|
-
# @return [Arel::Nodes::Grouping] An
|
293
|
+
# @return [Arel::Nodes::Grouping] An Arel Grouping node, with expression visited
|
294
294
|
def visit_Squeel_Nodes_Grouping(o, parent)
|
295
295
|
Arel::Nodes::Grouping.new(visit(o.expr, parent))
|
296
296
|
end
|
297
297
|
#
|
298
|
-
# Visit a Squeel function, returning an
|
298
|
+
# Visit a Squeel function, returning an Arel NamedFunction node.
|
299
299
|
#
|
300
300
|
# @param [Nodes::Function] o The function node to visit
|
301
301
|
# @param parent The parent object in the context
|
@@ -315,10 +315,10 @@ module Squeel
|
|
315
315
|
end
|
316
316
|
end
|
317
317
|
|
318
|
-
Arel::Nodes::NamedFunction.new(o.
|
318
|
+
Arel::Nodes::NamedFunction.new(o.function_name, args)
|
319
319
|
end
|
320
320
|
|
321
|
-
# Visit a Squeel operation node, convering it to an
|
321
|
+
# Visit a Squeel operation node, convering it to an Arel InfixOperation
|
322
322
|
# (or subclass, as appropriate)
|
323
323
|
#
|
324
324
|
# @param [Nodes::Operation] o The Operation node to visit
|
@@ -356,7 +356,7 @@ module Squeel
|
|
356
356
|
# Visit an Active Record Relation, returning an Arel::SelectManager
|
357
357
|
# @param [ActiveRecord::Relation] o The Relation to visit
|
358
358
|
# @param parent The parent object in the context
|
359
|
-
# @return [Arel::SelectManager] The
|
359
|
+
# @return [Arel::SelectManager] The Arel select manager that represents
|
360
360
|
# the relation's query
|
361
361
|
def visit_ActiveRecord_Relation(o, parent)
|
362
362
|
o.arel
|
data/spec/spec_helper.rb
CHANGED
@@ -3,12 +3,10 @@ require 'sham'
|
|
3
3
|
require 'faker'
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
|
+
# Shamelessly swiped from the AR test code
|
6
7
|
class SQLCounter
|
7
8
|
IGNORED_SQL = [/^PRAGMA /, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/,
|
8
9
|
/SELECT name\s+FROM sqlite_master\s+WHERE type = 'table' AND NOT name = 'sqlite_sequence'/]
|
9
|
-
|
10
|
-
# FIXME: this needs to be refactored so specific database can add their own
|
11
|
-
# ignored SQL. This ignored SQL is for Oracle.
|
12
10
|
IGNORED_SQL.concat [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from all_triggers/im]
|
13
11
|
|
14
12
|
def initialize
|
@@ -26,6 +24,10 @@ module ActiveRecord
|
|
26
24
|
ActiveSupport::Notifications.subscribe('sql.active_record', SQLCounter.new)
|
27
25
|
end
|
28
26
|
|
27
|
+
unless ENV['DEPRECATIONS']
|
28
|
+
ActiveSupport::Deprecation.silenced = true
|
29
|
+
end
|
30
|
+
|
29
31
|
Dir[File.expand_path('../helpers/*.rb', __FILE__)].each do |f|
|
30
32
|
require f
|
31
33
|
end
|
@@ -45,7 +47,7 @@ end
|
|
45
47
|
RSpec.configure do |config|
|
46
48
|
config.before(:suite) do
|
47
49
|
puts '=' * 80
|
48
|
-
puts "Running specs against Active Record #{ActiveRecord::VERSION::STRING} and
|
50
|
+
puts "Running specs against Active Record #{ActiveRecord::VERSION::STRING} and Arel #{Arel::VERSION}..."
|
49
51
|
puts '=' * 80
|
50
52
|
Models.make
|
51
53
|
end
|
@@ -22,19 +22,19 @@ module Squeel
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
it { should respond_to :
|
26
|
-
specify { subject.
|
25
|
+
it { should respond_to :sifter_title_or_body_contains }
|
26
|
+
specify { subject.sifter_title_or_body_contains('ernie').should be_a Nodes::Or }
|
27
27
|
end
|
28
28
|
|
29
29
|
context 'with a sifter defined via method' do
|
30
30
|
before :all do
|
31
|
-
def subject.
|
31
|
+
def subject.sifter_title_starts_with(val)
|
32
32
|
squeel{title =~ "#{val}%"}
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
it { should respond_to :
|
37
|
-
specify { subject.
|
36
|
+
it { should respond_to :sifter_title_starts_with }
|
37
|
+
specify { subject.sifter_title_starts_with('ernie').should be_a Nodes::Predicate }
|
38
38
|
end
|
39
39
|
|
40
40
|
end
|
@@ -42,4 +42,4 @@ module Squeel
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
45
|
-
end
|
45
|
+
end
|
@@ -78,7 +78,7 @@ module Squeel
|
|
78
78
|
Article.first.uniq_commenters.length.should eq Article.first.uniq_commenters.count
|
79
79
|
end
|
80
80
|
|
81
|
-
it 'visits wheres with a PredicateVisitor, converting them to
|
81
|
+
it 'visits wheres with a PredicateVisitor, converting them to Arel nodes' do
|
82
82
|
relation = Person.where(:name.matches => '%bob%')
|
83
83
|
arel = relation.build_arel
|
84
84
|
arel.to_sql.should match /"people"."name" LIKE '%bob%'/
|
@@ -155,25 +155,29 @@ module Squeel
|
|
155
155
|
end
|
156
156
|
|
157
157
|
it 'maps orders inside a hash to their appropriate association table' do
|
158
|
-
|
159
|
-
|
158
|
+
unless activerecord_version_at_least '4.0.0'
|
159
|
+
relation = Person.joins({
|
160
160
|
:children => {
|
161
|
-
:
|
161
|
+
:children => {
|
162
|
+
:parent => :parent
|
163
|
+
}
|
162
164
|
}
|
163
|
-
}
|
164
|
-
}).order({
|
165
|
-
:children => {
|
165
|
+
}).order({
|
166
166
|
:children => {
|
167
|
-
:
|
168
|
-
:parent =>
|
167
|
+
:children => {
|
168
|
+
:parent => {
|
169
|
+
:parent => :id.asc
|
170
|
+
}
|
169
171
|
}
|
170
172
|
}
|
171
|
-
}
|
172
|
-
})
|
173
|
+
})
|
173
174
|
|
174
|
-
|
175
|
+
arel = relation.build_arel
|
175
176
|
|
176
|
-
|
177
|
+
arel.to_sql.should match /ORDER BY "parents_people_2"."id" ASC/
|
178
|
+
else
|
179
|
+
pending 'Unsupported in ActiveRecord 4.0.0+'
|
180
|
+
end
|
177
181
|
end
|
178
182
|
|
179
183
|
it 'does not inadvertently convert KeyPaths to booleans when uniqing where_values' do
|
@@ -186,7 +190,7 @@ module Squeel
|
|
186
190
|
end
|
187
191
|
|
188
192
|
it 'reverses order of Arel::Attributes when #last is called' do
|
189
|
-
sorted_people = Person.all.sort {|a, b| a.name.downcase <=> b.name.downcase}
|
193
|
+
sorted_people = Person.all.to_a.sort {|a, b| a.name.downcase <=> b.name.downcase}
|
190
194
|
|
191
195
|
Person.order{name}.last.should eq sorted_people.last
|
192
196
|
end
|
@@ -242,7 +246,7 @@ module Squeel
|
|
242
246
|
it 'eager loads belongs_to associations' do
|
243
247
|
queries = queries_for do
|
244
248
|
Article.includes(:person).
|
245
|
-
where{person.name == 'Ernie'}.
|
249
|
+
where{person.name == 'Ernie'}.to_a
|
246
250
|
end
|
247
251
|
queries.should have(1).item
|
248
252
|
queries.first.should match /LEFT OUTER JOIN "people"/
|
@@ -252,7 +256,7 @@ module Squeel
|
|
252
256
|
it 'eager loads belongs_to associations on models with default_scopes' do
|
253
257
|
queries = queries_for do
|
254
258
|
PersonNamedBill.includes(:parent).
|
255
|
-
where{parent.name == 'Ernie'}.
|
259
|
+
where{parent.name == 'Ernie'}.to_a
|
256
260
|
end
|
257
261
|
queries.should have(1).item
|
258
262
|
queries.first.should match /LEFT OUTER JOIN "people"/
|
@@ -289,13 +293,13 @@ module Squeel
|
|
289
293
|
|
290
294
|
it 'builds options with a block' do
|
291
295
|
relation = Person.preload{children}
|
292
|
-
queries_for {relation.
|
296
|
+
queries_for {relation.to_a}.should have(2).items
|
293
297
|
queries_for {relation.first.children}.should have(0).items
|
294
298
|
end
|
295
299
|
|
296
300
|
it 'builds options with a keypath' do
|
297
301
|
relation = Person.preload{articles.comments}
|
298
|
-
queries_for {relation.
|
302
|
+
queries_for {relation.to_a}.should have(3).items
|
299
303
|
queries_for {relation.first.articles.first.comments}.should have(0).items
|
300
304
|
end
|
301
305
|
|
@@ -306,7 +310,7 @@ module Squeel
|
|
306
310
|
}
|
307
311
|
}}
|
308
312
|
|
309
|
-
queries_for {relation.
|
313
|
+
queries_for {relation.to_a}.should have(4).items
|
310
314
|
|
311
315
|
queries_for {
|
312
316
|
relation.first.articles
|
@@ -323,7 +327,7 @@ module Squeel
|
|
323
327
|
standard = Person.eager_load(:children => :children)
|
324
328
|
block = Person.eager_load{{children => children}}
|
325
329
|
block.debug_sql.should eq standard.debug_sql
|
326
|
-
queries_for {block.
|
330
|
+
queries_for {block.to_a}.should have(1).item
|
327
331
|
queries_for {block.first.children}.should have(0).items
|
328
332
|
end
|
329
333
|
|
@@ -417,7 +421,11 @@ module Squeel
|
|
417
421
|
describe '#count' do
|
418
422
|
|
419
423
|
it 'works with non-strings in select' do
|
420
|
-
|
424
|
+
if activerecord_version_at_least '4.0.0'
|
425
|
+
pending 'broken on current 4-0-stable'
|
426
|
+
else
|
427
|
+
Article.select{distinct(title)}.count.should eq 51
|
428
|
+
end
|
421
429
|
end
|
422
430
|
|
423
431
|
it 'works with non-strings in wheres' do
|
@@ -496,6 +504,16 @@ module Squeel
|
|
496
504
|
old_and_busted.to_a.should eq new_hotness.to_a
|
497
505
|
end
|
498
506
|
|
507
|
+
it 'is backwards-compatible with "where.not"' do
|
508
|
+
if activerecord_version_at_least '4.0.0'
|
509
|
+
name = Person.first.name
|
510
|
+
result = Person.where.not(:name => name)
|
511
|
+
result.should_not include Person.first
|
512
|
+
else
|
513
|
+
pending 'Not required pre-4.0'
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
499
517
|
end
|
500
518
|
|
501
519
|
describe '#joins' do
|
@@ -572,9 +590,22 @@ module Squeel
|
|
572
590
|
describe '#order' do
|
573
591
|
|
574
592
|
it 'builds options with a block' do
|
575
|
-
standard = Person.order(:name)
|
576
593
|
block = Person.order{name}
|
577
|
-
block.to_sql.should
|
594
|
+
block.to_sql.should match /ORDER BY "people"\."name"/
|
595
|
+
end
|
596
|
+
|
597
|
+
it 'allows AR 4.0-style hash options' do
|
598
|
+
if activerecord_version_at_least '4.0.0'
|
599
|
+
block = Person.order(:name => :desc)
|
600
|
+
block.to_sql.should match /ORDER BY "people"\."name" DESC/
|
601
|
+
else
|
602
|
+
pending 'Not required in AR versions < 4.0.0'
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
it 'allows ordering by an attributes of a joined table' do
|
607
|
+
relation = Article.joins(:person).order { person.id.asc }
|
608
|
+
relation.to_sql.should match /ORDER BY "people"\."id" ASC/
|
578
609
|
end
|
579
610
|
|
580
611
|
end
|
@@ -631,7 +662,7 @@ module Squeel
|
|
631
662
|
wheres.should eq ["name like '%bob%'"]
|
632
663
|
end
|
633
664
|
|
634
|
-
it 'adds hash where values without converting to
|
665
|
+
it 'adds hash where values without converting to Arel predicates' do
|
635
666
|
wheres = Person.where({:name => 'bob'}).where_values
|
636
667
|
wheres.should eq [{:name => 'bob'}]
|
637
668
|
end
|