squeel 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.yardopts +3 -0
  2. data/Gemfile +8 -3
  3. data/README.md +368 -0
  4. data/lib/core_ext/hash.rb +8 -8
  5. data/lib/core_ext/symbol.rb +7 -6
  6. data/lib/squeel.rb +2 -0
  7. data/lib/squeel/adapters/active_record.rb +25 -20
  8. data/lib/squeel/adapters/active_record/3.0/compat.rb +1 -2
  9. data/lib/squeel/adapters/active_record/3.0/context.rb +6 -7
  10. data/lib/squeel/adapters/active_record/3.0/join_dependency.rb +5 -5
  11. data/lib/squeel/adapters/active_record/context.rb +6 -7
  12. data/lib/squeel/adapters/active_record/join_dependency.rb +5 -5
  13. data/lib/squeel/configuration.rb +29 -0
  14. data/lib/squeel/constants.rb +1 -0
  15. data/lib/squeel/context.rb +36 -7
  16. data/lib/squeel/dsl.rb +57 -2
  17. data/lib/squeel/nodes.rb +6 -0
  18. data/lib/squeel/nodes/and.rb +1 -0
  19. data/lib/squeel/nodes/binary.rb +11 -2
  20. data/lib/squeel/nodes/function.rb +30 -48
  21. data/lib/squeel/nodes/join.rb +56 -12
  22. data/lib/squeel/nodes/key_path.rb +68 -2
  23. data/lib/squeel/nodes/nary.rb +12 -2
  24. data/lib/squeel/nodes/not.rb +1 -0
  25. data/lib/squeel/nodes/operation.rb +9 -0
  26. data/lib/squeel/nodes/operators.rb +16 -0
  27. data/lib/squeel/nodes/or.rb +1 -0
  28. data/lib/squeel/nodes/order.rb +19 -1
  29. data/lib/squeel/nodes/predicate.rb +25 -3
  30. data/lib/squeel/nodes/predicate_operators.rb +12 -0
  31. data/lib/squeel/nodes/stub.rb +55 -48
  32. data/lib/squeel/nodes/unary.rb +7 -1
  33. data/lib/squeel/predicate_methods.rb +2 -10
  34. data/lib/squeel/version.rb +1 -1
  35. data/lib/squeel/visitors/attribute_visitor.rb +80 -4
  36. data/lib/squeel/visitors/base.rb +70 -4
  37. data/lib/squeel/visitors/predicate_visitor.rb +28 -9
  38. data/lib/squeel/visitors/symbol_visitor.rb +1 -1
  39. data/spec/core_ext/symbol_spec.rb +2 -2
  40. data/spec/spec_helper.rb +6 -1
  41. data/spec/squeel/adapters/active_record/context_spec.rb +0 -7
  42. data/spec/squeel/adapters/active_record/relation_spec.rb +27 -0
  43. data/spec/squeel/dsl_spec.rb +20 -1
  44. data/spec/squeel/nodes/join_spec.rb +11 -4
  45. data/spec/squeel/nodes/key_path_spec.rb +1 -1
  46. data/spec/squeel/nodes/predicate_spec.rb +0 -42
  47. data/spec/squeel/nodes/stub_spec.rb +9 -8
  48. data/spec/squeel/visitors/predicate_visitor_spec.rb +34 -9
  49. data/squeel.gemspec +6 -9
  50. metadata +8 -10
  51. data/README.rdoc +0 -117
  52. data/lib/squeel/predicate_methods/function.rb +0 -9
  53. data/lib/squeel/predicate_methods/predicate.rb +0 -11
  54. data/lib/squeel/predicate_methods/stub.rb +0 -9
  55. data/lib/squeel/predicate_methods/symbol.rb +0 -9
@@ -0,0 +1,3 @@
1
+ --main README.md
2
+ --private
3
+ --exclude compat
data/Gemfile CHANGED
@@ -1,8 +1,13 @@
1
1
  source "http://rubygems.org"
2
2
  gemspec
3
3
 
4
- gem 'arel', :git => 'git://github.com/rails/arel.git'
5
- git 'git://github.com/rails/rails.git' do
4
+ if ENV['RAILS_VERSION'] == 'release'
6
5
  gem 'activesupport'
7
6
  gem 'activerecord'
8
- end
7
+ else
8
+ gem 'arel', :git => 'git://github.com/rails/arel.git'
9
+ git 'git://github.com/rails/rails.git' do
10
+ gem 'activesupport'
11
+ gem 'activerecord'
12
+ end
13
+ end
@@ -0,0 +1,368 @@
1
+ # Squeel
2
+
3
+ Squeel is a rewrite of [MetaWhere](http://metautonomo.us/projects/metawhere).
4
+
5
+ ## Getting started
6
+
7
+ In your Gemfile:
8
+
9
+ gem "squeel" # Last officially released gem
10
+ # gem "squeel", :git => "git://github.com/ernie/squeel.git" # Track git repo
11
+
12
+ In an intitializer:
13
+
14
+ Squeel.configure do |config|
15
+ # To load hash extensions (to allow for AND (&), OR (|), and NOT (-) against
16
+ # hashes of conditions)
17
+ config.load_core_extensions :hash
18
+
19
+ # To load symbol extensions (for a subset of the old MetaWhere functionality,
20
+ # via ARel predicate methods on Symbols: :name.matches, etc)
21
+ # config.load_core_extensions :symbol
22
+
23
+ # To load both hash and symbol extensions
24
+ # config.load_core_extensions :hash, :symbol
25
+ end
26
+
27
+ ## The Squeel Query DSL
28
+
29
+ Squeel enhances the normal ActiveRecord query methods by enabling them to accept
30
+ blocks. Inside a block, the Squeel query DSL can be used. Note the use of curly braces
31
+ in these examples instead of parentheses. `{}` denotes a Squeel DSL query.
32
+
33
+ Stubs and keypaths are the two primary building blocks used in a Squeel DSL query, so
34
+ before we go on, let's take a look at them. Most of the other examples that follow will
35
+ be based on this "symbol-less" syntax, so it might look a bit foreign otherwise.
36
+
37
+ ### Stubs
38
+
39
+ Stubs are, for most intents and purposes, just like Symbols in a normal call to
40
+ `Relation#where` (note the need for doubling up on the curly braces here, the first ones
41
+ start the block, the second are the hash braces):
42
+
43
+ Person.where{{name => 'Ernie'}}
44
+ => SELECT "people".* FROM "people" WHERE "people"."name" = 'Ernie'
45
+
46
+ You normally wouldn't bother using the DSL in this case, as a simple hash would
47
+ suffice. However, stubs serve as a building block for keypaths, and keypaths are
48
+ very handy.
49
+
50
+ ### KeyPaths
51
+
52
+ A Squeel keypath is essentially a more concise and readable alternative to a
53
+ deeply nested hash. For instance, in standard ActiveRecord, you might join several
54
+ associations like this to perform a query:
55
+
56
+ Person.joins(:articles => {:comments => :person})
57
+ => SELECT "people".* FROM "people"
58
+ INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
59
+ INNER JOIN "comments" ON "comments"."article_id" = "articles"."id"
60
+ INNER JOIN "people" "people_comments" ON "people_comments"."id" = "comments"."person_id"
61
+
62
+ With a keypath, this would look like:
63
+
64
+ Person.joins{articles.comments.person}
65
+
66
+ A keypath can exist in the context of a hash, and is normally interpreted relative to
67
+ the current level of nesting. It can be forced into an "absolute" path by anchoring it with
68
+ a ~, like:
69
+
70
+ ~articles.comments.person
71
+
72
+ This isn't quite so useful in the typical hash context, but can be very useful when it comes
73
+ to interpreting functions and the like. We'll cover those later.
74
+
75
+ ### Predicates
76
+
77
+ All of the ARel "predication" methods can be accessed inside the Squeel DSL, via
78
+ their method name, an alias, or an an operator, to create ARel predicates, which are
79
+ used in `WHERE` or `HAVING` clauses.
80
+
81
+ <table>
82
+ <tr>
83
+ <th>SQL</th>
84
+ <th>Predication</th>
85
+ <th>Operator</th>
86
+ <th>Alias</th>
87
+ </tr>
88
+ <tr>
89
+ <td>=</td>
90
+ <td>eq</td>
91
+ <td>==</td>
92
+ <td></td>
93
+ </tr>
94
+ <tr>
95
+ <td>!=</td>
96
+ <td>not_eq</td>
97
+ <td>!=</td>
98
+ <td></td>
99
+ </tr>
100
+ <tr>
101
+ <td>LIKE</td>
102
+ <td>matches</td>
103
+ <td>=~</td>
104
+ <td>like</td>
105
+ </tr>
106
+ <tr>
107
+ <td>NOT LIKE</td>
108
+ <td>does_not_match</td>
109
+ <td>!~</td>
110
+ <td>not_like</td>
111
+ </tr>
112
+ <tr>
113
+ <td>&lt;</td>
114
+ <td>lt</td>
115
+ <td>&lt;</td>
116
+ <td></td>
117
+ </tr>
118
+ <tr>
119
+ <td>&lt;=</td>
120
+ <td>lteq</td>
121
+ <td>&lt;=</td>
122
+ <td>lte</td>
123
+ </tr>
124
+ <tr>
125
+ <td>></td>
126
+ <td>gt</td>
127
+ <td>></td>
128
+ <td></td>
129
+ </tr>
130
+ <tr>
131
+ <td>>=</td>
132
+ <td>gteq</td>
133
+ <td>>=</td>
134
+ <td>gte</td>
135
+ </tr>
136
+ <tr>
137
+ <td>IN</td>
138
+ <td>in</td>
139
+ <td>>></td>
140
+ <td></td>
141
+ </tr>
142
+ <tr>
143
+ <td>NOT IN</td>
144
+ <td>not_in</td>
145
+ <td>&lt;&lt;</td>
146
+ <td></td>
147
+ </tr>
148
+ </table>
149
+
150
+ Let's say we want to generate this simple query:
151
+
152
+ SELECT "people".* FROM people WHERE "people"."name" = 'Joe Blow'
153
+
154
+ All of the following will generate the above SQL:
155
+
156
+ Person.where(:name => 'Joe Blow')
157
+ Person.where{{name => 'Joe Blow'}}
158
+ Person.where{{name.eq => 'Joe Blow'}}
159
+ Person.where{name.eq 'Joe Blow'}
160
+ Person.where{name == 'Joe Blow'}
161
+
162
+ Not a very exciting example since equality is handled just fine via the
163
+ first example in standard ActiveRecord. But consider the following query:
164
+
165
+ SELECT "people".* FROM people
166
+ WHERE ("people"."name" LIKE 'Ernie%' AND "people"."salary" < 50000)
167
+ OR ("people"."name" LIKE 'Joe%' AND "people"."salary" > 100000)
168
+
169
+ To do this with standard ActiveRecord, we'd do something like:
170
+
171
+ Person.where(
172
+ '(name LIKE ? AND salary < ?) OR (name LIKE ? AND salary > ?)',
173
+ 'Ernie%', 50000, 'Joe%', 100000
174
+ )
175
+
176
+ With Squeel:
177
+
178
+ Person.where{(name =~ 'Ernie%') & (salary < 50000) | (name =~ 'Joe%') & (salary > 100000)}
179
+
180
+ Here, we're using `&` and `|` to generate `AND` and `OR`, respectively.
181
+
182
+ There are two obvious but important differences between these two code samples, and
183
+ both of them have to do with *context*.
184
+
185
+ 1. To read code with SQL interpolation, the structure of the SQL query must
186
+ first be considered, then we must cross-reference the values to be substituted
187
+ with their placeholders. This carries with it a small but perceptible (and
188
+ annoying!) context shift during which we stop thinking about the comparison being
189
+ performed, and instead play "count the arguments", or, in the case of
190
+ named/hash interpolations, "find the word". The Squeel syntax places
191
+ both sides of each comparison in proximity to one another, allowing us to
192
+ focus on what our code is doing.
193
+
194
+ 2. In the first example, we're starting off with Ruby, switching context to SQL,
195
+ and then back to Ruby, and while we spend time in SQL-land, we're stuck with
196
+ SQL syntax, whether or not it's the best way to express what we're trying to do.
197
+ With Squeel, we're writing Ruby from start to finish. And with Ruby syntax comes
198
+ flexibility to express the query in the way we see fit.
199
+
200
+ ### Predicate aliases
201
+
202
+ That last bit is important. We can mix and match predicate methods with operators
203
+ and take advantage of Ruby's operator precedence or parenthetical grouping to make
204
+ our intentions more clear, on the first read-through. And if we don't like the
205
+ way that the existing predications read, we can create our own aliases in a Squeel
206
+ configure block:
207
+
208
+ Squeel.configure do |config|
209
+ config.alias_predicate :is_less_than, :lt
210
+ end
211
+
212
+ Person.where{salary.is_less_than 50000}.to_sql
213
+ # => SELECT "people".* FROM "people" WHERE "people"."salary" < 50000
214
+
215
+ And while we're on the topic of helping you make your code more expressive...
216
+
217
+ ### Compound conditions
218
+
219
+ Let's say you want to check if a Person has a name like one of several possibilities.
220
+
221
+ names = ['Ernie%', 'Joe%', 'Mary%']
222
+ Person.where('name LIKE ? OR name LIKE ? OR name LIKE ?', *names)
223
+
224
+ But you're smart, and you know that you might want to check more or less than
225
+ 3 names, so you make your query flexible:
226
+
227
+ Person.where((['name LIKE ?'] * names.size).join(' OR '), *names)
228
+
229
+ Yeah... that's readable, all right. How about:
230
+
231
+ Person.where{name.like_any names}
232
+ # => SELECT "people".* FROM "people"
233
+ WHERE (("people"."name" LIKE 'Ernie%' OR "people"."name" LIKE 'Joe%' OR "people"."name" LIKE 'Mary%'))
234
+
235
+ I'm not sure about you, but I much prefer the latter. In short, you can add `_any` or
236
+ `_all` to any predicate method, and it would do what you expect, when given an array of
237
+ possibilities to compare against.
238
+
239
+ ### Subqueries
240
+
241
+ You can supply an `ActiveRecord::Relation` as a value for a predicate in order to use
242
+ a subquery. So, for example:
243
+
244
+ awesome_people = Person.where{awesome == true}
245
+ Article.where{author_id.in(awesome_people.select{id})}
246
+ # => SELECT "articles".* FROM "articles"
247
+ WHERE "articles"."author_id" IN (SELECT "people"."id" FROM "people" WHERE "people"."awesome" = 't')
248
+
249
+ ### Joins
250
+
251
+ Squeel adds a couple of enhancements to joins. First, keypaths can be used as shorthand for
252
+ nested association joins. Second, you can specify join types (inner and outer), and a class
253
+ in the case of a polymorphic belongs_to relationship.
254
+
255
+ Person.joins{articles.outer}
256
+ => SELECT "people".* FROM "people"
257
+ LEFT OUTER JOIN "articles" ON "articles"."person_id" = "people"."id"
258
+ Note.joins{notable(Person).outer}
259
+ => SELECT "notes".* FROM "notes"
260
+ LEFT OUTER JOIN "people"
261
+ ON "people"."id" = "notes"."notable_id"
262
+ AND "notes"."notable_type" = 'Person'
263
+
264
+ These can also be used inside keypaths:
265
+
266
+ Note.joins{notable(Person).articles}
267
+ => SELECT "notes".* FROM "notes"
268
+ INNER JOIN "people" ON "people"."id" = "notes"."notable_id"
269
+ AND "notes"."notable_type" = 'Person'
270
+ INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
271
+
272
+ You can refer to these associations when constructing other parts of your query, and
273
+ they'll be automatically mapped to the proper table or table alias This is most noticeable
274
+ when using self-referential associations:
275
+
276
+ Person.joins{children.parent.children}.
277
+ where{
278
+ (children.name.like 'Ernie%') |
279
+ (children.parent.name.like 'Ernie%') |
280
+ (children.parent.children.name.like 'Ernie%')
281
+ }
282
+ => SELECT "people".* FROM "people"
283
+ INNER JOIN "people" "children_people" ON "children_people"."parent_id" = "people"."id"
284
+ INNER JOIN "people" "parents_people" ON "parents_people"."id" = "children_people"."parent_id"
285
+ INNER JOIN "people" "children_people_2" ON "children_people_2"."parent_id" = "parents_people"."id"
286
+ WHERE ((("children_people"."name" LIKE 'Ernie%'
287
+ OR "parents_people"."name" LIKE 'Ernie%')
288
+ OR "children_people_2"."name" LIKE 'Ernie%'))
289
+
290
+ Keypaths were used here for clarity, but nested hashes would work just as well.
291
+
292
+ ### Functions
293
+
294
+ You can call SQL functions just like you would call a method in Ruby...
295
+
296
+ Person.select{coalesce(name, '<no name given>')}
297
+ => SELECT coalesce("people"."name", '<no name given>') FROM "people"
298
+
299
+ ...and you can easily give it an alias:
300
+
301
+ person = Person.select{
302
+ coalesce(name, '<no name given>').as(name_with_default)
303
+ }.first
304
+ person.name_with_default # name or <no name given>, depending on data
305
+
306
+ When you use a stub, symbol, or keypath inside a function call, it'll be interpreted relative to
307
+ its place inside any nested associations:
308
+
309
+ Person.joins{articles}.group{articles.title}.having{{articles => {max(id) => id}}}
310
+ => SELECT "people".* FROM "people"
311
+ INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
312
+ GROUP BY "articles"."title"
313
+ HAVING max("articles"."id") = "articles"."id"
314
+
315
+ If you want to use an attribute from a different branch of the hierarchy, use an absolute
316
+ keypath (~) as done here:
317
+
318
+ Person.joins{articles}.group{articles.title}.having{{articles => {max(~id) => id}}}
319
+ => SELECT "people".* FROM "people"
320
+ INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
321
+ GROUP BY "articles"."title"
322
+ HAVING max("people"."id") = "articles"."id"
323
+
324
+ ### SQL Operators
325
+
326
+ You can use the standard mathematical operators (`+`, `-`, `*`, `/`) inside the Squeel DSL to
327
+ specify operators in the resulting SQL, or the `op` method to specify another
328
+ custom operator, such as the standard SQL concatenation operator, `||`:
329
+
330
+ p = Person.select{name.op('||', '-diddly').as(flanderized_name)}.first
331
+ p.flanderized_name
332
+ => "Aric Smith-diddly"
333
+
334
+ As you can see, just like functions, these operations can be given aliases.
335
+
336
+ ## Legacy compatibility
337
+
338
+ While the Squeel DSL is the preferred way to access advanced query functionality, you can
339
+ still enable methods on symbols to access ARel predications in a similar manner to MetaWhere:
340
+
341
+ Squeel.configure do |config|
342
+ config.load_core_extensions :symbol
343
+ end
344
+
345
+ Person.joins(:articles => :comments).
346
+ where(:articles => {:comments => {:body.matches => 'Hello!'}})
347
+ SELECT "people".* FROM "people"
348
+ INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
349
+ INNER JOIN "comments" ON "comments"."article_id" = "articles"."id"
350
+ WHERE "comments"."body" LIKE 'Hello!'
351
+
352
+ This should help to smooth over the transition to the new DSL.
353
+
354
+ ## Contributions
355
+
356
+ If you'd like to support the continued development of Squeel, please consider
357
+ [making a donation](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=N7QP5N3UB76ME).
358
+
359
+ To support the project in other ways:
360
+
361
+ * Use Squeel in your apps, and let me know if you encounter anything that's broken or missing.
362
+ A failing spec is awesome. A pull request is even better!
363
+ * Spread the word on Twitter, Facebook, and elsewhere if Squeel's been useful to you. The more
364
+ people who are using the project, the quicker we can find and fix bugs!
365
+
366
+ ## Copyright
367
+
368
+ Copyright &copy; 2011 [Ernie Miller](http://twitter.com/erniemiller)
@@ -1,13 +1,13 @@
1
1
  require 'squeel/nodes/predicate_operators'
2
2
 
3
+ # Hashes are "acceptable" by PredicateVisitor, so they
4
+ # can be treated like nodes for the purposes of and/or/not
5
+ # if you load these extensions.
6
+ #
7
+ # @example Load Hash extensions
8
+ # Squeel.configure do |config|
9
+ # config.load_core_extensions :hash
10
+ # end
3
11
  class Hash
4
- # Hashes are "acceptable" by PredicateVisitor, so they
5
- # can be treated like nodes for the purposes of and/or/not
6
- # if you load core extensions with:
7
- #
8
- # Squeel.configure do |config|
9
- # config.load_core_extensions :hash
10
- # end
11
-
12
12
  include Squeel::Nodes::PredicateOperators
13
13
  end
@@ -1,12 +1,13 @@
1
1
  require 'squeel/predicate_methods'
2
2
 
3
+ # These extensions to Symbol are loaded optionally, mostly to provide
4
+ # a small amount of backwards compatibility with MetaWhere.
5
+ #
6
+ # @example Load Symbol extensions
7
+ # Squeel.configure do |config|
8
+ # config.load_core_extensions :symbol
9
+ # end
3
10
  class Symbol
4
- # These extensions to Symbol are loaded optionally, with:
5
- #
6
- # Squeel.configure do |config|
7
- # config.load_core_extensions :symbol
8
- # end
9
-
10
11
  include Squeel::PredicateMethods
11
12
 
12
13
  def asc
@@ -4,6 +4,7 @@ module Squeel
4
4
 
5
5
  extend Configuration
6
6
 
7
+ # Prevent warnings on the console when doing things some might describe as "evil"
7
8
  def self.evil_things
8
9
  original_verbosity = $VERBOSE
9
10
  $VERBOSE = nil
@@ -12,6 +13,7 @@ module Squeel
12
13
  $VERBOSE = original_verbosity
13
14
  end
14
15
 
16
+ # Set up initial predicate aliases
15
17
  Constants::PREDICATE_ALIASES.each do |original, aliases|
16
18
  aliases.each do |aliaz|
17
19
  alias_predicate aliaz, original
@@ -1,23 +1,28 @@
1
- case ActiveRecord::VERSION::STRING
2
- when /^3\.0\./
3
- require 'squeel/adapters/active_record/3.0/compat'
4
- require 'squeel/adapters/active_record/3.0/relation'
5
- require 'squeel/adapters/active_record/3.0/join_dependency'
6
- require 'squeel/adapters/active_record/3.0/join_association'
7
- require 'squeel/adapters/active_record/3.0/association_preload'
8
- require 'squeel/adapters/active_record/3.0/context'
1
+ case ActiveRecord::VERSION::MAJOR
2
+ when 3
3
+ case ActiveRecord::VERSION::MINOR
4
+ when 0
5
+ require 'squeel/adapters/active_record/3.0/compat'
6
+ require 'squeel/adapters/active_record/3.0/relation'
7
+ require 'squeel/adapters/active_record/3.0/join_dependency'
8
+ require 'squeel/adapters/active_record/3.0/join_association'
9
+ require 'squeel/adapters/active_record/3.0/association_preload'
10
+ require 'squeel/adapters/active_record/3.0/context'
9
11
 
10
- ActiveRecord::Relation.send :include, Squeel::Adapters::ActiveRecord::Relation
11
- ActiveRecord::Associations::ClassMethods::JoinDependency.send :include, Squeel::Adapters::ActiveRecord::JoinDependency
12
- ActiveRecord::Base.extend Squeel::Adapters::ActiveRecord::AssociationPreload
13
- else
14
- require 'squeel/adapters/active_record/relation'
15
- require 'squeel/adapters/active_record/join_dependency'
16
- require 'squeel/adapters/active_record/join_association'
17
- require 'squeel/adapters/active_record/preloader'
18
- require 'squeel/adapters/active_record/context'
12
+ ActiveRecord::Relation.send :include, Squeel::Adapters::ActiveRecord::Relation
13
+ ActiveRecord::Associations::ClassMethods::JoinDependency.send :include, Squeel::Adapters::ActiveRecord::JoinDependency
14
+ ActiveRecord::Base.extend Squeel::Adapters::ActiveRecord::AssociationPreload
15
+ else
16
+ require 'squeel/adapters/active_record/relation'
17
+ require 'squeel/adapters/active_record/join_dependency'
18
+ require 'squeel/adapters/active_record/join_association'
19
+ require 'squeel/adapters/active_record/preloader'
20
+ require 'squeel/adapters/active_record/context'
19
21
 
20
- ActiveRecord::Relation.send :include, Squeel::Adapters::ActiveRecord::Relation
21
- ActiveRecord::Associations::JoinDependency.send :include, Squeel::Adapters::ActiveRecord::JoinDependency
22
- ActiveRecord::Associations::Preloader.send :include, Squeel::Adapters::ActiveRecord::Preloader
22
+ ActiveRecord::Relation.send :include, Squeel::Adapters::ActiveRecord::Relation
23
+ ActiveRecord::Associations::JoinDependency.send :include, Squeel::Adapters::ActiveRecord::JoinDependency
24
+ ActiveRecord::Associations::Preloader.send :include, Squeel::Adapters::ActiveRecord::Preloader
25
+ end
26
+ else
27
+ raise NotImplementedError, "Squeel does not support ActiveRecord version #{ActiveRecord::VERSION::STRING}"
23
28
  end