squeel 0.9.3 → 0.9.4
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/.travis.yml +5 -2
- data/lib/squeel/adapters/active_record.rb +8 -0
- data/lib/squeel/adapters/active_record/3.1/context.rb +76 -0
- data/lib/squeel/adapters/active_record/3.1/preloader_extensions.rb +21 -0
- data/lib/squeel/adapters/active_record/3.1/relation_extensions.rb +360 -0
- data/lib/squeel/adapters/active_record/context.rb +1 -76
- data/lib/squeel/adapters/active_record/preloader_extensions.rb +1 -21
- data/lib/squeel/adapters/active_record/relation_extensions.rb +5 -323
- data/lib/squeel/configuration.rb +2 -2
- data/lib/{core_ext → squeel/core_ext}/hash.rb +0 -0
- data/lib/{core_ext → squeel/core_ext}/symbol.rb +0 -0
- data/lib/squeel/version.rb +1 -1
- data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +4 -0
- data/spec/support/schema.rb +2 -0
- metadata +21 -18
data/.travis.yml
CHANGED
@@ -15,6 +15,14 @@ when 3
|
|
15
15
|
ActiveRecord::Relation.send :include, Squeel::Adapters::ActiveRecord::RelationExtensions
|
16
16
|
ActiveRecord::Associations::ClassMethods::JoinDependency.send :include, Squeel::Adapters::ActiveRecord::JoinDependencyExtensions
|
17
17
|
ActiveRecord::Base.extend Squeel::Adapters::ActiveRecord::AssociationPreloadExtensions
|
18
|
+
when 1
|
19
|
+
require 'squeel/adapters/active_record/3.1/relation_extensions'
|
20
|
+
require 'squeel/adapters/active_record/3.1/preloader_extensions'
|
21
|
+
require 'squeel/adapters/active_record/3.1/context'
|
22
|
+
|
23
|
+
ActiveRecord::Relation.send :include, Squeel::Adapters::ActiveRecord::RelationExtensions
|
24
|
+
ActiveRecord::Associations::JoinDependency.send :include, Squeel::Adapters::ActiveRecord::JoinDependencyExtensions
|
25
|
+
ActiveRecord::Associations::Preloader.send :include, Squeel::Adapters::ActiveRecord::PreloaderExtensions
|
18
26
|
else
|
19
27
|
require 'squeel/adapters/active_record/relation_extensions'
|
20
28
|
require 'squeel/adapters/active_record/preloader_extensions'
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'squeel/context'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Adapters
|
5
|
+
module ActiveRecord
|
6
|
+
class Context < ::Squeel::Context
|
7
|
+
# Because the AR::Associations namespace is insane
|
8
|
+
JoinPart = ::ActiveRecord::Associations::JoinDependency::JoinPart
|
9
|
+
|
10
|
+
def initialize(object)
|
11
|
+
super
|
12
|
+
@base = object.join_base
|
13
|
+
@engine = @base.arel_engine
|
14
|
+
@arel_visitor = @engine.connection.visitor
|
15
|
+
@default_table = Arel::Table.new(@base.table_name, :as => @base.aliased_table_name, :engine => @engine)
|
16
|
+
end
|
17
|
+
|
18
|
+
def find(object, parent = @base)
|
19
|
+
if JoinPart === parent
|
20
|
+
object = object.to_sym if String === object
|
21
|
+
case object
|
22
|
+
when Symbol, Nodes::Stub
|
23
|
+
@object.join_associations.detect { |j|
|
24
|
+
j.reflection.name == object.to_sym && j.parent == parent
|
25
|
+
}
|
26
|
+
when Nodes::Join
|
27
|
+
@object.join_associations.detect { |j|
|
28
|
+
j.reflection.name == object.name && j.parent == parent &&
|
29
|
+
(object.polymorphic? ? j.reflection.klass == object._klass : true)
|
30
|
+
}
|
31
|
+
else
|
32
|
+
@object.join_associations.detect { |j|
|
33
|
+
j.reflection == object && j.parent == parent
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def traverse(keypath, parent = @base, include_endpoint = false)
|
40
|
+
parent = @base if keypath.absolute?
|
41
|
+
keypath.path.each do |key|
|
42
|
+
parent = find(key, parent) || key
|
43
|
+
end
|
44
|
+
parent = find(keypath.endpoint, parent) if include_endpoint
|
45
|
+
|
46
|
+
parent
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def get_table(object)
|
52
|
+
if [Symbol, String, Nodes::Stub].include?(object.class)
|
53
|
+
Arel::Table.new(object.to_sym, :engine => @engine)
|
54
|
+
elsif Nodes::Join === object
|
55
|
+
object._klass ? object._klass.arel_table : Arel::Table.new(object._name, :engine => @engine)
|
56
|
+
elsif object.respond_to?(:aliased_table_name)
|
57
|
+
Arel::Table.new(object.table_name, :as => object.aliased_table_name, :engine => @engine)
|
58
|
+
else
|
59
|
+
raise ArgumentError, "Unable to get table for #{object}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def classify(object)
|
64
|
+
if Class === object
|
65
|
+
object
|
66
|
+
elsif object.respond_to? :active_record
|
67
|
+
object.active_record
|
68
|
+
else
|
69
|
+
raise ArgumentError, "#{object} can't be converted to a class"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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 :run, :squeel
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_with_squeel
|
13
|
+
unless records.empty?
|
14
|
+
Visitors::SymbolVisitor.new.accept(associations).each { |association| preload(association) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,360 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Adapters
|
5
|
+
module ActiveRecord
|
6
|
+
module RelationExtensions
|
7
|
+
|
8
|
+
JoinAssociation = ::ActiveRecord::Associations::JoinDependency::JoinAssociation
|
9
|
+
JoinDependency = ::ActiveRecord::Associations::JoinDependency
|
10
|
+
|
11
|
+
attr_writer :join_dependency
|
12
|
+
private :join_dependency=
|
13
|
+
|
14
|
+
# Returns a JoinDependency for the current relation.
|
15
|
+
#
|
16
|
+
# We don't need to clear out @join_dependency by overriding #reset, because
|
17
|
+
# the default #reset already does this, despite never setting it anywhere that
|
18
|
+
# I can find. Serendipity, I say!
|
19
|
+
def join_dependency
|
20
|
+
@join_dependency ||= (build_join_dependency(table.from(table), @joins_values) && @join_dependency)
|
21
|
+
end
|
22
|
+
|
23
|
+
def predicate_visitor
|
24
|
+
Visitors::PredicateVisitor.new(
|
25
|
+
Context.new(join_dependency)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def attribute_visitor
|
30
|
+
Visitors::AttributeVisitor.new(
|
31
|
+
Context.new(join_dependency)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
# We need to be able to support merging two relations that have a different
|
36
|
+
# base class. Stock ActiveRecord doesn't have to do anything too special, because
|
37
|
+
# it's already created predicates out of the where_values by now, and they're
|
38
|
+
# already bound to the proper table.
|
39
|
+
#
|
40
|
+
# Squeel, on the other hand, needs to do its best to ensure the predicates are still
|
41
|
+
# winding up against the proper table. The most "correct" way I can think of to do
|
42
|
+
# this is to try to emulate the default AR behavior -- that is, de-squeelifying
|
43
|
+
# the *_values, erm... values by visiting them and converting them to ARel nodes
|
44
|
+
# before merging. Merging relations is a nifty little trick, but it's another
|
45
|
+
# little corner of ActiveRecord where the magic quickly fades. :(
|
46
|
+
def merge(r)
|
47
|
+
if relation_with_different_base?(r)
|
48
|
+
r = r.clone.visit!
|
49
|
+
end
|
50
|
+
|
51
|
+
super(r)
|
52
|
+
end
|
53
|
+
|
54
|
+
def relation_with_different_base?(r)
|
55
|
+
::ActiveRecord::Relation === r &&
|
56
|
+
base_class.name != r.klass.base_class.name
|
57
|
+
end
|
58
|
+
|
59
|
+
def prepare_relation_for_association_merge!(r, association_name)
|
60
|
+
r.where_values.map! {|w| Squeel::Visitors::PredicateVisitor.can_visit?(w) ? {association_name => w} : w}
|
61
|
+
r.having_values.map! {|h| Squeel::Visitors::PredicateVisitor.can_visit?(h) ? {association_name => h} : h}
|
62
|
+
r.group_values.map! {|g| Squeel::Visitors::AttributeVisitor.can_visit?(g) ? {association_name => g} : g}
|
63
|
+
r.order_values.map! {|o| Squeel::Visitors::AttributeVisitor.can_visit?(o) ? {association_name => o} : o}
|
64
|
+
r.select_values.map! {|s| Squeel::Visitors::AttributeVisitor.can_visit?(s) ? {association_name => s} : s}
|
65
|
+
r.joins_values.map! {|j| [Symbol, Hash, Nodes::Stub, Nodes::Join, Nodes::KeyPath].include?(j.class) ? {association_name => j} : j}
|
66
|
+
r.includes_values.map! {|i| [Symbol, Hash, Nodes::Stub, Nodes::Join, Nodes::KeyPath].include?(i.class) ? {association_name => i} : i}
|
67
|
+
end
|
68
|
+
|
69
|
+
def visit!
|
70
|
+
predicate_viz = predicate_visitor
|
71
|
+
attribute_viz = attribute_visitor
|
72
|
+
|
73
|
+
@where_values = predicate_viz.accept((@where_values - ['']).uniq)
|
74
|
+
@having_values = predicate_viz.accept(@having_values.uniq.reject{|h| h.blank?})
|
75
|
+
@group_values = attribute_viz.accept(@group_values.uniq.reject{|g| g.blank?})
|
76
|
+
@order_values = attribute_viz.accept(@order_values.uniq.reject{|o| o.blank?})
|
77
|
+
@select_values = attribute_viz.accept(@select_values.uniq)
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def build_arel
|
83
|
+
arel = table.from table
|
84
|
+
|
85
|
+
build_join_dependency(arel, @joins_values) unless @joins_values.empty?
|
86
|
+
|
87
|
+
predicate_viz = predicate_visitor
|
88
|
+
attribute_viz = attribute_visitor
|
89
|
+
|
90
|
+
collapse_wheres(arel, predicate_viz.accept((@where_values - ['']).uniq))
|
91
|
+
|
92
|
+
arel.having(*predicate_viz.accept(@having_values.uniq.reject{|h| h.blank?})) unless @having_values.empty?
|
93
|
+
|
94
|
+
arel.take(connection.sanitize_limit(@limit_value)) if @limit_value
|
95
|
+
arel.skip(@offset_value) if @offset_value
|
96
|
+
|
97
|
+
arel.group(*attribute_viz.accept(@group_values.uniq.reject{|g| g.blank?})) unless @group_values.empty?
|
98
|
+
|
99
|
+
order = @reorder_value ? @reorder_value : @order_values
|
100
|
+
order = attribute_viz.accept(order.uniq.reject{|o| o.blank?})
|
101
|
+
order = reverse_sql_order(attrs_to_orderings(order)) if @reverse_order_value
|
102
|
+
arel.order(*order) unless order.empty?
|
103
|
+
|
104
|
+
build_select(arel, attribute_viz.accept(@select_values.uniq))
|
105
|
+
|
106
|
+
arel.from(@from_value) if @from_value
|
107
|
+
arel.lock(@lock_value) if @lock_value
|
108
|
+
|
109
|
+
arel
|
110
|
+
end
|
111
|
+
|
112
|
+
# reverse_sql_order will reverse the order of strings or Orderings,
|
113
|
+
# but not attributes
|
114
|
+
def attrs_to_orderings(order)
|
115
|
+
order.map do |o|
|
116
|
+
Arel::Attribute === o ? o.asc : o
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def build_join_dependency(manager, joins)
|
121
|
+
buckets = joins.group_by do |join|
|
122
|
+
case join
|
123
|
+
when String
|
124
|
+
'string_join'
|
125
|
+
when Hash, Symbol, Array, Nodes::Stub, Nodes::Join, Nodes::KeyPath
|
126
|
+
'association_join'
|
127
|
+
when JoinAssociation
|
128
|
+
'stashed_join'
|
129
|
+
when Arel::Nodes::Join
|
130
|
+
'join_node'
|
131
|
+
else
|
132
|
+
raise 'unknown class: %s' % join.class.name
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
association_joins = buckets['association_join'] || []
|
137
|
+
stashed_association_joins = buckets['stashed_join'] || []
|
138
|
+
join_nodes = buckets['join_node'] || []
|
139
|
+
string_joins = (buckets['string_join'] || []).map { |x|
|
140
|
+
x.strip
|
141
|
+
}.uniq
|
142
|
+
|
143
|
+
join_list = custom_join_ast(manager, string_joins)
|
144
|
+
|
145
|
+
# All of this duplication just to add
|
146
|
+
self.join_dependency = JoinDependency.new(
|
147
|
+
@klass,
|
148
|
+
association_joins,
|
149
|
+
join_list
|
150
|
+
)
|
151
|
+
|
152
|
+
join_nodes.each do |join|
|
153
|
+
join_dependency.alias_tracker.aliased_name_for(join.left.name.downcase)
|
154
|
+
end
|
155
|
+
|
156
|
+
join_dependency.graft(*stashed_association_joins)
|
157
|
+
|
158
|
+
@implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
|
159
|
+
|
160
|
+
join_dependency.join_associations.each do |association|
|
161
|
+
association.join_to(manager)
|
162
|
+
end
|
163
|
+
|
164
|
+
manager.join_sources.concat join_nodes.uniq
|
165
|
+
manager.join_sources.concat join_list
|
166
|
+
|
167
|
+
manager
|
168
|
+
end
|
169
|
+
|
170
|
+
def includes(*args)
|
171
|
+
if block_given? && args.empty?
|
172
|
+
super(DSL.eval &Proc.new)
|
173
|
+
else
|
174
|
+
super
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def preload(*args)
|
179
|
+
if block_given? && args.empty?
|
180
|
+
super(DSL.eval &Proc.new)
|
181
|
+
else
|
182
|
+
super
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def eager_load(*args)
|
187
|
+
if block_given? && args.empty?
|
188
|
+
super(DSL.eval &Proc.new)
|
189
|
+
else
|
190
|
+
super
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def select(value = Proc.new)
|
195
|
+
if block_given? && Proc === value
|
196
|
+
if value.arity > 0
|
197
|
+
to_a.select {|*block_args| value.call(*block_args)}
|
198
|
+
else
|
199
|
+
relation = clone
|
200
|
+
relation.select_values += Array.wrap(DSL.eval &value)
|
201
|
+
relation
|
202
|
+
end
|
203
|
+
else
|
204
|
+
super
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def group(*args)
|
209
|
+
if block_given? && args.empty?
|
210
|
+
super(DSL.eval &Proc.new)
|
211
|
+
else
|
212
|
+
super
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def order(*args)
|
217
|
+
if block_given? && args.empty?
|
218
|
+
super(DSL.eval &Proc.new)
|
219
|
+
else
|
220
|
+
super
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def reorder(*args)
|
225
|
+
if block_given? && args.empty?
|
226
|
+
super(DSL.eval &Proc.new)
|
227
|
+
else
|
228
|
+
super
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def joins(*args)
|
233
|
+
if block_given? && args.empty?
|
234
|
+
super(DSL.eval &Proc.new)
|
235
|
+
else
|
236
|
+
super
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def where(opts = Proc.new, *rest)
|
241
|
+
if block_given? && Proc === opts
|
242
|
+
super(DSL.eval &opts)
|
243
|
+
else
|
244
|
+
super
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def having(*args)
|
249
|
+
if block_given? && args.empty?
|
250
|
+
super(DSL.eval &Proc.new)
|
251
|
+
else
|
252
|
+
super
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def build_where(opts, other = [])
|
257
|
+
case opts
|
258
|
+
when String, Array
|
259
|
+
super
|
260
|
+
else # Let's prevent PredicateBuilder from doing its thing
|
261
|
+
[opts, *other].map do |arg|
|
262
|
+
case arg
|
263
|
+
when Array # Just in case there's an array in there somewhere
|
264
|
+
@klass.send(:sanitize_sql, arg)
|
265
|
+
when Hash
|
266
|
+
@klass.send(:expand_hash_conditions_for_aggregates, arg)
|
267
|
+
else
|
268
|
+
arg
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def collapse_wheres(arel, wheres)
|
275
|
+
wheres = Array(wheres)
|
276
|
+
binaries = wheres.grep(Arel::Nodes::Binary)
|
277
|
+
|
278
|
+
groups = binaries.group_by {|b| [b.class, b.left]}
|
279
|
+
|
280
|
+
groups.each do |_, bins|
|
281
|
+
arel.where(Arel::Nodes::And.new(bins))
|
282
|
+
end
|
283
|
+
|
284
|
+
(wheres - binaries).each do |where|
|
285
|
+
where = Arel.sql(where) if String === where
|
286
|
+
arel.where(Arel::Nodes::Grouping.new(where))
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def find_equality_predicates(nodes)
|
291
|
+
nodes.map { |node|
|
292
|
+
case node
|
293
|
+
when Arel::Nodes::Equality
|
294
|
+
node if node.left.relation.name == table_name
|
295
|
+
when Arel::Nodes::Grouping
|
296
|
+
find_equality_predicates([node.expr])
|
297
|
+
when Arel::Nodes::And
|
298
|
+
find_equality_predicates(node.children)
|
299
|
+
else
|
300
|
+
nil
|
301
|
+
end
|
302
|
+
}.compact.flatten
|
303
|
+
end
|
304
|
+
|
305
|
+
# Simulate the logic that occurs in #to_a
|
306
|
+
#
|
307
|
+
# This will let us get a dump of the SQL that will be run against the
|
308
|
+
# DB for debug purposes without actually running the query.
|
309
|
+
def debug_sql
|
310
|
+
if eager_loading?
|
311
|
+
including = (@eager_load_values + @includes_values).uniq
|
312
|
+
join_dependency = JoinDependency.new(@klass, including, [])
|
313
|
+
construct_relation_for_association_find(join_dependency).to_sql
|
314
|
+
else
|
315
|
+
arel.to_sql
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
### ZOMG ALIAS_METHOD_CHAIN IS BELOW. HIDE YOUR EYES!
|
320
|
+
# ...
|
321
|
+
# ...
|
322
|
+
# ...
|
323
|
+
# Since you're still looking, let me explain this horrible
|
324
|
+
# transgression you see before you.
|
325
|
+
# You see, Relation#where_values_hash is defined on the
|
326
|
+
# ActiveRecord::Relation class. Since it's defined there, but
|
327
|
+
# I would very much like to modify its behavior, I have three
|
328
|
+
# choices.
|
329
|
+
#
|
330
|
+
# 1. Inherit from ActiveRecord::Relation in a Squeel::Relation
|
331
|
+
# class, and make an attempt to usurp all of the various calls
|
332
|
+
# to methods on ActiveRecord::Relation by doing some really
|
333
|
+
# evil stuff with constant reassignment, all for the sake of
|
334
|
+
# being able to use super().
|
335
|
+
#
|
336
|
+
# 2. Submit a patch to Rails core, breaking this method off into
|
337
|
+
# another module, all for my own selfish desire to use super()
|
338
|
+
# while mucking about in Rails internals.
|
339
|
+
#
|
340
|
+
# 3. Use alias_method_chain, and say 10 hail Hanssons as penance.
|
341
|
+
#
|
342
|
+
# I opted to go with #3. Except for the hail Hansson thing.
|
343
|
+
# Unless you're DHH, in which case, I totally said them.
|
344
|
+
|
345
|
+
def self.included(base)
|
346
|
+
base.class_eval do
|
347
|
+
alias_method_chain :where_values_hash, :squeel
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def where_values_hash_with_squeel
|
352
|
+
equalities = find_equality_predicates(predicate_visitor.accept(@where_values))
|
353
|
+
|
354
|
+
Hash[equalities.map { |where| [where.left.name, where.right] }]
|
355
|
+
end
|
356
|
+
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
@@ -1,76 +1 @@
|
|
1
|
-
require 'squeel/context'
|
2
|
-
|
3
|
-
module Squeel
|
4
|
-
module Adapters
|
5
|
-
module ActiveRecord
|
6
|
-
class Context < ::Squeel::Context
|
7
|
-
# Because the AR::Associations namespace is insane
|
8
|
-
JoinPart = ::ActiveRecord::Associations::JoinDependency::JoinPart
|
9
|
-
|
10
|
-
def initialize(object)
|
11
|
-
super
|
12
|
-
@base = object.join_base
|
13
|
-
@engine = @base.arel_engine
|
14
|
-
@arel_visitor = @engine.connection.visitor
|
15
|
-
@default_table = Arel::Table.new(@base.table_name, :as => @base.aliased_table_name, :engine => @engine)
|
16
|
-
end
|
17
|
-
|
18
|
-
def find(object, parent = @base)
|
19
|
-
if JoinPart === parent
|
20
|
-
object = object.to_sym if String === object
|
21
|
-
case object
|
22
|
-
when Symbol, Nodes::Stub
|
23
|
-
@object.join_associations.detect { |j|
|
24
|
-
j.reflection.name == object.to_sym && j.parent == parent
|
25
|
-
}
|
26
|
-
when Nodes::Join
|
27
|
-
@object.join_associations.detect { |j|
|
28
|
-
j.reflection.name == object.name && j.parent == parent &&
|
29
|
-
(object.polymorphic? ? j.reflection.klass == object._klass : true)
|
30
|
-
}
|
31
|
-
else
|
32
|
-
@object.join_associations.detect { |j|
|
33
|
-
j.reflection == object && j.parent == parent
|
34
|
-
}
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def traverse(keypath, parent = @base, include_endpoint = false)
|
40
|
-
parent = @base if keypath.absolute?
|
41
|
-
keypath.path.each do |key|
|
42
|
-
parent = find(key, parent) || key
|
43
|
-
end
|
44
|
-
parent = find(keypath.endpoint, parent) if include_endpoint
|
45
|
-
|
46
|
-
parent
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def get_table(object)
|
52
|
-
if [Symbol, String, Nodes::Stub].include?(object.class)
|
53
|
-
Arel::Table.new(object.to_sym, :engine => @engine)
|
54
|
-
elsif Nodes::Join === object
|
55
|
-
object._klass ? object._klass.arel_table : Arel::Table.new(object._name, :engine => @engine)
|
56
|
-
elsif object.respond_to?(:aliased_table_name)
|
57
|
-
Arel::Table.new(object.table_name, :as => object.aliased_table_name, :engine => @engine)
|
58
|
-
else
|
59
|
-
raise ArgumentError, "Unable to get table for #{object}"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def classify(object)
|
64
|
-
if Class === object
|
65
|
-
object
|
66
|
-
elsif object.respond_to? :active_record
|
67
|
-
object.active_record
|
68
|
-
else
|
69
|
-
raise ArgumentError, "#{object} can't be converted to a class"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
1
|
+
require 'squeel/adapters/active_record/3.1/context'
|
@@ -1,21 +1 @@
|
|
1
|
-
|
2
|
-
module Adapters
|
3
|
-
module ActiveRecord
|
4
|
-
module PreloaderExtensions
|
5
|
-
|
6
|
-
def self.included(base)
|
7
|
-
base.class_eval do
|
8
|
-
alias_method_chain :run, :squeel
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def run_with_squeel
|
13
|
-
unless records.empty?
|
14
|
-
Visitors::SymbolVisitor.new.accept(associations).each { |association| preload(association) }
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
1
|
+
require 'squeel/adapters/active_record/3.1/preloader_extensions'
|
@@ -1,84 +1,10 @@
|
|
1
|
-
require 'active_record'
|
1
|
+
require 'squeel/adapters/active_record/3.1/relation_extensions'
|
2
2
|
|
3
3
|
module Squeel
|
4
4
|
module Adapters
|
5
5
|
module ActiveRecord
|
6
6
|
module RelationExtensions
|
7
|
-
|
8
|
-
JoinAssociation = ::ActiveRecord::Associations::JoinDependency::JoinAssociation
|
9
|
-
JoinDependency = ::ActiveRecord::Associations::JoinDependency
|
10
|
-
|
11
|
-
attr_writer :join_dependency
|
12
|
-
private :join_dependency=
|
13
|
-
|
14
|
-
# Returns a JoinDependency for the current relation.
|
15
|
-
#
|
16
|
-
# We don't need to clear out @join_dependency by overriding #reset, because
|
17
|
-
# the default #reset already does this, despite never setting it anywhere that
|
18
|
-
# I can find. Serendipity, I say!
|
19
|
-
def join_dependency
|
20
|
-
@join_dependency ||= (build_join_dependency(table.from(table), @joins_values) && @join_dependency)
|
21
|
-
end
|
22
|
-
|
23
|
-
def predicate_visitor
|
24
|
-
Visitors::PredicateVisitor.new(
|
25
|
-
Context.new(join_dependency)
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
def attribute_visitor
|
30
|
-
Visitors::AttributeVisitor.new(
|
31
|
-
Context.new(join_dependency)
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
# We need to be able to support merging two relations that have a different
|
36
|
-
# base class. Stock ActiveRecord doesn't have to do anything too special, because
|
37
|
-
# it's already created predicates out of the where_values by now, and they're
|
38
|
-
# already bound to the proper table.
|
39
|
-
#
|
40
|
-
# Squeel, on the other hand, needs to do its best to ensure the predicates are still
|
41
|
-
# winding up against the proper table. The most "correct" way I can think of to do
|
42
|
-
# this is to try to emulate the default AR behavior -- that is, de-squeelifying
|
43
|
-
# the *_values, erm... values by visiting them and converting them to ARel nodes
|
44
|
-
# before merging. Merging relations is a nifty little trick, but it's another
|
45
|
-
# little corner of ActiveRecord where the magic quickly fades. :(
|
46
|
-
def merge(r)
|
47
|
-
if relation_with_different_base?(r)
|
48
|
-
r = r.clone.visit!
|
49
|
-
end
|
50
|
-
|
51
|
-
super(r)
|
52
|
-
end
|
53
|
-
|
54
|
-
def relation_with_different_base?(r)
|
55
|
-
::ActiveRecord::Relation === r &&
|
56
|
-
base_class.name != r.klass.base_class.name
|
57
|
-
end
|
58
|
-
|
59
|
-
def prepare_relation_for_association_merge!(r, association_name)
|
60
|
-
r.where_values.map! {|w| Squeel::Visitors::PredicateVisitor.can_visit?(w) ? {association_name => w} : w}
|
61
|
-
r.having_values.map! {|h| Squeel::Visitors::PredicateVisitor.can_visit?(h) ? {association_name => h} : h}
|
62
|
-
r.group_values.map! {|g| Squeel::Visitors::AttributeVisitor.can_visit?(g) ? {association_name => g} : g}
|
63
|
-
r.order_values.map! {|o| Squeel::Visitors::AttributeVisitor.can_visit?(o) ? {association_name => o} : o}
|
64
|
-
r.select_values.map! {|s| Squeel::Visitors::AttributeVisitor.can_visit?(s) ? {association_name => s} : s}
|
65
|
-
r.joins_values.map! {|j| [Symbol, Hash, Nodes::Stub, Nodes::Join, Nodes::KeyPath].include?(j.class) ? {association_name => j} : j}
|
66
|
-
r.includes_values.map! {|i| [Symbol, Hash, Nodes::Stub, Nodes::Join, Nodes::KeyPath].include?(i.class) ? {association_name => i} : i}
|
67
|
-
end
|
68
|
-
|
69
|
-
def visit!
|
70
|
-
predicate_viz = predicate_visitor
|
71
|
-
attribute_viz = attribute_visitor
|
72
|
-
|
73
|
-
@where_values = predicate_viz.accept((@where_values - ['']).uniq)
|
74
|
-
@having_values = predicate_viz.accept(@having_values.uniq.reject{|h| h.blank?})
|
75
|
-
@group_values = attribute_viz.accept(@group_values.uniq.reject{|g| g.blank?})
|
76
|
-
@order_values = attribute_viz.accept(@order_values.uniq.reject{|o| o.blank?})
|
77
|
-
@select_values = attribute_viz.accept(@select_values.uniq)
|
78
|
-
|
79
|
-
self
|
80
|
-
end
|
81
|
-
|
7
|
+
|
82
8
|
def build_arel
|
83
9
|
arel = table.from table
|
84
10
|
|
@@ -102,258 +28,14 @@ module Squeel
|
|
102
28
|
arel.order(*order) unless order.empty?
|
103
29
|
|
104
30
|
build_select(arel, attribute_viz.accept(@select_values.uniq))
|
105
|
-
|
31
|
+
|
32
|
+
arel.distinct(@uniq_value)
|
106
33
|
arel.from(@from_value) if @from_value
|
107
34
|
arel.lock(@lock_value) if @lock_value
|
108
35
|
|
109
36
|
arel
|
110
37
|
end
|
111
|
-
|
112
|
-
# reverse_sql_order will reverse the order of strings or Orderings,
|
113
|
-
# but not attributes
|
114
|
-
def attrs_to_orderings(order)
|
115
|
-
order.map do |o|
|
116
|
-
Arel::Attribute === o ? o.asc : o
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def build_join_dependency(manager, joins)
|
121
|
-
buckets = joins.group_by do |join|
|
122
|
-
case join
|
123
|
-
when String
|
124
|
-
'string_join'
|
125
|
-
when Hash, Symbol, Array, Nodes::Stub, Nodes::Join, Nodes::KeyPath
|
126
|
-
'association_join'
|
127
|
-
when JoinAssociation
|
128
|
-
'stashed_join'
|
129
|
-
when Arel::Nodes::Join
|
130
|
-
'join_node'
|
131
|
-
else
|
132
|
-
raise 'unknown class: %s' % join.class.name
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
association_joins = buckets['association_join'] || []
|
137
|
-
stashed_association_joins = buckets['stashed_join'] || []
|
138
|
-
join_nodes = buckets['join_node'] || []
|
139
|
-
string_joins = (buckets['string_join'] || []).map { |x|
|
140
|
-
x.strip
|
141
|
-
}.uniq
|
142
|
-
|
143
|
-
join_list = custom_join_ast(manager, string_joins)
|
144
|
-
|
145
|
-
# All of this duplication just to add
|
146
|
-
self.join_dependency = JoinDependency.new(
|
147
|
-
@klass,
|
148
|
-
association_joins,
|
149
|
-
join_list
|
150
|
-
)
|
151
|
-
|
152
|
-
join_nodes.each do |join|
|
153
|
-
join_dependency.alias_tracker.aliased_name_for(join.left.name.downcase)
|
154
|
-
end
|
155
|
-
|
156
|
-
join_dependency.graft(*stashed_association_joins)
|
157
|
-
|
158
|
-
@implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
|
159
|
-
|
160
|
-
join_dependency.join_associations.each do |association|
|
161
|
-
association.join_to(manager)
|
162
|
-
end
|
163
|
-
|
164
|
-
manager.join_sources.concat join_nodes.uniq
|
165
|
-
manager.join_sources.concat join_list
|
166
|
-
|
167
|
-
manager
|
168
|
-
end
|
169
|
-
|
170
|
-
def includes(*args)
|
171
|
-
if block_given? && args.empty?
|
172
|
-
super(DSL.eval &Proc.new)
|
173
|
-
else
|
174
|
-
super
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def preload(*args)
|
179
|
-
if block_given? && args.empty?
|
180
|
-
super(DSL.eval &Proc.new)
|
181
|
-
else
|
182
|
-
super
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def eager_load(*args)
|
187
|
-
if block_given? && args.empty?
|
188
|
-
super(DSL.eval &Proc.new)
|
189
|
-
else
|
190
|
-
super
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
def select(value = Proc.new)
|
195
|
-
if block_given? && Proc === value
|
196
|
-
if value.arity > 0
|
197
|
-
to_a.select {|*block_args| value.call(*block_args)}
|
198
|
-
else
|
199
|
-
relation = clone
|
200
|
-
relation.select_values += Array.wrap(DSL.eval &value)
|
201
|
-
relation
|
202
|
-
end
|
203
|
-
else
|
204
|
-
super
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
def group(*args)
|
209
|
-
if block_given? && args.empty?
|
210
|
-
super(DSL.eval &Proc.new)
|
211
|
-
else
|
212
|
-
super
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def order(*args)
|
217
|
-
if block_given? && args.empty?
|
218
|
-
super(DSL.eval &Proc.new)
|
219
|
-
else
|
220
|
-
super
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def reorder(*args)
|
225
|
-
if block_given? && args.empty?
|
226
|
-
super(DSL.eval &Proc.new)
|
227
|
-
else
|
228
|
-
super
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
def joins(*args)
|
233
|
-
if block_given? && args.empty?
|
234
|
-
super(DSL.eval &Proc.new)
|
235
|
-
else
|
236
|
-
super
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
def where(opts = Proc.new, *rest)
|
241
|
-
if block_given? && Proc === opts
|
242
|
-
super(DSL.eval &opts)
|
243
|
-
else
|
244
|
-
super
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
def having(*args)
|
249
|
-
if block_given? && args.empty?
|
250
|
-
super(DSL.eval &Proc.new)
|
251
|
-
else
|
252
|
-
super
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
def build_where(opts, other = [])
|
257
|
-
case opts
|
258
|
-
when String, Array
|
259
|
-
super
|
260
|
-
else # Let's prevent PredicateBuilder from doing its thing
|
261
|
-
[opts, *other].map do |arg|
|
262
|
-
case arg
|
263
|
-
when Array # Just in case there's an array in there somewhere
|
264
|
-
@klass.send(:sanitize_sql, arg)
|
265
|
-
when Hash
|
266
|
-
@klass.send(:expand_hash_conditions_for_aggregates, arg)
|
267
|
-
else
|
268
|
-
arg
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
def collapse_wheres(arel, wheres)
|
275
|
-
wheres = Array(wheres)
|
276
|
-
binaries = wheres.grep(Arel::Nodes::Binary)
|
277
|
-
|
278
|
-
groups = binaries.group_by {|b| [b.class, b.left]}
|
279
|
-
|
280
|
-
groups.each do |_, bins|
|
281
|
-
arel.where(Arel::Nodes::And.new(bins))
|
282
|
-
end
|
283
|
-
|
284
|
-
(wheres - binaries).each do |where|
|
285
|
-
where = Arel.sql(where) if String === where
|
286
|
-
arel.where(Arel::Nodes::Grouping.new(where))
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
def find_equality_predicates(nodes)
|
291
|
-
nodes.map { |node|
|
292
|
-
case node
|
293
|
-
when Arel::Nodes::Equality
|
294
|
-
node if node.left.relation.name == table_name
|
295
|
-
when Arel::Nodes::Grouping
|
296
|
-
find_equality_predicates([node.expr])
|
297
|
-
when Arel::Nodes::And
|
298
|
-
find_equality_predicates(node.children)
|
299
|
-
else
|
300
|
-
nil
|
301
|
-
end
|
302
|
-
}.compact.flatten
|
303
|
-
end
|
304
|
-
|
305
|
-
# Simulate the logic that occurs in #to_a
|
306
|
-
#
|
307
|
-
# This will let us get a dump of the SQL that will be run against the
|
308
|
-
# DB for debug purposes without actually running the query.
|
309
|
-
def debug_sql
|
310
|
-
if eager_loading?
|
311
|
-
including = (@eager_load_values + @includes_values).uniq
|
312
|
-
join_dependency = JoinDependency.new(@klass, including, [])
|
313
|
-
construct_relation_for_association_find(join_dependency).to_sql
|
314
|
-
else
|
315
|
-
arel.to_sql
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
### ZOMG ALIAS_METHOD_CHAIN IS BELOW. HIDE YOUR EYES!
|
320
|
-
# ...
|
321
|
-
# ...
|
322
|
-
# ...
|
323
|
-
# Since you're still looking, let me explain this horrible
|
324
|
-
# transgression you see before you.
|
325
|
-
# You see, Relation#where_values_hash is defined on the
|
326
|
-
# ActiveRecord::Relation class. Since it's defined there, but
|
327
|
-
# I would very much like to modify its behavior, I have three
|
328
|
-
# choices.
|
329
|
-
#
|
330
|
-
# 1. Inherit from ActiveRecord::Relation in a Squeel::Relation
|
331
|
-
# class, and make an attempt to usurp all of the various calls
|
332
|
-
# to methods on ActiveRecord::Relation by doing some really
|
333
|
-
# evil stuff with constant reassignment, all for the sake of
|
334
|
-
# being able to use super().
|
335
|
-
#
|
336
|
-
# 2. Submit a patch to Rails core, breaking this method off into
|
337
|
-
# another module, all for my own selfish desire to use super()
|
338
|
-
# while mucking about in Rails internals.
|
339
|
-
#
|
340
|
-
# 3. Use alias_method_chain, and say 10 hail Hanssons as penance.
|
341
|
-
#
|
342
|
-
# I opted to go with #3. Except for the hail Hansson thing.
|
343
|
-
# Unless you're DHH, in which case, I totally said them.
|
344
|
-
|
345
|
-
def self.included(base)
|
346
|
-
base.class_eval do
|
347
|
-
alias_method_chain :where_values_hash, :squeel
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
def where_values_hash_with_squeel
|
352
|
-
equalities = find_equality_predicates(predicate_visitor.accept(@where_values))
|
353
|
-
|
354
|
-
Hash[equalities.map { |where| [where.left.name, where.right] }]
|
355
|
-
end
|
356
|
-
|
38
|
+
|
357
39
|
end
|
358
40
|
end
|
359
41
|
end
|
data/lib/squeel/configuration.rb
CHANGED
@@ -34,7 +34,7 @@ module Squeel
|
|
34
34
|
# @param [Symbol] sym2 :hash or :symbol
|
35
35
|
def load_core_extensions(*exts)
|
36
36
|
exts.each do |ext|
|
37
|
-
require "core_ext/#{ext}"
|
37
|
+
require "squeel/core_ext/#{ext}"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -51,4 +51,4 @@ module Squeel
|
|
51
51
|
end
|
52
52
|
|
53
53
|
end
|
54
|
-
end
|
54
|
+
end
|
File without changes
|
File without changes
|
data/lib/squeel/version.rb
CHANGED
@@ -97,6 +97,10 @@ module Squeel
|
|
97
97
|
relation.join_dependency.join_associations.should have(6).items
|
98
98
|
arel.to_sql.should match /INNER JOIN "people" "parents_people_3" ON "parents_people_3"."id" = "children_people_3"."parent_id"/
|
99
99
|
end
|
100
|
+
|
101
|
+
it 'respects :uniq option on associations' do
|
102
|
+
Article.first.uniq_commenters.length.should eq Article.first.uniq_commenters.count
|
103
|
+
end
|
100
104
|
|
101
105
|
it 'visits wheres with a PredicateVisitor, converting them to ARel nodes' do
|
102
106
|
relation = Person.where(:name.matches => '%bob%')
|
data/spec/support/schema.rb
CHANGED
@@ -48,6 +48,7 @@ class Article < ActiveRecord::Base
|
|
48
48
|
has_and_belongs_to_many :tags
|
49
49
|
has_many :notes, :as => :notable
|
50
50
|
has_many :commenters, :through => :comments, :source => :person
|
51
|
+
has_many :uniq_commenters, :through => :comments, :source => :person, :uniq => true
|
51
52
|
end
|
52
53
|
|
53
54
|
class Comment < ActiveRecord::Base
|
@@ -137,6 +138,7 @@ module Schema
|
|
137
138
|
end
|
138
139
|
|
139
140
|
Comment.make(:body => 'First post!', :article => Article.make(:title => 'Hello, world!'))
|
141
|
+
Comment.make(:body => 'Last post!', :article => Article.first, :person => Article.first.commenters.first)
|
140
142
|
|
141
143
|
end
|
142
144
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: squeel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-01-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
|
-
requirement: &
|
16
|
+
requirement: &70129585123660 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70129585123660
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activesupport
|
27
|
-
requirement: &
|
27
|
+
requirement: &70129585122480 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '3.0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70129585122480
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: polyamorous
|
38
|
-
requirement: &
|
38
|
+
requirement: &70129585121660 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 0.5.0
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70129585121660
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &70129585121080 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 2.6.0
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70129585121080
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: machinist
|
60
|
-
requirement: &
|
60
|
+
requirement: &70129585120560 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.0.6
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70129585120560
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: faker
|
71
|
-
requirement: &
|
71
|
+
requirement: &70129585135820 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: 0.9.5
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70129585135820
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: sqlite3
|
82
|
-
requirement: &
|
82
|
+
requirement: &70129585134740 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ~>
|
@@ -87,7 +87,7 @@ dependencies:
|
|
87
87
|
version: 1.3.3
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70129585134740
|
91
91
|
description: ! "\n Squeel unlocks the power of ARel in your Rails 3 application
|
92
92
|
with\n a handy block-based syntax. You can write subqueries, access named\n
|
93
93
|
\ functions provided by your RDBMS, and more, all without writing\n SQL
|
@@ -105,14 +105,15 @@ files:
|
|
105
105
|
- LICENSE
|
106
106
|
- README.md
|
107
107
|
- Rakefile
|
108
|
-
- lib/core_ext/hash.rb
|
109
|
-
- lib/core_ext/symbol.rb
|
110
108
|
- lib/squeel.rb
|
111
109
|
- lib/squeel/adapters/active_record.rb
|
112
110
|
- lib/squeel/adapters/active_record/3.0/association_preload_extensions.rb
|
113
111
|
- lib/squeel/adapters/active_record/3.0/compat.rb
|
114
112
|
- lib/squeel/adapters/active_record/3.0/context.rb
|
115
113
|
- lib/squeel/adapters/active_record/3.0/relation_extensions.rb
|
114
|
+
- lib/squeel/adapters/active_record/3.1/context.rb
|
115
|
+
- lib/squeel/adapters/active_record/3.1/preloader_extensions.rb
|
116
|
+
- lib/squeel/adapters/active_record/3.1/relation_extensions.rb
|
116
117
|
- lib/squeel/adapters/active_record/base_extensions.rb
|
117
118
|
- lib/squeel/adapters/active_record/context.rb
|
118
119
|
- lib/squeel/adapters/active_record/join_dependency_extensions.rb
|
@@ -121,6 +122,8 @@ files:
|
|
121
122
|
- lib/squeel/configuration.rb
|
122
123
|
- lib/squeel/constants.rb
|
123
124
|
- lib/squeel/context.rb
|
125
|
+
- lib/squeel/core_ext/hash.rb
|
126
|
+
- lib/squeel/core_ext/symbol.rb
|
124
127
|
- lib/squeel/dsl.rb
|
125
128
|
- lib/squeel/nodes.rb
|
126
129
|
- lib/squeel/nodes/aliasing.rb
|