sequel 3.21.0 → 3.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. data/CHANGELOG +855 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +23 -7
  4. data/Rakefile +42 -24
  5. data/bin/sequel +26 -8
  6. data/doc/active_record.rdoc +1 -0
  7. data/doc/advanced_associations.rdoc +171 -11
  8. data/doc/association_basics.rdoc +293 -43
  9. data/doc/dataset_basics.rdoc +5 -5
  10. data/doc/dataset_filtering.rdoc +8 -0
  11. data/doc/mass_assignment.rdoc +56 -0
  12. data/doc/migration.rdoc +85 -552
  13. data/doc/model_hooks.rdoc +78 -27
  14. data/doc/object_model.rdoc +541 -0
  15. data/doc/opening_databases.rdoc +97 -50
  16. data/doc/prepared_statements.rdoc +40 -14
  17. data/doc/querying.rdoc +28 -4
  18. data/doc/reflection.rdoc +30 -4
  19. data/doc/release_notes/3.22.0.txt +39 -0
  20. data/doc/release_notes/3.23.0.txt +172 -0
  21. data/doc/release_notes/3.24.0.txt +420 -0
  22. data/doc/release_notes/3.25.0.txt +88 -0
  23. data/doc/release_notes/3.26.0.txt +88 -0
  24. data/doc/release_notes/3.27.0.txt +82 -0
  25. data/doc/release_notes/3.28.0.txt +304 -0
  26. data/doc/release_notes/3.29.0.txt +459 -0
  27. data/doc/release_notes/3.30.0.txt +135 -0
  28. data/doc/release_notes/3.31.0.txt +146 -0
  29. data/doc/release_notes/3.32.0.txt +202 -0
  30. data/doc/release_notes/3.33.0.txt +157 -0
  31. data/doc/release_notes/3.34.0.txt +671 -0
  32. data/doc/release_notes/3.35.0.txt +144 -0
  33. data/doc/release_notes/3.36.0.txt +245 -0
  34. data/doc/schema_modification.rdoc +572 -0
  35. data/doc/sharding.rdoc +95 -3
  36. data/doc/testing.rdoc +129 -0
  37. data/doc/thread_safety.rdoc +17 -0
  38. data/doc/transactions.rdoc +137 -0
  39. data/doc/virtual_rows.rdoc +51 -2
  40. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  41. data/lib/sequel/adapters/ado.rb +40 -18
  42. data/lib/sequel/adapters/amalgalite.rb +17 -9
  43. data/lib/sequel/adapters/db2.rb +175 -86
  44. data/lib/sequel/adapters/dbi.rb +15 -15
  45. data/lib/sequel/adapters/do/mysql.rb +17 -11
  46. data/lib/sequel/adapters/do/postgres.rb +1 -57
  47. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  48. data/lib/sequel/adapters/do.rb +18 -36
  49. data/lib/sequel/adapters/firebird.rb +27 -208
  50. data/lib/sequel/adapters/ibmdb.rb +453 -0
  51. data/lib/sequel/adapters/informix.rb +6 -23
  52. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  53. data/lib/sequel/adapters/jdbc/db2.rb +47 -0
  54. data/lib/sequel/adapters/jdbc/derby.rb +287 -0
  55. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  56. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  57. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  58. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  59. data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  61. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  62. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
  64. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  65. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  66. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  67. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  68. data/lib/sequel/adapters/jdbc.rb +265 -94
  69. data/lib/sequel/adapters/mock.rb +361 -0
  70. data/lib/sequel/adapters/mysql.rb +118 -222
  71. data/lib/sequel/adapters/mysql2.rb +58 -57
  72. data/lib/sequel/adapters/odbc/mssql.rb +15 -7
  73. data/lib/sequel/adapters/odbc.rb +28 -9
  74. data/lib/sequel/adapters/openbase.rb +3 -5
  75. data/lib/sequel/adapters/oracle.rb +349 -53
  76. data/lib/sequel/adapters/postgres.rb +356 -107
  77. data/lib/sequel/adapters/shared/access.rb +32 -9
  78. data/lib/sequel/adapters/shared/db2.rb +342 -0
  79. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  80. data/lib/sequel/adapters/shared/informix.rb +53 -0
  81. data/lib/sequel/adapters/shared/mssql.rb +335 -118
  82. data/lib/sequel/adapters/shared/mysql.rb +340 -76
  83. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  84. data/lib/sequel/adapters/shared/oracle.rb +243 -45
  85. data/lib/sequel/adapters/shared/postgres.rb +524 -279
  86. data/lib/sequel/adapters/shared/progress.rb +5 -8
  87. data/lib/sequel/adapters/shared/sqlite.rb +265 -89
  88. data/lib/sequel/adapters/sqlite.rb +101 -39
  89. data/lib/sequel/adapters/swift/mysql.rb +9 -12
  90. data/lib/sequel/adapters/swift/postgres.rb +9 -74
  91. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  92. data/lib/sequel/adapters/swift.rb +8 -7
  93. data/lib/sequel/adapters/tinytds.rb +161 -21
  94. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  95. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  96. data/lib/sequel/ast_transformer.rb +194 -0
  97. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  98. data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
  99. data/lib/sequel/connection_pool/single.rb +5 -0
  100. data/lib/sequel/connection_pool/threaded.rb +38 -14
  101. data/lib/sequel/connection_pool.rb +10 -2
  102. data/lib/sequel/core.rb +118 -11
  103. data/lib/sequel/database/connecting.rb +38 -28
  104. data/lib/sequel/database/dataset.rb +4 -4
  105. data/lib/sequel/database/dataset_defaults.rb +63 -2
  106. data/lib/sequel/database/logging.rb +7 -2
  107. data/lib/sequel/database/misc.rb +150 -46
  108. data/lib/sequel/database/query.rb +215 -65
  109. data/lib/sequel/database/schema_generator.rb +64 -20
  110. data/lib/sequel/database/schema_methods.rb +212 -54
  111. data/lib/sequel/dataset/actions.rb +322 -85
  112. data/lib/sequel/dataset/features.rb +96 -8
  113. data/lib/sequel/dataset/graph.rb +38 -11
  114. data/lib/sequel/dataset/misc.rb +50 -23
  115. data/lib/sequel/dataset/mutation.rb +12 -7
  116. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  117. data/lib/sequel/dataset/query.rb +237 -44
  118. data/lib/sequel/dataset/sql.rb +698 -278
  119. data/lib/sequel/dataset.rb +8 -0
  120. data/lib/sequel/exceptions.rb +4 -0
  121. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  122. data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
  123. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  124. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
  125. data/lib/sequel/extensions/migration.rb +97 -11
  126. data/lib/sequel/extensions/named_timezones.rb +5 -0
  127. data/lib/sequel/extensions/null_dataset.rb +90 -0
  128. data/lib/sequel/extensions/pg_array.rb +460 -0
  129. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  130. data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
  131. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  132. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  133. data/lib/sequel/extensions/pg_inet.rb +89 -0
  134. data/lib/sequel/extensions/pg_json.rb +178 -0
  135. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  136. data/lib/sequel/extensions/pretty_table.rb +5 -71
  137. data/lib/sequel/extensions/query.rb +1 -1
  138. data/lib/sequel/extensions/query_literals.rb +79 -0
  139. data/lib/sequel/extensions/schema_caching.rb +76 -0
  140. data/lib/sequel/extensions/schema_dumper.rb +251 -37
  141. data/lib/sequel/extensions/select_remove.rb +35 -0
  142. data/lib/sequel/extensions/server_block.rb +139 -0
  143. data/lib/sequel/extensions/sql_expr.rb +4 -110
  144. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  145. data/lib/sequel/extensions/to_dot.rb +95 -83
  146. data/lib/sequel/model/associations.rb +1187 -393
  147. data/lib/sequel/model/base.rb +578 -170
  148. data/lib/sequel/model/errors.rb +1 -1
  149. data/lib/sequel/model/exceptions.rb +5 -1
  150. data/lib/sequel/model/inflections.rb +1 -1
  151. data/lib/sequel/model.rb +30 -11
  152. data/lib/sequel/no_core_ext.rb +2 -0
  153. data/lib/sequel/plugins/active_model.rb +13 -1
  154. data/lib/sequel/plugins/association_pks.rb +22 -4
  155. data/lib/sequel/plugins/caching.rb +25 -18
  156. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  157. data/lib/sequel/plugins/composition.rb +44 -12
  158. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  159. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  160. data/lib/sequel/plugins/dirty.rb +214 -0
  161. data/lib/sequel/plugins/eager_each.rb +59 -0
  162. data/lib/sequel/plugins/force_encoding.rb +6 -6
  163. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  164. data/lib/sequel/plugins/identity_map.rb +123 -8
  165. data/lib/sequel/plugins/instance_filters.rb +10 -0
  166. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  167. data/lib/sequel/plugins/json_serializer.rb +58 -6
  168. data/lib/sequel/plugins/list.rb +12 -2
  169. data/lib/sequel/plugins/many_through_many.rb +79 -28
  170. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  171. data/lib/sequel/plugins/nested_attributes.rb +139 -63
  172. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  173. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  174. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  175. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  176. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  177. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  178. data/lib/sequel/plugins/schema.rb +7 -2
  179. data/lib/sequel/plugins/serialization.rb +98 -49
  180. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  181. data/lib/sequel/plugins/sharding.rb +21 -54
  182. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  183. data/lib/sequel/plugins/static_cache.rb +99 -0
  184. data/lib/sequel/plugins/subclasses.rb +10 -2
  185. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  186. data/lib/sequel/plugins/timestamps.rb +1 -1
  187. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  188. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  189. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  190. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  191. data/lib/sequel/sql.rb +526 -59
  192. data/lib/sequel/timezones.rb +57 -38
  193. data/lib/sequel/version.rb +1 -1
  194. data/spec/adapters/db2_spec.rb +146 -0
  195. data/spec/adapters/firebird_spec.rb +1 -1
  196. data/spec/adapters/mssql_spec.rb +142 -40
  197. data/spec/adapters/mysql_spec.rb +380 -234
  198. data/spec/adapters/oracle_spec.rb +67 -77
  199. data/spec/adapters/postgres_spec.rb +1050 -212
  200. data/spec/adapters/spec_helper.rb +8 -5
  201. data/spec/adapters/sqlite_spec.rb +139 -27
  202. data/spec/core/connection_pool_spec.rb +196 -93
  203. data/spec/core/database_spec.rb +879 -510
  204. data/spec/core/dataset_spec.rb +1415 -1086
  205. data/spec/core/expression_filters_spec.rb +554 -109
  206. data/spec/core/mock_adapter_spec.rb +449 -0
  207. data/spec/core/object_graph_spec.rb +86 -114
  208. data/spec/core/schema_generator_spec.rb +4 -4
  209. data/spec/core/schema_spec.rb +482 -38
  210. data/spec/core/spec_helper.rb +6 -48
  211. data/spec/extensions/active_model_spec.rb +13 -0
  212. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  213. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  214. data/spec/extensions/association_dependencies_spec.rb +15 -25
  215. data/spec/extensions/association_pks_spec.rb +66 -32
  216. data/spec/extensions/association_proxies_spec.rb +4 -4
  217. data/spec/extensions/caching_spec.rb +47 -51
  218. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  219. data/spec/extensions/columns_introspection_spec.rb +91 -0
  220. data/spec/extensions/composition_spec.rb +18 -13
  221. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
  222. data/spec/extensions/dataset_associations_spec.rb +199 -0
  223. data/spec/extensions/defaults_setter_spec.rb +64 -0
  224. data/spec/extensions/dirty_spec.rb +155 -0
  225. data/spec/extensions/eager_each_spec.rb +34 -0
  226. data/spec/extensions/force_encoding_spec.rb +4 -2
  227. data/spec/extensions/hook_class_methods_spec.rb +69 -92
  228. data/spec/extensions/identity_map_spec.rb +131 -22
  229. data/spec/extensions/inflector_spec.rb +0 -4
  230. data/spec/extensions/instance_filters_spec.rb +11 -21
  231. data/spec/extensions/instance_hooks_spec.rb +72 -0
  232. data/spec/extensions/json_serializer_spec.rb +49 -6
  233. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  234. data/spec/extensions/list_spec.rb +48 -39
  235. data/spec/extensions/many_through_many_spec.rb +283 -250
  236. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  237. data/spec/extensions/migration_spec.rb +140 -35
  238. data/spec/extensions/named_timezones_spec.rb +29 -11
  239. data/spec/extensions/nested_attributes_spec.rb +251 -89
  240. data/spec/extensions/null_dataset_spec.rb +85 -0
  241. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  242. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  243. data/spec/extensions/pg_array_spec.rb +196 -0
  244. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  245. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  246. data/spec/extensions/pg_hstore_spec.rb +195 -0
  247. data/spec/extensions/pg_inet_spec.rb +44 -0
  248. data/spec/extensions/pg_json_spec.rb +101 -0
  249. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  250. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  251. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  252. data/spec/extensions/prepared_statements_spec.rb +87 -0
  253. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  254. data/spec/extensions/pretty_table_spec.rb +7 -6
  255. data/spec/extensions/query_literals_spec.rb +168 -0
  256. data/spec/extensions/query_spec.rb +6 -0
  257. data/spec/extensions/rcte_tree_spec.rb +50 -43
  258. data/spec/extensions/schema_caching_spec.rb +41 -0
  259. data/spec/extensions/schema_dumper_spec.rb +429 -22
  260. data/spec/extensions/schema_spec.rb +25 -21
  261. data/spec/extensions/select_remove_spec.rb +38 -0
  262. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  263. data/spec/extensions/serialization_spec.rb +85 -43
  264. data/spec/extensions/server_block_spec.rb +90 -0
  265. data/spec/extensions/sharding_spec.rb +69 -143
  266. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  267. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  268. data/spec/extensions/spec_helper.rb +22 -61
  269. data/spec/extensions/sql_expr_spec.rb +29 -60
  270. data/spec/extensions/static_cache_spec.rb +145 -0
  271. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  272. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  273. data/spec/extensions/timestamps_spec.rb +6 -6
  274. data/spec/extensions/to_dot_spec.rb +4 -7
  275. data/spec/extensions/touch_spec.rb +13 -14
  276. data/spec/extensions/tree_spec.rb +11 -26
  277. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  278. data/spec/extensions/update_primary_key_spec.rb +30 -24
  279. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  280. data/spec/extensions/validation_helpers_spec.rb +16 -35
  281. data/spec/extensions/xml_serializer_spec.rb +29 -4
  282. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  283. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  284. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  285. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  286. data/spec/integration/associations_test.rb +659 -21
  287. data/spec/integration/database_test.rb +9 -3
  288. data/spec/integration/dataset_test.rb +605 -91
  289. data/spec/integration/eager_loader_test.rb +19 -21
  290. data/spec/integration/migrator_test.rb +2 -3
  291. data/spec/integration/model_test.rb +81 -2
  292. data/spec/integration/plugin_test.rb +454 -143
  293. data/spec/integration/prepared_statement_test.rb +263 -128
  294. data/spec/integration/schema_test.rb +309 -43
  295. data/spec/integration/spec_helper.rb +40 -30
  296. data/spec/integration/timezone_test.rb +38 -12
  297. data/spec/integration/transaction_test.rb +183 -8
  298. data/spec/integration/type_test.rb +18 -4
  299. data/spec/model/association_reflection_spec.rb +201 -7
  300. data/spec/model/associations_spec.rb +1067 -661
  301. data/spec/model/base_spec.rb +329 -95
  302. data/spec/model/dataset_methods_spec.rb +7 -27
  303. data/spec/model/eager_loading_spec.rb +677 -676
  304. data/spec/model/hooks_spec.rb +349 -67
  305. data/spec/model/model_spec.rb +240 -168
  306. data/spec/model/plugins_spec.rb +24 -13
  307. data/spec/model/record_spec.rb +490 -232
  308. data/spec/model/spec_helper.rb +14 -71
  309. data/spec/model/validations_spec.rb +11 -0
  310. data/spec/rcov.opts +2 -0
  311. metadata +178 -80
@@ -247,7 +247,7 @@ example is a tree structure:
247
247
 
248
248
  class Node
249
249
  many_to_one :parent, :class=>self
250
- one_to_many :children :key=>:parent_id, :class=>self
250
+ one_to_many :children, :key=>:parent_id, :class=>self
251
251
  end
252
252
 
253
253
  For many_to_many self_referential associations, it's fairly similar. Here's
@@ -293,32 +293,6 @@ Examples:
293
293
  @artist.remove_album(@album)
294
294
  @artist.remove_all_albums
295
295
 
296
- == Dataset Method
297
-
298
- In addition to the above methods, associations also add a instance method
299
- ending in +_dataset+ 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
296
  == Caching
323
297
 
324
298
  Associations are cached after being retrieved:
@@ -352,13 +326,150 @@ instance method:
352
326
  @album.artists # [<Artist ...>, ...]
353
327
  @album.associations[:artists] # [<Artist ...>, ...]
354
328
 
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:
329
+ == Dataset Method
330
+
331
+ In addition to the above methods, associations also add a instance method
332
+ ending in +_dataset+ that returns a dataset representing the objects in the associated table:
333
+
334
+ @album.artist_id
335
+ # 10
336
+ @album.artist_dataset
337
+ # SELECT * FROM artists WHERE (id = 10)
338
+
339
+ @artist.id
340
+ # 20
341
+ @artist.albums_dataset
342
+ # SELECT * FROM albums WHERE (artist_id = 20)
343
+
344
+ The association dataset is just like any other Sequel dataset, in that
345
+ it can be further filtered, ordered, etc.:
346
+
347
+ @artist.albums_dataset.
348
+ filter(:name.like('A%')).
349
+ order(:copies_sold).
350
+ limit(10)
351
+ # SELECT * FROM albums
352
+ # WHERE ((artist_id = 20) AND (name LIKE 'A%'))
353
+ # ORDER BY copies_sold LIMIT 10
354
+
355
+ Records retrieved using the +_dataset+ method are not cached in the
356
+ associations cache.
358
357
 
359
358
  @album.artists_dataset.all # [<Artist ...>, ...]
360
359
  @album.associations[:artists] # nil
361
360
 
361
+ == Dynamic Association Modification
362
+
363
+ Similar to the +_dataset+ method, you can provide a block to the association
364
+ method to customize the dataset that will be used to retrieve the records. So
365
+ you can apply a filter in either of these two ways:
366
+
367
+ @artist.albums_dataset.filter(:name.like('A%'))
368
+ @artist.albums{|ds| ds.filter(:name.like('A%'))}
369
+
370
+ While they both apply the same filter, using the +_dataset+ method does not
371
+ apply any of the association callbacks or handle association reciprocals (see
372
+ below for details about callbacks and reciprocals). Using a block instead handles
373
+ all those things, and also caches its results in the associations cache (ignoring
374
+ any previously cached value).
375
+
376
+ Note that if you are using ruby 1.8.6, you can't pass a block to the association
377
+ method, you have to pass a proc as an argument:
378
+
379
+ @artist.albums(proc{|ds| ds.filter(:name.like('A%'))})
380
+
381
+ == Filtering By Associations
382
+
383
+ In addition to using the association method to get associated objects, you
384
+ can also use associated objects in filters. For example, to get
385
+ all albums for a given artist, you would usually do:
386
+
387
+ @artist.albums
388
+ # or @artist.albums_dataset for a dataset
389
+
390
+ You can also do the following:
391
+
392
+ Album.filter(:artist=>@artist).all
393
+ # or leave off the .all for a dataset
394
+
395
+ For filtering by a single association, this isn't very useful. However, unlike
396
+ using the association method, using a filter allows you to filter by multiple
397
+ associations:
398
+
399
+ Album.filter(:artist=>@artist, :publisher=>@publisher)
400
+
401
+ This will return all albums by that artist and published by that publisher.
402
+ This isn't possible using just the association method approach, though you
403
+ can combine the approaches:
404
+
405
+ @artist.albums_dataset.filter(:publisher=>@publisher)
406
+
407
+ This doesn't just work for +many_to_one+ associations, it also works for
408
+ +one_to_one+, +one_to_many+, and +many_to_many+ associations:
409
+
410
+ Album.one_to_one :album_info
411
+ # The album related to that AlbumInfo instance
412
+ Album.filter(:album_info=>AlbumInfo[2])
413
+
414
+ Album.one_to_many :tracks
415
+ # The album related to that Track instance
416
+ Album.filter(:tracks=>Track[3])
417
+
418
+ Album.many_to_many :tags
419
+ # All albums related to that Tag instance
420
+ Album.filter(:tags=>Tag[4])
421
+
422
+ Note that for +one_to_many+ and +many_to_many+ associations, you still
423
+ use the plural form even though only a single model object is given.
424
+
425
+ You can also exclude by associations:
426
+
427
+ Album.exclude(:artist=>@artist).all
428
+
429
+ This will return all albums not by that artist.
430
+
431
+ You can also provide an array with multiple model objects:
432
+
433
+ Album.filter(:artist=>[@artist1, @artist2]).all
434
+
435
+ Similar to using an array of integers or strings, this will return
436
+ all albums whose artist is one of those two artists. You can also
437
+ use +exclude+ if you want all albums not by either of those artists:
438
+
439
+ Album.exclude(:artist=>[@artist1, @artist2]).all
440
+
441
+ If you are using a +one_to_many+ or +many_to_many+ association, you
442
+ may want to return records where the records matches all of multiple
443
+ records, instead of matching any of them. For example:
444
+
445
+ Album.filter(:tags=>[@tag1, @tag2])
446
+
447
+ This matches albums that are associated with either @tag1 or @tag2 or
448
+ both. If you only want ones that you are associated with both, you can
449
+ use separate filter calls:
450
+
451
+ Album.filter(:tags=>@tag1).filter(:tags=>@tag2)
452
+
453
+ Or the the array form of condition specifiers:
454
+
455
+ Album.filter([[:tags, @tag1], [:tags, @tag2]])
456
+
457
+ These will return albums associated with both @tag1 and @tag2.
458
+
459
+ You can also provide a dataset value when filtering by associations:
460
+
461
+ Album.filter(:artist=>Artist.filter(:name.like('A%'))).all
462
+
463
+ This will return all albums whose artist starts with 'A'. Like
464
+ the other forms, this can be inverted:
465
+
466
+ Album.exclude(:artist=>Artist.filter(:name.like('A%'))).all
467
+
468
+ This will return all albums whose artist does not start with 'A'.
469
+
470
+ Note that filtering by associations only works correctly for simple
471
+ associations (ones without conditions).
472
+
362
473
  == Name Collisions
363
474
 
364
475
  Because associations create instance methods, it's possible to override
@@ -368,7 +479,7 @@ would be bad association names.
368
479
 
369
480
  == Database Schema
370
481
 
371
- Creating an association, doesn't modify the database schema. Sequel
482
+ Creating an association doesn't modify the database schema. Sequel
372
483
  assumes your associations reflect the existing database schema. If not,
373
484
  you should modify your schema before creating the associations.
374
485
 
@@ -1055,7 +1166,7 @@ when eager loading via eager_graph, but called when eager loading via eager.
1055
1166
  class Artist
1056
1167
  # Cache all album names to a single string when retrieving the
1057
1168
  # albums.
1058
- one_to_many :albums, :after_add=>:cache_album_names
1169
+ one_to_many :albums, :after_load=>:cache_album_names
1059
1170
 
1060
1171
  attr_reader :album_names
1061
1172
 
@@ -1218,25 +1329,44 @@ a JOIN USING or NATURAL JOIN for the graph:
1218
1329
  Artist.one_to_many :albums, :key=>:artist_name,
1219
1330
  :graph_only_conditions=>nil, :graph_join_type=>:natural
1220
1331
 
1332
+ ==== :graph_alias_base
1333
+
1334
+ The base name to use for the table alias when eager graphing. Defaults to the name
1335
+ of the association. If the alias name has already been used in the query, Sequel will create
1336
+ a unique alias by appending a numeric suffix (e.g. alias_0, alias_1, ...) until the alias is
1337
+ unique.
1338
+
1339
+ This is mostly useful if you have associations with the same name in many models, and you want
1340
+ to be able to easily tell which table alias corresponds to which association when eagerly
1341
+ graphing multiple associations with the same name.
1342
+
1221
1343
  ==== :eager_grapher
1222
1344
 
1223
1345
  Sets up a custom grapher to use when eager loading the objects via eager_graph.
1224
- This is the eager_graph analogue to the :eager_loader option.
1346
+ This is the eager_graph analogue to the :eager_loader option. This isn't generally
1347
+ needed, as one of the other eager_graph related association options is usually sufficient.
1348
+
1349
+ If specified, should be a proc that accepts one or three three arguments.
1350
+ If the proc takes one argument, it will be given a hash with the following keys:
1225
1351
 
1226
- If specified, should be a proc that accepts three three arguments: a dataset,
1227
- an alias to use for the table to graph for this association, and the alias that
1228
- was used for the current table (since you can cascade associations). Should
1229
- return a modified copy of the dataset with the association graphed into it.
1352
+ :self :: The dataset that is doing the eager loading
1353
+ :table_alias :: An alias to use for the table to graph for this association.
1354
+ :implicit_qualifier :: The alias that was used for the current table (since you can cascade associations).
1355
+ :callback :: A callback proc used to dynamically modify the dataset to graph into the
1356
+ current dataset, before such graphing is done. This is nil if no callback
1357
+ proc is used.
1358
+
1359
+ If the proc takes three arguments, it gets passed the :self, :association_alias,
1360
+ and :table_alias values. The 3 argument procs are allowed for backwards
1361
+ compatibility, and it is recommended to use the 1 argument proc format
1362
+ for new code.
1230
1363
 
1231
1364
  Artist.one_to_many :self_title_albums, :class=>:Album,
1232
- :eager_grapher=>(proc do |ds, ta, iq|
1233
- ds.graph(Album, {:artist_id=>:id, :name=>:name},
1234
- :table_alias=>ta, :implicit_qualifier=>iq)
1365
+ :eager_grapher=>(proc do |eo|
1366
+ eo[:self].graph(Album, {:artist_id=>:id, :name=>:name},
1367
+ :table_alias=>eo[:table_alias], :implicit_qualifier=>eo[:implicit_qualifier])
1235
1368
  end)
1236
1369
 
1237
- This isn't generally needed, as one of the other eager_graph related
1238
- association options is usually sufficient.
1239
-
1240
1370
  ==== :order_eager_graph
1241
1371
 
1242
1372
  Whether to add the order to the dataset's order when graphing via eager_graph.
@@ -1300,6 +1430,78 @@ by the foreign/primary keys. This option causes the
1300
1430
  you want to replace the default foreign/primary key conditions that Sequel
1301
1431
  would use when eagerly graphing.
1302
1432
 
1433
+ === Column Naming Conflict Options
1434
+
1435
+ Sequel's association support historically called methods on model objects
1436
+ to get primary key or foreign key values instead of accessing the column
1437
+ values directly, in order to allow advanced features such as associations
1438
+ based on virtual column keys. Unfortunately, that causes issues if columns
1439
+ are used with names that clash with existing method names, which can happen
1440
+ if you want to name the association the same name as an existing column, or
1441
+ if the column has the same name as an already defined method such as
1442
+ <tt>object_id</tt>.
1443
+
1444
+ Sequel has added the following options that allow you to work around the
1445
+ issue by either specifying the column name symbol or the method name symbol
1446
+ to use. In most cases, these methods are designed to be used with column
1447
+ aliases defined with <tt>Model.def_column_alias</tt>:
1448
+
1449
+ # Example schema:
1450
+ # albums artists
1451
+ # :id /--> :id
1452
+ # :artist --/ :name
1453
+ # :name
1454
+ class Album < Sequel::Model
1455
+ def_column_alias(:artist_id, :artist)
1456
+ many_to_one :artist, :key=>:artist_id, :key_column=>:artist
1457
+ end
1458
+
1459
+ # Example schema:
1460
+ # things objs
1461
+ # :id /--> :id
1462
+ # :object_id --/ :name
1463
+ # :name
1464
+ class Thing < Sequel::Model
1465
+ def_column_alias(:obj_id, :object_id)
1466
+ end
1467
+ class Obj < Sequel::Model
1468
+ many_to_one :things, :key=>:object_id, :key_method=>:obj_id
1469
+ end
1470
+
1471
+ Note that for eager loading purposes, you generally need to set the
1472
+ <tt>:eager_loader_key</tt> option as well, specifying the underlying
1473
+ column(s) to use.
1474
+
1475
+ ==== :key_column [+many_to_one+]
1476
+
1477
+ Like the :key option, but :key references the method name, while
1478
+ :key_column references the underlying column.
1479
+
1480
+ ==== :primary_key_method [+many_to_one+]
1481
+
1482
+ Like the :primary_key option, but :primary_key references the column
1483
+ name, while :primary_key_method references the method name.
1484
+
1485
+ ==== :primary_key_column [+one_to_many+, +one_to_one+]
1486
+
1487
+ Like the :primary_key option, but :primary_key references the method name, while
1488
+ :primary_key_column references the underlying column.
1489
+
1490
+ ==== :key_method [+one_to_many+, +one_to_one+]
1491
+
1492
+ Like the :key option, but :key references the column
1493
+ name, while :key_method references the method name.
1494
+
1495
+ ==== :left_primary_key_column [+many_to_many+]
1496
+
1497
+ Like the :left_primary_key option, but :left_primary_key references the method name, while
1498
+ :left_primary_key_column references the underlying column.
1499
+
1500
+ ==== :right_primary_key_method [+many_to_many+]
1501
+
1502
+ Like the :right_primary_key option, but :right_primary_key references the column
1503
+ name, while :right_primary_key_method references the method name.
1504
+
1303
1505
  === Advanced Options
1304
1506
 
1305
1507
  ==== :reciprocal
@@ -1399,3 +1601,51 @@ associations depends on another plugin that defines instance methods of
1399
1601
  the same name. In that case, the instance methods of the dependent
1400
1602
  plugin would override the association methods created by the main
1401
1603
  plugin.
1604
+
1605
+ ==== :eager_limit_strategy
1606
+
1607
+ This setting determines what strategy to use for loading the associations
1608
+ that use the :limit setting to limit the number of returned records. You
1609
+ can't use LIMIT directly, since you want a limit for each associated
1610
+ record, not a LIMIT on the number of records returned by the dataset.
1611
+
1612
+ By default, no strategy is used for one_to_one associations, and
1613
+ the :ruby strategy is used for *_many associations, which does a simple
1614
+ array slice after loading the associated records. That doesn't provide
1615
+ a performance advantage, since all records are still loaded from the
1616
+ database, but it at least makes sure the cached records are accurately
1617
+ limited as they would be in the lazy load case.
1618
+
1619
+ The reason no strategy is used by default for one_to_one associations
1620
+ is that none is needed for a true one_to_one association (since there
1621
+ is only one associated record per current record). However, if you are
1622
+ using a one_to_one association where the relationship is really one_to_many,
1623
+ and using an order to pick the first matching row, then if you don't
1624
+ specify an :eager_limit_strategy option, you'll be loading all related
1625
+ rows just to have Sequel ignore all rows after the first. By using a
1626
+ strategy to change the query to only return one associated record per
1627
+ current record, you can get much better database performance.
1628
+
1629
+ You can set a value of +true+ for this option to have Sequel select what
1630
+ it thinks is the best way of limiting the records for your database. You
1631
+ can also specify a symbol to manually choose a strategy. The available
1632
+ strategies are:
1633
+
1634
+ :distinct_on :: Uses DISTINCT ON to ensure only the first matching record
1635
+ is loaded (one_to_one associations only). This is used by
1636
+ default on PostgreSQL.
1637
+ :window_function :: Uses window functions if the database supports it.
1638
+ This is used by default on databases that support window
1639
+ functions.
1640
+ :correlated_subquery :: Uses a correlated subquery to get the information.
1641
+ This is never used by default as if you aren't careful,
1642
+ it can result in pathologically long running times.
1643
+ This will not work correctly for associations where
1644
+ the associated table has a composite primary key if
1645
+ the database doesn't support using IN
1646
+ with multiple columns. This will also not work on MySQL
1647
+ because MySQL has problems using IN with a correlated
1648
+ subquery that contains a limit.
1649
+ :ruby :: Uses ruby array slicing to emulate database limiting (*_many
1650
+ associations only). This is the default if the database doesn't
1651
+ support window functions.
@@ -74,12 +74,12 @@ Most Dataset methods that users will use can be broken down into two types:
74
74
 
75
75
  Most dataset methods fall into this category, which can be further broken down by the clause they affect:
76
76
 
77
- SELECT:: select, select_all, select_append, select_more
77
+ SELECT:: select, select_all, select_append, select_group, select_more
78
78
  FROM:: from, from_self
79
79
  JOIN:: join, left_join, right_join, full_join, natural_join, natural_left_join, natural_right_join, natural_full_join, cross_join, inner_join, left_outer_join, right_outer_join, full_outer_join, join_table
80
- WHERE:: where, filter, exclude, and, or, grep, invert, unfiltered
81
- GROUP:: group, group_by, group_and_count, ungrouped
82
- HAVING:: having, filter, exclude, and, or, grep, invert, unfiltered
80
+ WHERE:: where, filter, exclude, exclude_where, and, or, grep, invert, unfiltered
81
+ GROUP:: group, group_by, group_and_count, select_group, ungrouped
82
+ HAVING:: having, filter, exclude, exclude_having, and, or, grep, invert, unfiltered
83
83
  ORDER:: order, order_by, order_append, order_prepend, order_more, reverse, reverse_order, unordered
84
84
  LIMIT:: limit, unlimited
85
85
  compounds:: union, intersect, except
@@ -93,7 +93,7 @@ other:: clone, distinct, naked, server, with_sql
93
93
 
94
94
  Most other dataset methods commonly used will execute the dataset's SQL on the database:
95
95
 
96
- SELECT (All Records):: all, each, map, to_hash, select_map, select_order_map, select_hash, to_csv
96
+ SELECT (All Records):: all, each, map, to_hash, to_hash_groups, select_map, select_order_map, select_hash, select_hash_groups, to_csv
97
97
  SELECT (First Record):: first, last, get, []
98
98
  SELECT (Aggregates):: count, avg, max, min, sum, range, interval
99
99
  INSERT:: insert, <<, import, multi_insert, insert_multiple
@@ -59,6 +59,14 @@ Ranges (both inclusive and exclusive) can also be used:
59
59
  items.filter(:price => 100...200).sql
60
60
  #=> "SELECT * FROM items WHERE (price >= 100 AND price < 200)"
61
61
 
62
+ == Filtering using an array
63
+
64
+ If you need to select multiple items from a dataset, you can supply an array:
65
+
66
+ item_array = [1, 38, 47, 99]
67
+ items.filter(:id => item_array).sql
68
+ #=> "SELECT * FROM items WHERE (id IN (1, 38, 47, 99))"
69
+
62
70
  == Filtering using expressions
63
71
 
64
72
  Sequel allows you to use ruby expressions directly in the call to filter:
@@ -0,0 +1,56 @@
1
+ = Sequel::Model Mass Assignment
2
+
3
+ Most Model methods that take a hash of attribute keys and values, including <tt>Model.new</tt>, <tt>Model.create</tt>, <tt>Model#set</tt> and <tt>Model#update</tt> are subject to Sequel's mass assignment rules.
4
+ When you pass a hash to these methods, each key has an <tt>=</tt> appended to it (the setter method), and if the setter method exists and access to it is not restricted, Sequel will call the setter method with the hash value.
5
+ By default, there are two types of setter methods that are restricted.
6
+ The first is methods like <tt>typecast_on_assignment=</tt> and <tt>==</tt>, which don't affect columns.
7
+ These methods cannot be enabled for mass assignment.
8
+ The second is primary key setters.
9
+ To enable use of primary key setters, you need to call +unrestrict_primary_key+ for that model:
10
+
11
+ Post.unrestrict_primary_key
12
+
13
+ Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases.
14
+ Sequel has multiple ways of securing mass assignment.
15
+ The first way is using +set_allowed_columns+:
16
+
17
+ Post.set_allowed_columns :title, :body, :category
18
+
19
+ This explicitly sets which methods are allowed (<tt>title=</tt>, <tt>body=</tt>, and <tt>category=</tt>), all other methods will not be allowed.
20
+ This method is useful in simple applications where the same columns are allowed in all cases, but not appropriate when different columns are allowed in different scenarios (e.g. admin access vs. user access).
21
+ To handle cases where different columns are allowed in different cases, you can use +set_only+ or +update_only+:
22
+
23
+ # user case
24
+ post.set_only(params[:post], :title, :body)
25
+ # admin case
26
+ post.set_only(params[:post], :title, :body, :deleted)
27
+
28
+ In this case, only the <tt>title=</tt> and <tt>body=</tt> methods will be allowed in the mass assignment.
29
+
30
+ By default, if an invalid setter method call is attempted, Sequel raises a <tt>Sequel::Error</tt> exception. You can have Sequel silently ignore invalid calls by doing:
31
+
32
+ # Global default
33
+ Sequel::Model.strict_param_setting = false
34
+ # Class level
35
+ Post.strict_param_setting = false
36
+ # Instance level
37
+ post.strict_param_setting = false
38
+
39
+ These mass assignment methods have been around a long time, but starting in Sequel 3.12.0, the +set_fields+ and +update_fields+ methods were added, and these may be a better mass assignment choice for most users.
40
+ These methods take two arguments, the attributes hash as the first argument, and a single array of valid field names as the second argument:
41
+
42
+ post.set_fields(params[:post], [:title, :body])
43
+
44
+ +set_fields+ and +update_fields+ differ in implementation from +set_only+ and +update_only+.
45
+ With +set_only+ and +update_only+, the hash is iterated over and it checks each method call attempt to see if it is valid.
46
+ With +set_fields+ and +update_fields+, the array is iterated over, and it just looks up the value in the hash and calls the appropriate setter method.
47
+
48
+ +set_fields+ and +update_fields+ are designed for the case where you are expecting specific fields in the input, and want to ignore the other fields.
49
+ They work great for things like HTML forms where the form fields are static.
50
+ +set_only+ and +update_only+ are designed for cases where you are not sure what fields are going to be present in the input, but still want to make sure only certain setter methods can be called.
51
+ They work great for flexible APIs.
52
+
53
+ Starting in Sequel 3.34.0, +set_fields+ and +update_fields+ take an optional argument hash, and currently handles the :missing option. With <tt>:missing=>:skip</tt>, +set_fields+ and +update_fields+ will just skip missing entries in the hash, allowing them to be used in flexible APIs. With <tt>:missing=>:raise</tt>, +set_fields+ and +update_fields+ will raise an error if one of the entries in the hash is missing, instead of just assigning the value to nil or whatever the hash's default value is. That allows stricter checks, similar to the :strict_param_checking setting for the default mass assignment methods.
54
+
55
+ In all of the mass assignment cases, methods starting with +set+ will set the attributes without saving the object, while methods starting with +update+ will set the attributes and then save the changes to the object.
56
+