squeel 1.0.18 → 1.1.0
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/.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
|