sequel 4.36.0 → 5.61.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 (760) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +548 -5749
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +265 -159
  5. data/bin/sequel +34 -12
  6. data/doc/advanced_associations.rdoc +228 -187
  7. data/doc/association_basics.rdoc +281 -291
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +86 -51
  10. data/doc/code_order.rdoc +25 -19
  11. data/doc/core_extensions.rdoc +104 -63
  12. data/doc/dataset_basics.rdoc +12 -21
  13. data/doc/dataset_filtering.rdoc +99 -86
  14. data/doc/extensions.rdoc +3 -10
  15. data/doc/fork_safety.rdoc +84 -0
  16. data/doc/mass_assignment.rdoc +74 -31
  17. data/doc/migration.rdoc +59 -51
  18. data/doc/model_dataset_method_design.rdoc +129 -0
  19. data/doc/model_hooks.rdoc +15 -25
  20. data/doc/model_plugins.rdoc +12 -12
  21. data/doc/mssql_stored_procedures.rdoc +3 -3
  22. data/doc/object_model.rdoc +58 -68
  23. data/doc/opening_databases.rdoc +85 -95
  24. data/doc/postgresql.rdoc +263 -38
  25. data/doc/prepared_statements.rdoc +29 -24
  26. data/doc/querying.rdoc +189 -167
  27. data/doc/reflection.rdoc +5 -6
  28. data/doc/release_notes/5.0.0.txt +159 -0
  29. data/doc/release_notes/5.1.0.txt +31 -0
  30. data/doc/release_notes/5.10.0.txt +84 -0
  31. data/doc/release_notes/5.11.0.txt +83 -0
  32. data/doc/release_notes/5.12.0.txt +141 -0
  33. data/doc/release_notes/5.13.0.txt +27 -0
  34. data/doc/release_notes/5.14.0.txt +63 -0
  35. data/doc/release_notes/5.15.0.txt +39 -0
  36. data/doc/release_notes/5.16.0.txt +110 -0
  37. data/doc/release_notes/5.17.0.txt +31 -0
  38. data/doc/release_notes/5.18.0.txt +69 -0
  39. data/doc/release_notes/5.19.0.txt +28 -0
  40. data/doc/release_notes/5.2.0.txt +33 -0
  41. data/doc/release_notes/5.20.0.txt +89 -0
  42. data/doc/release_notes/5.21.0.txt +87 -0
  43. data/doc/release_notes/5.22.0.txt +48 -0
  44. data/doc/release_notes/5.23.0.txt +56 -0
  45. data/doc/release_notes/5.24.0.txt +56 -0
  46. data/doc/release_notes/5.25.0.txt +32 -0
  47. data/doc/release_notes/5.26.0.txt +35 -0
  48. data/doc/release_notes/5.27.0.txt +21 -0
  49. data/doc/release_notes/5.28.0.txt +16 -0
  50. data/doc/release_notes/5.29.0.txt +22 -0
  51. data/doc/release_notes/5.3.0.txt +121 -0
  52. data/doc/release_notes/5.30.0.txt +20 -0
  53. data/doc/release_notes/5.31.0.txt +148 -0
  54. data/doc/release_notes/5.32.0.txt +46 -0
  55. data/doc/release_notes/5.33.0.txt +24 -0
  56. data/doc/release_notes/5.34.0.txt +40 -0
  57. data/doc/release_notes/5.35.0.txt +56 -0
  58. data/doc/release_notes/5.36.0.txt +60 -0
  59. data/doc/release_notes/5.37.0.txt +30 -0
  60. data/doc/release_notes/5.38.0.txt +28 -0
  61. data/doc/release_notes/5.39.0.txt +19 -0
  62. data/doc/release_notes/5.4.0.txt +80 -0
  63. data/doc/release_notes/5.40.0.txt +40 -0
  64. data/doc/release_notes/5.41.0.txt +25 -0
  65. data/doc/release_notes/5.42.0.txt +136 -0
  66. data/doc/release_notes/5.43.0.txt +98 -0
  67. data/doc/release_notes/5.44.0.txt +32 -0
  68. data/doc/release_notes/5.45.0.txt +34 -0
  69. data/doc/release_notes/5.46.0.txt +87 -0
  70. data/doc/release_notes/5.47.0.txt +59 -0
  71. data/doc/release_notes/5.48.0.txt +14 -0
  72. data/doc/release_notes/5.49.0.txt +59 -0
  73. data/doc/release_notes/5.5.0.txt +61 -0
  74. data/doc/release_notes/5.50.0.txt +78 -0
  75. data/doc/release_notes/5.51.0.txt +47 -0
  76. data/doc/release_notes/5.52.0.txt +87 -0
  77. data/doc/release_notes/5.53.0.txt +23 -0
  78. data/doc/release_notes/5.54.0.txt +27 -0
  79. data/doc/release_notes/5.55.0.txt +21 -0
  80. data/doc/release_notes/5.56.0.txt +51 -0
  81. data/doc/release_notes/5.57.0.txt +23 -0
  82. data/doc/release_notes/5.58.0.txt +31 -0
  83. data/doc/release_notes/5.59.0.txt +73 -0
  84. data/doc/release_notes/5.6.0.txt +31 -0
  85. data/doc/release_notes/5.60.0.txt +22 -0
  86. data/doc/release_notes/5.61.0.txt +43 -0
  87. data/doc/release_notes/5.7.0.txt +108 -0
  88. data/doc/release_notes/5.8.0.txt +170 -0
  89. data/doc/release_notes/5.9.0.txt +99 -0
  90. data/doc/schema_modification.rdoc +95 -75
  91. data/doc/security.rdoc +109 -80
  92. data/doc/sharding.rdoc +74 -47
  93. data/doc/sql.rdoc +147 -122
  94. data/doc/testing.rdoc +43 -20
  95. data/doc/thread_safety.rdoc +2 -4
  96. data/doc/transactions.rdoc +97 -18
  97. data/doc/validations.rdoc +52 -50
  98. data/doc/virtual_rows.rdoc +90 -109
  99. data/lib/sequel/adapters/ado/access.rb +15 -17
  100. data/lib/sequel/adapters/ado/mssql.rb +6 -15
  101. data/lib/sequel/adapters/ado.rb +150 -20
  102. data/lib/sequel/adapters/amalgalite.rb +11 -23
  103. data/lib/sequel/adapters/ibmdb.rb +47 -55
  104. data/lib/sequel/adapters/jdbc/db2.rb +29 -39
  105. data/lib/sequel/adapters/jdbc/derby.rb +58 -54
  106. data/lib/sequel/adapters/jdbc/h2.rb +93 -35
  107. data/lib/sequel/adapters/jdbc/hsqldb.rb +24 -31
  108. data/lib/sequel/adapters/jdbc/jtds.rb +2 -10
  109. data/lib/sequel/adapters/jdbc/mssql.rb +3 -11
  110. data/lib/sequel/adapters/jdbc/mysql.rb +17 -20
  111. data/lib/sequel/adapters/jdbc/oracle.rb +22 -18
  112. data/lib/sequel/adapters/jdbc/postgresql.rb +69 -71
  113. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +11 -23
  114. data/lib/sequel/adapters/jdbc/sqlite.rb +47 -11
  115. data/lib/sequel/adapters/jdbc/sqlserver.rb +34 -9
  116. data/lib/sequel/adapters/jdbc/transactions.rb +22 -38
  117. data/lib/sequel/adapters/jdbc.rb +145 -130
  118. data/lib/sequel/adapters/mock.rb +100 -111
  119. data/lib/sequel/adapters/mysql.rb +114 -122
  120. data/lib/sequel/adapters/mysql2.rb +147 -63
  121. data/lib/sequel/adapters/odbc/db2.rb +1 -1
  122. data/lib/sequel/adapters/odbc/mssql.rb +8 -14
  123. data/lib/sequel/adapters/odbc/oracle.rb +11 -0
  124. data/lib/sequel/adapters/odbc.rb +20 -25
  125. data/lib/sequel/adapters/oracle.rb +50 -56
  126. data/lib/sequel/adapters/postgres.rb +305 -327
  127. data/lib/sequel/adapters/postgresql.rb +1 -1
  128. data/lib/sequel/adapters/shared/access.rb +74 -78
  129. data/lib/sequel/adapters/shared/db2.rb +118 -71
  130. data/lib/sequel/adapters/shared/mssql.rb +301 -220
  131. data/lib/sequel/adapters/shared/mysql.rb +299 -217
  132. data/lib/sequel/adapters/shared/oracle.rb +226 -65
  133. data/lib/sequel/adapters/shared/postgres.rb +935 -395
  134. data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -126
  135. data/lib/sequel/adapters/shared/sqlite.rb +447 -173
  136. data/lib/sequel/adapters/sqlanywhere.rb +48 -35
  137. data/lib/sequel/adapters/sqlite.rb +156 -111
  138. data/lib/sequel/adapters/tinytds.rb +30 -38
  139. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  140. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +3 -6
  141. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +2 -2
  142. data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
  143. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
  144. data/lib/sequel/adapters/utils/replace.rb +1 -4
  145. data/lib/sequel/adapters/utils/stored_procedures.rb +7 -22
  146. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
  147. data/lib/sequel/ast_transformer.rb +17 -89
  148. data/lib/sequel/connection_pool/sharded_single.rb +18 -15
  149. data/lib/sequel/connection_pool/sharded_threaded.rb +130 -111
  150. data/lib/sequel/connection_pool/single.rb +18 -13
  151. data/lib/sequel/connection_pool/threaded.rb +121 -120
  152. data/lib/sequel/connection_pool.rb +48 -29
  153. data/lib/sequel/core.rb +351 -301
  154. data/lib/sequel/database/connecting.rb +69 -57
  155. data/lib/sequel/database/dataset.rb +13 -5
  156. data/lib/sequel/database/dataset_defaults.rb +18 -102
  157. data/lib/sequel/database/features.rb +18 -4
  158. data/lib/sequel/database/logging.rb +12 -11
  159. data/lib/sequel/database/misc.rb +180 -122
  160. data/lib/sequel/database/query.rb +47 -27
  161. data/lib/sequel/database/schema_generator.rb +178 -84
  162. data/lib/sequel/database/schema_methods.rb +172 -97
  163. data/lib/sequel/database/transactions.rb +205 -44
  164. data/lib/sequel/database.rb +17 -2
  165. data/lib/sequel/dataset/actions.rb +339 -155
  166. data/lib/sequel/dataset/dataset_module.rb +46 -0
  167. data/lib/sequel/dataset/features.rb +90 -35
  168. data/lib/sequel/dataset/graph.rb +80 -58
  169. data/lib/sequel/dataset/misc.rb +137 -47
  170. data/lib/sequel/dataset/placeholder_literalizer.rb +63 -25
  171. data/lib/sequel/dataset/prepared_statements.rb +188 -85
  172. data/lib/sequel/dataset/query.rb +530 -222
  173. data/lib/sequel/dataset/sql.rb +590 -368
  174. data/lib/sequel/dataset.rb +26 -16
  175. data/lib/sequel/deprecated.rb +12 -2
  176. data/lib/sequel/exceptions.rb +46 -16
  177. data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
  178. data/lib/sequel/extensions/_model_pg_row.rb +43 -0
  179. data/lib/sequel/extensions/_pretty_table.rb +2 -5
  180. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  181. data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
  182. data/lib/sequel/extensions/async_thread_pool.rb +438 -0
  183. data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  184. data/lib/sequel/extensions/blank.rb +8 -0
  185. data/lib/sequel/extensions/caller_logging.rb +79 -0
  186. data/lib/sequel/extensions/columns_introspection.rb +4 -3
  187. data/lib/sequel/extensions/connection_expiration.rb +20 -10
  188. data/lib/sequel/extensions/connection_validator.rb +11 -10
  189. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  190. data/lib/sequel/extensions/constraint_validations.rb +62 -39
  191. data/lib/sequel/extensions/core_extensions.rb +42 -48
  192. data/lib/sequel/extensions/core_refinements.rb +80 -59
  193. data/lib/sequel/extensions/current_datetime_timestamp.rb +1 -4
  194. data/lib/sequel/extensions/date_arithmetic.rb +98 -39
  195. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  196. data/lib/sequel/extensions/datetime_parse_to_time.rb +41 -0
  197. data/lib/sequel/extensions/duplicate_columns_handler.rb +21 -14
  198. data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
  199. data/lib/sequel/extensions/escaped_like.rb +100 -0
  200. data/lib/sequel/extensions/eval_inspect.rb +12 -15
  201. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  202. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  203. data/lib/sequel/extensions/freeze_datasets.rb +3 -0
  204. data/lib/sequel/extensions/from_block.rb +1 -34
  205. data/lib/sequel/extensions/graph_each.rb +4 -4
  206. data/lib/sequel/extensions/identifier_mangling.rb +180 -0
  207. data/lib/sequel/extensions/implicit_subquery.rb +48 -0
  208. data/lib/sequel/extensions/index_caching.rb +109 -0
  209. data/lib/sequel/extensions/inflector.rb +13 -5
  210. data/lib/sequel/extensions/integer64.rb +32 -0
  211. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  212. data/lib/sequel/extensions/looser_typecasting.rb +17 -8
  213. data/lib/sequel/extensions/migration.rb +119 -78
  214. data/lib/sequel/extensions/named_timezones.rb +88 -23
  215. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -82
  216. data/lib/sequel/extensions/null_dataset.rb +8 -8
  217. data/lib/sequel/extensions/pagination.rb +32 -29
  218. data/lib/sequel/extensions/pg_array.rb +221 -287
  219. data/lib/sequel/extensions/pg_array_ops.rb +17 -9
  220. data/lib/sequel/extensions/pg_enum.rb +63 -23
  221. data/lib/sequel/extensions/pg_extended_date_support.rb +241 -0
  222. data/lib/sequel/extensions/pg_hstore.rb +45 -54
  223. data/lib/sequel/extensions/pg_hstore_ops.rb +58 -6
  224. data/lib/sequel/extensions/pg_inet.rb +31 -12
  225. data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
  226. data/lib/sequel/extensions/pg_interval.rb +56 -29
  227. data/lib/sequel/extensions/pg_json.rb +417 -140
  228. data/lib/sequel/extensions/pg_json_ops.rb +270 -18
  229. data/lib/sequel/extensions/pg_loose_count.rb +4 -2
  230. data/lib/sequel/extensions/pg_multirange.rb +372 -0
  231. data/lib/sequel/extensions/pg_range.rb +131 -191
  232. data/lib/sequel/extensions/pg_range_ops.rb +42 -13
  233. data/lib/sequel/extensions/pg_row.rb +48 -81
  234. data/lib/sequel/extensions/pg_row_ops.rb +33 -14
  235. data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
  236. data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
  237. data/lib/sequel/extensions/query.rb +9 -7
  238. data/lib/sequel/extensions/round_timestamps.rb +0 -6
  239. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  240. data/lib/sequel/extensions/s.rb +60 -0
  241. data/lib/sequel/extensions/schema_caching.rb +10 -1
  242. data/lib/sequel/extensions/schema_dumper.rb +71 -48
  243. data/lib/sequel/extensions/select_remove.rb +4 -4
  244. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
  245. data/lib/sequel/extensions/server_block.rb +51 -27
  246. data/lib/sequel/extensions/split_array_nil.rb +4 -4
  247. data/lib/sequel/extensions/sql_comments.rb +119 -7
  248. data/lib/sequel/extensions/sql_expr.rb +2 -1
  249. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  250. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  251. data/lib/sequel/extensions/string_agg.rb +11 -8
  252. data/lib/sequel/extensions/string_date_time.rb +19 -23
  253. data/lib/sequel/extensions/symbol_aref.rb +55 -0
  254. data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
  255. data/lib/sequel/extensions/symbol_as.rb +23 -0
  256. data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
  257. data/lib/sequel/extensions/synchronize_sql.rb +45 -0
  258. data/lib/sequel/extensions/to_dot.rb +10 -4
  259. data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
  260. data/lib/sequel/model/associations.rb +1006 -284
  261. data/lib/sequel/model/base.rb +560 -805
  262. data/lib/sequel/model/dataset_module.rb +11 -10
  263. data/lib/sequel/model/default_inflections.rb +1 -1
  264. data/lib/sequel/model/errors.rb +10 -3
  265. data/lib/sequel/model/exceptions.rb +8 -10
  266. data/lib/sequel/model/inflections.rb +7 -20
  267. data/lib/sequel/model/plugins.rb +114 -0
  268. data/lib/sequel/model.rb +32 -82
  269. data/lib/sequel/plugins/active_model.rb +30 -14
  270. data/lib/sequel/plugins/after_initialize.rb +1 -1
  271. data/lib/sequel/plugins/association_dependencies.rb +25 -18
  272. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  273. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  274. data/lib/sequel/plugins/association_pks.rb +147 -70
  275. data/lib/sequel/plugins/association_proxies.rb +33 -9
  276. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  277. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  278. data/lib/sequel/plugins/auto_validations.rb +95 -28
  279. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  280. data/lib/sequel/plugins/before_after_save.rb +0 -42
  281. data/lib/sequel/plugins/blacklist_security.rb +21 -12
  282. data/lib/sequel/plugins/boolean_readers.rb +5 -5
  283. data/lib/sequel/plugins/boolean_subsets.rb +13 -8
  284. data/lib/sequel/plugins/caching.rb +25 -16
  285. data/lib/sequel/plugins/class_table_inheritance.rb +179 -100
  286. data/lib/sequel/plugins/column_conflicts.rb +16 -3
  287. data/lib/sequel/plugins/column_encryption.rb +728 -0
  288. data/lib/sequel/plugins/column_select.rb +7 -5
  289. data/lib/sequel/plugins/columns_updated.rb +42 -0
  290. data/lib/sequel/plugins/composition.rb +42 -26
  291. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  292. data/lib/sequel/plugins/constraint_validations.rb +20 -14
  293. data/lib/sequel/plugins/csv_serializer.rb +56 -35
  294. data/lib/sequel/plugins/dataset_associations.rb +40 -17
  295. data/lib/sequel/plugins/def_dataset_method.rb +90 -0
  296. data/lib/sequel/plugins/defaults_setter.rb +65 -10
  297. data/lib/sequel/plugins/delay_add_association.rb +1 -1
  298. data/lib/sequel/plugins/dirty.rb +62 -24
  299. data/lib/sequel/plugins/eager_each.rb +3 -3
  300. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  301. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  302. data/lib/sequel/plugins/enum.rb +124 -0
  303. data/lib/sequel/plugins/error_splitter.rb +17 -12
  304. data/lib/sequel/plugins/finder.rb +246 -0
  305. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  306. data/lib/sequel/plugins/force_encoding.rb +7 -12
  307. data/lib/sequel/plugins/hook_class_methods.rb +37 -54
  308. data/lib/sequel/plugins/input_transformer.rb +18 -10
  309. data/lib/sequel/plugins/insert_conflict.rb +76 -0
  310. data/lib/sequel/plugins/insert_returning_select.rb +2 -2
  311. data/lib/sequel/plugins/instance_filters.rb +10 -8
  312. data/lib/sequel/plugins/instance_hooks.rb +34 -17
  313. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  314. data/lib/sequel/plugins/inverted_subsets.rb +22 -13
  315. data/lib/sequel/plugins/json_serializer.rb +124 -64
  316. data/lib/sequel/plugins/lazy_attributes.rb +21 -14
  317. data/lib/sequel/plugins/list.rb +35 -21
  318. data/lib/sequel/plugins/many_through_many.rb +134 -21
  319. data/lib/sequel/plugins/modification_detection.rb +15 -5
  320. data/lib/sequel/plugins/mssql_optimistic_locking.rb +6 -5
  321. data/lib/sequel/plugins/nested_attributes.rb +61 -31
  322. data/lib/sequel/plugins/optimistic_locking.rb +3 -3
  323. data/lib/sequel/plugins/pg_array_associations.rb +103 -53
  324. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +350 -0
  325. data/lib/sequel/plugins/pg_row.rb +5 -51
  326. data/lib/sequel/plugins/prepared_statements.rb +60 -72
  327. data/lib/sequel/plugins/prepared_statements_safe.rb +9 -4
  328. data/lib/sequel/plugins/rcte_tree.rb +68 -82
  329. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  330. data/lib/sequel/plugins/serialization.rb +43 -46
  331. data/lib/sequel/plugins/serialization_modification_detection.rb +3 -2
  332. data/lib/sequel/plugins/sharding.rb +15 -10
  333. data/lib/sequel/plugins/single_table_inheritance.rb +67 -28
  334. data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
  335. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  336. data/lib/sequel/plugins/split_values.rb +11 -6
  337. data/lib/sequel/plugins/sql_comments.rb +189 -0
  338. data/lib/sequel/plugins/static_cache.rb +77 -53
  339. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  340. data/lib/sequel/plugins/string_stripper.rb +3 -3
  341. data/lib/sequel/plugins/subclasses.rb +43 -10
  342. data/lib/sequel/plugins/subset_conditions.rb +15 -5
  343. data/lib/sequel/plugins/table_select.rb +2 -2
  344. data/lib/sequel/plugins/tactical_eager_loading.rb +96 -12
  345. data/lib/sequel/plugins/throw_failures.rb +110 -0
  346. data/lib/sequel/plugins/timestamps.rb +20 -8
  347. data/lib/sequel/plugins/touch.rb +19 -8
  348. data/lib/sequel/plugins/tree.rb +62 -32
  349. data/lib/sequel/plugins/typecast_on_load.rb +12 -4
  350. data/lib/sequel/plugins/unlimited_update.rb +1 -7
  351. data/lib/sequel/plugins/unused_associations.rb +521 -0
  352. data/lib/sequel/plugins/update_or_create.rb +4 -4
  353. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  354. data/lib/sequel/plugins/update_refresh.rb +26 -15
  355. data/lib/sequel/plugins/uuid.rb +7 -11
  356. data/lib/sequel/plugins/validate_associated.rb +18 -0
  357. data/lib/sequel/plugins/validation_class_methods.rb +38 -19
  358. data/lib/sequel/plugins/validation_contexts.rb +49 -0
  359. data/lib/sequel/plugins/validation_helpers.rb +57 -41
  360. data/lib/sequel/plugins/whitelist_security.rb +122 -0
  361. data/lib/sequel/plugins/xml_serializer.rb +30 -31
  362. data/lib/sequel/sql.rb +471 -331
  363. data/lib/sequel/timezones.rb +78 -47
  364. data/lib/sequel/version.rb +7 -2
  365. data/lib/sequel.rb +1 -1
  366. metadata +217 -521
  367. data/Rakefile +0 -164
  368. data/doc/active_record.rdoc +0 -928
  369. data/doc/release_notes/1.0.txt +0 -38
  370. data/doc/release_notes/1.1.txt +0 -143
  371. data/doc/release_notes/1.3.txt +0 -101
  372. data/doc/release_notes/1.4.0.txt +0 -53
  373. data/doc/release_notes/1.5.0.txt +0 -155
  374. data/doc/release_notes/2.0.0.txt +0 -298
  375. data/doc/release_notes/2.1.0.txt +0 -271
  376. data/doc/release_notes/2.10.0.txt +0 -328
  377. data/doc/release_notes/2.11.0.txt +0 -215
  378. data/doc/release_notes/2.12.0.txt +0 -534
  379. data/doc/release_notes/2.2.0.txt +0 -253
  380. data/doc/release_notes/2.3.0.txt +0 -88
  381. data/doc/release_notes/2.4.0.txt +0 -106
  382. data/doc/release_notes/2.5.0.txt +0 -137
  383. data/doc/release_notes/2.6.0.txt +0 -157
  384. data/doc/release_notes/2.7.0.txt +0 -166
  385. data/doc/release_notes/2.8.0.txt +0 -171
  386. data/doc/release_notes/2.9.0.txt +0 -97
  387. data/doc/release_notes/3.0.0.txt +0 -221
  388. data/doc/release_notes/3.1.0.txt +0 -406
  389. data/doc/release_notes/3.10.0.txt +0 -286
  390. data/doc/release_notes/3.11.0.txt +0 -254
  391. data/doc/release_notes/3.12.0.txt +0 -304
  392. data/doc/release_notes/3.13.0.txt +0 -210
  393. data/doc/release_notes/3.14.0.txt +0 -118
  394. data/doc/release_notes/3.15.0.txt +0 -78
  395. data/doc/release_notes/3.16.0.txt +0 -45
  396. data/doc/release_notes/3.17.0.txt +0 -58
  397. data/doc/release_notes/3.18.0.txt +0 -120
  398. data/doc/release_notes/3.19.0.txt +0 -67
  399. data/doc/release_notes/3.2.0.txt +0 -268
  400. data/doc/release_notes/3.20.0.txt +0 -41
  401. data/doc/release_notes/3.21.0.txt +0 -87
  402. data/doc/release_notes/3.22.0.txt +0 -39
  403. data/doc/release_notes/3.23.0.txt +0 -172
  404. data/doc/release_notes/3.24.0.txt +0 -420
  405. data/doc/release_notes/3.25.0.txt +0 -88
  406. data/doc/release_notes/3.26.0.txt +0 -88
  407. data/doc/release_notes/3.27.0.txt +0 -82
  408. data/doc/release_notes/3.28.0.txt +0 -304
  409. data/doc/release_notes/3.29.0.txt +0 -459
  410. data/doc/release_notes/3.3.0.txt +0 -192
  411. data/doc/release_notes/3.30.0.txt +0 -135
  412. data/doc/release_notes/3.31.0.txt +0 -146
  413. data/doc/release_notes/3.32.0.txt +0 -202
  414. data/doc/release_notes/3.33.0.txt +0 -157
  415. data/doc/release_notes/3.34.0.txt +0 -671
  416. data/doc/release_notes/3.35.0.txt +0 -144
  417. data/doc/release_notes/3.36.0.txt +0 -245
  418. data/doc/release_notes/3.37.0.txt +0 -338
  419. data/doc/release_notes/3.38.0.txt +0 -234
  420. data/doc/release_notes/3.39.0.txt +0 -237
  421. data/doc/release_notes/3.4.0.txt +0 -325
  422. data/doc/release_notes/3.40.0.txt +0 -73
  423. data/doc/release_notes/3.41.0.txt +0 -155
  424. data/doc/release_notes/3.42.0.txt +0 -74
  425. data/doc/release_notes/3.43.0.txt +0 -105
  426. data/doc/release_notes/3.44.0.txt +0 -152
  427. data/doc/release_notes/3.45.0.txt +0 -179
  428. data/doc/release_notes/3.46.0.txt +0 -122
  429. data/doc/release_notes/3.47.0.txt +0 -270
  430. data/doc/release_notes/3.48.0.txt +0 -477
  431. data/doc/release_notes/3.5.0.txt +0 -510
  432. data/doc/release_notes/3.6.0.txt +0 -366
  433. data/doc/release_notes/3.7.0.txt +0 -179
  434. data/doc/release_notes/3.8.0.txt +0 -151
  435. data/doc/release_notes/3.9.0.txt +0 -233
  436. data/doc/release_notes/4.0.0.txt +0 -262
  437. data/doc/release_notes/4.1.0.txt +0 -85
  438. data/doc/release_notes/4.10.0.txt +0 -226
  439. data/doc/release_notes/4.11.0.txt +0 -147
  440. data/doc/release_notes/4.12.0.txt +0 -105
  441. data/doc/release_notes/4.13.0.txt +0 -169
  442. data/doc/release_notes/4.14.0.txt +0 -68
  443. data/doc/release_notes/4.15.0.txt +0 -56
  444. data/doc/release_notes/4.16.0.txt +0 -36
  445. data/doc/release_notes/4.17.0.txt +0 -38
  446. data/doc/release_notes/4.18.0.txt +0 -36
  447. data/doc/release_notes/4.19.0.txt +0 -45
  448. data/doc/release_notes/4.2.0.txt +0 -129
  449. data/doc/release_notes/4.20.0.txt +0 -79
  450. data/doc/release_notes/4.21.0.txt +0 -94
  451. data/doc/release_notes/4.22.0.txt +0 -72
  452. data/doc/release_notes/4.23.0.txt +0 -65
  453. data/doc/release_notes/4.24.0.txt +0 -99
  454. data/doc/release_notes/4.25.0.txt +0 -181
  455. data/doc/release_notes/4.26.0.txt +0 -44
  456. data/doc/release_notes/4.27.0.txt +0 -78
  457. data/doc/release_notes/4.28.0.txt +0 -57
  458. data/doc/release_notes/4.29.0.txt +0 -41
  459. data/doc/release_notes/4.3.0.txt +0 -40
  460. data/doc/release_notes/4.30.0.txt +0 -37
  461. data/doc/release_notes/4.31.0.txt +0 -57
  462. data/doc/release_notes/4.32.0.txt +0 -132
  463. data/doc/release_notes/4.33.0.txt +0 -88
  464. data/doc/release_notes/4.34.0.txt +0 -86
  465. data/doc/release_notes/4.35.0.txt +0 -130
  466. data/doc/release_notes/4.36.0.txt +0 -116
  467. data/doc/release_notes/4.4.0.txt +0 -92
  468. data/doc/release_notes/4.5.0.txt +0 -34
  469. data/doc/release_notes/4.6.0.txt +0 -30
  470. data/doc/release_notes/4.7.0.txt +0 -103
  471. data/doc/release_notes/4.8.0.txt +0 -175
  472. data/doc/release_notes/4.9.0.txt +0 -190
  473. data/lib/sequel/adapters/cubrid.rb +0 -144
  474. data/lib/sequel/adapters/do/mysql.rb +0 -66
  475. data/lib/sequel/adapters/do/postgres.rb +0 -44
  476. data/lib/sequel/adapters/do/sqlite3.rb +0 -42
  477. data/lib/sequel/adapters/do.rb +0 -158
  478. data/lib/sequel/adapters/jdbc/as400.rb +0 -84
  479. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -64
  480. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -36
  481. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -33
  482. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -33
  483. data/lib/sequel/adapters/odbc/progress.rb +0 -10
  484. data/lib/sequel/adapters/shared/cubrid.rb +0 -245
  485. data/lib/sequel/adapters/shared/firebird.rb +0 -247
  486. data/lib/sequel/adapters/shared/informix.rb +0 -54
  487. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -152
  488. data/lib/sequel/adapters/shared/progress.rb +0 -40
  489. data/lib/sequel/adapters/swift/mysql.rb +0 -49
  490. data/lib/sequel/adapters/swift/postgres.rb +0 -47
  491. data/lib/sequel/adapters/swift/sqlite.rb +0 -49
  492. data/lib/sequel/adapters/swift.rb +0 -160
  493. data/lib/sequel/adapters/utils/pg_types.rb +0 -70
  494. data/lib/sequel/dataset/mutation.rb +0 -111
  495. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -5
  496. data/lib/sequel/extensions/filter_having.rb +0 -63
  497. data/lib/sequel/extensions/hash_aliases.rb +0 -49
  498. data/lib/sequel/extensions/meta_def.rb +0 -35
  499. data/lib/sequel/extensions/query_literals.rb +0 -84
  500. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -24
  501. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -122
  502. data/lib/sequel/extensions/set_overrides.rb +0 -76
  503. data/lib/sequel/no_core_ext.rb +0 -3
  504. data/lib/sequel/plugins/association_autoreloading.rb +0 -9
  505. data/lib/sequel/plugins/identifier_columns.rb +0 -47
  506. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -9
  507. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -81
  508. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -119
  509. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -61
  510. data/lib/sequel/plugins/schema.rb +0 -82
  511. data/lib/sequel/plugins/scissors.rb +0 -35
  512. data/spec/adapter_spec.rb +0 -4
  513. data/spec/adapters/db2_spec.rb +0 -160
  514. data/spec/adapters/firebird_spec.rb +0 -411
  515. data/spec/adapters/informix_spec.rb +0 -100
  516. data/spec/adapters/mssql_spec.rb +0 -733
  517. data/spec/adapters/mysql_spec.rb +0 -1319
  518. data/spec/adapters/oracle_spec.rb +0 -313
  519. data/spec/adapters/postgres_spec.rb +0 -3790
  520. data/spec/adapters/spec_helper.rb +0 -49
  521. data/spec/adapters/sqlanywhere_spec.rb +0 -170
  522. data/spec/adapters/sqlite_spec.rb +0 -688
  523. data/spec/bin_spec.rb +0 -258
  524. data/spec/core/connection_pool_spec.rb +0 -1045
  525. data/spec/core/database_spec.rb +0 -2636
  526. data/spec/core/dataset_spec.rb +0 -5175
  527. data/spec/core/deprecated_spec.rb +0 -70
  528. data/spec/core/expression_filters_spec.rb +0 -1247
  529. data/spec/core/mock_adapter_spec.rb +0 -464
  530. data/spec/core/object_graph_spec.rb +0 -303
  531. data/spec/core/placeholder_literalizer_spec.rb +0 -163
  532. data/spec/core/schema_generator_spec.rb +0 -203
  533. data/spec/core/schema_spec.rb +0 -1676
  534. data/spec/core/spec_helper.rb +0 -34
  535. data/spec/core/version_spec.rb +0 -7
  536. data/spec/core_extensions_spec.rb +0 -699
  537. data/spec/core_model_spec.rb +0 -2
  538. data/spec/core_spec.rb +0 -1
  539. data/spec/extensions/accessed_columns_spec.rb +0 -51
  540. data/spec/extensions/active_model_spec.rb +0 -85
  541. data/spec/extensions/after_initialize_spec.rb +0 -24
  542. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  543. data/spec/extensions/association_dependencies_spec.rb +0 -117
  544. data/spec/extensions/association_pks_spec.rb +0 -405
  545. data/spec/extensions/association_proxies_spec.rb +0 -86
  546. data/spec/extensions/auto_validations_spec.rb +0 -192
  547. data/spec/extensions/before_after_save_spec.rb +0 -40
  548. data/spec/extensions/blacklist_security_spec.rb +0 -88
  549. data/spec/extensions/blank_spec.rb +0 -69
  550. data/spec/extensions/boolean_readers_spec.rb +0 -93
  551. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  552. data/spec/extensions/caching_spec.rb +0 -270
  553. data/spec/extensions/class_table_inheritance_spec.rb +0 -444
  554. data/spec/extensions/column_conflicts_spec.rb +0 -60
  555. data/spec/extensions/column_select_spec.rb +0 -108
  556. data/spec/extensions/columns_introspection_spec.rb +0 -91
  557. data/spec/extensions/composition_spec.rb +0 -242
  558. data/spec/extensions/connection_expiration_spec.rb +0 -121
  559. data/spec/extensions/connection_validator_spec.rb +0 -127
  560. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -288
  561. data/spec/extensions/constraint_validations_spec.rb +0 -389
  562. data/spec/extensions/core_refinements_spec.rb +0 -519
  563. data/spec/extensions/csv_serializer_spec.rb +0 -180
  564. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  565. data/spec/extensions/dataset_associations_spec.rb +0 -343
  566. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  567. data/spec/extensions/date_arithmetic_spec.rb +0 -167
  568. data/spec/extensions/defaults_setter_spec.rb +0 -102
  569. data/spec/extensions/delay_add_association_spec.rb +0 -74
  570. data/spec/extensions/dirty_spec.rb +0 -180
  571. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -110
  572. data/spec/extensions/eager_each_spec.rb +0 -66
  573. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  574. data/spec/extensions/error_splitter_spec.rb +0 -18
  575. data/spec/extensions/error_sql_spec.rb +0 -20
  576. data/spec/extensions/eval_inspect_spec.rb +0 -73
  577. data/spec/extensions/filter_having_spec.rb +0 -40
  578. data/spec/extensions/force_encoding_spec.rb +0 -114
  579. data/spec/extensions/from_block_spec.rb +0 -21
  580. data/spec/extensions/graph_each_spec.rb +0 -119
  581. data/spec/extensions/hash_aliases_spec.rb +0 -24
  582. data/spec/extensions/hook_class_methods_spec.rb +0 -429
  583. data/spec/extensions/identifier_columns_spec.rb +0 -17
  584. data/spec/extensions/inflector_spec.rb +0 -183
  585. data/spec/extensions/input_transformer_spec.rb +0 -54
  586. data/spec/extensions/insert_returning_select_spec.rb +0 -46
  587. data/spec/extensions/instance_filters_spec.rb +0 -79
  588. data/spec/extensions/instance_hooks_spec.rb +0 -276
  589. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  590. data/spec/extensions/json_serializer_spec.rb +0 -304
  591. data/spec/extensions/lazy_attributes_spec.rb +0 -170
  592. data/spec/extensions/list_spec.rb +0 -278
  593. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  594. data/spec/extensions/many_through_many_spec.rb +0 -2172
  595. data/spec/extensions/meta_def_spec.rb +0 -21
  596. data/spec/extensions/migration_spec.rb +0 -728
  597. data/spec/extensions/modification_detection_spec.rb +0 -80
  598. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
  599. data/spec/extensions/named_timezones_spec.rb +0 -108
  600. data/spec/extensions/nested_attributes_spec.rb +0 -697
  601. data/spec/extensions/no_auto_literal_strings_spec.rb +0 -65
  602. data/spec/extensions/null_dataset_spec.rb +0 -85
  603. data/spec/extensions/optimistic_locking_spec.rb +0 -128
  604. data/spec/extensions/pagination_spec.rb +0 -118
  605. data/spec/extensions/pg_array_associations_spec.rb +0 -736
  606. data/spec/extensions/pg_array_ops_spec.rb +0 -143
  607. data/spec/extensions/pg_array_spec.rb +0 -390
  608. data/spec/extensions/pg_enum_spec.rb +0 -92
  609. data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
  610. data/spec/extensions/pg_hstore_spec.rb +0 -206
  611. data/spec/extensions/pg_inet_ops_spec.rb +0 -101
  612. data/spec/extensions/pg_inet_spec.rb +0 -52
  613. data/spec/extensions/pg_interval_spec.rb +0 -76
  614. data/spec/extensions/pg_json_ops_spec.rb +0 -275
  615. data/spec/extensions/pg_json_spec.rb +0 -218
  616. data/spec/extensions/pg_loose_count_spec.rb +0 -17
  617. data/spec/extensions/pg_range_ops_spec.rb +0 -58
  618. data/spec/extensions/pg_range_spec.rb +0 -473
  619. data/spec/extensions/pg_row_ops_spec.rb +0 -60
  620. data/spec/extensions/pg_row_plugin_spec.rb +0 -62
  621. data/spec/extensions/pg_row_spec.rb +0 -360
  622. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
  623. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
  624. data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
  625. data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
  626. data/spec/extensions/prepared_statements_spec.rb +0 -103
  627. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
  628. data/spec/extensions/pretty_table_spec.rb +0 -92
  629. data/spec/extensions/query_literals_spec.rb +0 -183
  630. data/spec/extensions/query_spec.rb +0 -102
  631. data/spec/extensions/rcte_tree_spec.rb +0 -392
  632. data/spec/extensions/round_timestamps_spec.rb +0 -43
  633. data/spec/extensions/schema_caching_spec.rb +0 -41
  634. data/spec/extensions/schema_dumper_spec.rb +0 -814
  635. data/spec/extensions/schema_spec.rb +0 -117
  636. data/spec/extensions/scissors_spec.rb +0 -26
  637. data/spec/extensions/select_remove_spec.rb +0 -38
  638. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
  639. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  640. data/spec/extensions/serialization_spec.rb +0 -362
  641. data/spec/extensions/server_block_spec.rb +0 -90
  642. data/spec/extensions/server_logging_spec.rb +0 -45
  643. data/spec/extensions/set_overrides_spec.rb +0 -61
  644. data/spec/extensions/sharding_spec.rb +0 -198
  645. data/spec/extensions/shared_caching_spec.rb +0 -175
  646. data/spec/extensions/single_table_inheritance_spec.rb +0 -297
  647. data/spec/extensions/singular_table_names_spec.rb +0 -22
  648. data/spec/extensions/skip_create_refresh_spec.rb +0 -17
  649. data/spec/extensions/spec_helper.rb +0 -71
  650. data/spec/extensions/split_array_nil_spec.rb +0 -24
  651. data/spec/extensions/split_values_spec.rb +0 -22
  652. data/spec/extensions/sql_comments_spec.rb +0 -27
  653. data/spec/extensions/sql_expr_spec.rb +0 -60
  654. data/spec/extensions/static_cache_spec.rb +0 -361
  655. data/spec/extensions/string_agg_spec.rb +0 -85
  656. data/spec/extensions/string_date_time_spec.rb +0 -95
  657. data/spec/extensions/string_stripper_spec.rb +0 -68
  658. data/spec/extensions/subclasses_spec.rb +0 -66
  659. data/spec/extensions/subset_conditions_spec.rb +0 -38
  660. data/spec/extensions/table_select_spec.rb +0 -71
  661. data/spec/extensions/tactical_eager_loading_spec.rb +0 -136
  662. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  663. data/spec/extensions/timestamps_spec.rb +0 -175
  664. data/spec/extensions/to_dot_spec.rb +0 -154
  665. data/spec/extensions/touch_spec.rb +0 -203
  666. data/spec/extensions/tree_spec.rb +0 -274
  667. data/spec/extensions/typecast_on_load_spec.rb +0 -80
  668. data/spec/extensions/unlimited_update_spec.rb +0 -20
  669. data/spec/extensions/update_or_create_spec.rb +0 -87
  670. data/spec/extensions/update_primary_key_spec.rb +0 -100
  671. data/spec/extensions/update_refresh_spec.rb +0 -53
  672. data/spec/extensions/uuid_spec.rb +0 -106
  673. data/spec/extensions/validate_associated_spec.rb +0 -52
  674. data/spec/extensions/validation_class_methods_spec.rb +0 -1027
  675. data/spec/extensions/validation_helpers_spec.rb +0 -554
  676. data/spec/extensions/xml_serializer_spec.rb +0 -207
  677. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  678. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  679. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  680. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  681. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  682. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  683. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  684. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  685. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  686. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  687. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  688. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  689. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  690. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  691. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  692. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  693. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  694. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  695. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  696. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  697. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  698. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  699. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  700. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  701. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  702. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  703. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  704. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  705. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  706. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  707. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  708. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  709. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  710. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  711. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  712. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  713. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  714. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  715. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  716. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  717. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  718. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  719. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  720. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  721. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  722. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  723. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  724. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  725. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  726. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  727. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  728. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  729. data/spec/guards_helper.rb +0 -55
  730. data/spec/integration/associations_test.rb +0 -2506
  731. data/spec/integration/database_test.rb +0 -113
  732. data/spec/integration/dataset_test.rb +0 -1858
  733. data/spec/integration/eager_loader_test.rb +0 -687
  734. data/spec/integration/migrator_test.rb +0 -262
  735. data/spec/integration/model_test.rb +0 -230
  736. data/spec/integration/plugin_test.rb +0 -2297
  737. data/spec/integration/prepared_statement_test.rb +0 -467
  738. data/spec/integration/schema_test.rb +0 -815
  739. data/spec/integration/spec_helper.rb +0 -56
  740. data/spec/integration/timezone_test.rb +0 -86
  741. data/spec/integration/transaction_test.rb +0 -406
  742. data/spec/integration/type_test.rb +0 -133
  743. data/spec/model/association_reflection_spec.rb +0 -565
  744. data/spec/model/associations_spec.rb +0 -4589
  745. data/spec/model/base_spec.rb +0 -759
  746. data/spec/model/class_dataset_methods_spec.rb +0 -150
  747. data/spec/model/dataset_methods_spec.rb +0 -149
  748. data/spec/model/eager_loading_spec.rb +0 -2197
  749. data/spec/model/hooks_spec.rb +0 -604
  750. data/spec/model/inflector_spec.rb +0 -26
  751. data/spec/model/model_spec.rb +0 -1097
  752. data/spec/model/plugins_spec.rb +0 -299
  753. data/spec/model/record_spec.rb +0 -2162
  754. data/spec/model/spec_helper.rb +0 -46
  755. data/spec/model/validations_spec.rb +0 -193
  756. data/spec/model_no_assoc_spec.rb +0 -1
  757. data/spec/model_spec.rb +0 -1
  758. data/spec/plugin_spec.rb +0 -1
  759. data/spec/sequel_coverage.rb +0 -15
  760. data/spec/spec_config.rb +0 -10
@@ -1,26 +1,149 @@
1
1
  = Advanced Associations
2
2
 
3
- Sequel::Model has the most powerful and flexible associations of any ruby ORM.
3
+ Sequel::Model's association support is powerful and flexible, but it can be difficult for
4
+ new users to understand what the support enables. This guide shows off some of the more
5
+ advanced Sequel::Model association features.
4
6
 
5
- == Background: Sequel::Model association options
7
+ You should probably review the {Model Associations Basics and Options guide}[rdoc-ref:doc/association_basics.rdoc]
8
+ before reviewing this guide.
9
+
10
+ == Sequel::Model Eager Loading
11
+
12
+ Sequel::Model offers two different ways to perform eager loading, +eager+ and
13
+ +eager_graph+. +eager+ uses an SQL query per association, +eager_graph+ uses a single
14
+ SQL query containing JOINs.
15
+
16
+ Assuming the following associations:
17
+
18
+ Artist.one_to_many :albums
19
+ Album.one_to_many :tracks
20
+ Tracks.many_to_one :lyric
21
+
22
+ Let's say you wanted to load all artists and eagerly load the related albums, tracks, and lyrics.
23
+
24
+ Artist.eager(albums: {tracks: :lyric})
25
+ # 4 Queries:
26
+ # SELECT * FROM artists;
27
+ # SELECT * FROM albums WHERE (artist_id IN (...));
28
+ # SELECT * FROM tracks WHERE (album_id IN (...));
29
+ # SELECT * FROM lyrics WHERE (id IN (...));
30
+
31
+ Artist.eager_graph(albums: {tracks: :lyric})
32
+ # 1 Query:
33
+ # SELECT artists.id, artists.name, ...
34
+ # albums.id AS albums_id, albums.name AS albums_name, ...
35
+ # tracks.id AS tracks_id, tracks.name AS tracks_name, ...
36
+ # lyric.id AS lyric_id, ...
37
+ # FROM artists
38
+ # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
39
+ # LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
40
+ # LEFT OUTER JOIN lyrics AS lyric ON (lyric.id = tracks.lyric_id);
41
+
42
+ In general, the recommendation is to use +eager+ unless you have a reason to use +eager_graph+.
43
+ +eager_graph+ is needed when you want to reference columns in an associated table. For example,
44
+ if you want to order the loading of returned artists based on the names of the albums, you cannot
45
+ do:
46
+
47
+ Artist.eager(albums: {tracks: :lyric}).order{albums[:name]}
48
+
49
+ because the initial query Sequel will use would be:
50
+
51
+ # SELECT * FROM artists ORDER BY albums.name;
52
+
53
+ and +albums+ is not a valid qualifier in such a query. In this situation, you must use +eager_graph+:
54
+
55
+ Artist.eager_graph(albums: {tracks: :lyric}).order{albums[:name]}
56
+
57
+ Whether +eager+ or +eager_graph+ performs better is association and database dependent. If
58
+ you are concerned about performance, you should try benchmarking both cases with appropriate
59
+ data to see which performs better.
60
+
61
+ === Mixing eager and eager_graph
62
+
63
+ Sequel offers the ability to mix +eager+ and +eager_graph+ when loading results. This can
64
+ be done at the main level by calling both +eager+ and +eager_graph+ on the same dataset:
65
+
66
+ Album.eager(:artist).eager_graph(:tracks)
67
+ # 2 Queries:
68
+ # SELECT albums.id, albums.name, ...
69
+ # artist.id AS artist_id, artist.name AS artist_name, ...
70
+ # FROM albums
71
+ # LEFT OUTER JOIN artists AS artist ON (artist.id = albums.artist_id);
72
+ # SELECT * FROM artists WHERE (id IN (...));
73
+
74
+ You can also use +eager+ to load initial associations, and +eager_graph+ to load
75
+ remaining associations, by using +eager_graph+ in an eager load callback:
76
+
77
+ Artist.eager(albums: {tracks: proc{|ds| ds.eager_graph(:lyric)}})
78
+ # 3 Queries:
79
+ # SELECT * FROM artists;
80
+ # SELECT * FROM albums WHERE (artist_id IN (...));
81
+ # SELECT tracks.id, tracks.name, ...
82
+ # lyric.id AS lyric_id, ...
83
+ # FROM tracks
84
+ # LEFT OUTER JOIN lyrics AS lyric ON (lyric.id = tracks.lyric_id)
85
+ # WHERE (tracks.album_id IN (...));
86
+
87
+ Using the +eager_graph_eager+ plugin, you can use +eager_graph+ to load the
88
+ initial associations, and +eager+ to load the remaining associations. When
89
+ you call +eager_graph_eager+, you must specify the dependency chain at
90
+ which to start the eager loading via +eager+:
91
+
92
+ Artist.plugin :eager_graph_eager
93
+ Artist.eager_graph(albums: :tracks).eager_graph_eager([:albums, :tracks], :lyric)
94
+ # 2 Queries:
95
+ # SELECT artists.id, artists.name, ...
96
+ # albums.id AS albums_id, albums.name AS albums_name, ...
97
+ # tracks.id AS tracks_id, tracks.name AS tracks_name, ...
98
+ # FROM artists
99
+ # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id)
100
+ # LEFT OUTER JOIN tracks ON (tracks.album_id= albums.id);
101
+ # SELECT * FROM lyrics WHERE (id IN (...));
102
+
103
+ These two approaches can also be nested, with +eager+ -> +eager_graph+ -> +eager+:
104
+
105
+ Album.plugin :eager_graph_eager
106
+ Artist.eager(albums: proc{|ds| ds.eager_graph(:tracks).eager_graph_eager([:tracks], :lyric)})
107
+ # 3 Queries:
108
+ # SELECT * FROM artists;
109
+ # SELECT albums.id, albums.name, ...
110
+ # tracks.id AS tracks_id, tracks.name AS tracks_name, ...
111
+ # FROM albums
112
+ # LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)
113
+ # WHERE (albums.artist_id IN (...));
114
+ # SELECT * FROM lyrics WHERE (id IN (...));
115
+
116
+ Or with 2 separate +eager_graph+ queries:
117
+
118
+ Artist.eager_graph(:albums).eager_graph_eager([:albums], :tracks=>proc{|ds| ds.eager_graph(:lyric)})
119
+ # 2 Queries:
120
+ # SELECT artists.id, artists.name, ...
121
+ # albums.id AS albums_id, albums.name AS albums_name, ...
122
+ # FROM artists
123
+ # LEFT OUTER JOIN albums ON (albums.artist_id = artists.id);
124
+ # SELECT tracks.id, tracks.name, ...
125
+ # lyric.id AS lyric_id, ...
126
+ # FROM tracks
127
+ # LEFT OUTER JOIN lyrics AS lyric ON (lyric.id = tracks.lyric_id)
128
+ # WHERE (tracks.album_id IN (...));
129
+
130
+ == Sequel::Model Association Loading Options
6
131
 
7
132
  There are a bunch of advanced association options that are available to
8
- handle more complex cases. First we'll go over some of
9
- the simpler ones:
133
+ handle more complex cases. First we'll go over some of the simpler ones:
10
134
 
11
135
  All associations take a block that can be used to further filter/modify the
12
- default dataset. There's also an :eager_block option if you want to use
13
- a different block when eager loading via <tt>Dataset#eager</tt>. Association blocks are
14
- useful for things like:
136
+ default dataset:
15
137
 
16
- Artist.one_to_many :gold_albums, :class=>:Album do |ds|
138
+ Artist.one_to_many :gold_albums, class: :Album do |ds|
17
139
  ds.where{copies_sold > 500000}
18
140
  end
19
141
 
20
- There are a whole bunch of options for changing how the association is eagerly
21
- loaded via <tt>Dataset#eager_graph</tt>: <tt>:graph_block</tt>, <tt>:graph_conditions</tt>,
22
- <tt>:graph_only_conditions</tt>, <tt>:graph_join_type</tt> (and <tt>:graph_join_table_*</tt> ones for
23
- JOINing to the join table in a many_to_many association).
142
+ There's also an :eager_block option if you want to use a different block when
143
+ eager loading via <tt>Dataset#eager</tt>.
144
+
145
+ There are many options for changing how the association is eagerly
146
+ loaded via <tt>Dataset#eager_graph</tt>:
24
147
 
25
148
  :graph_join_type :: The type of join to do (<tt>:inner</tt>, <tt>:left</tt>, <tt>:right</tt>)
26
149
  :graph_conditions :: Additional conditions to put on join (needs to be a
@@ -42,28 +165,23 @@ These can be used like this:
42
165
 
43
166
  # Makes Artist.eager_graph(:required_albums).all not return artists that
44
167
  # don't have any albums
45
- Artist.one_to_many :required_albums, :class=>:Album, :graph_join_type=>:inner
168
+ Artist.one_to_many :required_albums, class: :Album, graph_join_type: :inner
46
169
 
47
170
  # Makes sure all returned albums have the active flag set
48
- Artist.one_to_many :active_albums, :class=>:Album, \
49
- :graph_conditions=>{:active=>true}
171
+ Artist.one_to_many :active_albums, class: :Album, graph_conditions: {active: true}
50
172
 
51
173
  # Only returns albums that have sold more than 500,000 copies
52
- Artist.one_to_many :gold_albums, :class=>:Album, \
53
- :graph_block=>proc{|j,lj,js| Sequel.qualify(j, :copies_sold) > 500000}
174
+ Artist.one_to_many :gold_albums, class: :Album,
175
+ graph_block: proc{|j,lj,js| Sequel[j][:copies_sold] > 500000}
54
176
 
55
177
  # Handles the case where the tables are associated by a case insensitive name string
56
- Artist.one_to_many :albums, :key=>:artist_name, \
57
- :graph_only_conditions=>nil, \
58
- :graph_block=>proc{|j,lj,js| {Sequel.function(:lower, Sequel.qualify(j, :artist_name))=>Sequel.function(:lower, Sequel.qualify(lj, :name))}}
178
+ Artist.one_to_many :albums, key: :artist_name,
179
+ graph_only_conditions: nil,
180
+ graph_block: proc{|j,lj,js| {Sequel.function(:lower, Sequel[j][:artist_name])=>Sequel.function(:lower, Sequel[lj][:name])}}
59
181
 
60
182
  # Handles the case where both key columns have the name artist_name, and you want to use
61
183
  # a JOIN USING
62
- Artist.one_to_many :albums, :key=>:artist_name, :graph_only_conditions=>[:artist_name]
63
-
64
- Remember, using +eager_graph+ is generally only necessary when you need to
65
- filter/order based on columns in an associated table, it is recommended to
66
- use +eager+ for eager loading if possible.
184
+ Artist.one_to_many :albums, key: :artist_name, graph_only_conditions: [:artist_name]
67
185
 
68
186
  One advantage of using +eager_graph+ is that you can easily filter/order
69
187
  on columns in an associated table on a per-query basis, using regular
@@ -73,14 +191,16 @@ ordered by the albums name, you can do:
73
191
 
74
192
  albums = Artist.
75
193
  eager_graph(:albums).
76
- where(Sequel.like(:albums__name, 'A%')).
77
- order(:albums__name).
194
+ where{Sequel.like(albums[:name], 'A%')}.
195
+ order{albums[:name]}.
78
196
  all
79
197
 
80
198
  For lazy loading (e.g. Model[1].association), the <tt>:dataset</tt> option can be used
81
199
  to specify an arbitrary dataset (one that uses different keys, multiple keys,
82
200
  joins to other tables, etc.).
83
201
 
202
+ == Custom Eager Loaders
203
+
84
204
  For eager loading via +eager+, the <tt>:eager_loader</tt> option can be used to specify
85
205
  how to eagerly load a complex association. This is an extremely powerful
86
206
  option. Though it can often be verbose (compared to other things in Sequel),
@@ -211,7 +331,7 @@ and the tracks eager loader looks like:
211
331
  Album.one_to_many :tracks, :eager_loader=>(proc do |eo_opts|
212
332
  eo_opts[:rows].each{|album| album.associations[:tracks] = []}
213
333
  id_map = eo_opts[:id_map]
214
- Track.where(:id=>id_map.keys).all do |tracks|
334
+ Track.where(:album_id=>id_map.keys).all do |track|
215
335
  if albums = id_map[track.album_id]
216
336
  albums.each do |album|
217
337
  album.associations[:tracks] << track
@@ -244,7 +364,7 @@ loading.
244
364
 
245
365
  Sequel supports specifying limits and/or offsets for associations:
246
366
 
247
- Artist.one_to_many :first_10_albums, :class=>:Album, :order=>:release_date, :limit=>10
367
+ Artist.one_to_many :first_10_albums, class: :Album, order: :release_date, limit: 10
248
368
 
249
369
  For retrieving the associated objects for a single object, this just uses
250
370
  a LIMIT:
@@ -260,7 +380,7 @@ approach. Sequel has 4 separate strategies for dealing with such cases.
260
380
  The default strategy used on all databases is a UNION-based approach, which
261
381
  will submit multiple subqueries in a UNION query:
262
382
 
263
- Artist.where(:id=>[1,2]).eager(:first_10_albums).all
383
+ Artist.where(id: [1,2]).eager(:first_10_albums).all
264
384
  # SELECT * FROM (SELECT * FROM albums WHERE (artist_id = 1) LIMIT 10) UNION ALL
265
385
  # SELECT * FROM (SELECT * FROM albums WHERE (artist_id = 2) LIMIT 10)
266
386
 
@@ -272,9 +392,9 @@ index, you'll want to manually specify the :eager_limit_strategy option as shown
272
392
  On PostgreSQL, for *_one associations that don't use an offset, you can
273
393
  choose to use a the distinct on strategy:
274
394
 
275
- Artist.one_to_one :first_album, :class=>:Album, :order=>:release_date,
276
- :eager_limit_strategy=>:distinct_on
277
- Artist.where(:id=>[1,2]).eager(:first_album).all
395
+ Artist.one_to_one :first_album, class: :Album, order: :release_date,
396
+ eager_limit_strategy: :distinct_on
397
+ Artist.where(id: [1,2]).eager(:first_album).all
278
398
  # SELECT DISTINCT ON (albums.artist_id) *
279
399
  # FROM albums
280
400
  # WHERE (albums.artist_id IN (1, 2))
@@ -283,8 +403,8 @@ choose to use a the distinct on strategy:
283
403
  Otherwise, if the database supports window functions, you can choose to use
284
404
  the window function strategy:
285
405
 
286
- Artist.one_to_many :first_10_albums, :class=>:Album, :order=>:release_date, :limit=>10,
287
- :eager_limit_strategy=>:window_function
406
+ Artist.one_to_many :first_10_albums, class: :Album, order: :release_date, limit: 10,
407
+ eager_limit_strategy: :window_function
288
408
  Artist.where(:id=>[1,2]).eager(:first_10_albums).all
289
409
  # SELECT * FROM (
290
410
  # SELECT *, row_number() OVER (PARTITION BY albums.artist_id ORDER BY release_date) AS x_sequel_row_number_x
@@ -304,7 +424,7 @@ known at the time of the association definition), Sequel supports an
304
424
  :eager_limit dataset option that can be defined in an eager loading callback:
305
425
 
306
426
  Artist.one_to_many :albums
307
- Artist.where(:id => [1, 2]).eager(:albums => proc{|ds| ds.order(:release_date).clone(:eager_limit => 3)}).all
427
+ Artist.where(id: [1, 2]).eager(albums: lambda{|ds| ds.order(:release_date).clone(eager_limit: 3)}).all
308
428
  # SELECT * FROM (
309
429
  # SELECT *, row_number() OVER (PARTITION BY albums.artist_id ORDER BY release_date) AS x_sequel_row_number_x
310
430
  # FROM albums
@@ -314,7 +434,7 @@ known at the time of the association definition), Sequel supports an
314
434
 
315
435
  You can also customize the :eager_limit_strategy on a case-by-case basis by passing in that option in the same way:
316
436
 
317
- Artist.where(:id => [1, 2]).eager(:albums => proc{|ds| ds.order(:release_date).clone(:eager_limit => 3, :eager_limit_strategy => :ruby)}).all
437
+ Artist.where(id: [1, 2]).eager(albums: lambda{|ds| ds.order(:release_date).clone(eager_limit: 3, eager_limit_strategy: :ruby)}).all
318
438
  # SELECT * FROM albums WHERE (albums.artist_id IN (1, 2)) ORDER BY release_date
319
439
 
320
440
  The :eager_limit and :eager_limit_strategy options currently only work when
@@ -333,7 +453,7 @@ eager_graph_with_options method with the :limit_strategy option.
333
453
  The :distinct_on strategy uses DISTINCT ON in a subquery and JOINs that
334
454
  subquery:
335
455
 
336
- Artist.eager_graph_with_options(:first_album, :limit_strategy=>true).all
456
+ Artist.eager_graph_with_options(:first_album, limit_strategy: :distinct_on).all
337
457
  # SELECT artists.id, artists.name, first_album.id AS first_album_id,
338
458
  # first_album.name AS first_album_name, first_album.artist_id,
339
459
  # first_album.release_date
@@ -347,7 +467,7 @@ subquery:
347
467
  The :window_function approach JOINs to a nested subquery using a window
348
468
  function:
349
469
 
350
- Artist.eager_graph_with_options(:first_10_albums, :limit_strategy=>true).all
470
+ Artist.eager_graph_with_options(:first_10_albums, limit_strategy: :window_function).all
351
471
  # SELECT artists.id, artists.name, first_10_albums.id AS first_10_albums_id,
352
472
  # first_10_albums.name AS first_10_albums_name, first_10_albums.artist_id,
353
473
  # first_10_albums.release_date
@@ -363,7 +483,7 @@ function:
363
483
  The :correlated_subquery approach JOINs to a nested subquery using a correlated
364
484
  subquery:
365
485
 
366
- Artist.eager_graph_with_options(:first_10_albums, :limit_strategy=>true).all
486
+ Artist.eager_graph_with_options(:first_10_albums, :limit_strategy=>:correlated_subquery).all
367
487
  # SELECT artists.id, artists.name, first_10_albums.id AS first_10_albums_id,
368
488
  # first_10_albums.name AS first_10_albums_name, first_10_albums.artist_id,
369
489
  # first_10_albums.release_date
@@ -380,8 +500,6 @@ subquery:
380
500
  # )
381
501
  # ) AS first_10_albums ON (first_10_albums.artist_id = artists.id)
382
502
 
383
- (SELECT * FROM tracks WHERE (tracks.id IN (SELECT t1.id FROM tracks AS t1 WHERE (t1.album_id = tracks.album_id) LIMIT 1)))
384
-
385
503
  The reason that Sequel does not automatically use the :distinct_on, :window function
386
504
  or :correlated_subquery strategy for eager_graph is that it can perform much worse than the
387
505
  default of just doing the array slicing in ruby. If you are only using eager_graph to
@@ -403,7 +521,7 @@ strategy based on the database you are using, and you can override it using the
403
521
 
404
522
  The :distinct_on strategy:
405
523
 
406
- Artist.where(:first_album=>Album[1]).all
524
+ Artist.where(first_album: Album[1]).all
407
525
  # SELECT *
408
526
  # FROM artists
409
527
  # WHERE (artists.id IN (
@@ -417,7 +535,7 @@ The :distinct_on strategy:
417
535
 
418
536
  The :window_function strategy:
419
537
 
420
- Artist.where(:first_10_albums=>Album[1]).all
538
+ Artist.where(first_10_albums: Album[1]).all
421
539
  # SELECT *
422
540
  # FROM artists
423
541
  # WHERE (artists.id IN (
@@ -433,7 +551,7 @@ The :window_function strategy:
433
551
 
434
552
  The :correlated_subquery strategy:
435
553
 
436
- Artist.where(:first_10_albums=>Album[1]).all
554
+ Artist.where(first_10_albums: Album[1]).all
437
555
  # SELECT *
438
556
  # FROM artists
439
557
  # WHERE (artists.id IN (
@@ -447,11 +565,11 @@ The :correlated_subquery strategy:
447
565
  # LIMIT 1
448
566
  # )) AND (albums.id = 1))))
449
567
 
450
- Note that filtering by limited associations does not work on MySQL, as does not support
568
+ Note that filtering by limited associations does not work on MySQL, as MySQL does not support
451
569
  any of the strategies. It's also not supported when using composite keys on databases
452
570
  that don't support window functions and don't support multiple columns in IN.
453
571
 
454
- == Additional Association Types
572
+ === Additional Association Types
455
573
 
456
574
  While the above examples for limited associations showed one_to_many and one_to_one associations,
457
575
  it's just because those are the simplest examples. Sequel supports all of the same features for
@@ -459,29 +577,7 @@ many_to_many and one_through_one associations that are enabled by default, as we
459
577
  many_through_many and one_through_many associations that are added by the many_through_many
460
578
  plugin.
461
579
 
462
- == ActiveRecord associations
463
-
464
- Sequel supports all of associations that ActiveRecord supports, though some
465
- require different approaches or custom <tt>:eager_loader</tt> options.
466
-
467
- === Association callbacks
468
-
469
- Sequel supports the same callbacks that ActiveRecord does for +one_to_many+ and
470
- +many_to_many+ associations: <tt>:before_add</tt>, <tt>:before_remove</tt>, <tt>:after_add</tt>, and
471
- <tt>:after_remove</tt>. For +many_to_one+ associations and +one_to_one+ associations, Sequel
472
- supports the <tt>:before_set</tt> and <tt>:after_set</tt> callbacks. On all associations,
473
- Sequel supports <tt>:after_load</tt>, which is called after the association has been
474
- loaded.
475
-
476
- Each of these options can be a symbol specifying an instance method
477
- that takes one argument (the associated object), or a proc that takes
478
- two arguments (the current object and the associated object), or an
479
- array of symbols and procs. For <tt>:after_load</tt> with a *_to_many association,
480
- the associated object argument is an array of associated objects.
481
-
482
- If any of the before callbacks return +false+, the adding/removing
483
- does not happen and it either raises a <tt>Sequel::HookFailed</tt> (the default), or
484
- returns false (if +raise_on_save_failure+ is false).
580
+ == More advanced association examples
485
581
 
486
582
  === Association extensions
487
583
 
@@ -504,36 +600,21 @@ the model object that created the association dataset via the dataset's
504
600
  end
505
601
  end
506
602
  class Author < Sequel::Model
507
- one_to_many :authorships, :extend=>FindOrCreate
603
+ one_to_many :authorships, extend: FindOrCreate
508
604
  end
509
- Author.first.authorships_dataset.find_or_create(:name=>'Blah', :number=>10)
605
+ Author.first.authorships_dataset.find_or_create(name: 'Blah', number: 10)
510
606
 
511
- === <tt>has_many :through</tt> associations
607
+ === many_to_many associations through model tables
512
608
 
513
- +many_to_many+ handles the usual case of a <tt>has_many :through</tt> with a +belongs_to+ in
514
- the associated model. It doesn't break on the case where the join table is a
515
- model table, unlike ActiveRecord's +has_and_belongs_to_many+.
516
-
517
- ActiveRecord:
518
-
519
- class Author < ActiveRecord::Base
520
- has_many :authorships
521
- has_many :books, :through => :authorships
522
- end
523
-
524
- class Authorship < ActiveRecord::Base
525
- belongs_to :author
526
- belongs_to :book
527
- end
528
-
529
- @author = Author.find :first
530
- @author.books
531
-
532
- Sequel::Model:
609
+ The many_to_many association can be used even when the join table is a table used for a
610
+ model. The only requirement is the join table has foreign keys to both the current
611
+ model and the associated model. Anytime there is a one_to_many association from model A to
612
+ model B, and model B has a many_to_one association to model C, you can use a many_to_many
613
+ association from model A to model C.
533
614
 
534
615
  class Author < Sequel::Model
535
616
  one_to_many :authorships
536
- many_to_many :books, :join_table=>:authorships
617
+ many_to_many :books, join_table: :authorships
537
618
  end
538
619
 
539
620
  class Authorship < Sequel::Model
@@ -544,33 +625,17 @@ Sequel::Model:
544
625
  @author = Author.first
545
626
  @author.books
546
627
 
547
- If you use an association other than +belongs_to+ in the associated model, such as a +has_many+,
548
- you still use a +many_to_many+ association, but you need to use some options:
549
-
550
- ActiveRecord:
551
-
552
- class Firm < ActiveRecord::Base
553
- has_many :clients
554
- has_many :invoices, :through => :clients
555
- end
556
-
557
- class Client < ActiveRecord::Base
558
- belongs_to :firm
559
- has_many :invoices
560
- end
561
-
562
- class Invoice < ActiveRecord::Base
563
- belongs_to :client
564
- has_one :firm, :through => :client
565
- end
628
+ === many_to_many for three-level associations
566
629
 
567
- Firm.find(:first).invoices
568
-
569
- Sequel::Model:
630
+ You can even use a many_to_many association between model A and model C if model A has a
631
+ one_to_many association to model B, and model B has a one_to_many association to model C.
632
+ You just need to use the appropriate :right_key and :right_primary_key options. And in
633
+ the reverse direction from model C to model A, you can use a one_through_one association
634
+ using the :left_key and :left_primary_key options.
570
635
 
571
636
  class Firm < Sequel::Model
572
637
  one_to_many :clients
573
- many_to_many :invoices, :join_table=>:clients, :right_key=>:id, :right_primary_key=>:client_id
638
+ many_to_many :invoices, join_table: :clients, right_key: :id, right_primary_key: :client_id
574
639
  end
575
640
 
576
641
  class Client < Sequel::Model
@@ -580,12 +645,13 @@ Sequel::Model:
580
645
 
581
646
  class Invoice < Sequel::Model
582
647
  many_to_one :client
583
- one_through_one :firm, :join_table=>:clients, :left_key=>:id, :left_primary_key=>:client_id, :right_key=>:firm_id
648
+ one_through_one :firm, join_table: :clients, left_key: :id, left_primary_key: :client_id
584
649
  end
585
650
 
586
651
  Firm.first.invoices
652
+ Invoice.first.firm
587
653
 
588
- To handle cases where there are multiple join tables, use the many_through_many
654
+ To handle cases where there are multiple join tables, you can use the many_through_many
589
655
  plugin that ships with Sequel.
590
656
 
591
657
  === Polymorphic Associations
@@ -602,38 +668,19 @@ you are stuck with an existing design that uses them.
602
668
  If you must use them, look for the sequel_polymorphic external plugin, as it makes using
603
669
  polymorphic associations in Sequel about as easy as it is in ActiveRecord. However,
604
670
  here's how they can be done using Sequel's custom associations (the sequel_polymorphic
605
- plugin is just a generic version of this code):
606
-
607
- ActiveRecord:
608
-
609
- class Asset < ActiveRecord::Base
610
- belongs_to :attachable, :polymorphic => true
611
- end
612
-
613
- class Post < ActiveRecord::Base
614
- has_many :assets, :as => :attachable
615
- end
616
-
617
- class Note < ActiveRecord::Base
618
- has_many :assets, :as => :attachable
619
- end
620
-
621
- @asset.attachable = @post
622
- @asset.attachable = @note
623
-
624
- Sequel::Model:
671
+ external plugin is just a generic version of this code):
625
672
 
626
673
  class Asset < Sequel::Model
627
- many_to_one :attachable, :reciprocal=>:assets,
628
- :setter=>(proc do |attachable|
674
+ many_to_one :attachable, reciprocal: :assets,
675
+ setter: (lambda do |attachable|
629
676
  self[:attachable_id] = (attachable.pk if attachable)
630
677
  self[:attachable_type] = (attachable.class.name if attachable)
631
678
  end),
632
- :dataset=>(proc do
679
+ dataset: (proc do
633
680
  klass = attachable_type.constantize
634
681
  klass.where(klass.primary_key=>attachable_id)
635
682
  end),
636
- :eager_loader=>(proc do |eo|
683
+ eager_loader: (lambda do |eo|
637
684
  id_map = {}
638
685
  eo[:rows].each do |asset|
639
686
  asset.associations[:attachable] = nil
@@ -651,24 +698,22 @@ Sequel::Model:
651
698
  end
652
699
 
653
700
  class Post < Sequel::Model
654
- one_to_many :assets, :key=>:attachable_id, :reciprocal=>:attachable, :conditions=>{:attachable_type=>'Post'},
655
- :adder=>proc{|asset| asset.update(:attachable_id=>pk, :attachable_type=>'Post')},
656
- :remover=>proc{|asset| asset.update(:attachable_id=>nil, :attachable_type=>nil)},
657
- :clearer=>proc{assets_dataset.update(:attachable_id=>nil, :attachable_type=>nil)}
701
+ one_to_many :assets, key: :attachable_id, reciprocal: :attachable, conditions: {attachable_type: 'Post'},
702
+ adder: lambda{|asset| asset.update(attachable_id: pk, attachable_type: 'Post')},
703
+ remover: lambda{|asset| asset.update(attachable_id: nil, attachable_type: nil)},
704
+ clearer: lambda{assets_dataset.update(attachable_id: nil, attachable_type: nil)}
658
705
  end
659
706
 
660
707
  class Note < Sequel::Model
661
- one_to_many :assets, :key=>:attachable_id, :reciprocal=>:attachable, :conditions=>{:attachable_type=>'Note'},
662
- :adder=>proc{|asset| asset.update(:attachable_id=>pk, :attachable_type=>'Note')},
663
- :remover=>proc{|asset| asset.update(:attachable_id=>nil, :attachable_type=>nil)},
664
- :clearer=>proc{assets_dataset.update(:attachable_id=>nil, :attachable_type=>nil)}
708
+ one_to_many :assets, key: :attachable_id, reciprocal: :attachable, conditions: {attachable_type: 'Note'},
709
+ adder: lambda{|asset| asset.update(attachable_id: pk, attachable_type: 'Note')},
710
+ remover: lambda{|asset| asset.update(attachable_id: nil, attachable_type: nil)},
711
+ clearer: lambda{assets_dataset.update(attachable_id: nil, attachable_type: nil)}
665
712
  end
666
713
 
667
714
  @asset.attachable = @post
668
715
  @asset.attachable = @note
669
716
 
670
- == Other advanced associations
671
-
672
717
  === Joining on multiple keys
673
718
 
674
719
  Let's say you have two tables that are associated with each other with multiple
@@ -680,36 +725,36 @@ associations:
680
725
  # associated favorite track
681
726
 
682
727
  class Track < Sequel::Model
683
- many_to_one :favorite_track, :key=>[:disc_number, :number, :album_id], :primary_key=>[:disc_number, :number, :album_id]
728
+ many_to_one :favorite_track, key: [:disc_number, :number, :album_id], primary_key: [:disc_number, :number, :album_id]
684
729
  end
685
730
  class FavoriteTrack < Sequel::Model
686
- one_to_one :tracks, :key=>[:disc_number, :number, :album_id], :primary_key=>[:disc_number, :number, :album_id]
731
+ one_to_one :tracks, key: [:disc_number, :number, :album_id], primary_key: [:disc_number, :number, :album_id]
687
732
  end
688
733
 
689
- === Tree - All Ancestors and Descendents
734
+ === Tree - All Ancestors and Descendants
690
735
 
691
736
  Let's say you want to store a tree relationship in your database, it's pretty
692
737
  simple:
693
738
 
694
739
  class Node < Sequel::Model
695
- many_to_one :parent, :class=>self
696
- one_to_many :children, :key=>:parent_id, :class=>self
740
+ many_to_one :parent, class: self
741
+ one_to_many :children, key: :parent_id, class: self
697
742
  end
698
743
 
699
744
  You can easily get a node's parent with node.parent, and a node's children with
700
745
  node.children. You can even eager load the relationship up to a certain depth:
701
746
 
702
747
  # Eager load three generations of generations of children for a given node
703
- Node.filter(:id=>1).eager(:children=>{:children=>:children}).all.first
748
+ Node.where(id: 1).eager(children: {children: :children}).all.first
704
749
  # Load parents and grandparents for a group of nodes
705
- Node.filter{id < 10}.eager(:parent=>:parent).all
750
+ Node.where{id < 10}.eager(parent: :parent).all
706
751
 
707
- What if you want to get all ancestors up to the root node, or all descendents,
752
+ What if you want to get all ancestors up to the root node, or all descendants,
708
753
  without knowing the depth of the tree?
709
754
 
710
755
  class Node < Sequel::Model
711
- many_to_one :ancestors, :class=>self,
712
- :eager_loader=>(proc do |eo|
756
+ many_to_one :ancestors, class: self,
757
+ eager_loader: (lambda do |eo|
713
758
  # Handle cases where the root node has the same parent_id as primary_key
714
759
  # and also when it is NULL
715
760
  non_root_nodes = eo[:rows].reject do |n|
@@ -725,15 +770,15 @@ without knowing the depth of the tree?
725
770
  id_map = {}
726
771
  # Create an map of parent_ids to nodes that have that parent id
727
772
  non_root_nodes.each{|n| (id_map[n.parent_id] ||= []) << n}
728
- # Doesn't cause an infinte loop, because when only the root node
773
+ # Doesn't cause an infinite loop, because when only the root node
729
774
  # is left, this is not called.
730
- Node.where(Node.primary_key=>id_map.keys).eager(:ancestors).all do |node|
775
+ Node.where(id: id_map.keys).eager(:ancestors).all do |node|
731
776
  # Populate the parent association for each node
732
777
  id_map[node.pk].each{|n| n.associations[:parent] = node}
733
778
  end
734
779
  end
735
780
  end)
736
- many_to_one :descendants, :eager_loader=>(proc do |eo|
781
+ many_to_one :descendants, eager_loader: (lambda do |eo|
737
782
  id_map = {}
738
783
  eo[:rows].each do |n|
739
784
  # Initialize an empty array of child associations for each parent node
@@ -745,7 +790,7 @@ without knowing the depth of the tree?
745
790
  # if no records are returned. Exclude id = parent_id to avoid infinite loop
746
791
  # if the root note is one of the returned records and it has parent_id = id
747
792
  # instead of parent_id = NULL.
748
- Node.where(:parent_id=>id_map.keys).exclude(:id=>:parent_id).eager(:descendants).all do |node|
793
+ Node.where(parent_id: id_map.keys).exclude(id: :parent_id).eager(:descendants).all do |node|
749
794
  # Get the parent from the identity map
750
795
  parent = id_map[node.parent_id]
751
796
  # Set the child's parent association to the parent
@@ -756,11 +801,7 @@ without knowing the depth of the tree?
756
801
  end)
757
802
  end
758
803
 
759
- Note that unlike ActiveRecord, Sequel supports common table expressions, which allows you to use recursive queries.
760
- The results are not the same as in the above case, as all descendents are stored in a single association,
761
- but all descendants can be both lazy loaded or eager loaded in a single query (assuming your database
762
- supports recursive common table expressions). Sequel ships with an +rcte_tree+ plugin that makes
763
- this easy:
804
+ Note that Sequel ships with an rcte_tree plugin that does all of the above and more:
764
805
 
765
806
  class Node < Sequel::Model
766
807
  plugin :rcte_tree
@@ -780,21 +821,21 @@ What you want to do is get all songs for a given artist, ordered by the song's
780
821
  name, with no duplicates?
781
822
 
782
823
  class Artist < Sequel::Model
783
- one_to_many :songs, :order=>:songs__name, \
784
- :dataset=>proc{Song.select_all(:songs).join(Lyric, :id=>:lyric_id, id=>[:composer_id, :arranger_id, :vocalist_id, :lyricist_id])}, \
785
- :eager_loader=>(proc do |eo|
824
+ one_to_many :songs, order: Sequel[:songs][:name],
825
+ dataset: proc{Song.select_all(:songs).join(:lyrics, id: :lyric_id, id=>[:composer_id, :arranger_id, :vocalist_id, :lyricist_id])},
826
+ eager_loader: (lambda do |eo|
786
827
  h = eo[:id_map]
787
828
  ids = h.keys
788
829
  eo[:rows].each{|r| r.associations[:songs] = []}
789
830
  Song.select_all(:songs).
790
- select_append(:lyrics__composer_id, :lyrics__arranger_id, :lyrics__vocalist_id, :lyrics__lyricist_id).
791
- join(Lyric, :id=>:lyric_id){Sequel.or(:composer_id=>ids, :arranger_id=>ids, :vocalist_id=>ids, :lyricist_id=>ids)}.
792
- order(:songs__name).all do |song|
793
- [:composer_id, :arranger_id, :vocalist_id, :lyricist_id].each do |x|
794
- recs = h[song.values.delete(x)]
795
- recs.each{|r| r.associations[:songs] << song} if recs
831
+ select_append{[lyrics[:composer_id], lyrics[:arranger_id], lyrics[:vocalist_id], lyrics[:lyricist_id]]}.
832
+ join(:lyrics, id: :lyric_id){Sequel.or(composer_id: ids, arranger_id: ids, vocalist_id: ids, lyricist_id: ids)}.
833
+ order{songs[:name]}.all do |song|
834
+ [:composer_id, :arranger_id, :vocalist_id, :lyricist_id].each do |x|
835
+ recs = h[song.values.delete(x)]
836
+ recs.each{|r| r.associations[:songs] << song} if recs
837
+ end
796
838
  end
797
- end
798
839
  eo[:rows].each{|r| r.associations[:songs].uniq!}
799
840
  end)
800
841
  end
@@ -811,11 +852,11 @@ associated tickets.
811
852
 
812
853
  class Project < Sequel::Model
813
854
  one_to_many :tickets
814
- many_to_one :ticket_hours, :read_only=>true, :key=>:id,
815
- :dataset=>proc{Ticket.where(:project_id=>id).select{sum(hours).as(hours)}},
816
- :eager_loader=>(proc do |eo|
855
+ many_to_one :ticket_hours, read_only: true, key: :id,
856
+ dataset: proc{Ticket.where(:project_id=>id).select{sum(hours).as(hours)}},
857
+ eager_loader: (lambda do |eo|
817
858
  eo[:rows].each{|p| p.associations[:ticket_hours] = nil}
818
- Ticket.where(:project_id=>eo[:id_map].keys).
859
+ Ticket.where(project_id: eo[:id_map].keys).
819
860
  select_group(:project_id).
820
861
  select_append{sum(hours).as(hours)}.
821
862
  all do |t|
@@ -838,4 +879,4 @@ associated tickets.
838
879
  end
839
880
 
840
881
  Note that it is often better to use a sum cache instead of this approach. You can implement
841
- a sum cache using +after_create+ and +after_delete+ hooks, or preferrably using a database trigger.
882
+ a sum cache using +after_create+, +after_update+, and +after_delete+ hooks, or preferably using a database trigger.