sequel 3.37.0 → 3.38.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +56 -0
- data/README.rdoc +82 -58
- data/Rakefile +6 -5
- data/bin/sequel +1 -1
- data/doc/active_record.rdoc +67 -52
- data/doc/advanced_associations.rdoc +33 -48
- data/doc/association_basics.rdoc +41 -51
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +47 -43
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +4 -5
- data/doc/model_hooks.rdoc +3 -3
- data/doc/object_model.rdoc +31 -25
- data/doc/opening_databases.rdoc +19 -5
- data/doc/prepared_statements.rdoc +2 -2
- data/doc/querying.rdoc +109 -52
- data/doc/reflection.rdoc +6 -6
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/schema_modification.rdoc +22 -13
- data/doc/sharding.rdoc +8 -9
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +47 -7
- data/doc/thread_safety.rdoc +1 -1
- data/doc/transactions.rdoc +1 -1
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +29 -43
- data/lib/sequel/adapters/do/postgres.rb +1 -4
- data/lib/sequel/adapters/jdbc.rb +14 -3
- data/lib/sequel/adapters/jdbc/db2.rb +9 -0
- data/lib/sequel/adapters/jdbc/derby.rb +41 -4
- data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
- data/lib/sequel/adapters/mock.rb +10 -4
- data/lib/sequel/adapters/postgres.rb +1 -28
- data/lib/sequel/adapters/shared/mssql.rb +23 -13
- data/lib/sequel/adapters/shared/postgres.rb +46 -0
- data/lib/sequel/adapters/swift.rb +21 -13
- data/lib/sequel/adapters/swift/mysql.rb +1 -0
- data/lib/sequel/adapters/swift/postgres.rb +4 -5
- data/lib/sequel/adapters/swift/sqlite.rb +2 -1
- data/lib/sequel/adapters/tinytds.rb +14 -2
- data/lib/sequel/adapters/utils/pg_types.rb +5 -0
- data/lib/sequel/core.rb +29 -17
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +3 -0
- data/lib/sequel/dataset/actions.rb +5 -6
- data/lib/sequel/dataset/query.rb +7 -7
- data/lib/sequel/dataset/sql.rb +5 -18
- data/lib/sequel/extensions/core_extensions.rb +8 -12
- data/lib/sequel/extensions/pg_array.rb +59 -33
- data/lib/sequel/extensions/pg_array_ops.rb +32 -4
- data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +32 -17
- data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
- data/lib/sequel/extensions/pg_inet.rb +1 -2
- data/lib/sequel/extensions/pg_interval.rb +0 -1
- data/lib/sequel/extensions/pg_json.rb +41 -23
- data/lib/sequel/extensions/pg_range.rb +36 -11
- data/lib/sequel/extensions/pg_range_ops.rb +32 -4
- data/lib/sequel/extensions/pg_row.rb +572 -0
- data/lib/sequel/extensions/pg_row_ops.rb +164 -0
- data/lib/sequel/extensions/query.rb +3 -3
- data/lib/sequel/extensions/schema_dumper.rb +7 -8
- data/lib/sequel/extensions/select_remove.rb +1 -1
- data/lib/sequel/model/base.rb +1 -0
- data/lib/sequel/no_core_ext.rb +1 -1
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/validation_helpers.rb +31 -0
- data/lib/sequel/sql.rb +64 -44
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +37 -12
- data/spec/adapters/mysql_spec.rb +39 -75
- data/spec/adapters/oracle_spec.rb +11 -11
- data/spec/adapters/postgres_spec.rb +414 -237
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +14 -14
- data/spec/core/database_spec.rb +6 -6
- data/spec/core/dataset_spec.rb +169 -205
- data/spec/core/expression_filters_spec.rb +182 -295
- data/spec/core/object_graph_spec.rb +6 -6
- data/spec/core/schema_spec.rb +14 -14
- data/spec/core/spec_helper.rb +1 -0
- data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
- data/spec/extensions/columns_introspection_spec.rb +5 -5
- data/spec/extensions/hook_class_methods_spec.rb +28 -36
- data/spec/extensions/many_through_many_spec.rb +4 -4
- data/spec/extensions/pg_array_ops_spec.rb +15 -7
- data/spec/extensions/pg_array_spec.rb +81 -48
- data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
- data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
- data/spec/extensions/pg_hstore_spec.rb +66 -65
- data/spec/extensions/pg_inet_spec.rb +2 -4
- data/spec/extensions/pg_interval_spec.rb +2 -3
- data/spec/extensions/pg_json_spec.rb +20 -18
- data/spec/extensions/pg_range_ops_spec.rb +11 -4
- data/spec/extensions/pg_range_spec.rb +30 -7
- data/spec/extensions/pg_row_ops_spec.rb +48 -0
- data/spec/extensions/pg_row_plugin_spec.rb +45 -0
- data/spec/extensions/pg_row_spec.rb +323 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
- data/spec/extensions/query_literals_spec.rb +11 -11
- data/spec/extensions/query_spec.rb +3 -3
- data/spec/extensions/schema_dumper_spec.rb +20 -4
- data/spec/extensions/schema_spec.rb +18 -41
- data/spec/extensions/select_remove_spec.rb +4 -4
- data/spec/extensions/spec_helper.rb +4 -8
- data/spec/extensions/to_dot_spec.rb +5 -5
- data/spec/extensions/validation_class_methods_spec.rb +28 -16
- data/spec/integration/associations_test.rb +20 -20
- data/spec/integration/dataset_test.rb +98 -98
- data/spec/integration/eager_loader_test.rb +13 -27
- data/spec/integration/plugin_test.rb +5 -5
- data/spec/integration/prepared_statement_test.rb +22 -13
- data/spec/integration/schema_test.rb +28 -18
- data/spec/integration/spec_helper.rb +1 -1
- data/spec/integration/timezone_test.rb +2 -2
- data/spec/integration/type_test.rb +15 -6
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +4 -4
- data/spec/model/base_spec.rb +5 -5
- data/spec/model/eager_loading_spec.rb +15 -15
- data/spec/model/model_spec.rb +32 -32
- data/spec/model/record_spec.rb +16 -0
- data/spec/model/spec_helper.rb +2 -6
- data/spec/model/validations_spec.rb +1 -1
- metadata +16 -4
data/doc/opening_databases.rdoc
CHANGED
@@ -48,7 +48,7 @@ unless the first argument is a hash. So the following statements are equivalent
|
|
48
48
|
|
49
49
|
Note that using an adapter method forces the use of the specified adapter, not a database type, even
|
50
50
|
though some adapters have the same name as the database type. So if you
|
51
|
-
want to connect to SQLite, for example, you can do so using the sqlite, do,
|
51
|
+
want to connect to SQLite, for example, you can do so using the sqlite, do, jdbc, and swift adapters.
|
52
52
|
If you want to connect to SQLite on JRuby using the jdbc adapter, you should not use <tt>Sequel.sqlite</tt>
|
53
53
|
for example, as that uses the C-based sqlite3 gem. Instead, the <tt>Sequel.jdbc</tt> would be appropriate (though
|
54
54
|
as mentioned below, using <tt>Sequel.connect</tt> is recommended instead of <tt>Sequel.jdbc</tt>).
|
@@ -192,7 +192,7 @@ be faster than the other adapters.
|
|
192
192
|
Similar to the JDBC adapter, the DO adapter only cares about connection strings,
|
193
193
|
which can either be the String argument given to Sequel.connect directly or contained
|
194
194
|
in a :uri or :url option. The DO adapter passes through the connection string
|
195
|
-
directly to DataObjects, it does no processing of it.
|
195
|
+
directly to DataObjects, it does no processing of it (other than removing the do: prefix).
|
196
196
|
|
197
197
|
Connection string examples:
|
198
198
|
|
@@ -232,9 +232,9 @@ Requires: java
|
|
232
232
|
|
233
233
|
Houses Sequel's JDBC support when running on JRuby.
|
234
234
|
Support for individual database types is done using sub adapters.
|
235
|
-
There are currently subadapters for PostgreSQL, MySQL, SQLite, H2,
|
236
|
-
Oracle, MSSQL, JTDS, AS400, and DB2.
|
237
|
-
jdbc-* gem, for
|
235
|
+
There are currently subadapters for PostgreSQL, MySQL, SQLite, H2, HSQLDB, Derby,
|
236
|
+
Oracle, MSSQL, JTDS, AS400, Progress, Firebird, Informix, and DB2. For PostgreSQL, MySQL, SQLite, H2, Derby,
|
237
|
+
and JTDS, this can use the jdbc-* gem, for the others you need to have the .jar in your CLASSPATH
|
238
238
|
or load the Java class manually before calling Sequel.connect.
|
239
239
|
|
240
240
|
You just use the JDBC connection string directly, which can be specified
|
@@ -387,6 +387,12 @@ swift is a ruby 1.9 only library, so you'll need to be running ruby 1.9. It
|
|
387
387
|
can connect to SQLite, MySQL, and PostgreSQL, and you must specify which
|
388
388
|
database using the db_type option.
|
389
389
|
|
390
|
+
You need to install one of the swift db adapters
|
391
|
+
|
392
|
+
* swift-db-sqlite3
|
393
|
+
* swift-db-mysql
|
394
|
+
* swift-db-postgres
|
395
|
+
|
390
396
|
Examples:
|
391
397
|
|
392
398
|
swift:///?database=:memory:&db_type=sqlite
|
@@ -405,6 +411,14 @@ should specify the :dataserver option with that name as the value. Some other
|
|
405
411
|
options that you may want to set are :login_timeout, :timeout, :tds_version, :azure,
|
406
412
|
:appname, and :encoding, see the tiny_tds README for details.
|
407
413
|
|
414
|
+
Other Sequel specific options:
|
415
|
+
|
416
|
+
:textsize :: Override the default TEXTSIZE setting for this connection. The FreeTDS
|
417
|
+
default is small (around 64000 bytes), but can be set up to around 2GB.
|
418
|
+
This should be specified as an integer. If you plan on setting large
|
419
|
+
text or blob values via tinytds, you should use this option or modify
|
420
|
+
your freetds.conf file.
|
421
|
+
|
408
422
|
For highest performance, you should disable any identifier output method when
|
409
423
|
using the tinytds adapter, which probably means disabling any identifier input method
|
410
424
|
as well. The default for Microsoft SQL Server is to :downcase identifiers on output
|
@@ -10,7 +10,7 @@ the following adapters:
|
|
10
10
|
* mysql (prepared statements only)
|
11
11
|
* mysql2 (prepared statements only)
|
12
12
|
* oracle (requires type specifiers for nil/NULL values)
|
13
|
-
* postgres (when using the pg driver
|
13
|
+
* postgres (when using the pg driver)
|
14
14
|
* sqlite
|
15
15
|
* tinytds
|
16
16
|
|
@@ -29,7 +29,7 @@ significantly for placeholders (e.g. :name, $1, ?). Sequel abstracts all of
|
|
29
29
|
that and allows you to specify placeholders by using the :$name format for
|
30
30
|
placeholders, e.g.:
|
31
31
|
|
32
|
-
ds = DB[:items].
|
32
|
+
ds = DB[:items].where(:name=>:$n)
|
33
33
|
|
34
34
|
== Bound Variables
|
35
35
|
|
data/doc/querying.rdoc
CHANGED
@@ -10,7 +10,9 @@ aims to be a gentle introduction to Sequel's querying support.
|
|
10
10
|
|
11
11
|
While you can easily use raw SQL with Sequel, a large part of the
|
12
12
|
advantage you get from using Sequel is Sequel's ability to abstract
|
13
|
-
SQL from you and give you a much nicer interface.
|
13
|
+
SQL from you and give you a much nicer interface. Sequel also ships with
|
14
|
+
a {core_extensions extension}[link:files/doc/core_extensions_rdoc.html],
|
15
|
+
which better integrates Sequel's DSL into the ruby language.
|
14
16
|
|
15
17
|
== Retrieving Objects
|
16
18
|
|
@@ -57,7 +59,7 @@ Any options you pass to +first+ will be used as a filter:
|
|
57
59
|
# SELECT * FROM artists WHERE (name = 'YJM') LIMIT 1
|
58
60
|
=> #<Artist @values={:name=>"YJM", :id=>1}>
|
59
61
|
|
60
|
-
artist = Artist.first(
|
62
|
+
artist = Artist.first(Sequel.like(:name, 'Y%'))
|
61
63
|
# SELECT * FROM artists WHERE (name LIKE 'Y%') LIMIT 1
|
62
64
|
=> #<Artist @values={:name=>"YJM", :id=>1}>
|
63
65
|
|
@@ -69,12 +71,12 @@ requires an argument:
|
|
69
71
|
=> {:name=>"YJM", :id=>1}
|
70
72
|
|
71
73
|
Note that while Model.[] allows you to pass a primary key directly,
|
72
|
-
Dataset#[] does not.
|
74
|
+
Dataset#[] does not (unless it is a model dataset).
|
73
75
|
|
74
76
|
==== Using +last+
|
75
77
|
|
76
78
|
If you want the last record in the dataset,
|
77
|
-
<tt>Sequel::Dataset#last</tt> is an obvious method to use. Note
|
79
|
+
<tt>Sequel::Dataset#last</tt> is an obvious method to use. Note
|
78
80
|
that last requires that the dataset be ordered. Without an order, any
|
79
81
|
object can be considered the first as well as the last.
|
80
82
|
|
@@ -162,6 +164,13 @@ It's also common to want to order such a map, so Sequel provides a
|
|
162
164
|
# SELECT name FROM artists ORDER BY name
|
163
165
|
=> ["AS", "YJM"]
|
164
166
|
|
167
|
+
In all of these cases, you can provide an array of column symbols and
|
168
|
+
an array of arrays of values will be returned:
|
169
|
+
|
170
|
+
artist_names = Artist.select_map([:id, :name])
|
171
|
+
# SELECT id, name FROM artists
|
172
|
+
=> [[1, "YJM"], [2, "AS"]]
|
173
|
+
|
165
174
|
==== As a Hash
|
166
175
|
|
167
176
|
Sequel makes it easy to take an SQL query and return it as a ruby hash,
|
@@ -256,7 +265,7 @@ table +artists+:
|
|
256
265
|
Let's say we are only interested in the artists whose names
|
257
266
|
start with "A":
|
258
267
|
|
259
|
-
ds2 = ds1.where(
|
268
|
+
ds2 = ds1.where(Sequel.like(:name, 'A%'))
|
260
269
|
# SELECT * FROM artists WHERE name LIKE 'A%'
|
261
270
|
|
262
271
|
Here we see that +where+ returns a dataset that adds a +WHERE+
|
@@ -306,47 +315,47 @@ of condition is used depends on the values in the hash.
|
|
306
315
|
Unless Sequel has special support for the value's class, it uses a simple
|
307
316
|
equality statement:
|
308
317
|
|
309
|
-
Artist.
|
318
|
+
Artist.where(:id=>1)
|
310
319
|
# SELECT * FROM artists WHERE id = 1
|
311
320
|
|
312
|
-
Artist.
|
321
|
+
Artist.where(:name=>'YJM')
|
313
322
|
# SELECT * FROM artists WHERE name = 'YJM'
|
314
323
|
|
315
324
|
For arrays, Sequel uses the IN operator.
|
316
325
|
|
317
|
-
Artist.
|
326
|
+
Artist.where(:id=>[1, 2])
|
318
327
|
# SELECT * FROM artists WHERE id IN (1, 2)
|
319
328
|
|
320
329
|
For datasets, Sequel uses the IN operator with a subselect:
|
321
330
|
|
322
|
-
Artist.
|
331
|
+
Artist.where(:id=>Album.select(:artist_id))
|
323
332
|
# SELECT * FROM artists WHERE id IN (
|
324
333
|
# SELECT artist_id FROM albums)
|
325
334
|
|
326
335
|
For boolean values such as nil, true, and false, Sequel uses the IS operator:
|
327
336
|
|
328
|
-
Artist.
|
337
|
+
Artist.where(:id=>nil)
|
329
338
|
# SELECT * FROM artists WHERE id IS NULL
|
330
339
|
|
331
340
|
For ranges, Sequel uses a pair of inequality statements:
|
332
341
|
|
333
|
-
Artist.
|
342
|
+
Artist.where(:id=>1..5)
|
334
343
|
# SELECT * FROM artists WHERE id >= 1 AND id <= 5
|
335
344
|
|
336
345
|
Finally, for regexps, Sequel uses an SQL regular expression. Note that this
|
337
346
|
is probably only supported on PostgreSQL and MySQL.
|
338
347
|
|
339
|
-
Artist.
|
348
|
+
Artist.where(:name=>/JM$/)
|
340
349
|
# SELECT * FROM artists WHERE name ~ 'JM$'
|
341
350
|
|
342
351
|
If there are multiple arguments in the hash, the filters are ANDed together:
|
343
352
|
|
344
|
-
Artist.
|
353
|
+
Artist.where(:id=>1, :name=>/JM$/)
|
345
354
|
# SELECT * FROM artists WHERE id = 1 AND name ~ 'JM$'
|
346
355
|
|
347
|
-
This works the same as if you used two separate
|
356
|
+
This works the same as if you used two separate +where+ calls:
|
348
357
|
|
349
|
-
Artist.
|
358
|
+
Artist.where(:id=>1).where(:name=>/JM$/)
|
350
359
|
# SELECT * FROM artists WHERE id = 1 AND name ~ 'JM$'
|
351
360
|
|
352
361
|
=== Array of Two Element Arrays
|
@@ -355,14 +364,14 @@ If you use an array of two element arrays, it is treated as a hash. The only
|
|
355
364
|
advantage to using an array of two element arrays is that it allows you to
|
356
365
|
duplicate keys, so you can do:
|
357
366
|
|
358
|
-
Artist.
|
367
|
+
Artist.where([[:name, /JM$/], [:name, /^YJ/]])
|
359
368
|
# SELECT * FROM artists WHERE name ~ 'JM$' AND name ~ '^YJ'
|
360
369
|
|
361
370
|
=== Virtual Row Blocks
|
362
371
|
|
363
|
-
If a block is passed to filter, it is treated as a virtual row block:
|
372
|
+
If a block is passed to a filter, it is treated as a virtual row block:
|
364
373
|
|
365
|
-
Artist.
|
374
|
+
Artist.where{id > 5}
|
366
375
|
# SELECT * FROM artists WHERE id > 5
|
367
376
|
|
368
377
|
You can learn more about virtual row blocks in the {"Virtual Rows" guide}[link:files/doc/virtual_rows_rdoc.html].
|
@@ -370,7 +379,7 @@ You can learn more about virtual row blocks in the {"Virtual Rows" guide}[link:f
|
|
370
379
|
You can provide both regular arguments and a block, in which case the results
|
371
380
|
will be ANDed together:
|
372
381
|
|
373
|
-
Artist.
|
382
|
+
Artist.where(:name=>'A'...'M'){id > 5}
|
374
383
|
# SELECT * FROM artists WHERE name >= 'A' AND name < 'M' AND id > 5
|
375
384
|
|
376
385
|
=== Symbols
|
@@ -387,28 +396,30 @@ Sequel has a DSL that allows easily creating SQL expressions. These SQL
|
|
387
396
|
expressions are instances of subclasses of Sequel::SQL::Expression. You've
|
388
397
|
already seen an example earlier:
|
389
398
|
|
390
|
-
Artist.
|
399
|
+
Artist.where(Sequel.like(:name, 'Y%'))
|
391
400
|
# SELECT * FROM artists WHERE name LIKE 'Y%'
|
392
401
|
|
393
|
-
In this case
|
402
|
+
In this case Sequel.like returns a Sequel::SQL::BooleanExpression object,
|
394
403
|
which is used directly in the filter.
|
395
404
|
|
396
405
|
You can use the DSL to create arbitrarily complex expressions. SQL::Expression
|
397
|
-
objects
|
398
|
-
|
406
|
+
objects can be created via singleton methods on the Sequel module. The most common
|
407
|
+
method is Sequel.expr, which takes any object and wraps it in a SQL::Expression
|
408
|
+
object. In most cases, the SQL::Expression returned supports the & operator for
|
409
|
+
+AND+, the | operator for +OR+, and the ~ operator for inversion:
|
399
410
|
|
400
|
-
Artist.
|
411
|
+
Artist.where(Sequel.like(:name, 'Y%') & (Sequel.expr(:b=>1) | Sequel.~(:c=>3)))
|
401
412
|
# SELECT * FROM artists WHERE name LIKE 'Y%' AND (b = 1 OR c != 3)
|
402
413
|
|
403
414
|
You can combine these expression operators with the virtual row support:
|
404
415
|
|
405
|
-
Artist.
|
416
|
+
Artist.where{(a > 1) & ~((b(c) < 1) | d)}
|
406
417
|
# SELECT * FROM artists WHERE a > 1 AND b(c) >= 1 AND NOT d
|
407
418
|
|
408
419
|
Note the use of parentheses when using the & and | operators, as they have lower
|
409
420
|
precedence than other operators. The following will not work:
|
410
421
|
|
411
|
-
Artist.
|
422
|
+
Artist.where{a > 1 & ~(b(c) < 1 | d)}
|
412
423
|
# Raises a TypeError, as it calls Integer#| with a Sequel::SQL::Identifier
|
413
424
|
|
414
425
|
=== Strings with Placeholders
|
@@ -416,24 +427,24 @@ precedence than other operators. The following will not work:
|
|
416
427
|
Assuming you want to get your hands dirty and write some SQL, Sequel allows you
|
417
428
|
to use strings using placeholders for the values:
|
418
429
|
|
419
|
-
Artist.
|
430
|
+
Artist.where("name LIKE ?", 'Y%')
|
420
431
|
# SELECT * FROM artists WHERE name LIKE 'Y%'
|
421
432
|
|
422
433
|
This is the most common type of placeholder, where each question mark is substituted
|
423
434
|
with the next argument:
|
424
435
|
|
425
|
-
Artist.
|
436
|
+
Artist.where("name LIKE ? AND id = ?", 'Y%', 5)
|
426
437
|
# SELECT * FROM artists WHERE name LIKE 'Y%' AND id = 5
|
427
438
|
|
428
439
|
You can also use named placeholders with a hash, where the named placeholders use
|
429
440
|
colons before the placeholder names:
|
430
441
|
|
431
|
-
Artist.
|
442
|
+
Artist.where("name LIKE :name AND id = :id", :name=>'Y%', :id=>5)
|
432
443
|
# SELECT * FROM artists WHERE name LIKE 'Y%' AND id = 5
|
433
444
|
|
434
445
|
You don't have to provide any placeholders if you don't want to:
|
435
446
|
|
436
|
-
Artist.
|
447
|
+
Artist.where("id = 2")
|
437
448
|
# SELECT * FROM artists WHERE id = 2
|
438
449
|
|
439
450
|
However, if you are using any untrusted input, you should definitely be using placeholders.
|
@@ -441,9 +452,9 @@ In general, unless you are hardcoding values in the strings, you should use plac
|
|
441
452
|
You should never pass a string that has been built using interpolation, unless you are
|
442
453
|
sure of what you are doing.
|
443
454
|
|
444
|
-
Artist.
|
445
|
-
Artist.
|
446
|
-
Artist.
|
455
|
+
Artist.where("id = #{params[:id]}") # Don't do this!
|
456
|
+
Artist.where("id = ?", params[:id]) # Do this instead
|
457
|
+
Artist.where(:id=>params[:id]) # Even better
|
447
458
|
|
448
459
|
=== Inverting
|
449
460
|
|
@@ -451,12 +462,12 @@ You may be wondering how to specify a not equals condition in Sequel, or the NOT
|
|
451
462
|
operator. Sequel has generic support for inverting conditions, so to write a not
|
452
463
|
equals condition, you write an equals condition, and invert it:
|
453
464
|
|
454
|
-
Artist.
|
465
|
+
Artist.where(:id=>5).invert
|
455
466
|
# SELECT * FROM artists WHERE id != 5
|
456
467
|
|
457
468
|
Note that +invert+ inverts the entire filter:
|
458
469
|
|
459
|
-
Artist.
|
470
|
+
Artist.where(:id=>5).where{name > 'A'}.invert
|
460
471
|
# SELECT * FROM artists WHERE id != 5 OR name <= 'A'
|
461
472
|
|
462
473
|
In general, +invert+ is used rarely, since +exclude+ allows you to invert only specific
|
@@ -465,7 +476,7 @@ filters:
|
|
465
476
|
Artist.exclude(:id=>5)
|
466
477
|
# SELECT * FROM artists WHERE id != 5
|
467
478
|
|
468
|
-
Artist.
|
479
|
+
Artist.where(:id=>5).exclude{name > 'A'}
|
469
480
|
# SELECT * FROM artists WHERE id = 5 OR name <= 'A'
|
470
481
|
|
471
482
|
So to do a NOT IN with an array:
|
@@ -475,14 +486,14 @@ So to do a NOT IN with an array:
|
|
475
486
|
|
476
487
|
Or to use the NOT LIKE operator:
|
477
488
|
|
478
|
-
Artist.exclude(
|
489
|
+
Artist.exclude(Sequel.like(:name, '%J%'))
|
479
490
|
# SELECT * FROM artists WHERE name NOT LIKE '%J%'
|
480
491
|
|
481
492
|
=== Removing
|
482
493
|
|
483
494
|
To remove all existing filters, use +unfiltered+:
|
484
495
|
|
485
|
-
Artist.
|
496
|
+
Artist.where(:id=>1).unfiltered
|
486
497
|
# SELECT * FROM artists
|
487
498
|
|
488
499
|
== Ordering
|
@@ -498,7 +509,7 @@ You can specify multiple arguments to order by more than one column:
|
|
498
509
|
Album.order(:artist_id, :id)
|
499
510
|
# SELECT * FROM album ORDER BY artist_id, id
|
500
511
|
|
501
|
-
Note that unlike +
|
512
|
+
Note that unlike +where+, +order+ replaces an existing order, it does not
|
502
513
|
append to an existing order:
|
503
514
|
|
504
515
|
Artist.order(:id).order(:name)
|
@@ -523,15 +534,15 @@ order, using +reverse+:
|
|
523
534
|
# SELECT FROM artists ORDER BY id DESC
|
524
535
|
|
525
536
|
As you might expect, +reverse+ is not used all that much. In general,
|
526
|
-
<tt>
|
537
|
+
<tt>Sequel.desc</tt> is used more commonly to specify a descending order
|
527
538
|
for columns:
|
528
539
|
|
529
|
-
Artist.order(:id
|
540
|
+
Artist.order(Sequel.desc(:id))
|
530
541
|
# SELECT FROM artists ORDER BY id DESC
|
531
542
|
|
532
543
|
This allows you to easily use both ascending and descending orders:
|
533
544
|
|
534
|
-
Artist.order(:name, :id
|
545
|
+
Artist.order(:name, Sequel.desc(:id))
|
535
546
|
# SELECT FROM artists ORDER BY name, id DESC
|
536
547
|
|
537
548
|
=== Removing
|
@@ -583,6 +594,12 @@ columns, use +select_all+:
|
|
583
594
|
Artist.select(:id).select_all
|
584
595
|
# SELECT * FROM artists
|
585
596
|
|
597
|
+
To select all columns from a given table, provide an argument to
|
598
|
+
+select_all+:
|
599
|
+
|
600
|
+
Artist.select_all(:artists)
|
601
|
+
# SELECT artists.* FROM artists
|
602
|
+
|
586
603
|
=== Distinct
|
587
604
|
|
588
605
|
To treat duplicate rows as a single row when retrieving the records,
|
@@ -637,6 +654,17 @@ and Sequel provides a +group_and_count+ method to make this easier:
|
|
637
654
|
|
638
655
|
This will return the number of albums for each artist_id.
|
639
656
|
|
657
|
+
If you want to select and group on the same columns, you can use +select_group+:
|
658
|
+
|
659
|
+
Album.select_group(:artist_id)
|
660
|
+
# SELECT artist_id FROM albums GROUP BY artist_id
|
661
|
+
|
662
|
+
Usually you would add a +select_append+ call after that, to add some sort of
|
663
|
+
aggregation:
|
664
|
+
|
665
|
+
Album.select_group(:artist_id).select_append{sum(num_tracks).as(tracks)}
|
666
|
+
# SELECT artist_id, sum(num_tracks) AS tracks FROM albums GROUP BY artist_id
|
667
|
+
|
640
668
|
== Having
|
641
669
|
|
642
670
|
The SQL HAVING clause is similar to the WHERE clause, except that
|
@@ -656,12 +684,9 @@ will add to the HAVING clause instead of the WHERE clause:
|
|
656
684
|
# SELECT artist_id, COUNT(*) AS count FROM albums
|
657
685
|
# GROUP BY artist_id HAVING count >= 10 AND count < 15
|
658
686
|
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
having{count >= 10}.where(:name.like('A%'))
|
663
|
-
# SELECT artist_id, COUNT(*) AS count FROM albums
|
664
|
-
# WHERE name LIKE 'A%' GROUP BY artist_id HAVING count >= 10
|
687
|
+
This can be confusing, so it is recommended that you always use
|
688
|
+
either +having+ or +where+ instead of +filter+, indicating which
|
689
|
+
clause that would want affected.
|
665
690
|
|
666
691
|
Both the WHERE clause and the HAVING clause are removed by +unfiltered+:
|
667
692
|
|
@@ -702,7 +727,7 @@ can also provide a model class:
|
|
702
727
|
|
703
728
|
Or a dataset, in which case a subselect is used:
|
704
729
|
|
705
|
-
Album.join(Artist.
|
730
|
+
Album.join(Artist.where{name < 'A'}, :id=>:artist_id)
|
706
731
|
# SELECT * FROM albums
|
707
732
|
# INNER JOIN (SELECT * FROM artists WHERE (name < 'A')) AS t1
|
708
733
|
# ON (t1.id = albums.artist_id)
|
@@ -770,6 +795,19 @@ as a hash, but allows for duplicate keys:
|
|
770
795
|
And just like in the hash case, unqualified symbol elements in the
|
771
796
|
array are implicitly qualified.
|
772
797
|
|
798
|
+
By default, Sequel only qualifies unqualified symbols in the conditions. However,
|
799
|
+
You can provide an options hash with a <tt>:qualify=>:deep</tt> option to do a deep
|
800
|
+
qualification, which can qualify subexpressions. For example, let's say you are doing
|
801
|
+
a JOIN using case insensitive string comparison:
|
802
|
+
|
803
|
+
Album.join(:artists, {Sequel.function(:lower, :name) =>
|
804
|
+
Sequel.function(:lower, :artist_name)},
|
805
|
+
:qualify => :deep)
|
806
|
+
# SELECT * FROM albums INNER JOIN artists
|
807
|
+
# ON (lower(artists.name) = lower(albums.artist_name))
|
808
|
+
|
809
|
+
Note how the arguments to lower were qualified correctly in both cases.
|
810
|
+
|
773
811
|
==== USING Joins
|
774
812
|
|
775
813
|
The most common type of join conditions is a JOIN ON, as displayed
|
@@ -812,7 +850,7 @@ and artists tables, but only want albums where the artist's name
|
|
812
850
|
comes before the album's name.
|
813
851
|
|
814
852
|
Album.join(:artists, :id=>:artist_id) do |j, lj, js|
|
815
|
-
|
853
|
+
Sequel.qualify(j, :name) < Sequel.qualify(lj, :name)
|
816
854
|
end
|
817
855
|
# SELECT * FROM albums INNER JOIN artists
|
818
856
|
# ON artists.id = albums.artist_id
|
@@ -912,6 +950,25 @@ With either of these methods, you can use placeholders:
|
|
912
950
|
DB[:albums].with_sql("SELECT * FROM artists WHERE id = :id", :id=>5)
|
913
951
|
# SELECT * FROM artists WHERE id = 5
|
914
952
|
|
953
|
+
Note that if you specify the dataset using custom SQL, you can still call the dataset
|
954
|
+
modification methods, but in many cases they will appear to have no affect:
|
955
|
+
|
956
|
+
DB["SELECT * FROM artists"].select(:name).order(:id)
|
957
|
+
# SELECT * FROM artists
|
958
|
+
|
959
|
+
If you must drop down to using custom SQL, it's recommended that you only do so for
|
960
|
+
specific parts of a query. For example, if the reason you are using custom SQL is
|
961
|
+
to use a custom operator in the database in the SELECT clause:
|
962
|
+
|
963
|
+
DB["SELECT name, (foo !@# ?) AS baz FROM artists", 'bar']
|
964
|
+
|
965
|
+
it's better to use Sequel's DSL, and use a literal string for the custom operator:
|
966
|
+
|
967
|
+
DB[:artists].select(:name, Sequel.lit("(foo !@# ?)", 'bar').as(:baz))
|
968
|
+
|
969
|
+
That way Sequel's method chaining still works, and it increases Sequel's ability to
|
970
|
+
introspect the code.
|
971
|
+
|
915
972
|
== Checking for Records
|
916
973
|
|
917
974
|
If you just want to know whether the current dataset would return any rows, use <tt>empty?</tt>:
|
@@ -920,11 +977,11 @@ If you just want to know whether the current dataset would return any rows, use
|
|
920
977
|
# SELECT 1 FROM albums LIMIT 1
|
921
978
|
=> false
|
922
979
|
|
923
|
-
Album.
|
980
|
+
Album.where(:id=>0).empty?
|
924
981
|
# SELECT 1 FROM albums WHERE id = 0 LIMIT 1
|
925
982
|
=> true
|
926
983
|
|
927
|
-
Album.
|
984
|
+
Album.where(Sequel.like(:name, 'R%')).empty?
|
928
985
|
# SELECT 1 FROM albums WHERE name LIKE 'R%' LIMIT 1
|
929
986
|
=> false
|
930
987
|
|