squeel 1.0.18 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +2 -7
- data/CHANGELOG.md +9 -0
- data/Gemfile +2 -2
- data/README.md +223 -147
- data/lib/generators/templates/squeel.rb +1 -1
- data/lib/squeel/adapters/active_record.rb +1 -1
- data/lib/squeel/adapters/active_record/4.0/compat.rb +17 -0
- data/lib/squeel/adapters/active_record/4.0/context.rb +1 -0
- data/lib/squeel/adapters/active_record/4.0/preloader_extensions.rb +1 -0
- data/lib/squeel/adapters/active_record/4.0/relation_extensions.rb +126 -0
- data/lib/squeel/adapters/active_record/base_extensions.rb +1 -1
- data/lib/squeel/adapters/active_record/context.rb +10 -10
- data/lib/squeel/adapters/active_record/relation_extensions.rb +24 -16
- data/lib/squeel/configuration.rb +1 -0
- data/lib/squeel/constants.rb +2 -2
- data/lib/squeel/context.rb +2 -2
- data/lib/squeel/dsl.rb +1 -1
- data/lib/squeel/nodes.rb +2 -0
- data/lib/squeel/nodes/binary.rb +1 -1
- data/lib/squeel/nodes/function.rb +5 -5
- data/lib/squeel/nodes/join.rb +2 -2
- data/lib/squeel/nodes/key_path.rb +10 -5
- data/lib/squeel/nodes/literal.rb +1 -1
- data/lib/squeel/nodes/nary.rb +5 -7
- data/lib/squeel/nodes/node.rb +6 -0
- data/lib/squeel/nodes/operation.rb +1 -1
- data/lib/squeel/nodes/order.rb +1 -1
- data/lib/squeel/nodes/predicate.rb +5 -5
- data/lib/squeel/nodes/predicate_methods.rb +11 -2
- data/lib/squeel/nodes/sifter.rb +2 -2
- data/lib/squeel/nodes/stub.rb +2 -2
- data/lib/squeel/nodes/unary.rb +1 -1
- data/lib/squeel/version.rb +1 -1
- data/lib/squeel/visitors/predicate_visitation.rb +6 -6
- data/lib/squeel/visitors/predicate_visitor.rb +1 -1
- data/lib/squeel/visitors/visitor.rb +20 -20
- data/spec/spec_helper.rb +6 -4
- data/spec/squeel/adapters/active_record/base_extensions_spec.rb +6 -6
- data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +55 -24
- data/spec/squeel/core_ext/symbol_spec.rb +2 -2
- data/spec/squeel/nodes/key_path_spec.rb +3 -3
- data/spec/squeel/nodes/predicate_operators_spec.rb +4 -4
- data/spec/squeel/visitors/predicate_visitor_spec.rb +11 -11
- data/spec/squeel/visitors/visitor_spec.rb +9 -9
- data/spec/support/models.rb +25 -7
- data/spec/support/schema.rb +1 -1
- data/squeel.gemspec +4 -4
- metadata +19 -12
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
squeel
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-1.9.3
|
data/.travis.yml
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
rvm:
|
2
|
-
- 1.8.7
|
3
2
|
- 1.9.3
|
4
|
-
# TODO: Re-enable when updates to Rubinius on
|
5
|
-
# Travis stop randomly breaking specs that
|
6
|
-
# pass on MRI. :(
|
7
|
-
# - rbx-18mode
|
8
|
-
# - rbx-19mode
|
9
3
|
|
10
4
|
env:
|
11
|
-
- RAILS=
|
5
|
+
- RAILS=4-0-stable AREL=master
|
6
|
+
- RAILS=3-2-stable AREL=3-0-stable
|
12
7
|
- RAILS=3-1-stable AREL=2-2-stable
|
13
8
|
- RAILS=3-0-stable AREL=2-0-stable
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 1.1.0 (2013-07-14)
|
2
|
+
|
3
|
+
* Support for Active Record 4.0.0!
|
4
|
+
* Deprecated core extensions. In Squeel 2.0, the DSL will be the way to
|
5
|
+
construct queries, and Symbol/Hash extensions will go away.
|
6
|
+
* Prefix generated sifter methods with `sifter_` so as not to interfere with
|
7
|
+
similarly-named scopes.
|
8
|
+
* No longer mutate And nodes when using `&` and `-` on the node
|
9
|
+
|
1
10
|
## 1.0.18 (2013-03-07)
|
2
11
|
|
3
12
|
* Stop treating nils as quotable. Fixes issue #221.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
# Squeel [![Build Status](https://secure.travis-ci.org/ernie/squeel.png)](http://travis-ci.org/ernie/squeel) [![endorse](http://api.coderwall.com/ernie/endorsecount.png)](http://coderwall.com/ernie)
|
2
2
|
|
3
3
|
Squeel lets you write your Active Record queries with fewer strings, and more Ruby,
|
4
|
-
by making the
|
4
|
+
by making the Arel awesomeness that lies beneath Active Record more accessible.
|
5
5
|
|
6
6
|
Squeel lets you rewrite...
|
7
7
|
|
8
|
-
|
8
|
+
```ruby
|
9
|
+
Article.where ['created_at >= ?', 2.weeks.ago]
|
10
|
+
```
|
9
11
|
|
10
12
|
...as...
|
11
13
|
|
12
|
-
|
14
|
+
```ruby
|
15
|
+
Article.where{created_at >= 2.weeks.ago}
|
16
|
+
```
|
13
17
|
|
14
18
|
This is a _good thing_. If you don't agree, Squeel might not be for you. The above is
|
15
19
|
just a simple example -- Squeel's capable of a whole lot more. Keep reading.
|
@@ -18,8 +22,10 @@ just a simple example -- Squeel's capable of a whole lot more. Keep reading.
|
|
18
22
|
|
19
23
|
In your Gemfile:
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
```ruby
|
26
|
+
gem "squeel" # Last officially released gem
|
27
|
+
# gem "squeel", :git => "git://github.com/ernie/squeel.git" # Track git repo
|
28
|
+
```
|
23
29
|
|
24
30
|
Then bundle as usual.
|
25
31
|
|
@@ -27,7 +33,9 @@ If you'd like to customize Squeel's functionality by enabling core
|
|
27
33
|
extensions for hashes or symbols, or aliasing some predicates, you can
|
28
34
|
create a sample initializer with:
|
29
35
|
|
30
|
-
|
36
|
+
```sh
|
37
|
+
$ rails g squeel:initializer
|
38
|
+
```
|
31
39
|
|
32
40
|
## The Squeel Query DSL
|
33
41
|
|
@@ -63,8 +71,10 @@ Stubs are, for most intents and purposes, just like Symbols in a normal call to
|
|
63
71
|
`Relation#where` (note the need for doubling up on the curly braces here, the first ones
|
64
72
|
start the block, the second are the hash braces):
|
65
73
|
|
66
|
-
|
67
|
-
|
74
|
+
```ruby
|
75
|
+
Person.where{{name => 'Ernie'}}
|
76
|
+
# => SELECT "people".* FROM "people" WHERE "people"."name" = 'Ernie'
|
77
|
+
```
|
68
78
|
|
69
79
|
You normally wouldn't bother using the DSL in this case, as a simple hash would
|
70
80
|
suffice. However, stubs serve as a building block for keypaths, and keypaths are
|
@@ -76,29 +86,35 @@ A Squeel keypath is essentially a more concise and readable alternative to a
|
|
76
86
|
deeply nested hash. For instance, in standard Active Record, you might join several
|
77
87
|
associations like this to perform a query:
|
78
88
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
89
|
+
```ruby
|
90
|
+
Person.joins(:articles => {:comments => :person})
|
91
|
+
# => SELECT "people".* FROM "people"
|
92
|
+
# INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
93
|
+
# INNER JOIN "comments" ON "comments"."article_id" = "articles"."id"
|
94
|
+
# INNER JOIN "people" "people_comments" ON "people_comments"."id" = "comments"."person_id"
|
95
|
+
```
|
84
96
|
|
85
97
|
With a keypath, this would look like:
|
86
98
|
|
87
|
-
|
99
|
+
```ruby
|
100
|
+
Person.joins{articles.comments.person}
|
101
|
+
```
|
88
102
|
|
89
103
|
A keypath can exist in the context of a hash, and is normally interpreted relative to
|
90
104
|
the current level of nesting. It can be forced into an "absolute" path by anchoring it with
|
91
105
|
a ~, like:
|
92
106
|
|
93
|
-
|
107
|
+
```ruby
|
108
|
+
~articles.comments.person
|
109
|
+
```
|
94
110
|
|
95
111
|
This isn't quite so useful in the typical hash context, but can be very useful when it comes
|
96
112
|
to interpreting functions and the like. We'll cover those later.
|
97
113
|
|
98
114
|
### Predicates
|
99
115
|
|
100
|
-
All of the
|
101
|
-
their method name, an alias, or an an operator, to create
|
116
|
+
All of the Arel "predication" methods can be accessed inside the Squeel DSL, via
|
117
|
+
their method name, an alias, or an an operator, to create Arel predicates, which are
|
102
118
|
used in `WHERE` or `HAVING` clauses.
|
103
119
|
|
104
120
|
<table>
|
@@ -172,34 +188,44 @@ used in `WHERE` or `HAVING` clauses.
|
|
172
188
|
|
173
189
|
Let's say we want to generate this simple query:
|
174
190
|
|
175
|
-
|
191
|
+
```
|
192
|
+
SELECT "people".* FROM people WHERE "people"."name" = 'Joe Blow'
|
193
|
+
```
|
176
194
|
|
177
195
|
All of the following will generate the above SQL:
|
178
196
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
197
|
+
```ruby
|
198
|
+
Person.where(:name => 'Joe Blow')
|
199
|
+
Person.where{{name => 'Joe Blow'}}
|
200
|
+
Person.where{{name.eq => 'Joe Blow'}}
|
201
|
+
Person.where{name.eq 'Joe Blow'}
|
202
|
+
Person.where{name == 'Joe Blow'}
|
203
|
+
```
|
204
|
+
|
185
205
|
Not a very exciting example since equality is handled just fine via the
|
186
206
|
first example in standard Active Record. But consider the following query:
|
187
207
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
208
|
+
```
|
209
|
+
SELECT "people".* FROM people
|
210
|
+
WHERE ("people"."name" LIKE 'Ernie%' AND "people"."salary" < 50000)
|
211
|
+
OR ("people"."name" LIKE 'Joe%' AND "people"."salary" > 100000)
|
212
|
+
```
|
213
|
+
|
192
214
|
To do this with standard Active Record, we'd do something like:
|
193
215
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
216
|
+
```ruby
|
217
|
+
Person.where(
|
218
|
+
'(name LIKE ? AND salary < ?) OR (name LIKE ? AND salary > ?)',
|
219
|
+
'Ernie%', 50000, 'Joe%', 100000
|
220
|
+
)
|
221
|
+
```
|
222
|
+
|
199
223
|
With Squeel:
|
200
224
|
|
201
|
-
|
202
|
-
|
225
|
+
```ruby
|
226
|
+
Person.where{(name =~ 'Ernie%') & (salary < 50000) | (name =~ 'Joe%') & (salary > 100000)}
|
227
|
+
```
|
228
|
+
|
203
229
|
Here, we're using `&` and `|` to generate `AND` and `OR`, respectively.
|
204
230
|
|
205
231
|
There are two obvious but important differences between these two code samples, and
|
@@ -209,7 +235,7 @@ both of them have to do with *context*.
|
|
209
235
|
first be considered, then we must cross-reference the values to be substituted
|
210
236
|
with their placeholders. This carries with it a small but perceptible (and
|
211
237
|
annoying!) context shift during which we stop thinking about the comparison being
|
212
|
-
performed, and instead play "count the arguments", or, in the case of
|
238
|
+
performed, and instead play "count the arguments", or, in the case of
|
213
239
|
named/hash interpolations, "find the word". The Squeel syntax places
|
214
240
|
both sides of each comparison in proximity to one another, allowing us to
|
215
241
|
focus on what our code is doing.
|
@@ -228,12 +254,15 @@ our intentions more clear, on the first read-through. And if we don't like the
|
|
228
254
|
way that the existing predications read, we can create our own aliases in a Squeel
|
229
255
|
configure block:
|
230
256
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
257
|
+
```ruby
|
258
|
+
Squeel.configure do |config|
|
259
|
+
config.alias_predicate :is_less_than, :lt
|
260
|
+
end
|
261
|
+
```
|
262
|
+
```ruby
|
263
|
+
Person.where{salary.is_less_than 50000}.to_sql
|
264
|
+
# => SELECT "people".* FROM "people" WHERE "people"."salary" < 50000
|
265
|
+
```
|
237
266
|
|
238
267
|
And while we're on the topic of helping you make your code more expressive...
|
239
268
|
|
@@ -241,20 +270,26 @@ And while we're on the topic of helping you make your code more expressive...
|
|
241
270
|
|
242
271
|
Let's say you want to check if a Person has a name like one of several possibilities.
|
243
272
|
|
244
|
-
|
245
|
-
|
273
|
+
```ruby
|
274
|
+
names = ['Ernie%', 'Joe%', 'Mary%']
|
275
|
+
Person.where('name LIKE ? OR name LIKE ? OR name LIKE ?', *names)
|
276
|
+
```
|
246
277
|
|
247
278
|
But you're smart, and you know that you might want to check more or less than
|
248
279
|
3 names, so you make your query flexible:
|
249
280
|
|
250
|
-
|
281
|
+
```ruby
|
282
|
+
Person.where((['name LIKE ?'] * names.size).join(' OR '), *names)
|
283
|
+
```
|
251
284
|
|
252
285
|
Yeah... that's readable, all right. How about:
|
253
286
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
287
|
+
```ruby
|
288
|
+
Person.where{name.like_any names}
|
289
|
+
# => SELECT "people".* FROM "people"
|
290
|
+
# WHERE (("people"."name" LIKE 'Ernie%' OR "people"."name" LIKE 'Joe%' OR "people"."name" LIKE 'Mary%'))
|
291
|
+
```
|
292
|
+
|
258
293
|
I'm not sure about you, but I much prefer the latter. In short, you can add `_any` or
|
259
294
|
`_all` to any predicate method, and it would do what you expect, when given an array of
|
260
295
|
possibilities to compare against.
|
@@ -265,57 +300,69 @@ Sifters are like little snippets of conditions that take parameters. Let's say t
|
|
265
300
|
have a model called Article, and you often want to query for articles that contain a
|
266
301
|
string in the title or body. So you write a scope:
|
267
302
|
|
268
|
-
|
269
|
-
|
270
|
-
|
303
|
+
```ruby
|
304
|
+
def self.title_or_body_contains(string)
|
305
|
+
where{title.matches("%#{string}%") | body.matches("%#{string}%")}
|
306
|
+
end
|
307
|
+
```
|
271
308
|
|
272
309
|
But then you want to query for people who wrote an article that matches these conditions,
|
273
310
|
but the scope only works against the model where it was defined. So instead, you write a
|
274
311
|
sifter:
|
275
312
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
313
|
+
```ruby
|
314
|
+
class Article < ActiveRecord::Base
|
315
|
+
sifter :title_or_body_contains do |string|
|
316
|
+
title.matches("%#{string}%") | body.matches("%#{string}%")
|
317
|
+
end
|
318
|
+
end
|
319
|
+
```
|
281
320
|
|
282
321
|
Now you can write...
|
283
322
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
323
|
+
```ruby
|
324
|
+
Article.where{sift :title_or_body_contains, 'awesome'}
|
325
|
+
# => SELECT "articles".* FROM "articles"
|
326
|
+
# WHERE ((
|
327
|
+
# "articles"."title" LIKE '%awesome%'
|
328
|
+
# OR "articles"."body" LIKE '%awesome%'
|
329
|
+
# ))
|
330
|
+
```
|
290
331
|
|
291
332
|
... or ...
|
292
333
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
334
|
+
```ruby
|
335
|
+
Person.joins(:articles).
|
336
|
+
where{
|
337
|
+
{articles => sift(:title_or_body_contains, 'awesome')}
|
338
|
+
}
|
339
|
+
# => SELECT "people".* FROM "people"
|
340
|
+
# INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
341
|
+
# WHERE ((
|
342
|
+
# "articles"."title" LIKE '%awesome%'
|
343
|
+
# OR "articles"."body" LIKE '%awesome%'
|
344
|
+
# ))
|
345
|
+
```
|
303
346
|
|
304
347
|
Or, you can just modify your previous scope, changing `where` to `squeel`:
|
305
348
|
|
306
|
-
|
307
|
-
|
308
|
-
|
349
|
+
```ruby
|
350
|
+
def self.title_or_body_contains(string)
|
351
|
+
squeel{title.matches("%#{string}%") | body.matches("%#{string}%")}
|
352
|
+
end
|
353
|
+
```
|
309
354
|
|
310
355
|
### Subqueries
|
311
356
|
|
312
357
|
You can supply an `ActiveRecord::Relation` as a value for a predicate in order to use
|
313
358
|
a subquery. So, for example:
|
314
359
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
360
|
+
```ruby
|
361
|
+
awesome_people = Person.where{awesome == true}
|
362
|
+
Article.where{author_id.in(awesome_people.select{id})}
|
363
|
+
# => SELECT "articles".* FROM "articles"
|
364
|
+
# WHERE "articles"."author_id" IN (SELECT "people"."id" FROM "people" WHERE "people"."awesome" = 't')
|
365
|
+
```
|
319
366
|
|
320
367
|
### Joins
|
321
368
|
|
@@ -323,40 +370,46 @@ Squeel adds a couple of enhancements to joins. First, keypaths can be used as sh
|
|
323
370
|
nested association joins. Second, you can specify join types (inner and outer), and a class
|
324
371
|
in the case of a polymorphic belongs_to relationship.
|
325
372
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
373
|
+
```ruby
|
374
|
+
Person.joins{articles.outer}
|
375
|
+
# => SELECT "people".* FROM "people"
|
376
|
+
# LEFT OUTER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
377
|
+
Note.joins{notable(Person).outer}
|
378
|
+
# => SELECT "notes".* FROM "notes"
|
379
|
+
# LEFT OUTER JOIN "people"
|
380
|
+
# ON "people"."id" = "notes"."notable_id"
|
381
|
+
# AND "notes"."notable_type" = 'Person'
|
382
|
+
```
|
334
383
|
|
335
384
|
These can also be used inside keypaths:
|
336
385
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
386
|
+
```ruby
|
387
|
+
Note.joins{notable(Person).articles}
|
388
|
+
# => SELECT "notes".* FROM "notes"
|
389
|
+
# INNER JOIN "people" ON "people"."id" = "notes"."notable_id"
|
390
|
+
# AND "notes"."notable_type" = 'Person'
|
391
|
+
# INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
392
|
+
```
|
393
|
+
|
343
394
|
You can refer to these associations when constructing other parts of your query, and
|
344
395
|
they'll be automatically mapped to the proper table or table alias This is most noticeable
|
345
396
|
when using self-referential associations:
|
346
397
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
398
|
+
```ruby
|
399
|
+
Person.joins{children.parent.children}.
|
400
|
+
where{
|
401
|
+
(children.name.like 'Ernie%') |
|
402
|
+
(children.parent.name.like 'Ernie%') |
|
403
|
+
(children.parent.children.name.like 'Ernie%')
|
404
|
+
}
|
405
|
+
# => SELECT "people".* FROM "people"
|
406
|
+
# INNER JOIN "people" "children_people" ON "children_people"."parent_id" = "people"."id"
|
407
|
+
# INNER JOIN "people" "parents_people" ON "parents_people"."id" = "children_people"."parent_id"
|
408
|
+
# INNER JOIN "people" "children_people_2" ON "children_people_2"."parent_id" = "parents_people"."id"
|
409
|
+
# WHERE ((("children_people"."name" LIKE 'Ernie%'
|
410
|
+
# OR "parents_people"."name" LIKE 'Ernie%')
|
411
|
+
# OR "children_people_2"."name" LIKE 'Ernie%'))
|
412
|
+
```
|
360
413
|
|
361
414
|
Keypaths were used here for clarity, but nested hashes would work just as well.
|
362
415
|
|
@@ -364,33 +417,41 @@ Keypaths were used here for clarity, but nested hashes would work just as well.
|
|
364
417
|
|
365
418
|
You can call SQL functions just like you would call a method in Ruby...
|
366
419
|
|
367
|
-
|
368
|
-
|
420
|
+
```ruby
|
421
|
+
Person.select{coalesce(name, '<no name given>')}
|
422
|
+
# => SELECT coalesce("people"."name", '<no name given>') FROM "people"
|
423
|
+
```
|
369
424
|
|
370
425
|
...and you can easily give it an alias:
|
371
426
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
427
|
+
```ruby
|
428
|
+
person = Person.select{
|
429
|
+
coalesce(name, '<no name given>').as(name_with_default)
|
430
|
+
}.first
|
431
|
+
person.name_with_default # name or <no name given>, depending on data
|
432
|
+
```
|
376
433
|
|
377
434
|
When you use a stub, symbol, or keypath inside a function call, it'll be interpreted relative to
|
378
435
|
its place inside any nested associations:
|
379
436
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
437
|
+
```ruby
|
438
|
+
Person.joins{articles}.group{articles.title}.having{{articles => {max(id) => id}}}
|
439
|
+
# => SELECT "people".* FROM "people"
|
440
|
+
# INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
441
|
+
# GROUP BY "articles"."title"
|
442
|
+
# HAVING max("articles"."id") = "articles"."id"
|
443
|
+
```
|
444
|
+
|
386
445
|
If you want to use an attribute from a different branch of the hierarchy, use an absolute
|
387
446
|
keypath (~) as done here:
|
388
447
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
448
|
+
```ruby
|
449
|
+
Person.joins{articles}.group{articles.title}.having{{articles => {max(~id) => id}}}
|
450
|
+
# => SELECT "people".* FROM "people"
|
451
|
+
# INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
452
|
+
# GROUP BY "articles"."title"
|
453
|
+
# HAVING max("people"."id") = "articles"."id"
|
454
|
+
```
|
394
455
|
|
395
456
|
### SQL Operators
|
396
457
|
|
@@ -398,13 +459,15 @@ You can use the standard mathematical operators (`+`, `-`, `*`, `/`) inside the
|
|
398
459
|
specify operators in the resulting SQL, or the `op` method to specify another
|
399
460
|
custom operator, such as the standard SQL concatenation operator, `||`:
|
400
461
|
|
401
|
-
|
402
|
-
|
403
|
-
|
462
|
+
```ruby
|
463
|
+
p = Person.select{name.op('||', '-diddly').as(flanderized_name)}.first
|
464
|
+
p.flanderized_name
|
465
|
+
# => "Aric Smith-diddly"
|
466
|
+
```
|
404
467
|
|
405
468
|
As you can see, just like functions, these operations can be given aliases.
|
406
469
|
|
407
|
-
## Compatibility with Active Record
|
470
|
+
## Compatibility with Active Record
|
408
471
|
|
409
472
|
Most of the new functionality provided by Squeel is accessed with the new block-style `where{}`
|
410
473
|
syntax.
|
@@ -424,15 +487,21 @@ the name of a **column** instead of simply treating the symbol as a **string lit
|
|
424
487
|
|
425
488
|
For example, this query:
|
426
489
|
|
427
|
-
|
490
|
+
```ruby
|
491
|
+
Person.where(:first_name => :last_name)
|
492
|
+
```
|
428
493
|
|
429
494
|
produces this SQL query in plain Active Record:
|
430
495
|
|
431
|
-
|
496
|
+
```
|
497
|
+
SELECT people.* FROM people WHERE people.first_name = 'last_name'.
|
498
|
+
```
|
432
499
|
|
433
500
|
but produces this SQL query if you are using Squeel:
|
434
501
|
|
435
|
-
|
502
|
+
```
|
503
|
+
SELECT people.* FROM people WHERE people.first_name = people.last_name
|
504
|
+
```
|
436
505
|
|
437
506
|
Note that this new behavior applies to the plain `where()`-style expressions in addition to the new
|
438
507
|
`where{}` Squeel style.
|
@@ -440,13 +509,17 @@ Note that this new behavior applies to the plain `where()`-style expressions in
|
|
440
509
|
In order for your existing `where()` clauses with symbols to continue to behave the same, you
|
441
510
|
**must** change the symbols into strings. These scopes, for example:
|
442
511
|
|
443
|
-
|
444
|
-
|
512
|
+
```ruby
|
513
|
+
scope :active, where(:state => :active)
|
514
|
+
scope :in_state, lambda {|state| where(:state => state) }
|
515
|
+
```
|
445
516
|
|
446
517
|
should be changed to this:
|
447
518
|
|
448
|
-
|
449
|
-
|
519
|
+
```ruby
|
520
|
+
scope :active, where(:state => 'active')
|
521
|
+
scope :in_state, lambda {|state| where(:state => state.to_s) }
|
522
|
+
```
|
450
523
|
|
451
524
|
For further information, see
|
452
525
|
[this post to the Rails list](https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-core/NQJJzZ7R7S0),
|
@@ -459,18 +532,21 @@ the [Active Record guides](http://edgeguides.rubyonrails.org/active_record_query
|
|
459
532
|
## Compatibility with MetaWhere
|
460
533
|
|
461
534
|
While the Squeel DSL is the preferred way to access advanced query functionality, you can
|
462
|
-
still enable methods on symbols to access
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
535
|
+
still enable methods on symbols to access Arel predications in a similar manner to MetaWhere:
|
536
|
+
|
537
|
+
```ruby
|
538
|
+
Squeel.configure do |config|
|
539
|
+
config.load_core_extensions :symbol
|
540
|
+
end
|
541
|
+
```
|
542
|
+
```ruby
|
543
|
+
Person.joins(:articles => :comments).
|
544
|
+
where(:articles => {:comments => {:body.matches => 'Hello!'}})
|
545
|
+
# => SELECT "people".* FROM "people"
|
546
|
+
# INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
547
|
+
# INNER JOIN "comments" ON "comments"."article_id" = "articles"."id"
|
548
|
+
# WHERE "comments"."body" LIKE 'Hello!'
|
549
|
+
```
|
474
550
|
|
475
551
|
This should help to smooth over the transition to the new DSL.
|
476
552
|
|