squeel 1.0.9 → 1.0.11
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 +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
|