sequel 3.37.0 → 3.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/CHANGELOG +56 -0
  2. data/README.rdoc +82 -58
  3. data/Rakefile +6 -5
  4. data/bin/sequel +1 -1
  5. data/doc/active_record.rdoc +67 -52
  6. data/doc/advanced_associations.rdoc +33 -48
  7. data/doc/association_basics.rdoc +41 -51
  8. data/doc/cheat_sheet.rdoc +21 -21
  9. data/doc/core_extensions.rdoc +374 -0
  10. data/doc/dataset_basics.rdoc +5 -5
  11. data/doc/dataset_filtering.rdoc +47 -43
  12. data/doc/mass_assignment.rdoc +1 -1
  13. data/doc/migration.rdoc +4 -5
  14. data/doc/model_hooks.rdoc +3 -3
  15. data/doc/object_model.rdoc +31 -25
  16. data/doc/opening_databases.rdoc +19 -5
  17. data/doc/prepared_statements.rdoc +2 -2
  18. data/doc/querying.rdoc +109 -52
  19. data/doc/reflection.rdoc +6 -6
  20. data/doc/release_notes/3.38.0.txt +234 -0
  21. data/doc/schema_modification.rdoc +22 -13
  22. data/doc/sharding.rdoc +8 -9
  23. data/doc/sql.rdoc +154 -112
  24. data/doc/testing.rdoc +47 -7
  25. data/doc/thread_safety.rdoc +1 -1
  26. data/doc/transactions.rdoc +1 -1
  27. data/doc/validations.rdoc +1 -1
  28. data/doc/virtual_rows.rdoc +29 -43
  29. data/lib/sequel/adapters/do/postgres.rb +1 -4
  30. data/lib/sequel/adapters/jdbc.rb +14 -3
  31. data/lib/sequel/adapters/jdbc/db2.rb +9 -0
  32. data/lib/sequel/adapters/jdbc/derby.rb +41 -4
  33. data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
  34. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
  35. data/lib/sequel/adapters/mock.rb +10 -4
  36. data/lib/sequel/adapters/postgres.rb +1 -28
  37. data/lib/sequel/adapters/shared/mssql.rb +23 -13
  38. data/lib/sequel/adapters/shared/postgres.rb +46 -0
  39. data/lib/sequel/adapters/swift.rb +21 -13
  40. data/lib/sequel/adapters/swift/mysql.rb +1 -0
  41. data/lib/sequel/adapters/swift/postgres.rb +4 -5
  42. data/lib/sequel/adapters/swift/sqlite.rb +2 -1
  43. data/lib/sequel/adapters/tinytds.rb +14 -2
  44. data/lib/sequel/adapters/utils/pg_types.rb +5 -0
  45. data/lib/sequel/core.rb +29 -17
  46. data/lib/sequel/database/query.rb +1 -1
  47. data/lib/sequel/database/schema_generator.rb +3 -0
  48. data/lib/sequel/dataset/actions.rb +5 -6
  49. data/lib/sequel/dataset/query.rb +7 -7
  50. data/lib/sequel/dataset/sql.rb +5 -18
  51. data/lib/sequel/extensions/core_extensions.rb +8 -12
  52. data/lib/sequel/extensions/pg_array.rb +59 -33
  53. data/lib/sequel/extensions/pg_array_ops.rb +32 -4
  54. data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
  55. data/lib/sequel/extensions/pg_hstore.rb +32 -17
  56. data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
  57. data/lib/sequel/extensions/pg_inet.rb +1 -2
  58. data/lib/sequel/extensions/pg_interval.rb +0 -1
  59. data/lib/sequel/extensions/pg_json.rb +41 -23
  60. data/lib/sequel/extensions/pg_range.rb +36 -11
  61. data/lib/sequel/extensions/pg_range_ops.rb +32 -4
  62. data/lib/sequel/extensions/pg_row.rb +572 -0
  63. data/lib/sequel/extensions/pg_row_ops.rb +164 -0
  64. data/lib/sequel/extensions/query.rb +3 -3
  65. data/lib/sequel/extensions/schema_dumper.rb +7 -8
  66. data/lib/sequel/extensions/select_remove.rb +1 -1
  67. data/lib/sequel/model/base.rb +1 -0
  68. data/lib/sequel/no_core_ext.rb +1 -1
  69. data/lib/sequel/plugins/pg_row.rb +121 -0
  70. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  71. data/lib/sequel/plugins/validation_helpers.rb +31 -0
  72. data/lib/sequel/sql.rb +64 -44
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/mssql_spec.rb +37 -12
  75. data/spec/adapters/mysql_spec.rb +39 -75
  76. data/spec/adapters/oracle_spec.rb +11 -11
  77. data/spec/adapters/postgres_spec.rb +414 -237
  78. data/spec/adapters/spec_helper.rb +1 -1
  79. data/spec/adapters/sqlite_spec.rb +14 -14
  80. data/spec/core/database_spec.rb +6 -6
  81. data/spec/core/dataset_spec.rb +169 -205
  82. data/spec/core/expression_filters_spec.rb +182 -295
  83. data/spec/core/object_graph_spec.rb +6 -6
  84. data/spec/core/schema_spec.rb +14 -14
  85. data/spec/core/spec_helper.rb +1 -0
  86. data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
  87. data/spec/extensions/columns_introspection_spec.rb +5 -5
  88. data/spec/extensions/hook_class_methods_spec.rb +28 -36
  89. data/spec/extensions/many_through_many_spec.rb +4 -4
  90. data/spec/extensions/pg_array_ops_spec.rb +15 -7
  91. data/spec/extensions/pg_array_spec.rb +81 -48
  92. data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
  93. data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
  94. data/spec/extensions/pg_hstore_spec.rb +66 -65
  95. data/spec/extensions/pg_inet_spec.rb +2 -4
  96. data/spec/extensions/pg_interval_spec.rb +2 -3
  97. data/spec/extensions/pg_json_spec.rb +20 -18
  98. data/spec/extensions/pg_range_ops_spec.rb +11 -4
  99. data/spec/extensions/pg_range_spec.rb +30 -7
  100. data/spec/extensions/pg_row_ops_spec.rb +48 -0
  101. data/spec/extensions/pg_row_plugin_spec.rb +45 -0
  102. data/spec/extensions/pg_row_spec.rb +323 -0
  103. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  104. data/spec/extensions/query_literals_spec.rb +11 -11
  105. data/spec/extensions/query_spec.rb +3 -3
  106. data/spec/extensions/schema_dumper_spec.rb +20 -4
  107. data/spec/extensions/schema_spec.rb +18 -41
  108. data/spec/extensions/select_remove_spec.rb +4 -4
  109. data/spec/extensions/spec_helper.rb +4 -8
  110. data/spec/extensions/to_dot_spec.rb +5 -5
  111. data/spec/extensions/validation_class_methods_spec.rb +28 -16
  112. data/spec/integration/associations_test.rb +20 -20
  113. data/spec/integration/dataset_test.rb +98 -98
  114. data/spec/integration/eager_loader_test.rb +13 -27
  115. data/spec/integration/plugin_test.rb +5 -5
  116. data/spec/integration/prepared_statement_test.rb +22 -13
  117. data/spec/integration/schema_test.rb +28 -18
  118. data/spec/integration/spec_helper.rb +1 -1
  119. data/spec/integration/timezone_test.rb +2 -2
  120. data/spec/integration/type_test.rb +15 -6
  121. data/spec/model/association_reflection_spec.rb +1 -1
  122. data/spec/model/associations_spec.rb +4 -4
  123. data/spec/model/base_spec.rb +5 -5
  124. data/spec/model/eager_loading_spec.rb +15 -15
  125. data/spec/model/model_spec.rb +32 -32
  126. data/spec/model/record_spec.rb +16 -0
  127. data/spec/model/spec_helper.rb +2 -6
  128. data/spec/model/validations_spec.rb +1 -1
  129. metadata +16 -4
@@ -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, dbi, jdbc, odbc, and swift adapters.
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. All except Oracle, MSSQL, AS400, and DB2 can load the
237
- jdbc-* gem, for those you need to have the .jar in your CLASSPATH
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, may require type specifiers)
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].filter(:name=>:$n)
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(:name.like('Y%'))
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 first
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(:name.like('A%'))
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.filter(:id=>1)
318
+ Artist.where(:id=>1)
310
319
  # SELECT * FROM artists WHERE id = 1
311
320
 
312
- Artist.filter(:name=>'YJM')
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.filter(:id=>[1, 2])
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.filter(:id=>Album.select(:artist_id))
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.filter(:id=>nil)
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.filter(:id=>1..5)
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.filter(:name=>/JM$/)
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.filter(:id=>1, :name=>/JM$/)
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 filter calls:
356
+ This works the same as if you used two separate +where+ calls:
348
357
 
349
- Artist.filter(:id=>1).filter(:name=>/JM$/)
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.filter([[:name, /JM$/], [:name, /^YJ/]])
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.filter{id > 5}
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.filter(:name=>'A'...'M'){id > 5}
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.filter(:name.like('Y%'))
399
+ Artist.where(Sequel.like(:name, 'Y%'))
391
400
  # SELECT * FROM artists WHERE name LIKE 'Y%'
392
401
 
393
- In this case Symbol#like returns a Sequel::SQL::BooleanExpression object,
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 support the & operator for +AND+, the | operator for +OR+, and the ~ operator
398
- for inversion:
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.filter(:name.like('Y%') & ({:b=>1} | ~{:c=>3}))
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.filter{(a > 1) & ~((b(c) < 1) | d)}
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.filter{a > 1 & ~(b(c) < 1 | d)}
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.filter("name LIKE ?", 'Y%')
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.filter("name LIKE ? AND id = ?", 'Y%', 5)
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.filter("name LIKE :name AND id = :id", :name=>'Y%', :id=>5)
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.filter("id = 2")
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.filter("id = #{params[:id]}") # Don't do this!
445
- Artist.filter("id = ?", params[:id]) # Do this instead
446
- Artist.filter(:id=>params[:id]) # Even better
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.filter(:id=>5).invert
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.filter(:id=>5).filter{name > 'A'}.invert
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.filter(:id=>5).exclude{name > 'A'}
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(:name.like('%J%'))
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.filter(:id=>1).unfiltered
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 +filter+, +order+ replaces an existing order, it does not
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>Symbol#desc</tt> is used more commonly to specify a descending order
537
+ <tt>Sequel.desc</tt> is used more commonly to specify a descending order
527
538
  for columns:
528
539
 
529
- Artist.order(:id.desc)
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.desc)
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
- Unlike +filter+, +where+ always affects the WHERE clause:
660
-
661
- Album.group_and_count(:artist_id).
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.filter{name < 'A'}, :id=>:artist_id)
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
- :name.qualify(j) < :name.qualify(lj)
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.filter(:id=>0).empty?
980
+ Album.where(:id=>0).empty?
924
981
  # SELECT 1 FROM albums WHERE id = 0 LIMIT 1
925
982
  => true
926
983
 
927
- Album.filter(:name.like('R%')).empty?
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