squeel 1.0.9 → 1.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +10 -0
- data/lib/squeel.rb +5 -0
- data/lib/squeel/adapters/active_record/3.0/association_preload_extensions.rb +2 -2
- data/lib/squeel/adapters/active_record/3.0/relation_extensions.rb +98 -46
- data/lib/squeel/adapters/active_record/3.1/preloader_extensions.rb +2 -2
- data/lib/squeel/adapters/active_record/3.1/relation_extensions.rb +71 -85
- data/lib/squeel/adapters/active_record/base_extensions.rb +0 -19
- data/lib/squeel/adapters/active_record/relation_extensions.rb +6 -9
- data/lib/squeel/nodes/binary.rb +4 -0
- data/lib/squeel/nodes/function.rb +10 -0
- data/lib/squeel/nodes/nary.rb +1 -1
- data/lib/squeel/nodes/order.rb +11 -1
- data/lib/squeel/nodes/predicate.rb +2 -2
- data/lib/squeel/nodes/stub.rb +2 -0
- data/lib/squeel/nodes/unary.rb +4 -0
- data/lib/squeel/version.rb +1 -1
- data/lib/squeel/visitors.rb +10 -3
- data/lib/squeel/visitors/from_visitor.rb +6 -0
- data/lib/squeel/visitors/group_visitor.rb +6 -0
- data/lib/squeel/visitors/having_visitor.rb +9 -0
- data/lib/squeel/visitors/order_visitor.rb +20 -0
- data/lib/squeel/visitors/predicate_visitation.rb +126 -0
- data/lib/squeel/visitors/predicate_visitor.rb +3 -326
- data/lib/squeel/visitors/{symbol_visitor.rb → preload_visitor.rb} +4 -4
- data/lib/squeel/visitors/select_visitor.rb +7 -0
- data/lib/squeel/visitors/visitor.rb +244 -12
- data/lib/squeel/visitors/where_visitor.rb +8 -0
- data/spec/helpers/squeel_helper.rb +14 -1
- data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +65 -49
- data/spec/squeel/nodes/as_spec.rb +20 -0
- data/spec/squeel/nodes/function_spec.rb +6 -0
- data/spec/squeel/nodes/grouping_spec.rb +6 -0
- data/spec/squeel/nodes/key_path_spec.rb +3 -3
- data/spec/squeel/nodes/operation_spec.rb +6 -0
- data/spec/squeel/nodes/order_spec.rb +6 -1
- data/spec/squeel/nodes/predicate_operators_spec.rb +1 -1
- data/spec/squeel/nodes/predicate_spec.rb +14 -1
- data/spec/squeel/nodes/sifter_spec.rb +2 -1
- data/spec/squeel/nodes/stub_spec.rb +4 -0
- data/spec/squeel/visitors/order_visitor_spec.rb +36 -0
- data/spec/squeel/visitors/{symbol_visitor_spec.rb → preload_visitor_spec.rb} +4 -3
- data/spec/squeel/visitors/select_visitor_spec.rb +26 -0
- data/spec/squeel/visitors/{attribute_visitor_spec.rb → visitor_spec.rb} +23 -37
- data/spec/support/models.rb +4 -0
- metadata +22 -10
- data/lib/squeel/visitors/attribute_visitor.rb +0 -214
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 1.0.11 (2012-09-03)
|
2
|
+
|
3
|
+
* Fixed issue #157, resolving problems when joining the same table twice.
|
4
|
+
* Allow predicates in order/select values
|
5
|
+
* Support Relation#from in Squeel DSL
|
6
|
+
|
7
|
+
## 1.0.10 (2012-09-01)
|
8
|
+
|
9
|
+
* Yanked from RubyGems.org due to semantic versioning oversight
|
10
|
+
|
1
11
|
## 1.0.9 (2012-08-06)
|
2
12
|
|
3
13
|
* Fix issue with duplication of order conditions in default_scope on AR 3.0.x
|
data/lib/squeel.rb
CHANGED
@@ -13,6 +13,11 @@ module Squeel
|
|
13
13
|
$VERBOSE = original_verbosity
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.deprecate(message)
|
17
|
+
external_caller = caller.find {|s| !s.include?('/lib/squeel/')}
|
18
|
+
warn "DEPRECATION WARNING: #{message} (called from #{external_caller})"
|
19
|
+
end
|
20
|
+
|
16
21
|
# Set up initial predicate aliases
|
17
22
|
Constants::PREDICATE_ALIASES.each do |original, aliases|
|
18
23
|
aliases.each do |aliaz|
|
@@ -4,10 +4,10 @@ module Squeel
|
|
4
4
|
module AssociationPreloadExtensions
|
5
5
|
|
6
6
|
def preload_associations(records, associations, preload_options={})
|
7
|
-
super(records, Visitors::
|
7
|
+
super(records, Visitors::PreloadVisitor.new.accept(associations), preload_options)
|
8
8
|
end
|
9
9
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
|
-
end
|
13
|
+
end
|
@@ -13,37 +13,37 @@ module Squeel
|
|
13
13
|
|
14
14
|
# Returns a JoinDependency for the current relation.
|
15
15
|
#
|
16
|
-
# We don't need to clear out @join_dependency by overriding #reset,
|
17
|
-
# the default #reset already does this, despite never setting
|
18
|
-
# I can find. Serendipity, I say!
|
16
|
+
# We don't need to clear out @join_dependency by overriding #reset,
|
17
|
+
# because the default #reset already does this, despite never setting
|
18
|
+
# it anywhere that I can find. Serendipity, I say!
|
19
19
|
def join_dependency
|
20
20
|
@join_dependency ||= (build_join_dependency(table, @joins_values) && @join_dependency)
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def attribute_visitor
|
30
|
-
Visitors::AttributeVisitor.new(
|
31
|
-
Context.new(join_dependency)
|
32
|
-
)
|
23
|
+
%w(where having group order select from).each do |visitor|
|
24
|
+
define_method "#{visitor}_visit" do |values|
|
25
|
+
Visitors.const_get("#{visitor.capitalize}Visitor").new(
|
26
|
+
Context.new(join_dependency)
|
27
|
+
).accept(values)
|
28
|
+
end
|
33
29
|
end
|
34
30
|
|
35
31
|
# We need to be able to support merging two relations without having
|
36
|
-
# to get our hooks too deeply into ActiveRecord.
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
def merge(r,
|
43
|
-
if
|
44
|
-
|
32
|
+
# to get our hooks too deeply into ActiveRecord. That proves to be
|
33
|
+
# easier said than done. I hate Relation#merge. If Squeel has a
|
34
|
+
# nemesis, Relation#merge would be it.
|
35
|
+
#
|
36
|
+
# Whatever code you see here currently is my current best attempt at
|
37
|
+
# coexisting peacefully with said nemesis.
|
38
|
+
def merge(r, equalities_resolved = false)
|
39
|
+
if ::ActiveRecord::Relation === r && !equalities_resolved
|
40
|
+
if self.table_name != r.table_name
|
41
|
+
super(r.visited)
|
42
|
+
else
|
43
|
+
merge_resolving_duplicate_squeel_equalities(r)
|
44
|
+
end
|
45
45
|
else
|
46
|
-
|
46
|
+
super(r)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -52,15 +52,12 @@ module Squeel
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def visit!
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@where_values = predicate_viz.accept((@where_values - ['']).uniq)
|
59
|
-
@having_values = predicate_viz.accept(@having_values.uniq.reject{|h| h.blank?})
|
55
|
+
@where_values = where_visit((@where_values - ['']).uniq)
|
56
|
+
@having_values = having_visit(@having_values.uniq.reject{|h| h.blank?})
|
60
57
|
# FIXME: AR barfs on ARel attributes in group_values. Workaround?
|
61
|
-
# @group_values =
|
62
|
-
@order_values =
|
63
|
-
@select_values =
|
58
|
+
# @group_values = group_visit(@group_values.uniq.reject{|g| g.blank?})
|
59
|
+
@order_values = order_visit(@order_values.uniq.reject{|o| o.blank?})
|
60
|
+
@select_values = select_visit(@select_values.uniq)
|
64
61
|
|
65
62
|
self
|
66
63
|
end
|
@@ -70,23 +67,20 @@ module Squeel
|
|
70
67
|
|
71
68
|
arel = build_join_dependency(arel, @joins_values) unless @joins_values.empty?
|
72
69
|
|
73
|
-
|
74
|
-
attribute_viz = attribute_visitor
|
75
|
-
|
76
|
-
arel = collapse_wheres(arel, predicate_viz.accept((@where_values - ['']).uniq))
|
70
|
+
arel = collapse_wheres(arel, where_visit((@where_values - ['']).uniq))
|
77
71
|
|
78
|
-
arel = arel.having(*
|
72
|
+
arel = arel.having(*having_visit(@having_values.uniq.reject{|h| h.blank?})) unless @having_values.empty?
|
79
73
|
|
80
74
|
arel = arel.take(connection.sanitize_limit(@limit_value)) if @limit_value
|
81
75
|
arel = arel.skip(@offset_value) if @offset_value
|
82
76
|
|
83
|
-
arel = arel.group(*
|
77
|
+
arel = arel.group(*group_visit(@group_values.uniq.reject{|g| g.blank?})) unless @group_values.empty?
|
84
78
|
|
85
|
-
arel = arel.order(*
|
79
|
+
arel = arel.order(*order_visit(@order_values.uniq.reject{|o| o.blank?})) unless @order_values.empty?
|
86
80
|
|
87
|
-
arel = build_select(arel,
|
81
|
+
arel = build_select(arel, select_visit(@select_values.uniq))
|
88
82
|
|
89
|
-
arel = arel.from(@from_value) if @from_value
|
83
|
+
arel = arel.from(from_visit(@from_value)) if @from_value
|
90
84
|
arel = arel.lock(@lock_value) if @lock_value
|
91
85
|
|
92
86
|
arel
|
@@ -104,7 +98,7 @@ module Squeel
|
|
104
98
|
# Rails core, but for now, I'm going to settle for this hack
|
105
99
|
# that tries really hard to coerce things to a string.
|
106
100
|
def select_for_count
|
107
|
-
visited_values =
|
101
|
+
visited_values = select_visit(select_values.uniq)
|
108
102
|
if visited_values.size == 1
|
109
103
|
select = visited_values.first
|
110
104
|
|
@@ -245,6 +239,14 @@ module Squeel
|
|
245
239
|
end
|
246
240
|
end
|
247
241
|
|
242
|
+
def from(*args)
|
243
|
+
if block_given? && args.empty?
|
244
|
+
super(DSL.eval &Proc.new)
|
245
|
+
else
|
246
|
+
super
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
248
250
|
def build_where(opts, other = [])
|
249
251
|
case opts
|
250
252
|
when String, Array
|
@@ -285,7 +287,10 @@ module Squeel
|
|
285
287
|
nodes.map { |node|
|
286
288
|
case node
|
287
289
|
when Arel::Nodes::Equality
|
288
|
-
|
290
|
+
if node.left.respond_to?(:relation) &&
|
291
|
+
node.left.relation.name == table_name
|
292
|
+
node
|
293
|
+
end
|
289
294
|
when Arel::Nodes::Grouping
|
290
295
|
find_equality_predicates([node.expr])
|
291
296
|
when Arel::Nodes::And
|
@@ -296,6 +301,48 @@ module Squeel
|
|
296
301
|
}.compact.flatten
|
297
302
|
end
|
298
303
|
|
304
|
+
def flatten_nodes(nodes)
|
305
|
+
nodes.map { |node|
|
306
|
+
case node
|
307
|
+
when Array
|
308
|
+
flatten_nodes(node)
|
309
|
+
when Nodes::And
|
310
|
+
flatten_nodes(node.children)
|
311
|
+
when Nodes::Grouping
|
312
|
+
flatten_nodes(node.expr)
|
313
|
+
else
|
314
|
+
node
|
315
|
+
end
|
316
|
+
}.flatten
|
317
|
+
end
|
318
|
+
|
319
|
+
def merge_resolving_duplicate_squeel_equalities(r)
|
320
|
+
left = clone
|
321
|
+
right = r.clone
|
322
|
+
left.where_values = flatten_nodes(left.where_values)
|
323
|
+
right.where_values = flatten_nodes(right.where_values)
|
324
|
+
right_equalities = right.where_values.select do |obj|
|
325
|
+
Nodes::Predicate === obj && obj.method_name == :eq
|
326
|
+
end
|
327
|
+
right.where_values -= right_equalities
|
328
|
+
left.where_values = resolve_duplicate_squeel_equalities(
|
329
|
+
left.where_values + right_equalities
|
330
|
+
)
|
331
|
+
left.merge(right, true)
|
332
|
+
end
|
333
|
+
|
334
|
+
def resolve_duplicate_squeel_equalities(wheres)
|
335
|
+
seen = {}
|
336
|
+
wheres.reverse.reject { |n|
|
337
|
+
nuke = false
|
338
|
+
if Nodes::Predicate === n && n.method_name == :eq
|
339
|
+
nuke = seen[n.expr]
|
340
|
+
seen[n.expr] = true
|
341
|
+
end
|
342
|
+
nuke
|
343
|
+
}.reverse
|
344
|
+
end
|
345
|
+
|
299
346
|
# Simulate the logic that occurs in #to_a
|
300
347
|
#
|
301
348
|
# This will let us get a dump of the SQL that will be run against the
|
@@ -316,10 +363,12 @@ module Squeel
|
|
316
363
|
# ...
|
317
364
|
# Since you're still looking, let me explain this horrible
|
318
365
|
# transgression you see before you.
|
366
|
+
#
|
319
367
|
# You see, Relation#where_values_hash is defined on the
|
320
|
-
# ActiveRecord::Relation class
|
321
|
-
#
|
322
|
-
#
|
368
|
+
# ActiveRecord::Relation class, itself.
|
369
|
+
#
|
370
|
+
# Since it's defined there, but I would very much like to modify its
|
371
|
+
# behavior, I have three choices:
|
323
372
|
#
|
324
373
|
# 1. Inherit from ActiveRecord::Relation in a Squeel::Relation
|
325
374
|
# class, and make an attempt to usurp all of the various calls
|
@@ -335,6 +384,9 @@ module Squeel
|
|
335
384
|
#
|
336
385
|
# I opted to go with #3. Except for the hail Hansson thing.
|
337
386
|
# Unless you're DHH, in which case, I totally said them.
|
387
|
+
#
|
388
|
+
# If you'd like to read more about alias_method_chain, see
|
389
|
+
# http://erniemiller.org/2011/02/03/when-to-use-alias_method_chain/
|
338
390
|
|
339
391
|
def self.included(base)
|
340
392
|
base.class_eval do
|
@@ -343,7 +395,7 @@ module Squeel
|
|
343
395
|
end
|
344
396
|
|
345
397
|
def where_values_hash_with_squeel
|
346
|
-
equalities = find_equality_predicates(
|
398
|
+
equalities = find_equality_predicates(where_visit(@where_values))
|
347
399
|
|
348
400
|
Hash[equalities.map { |where| [where.left.name, where.right] }]
|
349
401
|
end
|
@@ -11,11 +11,11 @@ module Squeel
|
|
11
11
|
|
12
12
|
def run_with_squeel
|
13
13
|
unless records.empty?
|
14
|
-
Visitors::
|
14
|
+
Visitors::PreloadVisitor.new.accept(associations).each { |association| preload(association) }
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|
@@ -13,37 +13,37 @@ module Squeel
|
|
13
13
|
|
14
14
|
# Returns a JoinDependency for the current relation.
|
15
15
|
#
|
16
|
-
# We don't need to clear out @join_dependency by overriding #reset,
|
17
|
-
# the default #reset already does this, despite never setting
|
18
|
-
# I can find. Serendipity, I say!
|
16
|
+
# We don't need to clear out @join_dependency by overriding #reset,
|
17
|
+
# because the default #reset already does this, despite never setting
|
18
|
+
# it anywhere that I can find. Serendipity, I say!
|
19
19
|
def join_dependency
|
20
20
|
@join_dependency ||= (build_join_dependency(table.from(table), @joins_values) && @join_dependency)
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
def attribute_visitor
|
30
|
-
Visitors::AttributeVisitor.new(
|
31
|
-
Context.new(join_dependency)
|
32
|
-
)
|
23
|
+
%w(where having group order select from).each do |visitor|
|
24
|
+
define_method "#{visitor}_visit" do |values|
|
25
|
+
Visitors.const_get("#{visitor.capitalize}Visitor").new(
|
26
|
+
Context.new(join_dependency)
|
27
|
+
).accept(values)
|
28
|
+
end
|
33
29
|
end
|
34
30
|
|
35
31
|
# We need to be able to support merging two relations without having
|
36
|
-
# to get our hooks too deeply into ActiveRecord.
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
def merge(r,
|
43
|
-
if
|
44
|
-
|
32
|
+
# to get our hooks too deeply into ActiveRecord. That proves to be
|
33
|
+
# easier said than done. I hate Relation#merge. If Squeel has a
|
34
|
+
# nemesis, Relation#merge would be it.
|
35
|
+
#
|
36
|
+
# Whatever code you see here currently is my current best attempt at
|
37
|
+
# coexisting peacefully with said nemesis.
|
38
|
+
def merge(r, equalities_resolved = false)
|
39
|
+
if ::ActiveRecord::Relation === r && !equalities_resolved
|
40
|
+
if self.table_name != r.table_name
|
41
|
+
super(r.visited)
|
42
|
+
else
|
43
|
+
merge_resolving_duplicate_squeel_equalities(r)
|
44
|
+
end
|
45
45
|
else
|
46
|
-
|
46
|
+
super(r)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -52,15 +52,12 @@ module Squeel
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def visit!
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@where_values = predicate_viz.accept((@where_values - ['']).uniq)
|
59
|
-
@having_values = predicate_viz.accept(@having_values.uniq.reject{|h| h.blank?})
|
55
|
+
@where_values = where_visit((@where_values - ['']).uniq)
|
56
|
+
@having_values = having_visit(@having_values.uniq.reject{|h| h.blank?})
|
60
57
|
# FIXME: AR barfs on ARel attributes in group_values. Workaround?
|
61
|
-
# @group_values =
|
62
|
-
@order_values =
|
63
|
-
@select_values =
|
58
|
+
# @group_values = group_visit(@group_values.uniq.reject{|g| g.blank?})
|
59
|
+
@order_values = order_visit(@order_values.uniq.reject{|o| o.blank?})
|
60
|
+
@select_values = select_visit(@select_values.uniq)
|
64
61
|
|
65
62
|
self
|
66
63
|
end
|
@@ -70,26 +67,23 @@ module Squeel
|
|
70
67
|
|
71
68
|
build_join_dependency(arel, @joins_values) unless @joins_values.empty?
|
72
69
|
|
73
|
-
|
74
|
-
attribute_viz = attribute_visitor
|
75
|
-
|
76
|
-
collapse_wheres(arel, predicate_viz.accept((@where_values - ['']).uniq))
|
70
|
+
collapse_wheres(arel, where_visit((@where_values - ['']).uniq))
|
77
71
|
|
78
|
-
arel.having(*
|
72
|
+
arel.having(*having_visit(@having_values.uniq.reject{|h| h.blank?})) unless @having_values.empty?
|
79
73
|
|
80
74
|
arel.take(connection.sanitize_limit(@limit_value)) if @limit_value
|
81
75
|
arel.skip(@offset_value) if @offset_value
|
82
76
|
|
83
|
-
arel.group(*
|
77
|
+
arel.group(*group_visit(@group_values.uniq.reject{|g| g.blank?})) unless @group_values.empty?
|
84
78
|
|
85
79
|
order = @reorder_value ? @reorder_value : @order_values
|
86
|
-
order =
|
80
|
+
order = order_visit(order)
|
87
81
|
order = reverse_sql_order(attrs_to_orderings(order)) if @reverse_order_value
|
88
82
|
arel.order(*order.uniq.reject{|o| o.blank?}) unless order.empty?
|
89
83
|
|
90
|
-
build_select(arel,
|
84
|
+
build_select(arel, select_visit(@select_values.uniq))
|
91
85
|
|
92
|
-
arel.from(@from_value) if @from_value
|
86
|
+
arel.from(from_visit(@from_value)) if @from_value
|
93
87
|
arel.lock(@lock_value) if @lock_value
|
94
88
|
|
95
89
|
arel
|
@@ -115,7 +109,7 @@ module Squeel
|
|
115
109
|
# Rails core, but for now, I'm going to settle for this hack
|
116
110
|
# that tries really hard to coerce things to a string.
|
117
111
|
def select_for_count
|
118
|
-
visited_values =
|
112
|
+
visited_values = select_visit(select_values.uniq)
|
119
113
|
if visited_values.size == 1
|
120
114
|
select = visited_values.first
|
121
115
|
|
@@ -263,6 +257,14 @@ module Squeel
|
|
263
257
|
end
|
264
258
|
end
|
265
259
|
|
260
|
+
def from(*args)
|
261
|
+
if block_given? && args.empty?
|
262
|
+
super(DSL.eval &Proc.new)
|
263
|
+
else
|
264
|
+
super
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
266
268
|
def build_where(opts, other = [])
|
267
269
|
case opts
|
268
270
|
when String, Array
|
@@ -301,7 +303,10 @@ module Squeel
|
|
301
303
|
nodes.map { |node|
|
302
304
|
case node
|
303
305
|
when Arel::Nodes::Equality
|
304
|
-
|
306
|
+
if node.left.respond_to?(:relation) &&
|
307
|
+
node.left.relation.name == table_name
|
308
|
+
node
|
309
|
+
end
|
305
310
|
when Arel::Nodes::Grouping
|
306
311
|
find_equality_predicates([node.expr])
|
307
312
|
when Arel::Nodes::And
|
@@ -327,9 +332,24 @@ module Squeel
|
|
327
332
|
}.flatten
|
328
333
|
end
|
329
334
|
|
330
|
-
def
|
335
|
+
def merge_resolving_duplicate_squeel_equalities(r)
|
336
|
+
left = clone
|
337
|
+
right = r.clone
|
338
|
+
left.where_values = flatten_nodes(left.where_values)
|
339
|
+
right.where_values = flatten_nodes(right.where_values)
|
340
|
+
right_equalities = right.where_values.select do |obj|
|
341
|
+
Nodes::Predicate === obj && obj.method_name == :eq
|
342
|
+
end
|
343
|
+
right.where_values -= right_equalities
|
344
|
+
left.where_values = resolve_duplicate_squeel_equalities(
|
345
|
+
left.where_values + right_equalities
|
346
|
+
)
|
347
|
+
left.merge(right, true)
|
348
|
+
end
|
349
|
+
|
350
|
+
def resolve_duplicate_squeel_equalities(wheres)
|
331
351
|
seen = {}
|
332
|
-
|
352
|
+
wheres.reverse.reject { |n|
|
333
353
|
nuke = false
|
334
354
|
if Nodes::Predicate === n && n.method_name == :eq
|
335
355
|
nuke = seen[n.expr]
|
@@ -360,11 +380,11 @@ module Squeel
|
|
360
380
|
# Since you're still looking, let me explain this horrible
|
361
381
|
# transgression you see before you.
|
362
382
|
#
|
363
|
-
# You see, Relation#where_values_hash
|
364
|
-
#
|
365
|
-
#
|
366
|
-
# I would very much like to modify
|
367
|
-
# choices
|
383
|
+
# You see, Relation#where_values_hash is defined on the
|
384
|
+
# ActiveRecord::Relation class, itself.
|
385
|
+
#
|
386
|
+
# Since it's defined there, but I would very much like to modify its
|
387
|
+
# behavior, I have three choices:
|
368
388
|
#
|
369
389
|
# 1. Inherit from ActiveRecord::Relation in a Squeel::Relation
|
370
390
|
# class, and make an attempt to usurp all of the various calls
|
@@ -372,7 +392,7 @@ module Squeel
|
|
372
392
|
# evil stuff with constant reassignment, all for the sake of
|
373
393
|
# being able to use super().
|
374
394
|
#
|
375
|
-
# 2. Submit a patch to Rails core, breaking
|
395
|
+
# 2. Submit a patch to Rails core, breaking this method off into
|
376
396
|
# another module, all for my own selfish desire to use super()
|
377
397
|
# while mucking about in Rails internals.
|
378
398
|
#
|
@@ -387,7 +407,6 @@ module Squeel
|
|
387
407
|
def self.included(base)
|
388
408
|
base.class_eval do
|
389
409
|
alias_method_chain :where_values_hash, :squeel
|
390
|
-
alias_method_chain :with_default_scope, :squeel
|
391
410
|
end
|
392
411
|
end
|
393
412
|
|
@@ -397,44 +416,11 @@ module Squeel
|
|
397
416
|
# And and Grouping nodes, which are equivalent to seeing top-level
|
398
417
|
# Equality nodes in stock AR terms.
|
399
418
|
def where_values_hash_with_squeel
|
400
|
-
equalities = find_equality_predicates(
|
419
|
+
equalities = find_equality_predicates(where_visit(with_default_scope.where_values))
|
401
420
|
|
402
421
|
Hash[equalities.map { |where| [where.left.name, where.right] }]
|
403
422
|
end
|
404
423
|
|
405
|
-
# with_default_scope was added to ActiveRecord ~> 3.1 in order to
|
406
|
-
# address https://github.com/rails/rails/issues/1233. Unfortunately,
|
407
|
-
# it plays havoc with Squeel's approach of visiting both sides of
|
408
|
-
# a relation merge. Thankfully, when merging with a relation from
|
409
|
-
# the same AR::Base, it's unnecessary to visit...
|
410
|
-
#
|
411
|
-
# Except, of course, this means we have to handle the edge case
|
412
|
-
# where equalities are duplicated on both sides of the merge, in
|
413
|
-
# which case, unlike all other chained relation calls, the latter
|
414
|
-
# equality overwrites the former.
|
415
|
-
#
|
416
|
-
# The workaround using overwrite_squeel_equalities works as long
|
417
|
-
# as you stick to the Squeel DSL, but breaks down if you throw hash
|
418
|
-
# conditions into the mix. If anyone's got any suggestions, I'm all
|
419
|
-
# ears. Otherwise, just stick to the Squeel DSL.
|
420
|
-
#
|
421
|
-
# Or, don't use default scopes. They're the devil, anyway. I can't
|
422
|
-
# remember the last time I used one and didn't find myself
|
423
|
-
# regretting the decision later.
|
424
|
-
def with_default_scope_with_squeel
|
425
|
-
if default_scoped? &&
|
426
|
-
default_scope = klass.build_default_scope_with_squeel
|
427
|
-
default_scope = default_scope.merge(self, true)
|
428
|
-
default_scope.default_scoped = false
|
429
|
-
default_scope.where_values = overwrite_squeel_equalities(
|
430
|
-
default_scope.where_values + self.where_values
|
431
|
-
)
|
432
|
-
default_scope
|
433
|
-
else
|
434
|
-
self
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
424
|
end
|
439
425
|
end
|
440
426
|
end
|