sequel 3.37.0 → 3.38.0
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/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
|
|