squeel 1.1.1 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|