sequel 3.10.0 → 3.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/CHANGELOG +68 -0
  2. data/COPYING +1 -1
  3. data/README.rdoc +87 -27
  4. data/bin/sequel +2 -4
  5. data/doc/association_basics.rdoc +1383 -0
  6. data/doc/dataset_basics.rdoc +106 -0
  7. data/doc/opening_databases.rdoc +45 -16
  8. data/doc/querying.rdoc +210 -0
  9. data/doc/release_notes/3.11.0.txt +254 -0
  10. data/doc/virtual_rows.rdoc +217 -31
  11. data/lib/sequel/adapters/ado.rb +28 -12
  12. data/lib/sequel/adapters/ado/mssql.rb +33 -1
  13. data/lib/sequel/adapters/amalgalite.rb +13 -8
  14. data/lib/sequel/adapters/db2.rb +1 -2
  15. data/lib/sequel/adapters/dbi.rb +7 -4
  16. data/lib/sequel/adapters/do.rb +14 -15
  17. data/lib/sequel/adapters/do/postgres.rb +4 -5
  18. data/lib/sequel/adapters/do/sqlite.rb +9 -0
  19. data/lib/sequel/adapters/firebird.rb +5 -10
  20. data/lib/sequel/adapters/informix.rb +2 -4
  21. data/lib/sequel/adapters/jdbc.rb +111 -49
  22. data/lib/sequel/adapters/jdbc/mssql.rb +1 -2
  23. data/lib/sequel/adapters/jdbc/mysql.rb +11 -0
  24. data/lib/sequel/adapters/jdbc/oracle.rb +4 -7
  25. data/lib/sequel/adapters/jdbc/postgresql.rb +8 -1
  26. data/lib/sequel/adapters/jdbc/sqlite.rb +12 -0
  27. data/lib/sequel/adapters/mysql.rb +14 -5
  28. data/lib/sequel/adapters/odbc.rb +2 -4
  29. data/lib/sequel/adapters/odbc/mssql.rb +2 -4
  30. data/lib/sequel/adapters/openbase.rb +1 -2
  31. data/lib/sequel/adapters/oracle.rb +4 -8
  32. data/lib/sequel/adapters/postgres.rb +4 -11
  33. data/lib/sequel/adapters/shared/mssql.rb +22 -9
  34. data/lib/sequel/adapters/shared/mysql.rb +33 -30
  35. data/lib/sequel/adapters/shared/oracle.rb +0 -5
  36. data/lib/sequel/adapters/shared/postgres.rb +13 -11
  37. data/lib/sequel/adapters/shared/sqlite.rb +56 -10
  38. data/lib/sequel/adapters/sqlite.rb +16 -9
  39. data/lib/sequel/connection_pool.rb +6 -1
  40. data/lib/sequel/connection_pool/single.rb +1 -0
  41. data/lib/sequel/core.rb +6 -1
  42. data/lib/sequel/database.rb +52 -23
  43. data/lib/sequel/database/schema_generator.rb +6 -0
  44. data/lib/sequel/database/schema_methods.rb +5 -5
  45. data/lib/sequel/database/schema_sql.rb +1 -1
  46. data/lib/sequel/dataset.rb +4 -190
  47. data/lib/sequel/dataset/actions.rb +323 -1
  48. data/lib/sequel/dataset/features.rb +18 -2
  49. data/lib/sequel/dataset/graph.rb +7 -0
  50. data/lib/sequel/dataset/misc.rb +119 -0
  51. data/lib/sequel/dataset/mutation.rb +64 -0
  52. data/lib/sequel/dataset/prepared_statements.rb +6 -0
  53. data/lib/sequel/dataset/query.rb +272 -6
  54. data/lib/sequel/dataset/sql.rb +186 -394
  55. data/lib/sequel/model.rb +4 -2
  56. data/lib/sequel/model/associations.rb +31 -14
  57. data/lib/sequel/model/base.rb +32 -13
  58. data/lib/sequel/model/exceptions.rb +8 -4
  59. data/lib/sequel/model/plugins.rb +3 -13
  60. data/lib/sequel/plugins/active_model.rb +26 -7
  61. data/lib/sequel/plugins/instance_filters.rb +98 -0
  62. data/lib/sequel/plugins/many_through_many.rb +1 -1
  63. data/lib/sequel/plugins/optimistic_locking.rb +25 -9
  64. data/lib/sequel/version.rb +1 -1
  65. data/spec/adapters/mssql_spec.rb +26 -0
  66. data/spec/adapters/mysql_spec.rb +33 -4
  67. data/spec/adapters/postgres_spec.rb +24 -1
  68. data/spec/adapters/spec_helper.rb +6 -0
  69. data/spec/adapters/sqlite_spec.rb +28 -0
  70. data/spec/core/connection_pool_spec.rb +17 -5
  71. data/spec/core/database_spec.rb +101 -1
  72. data/spec/core/dataset_spec.rb +42 -4
  73. data/spec/core/schema_spec.rb +13 -0
  74. data/spec/extensions/active_model_spec.rb +34 -11
  75. data/spec/extensions/caching_spec.rb +2 -0
  76. data/spec/extensions/instance_filters_spec.rb +55 -0
  77. data/spec/extensions/spec_helper.rb +2 -0
  78. data/spec/integration/dataset_test.rb +12 -1
  79. data/spec/integration/model_test.rb +12 -0
  80. data/spec/integration/plugin_test.rb +61 -1
  81. data/spec/integration/schema_test.rb +14 -3
  82. data/spec/model/base_spec.rb +27 -0
  83. data/spec/model/plugins_spec.rb +0 -22
  84. data/spec/model/record_spec.rb +32 -1
  85. data/spec/model/spec_helper.rb +2 -0
  86. metadata +14 -3
  87. data/lib/sequel/dataset/convenience.rb +0 -326
data/CHANGELOG CHANGED
@@ -1,3 +1,71 @@
1
+ === 3.11.0 (2010-05-03)
2
+
3
+ * Allow shared postgresql adapter to work with ruby 1.9 with the -Ku switch (golubev.pavel) (#298)
4
+
5
+ * Add support for connecting to MSSQL via JTDS in the JDBC adapter (jeremyevans)
6
+
7
+ * Support returning the number of rows updated/deleted on MSSQL when using the ADO adapter with an explicit :provider (jeremyevans)
8
+
9
+ * Support transactions in the ADO adapter if not using the default :provider (jeremyevans)
10
+
11
+ * Make Database#disconnect not raise an exception when using the unsharded single connection pool (jeremyevans)
12
+
13
+ * Attempt to handle JDBC connection problems in cases where driver auto loading doesn't work (e.g. Tomcat) (elskwid)
14
+
15
+ * Make native MySQL adapter's tinyint to boolean conversion only convert tinyint(1) columns and not larger tinyint columns (roland.swingler) (#294)
16
+
17
+ * Fix use of limit with distinct on Microsoft SQL Server (jeremyevans) (#297)
18
+
19
+ * Correctly swallow errors when using :ignore_index_errors in Database#create_table when using unsupported indexes (jeremyevans) (#295)
20
+
21
+ * Fix insert returning the autogenerated key when using the 5.1.12 MySQL JDBC driver (viking)
22
+
23
+ * Consider number/numeric/decimal columns with a 0 scale to be integer columns (e.g. numeric(10, 0)) (jeremyevans, QaDes)
24
+
25
+ * Fix Database#rename_table on Microsoft SQL Server (rohit.namjoshi) (#293)
26
+
27
+ * Add Dataset#provides_accurate_rows_matched?, for seeing if update and delete are likely to return correct numbers (jeremyevans)
28
+
29
+ * Add require_modification to Sequel::Model, for checking that model instance updating and deleting affects a single row (jeremyevans)
30
+
31
+ * Fix leak of ResultSets when getting metadata in the jdbc adapter (jrun)
32
+
33
+ * Make Dataset#filter and related methods just clone receiver if given an empty argument, such as {}, [], or '' (jeremyevans)
34
+
35
+ * Add instance_filters plugin, for adding arbitrary filters when updating/destroying the instance (jeremyevans)
36
+
37
+ * No longer create the #{plugin}_opts methods for plugins (jeremyevans)
38
+
39
+ * Support :auto_vacuum, :foreign_keys, :synchronous, and :temp_store Database options on SQLite, for thread-safe PRAGMA setting (jeremyevans)
40
+
41
+ * Add foreign_keys accessor to SQLite Database objects (enabled by default), which modifies the foreign_keys PRAGMA available in 3.6.19+ (jeremyevans)
42
+
43
+ * Add an Database#sqlite_version method when connecting to SQLite, used to determine feature support (jeremyevans)
44
+
45
+ * Fix rolling back transactions when connecting to Oracle via JDBC (jeremyevans)
46
+
47
+ * Fix syntax errors when connecting to MSSQL via the dbi adapter (jeremyevans) (#292)
48
+
49
+ * Add support for an :after_connect option when connection, called with each new connection made (jeremyevans)
50
+
51
+ * Add support for a :test option when connecting to be automatically test the connection (jeremyevans)
52
+
53
+ * Add Dataset#select_append, which always appends to the existing SELECTed columns (jeremyevans)
54
+
55
+ * Emulate DISTINCT ON on MySQL using GROUP BY (jeremyevans)
56
+
57
+ * Make MSSQL shared adapter emulate set_column_null alter table op better with types containing sizes (jeremyevans) (#291)
58
+
59
+ * Add :config_default_group and :config_local_infile options to the native MySQL adapter (jeremyevans)
60
+
61
+ * Add log_warn_duration attribute to Database, queries that take longer than it will be logged at warn level (jeremyevans)
62
+
63
+ * Switch Database logging to use log_yield instead of log_info, queries that raise errors are now logged at error level (jeremyevans)
64
+
65
+ * Update active_model plugin to work with the ActiveModel::Lint 3.0.0beta2 specs (jeremyevans)
66
+
67
+ * Support JNDI connection strings in the JDBC adapter (jrun)
68
+
1
69
  === 3.10.0 (2010-04-02)
2
70
 
3
71
  * Make one_to_one setter and *_to_many remove_all methods apply the association options (jeremyevans)
data/COPYING CHANGED
@@ -1,5 +1,5 @@
1
1
  Copyright (c) 2007-2008 Sharon Rosner
2
- Copyright (c) 2008-2009 Jeremy Evans
2
+ Copyright (c) 2008-2010 Jeremy Evans
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to
data/README.rdoc CHANGED
@@ -18,6 +18,7 @@ Sequel is a lightweight database access toolkit for Ruby.
18
18
  == Resources
19
19
 
20
20
  * {Website}[http://sequel.rubyforge.org]
21
+ * {Website}[http://sequel.heroku.com]
21
22
  * {Source code}[http://github.com/jeremyevans/sequel]
22
23
  * {Bug tracking}[http://code.google.com/p/ruby-sequel/issues/list]
23
24
  * {Google group}[http://groups.google.com/group/sequel-talk]
@@ -158,6 +159,7 @@ Datasets will only fetch records when you tell them to. They can be manipulated
158
159
  You can retrieve all records by using the all method:
159
160
 
160
161
  posts.all
162
+ # SELECT * FROM posts
161
163
 
162
164
  The all method returns an array of hashes, where each hash corresponds to a record.
163
165
 
@@ -173,53 +175,66 @@ Or perform more advanced stuff:
173
175
  You can also retrieve the first record in a dataset:
174
176
 
175
177
  posts.first
178
+ # SELECT * FROM posts LIMIT 1
176
179
 
177
180
  Or retrieve a single record with a specific value:
178
181
 
179
182
  posts[:id => 1]
183
+ # SELECT * FROM posts WHERE id = 1 LIMIT 1
180
184
 
181
185
  If the dataset is ordered, you can also ask for the last record:
182
186
 
183
187
  posts.order(:stamp).last
188
+ # SELECT * FROM posts ORDER BY stamp DESC LIMIT 1
184
189
 
185
190
  === Filtering Records
186
191
 
187
192
  An easy way to filter records is to provide a hash of values to match:
188
193
 
189
194
  my_posts = posts.filter(:category => 'ruby', :author => 'david')
195
+ # WHERE category = 'ruby' AND author = 'david'
190
196
 
191
197
  You can also specify ranges:
192
198
 
193
199
  my_posts = posts.filter(:stamp => (Date.today - 14)..(Date.today - 7))
200
+ # WHERE stamp >= '2010-06-30' AND stamp <= '2010-07-07'
194
201
 
195
202
  Or arrays of values:
196
203
 
197
204
  my_posts = posts.filter(:category => ['ruby', 'postgres', 'linux'])
205
+ # WHERE category IN ('ruby', 'postgres', 'linux')
198
206
 
199
207
  Sequel also accepts expressions:
200
208
 
201
209
  my_posts = posts.filter{|o| o.stamp > Date.today << 1}
210
+ # WHERE stamp > '2010-06-14'
202
211
 
203
212
  Some adapters will also let you specify Regexps:
204
213
 
205
214
  my_posts = posts.filter(:category => /ruby/i)
215
+ # WHERE category ~* 'ruby'
206
216
 
207
217
  You can also use an inverse filter:
208
218
 
209
219
  my_posts = posts.exclude(:category => /ruby/i)
220
+ # WHERE category !~* 'ruby'
210
221
 
211
222
  You can also specify a custom WHERE clause using a string:
212
223
 
213
224
  posts.filter('stamp IS NOT NULL')
225
+ # WHERE stamp IS NOT NULL
214
226
 
215
227
  You can use parameters in your string, as well:
216
228
 
229
+ author_name = 'JKR'
217
230
  posts.filter('(stamp < ?) AND (author != ?)', Date.today - 3, author_name)
231
+ # WHERE (stamp < '2010-07-11') AND (author != 'JKR')
218
232
  posts.filter{|o| (o.stamp < Date.today - 3) & ~{:author => author_name}} # same as above
219
233
 
220
234
  Datasets can also be used as subqueries:
221
235
 
222
236
  DB[:items].filter('price > ?', DB[:items].select{|o| o.avg(:price) + 100})
237
+ # WHERE price > (SELECT avg(price) + 100 FROM items)
223
238
 
224
239
  After filtering you can retrieve the matching records by using any of the retrieval methods:
225
240
 
@@ -230,77 +245,108 @@ See the doc/dataset_filtering.rdoc file for more details.
230
245
  === Summarizing Records
231
246
 
232
247
  Counting records is easy:
248
+
233
249
  posts.filter(:category => /ruby/i).count
250
+ # SELECT COUNT(*) FROM posts WHERE category ~* 'ruby'
234
251
 
235
252
  And you can also query maximum/minimum values:
253
+
236
254
  max = DB[:history].max(:value)
255
+ # SELECT max(value) FROM history
256
+
237
257
  min = DB[:history].min(:value)
258
+ # SELECT min(value) FROM history
238
259
 
239
260
  Or calculate a sum or average:
240
261
  sum = DB[:items].sum(:price)
262
+ # SELECT sum(price) FROM items
241
263
  avg = DB[:items].avg(:price)
264
+ # SELECT avg(price) FROM items
242
265
 
243
266
  === Ordering Records
244
267
 
245
268
  Ordering datasets is simple:
246
269
 
247
- posts.order(:stamp) # ORDER BY stamp
248
- posts.order(:stamp, :name) # ORDER BY stamp, name
270
+ posts.order(:stamp)
271
+ # ORDER BY stamp
272
+ posts.order(:stamp, :name)
273
+ # ORDER BY stamp, name
249
274
 
250
275
  Chaining order doesn't work the same as filter:
251
276
 
252
- posts.order(:stamp).order(:name) # ORDER BY name
277
+ posts.order(:stamp).order(:name)
278
+ # ORDER BY name
253
279
 
254
280
  The order_more method chains this way, though:
255
281
 
256
- posts.order(:stamp).order_more(:name) # ORDER BY stamp, name
282
+ posts.order(:stamp).order_more(:name)
283
+ # ORDER BY stamp, name
257
284
 
258
285
  You can also specify descending order:
259
286
 
260
- posts.order(:stamp.desc) # ORDER BY stamp DESC
287
+ posts.order(:stamp.desc)
288
+ # ORDER BY stamp DESC
261
289
 
262
290
  === Selecting Columns
263
291
 
264
292
  Selecting specific columns to be returned is also simple:
265
293
 
266
- posts.select(:stamp) # SELECT stamp FROM posts
267
- posts.select(:stamp, :name) # SELECT stamp, name FROM posts
294
+ posts.select(:stamp)
295
+ # SELECT stamp FROM posts
296
+ posts.select(:stamp, :name)
297
+ # SELECT stamp, name FROM posts
268
298
 
269
299
  Chaining select works like order, not filter:
270
300
 
271
- posts.select(:stamp).select(:name) # SELECT name FROM posts
301
+ posts.select(:stamp).select(:name)
302
+ # SELECT name FROM posts
272
303
 
273
304
  As you might expect, there is an order_more equivalent for select:
274
305
 
275
- posts.select(:stamp).select_more(:name) # SELECT stamp, name FROM posts
306
+ posts.select(:stamp).select_more(:name)
307
+ # SELECT stamp, name FROM posts
276
308
 
277
309
  === Deleting Records
278
310
 
279
311
  Deleting records from the table is done with delete:
280
312
 
281
313
  posts.filter('stamp < ?', Date.today - 3).delete
314
+ # DELETE FROM posts WHERE stamp < '2010-07-11'
282
315
 
283
316
  Be very careful when deleting, as delete affects all rows in the dataset.
284
- Filter first, delete second, unless you want to empty the table.
317
+ Filter first, delete second, unless you want to empty the table:
318
+
319
+ # DO THIS:
320
+ posts.filter('stamp < ?', Date.today - 7).delete
321
+ # NOT THIS:
322
+ posts.delete.filter('stamp < ?', Date.today - 7)
285
323
 
286
324
  === Inserting Records
287
325
 
288
326
  Inserting records into the table is done with insert:
289
327
 
290
328
  posts.insert(:category => 'ruby', :author => 'david')
329
+ # INSERT INTO posts (category, author) VALUES ('ruby', 'david')
291
330
 
292
331
  === Updating Records
293
332
 
294
333
  Updating records in the table is done with update:
295
334
 
296
335
  posts.filter('stamp < ?', Date.today - 7).update(:state => 'archived')
336
+ # UPDATE posts SET state = 'archived' WHERE stamp < '2010-07-07'
297
337
 
298
338
  You can reference table columns when choosing what values to set:
299
339
 
300
340
  posts.filter{|o| o.stamp < Date.today - 7}.update(:backup_number => :backup_number + 1)
341
+ # UPDATE posts SET backup_number = backup_number + 1 WHERE stamp < '2010-07-07'
301
342
 
302
343
  As with delete, this affects all rows in the dataset, so filter first,
303
- update second, unless you want to update all rows.
344
+ update second, unless you want to update all rows:
345
+
346
+ # DO THIS:
347
+ posts.filter('stamp < ?', Date.today - 7).update(:state => 'archived')
348
+ # NOT THIS:
349
+ posts.update(:state => 'archived').filter('stamp < ?', Date.today - 7)
304
350
 
305
351
  === Joining Tables
306
352
 
@@ -339,31 +385,38 @@ Using graph, you can split the result hashes into subhashes, one per join:
339
385
 
340
386
  == An aside: column references in Sequel
341
387
 
342
- Sequel expects column names to be specified using symbols. In addition, returned hashes always use symbols as their keys. This allows you to freely mix literal values and column references. For example, the two following lines produce equivalent SQL:
388
+ Sequel expects column names to be specified using symbols. In addition, returned hashes always use symbols as their keys. This allows you to freely mix literal values and column references in many cases. For example, the two following lines produce equivalent SQL:
343
389
 
344
- items.filter(:x => 1) #=> "SELECT * FROM items WHERE (x = 1)"
345
- items.filter(1 => :x) #=> "SELECT * FROM items WHERE (1 = x)"
390
+ items.filter(:x => 1)
391
+ # SELECT * FROM items WHERE (x = 1)
392
+ items.filter(1 => :x)
393
+ # SELECT * FROM items WHERE (1 = x)"
346
394
 
347
395
  Ruby strings are generally treated as SQL strings:
348
396
 
349
- items.filter(:x => 'x') #=> "SELECT * FROM items WHERE (x = 'x')"
397
+ items.filter(:x => 'x')
398
+ # SELECT * FROM items WHERE (x = 'x')
350
399
 
351
400
  === Qualifying column names
352
401
 
353
402
  Column references can be qualified by using the double underscore special notation :table__column:
354
403
 
355
- items.literal(:items__price) #=> "items.price"
404
+ items.literal(:items__price)
405
+ # items.price
356
406
 
357
407
  === Column aliases
358
408
 
359
409
  You can also alias columns by using the triple undersecore special notation :column___alias or :table__column___alias:
360
410
 
361
- items.literal(:price___p) #=> "price AS p"
362
- items.literal(:items__price___p) #=> "items.price AS p"
411
+ items.literal(:price___p)
412
+ # price AS p
413
+ items.literal(:items__price___p)
414
+ # items.price AS p
363
415
 
364
416
  Another way to alias columns is to use the #as method:
365
417
 
366
- items.literal(:price.as(:p)) #=> "price AS p"
418
+ items.literal(:price.as(:p))
419
+ # price AS p
367
420
 
368
421
  == Sequel Models
369
422
 
@@ -386,14 +439,14 @@ You can, however, explicitly set the table name or even the dataset used:
386
439
  # or:
387
440
  Post.set_dataset :my_posts
388
441
 
389
- If you use a symbol, it assumes you are referring to the table with the same name. You can also give it a dataset:
442
+ If you use a symbol, it assumes you are referring to the table with the same name. You can also give it a dataset, which will set the defaults for all retrievals for that model:
390
443
 
391
444
  Post.set_dataset DB[:my_posts].filter(:category => 'ruby')
392
445
  Post.set_dataset DB[:my_posts].select(:id, :name).order(:date)
393
446
 
394
447
  === Model instances
395
448
 
396
- Model instance are identified by a primary key. By default, Sequel assumes the primary key column to be :id, unless it can get the primary key information from the database. The Model.[] method can be used to fetch records by their primary key:
449
+ Model instances are identified by a primary key. In most cases, Sequel can introspec the database to determine the primary key, but if not, it defaults to using :id. The Model.[] method can be used to fetch records by their primary key:
397
450
 
398
451
  post = Post[123]
399
452
 
@@ -410,7 +463,7 @@ Sequel models allow you to use any column as a primary key, and even composite k
410
463
  post = Post['ruby', 'hello world']
411
464
  post.pk #=> ['ruby', 'hello world']
412
465
 
413
- You can also define a model class that does not have a primary key, but then you lose the ability to easily update records.
466
+ You can also define a model class that does not have a primary key, but then you lose the ability to easily update and delete records.
414
467
 
415
468
  A model instance can also be fetched by specifying a condition:
416
469
 
@@ -434,10 +487,15 @@ A model instances stores its values as a hash:
434
487
 
435
488
  post.values #=> {:id => 123, :category => 'ruby', :title => 'hello world'}
436
489
 
437
- You can read the record values as object attributes (assuming the attribute names are valid columns in the model's dataset):
490
+ You can read the record values as object attributes, assuming the attribute names are valid columns in the model's dataset:
438
491
 
439
492
  post.id #=> 123
440
493
  post.title #=> 'hello world'
494
+
495
+ If the record's attributes names are not valid columns in the model's dataset (maybe because you used select_more to add a computed value column), you can use Model#[] to access the values:
496
+
497
+ post[:id] #=> 123
498
+ post[:title] #=> 'hello world'
441
499
 
442
500
  You can also change record values:
443
501
 
@@ -449,7 +507,7 @@ That will just change the value for the object, it will not persist the changes
449
507
 
450
508
  post.save
451
509
 
452
- If you want to modify record values and save the object after doing so, use the #update method:
510
+ If you want to modify record values and save the changes to the object after doing so, use the #update method:
453
511
 
454
512
  post.update(:title => 'hey there')
455
513
 
@@ -506,12 +564,12 @@ Records can also be deleted en-masse by invoking Model.delete and Model.destroy.
506
564
  Post.filter(:category => 32).destroy #=> runs hooks
507
565
 
508
566
  Please note that if Model.destroy is called, each record is deleted
509
- separately, but Model.delete deletes all relevant records with a single
510
- SQL statement.
567
+ separately, but Model.delete deletes all matching records with a single
568
+ SQL query.
511
569
 
512
570
  === Associations
513
571
 
514
- Associations are used in order to specify relationships between model classes that reflect relations between tables in the database using foreign keys.
572
+ Associations are used in order to specify relationships between model classes that reflect relationships between tables in the database, which are usually specified using foreign keys.
515
573
 
516
574
  class Post < Sequel::Model
517
575
  many_to_one :author
@@ -546,6 +604,8 @@ one_to_many and many_to_many create a getter method, a method for adding an obje
546
604
  post.add_tag(tag)
547
605
  post.remove_tag(tag)
548
606
  post.remove_all_tags
607
+
608
+ Note that the remove_* and remove_all_* methods do not delete the object from the database, they merely disassociate the associated object from the receiver.
549
609
 
550
610
  All associations add a dataset method that can be used to further filter or reorder the returned objects, or modify all of them:
551
611
 
data/bin/sequel CHANGED
@@ -4,7 +4,7 @@ require 'rubygems'
4
4
  require 'optparse'
5
5
  require 'sequel'
6
6
 
7
- db_opts = {}
7
+ db_opts = {:test=>true}
8
8
  copy_databases = nil
9
9
  dump_migration = nil
10
10
  echo = nil
@@ -13,7 +13,6 @@ logfile = nil
13
13
  migrate_dir = nil
14
14
  migrate_ver = nil
15
15
  backtrace = nil
16
- test_connection = true
17
16
  load_dirs = []
18
17
 
19
18
  opts = OptionParser.new do |opts|
@@ -71,7 +70,7 @@ opts = OptionParser.new do |opts|
71
70
  end
72
71
 
73
72
  opts.on("-N", "--no-test-connection", "do not test the connection") do
74
- test_connection = false
73
+ db_opts[:test] = false
75
74
  end
76
75
 
77
76
  opts.on("-t", "--trace", "Output the full backtrace if an exception is raised") do
@@ -120,7 +119,6 @@ connect_proc = lambda do |database|
120
119
  else
121
120
  Sequel.connect(database, db_opts)
122
121
  end
123
- db.test_connection if test_connection
124
122
  db
125
123
  end
126
124
 
@@ -0,0 +1,1383 @@
1
+ = Association Basics
2
+
3
+ This guide is based on http://guides.rubyonrails.org/association_basics.html
4
+
5
+ == Why Associations?
6
+
7
+ Associations exist to simplify code that deals with related rows in separate
8
+ database tables. Without associations, if you had classes such as:
9
+
10
+ class Artist < Sequel::Model
11
+ end
12
+
13
+ class Album < Sequel::Model
14
+ end
15
+
16
+ And you wanted to get all of the albums for a given artist (assuming each
17
+ album was associated with only one artist):
18
+
19
+ Album.filter(:artist_id=>@artist.id).all
20
+
21
+ Or maybe you want to add an album for a given artist:
22
+
23
+ Album.create(:artist_id=>@artist.id, :name=>'RF')
24
+
25
+ With Associations, you can make the above code simpler, by setting up associations
26
+ between the two models:
27
+
28
+ class Artist < Sequel::Model
29
+ one_to_many :albums
30
+ end
31
+
32
+ class Album < Sequel::Model
33
+ many_to_one :artist
34
+ end
35
+
36
+ Then, the code to retrieve albums related to the artist is simpler:
37
+
38
+ @artist.albums
39
+
40
+ As is the code to add a related album to an artist:
41
+
42
+ @artist.add_album(:name=>'RF')
43
+
44
+ == The Types of Associations
45
+
46
+ Sequel has four different association types built in:
47
+
48
+ * many_to_one
49
+ * one_to_many
50
+ * one_to_one
51
+ * many_to_many
52
+
53
+ === many_to_one
54
+
55
+ The many_to_one association is used when the table for the current class
56
+ contains a foreign key that references the primary key in the table for the
57
+ associated class. It is named because there can be many rows in the current
58
+ table for each row in the associated table.
59
+
60
+ # Database schema:
61
+ # albums artists
62
+ # :id /--> :id
63
+ # :artist_id --/ :name
64
+ # :name
65
+
66
+ class Album
67
+ # Uses singular form of associated model name
68
+ many_to_one :artist
69
+ end
70
+
71
+ === one_to_many
72
+
73
+ The one_to_many association is used when the table for the associated class
74
+ contains a foreign key that references the primary key in the table for the
75
+ current class. It is named because for each row in the current table there
76
+ can be many rows in the associated table:
77
+
78
+ # Database schema:
79
+ # artists albums
80
+ # :id <----\ :id
81
+ # :name \----- :artist_id
82
+ # :name
83
+
84
+ class Artist
85
+ # Uses plural form of associated model name
86
+ one_to_many :albums
87
+ end
88
+
89
+ === one_to_one
90
+
91
+ The one_to_one association can be thought of as a subset of the one_to_many association,
92
+ but where there can only be either 0 or 1 records in the associated table.
93
+ It is the least frequently used of the four associations. If you assume
94
+ each artist cannot be associated with more than one album:
95
+
96
+ # Database schema:
97
+ # artists albums
98
+ # :id <----\ :id
99
+ # :name \----- :artist_id
100
+ # :name
101
+
102
+ class Artist
103
+ # Uses singular form of associated model name
104
+ one_to_one :album
105
+ end
106
+
107
+ === many_to_many
108
+
109
+ The many_to_many association allows each row in the current table to be associated
110
+ to many rows in the associated table, and each row in the associated table to
111
+ many rows in the current table, by using a join table to associate the two tables.
112
+ If you assume each artist can have multiple albums and each album can have multiple
113
+ artists:
114
+
115
+ # Database schema:
116
+ # albums
117
+ # :id <----\
118
+ # :name \ albums_artists
119
+ # \---- :album_id
120
+ # artists /---- :artist_id
121
+ # :id <-----/
122
+ # :name
123
+
124
+ class Artist
125
+ # Uses plural form of associated model name
126
+ many_to_many :albums
127
+ end
128
+ class Album
129
+ many_to_many :artists
130
+ end
131
+
132
+ === Differences Between many_to_one and one_to_one
133
+
134
+ If you want to setup a 1-1 relationship between two models, you have to use
135
+ many_to_one in one model, and one_to_one in the other model. How do you
136
+ know which to use in which model?
137
+
138
+ The simplest way to remember is that the model whose table has the foreign
139
+ key uses many_to_one, and the other model uses one_to_one:
140
+
141
+ # Database schema:
142
+ # artists albums
143
+ # :id <----\ :id
144
+ # :name \----- :artist_id
145
+ # :name
146
+
147
+ class Artist
148
+ one_to_one :album
149
+ end
150
+ class Album
151
+ many_to_one :artist
152
+ end
153
+
154
+ == Most Common Options
155
+
156
+ === :key
157
+
158
+ The :key option must be used if the default column symbol that Sequel would use is not
159
+ the correct column. For example:
160
+
161
+ class Album
162
+ # Assumes :key is :artist_id, based on association name of :artist
163
+ many_to_one :artist
164
+ end
165
+ class Artist
166
+ # Assumes :key is :artist_id, based on class name of Artist
167
+ one_to_many :albums
168
+ end
169
+
170
+ However, if your schema looks like:
171
+
172
+ # Database schema:
173
+ # artists albums
174
+ # :id <----\ :id
175
+ # :name \----- :artistid # Note missing underscore
176
+ # :name
177
+
178
+ Then the default :key option will not be correct. To fix this, you need to
179
+ specify an explicit :key option:
180
+
181
+ class Album
182
+ many_to_one :artist, :key=>:artistid
183
+ end
184
+ class Artist
185
+ one_to_many :albumst, :key=>:artistid
186
+ end
187
+
188
+ For many_to_many associations, the :left_key and :right_key options can be
189
+ used to specify the column names in the join table, and the :join_table
190
+ option can be used to specify the name of the join table:
191
+
192
+ # Database schema:
193
+ # albums
194
+ # :id <----\
195
+ # :name \ albumsartists
196
+ # \---- :albumid
197
+ # artists /---- :artistid
198
+ # :id <-----/
199
+ # :name
200
+
201
+ class Artist
202
+ # Note that :left_key refers to the foreign key pointing to the
203
+ # current table, and :right_key the foreign key pointing to the
204
+ # associated table.
205
+ many_to_many :albums, :left_key=>:artistid, :right_key=>:albumid,
206
+ :join_table=>:albumsartists
207
+ end
208
+ class Album
209
+ many_to_many :artists, :left_key=>:albumid, :right_key=>:artistid,
210
+ :join_table=>:albumsartists
211
+ end
212
+
213
+ === :class
214
+
215
+ If the class of the association can not be guessed directly by looking at
216
+ the association name, you need to specify it via the :class option. For
217
+ example, if you have two separate foreign keys in the albums table that
218
+ both point to the artists table, maybe to indicate one artist is the
219
+ vocalist and one is the composer, you'd have to use the :class option:
220
+
221
+ # Database schema:
222
+ # artists albums
223
+ # :id <----\ :id
224
+ # :name \----- :vocalist_id
225
+ # \---- :composer_id
226
+ # :name
227
+
228
+ class Album
229
+ many_to_one :vocalist, :class=>:Artist
230
+ many_to_one :composer, :class=>:Artist
231
+ end
232
+ class Artist
233
+ one_to_many :vocalist_albums, :class=>:Album, :key=>:vocalist_id
234
+ one_to_many :composer_albums, :class=>:Album, :key=>:composer_id
235
+ end
236
+
237
+ == Self-referential Associations
238
+
239
+ Self-referential associations are easy to handle in Sequel. The simplest
240
+ example is a tree structure:
241
+
242
+ # Database schema:
243
+ # nodes
244
+ # :id <--\
245
+ # :parent_id ---/
246
+ # :name
247
+
248
+ class Node
249
+ many_to_one :parent, :class=>self
250
+ one_to_many :children :key=>:parent_id, :class=>self
251
+ end
252
+
253
+ For many_to_many self_referential associations, it's fairly similar. Here's
254
+ an example of a directed graph:
255
+
256
+ # Database schema:
257
+ # nodes edges
258
+ # :id <----------- :successor_id
259
+ # :name \----- :predecessor_id
260
+
261
+ class Node
262
+ many_to_many :direct_successors, :left_key=>:successor_id,
263
+ :right_key=>:predecessor_id, :join_table=>:edges, :class=>self
264
+ many_to_many :direct_predecessors, :right_key=>:successor_id,
265
+ :left_key=>:predecessor_id, :join_table=>:edges, :class=>self
266
+ end
267
+
268
+ == Methods Added
269
+
270
+ When you create an association, it's going to add instance methods to
271
+ the class related to the association.
272
+
273
+ All associations are going to have an instance method added with the
274
+ same name as the association:
275
+
276
+ @artist.albums
277
+ @album.artists
278
+
279
+ many_to_one and one_to_one associations will also have a setter method
280
+ added to change the associated object:
281
+
282
+ @album.artist = Artist.create(:name=>'YJM')
283
+
284
+ many_to_many and one_to_many associations will have three methods added:
285
+
286
+ - add_* to associate an object to the current object
287
+ - remove_* to disassociate an object from the current object
288
+ - remove_all_* to dissociate all currently associated objects
289
+
290
+ Examples:
291
+
292
+ @artist.add_album(@album)
293
+ @artist.remove_album(@album)
294
+ @artist.remove_all_albums
295
+
296
+ == Dataset Method
297
+
298
+ In addition to the above methods, associations also add a dataset method
299
+ that returns a dataset representing the objects in the associated table:
300
+
301
+ @album.artist_id
302
+ # 10
303
+ @album.artist_dataset
304
+ # SELECT * FROM artists WHERE (id = 10)
305
+
306
+ @artist.id
307
+ # 20
308
+ @artist.albums_dataset
309
+ # SELECT * FROM albums WHERE (artist_id = 20)
310
+
311
+ The association dataset is just like any other Sequel dataset, in that
312
+ it can be further filtered, ordered, etc.:
313
+
314
+ @artist.albums_dataset.
315
+ filter(:name.like('A%')).
316
+ order(:copies_sold).
317
+ limit(10)
318
+ # SELECT * FROM albums
319
+ # WHERE ((artist_id = 20) AND (name LIKE 'A%'))
320
+ # ORDER BY copies_sold LIMIT 10
321
+
322
+ == Caching
323
+
324
+ Associations are cached after being retrieved:
325
+
326
+ @artist.album # Not cached - Database Query
327
+ @artist.album # Cached - No Database Query
328
+
329
+ @album.artists # Not cached - Database Query
330
+ @album.artists # Cached - No Database Query
331
+
332
+ You can choose to ignore the cached versions and do a database query to
333
+ retrieve results by passing a true argument to the association method:
334
+
335
+ @album.artists # Not cached - Database Query
336
+ @album.artists # Cached - No Database Query
337
+ @album.artists(true) # Ignore cache - Database Query
338
+
339
+ If you reload/refresh the object, it will automatically clear the
340
+ associations cache for the object:
341
+
342
+ @album.artists # Not cached - Database Query
343
+ @album.artists # Cached - No Database Query
344
+ @album.reload
345
+ @album.artists # Not Cached - Database Query
346
+
347
+ If you want direct access to the associations cache, use the associations
348
+ instance method:
349
+
350
+ @album.associations # {}
351
+ @album.associations[:artists] # nil
352
+ @album.artists # [<Artist ...>, ...]
353
+ @album.associations[:artists] # [<Artist ...>, ...]
354
+
355
+ Note that while the association method caches associated objects, if you
356
+ retrieve access through the association dataset directly, the results
357
+ will not be cached:
358
+
359
+ @album.artists_dataset.all # [<Artist ...>, ...]
360
+ @album.associations[:artists] # nil
361
+
362
+ == Name Collisions
363
+
364
+ Because associations create instance methods, it's possible to override
365
+ existing instance methods if you name an extension the same as an
366
+ existing method. For example, <tt>values</tt> and <tt>associations</tt>
367
+ would be bad association names.
368
+
369
+ == Database Schema
370
+
371
+ Creating an association, doesn't modify the database schema. Sequel
372
+ assumes your associations reflect the existing database schema. If not,
373
+ you should modify your schema before creating the associations.
374
+
375
+ === many_to_one/one_to_many
376
+
377
+ For example, for the following model code:
378
+
379
+ class Album
380
+ many_to_one :artist
381
+ end
382
+ class Artist
383
+ one_to_many :albums
384
+ end
385
+
386
+ You probably want the following database schema:
387
+
388
+ # albums artists
389
+ # :id /--> :id
390
+ # :artist_id --/ :name
391
+ # :name
392
+
393
+ Which could be created using the following Sequel code:
394
+
395
+ DB.create_table(:artists) do
396
+ # Primary key must be set explicitly
397
+ primary_key :id
398
+ String :name
399
+ end
400
+ DB.create_table(:albums) do
401
+ primary_key :id
402
+ # Table that foreign key references needs to be set explicitly
403
+ # for a database foreign key reference to be created.
404
+ foreign_key :artist_id, :artists
405
+ String :name
406
+ end
407
+
408
+ If you already had a schema such as:
409
+
410
+ # Database schema:
411
+ # albums artists
412
+ # :id :id
413
+ # :name :name
414
+
415
+ Then you just need to add the column:
416
+
417
+ DB.alter_table(:albums) do
418
+ add_foreign_key :artist_id, :artists
419
+ end
420
+
421
+ === many_to_many
422
+
423
+ With many_to_many associations, the default join table for the association
424
+ uses the sorted underscored names of both model classes. For example, with
425
+ the following model code:
426
+
427
+ class Album
428
+ many_to_many :artists
429
+ end
430
+ class Artist
431
+ many_to_many :albums
432
+ end
433
+
434
+ The default join table name would be <tt>albums_artists</tt>, not
435
+ <tt>artists_albums</tt>, because:
436
+
437
+ ["artists", "albums"].sort.join('_')
438
+ # "albums_artists"
439
+
440
+ Assume you already had the albums and artists tables created, and you just
441
+ wanted to add an albums_artists join table to create the following schema:
442
+
443
+ # Database schema:
444
+ # albums
445
+ # :id <----\
446
+ # :name \ albums_artists
447
+ # \---- :album_id
448
+ # artists /---- :artist_id
449
+ # :id <-----/
450
+ # :name
451
+
452
+ You could use the following Sequel code:
453
+
454
+ DB.create_table(:albums_artists) do
455
+ foreign_key :album_id, :albums
456
+ foreign_key :artist_id, :artists
457
+ end
458
+
459
+ == Association Scope
460
+
461
+ If you nest your Sequel::Model classes inside modules, then you should know
462
+ that Sequel will only look in the same module for associations by default.
463
+ So the following code will work fine:
464
+
465
+ module App
466
+ class Artist < Sequel::Model
467
+ one_to_many :albums
468
+ end
469
+ class Album < Sequel::Model
470
+ many_to_one :artist
471
+ end
472
+ end
473
+
474
+ However, if you enclose your model classes inside two different modules,
475
+ things will not work by default:
476
+
477
+ module App1
478
+ class Artist < Sequel::Model
479
+ one_to_many :albums
480
+ end
481
+ end
482
+ module App2
483
+ class Album < Sequel::Model
484
+ many_to_one :artist
485
+ end
486
+ end
487
+
488
+ To fix this, you need to specify the full model class name using the
489
+ :class option:
490
+
491
+ module App1
492
+ class Artist < Sequel::Model
493
+ one_to_many :albums, :class=>"App2::Album"
494
+ end
495
+ end
496
+ module App2
497
+ class Album < Sequel::Model
498
+ many_to_one :artist, :class=>"App1::Artist"
499
+ end
500
+ end
501
+
502
+ == Method Details
503
+
504
+ In all of these methods, _association_ is replaced by the symbol you
505
+ pass to the association.
506
+
507
+ === _association_(reload = false) (e.g. albums)
508
+
509
+ For +many_to_one+ and +one_to_one+ associations, the _association_ method
510
+ returns either the single object associated, or nil if no object is
511
+ associated.
512
+
513
+ @artist = @album.artist
514
+
515
+ For +one_to_many+ and +many_to_many+ associations, the _association_ method
516
+ returns an array of associated objects, which may be empty if no objects
517
+ are currently associated.
518
+
519
+ @albums = @artist.albums
520
+
521
+ === _association_=(object_to_associate) (e.g. artist=) [+many_to_one+ and +one_to_one+]
522
+
523
+ The _association_= method sets up an association of the passed object to
524
+ the current object. For +many_to_one+ associations, this sets the
525
+ foreign key for the current object to point to the associated
526
+ object's primary key.
527
+
528
+ @album.artist = @artist
529
+
530
+ For +one_to_one+ associations, this sets the foreign key of the
531
+ associated object to the primary key value of the current object.
532
+
533
+ For +many_to_one+ associations, this does not save the current object.
534
+ For +one_to_one+ associations, this does save the associated object.
535
+
536
+ === add_<i>association</i>(object_to_associate) (e.g. add_album) [+one_to_many+ and +many_to_many+]
537
+
538
+ The add_<i>association</i> method associates the passed object to the current
539
+ object. For +one_to_many+ associations, it sets the foreign key of the
540
+ associated object to the primary key value of the current object, and
541
+ saves the associated object. For +many_to_many+ associations, this inserts
542
+ a row into the join table with the foreign keys set to the primary key values
543
+ of the current and associated objects. Note that the singular form of the
544
+ association name is used in this method.
545
+
546
+ @artist.add_album(@album)
547
+
548
+ In addition to passing an actual associated object, you can pass a hash,
549
+ and a new associated object will be created from them:
550
+
551
+ @artist.add_album(:name=>'RF') # creates Album object
552
+
553
+ The add_<i>association</i> method returns the now associated object:
554
+
555
+ @album = @artist.add_album(:name=>'RF')
556
+
557
+ === remove_<i>association</i>(object_to_disassociate) (e.g. remove_album) [+one_to_many+ and +many_to_many+]
558
+
559
+ The remove_<i>association</i> method disassociates the the passed object from
560
+ the current object. For +one_to_many+ associations, it sets the foreign key of
561
+ the associated object to NULL, and saves the associated object. For
562
+ +many_to_many+ associations, this deletes the matching row in the join table.
563
+ Similar to the add_<i>association</i> method, the singular form of the
564
+ association name is used in this method.
565
+
566
+ @artist.remove_album(@album)
567
+
568
+ Note that this does not delete <tt>@album</tt> from the database, it only
569
+ disassociates it from the <tt>@artist</tt>. To delete <tt>@album</tt> from the
570
+ database:
571
+
572
+ @album.destroy
573
+
574
+ The add_<i>association</i> and remove_<i>association</i> methods should be
575
+ thought of as adding and removing from the association, not from the database.
576
+
577
+ In addition to passing the object directly to remove_<i>association</i>, you
578
+ can also pass the associated object's primary key:
579
+
580
+ @artist.remove_album(10)
581
+
582
+ This will look up the associated object using the key, and remove that
583
+ album.
584
+
585
+ The remove_<i>association</i> method returns the now disassociated object:
586
+
587
+ @album = @artist.remove_album(10)
588
+
589
+ === remove_all_<i>association</i> (e.g. remove_all_albums) [+one_to_many+ and +many_to_many+]
590
+
591
+ The remove_all_<i>association</i> method disassociates all currently associated
592
+ objects. For +one_to_many+ associations, it sets the foreign key of
593
+ all associated objects to NULL in a single query. For +many_to_many+
594
+ associations, this deletes all matching rows in the join table.
595
+ Unlike the add_<i>association</i> and remove_<i>association</i> method, the
596
+ plural form of the association name is used in this method.
597
+ The remove_all_<i>association</i> method returns the number of rows updated
598
+ for +one_to_many+ associations and the number of rows deleted for
599
+ +many_to_many+ associations:
600
+
601
+ @rows_modified = @artist.remove_all_albums
602
+
603
+ === <i>association</i>_dataset (e.g. albums_dataset)
604
+
605
+ The <i>association</i>_dataset method returns a dataset that represents
606
+ all associated objects. This dataset is like any other Sequel dataset,
607
+ in that it can be filtered, ordered, etc.:
608
+
609
+ ds = @artist.albums_dataset.filter(:name.like('A%')).order(:copies_sold)
610
+
611
+ Unlike most other Sequel datasets, association datasets have a couple of
612
+ added methods:
613
+
614
+ ds.model_object # @artist
615
+ ds.association_reflection # same as Artist.association_reflection(:albums)
616
+
617
+ For a more info on Sequel's reflection capabilities see the {Reflection page}[link:files/doc/reflection_rdoc.html].
618
+
619
+ == Overriding Method Behavior
620
+
621
+ Sequel is designed to be very flexible. If the default behavior of the
622
+ association modification methods isn't what you desire, you can override
623
+ the methods in your classes. However, you should be aware that for each
624
+ of the association modification methods described, there is a private
625
+ method that is preceeded by an underscore that does the actual
626
+ modification. The public method without the underscore handles caching
627
+ and callbacks, and shouldn't be overridden by the user.
628
+
629
+ === _<i>association</i>=
630
+
631
+ Let's say you want to set a specific field whenever associating an object
632
+ using the association setter method. For example, let's say you have
633
+ a file_under column for each album to tell you where to file it. If the
634
+ album is associated with an artist, it should be filed under the artist's
635
+ name and the album's name, otherwise it should just use the album's name.
636
+
637
+ class Album < Sequel::Model
638
+ many_to_one :artist
639
+
640
+ private
641
+
642
+ def _artist=(artist)
643
+ if artist
644
+ self.artist_id = artist.id
645
+ self.file_under = "#{artist.name}-#{name}"
646
+ else
647
+ self.artist_id = nil
648
+ self.file_under = name
649
+ end
650
+ end
651
+ end
652
+
653
+ The above example is contrived, as you would generally use a before_save model
654
+ hook to handle such a modification. However, if you only modify the album's
655
+ artist using the artist= method, this approach may perform better.
656
+
657
+ === \_add_<i>association</i>
658
+
659
+ Continuing with the same example, here's how would you handle the same case if
660
+ you also wanted to handle the Artist#add_album method:
661
+
662
+ class Artist < Sequel::Model
663
+ one_to_many :albums
664
+
665
+ private
666
+
667
+ def _add_album(album)
668
+ album.update(:artist_id => id, :file_under=>"#{name}-#{album.name}")
669
+ end
670
+ end
671
+
672
+ === \_remove_<i>association</i>
673
+
674
+ Continuing with the same example, here's how would you handle the same case if
675
+ you also wanted to handle the Artist#remove_album method:
676
+
677
+ class Artist < Sequel::Model
678
+ one_to_many :albums
679
+
680
+ private
681
+
682
+ def _remove_album(album)
683
+ album.update(:artist_id => nil, :file_under=>album.name)
684
+ end
685
+ end
686
+
687
+ === \_remove_all_<i>association</i>
688
+
689
+ Continuing with the same example, here's how would you handle the same case if
690
+ you also wanted to handle the Artist#remove_all_albums method:
691
+
692
+ class Artist < Sequel::Model
693
+ one_to_many :albums
694
+
695
+ private
696
+
697
+ def _remove_all_albums
698
+ # This is Dataset#update, not Model#update, so the :file_under=>:name
699
+ # ends up being "SET file_under = name" in SQL.
700
+ albums_dataset.update(:artist_id => nil, :file_under=>:name)
701
+ end
702
+ end
703
+
704
+ == Association Options
705
+
706
+ Sequel's associations mostly share the same options. For ease of understanding,
707
+ they are grouped here by section
708
+
709
+ === Association Dataset Modification Options
710
+
711
+ ==== block
712
+
713
+ All association defining methods take a block that is passed the
714
+ default dataset and should return a modified copy of the dataset to
715
+ use for the association. For example, if you wanted an association
716
+ that returns all albums of an artist that went gold (sold at least
717
+ 500,000 copies):
718
+
719
+ Artist.one_to_many :gold_albums, :class=>:Album do |ds|
720
+ ds.filter{copies_sold > 500000}
721
+ end
722
+
723
+ ==== :class
724
+
725
+ This is the class of the associated objects that will be used. It's
726
+ one of the most commonly used options. If it is not given, it guesses
727
+ based on the name of the association. If a *_to_many association is
728
+ used, uses the singular form of the association name. For example:
729
+
730
+ Album.many_to_one :artist # guesses Artist
731
+ Artist.one_to_many :albums # guesses Album
732
+
733
+ However, for more complex associations, especially ones that add
734
+ additional filters beyond the foreign/primary key relationships, the
735
+ default class guessed will be wrong:
736
+
737
+ # guesses GoldAlbum
738
+ Artist.one_to_many :gold_albums do |ds|
739
+ ds.filter{copies_sold > 500000}
740
+ end
741
+
742
+ You can specify the :class option using the class itself, a Symbol,
743
+ or a String:
744
+
745
+ Album.many_to_one :artist, :class=>Artist # Class
746
+ Album.many_to_one :artist, :class=>:Artist # Symbol
747
+ Album.many_to_one :artist, :class=>"Artist" # String
748
+
749
+ ==== :key
750
+
751
+ For +many_to_one+ associations, is the foreign_key in current model's table
752
+ that references associated model's primary key, as a symbol. Defaults to
753
+ :<i>association</i>_id. Can use an array of symbols for a composite key
754
+ association.
755
+
756
+ Album.many_to_one :artist # :key=>:artist_id
757
+
758
+ For +one_to_one+ and +one_to_many+ associations, is the foreign key in
759
+ associated model's table that references current model's primary key, as a
760
+ symbol. Defaults to :"#{self.name.underscore}_id".
761
+
762
+ Artist.one_to_many :albums # :key=>:artist_id
763
+
764
+ In both cases an array of symbols for a composite key association:
765
+
766
+ Apartment.many_to_one :building # :key=>[:city, :address]
767
+
768
+ ==== :conditions
769
+
770
+ The conditions to use to filter the association, can be any argument passed to filter.
771
+ If you use a hash or an array of two element arrays, this will also be used as a
772
+ filter when using eager_graph to load the association.
773
+
774
+ Artist.one_to_many :good_albums, :class=>:Album, :conditions=>{:good=>true}
775
+ @artist.good_albums
776
+ # SELECT * FROM albums WHERE ((artist_id = 1) AND (good IS TRUE))
777
+
778
+ ==== :order
779
+
780
+ The column(s) by which to order the association dataset. Can be a
781
+ singular column or an array.
782
+
783
+ Artist.one_to_many :albums_by_name, :class=>:Album,
784
+ :order=>:name
785
+ Artist.one_to_many :albums_by_num_tracks, :class=>:Album,
786
+ :order=>[:num_tracks, :name]
787
+
788
+ ==== :select
789
+
790
+ The columns to SELECT when loading the association. For most associations,
791
+ it defaults to nil, so * is used. For +many_to_many+ associations, it
792
+ defaults to the associated class's table_name.*, which means it doesn't include
793
+ the columns from the join table. This is to prevent the common issue where the
794
+ join table includes columns with the same name as columns in the associated
795
+ table, in which case the joined table's columns would usually end up clobbering
796
+ the values in the associated table. If you want to include the join table
797
+ attributes, you can use this option, but beware that the join table columns
798
+ can clash with columns from the associated table, so you should alias any
799
+ columns that have the same name in both the join table and the associated
800
+ table. Example:
801
+
802
+ Artist.one_to_many :albums, :select=>[:id, :name]
803
+ Album.many_to_many :tags, :select=>[:tags.*, :albums_tags__number]
804
+
805
+ ==== :limit
806
+
807
+ Limit the number of records to the provided value:
808
+
809
+ Artist.one_to_many :best_selling_albums, :class=>:Album,
810
+ :order=>:copies_sold, :limit=>5 # LIMIT 5
811
+
812
+ Use an array with two arguments for the value to specify a limit and an offset.
813
+
814
+ Artist.one_to_many :next_best_selling_albums, :class=>:Album,
815
+ :order=>:copies_sold, :limit=>[10, 5] # LIMIT 10 OFFSET 5
816
+
817
+ This probably doesn't make a lot of sense for *_to_one associations, though you
818
+ could use it to specify an offset.
819
+
820
+ This option is ignored when eager loading.
821
+
822
+ ==== :join_table [+many_to_many+]
823
+
824
+ Name of table that includes the foreign keys to both the current model and the
825
+ associated model, as a symbol. Defaults to the name of current model and name
826
+ of associated model, pluralized, underscored, sorted, and joined with '_'.
827
+ Here's an example of the defaults:
828
+
829
+ Artist.many_to_many :albums # :join_table=>:albums_artists
830
+ Album.many_to_many :artists # :join_table=>:albums_artists
831
+ Person.many_to_many :colleges # :join_table=>:colleges_people
832
+
833
+ ==== :left_key [+many_to_many+]
834
+
835
+ Foreign key in join table that points to current model's primary key, as a
836
+ symbol. Defaults to :"#{self.name.underscore}_id".
837
+
838
+ Album.many_to_many :tags # :left_key=>:album_id
839
+
840
+ Can use an array of symbols for a composite key association.
841
+
842
+ ==== :right_key [+many_to_many+]
843
+
844
+ Foreign key in join table that points to associated model's primary key, as a
845
+ symbol. Defaults to :"#{name.to_s.singularize}_id".
846
+
847
+ Album.many_to_many :tags # :left_key=>:tag_id
848
+
849
+ Can use an array of symbols for a composite key association.
850
+
851
+ ==== :distinct
852
+
853
+ Use the DISTINCT clause when selecting associating object, both when lazy
854
+ loading and eager loading via eager (but not when using eager_graph).
855
+
856
+ This is most useful for many_to_many associations that use join tables that
857
+ contain more than just the foreign keys, where you are storing additional
858
+ information. For example, if you have a database of people, degree types, and
859
+ colleges, and you want to return all people from a given college, you may want
860
+ to use :distinct so that if a person has two separate degrees from the same
861
+ college, they won't show up twice.
862
+
863
+ ==== :clone
864
+
865
+ The :clone option clones an existing association, taking the options
866
+ you specified for that association, and making a copy of them for this
867
+ association. Other options provided by this association are then merged
868
+ into the cloned options.
869
+
870
+ This is commonly used if you have a bunch of similar associations that
871
+ you want to DRY up:
872
+
873
+ one_to_many :english_verses, :class=>:LyricVerse, :key=>:lyricsongid,
874
+ :order=>:number, :conditions=>{:languageid=>1}
875
+ one_to_many :romaji_verses, :clone=>:english_verses, :conditions=>{:languageid=>2}
876
+ one_to_many :japanese_verses, :clone=>:english_verses, :conditions=>{:languageid=>3}
877
+
878
+ Note that for the final two asociations, you didn't have to specify the :class,
879
+ :key, or :order options, as they were copied by the :clone option. By specifying
880
+ the :conditions option for the final two associations, it overrides the :conditions
881
+ option of the first association, it doesn't attempt to merge them.
882
+
883
+ In addition to the options hash, the :clone option will copy a block argument
884
+ from the existing situation. If you want a cloned association to not have the
885
+ same block as the association you are cloning from, specify the :block=>nil option
886
+ in additon to the :clone option.
887
+
888
+ ==== :dataset
889
+
890
+ This is generally only specified for custom associations that aren't based on
891
+ primary/foreign key relationships. It should be a proc that is instance evaled
892
+ to get the base dataset to use before the other options are applied.
893
+
894
+ Here's an example of an association of songs to artists through lyrics, where
895
+ the artist can perform any one of four tasks for the lyric:
896
+
897
+ Album.one_to_many :songs, :dataset=>(proc do
898
+ Song.select(:songs.*).
899
+ join(Lyric, :id=>:lyricid,
900
+ id=>[:composer_id, :arranger_id, :vocalist_id, :lyricist_id])
901
+ end)
902
+ Artist.first.songs_dataset
903
+ # SELECT songs.* FROM songs
904
+ # INNER JOIN lyrics ON
905
+ # lyrics.id = songs.lyric_id AND
906
+ # 1 IN (composer_id, arranger_id, vocalist_id, lyricist_id)
907
+
908
+ ==== :extend
909
+
910
+ A module or array of modules to extend the dataset with. These are used to
911
+ set up association extensions. For more information , please see the
912
+ {Advanced Associations page}[link:files/doc/advanced_associations_rdoc.html].
913
+
914
+ ==== :primary_key
915
+
916
+ The column that the :key option references, as a symbol. For +many_to_one+
917
+ associations, this column in the associated table. For +one_to_one+ and
918
+ +one_to_many+ associations, this column in the current table. In both cases,
919
+ it defaults to the primary key of the table. Can use an
920
+ array of symbols for a composite key association.
921
+
922
+ Artist.set_primary_key :arid
923
+ Artist.one_to_many :albums # :primary_key=>:arid
924
+ Album.one_to_many :artist # :primary_key=>:arid
925
+
926
+ ==== :left_primary_key [+many_to_many+]
927
+
928
+ Column in current table that :left_key option points to, as a symbol.
929
+ Defaults to primary key of current table.
930
+
931
+ Album.set_primary_key :alid
932
+ Album.many_to_many :tags # :left_primary_key=>:alid
933
+
934
+ Can use an array of symbols for a composite key association.
935
+
936
+ ==== :right_primary_key [+many_to_many+]
937
+
938
+ Column in associated table that :right_key points to, as a symbol.
939
+ Defaults to primary key of the associated table.
940
+
941
+ Tag.set_primary_key :tid
942
+ Album.many_to_many :tags # :left_primary_key=>:tid
943
+
944
+ Can use an array of symbols for a composite key association.
945
+
946
+ === Callback Options
947
+
948
+ All callbacks can be specified as a Symbol, Proc, or array of both/either
949
+ specifying a callback to call. Symbols are interpreted as instance methods
950
+ that are called with the associated object. Procs are called with the receiver
951
+ as the first argument and the associated object as the second argument. If
952
+ an array is given, all of them are called in order.
953
+
954
+ Before callbacks are often used to check preconditions, they can return
955
+ false to signal Sequel to abort the modification. If any before callback
956
+ returns false, the remaining before callbacks are not called and modification
957
+ is aborted. Before callbacks are also commonly used to modify the current
958
+ object or the associated object.
959
+
960
+ After callbacks are often used for notification (logging, email) after a
961
+ successful modification has been made.
962
+
963
+ ==== :before_add [+one_to_many+, +many_to_many+]
964
+
965
+ Called before adding an object to the association:
966
+
967
+ class Artist
968
+ # Don't allow adding an album to an artist if it has no tracks
969
+ one_to_many :albums, :before_add=>proc{|ar, al| false if al.num_tracks == 0}
970
+ end
971
+
972
+ ==== :after_add [+one_to_many+, +many_to_many+]
973
+
974
+ Called after adding an object to the association:
975
+
976
+ class Artist
977
+ # Log all associations of albums to an audit logging table
978
+ one_to_many :albums, :after_add=>:log_add_album
979
+
980
+ private
981
+
982
+ def log_add_album(album)
983
+ DB[:audit_logs].insert(:log=>"Album #{album.inspect} associated to #{inspect}")
984
+ end
985
+ end
986
+
987
+ ==== :before_remove [+one_to_many+, +many_to_many+]
988
+
989
+ Called before removing an object from the association:
990
+
991
+ class Artist
992
+ # Don't allow removing a self-titled album
993
+ one_to_many :albums, :before_remove=>proc{|ar, al| false if al.name == ar.name}
994
+ end
995
+
996
+ ==== :after_remove [+one_to_many+, +many_to_many+]
997
+
998
+ Called after removing an object from the association:
999
+
1000
+ class Artist
1001
+ # Log all disassociations of albums to an audit logging table
1002
+ one_to_many :albums, :after_remove=>:log_remove_album
1003
+
1004
+ private
1005
+
1006
+ def log_remove_album(album)
1007
+ DB[:audit_logs].insert(:log=>"Album #{album.inspect} disassociated from #{inspect}")
1008
+ end
1009
+ end
1010
+
1011
+ ==== :before_set [+many_to_one+, +one_to_one+]
1012
+
1013
+ Called before the _<i>association</i>= method is called to modify the objects:
1014
+
1015
+ Called before removing an object from the association:
1016
+
1017
+ class Album
1018
+ # Don't associate the album with an artist if the year the album was
1019
+ # released is less than the year the artist/band started.
1020
+ many_to_one :artist, :before_set=>proc{|al, ar| false if al.year < ar.year_started}
1021
+ end
1022
+
1023
+ ==== :after_set [+many_to_one+, +one_to_one+]
1024
+
1025
+ Called after the _<i>association</i>= method is called to modify the objects:
1026
+
1027
+ class Album
1028
+ # Log all disassociations of albums to an audit logging table
1029
+ many_to_one :artist, :after_set=>:log_artist_set
1030
+
1031
+ private
1032
+
1033
+ def log_artist_set(artist)
1034
+ DB[:audit_logs].insert(:log=>"Artist for album #{inspect} set to #{artist.inspect}")
1035
+ end
1036
+ end
1037
+
1038
+ ==== :after_load
1039
+
1040
+ Called after retrieving the associated records from the database. Not called
1041
+ when eager loading via eager_graph, but called when eager loading via eager.
1042
+
1043
+ class Artist
1044
+ # Cache all album names to a single string when retrieving the
1045
+ # albums.
1046
+ one_to_many :albums, :after_add=>:cache_album_names
1047
+
1048
+ attr_reader :album_names
1049
+
1050
+ private
1051
+
1052
+ def cache_album_names(albums)
1053
+ @album_names = albums.map{|x| x.name}.join(", ")
1054
+ end
1055
+ end
1056
+
1057
+ Generally used if you know you will always want a certain action done
1058
+ when retrieving the association. However, you need to be careful if you
1059
+ also plan on using eager_graph to eagerly load the association.
1060
+
1061
+ For +one_to_many+ and +many_to_many+ associations, both the argument to
1062
+ symbol callbacks and the second argument to proc callbacks will be an
1063
+ array of associated objects instead of a single object.
1064
+
1065
+ ==== :uniq [+many_to_many+]
1066
+
1067
+ Adds a after_load callback that makes the array of objects unique. In many
1068
+ cases, using the :distinct option is a better approach.
1069
+
1070
+ === Eager Loading via eager (query per association) Options
1071
+
1072
+ ==== :eager
1073
+
1074
+ The associations to eagerly load via eager when loading the associated object(s).
1075
+ This is useful for example if you always want to eagerly load dependent
1076
+ associations when loading this association.
1077
+
1078
+ For example, if you know that any time that you want to load an artist's
1079
+ albums, you are also going to want access to the album's tracks as well:
1080
+
1081
+ # Eager load tracks when loading the albums
1082
+ Artist.one_to_many :albums, :eager=>:tracks
1083
+
1084
+ You can also use a hash or array to specify multiple dependent associations
1085
+ to eagerly load:
1086
+
1087
+ # Eager load the albums' tracks and the tracks' tags when loading the albums
1088
+ Artist.one_to_many :albums, :eager=>{:tracks=>:tags}
1089
+ # Eager load the albums' tags and tracks when loading the albums
1090
+ Artist.one_to_many :albums, :eager=>[:tags, :tracks]
1091
+ # Eager load the albums' tags, tracks, and tracks' tags when loading the albums
1092
+ Artist.one_to_many :albums, :eager=>[:tags, {:tracks=>:tags}]
1093
+
1094
+ ==== :eager_loader
1095
+
1096
+ A custom loader to use when eagerly load associated objects via eager. If
1097
+ specified, should be a proc that takes three arguments: a key hash (used
1098
+ solely to enhance performance), an array of current model instances, and a
1099
+ hash of dependent associations to eagerly load. The proc is responsible for
1100
+ querying the database to retrieve all associated records for any of the model
1101
+ instances (the second argument), and modifying the associations cache for each
1102
+ record to correctly set the associated records for that record.
1103
+
1104
+ For many details and examples of custom eager loaders, please see the
1105
+ {Advanced Associations page}[link:files/doc/advanced_associations_rdoc.html].
1106
+
1107
+ ==== :eager_loader_key
1108
+
1109
+ A symbol for the key column to use to populate the key hash for the eager
1110
+ loader. It can be necessary to specify this for custom eager loaders
1111
+ where the default key that would be used does not exist, as in that case, Sequel
1112
+ would think that the key values are all NULL, and would not attempt to
1113
+ eagerly load any associated objects for that association. If you have a
1114
+ custom eager loader and aren't sure of a good value to use here, and you
1115
+ aren't using the key_hash (first argument to the eager_loader proc), then
1116
+ you can probably use the primary key column of the model.
1117
+
1118
+ ==== :eager_block
1119
+
1120
+ If given, should be a proc to use instead of the association method block
1121
+ when eagerly loading. To not use a block when eager loading when one is
1122
+ used normally, should to nil. It's very uncommon to need this option.
1123
+
1124
+ === Eager Loading via eager_graph (one query with joins) Options
1125
+
1126
+ ==== :eager_graph
1127
+
1128
+ The associations to eagerly load via eager_graph when loading the associated
1129
+ object(s). This is useful for example if you always want to eagerly load dependent
1130
+ associations when loading this association, but you want to filter or order the
1131
+ association based on dependent associations:
1132
+
1133
+ Artist.one_to_many :albums_with_short_tracks, :class=>:Album,
1134
+ :eager_graph=>:tracks do |ds|
1135
+ ds.filter{tracks__seconds < 120}
1136
+ end
1137
+ Artist.one_to_many :albums_by_track_name, :class=>:Album,
1138
+ :eager_graph=>:tracks do |ds|
1139
+ ds.order(:tracks__name)
1140
+ end
1141
+
1142
+ You can also use a hash or array of arguments for :eager_graph, similar to
1143
+ what the :eager option accepts.
1144
+
1145
+ ==== :graph_conditions
1146
+
1147
+ The additional conditions to use on the SQL join when eagerly loading the
1148
+ association via eager_graph. Should be a hash or an array of two element
1149
+ arrays. If not specified, the :conditions option is used if it is a hash or
1150
+ array of two element arrays.
1151
+
1152
+ Artist.one_to_many :active_albums, :class=>:Album,
1153
+ :graph_conditions=>{:active=>true}
1154
+
1155
+ Note that these conditions on the association are in addition to the default
1156
+ conditions specified by the foreign/primary keys. If you want to replace
1157
+ the conditions specified by the foreign/primary keys, you need the
1158
+ :graph_only_conditions options.
1159
+
1160
+ ==== :graph_block
1161
+
1162
+ The block to pass to Dataset#join_table when eagerly loading the association
1163
+ via eager_graph. This is useful to specify conditions that can't be specified
1164
+ in a hash or array of two element arrays.
1165
+
1166
+ Artist.one_to_many :gold_albums, :class=>:Album,
1167
+ :graph_block=>proc{|j,lj,js| :copies_sold.qualify(j) > 500000}
1168
+
1169
+ ==== :graph_join_type
1170
+
1171
+ The type of SQL join to use when eagerly loading the association via
1172
+ eager_graph. Defaults to :left_outer. This is useful if you want to
1173
+ ensure that all return only artists that have albums:
1174
+
1175
+ Artist.one_to_many :albums, :graph_join_type=>:inner
1176
+ # Will exclude artists without an album
1177
+ Artist.eager_graph(:albums).all
1178
+
1179
+ ==== :graph_select
1180
+
1181
+ A column or array of columns to select from the associated table
1182
+ when eagerly loading the association via eager_graph. Defaults to all
1183
+ columns in the associated table.
1184
+
1185
+ ==== :graph_only_conditions
1186
+
1187
+ The conditions to use on the SQL join when eagerly loading the association via
1188
+ eager_graph, instead of the default conditions specified by the
1189
+ foreign/primary keys. This option causes the :graph_conditions option to be
1190
+ ignored. This can be useful if the keys you are using are strings and you
1191
+ want to do a case insensitive comparison. For example, let's say that instead
1192
+ of integer keys, you used string keys based on the album or artist name, and
1193
+ that the album was associated to the artist by name. However, you weren't
1194
+ enforcing case sensitivity between the keys, so you still want to return albums
1195
+ where the artist's name differs in case:
1196
+
1197
+ Artist.one_to_many :albums, :key=>:artist_name,
1198
+ :graph_only_conditions=>nil,
1199
+ :graph_block=>proc{|j,lj,js| {:lower.sql_function(artist_name.qualify(j))=>
1200
+ :lower.sql_function(name.qualify(lj))}}
1201
+
1202
+ Note how :graph_only_conditions is set to nil to ignore any existing conditions,
1203
+ and :graph_block is used to set up the case insensitive comparison.
1204
+
1205
+ Another case where :graph_only_conditions may be used is if you want to use
1206
+ a JOIN USING or NATURAL JOIN for the graph:
1207
+
1208
+ # JOIN USING
1209
+ Artist.one_to_many :albums, :key=>:artist_name,
1210
+ :graph_only_conditions=>[:artist_name]
1211
+
1212
+ # NATURAL JOIN
1213
+ Artist.one_to_many :albums, :key=>:artist_name,
1214
+ :graph_only_conditions=>nil, :graph_join_type=>:natural
1215
+
1216
+ ==== :eager_grapher
1217
+
1218
+ Sets up a custom grapher to use when eager loading the objects via eager_graph.
1219
+ This is the eager_graph analogue to the :eager_loader option.
1220
+
1221
+ If specified, should be a proc that accepts three three arguments: a dataset,
1222
+ an alias to use for the table to graph for this association, and the alias that
1223
+ was used for the current table (since you can cascade associations). Should
1224
+ return a modified copy of the dataset with the association graphed into it.
1225
+
1226
+ Artist.one_to_many :self_title_albums, :class=>:Album,
1227
+ :eager_grapher=>(proc do |ds, ta, iq|
1228
+ ds.graph(Album, {:artist_id=>:id, :name=>:name},
1229
+ :table_alias=>ta, :implicit_qualifier=>iq)
1230
+ end)
1231
+
1232
+ This isn't generally needed, as one of the other eager_graph related
1233
+ association options is usually sufficient.
1234
+
1235
+ ==== :order_eager_graph
1236
+
1237
+ Whether to add the order to the dataset's order when graphing via eager_graph.
1238
+ Defaults to true, so set to false to disable.
1239
+
1240
+ Sequel has to do some guess work when attempting to add the association's
1241
+ order to an eager_graphed dataset. In most cases it does so correctly, but
1242
+ if it has problems, you'll probably want to set this option to false.
1243
+
1244
+ ==== :graph_join_table_conditions [+many_to_many+]
1245
+
1246
+ The additional conditions to use on the SQL join for the join table when
1247
+ eagerly loading the association via eager_graph. Should be a hash or an array
1248
+ of two element arrays.
1249
+
1250
+ Let's say you have a database of people, colleges, and a table called
1251
+ degrees_received that includes a string field specifying the name of the
1252
+ degree, and you want to eager load all colleges for people where the person
1253
+ has received a specific degree:
1254
+
1255
+ Person.many_to_many :bs_degree_colleges, :class=>:College,
1256
+ :join_table=>:degrees_received,
1257
+ :graph_join_table_conditions=>{:degree=>'BS'}
1258
+
1259
+ ==== :graph_join_table_block [+many_to_many+]
1260
+
1261
+ The block to pass to join_table for the join table when eagerly loading the
1262
+ association via eager_graph. This is used for similar reasons as :graph_block,
1263
+ but is only used for +many_to_many+ associations when graphing the join
1264
+ table into the dataset. It's used in the same place as
1265
+ :graph_join_table_conditions but like :graph_block, is needed for situations
1266
+ where the conditions can't be specified as a hash or array of two element
1267
+ arrays.
1268
+
1269
+ Let's say you have a database of people, colleges, and a table called
1270
+ degrees_received that includes a string field specifying the name of the
1271
+ degree, and you want to eager load all colleges for people where the person
1272
+ has received a bachelor's degree (degree starting with B):
1273
+
1274
+ Person.many_to_many :bachelor_degree_colleges, :class=>:College,
1275
+ :join_table=>:degrees_received,
1276
+ :graph_join_table_block=>proc{|j,lj,js| :degree.qualify(j).like('B%')}
1277
+
1278
+ This should be done when graphing the join table, instead of when graphing the
1279
+ final table, as :degree is a column of the join table.
1280
+
1281
+ ==== :graph_join_table_join_type [+many_to_many+]
1282
+
1283
+ The type of SQL join to use for the join table when eagerly loading the
1284
+ association via eager_graph. Defaults to the :graph_join_type option or
1285
+ :left_outer. This exists mainly for consistency in the unlikely case that
1286
+ you want to use a different join type when JOINing to the join table then
1287
+ you want to use for JOINing to the final table
1288
+
1289
+ ==== :graph_join_table_only_conditions [+many_to_many+]
1290
+
1291
+ The conditions to use on the SQL join for the join table when eagerly loading
1292
+ the association via eager_graph, instead of the default conditions specified
1293
+ by the foreign/primary keys. This option causes the
1294
+ :graph_join_table_conditions option to be ignored. This is only useful if
1295
+ you want to replace the default foreign/primary key conditions that Sequel
1296
+ would use when eagerly graphing.
1297
+
1298
+ === Advanced Options
1299
+
1300
+ ==== :reciprocal
1301
+
1302
+ The symbol name of the reciprocal association, if it exists. By default,
1303
+ Sequel will try to determine it by looking at the associated model's
1304
+ assocations for a association that matches the current association's key(s).
1305
+ Set to nil to not use a reciprocal.
1306
+
1307
+ Reciprocals are used in Sequel to modify the matching cached associations
1308
+ in associated objects when calling association methods on the current object.
1309
+ For example, when you retrieve objects in a one_to_many association, it'll
1310
+ automatically set the matching many_to_one association in the associated
1311
+ objects. The result of this is that code that does this:
1312
+
1313
+ @artist.albums.each{|album| album.artist.name}
1314
+
1315
+ only does one database query, because when the @artist's albums are retrieved,
1316
+ the cached artist association for each album is set to @artist.
1317
+
1318
+ In addition to the one_to_many retrieval case, the association modification
1319
+ methods affect the reciprocals as well:
1320
+
1321
+ # Sets the cached artist association for @album to @artist
1322
+ @artist.add_album(@album)
1323
+
1324
+ # Sets the cached artist association for @album to nil
1325
+ @artist.remove_album(@album)
1326
+
1327
+ # Sets the cached artist association to nil for the @artist's
1328
+ # cached albums association
1329
+ @artist.remove_all_albums
1330
+
1331
+ # Remove @album from the artist1's cached albums association, and add @album
1332
+ # to @artist2's cached albums association.
1333
+ @album.artist # @artist1
1334
+ @album.artist = @artist2
1335
+
1336
+ Sequel can usually guess the correct reciprocal, but if you have multiple
1337
+ associations to the same associated class that use the same keys, you may
1338
+ want to specify the :reciprocal option manually to ensure the correct
1339
+ one is used.
1340
+
1341
+ ==== :read_only
1342
+
1343
+ For +many_to_one+ and +one_to_one+ associations, do not add a setter method.
1344
+ For +one_to_many+ and +many_to_many+, do not add the add_<i>association</i>,
1345
+ remove_<i>association</i>, or remove_all_<i>association</i> methods.
1346
+
1347
+ If the default modification methods would not do what you want, and you
1348
+ don't plan on overriding the internal modification methods to do what you
1349
+ want, it may be best to set this option to true.
1350
+
1351
+ ==== :validate
1352
+
1353
+ Set to false to not validate when implicitly saving any associated object.
1354
+ When using the +one_to_many+ association modification methods, the +one_to_one+
1355
+ setter method, or creating a new object by passing a hash to the
1356
+ add_<i>association</i> method, Sequel will automatically save the object.
1357
+ If you don't want to validate objects when these implicit saves are done,
1358
+ the validate option should be set to false.
1359
+
1360
+ ==== :allow_eager
1361
+
1362
+ If set to false, you cannot load the association eagerly via eager or
1363
+ eager_graph.
1364
+
1365
+ Artist.one_to_many :albums, :allow_eager=>false
1366
+ Artist.eager(:albums) # Raises Sequel::Error
1367
+
1368
+ This is usually used if the association dataset depends on specific values in
1369
+ model instance that would not be valid when eager loading for multiple
1370
+ instances.
1371
+
1372
+ ==== :cartesian_product_number
1373
+
1374
+ The number of joins completed by this association that could cause more
1375
+ than one row for each row in the current table (default: 0 for *_to_one
1376
+ associations, 1 for *_to_many associations).
1377
+
1378
+ This should only be modified in specific cases. For example, if you have
1379
+ a one_to_one association that can actually return more than one row
1380
+ (where the default association method will just return the first), or
1381
+ a many_to_many association where there is a unique index in the join table
1382
+ so that you know only one object will ever be associated through the
1383
+ association.