squeel 1.1.1 → 1.2.1
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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +3 -0
- data/.travis.yml +36 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile +1 -1
- data/README.md +47 -6
- data/Rakefile +14 -2
- data/lib/squeel.rb +9 -1
- data/lib/squeel/adapters/active_record.rb +0 -1
- data/lib/squeel/adapters/active_record/3.0/join_dependency_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/3.0/relation_extensions.rb +12 -1
- data/lib/squeel/adapters/active_record/3.1/join_dependency_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/3.2/join_dependency_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/4.0/join_dependency_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/4.0/relation_extensions.rb +92 -0
- data/lib/squeel/adapters/active_record/4.1/compat.rb +15 -0
- data/lib/squeel/adapters/active_record/4.1/context.rb +88 -0
- data/lib/squeel/adapters/active_record/4.1/preloader_extensions.rb +31 -0
- data/lib/squeel/adapters/active_record/4.1/reflection_extensions.rb +37 -0
- data/lib/squeel/adapters/active_record/4.1/relation_extensions.rb +307 -0
- data/lib/squeel/adapters/active_record/4.2/compat.rb +1 -0
- data/lib/squeel/adapters/active_record/4.2/context.rb +1 -0
- data/lib/squeel/adapters/active_record/4.2/preloader_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/4.2/relation_extensions.rb +108 -0
- data/lib/squeel/adapters/active_record/context.rb +7 -7
- data/lib/squeel/adapters/active_record/join_dependency_extensions.rb +9 -13
- data/lib/squeel/adapters/active_record/relation_extensions.rb +38 -8
- data/lib/squeel/core_ext/symbol.rb +3 -3
- data/lib/squeel/dsl.rb +1 -1
- data/lib/squeel/nodes.rb +1 -0
- data/lib/squeel/nodes/as.rb +12 -0
- data/lib/squeel/nodes/join.rb +8 -4
- data/lib/squeel/nodes/key_path.rb +10 -1
- data/lib/squeel/nodes/node.rb +21 -0
- data/lib/squeel/nodes/stub.rb +8 -4
- data/lib/squeel/nodes/subquery_join.rb +44 -0
- data/lib/squeel/version.rb +1 -1
- data/lib/squeel/visitors.rb +2 -0
- data/lib/squeel/visitors/enumeration_visitor.rb +101 -0
- data/lib/squeel/visitors/order_visitor.rb +9 -2
- data/lib/squeel/visitors/predicate_visitor.rb +11 -0
- data/lib/squeel/visitors/preload_visitor.rb +12 -0
- data/lib/squeel/visitors/visitor.rb +89 -13
- data/spec/config.travis.yml +13 -0
- data/spec/config.yml +12 -0
- data/spec/console.rb +3 -12
- data/spec/core_ext/symbol_spec.rb +3 -3
- data/spec/helpers/squeel_helper.rb +8 -5
- data/spec/spec_helper.rb +4 -16
- data/spec/squeel/adapters/active_record/context_spec.rb +8 -4
- data/spec/squeel/adapters/active_record/join_dependency_extensions_spec.rb +123 -38
- data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +350 -124
- data/spec/squeel/core_ext/symbol_spec.rb +3 -3
- data/spec/squeel/nodes/join_spec.rb +4 -4
- data/spec/squeel/nodes/stub_spec.rb +3 -3
- data/spec/squeel/nodes/subquery_join_spec.rb +46 -0
- data/spec/squeel/visitors/order_visitor_spec.rb +3 -3
- data/spec/squeel/visitors/predicate_visitor_spec.rb +69 -36
- data/spec/squeel/visitors/select_visitor_spec.rb +1 -1
- data/spec/squeel/visitors/visitor_spec.rb +7 -6
- data/spec/support/models.rb +99 -15
- data/spec/support/schema.rb +109 -4
- data/squeel.gemspec +8 -6
- metadata +89 -107
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/spec/blueprints/articles.rb +0 -5
- data/spec/blueprints/comments.rb +0 -5
- data/spec/blueprints/notes.rb +0 -3
- data/spec/blueprints/people.rb +0 -4
- data/spec/blueprints/tags.rb +0 -3
@@ -0,0 +1,31 @@
|
|
1
|
+
module Squeel
|
2
|
+
module Adapters
|
3
|
+
module ActiveRecord
|
4
|
+
module PreloaderExtensions
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
alias_method_chain :preload, :squeel
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def preload_with_squeel(records, associations, preload_scope = nil)
|
13
|
+
records = Array.wrap(records).compact.uniq
|
14
|
+
associations = Array.wrap(associations)
|
15
|
+
preload_scope = preload_scope || ::ActiveRecord::Associations::Preloader::NULL_RELATION
|
16
|
+
|
17
|
+
if records.empty?
|
18
|
+
[]
|
19
|
+
else
|
20
|
+
Visitors::PreloadVisitor.new.accept(associations).each do |association|
|
21
|
+
preloaders_on(association, records, preload_scope)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ActiveRecord::Associations::Preloader.send :include, Squeel::Adapters::ActiveRecord::PreloaderExtensions
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Squeel
|
2
|
+
module Adapters
|
3
|
+
module ActiveRecord
|
4
|
+
module ReflectionExtensions
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.class_eval do
|
8
|
+
class << self
|
9
|
+
alias_method_chain :reflect_on_aggregation, :squeel
|
10
|
+
alias_method_chain :reflect_on_association, :squeel
|
11
|
+
alias_method_chain :_reflect_on_association, :squeel
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def reflect_on_aggregation_with_squeel(aggregation)
|
18
|
+
aggregation ||= ""
|
19
|
+
reflect_on_aggregation_without_squeel(aggregation)
|
20
|
+
end
|
21
|
+
|
22
|
+
def reflect_on_association_with_squeel(association)
|
23
|
+
association ||= ""
|
24
|
+
reflect_on_association_without_squeel(association)
|
25
|
+
end
|
26
|
+
|
27
|
+
def _reflect_on_association_with_squeel(association)
|
28
|
+
association ||= ""
|
29
|
+
_reflect_on_association_without_squeel(association)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
ActiveRecord::Base.send :include, Squeel::Adapters::ActiveRecord::ReflectionExtensions
|
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'squeel/adapters/active_record/relation_extensions'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Adapters
|
5
|
+
module ActiveRecord
|
6
|
+
module RelationExtensions
|
7
|
+
|
8
|
+
attr_accessor :stashed_join_dependencies
|
9
|
+
private :stashed_join_dependencies, :stashed_join_dependencies=
|
10
|
+
|
11
|
+
def reset
|
12
|
+
@stashed_join_dependencies = nil
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
# where.not is a pain. It calls the private `build_where` method on its
|
17
|
+
# scope, and since ActiveRecord::Relation already includes the original
|
18
|
+
# ActiveRecord::QueryMethods module, we have to find a way to trick the
|
19
|
+
# scope passed to the WhereChain initializer into having the original
|
20
|
+
# behavior. This is a way to do it that avoids using alias_method_chain.
|
21
|
+
module WhereChainCompatibility
|
22
|
+
include ::ActiveRecord::QueryMethods
|
23
|
+
define_method :build_where,
|
24
|
+
::ActiveRecord::QueryMethods.instance_method(:build_where)
|
25
|
+
end
|
26
|
+
|
27
|
+
def where(opts = :chain, *rest)
|
28
|
+
if block_given?
|
29
|
+
super(DSL.eval &Proc.new)
|
30
|
+
else
|
31
|
+
if opts == :chain
|
32
|
+
scope = spawn
|
33
|
+
scope.extend(WhereChainCompatibility)
|
34
|
+
::ActiveRecord::QueryMethods::WhereChain.new(scope)
|
35
|
+
else
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def visited
|
42
|
+
visit!
|
43
|
+
end
|
44
|
+
|
45
|
+
def where_unscoping(target_value)
|
46
|
+
target_value = target_value.to_s
|
47
|
+
|
48
|
+
where_values.reject! do |rel|
|
49
|
+
case rel
|
50
|
+
when Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual
|
51
|
+
subrelation = (rel.left.kind_of?(Arel::Attributes::Attribute) ? rel.left : rel.right)
|
52
|
+
subrelation.name == target_value
|
53
|
+
when Hash
|
54
|
+
rel.stringify_keys.has_key?(target_value)
|
55
|
+
when Squeel::Nodes::Predicate
|
56
|
+
rel.expr.symbol.to_s == target_value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
bind_values.reject! { |col,_| col.name == target_value }
|
61
|
+
end
|
62
|
+
|
63
|
+
def reverse_sql_order(order_query)
|
64
|
+
return super if order_query.empty?
|
65
|
+
|
66
|
+
order_query.flat_map do |o|
|
67
|
+
case o
|
68
|
+
when Arel::Attributes::Attribute
|
69
|
+
Arel::Nodes::Ascending.new(o).reverse
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_arel
|
77
|
+
arel = Arel::SelectManager.new(table.engine, table)
|
78
|
+
|
79
|
+
build_joins(arel, joins_values.flatten) unless joins_values.empty?
|
80
|
+
|
81
|
+
collapse_wheres(arel, where_visit((where_values - ['']).uniq))
|
82
|
+
|
83
|
+
arel.having(*having_visit(having_values.uniq.reject{|h| h.blank?})) unless having_values.empty?
|
84
|
+
|
85
|
+
arel.take(connection.sanitize_limit(limit_value)) if limit_value
|
86
|
+
arel.skip(offset_value.to_i) if offset_value
|
87
|
+
|
88
|
+
arel.group(*group_visit(group_values.uniq.reject{|g| g.blank?})) unless group_values.empty?
|
89
|
+
|
90
|
+
build_order(arel)
|
91
|
+
|
92
|
+
build_select(arel, select_visit(select_values.uniq))
|
93
|
+
|
94
|
+
arel.distinct(distinct_value)
|
95
|
+
arel.from(build_from) if from_value
|
96
|
+
arel.lock(lock_value) if lock_value
|
97
|
+
|
98
|
+
# Reorder bind indexes when joins or subqueries include more bindings.
|
99
|
+
# Special for PostgreSQL
|
100
|
+
if arel.bind_values.any? || bind_values.size > 1
|
101
|
+
bvs = arel.bind_values + bind_values
|
102
|
+
arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
|
103
|
+
column = bvs[i].first
|
104
|
+
bp.replace connection.substitute_at(column, i)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
arel
|
109
|
+
end
|
110
|
+
|
111
|
+
def build_join_dependency(manager, joins)
|
112
|
+
buckets = joins.group_by do |join|
|
113
|
+
case join
|
114
|
+
when String
|
115
|
+
:string_join
|
116
|
+
when Hash, Symbol, Array, Nodes::Stub, Nodes::Join, Nodes::KeyPath
|
117
|
+
:association_join
|
118
|
+
when ::ActiveRecord::Associations::JoinDependency
|
119
|
+
:stashed_join
|
120
|
+
when Arel::Nodes::Join
|
121
|
+
:join_node
|
122
|
+
when Nodes::SubqueryJoin
|
123
|
+
:subquery_join
|
124
|
+
else
|
125
|
+
raise 'unknown class: %s' % join.class.name
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
association_joins = buckets[:association_join] || []
|
130
|
+
stashed_association_joins = buckets[:stashed_join] || []
|
131
|
+
join_nodes = (buckets[:join_node] || []).uniq
|
132
|
+
subquery_joins = (buckets[:subquery_join] || []).uniq
|
133
|
+
string_joins = (buckets[:string_join] || []).map { |x|
|
134
|
+
x.strip
|
135
|
+
}.uniq
|
136
|
+
|
137
|
+
join_list = join_nodes + custom_join_ast(manager, string_joins)
|
138
|
+
|
139
|
+
# All of that duplication just to do this...
|
140
|
+
self.join_dependency = ::ActiveRecord::Associations::JoinDependency.new(
|
141
|
+
@klass,
|
142
|
+
association_joins,
|
143
|
+
join_list
|
144
|
+
)
|
145
|
+
|
146
|
+
self.stashed_join_dependencies = stashed_association_joins
|
147
|
+
|
148
|
+
joins = join_dependency.join_constraints stashed_association_joins
|
149
|
+
|
150
|
+
joins.each { |join| manager.from(join) }
|
151
|
+
|
152
|
+
manager.join_sources.concat(join_list)
|
153
|
+
manager.join_sources.concat(build_join_from_subquery(subquery_joins))
|
154
|
+
|
155
|
+
manager
|
156
|
+
end
|
157
|
+
|
158
|
+
alias :build_joins :build_join_dependency
|
159
|
+
|
160
|
+
# Redefine all visiting methods that depends on build_join
|
161
|
+
# All includes_values and eager_loading_values are pushed into a new
|
162
|
+
# JoinDependency class after Rails 4.1 and never are grafted,
|
163
|
+
# so that we need to walk through all JoinDependency
|
164
|
+
# to find proper alias table names.
|
165
|
+
#
|
166
|
+
# And use a ! method in Context, so we can throw an error when we can't
|
167
|
+
# find proper value in a JoinDependency
|
168
|
+
%w(where having group order).each do |visitor|
|
169
|
+
define_method "#{visitor}_visit" do |values|
|
170
|
+
join_dependencies = [join_dependency] + stashed_join_dependencies
|
171
|
+
join_dependencies.each do |jd|
|
172
|
+
context = Adapters::ActiveRecord::Context.new(jd)
|
173
|
+
begin
|
174
|
+
return Visitors.const_get("#{visitor.capitalize}Visitor").new(context).accept!(values)
|
175
|
+
rescue Adapters::ActiveRecord::Context::NoParentFoundError => e
|
176
|
+
next
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Fail Safe, call the normal accept method.
|
181
|
+
context = Adapters::ActiveRecord::Context.new(join_dependency)
|
182
|
+
Visitors.const_get("#{visitor.capitalize}Visitor").new(context).accept(values)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def build_where(opts, other = [])
|
187
|
+
case opts
|
188
|
+
when String, Array
|
189
|
+
super
|
190
|
+
else # Let's prevent PredicateBuilder from doing its thing
|
191
|
+
[opts, *other].map do |arg|
|
192
|
+
case arg
|
193
|
+
when Array # Just in case there's an array in there somewhere
|
194
|
+
super
|
195
|
+
when Hash
|
196
|
+
attributes = expand_attrs_from_hash(arg)
|
197
|
+
|
198
|
+
preprocess_attrs_with_ar(attributes)
|
199
|
+
when Squeel::Nodes::Node
|
200
|
+
arg.grep(::ActiveRecord::Relation) do |rel|
|
201
|
+
self.bind_values += rel.bind_values
|
202
|
+
end
|
203
|
+
arg
|
204
|
+
else
|
205
|
+
arg
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def build_from
|
212
|
+
opts, name = from_visit(from_value)
|
213
|
+
case opts
|
214
|
+
when ::ActiveRecord::Relation
|
215
|
+
name ||= 'subquery'
|
216
|
+
self.bind_values = opts.bind_values + self.bind_values
|
217
|
+
opts.arel.as(name.to_s)
|
218
|
+
when ::Arel::SelectManager
|
219
|
+
name ||= 'subquery'
|
220
|
+
opts.as(name.to_s)
|
221
|
+
else
|
222
|
+
opts
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def build_order(arel)
|
227
|
+
orders = order_visit(dehashified_order_values)
|
228
|
+
orders = orders.uniq.reject(&:blank?)
|
229
|
+
orders = reverse_sql_order(orders) if reverse_order_value && !reordering_value
|
230
|
+
|
231
|
+
arel.order(*orders) unless orders.empty?
|
232
|
+
end
|
233
|
+
|
234
|
+
def where_values_hash_with_squeel(relation_table_name = table_name)
|
235
|
+
equalities = find_equality_predicates(where_visit(where_values), relation_table_name)
|
236
|
+
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
|
237
|
+
|
238
|
+
Hash[equalities.map { |where|
|
239
|
+
name = where.left.name
|
240
|
+
[name, binds.fetch(name.to_s) { where.right }]
|
241
|
+
}]
|
242
|
+
end
|
243
|
+
|
244
|
+
def debug_sql
|
245
|
+
eager_loading? ? to_sql : arel.to_sql
|
246
|
+
end
|
247
|
+
|
248
|
+
def to_sql_with_binding_params
|
249
|
+
@to_sql ||= begin
|
250
|
+
relation = self
|
251
|
+
connection = klass.connection
|
252
|
+
|
253
|
+
if eager_loading?
|
254
|
+
find_with_associations { |rel| relation = rel }
|
255
|
+
end
|
256
|
+
|
257
|
+
ast = relation.arel.ast
|
258
|
+
binds = relation.bind_values.dup
|
259
|
+
|
260
|
+
visitor = connection.visitor.clone
|
261
|
+
visitor.class_eval do
|
262
|
+
include ::Arel::Visitors::BindVisitor
|
263
|
+
end
|
264
|
+
|
265
|
+
visitor.accept(ast) do
|
266
|
+
connection.quote(*binds.shift.reverse)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
private
|
272
|
+
|
273
|
+
def expand_attrs_from_hash(opts)
|
274
|
+
opts = ::ActiveRecord::PredicateBuilder.resolve_column_aliases(klass, opts)
|
275
|
+
attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
|
276
|
+
|
277
|
+
attributes.values.grep(::ActiveRecord::Relation) do |rel|
|
278
|
+
self.bind_values += rel.bind_values
|
279
|
+
end
|
280
|
+
|
281
|
+
attributes
|
282
|
+
end
|
283
|
+
|
284
|
+
def dehashified_order_values
|
285
|
+
order_values.map { |o|
|
286
|
+
if Hash === o && o.values.all? { |v| [:asc, :desc].include?(v) }
|
287
|
+
o.map { |field, dir| table[field].send(dir) }
|
288
|
+
else
|
289
|
+
o
|
290
|
+
end
|
291
|
+
}
|
292
|
+
end
|
293
|
+
|
294
|
+
def build_join_from_subquery(subquery_joins)
|
295
|
+
subquery_joins.map do |join|
|
296
|
+
join.type.new(
|
297
|
+
Arel::Nodes::TableAlias.new(join.subquery.left.arel, join.subquery.right),
|
298
|
+
Arel::Nodes::On.new(where_visit(join.constraints))
|
299
|
+
)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
ActiveRecord::Relation.send :include, Squeel::Adapters::ActiveRecord::RelationExtensions
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'squeel/adapters/active_record/4.1/compat'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'squeel/adapters/active_record/4.1/context'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'squeel/adapters/active_record/4.1/preloader_extensions'
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'squeel/adapters/active_record/4.1/relation_extensions'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Adapters
|
5
|
+
module ActiveRecord
|
6
|
+
module RelationExtensions
|
7
|
+
|
8
|
+
undef_method 'to_sql_with_binding_params'
|
9
|
+
|
10
|
+
attr_accessor :reverse_order_value
|
11
|
+
private :reverse_order_value, :reverse_order_value=
|
12
|
+
|
13
|
+
# We are using 4.1 version of reverse_order!
|
14
|
+
# Because 4.2 reverse the order immediately before build_order
|
15
|
+
def reverse_order!
|
16
|
+
self.reverse_order_value = !reverse_order_value
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_join_dependency(manager, joins)
|
21
|
+
buckets = joins.group_by do |join|
|
22
|
+
case join
|
23
|
+
when String
|
24
|
+
:string_join
|
25
|
+
when Hash, Symbol, Array, Nodes::Stub, Nodes::Join, Nodes::KeyPath
|
26
|
+
:association_join
|
27
|
+
when ::ActiveRecord::Associations::JoinDependency
|
28
|
+
:stashed_join
|
29
|
+
when Arel::Nodes::Join
|
30
|
+
:join_node
|
31
|
+
when Nodes::SubqueryJoin
|
32
|
+
:subquery_join
|
33
|
+
else
|
34
|
+
raise 'unknown class: %s' % join.class.name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
association_joins = buckets[:association_join] || []
|
39
|
+
stashed_association_joins = buckets[:stashed_join] || []
|
40
|
+
join_nodes = (buckets[:join_node] || []).uniq
|
41
|
+
subquery_joins = buckets[:subquery_join] || []
|
42
|
+
string_joins = (buckets[:string_join] || []).map { |x|
|
43
|
+
x.strip
|
44
|
+
}.uniq
|
45
|
+
|
46
|
+
join_list = join_nodes + custom_join_ast(manager, string_joins)
|
47
|
+
|
48
|
+
# All of that duplication just to do this...
|
49
|
+
self.join_dependency = ::ActiveRecord::Associations::JoinDependency.new(
|
50
|
+
@klass,
|
51
|
+
association_joins,
|
52
|
+
join_list
|
53
|
+
)
|
54
|
+
|
55
|
+
self.stashed_join_dependencies = stashed_association_joins
|
56
|
+
|
57
|
+
join_infos = join_dependency.join_constraints stashed_association_joins
|
58
|
+
|
59
|
+
join_infos.each do |info|
|
60
|
+
info.joins.each { |join| manager.from(join) }
|
61
|
+
manager.bind_values.concat info.binds
|
62
|
+
end
|
63
|
+
|
64
|
+
manager.join_sources.concat(join_list)
|
65
|
+
manager.join_sources.concat(build_join_from_subquery(subquery_joins))
|
66
|
+
|
67
|
+
manager
|
68
|
+
end
|
69
|
+
|
70
|
+
alias :build_joins :build_join_dependency
|
71
|
+
|
72
|
+
def where_values_hash_with_squeel(relation_table_name = table_name)
|
73
|
+
equalities = find_equality_predicates(where_visit(where_values), relation_table_name)
|
74
|
+
|
75
|
+
binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
|
76
|
+
|
77
|
+
Hash[equalities.map { |where|
|
78
|
+
name = where.left.name
|
79
|
+
[name, binds.fetch(name.to_s) {
|
80
|
+
case where.right
|
81
|
+
when Array then where.right.map(&:val)
|
82
|
+
else
|
83
|
+
where.right.val
|
84
|
+
end
|
85
|
+
}]
|
86
|
+
}]
|
87
|
+
end
|
88
|
+
|
89
|
+
def expand_attrs_from_hash(opts)
|
90
|
+
opts = ::ActiveRecord::PredicateBuilder.resolve_column_aliases(klass, opts)
|
91
|
+
|
92
|
+
bv_len = bind_values.length
|
93
|
+
tmp_opts, bind_values = create_binds(opts, bv_len)
|
94
|
+
self.bind_values += bind_values
|
95
|
+
|
96
|
+
attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
|
97
|
+
attributes.values.grep(::ActiveRecord::Relation) do |rel|
|
98
|
+
self.bind_values += rel.bind_values
|
99
|
+
end
|
100
|
+
|
101
|
+
attributes
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
ActiveRecord::Relation.send :include, Squeel::Adapters::ActiveRecord::RelationExtensions
|