sequel 4.49.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (477) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +70 -0
  3. data/README.rdoc +195 -136
  4. data/Rakefile +26 -42
  5. data/bin/sequel +3 -5
  6. data/doc/advanced_associations.rdoc +86 -163
  7. data/doc/association_basics.rdoc +197 -274
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +66 -43
  10. data/doc/code_order.rdoc +1 -8
  11. data/doc/core_extensions.rdoc +81 -56
  12. data/doc/dataset_basics.rdoc +8 -17
  13. data/doc/dataset_filtering.rdoc +81 -86
  14. data/doc/extensions.rdoc +3 -10
  15. data/doc/mass_assignment.rdoc +73 -30
  16. data/doc/migration.rdoc +19 -36
  17. data/doc/model_dataset_method_design.rdoc +14 -17
  18. data/doc/model_hooks.rdoc +15 -25
  19. data/doc/model_plugins.rdoc +10 -10
  20. data/doc/mssql_stored_procedures.rdoc +3 -3
  21. data/doc/object_model.rdoc +52 -70
  22. data/doc/opening_databases.rdoc +39 -32
  23. data/doc/postgresql.rdoc +48 -38
  24. data/doc/prepared_statements.rdoc +27 -22
  25. data/doc/querying.rdoc +173 -150
  26. data/doc/reflection.rdoc +5 -6
  27. data/doc/release_notes/5.0.0.txt +159 -0
  28. data/doc/schema_modification.rdoc +63 -60
  29. data/doc/security.rdoc +97 -88
  30. data/doc/sharding.rdoc +43 -30
  31. data/doc/sql.rdoc +53 -65
  32. data/doc/testing.rdoc +3 -5
  33. data/doc/thread_safety.rdoc +2 -4
  34. data/doc/transactions.rdoc +18 -17
  35. data/doc/validations.rdoc +48 -45
  36. data/doc/virtual_rows.rdoc +87 -115
  37. data/lib/sequel.rb +1 -1
  38. data/lib/sequel/adapters/ado.rb +9 -25
  39. data/lib/sequel/adapters/ado/access.rb +7 -13
  40. data/lib/sequel/adapters/ado/mssql.rb +2 -9
  41. data/lib/sequel/adapters/amalgalite.rb +3 -18
  42. data/lib/sequel/adapters/ibmdb.rb +9 -45
  43. data/lib/sequel/adapters/jdbc.rb +13 -73
  44. data/lib/sequel/adapters/jdbc/db2.rb +8 -37
  45. data/lib/sequel/adapters/jdbc/derby.rb +4 -50
  46. data/lib/sequel/adapters/jdbc/h2.rb +4 -25
  47. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -26
  48. data/lib/sequel/adapters/jdbc/jtds.rb +2 -9
  49. data/lib/sequel/adapters/jdbc/mssql.rb +1 -11
  50. data/lib/sequel/adapters/jdbc/mysql.rb +1 -15
  51. data/lib/sequel/adapters/jdbc/oracle.rb +4 -26
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +2 -31
  53. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +4 -17
  54. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -7
  55. data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -13
  56. data/lib/sequel/adapters/jdbc/transactions.rb +1 -14
  57. data/lib/sequel/adapters/mock.rb +4 -30
  58. data/lib/sequel/adapters/mysql.rb +7 -44
  59. data/lib/sequel/adapters/mysql2.rb +5 -23
  60. data/lib/sequel/adapters/odbc.rb +0 -19
  61. data/lib/sequel/adapters/odbc/db2.rb +1 -1
  62. data/lib/sequel/adapters/odbc/mssql.rb +4 -12
  63. data/lib/sequel/adapters/odbc/oracle.rb +1 -1
  64. data/lib/sequel/adapters/oracle.rb +7 -13
  65. data/lib/sequel/adapters/postgres.rb +13 -57
  66. data/lib/sequel/adapters/postgresql.rb +1 -1
  67. data/lib/sequel/adapters/shared/access.rb +11 -51
  68. data/lib/sequel/adapters/shared/db2.rb +3 -61
  69. data/lib/sequel/adapters/shared/mssql.rb +21 -157
  70. data/lib/sequel/adapters/shared/mysql.rb +23 -224
  71. data/lib/sequel/adapters/shared/oracle.rb +13 -41
  72. data/lib/sequel/adapters/shared/postgres.rb +44 -259
  73. data/lib/sequel/adapters/shared/sqlanywhere.rb +4 -96
  74. data/lib/sequel/adapters/shared/sqlite.rb +12 -101
  75. data/lib/sequel/adapters/sqlanywhere.rb +4 -23
  76. data/lib/sequel/adapters/sqlite.rb +2 -19
  77. data/lib/sequel/adapters/tinytds.rb +5 -15
  78. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
  79. data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -4
  80. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +3 -6
  81. data/lib/sequel/adapters/utils/replace.rb +0 -5
  82. data/lib/sequel/adapters/utils/stored_procedures.rb +0 -2
  83. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +2 -0
  84. data/lib/sequel/ast_transformer.rb +3 -94
  85. data/lib/sequel/connection_pool.rb +26 -28
  86. data/lib/sequel/connection_pool/sharded_single.rb +1 -4
  87. data/lib/sequel/connection_pool/sharded_threaded.rb +97 -95
  88. data/lib/sequel/connection_pool/single.rb +0 -2
  89. data/lib/sequel/connection_pool/threaded.rb +94 -110
  90. data/lib/sequel/core.rb +42 -101
  91. data/lib/sequel/database.rb +12 -2
  92. data/lib/sequel/database/connecting.rb +23 -60
  93. data/lib/sequel/database/dataset.rb +6 -9
  94. data/lib/sequel/database/dataset_defaults.rb +4 -48
  95. data/lib/sequel/database/features.rb +5 -4
  96. data/lib/sequel/database/logging.rb +2 -9
  97. data/lib/sequel/database/misc.rb +23 -55
  98. data/lib/sequel/database/query.rb +8 -13
  99. data/lib/sequel/database/schema_generator.rb +89 -64
  100. data/lib/sequel/database/schema_methods.rb +61 -79
  101. data/lib/sequel/database/transactions.rb +4 -24
  102. data/lib/sequel/dataset.rb +18 -10
  103. data/lib/sequel/dataset/actions.rb +53 -107
  104. data/lib/sequel/dataset/dataset_module.rb +3 -15
  105. data/lib/sequel/dataset/features.rb +30 -30
  106. data/lib/sequel/dataset/graph.rb +40 -49
  107. data/lib/sequel/dataset/misc.rb +12 -37
  108. data/lib/sequel/dataset/placeholder_literalizer.rb +4 -4
  109. data/lib/sequel/dataset/prepared_statements.rb +23 -51
  110. data/lib/sequel/dataset/query.rb +71 -155
  111. data/lib/sequel/dataset/sql.rb +30 -225
  112. data/lib/sequel/deprecated.rb +18 -27
  113. data/lib/sequel/exceptions.rb +1 -17
  114. data/lib/sequel/extensions/_model_pg_row.rb +0 -7
  115. data/lib/sequel/extensions/_pretty_table.rb +1 -3
  116. data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
  117. data/lib/sequel/extensions/connection_expiration.rb +1 -1
  118. data/lib/sequel/extensions/connection_validator.rb +1 -1
  119. data/lib/sequel/extensions/constraint_validations.rb +11 -11
  120. data/lib/sequel/extensions/core_extensions.rb +39 -49
  121. data/lib/sequel/extensions/core_refinements.rb +39 -45
  122. data/lib/sequel/extensions/current_datetime_timestamp.rb +0 -4
  123. data/lib/sequel/extensions/date_arithmetic.rb +7 -7
  124. data/lib/sequel/extensions/duplicate_columns_handler.rb +12 -9
  125. data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
  126. data/lib/sequel/extensions/eval_inspect.rb +4 -11
  127. data/lib/sequel/extensions/freeze_datasets.rb +1 -69
  128. data/lib/sequel/extensions/from_block.rb +1 -35
  129. data/lib/sequel/extensions/graph_each.rb +2 -2
  130. data/lib/sequel/extensions/identifier_mangling.rb +9 -19
  131. data/lib/sequel/extensions/implicit_subquery.rb +2 -2
  132. data/lib/sequel/extensions/inflector.rb +4 -4
  133. data/lib/sequel/extensions/migration.rb +23 -40
  134. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -84
  135. data/lib/sequel/extensions/null_dataset.rb +2 -8
  136. data/lib/sequel/extensions/pagination.rb +1 -17
  137. data/lib/sequel/extensions/pg_array.rb +20 -189
  138. data/lib/sequel/extensions/pg_hstore.rb +11 -50
  139. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
  140. data/lib/sequel/extensions/pg_inet.rb +2 -15
  141. data/lib/sequel/extensions/pg_interval.rb +1 -20
  142. data/lib/sequel/extensions/pg_json.rb +7 -27
  143. data/lib/sequel/extensions/pg_loose_count.rb +1 -1
  144. data/lib/sequel/extensions/pg_range.rb +6 -121
  145. data/lib/sequel/extensions/pg_range_ops.rb +1 -3
  146. data/lib/sequel/extensions/pg_row.rb +5 -77
  147. data/lib/sequel/extensions/pg_row_ops.rb +2 -13
  148. data/lib/sequel/extensions/query.rb +3 -4
  149. data/lib/sequel/extensions/round_timestamps.rb +0 -6
  150. data/lib/sequel/extensions/schema_dumper.rb +13 -13
  151. data/lib/sequel/extensions/select_remove.rb +3 -3
  152. data/lib/sequel/extensions/split_array_nil.rb +2 -2
  153. data/lib/sequel/extensions/sql_comments.rb +2 -2
  154. data/lib/sequel/extensions/string_agg.rb +11 -8
  155. data/lib/sequel/extensions/symbol_aref.rb +6 -20
  156. data/lib/sequel/model.rb +27 -62
  157. data/lib/sequel/model/associations.rb +128 -131
  158. data/lib/sequel/model/base.rb +171 -711
  159. data/lib/sequel/model/default_inflections.rb +1 -1
  160. data/lib/sequel/model/errors.rb +0 -3
  161. data/lib/sequel/model/exceptions.rb +2 -6
  162. data/lib/sequel/model/inflections.rb +1 -26
  163. data/lib/sequel/model/plugins.rb +1 -0
  164. data/lib/sequel/plugins/active_model.rb +2 -5
  165. data/lib/sequel/plugins/association_dependencies.rb +15 -15
  166. data/lib/sequel/plugins/association_pks.rb +14 -28
  167. data/lib/sequel/plugins/association_proxies.rb +6 -7
  168. data/lib/sequel/plugins/auto_validations.rb +4 -4
  169. data/lib/sequel/plugins/before_after_save.rb +0 -43
  170. data/lib/sequel/plugins/blacklist_security.rb +9 -8
  171. data/lib/sequel/plugins/boolean_readers.rb +3 -3
  172. data/lib/sequel/plugins/boolean_subsets.rb +2 -2
  173. data/lib/sequel/plugins/caching.rb +5 -5
  174. data/lib/sequel/plugins/class_table_inheritance.rb +71 -102
  175. data/lib/sequel/plugins/column_conflicts.rb +2 -2
  176. data/lib/sequel/plugins/column_select.rb +2 -2
  177. data/lib/sequel/plugins/composition.rb +15 -24
  178. data/lib/sequel/plugins/constraint_validations.rb +4 -3
  179. data/lib/sequel/plugins/csv_serializer.rb +13 -20
  180. data/lib/sequel/plugins/dataset_associations.rb +2 -2
  181. data/lib/sequel/plugins/def_dataset_method.rb +5 -5
  182. data/lib/sequel/plugins/defaults_setter.rb +1 -1
  183. data/lib/sequel/plugins/delay_add_association.rb +1 -1
  184. data/lib/sequel/plugins/finder.rb +16 -10
  185. data/lib/sequel/plugins/force_encoding.rb +1 -7
  186. data/lib/sequel/plugins/hook_class_methods.rb +4 -106
  187. data/lib/sequel/plugins/input_transformer.rb +10 -11
  188. data/lib/sequel/plugins/insert_returning_select.rb +1 -9
  189. data/lib/sequel/plugins/instance_filters.rb +5 -5
  190. data/lib/sequel/plugins/instance_hooks.rb +7 -52
  191. data/lib/sequel/plugins/inverted_subsets.rb +3 -1
  192. data/lib/sequel/plugins/json_serializer.rb +19 -19
  193. data/lib/sequel/plugins/lazy_attributes.rb +1 -10
  194. data/lib/sequel/plugins/list.rb +6 -6
  195. data/lib/sequel/plugins/many_through_many.rb +11 -8
  196. data/lib/sequel/plugins/mssql_optimistic_locking.rb +3 -3
  197. data/lib/sequel/plugins/nested_attributes.rb +18 -31
  198. data/lib/sequel/plugins/optimistic_locking.rb +3 -3
  199. data/lib/sequel/plugins/pg_array_associations.rb +8 -2
  200. data/lib/sequel/plugins/pg_row.rb +2 -11
  201. data/lib/sequel/plugins/prepared_statements.rb +13 -66
  202. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -1
  203. data/lib/sequel/plugins/rcte_tree.rb +7 -7
  204. data/lib/sequel/plugins/serialization.rb +15 -33
  205. data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
  206. data/lib/sequel/plugins/sharding.rb +2 -8
  207. data/lib/sequel/plugins/single_table_inheritance.rb +10 -13
  208. data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
  209. data/lib/sequel/plugins/static_cache.rb +8 -9
  210. data/lib/sequel/plugins/string_stripper.rb +3 -3
  211. data/lib/sequel/plugins/subclasses.rb +1 -1
  212. data/lib/sequel/plugins/subset_conditions.rb +2 -2
  213. data/lib/sequel/plugins/table_select.rb +2 -2
  214. data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
  215. data/lib/sequel/plugins/timestamps.rb +6 -7
  216. data/lib/sequel/plugins/touch.rb +4 -8
  217. data/lib/sequel/plugins/tree.rb +3 -3
  218. data/lib/sequel/plugins/typecast_on_load.rb +2 -2
  219. data/lib/sequel/plugins/unlimited_update.rb +1 -7
  220. data/lib/sequel/plugins/update_or_create.rb +3 -3
  221. data/lib/sequel/plugins/update_refresh.rb +3 -3
  222. data/lib/sequel/plugins/uuid.rb +7 -11
  223. data/lib/sequel/plugins/validation_class_methods.rb +10 -9
  224. data/lib/sequel/plugins/validation_contexts.rb +4 -4
  225. data/lib/sequel/plugins/validation_helpers.rb +26 -25
  226. data/lib/sequel/plugins/whitelist_security.rb +13 -9
  227. data/lib/sequel/plugins/xml_serializer.rb +24 -25
  228. data/lib/sequel/sql.rb +145 -276
  229. data/lib/sequel/timezones.rb +8 -22
  230. data/lib/sequel/version.rb +2 -2
  231. data/spec/adapter_spec.rb +1 -1
  232. data/spec/adapters/db2_spec.rb +2 -103
  233. data/spec/adapters/mssql_spec.rb +89 -68
  234. data/spec/adapters/mysql_spec.rb +101 -480
  235. data/spec/adapters/oracle_spec.rb +1 -9
  236. data/spec/adapters/postgres_spec.rb +312 -565
  237. data/spec/adapters/spec_helper.rb +12 -31
  238. data/spec/adapters/sqlanywhere_spec.rb +2 -77
  239. data/spec/adapters/sqlite_spec.rb +8 -146
  240. data/spec/bin_spec.rb +11 -16
  241. data/spec/core/connection_pool_spec.rb +173 -74
  242. data/spec/core/database_spec.rb +64 -244
  243. data/spec/core/dataset_spec.rb +81 -415
  244. data/spec/core/deprecated_spec.rb +3 -3
  245. data/spec/core/expression_filters_spec.rb +37 -144
  246. data/spec/core/mock_adapter_spec.rb +176 -4
  247. data/spec/core/object_graph_spec.rb +11 -60
  248. data/spec/core/placeholder_literalizer_spec.rb +1 -14
  249. data/spec/core/schema_generator_spec.rb +51 -40
  250. data/spec/core/schema_spec.rb +74 -77
  251. data/spec/core/spec_helper.rb +6 -24
  252. data/spec/core/version_spec.rb +1 -1
  253. data/spec/core_extensions_spec.rb +7 -83
  254. data/spec/core_model_spec.rb +2 -2
  255. data/spec/deprecation_helper.rb +2 -14
  256. data/spec/extensions/accessed_columns_spec.rb +1 -1
  257. data/spec/extensions/active_model_spec.rb +3 -3
  258. data/spec/extensions/after_initialize_spec.rb +1 -1
  259. data/spec/extensions/arbitrary_servers_spec.rb +2 -2
  260. data/spec/extensions/association_dependencies_spec.rb +1 -1
  261. data/spec/extensions/association_pks_spec.rb +4 -59
  262. data/spec/extensions/association_proxies_spec.rb +1 -1
  263. data/spec/extensions/auto_literal_strings_spec.rb +1 -12
  264. data/spec/extensions/auto_validations_spec.rb +1 -1
  265. data/spec/extensions/blacklist_security_spec.rb +1 -1
  266. data/spec/extensions/blank_spec.rb +1 -1
  267. data/spec/extensions/boolean_readers_spec.rb +1 -1
  268. data/spec/extensions/boolean_subsets_spec.rb +1 -1
  269. data/spec/extensions/caching_spec.rb +1 -1
  270. data/spec/extensions/class_table_inheritance_spec.rb +35 -1086
  271. data/spec/extensions/column_conflicts_spec.rb +1 -1
  272. data/spec/extensions/column_select_spec.rb +4 -4
  273. data/spec/extensions/columns_introspection_spec.rb +1 -1
  274. data/spec/extensions/columns_updated_spec.rb +1 -1
  275. data/spec/extensions/composition_spec.rb +1 -7
  276. data/spec/extensions/connection_expiration_spec.rb +3 -3
  277. data/spec/extensions/connection_validator_spec.rb +3 -3
  278. data/spec/extensions/constraint_validations_plugin_spec.rb +1 -1
  279. data/spec/extensions/constraint_validations_spec.rb +1 -1
  280. data/spec/extensions/core_refinements_spec.rb +1 -3
  281. data/spec/extensions/csv_serializer_spec.rb +4 -9
  282. data/spec/extensions/current_datetime_timestamp_spec.rb +1 -1
  283. data/spec/extensions/dataset_associations_spec.rb +2 -1
  284. data/spec/extensions/dataset_source_alias_spec.rb +1 -1
  285. data/spec/extensions/date_arithmetic_spec.rb +3 -3
  286. data/spec/extensions/def_dataset_method_spec.rb +1 -1
  287. data/spec/extensions/defaults_setter_spec.rb +2 -2
  288. data/spec/extensions/delay_add_association_spec.rb +8 -9
  289. data/spec/extensions/dirty_spec.rb +1 -1
  290. data/spec/extensions/duplicate_columns_handler_spec.rb +1 -1
  291. data/spec/extensions/eager_each_spec.rb +2 -2
  292. data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
  293. data/spec/extensions/error_splitter_spec.rb +1 -1
  294. data/spec/extensions/error_sql_spec.rb +1 -1
  295. data/spec/extensions/eval_inspect_spec.rb +1 -1
  296. data/spec/extensions/finder_spec.rb +1 -1
  297. data/spec/extensions/force_encoding_spec.rb +2 -5
  298. data/spec/extensions/freeze_datasets_spec.rb +1 -1
  299. data/spec/extensions/graph_each_spec.rb +5 -5
  300. data/spec/extensions/hook_class_methods_spec.rb +1 -194
  301. data/spec/extensions/identifier_mangling_spec.rb +17 -170
  302. data/spec/extensions/implicit_subquery_spec.rb +1 -5
  303. data/spec/extensions/inflector_spec.rb +1 -1
  304. data/spec/extensions/input_transformer_spec.rb +7 -2
  305. data/spec/extensions/insert_returning_select_spec.rb +1 -1
  306. data/spec/extensions/instance_filters_spec.rb +1 -1
  307. data/spec/extensions/instance_hooks_spec.rb +1 -95
  308. data/spec/extensions/inverted_subsets_spec.rb +1 -1
  309. data/spec/extensions/json_serializer_spec.rb +1 -1
  310. data/spec/extensions/lazy_attributes_spec.rb +1 -7
  311. data/spec/extensions/list_spec.rb +1 -1
  312. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  313. data/spec/extensions/many_through_many_spec.rb +1 -1
  314. data/spec/extensions/migration_spec.rb +2 -2
  315. data/spec/extensions/modification_detection_spec.rb +1 -1
  316. data/spec/extensions/mssql_optimistic_locking_spec.rb +1 -1
  317. data/spec/extensions/named_timezones_spec.rb +3 -3
  318. data/spec/extensions/nested_attributes_spec.rb +1 -29
  319. data/spec/extensions/null_dataset_spec.rb +1 -11
  320. data/spec/extensions/optimistic_locking_spec.rb +1 -1
  321. data/spec/extensions/pagination_spec.rb +1 -1
  322. data/spec/extensions/pg_array_associations_spec.rb +4 -1
  323. data/spec/extensions/pg_array_ops_spec.rb +1 -1
  324. data/spec/extensions/pg_array_spec.rb +3 -48
  325. data/spec/extensions/pg_enum_spec.rb +1 -1
  326. data/spec/extensions/pg_hstore_ops_spec.rb +1 -1
  327. data/spec/extensions/pg_hstore_spec.rb +23 -32
  328. data/spec/extensions/pg_inet_ops_spec.rb +1 -1
  329. data/spec/extensions/pg_inet_spec.rb +1 -14
  330. data/spec/extensions/pg_interval_spec.rb +3 -13
  331. data/spec/extensions/pg_json_ops_spec.rb +1 -1
  332. data/spec/extensions/pg_json_spec.rb +1 -13
  333. data/spec/extensions/pg_loose_count_spec.rb +1 -1
  334. data/spec/extensions/pg_range_ops_spec.rb +1 -1
  335. data/spec/extensions/pg_range_spec.rb +3 -88
  336. data/spec/extensions/pg_row_ops_spec.rb +1 -1
  337. data/spec/extensions/pg_row_plugin_spec.rb +1 -1
  338. data/spec/extensions/pg_row_spec.rb +1 -44
  339. data/spec/extensions/pg_static_cache_updater_spec.rb +1 -1
  340. data/spec/extensions/prepared_statements_safe_spec.rb +1 -1
  341. data/spec/extensions/prepared_statements_spec.rb +13 -48
  342. data/spec/extensions/pretty_table_spec.rb +1 -1
  343. data/spec/extensions/query_spec.rb +1 -12
  344. data/spec/extensions/rcte_tree_spec.rb +1 -1
  345. data/spec/extensions/round_timestamps_spec.rb +1 -5
  346. data/spec/extensions/s_spec.rb +1 -1
  347. data/spec/extensions/schema_caching_spec.rb +1 -1
  348. data/spec/extensions/schema_dumper_spec.rb +1 -1
  349. data/spec/extensions/select_remove_spec.rb +1 -1
  350. data/spec/extensions/sequel_4_dataset_methods_spec.rb +1 -1
  351. data/spec/extensions/serialization_modification_detection_spec.rb +1 -1
  352. data/spec/extensions/serialization_spec.rb +2 -14
  353. data/spec/extensions/server_block_spec.rb +1 -1
  354. data/spec/extensions/server_logging_spec.rb +2 -2
  355. data/spec/extensions/sharding_spec.rb +1 -1
  356. data/spec/extensions/shared_caching_spec.rb +1 -28
  357. data/spec/extensions/single_table_inheritance_spec.rb +2 -5
  358. data/spec/extensions/singular_table_names_spec.rb +1 -1
  359. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  360. data/spec/extensions/spec_helper.rb +5 -27
  361. data/spec/extensions/split_array_nil_spec.rb +1 -1
  362. data/spec/extensions/split_values_spec.rb +1 -1
  363. data/spec/extensions/sql_comments_spec.rb +1 -1
  364. data/spec/extensions/sql_expr_spec.rb +1 -1
  365. data/spec/extensions/static_cache_spec.rb +1 -1
  366. data/spec/extensions/string_agg_spec.rb +2 -2
  367. data/spec/extensions/string_date_time_spec.rb +1 -1
  368. data/spec/extensions/string_stripper_spec.rb +1 -1
  369. data/spec/extensions/subclasses_spec.rb +1 -1
  370. data/spec/extensions/subset_conditions_spec.rb +1 -1
  371. data/spec/extensions/symbol_aref_refinement_spec.rb +1 -1
  372. data/spec/extensions/symbol_as_refinement_spec.rb +1 -1
  373. data/spec/extensions/table_select_spec.rb +4 -4
  374. data/spec/extensions/tactical_eager_loading_spec.rb +1 -6
  375. data/spec/extensions/thread_local_timezones_spec.rb +1 -1
  376. data/spec/extensions/timestamps_spec.rb +3 -3
  377. data/spec/extensions/to_dot_spec.rb +1 -1
  378. data/spec/extensions/touch_spec.rb +1 -1
  379. data/spec/extensions/tree_spec.rb +1 -1
  380. data/spec/extensions/typecast_on_load_spec.rb +1 -1
  381. data/spec/extensions/unlimited_update_spec.rb +1 -1
  382. data/spec/extensions/update_or_create_spec.rb +1 -1
  383. data/spec/extensions/update_primary_key_spec.rb +4 -3
  384. data/spec/extensions/update_refresh_spec.rb +1 -1
  385. data/spec/extensions/uuid_spec.rb +10 -12
  386. data/spec/extensions/validate_associated_spec.rb +1 -1
  387. data/spec/extensions/validation_class_methods_spec.rb +3 -3
  388. data/spec/extensions/validation_contexts_spec.rb +1 -1
  389. data/spec/extensions/validation_helpers_spec.rb +10 -44
  390. data/spec/extensions/whitelist_security_spec.rb +5 -5
  391. data/spec/extensions/xml_serializer_spec.rb +3 -3
  392. data/spec/guards_helper.rb +2 -1
  393. data/spec/integration/associations_test.rb +1 -23
  394. data/spec/integration/database_test.rb +7 -7
  395. data/spec/integration/dataset_test.rb +5 -47
  396. data/spec/integration/eager_loader_test.rb +1 -1
  397. data/spec/integration/migrator_test.rb +1 -1
  398. data/spec/integration/model_test.rb +4 -82
  399. data/spec/integration/plugin_test.rb +6 -22
  400. data/spec/integration/prepared_statement_test.rb +8 -88
  401. data/spec/integration/schema_test.rb +6 -6
  402. data/spec/integration/spec_helper.rb +13 -21
  403. data/spec/integration/timezone_test.rb +5 -5
  404. data/spec/integration/transaction_test.rb +3 -55
  405. data/spec/integration/type_test.rb +9 -9
  406. data/spec/model/association_reflection_spec.rb +24 -9
  407. data/spec/model/associations_spec.rb +124 -303
  408. data/spec/model/base_spec.rb +18 -137
  409. data/spec/model/class_dataset_methods_spec.rb +2 -20
  410. data/spec/model/dataset_methods_spec.rb +1 -20
  411. data/spec/model/eager_loading_spec.rb +17 -11
  412. data/spec/model/hooks_spec.rb +5 -300
  413. data/spec/model/inflector_spec.rb +1 -1
  414. data/spec/model/model_spec.rb +15 -320
  415. data/spec/model/plugins_spec.rb +2 -16
  416. data/spec/model/record_spec.rb +29 -121
  417. data/spec/model/spec_helper.rb +5 -15
  418. data/spec/model/validations_spec.rb +1 -1
  419. data/spec/sequel_warning.rb +1 -12
  420. metadata +8 -64
  421. data/doc/active_record.rdoc +0 -927
  422. data/lib/sequel/adapters/cubrid.rb +0 -160
  423. data/lib/sequel/adapters/do.rb +0 -166
  424. data/lib/sequel/adapters/do/mysql.rb +0 -69
  425. data/lib/sequel/adapters/do/postgres.rb +0 -46
  426. data/lib/sequel/adapters/do/sqlite3.rb +0 -41
  427. data/lib/sequel/adapters/jdbc/as400.rb +0 -92
  428. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -65
  429. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -37
  430. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -34
  431. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -34
  432. data/lib/sequel/adapters/odbc/progress.rb +0 -12
  433. data/lib/sequel/adapters/shared/cubrid.rb +0 -245
  434. data/lib/sequel/adapters/shared/firebird.rb +0 -261
  435. data/lib/sequel/adapters/shared/informix.rb +0 -63
  436. data/lib/sequel/adapters/shared/progress.rb +0 -40
  437. data/lib/sequel/adapters/swift.rb +0 -169
  438. data/lib/sequel/adapters/swift/mysql.rb +0 -50
  439. data/lib/sequel/adapters/swift/postgres.rb +0 -49
  440. data/lib/sequel/adapters/swift/sqlite.rb +0 -48
  441. data/lib/sequel/adapters/utils/pg_types.rb +0 -4
  442. data/lib/sequel/dataset/mutation.rb +0 -98
  443. data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +0 -117
  444. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -8
  445. data/lib/sequel/extensions/filter_having.rb +0 -65
  446. data/lib/sequel/extensions/hash_aliases.rb +0 -51
  447. data/lib/sequel/extensions/meta_def.rb +0 -37
  448. data/lib/sequel/extensions/query_literals.rb +0 -86
  449. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -26
  450. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -133
  451. data/lib/sequel/extensions/set_overrides.rb +0 -82
  452. data/lib/sequel/no_core_ext.rb +0 -4
  453. data/lib/sequel/plugins/association_autoreloading.rb +0 -11
  454. data/lib/sequel/plugins/identifier_columns.rb +0 -49
  455. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -11
  456. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -90
  457. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -137
  458. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -71
  459. data/lib/sequel/plugins/schema.rb +0 -84
  460. data/lib/sequel/plugins/scissors.rb +0 -37
  461. data/spec/core/dataset_mutation_spec.rb +0 -253
  462. data/spec/extensions/_deprecated_identifier_mangling_spec.rb +0 -314
  463. data/spec/extensions/before_after_save_spec.rb +0 -40
  464. data/spec/extensions/filter_having_spec.rb +0 -42
  465. data/spec/extensions/from_block_spec.rb +0 -21
  466. data/spec/extensions/hash_aliases_spec.rb +0 -26
  467. data/spec/extensions/identifier_columns_spec.rb +0 -19
  468. data/spec/extensions/meta_def_spec.rb +0 -35
  469. data/spec/extensions/no_auto_literal_strings_spec.rb +0 -69
  470. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -70
  471. data/spec/extensions/prepared_statements_associations_spec.rb +0 -212
  472. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -40
  473. data/spec/extensions/query_literals_spec.rb +0 -185
  474. data/spec/extensions/schema_spec.rb +0 -123
  475. data/spec/extensions/scissors_spec.rb +0 -27
  476. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -118
  477. data/spec/extensions/set_overrides_spec.rb +0 -75
@@ -19,10 +19,10 @@ rarely used PostgreSQL features that Sequel supports which are not mentioned her
19
19
 
20
20
  Some of this this support depends on the specific adapter or underlying driver in use.
21
21
  <tt>postgres only</tt> will denote support specific to the postgres adapter (i.e.
22
- not available when connecting to PostgreSQL via the jdbc, do, or swift adapters).
22
+ not available when connecting to PostgreSQL via the jdbc adapter).
23
23
  <tt>postgres/pg only</tt> will denote support specific to the postgres adapter when
24
- pg is used as the underlying driver (i.e. not available when using the postgres-pr or
25
- postgres drivers).
24
+ pg is used as the underlying driver (i.e. not available when using the postgres-pr
25
+ driver).
26
26
 
27
27
  == PostgreSQL-specific Database Type Support
28
28
 
@@ -44,7 +44,7 @@ pg_range :: ranges (for any scalar type), as a ruby Range-like object
44
44
  pg_row :: row-valued/composite types, as a ruby Hash-like or Sequel::Model object
45
45
 
46
46
  In general, these extensions just add support for Database objects to return retrieved
47
- column values as the appropriate type (<tt>postgres and jdbc/postgres only</tt>), and support for literalizing
47
+ column values as the appropriate type and support for literalizing
48
48
  the objects correctly for use in an SQL string, or using them as bound variable values (<tt>postgres/pg and jdbc/postgres only</tt>).
49
49
 
50
50
  There are also type-specific extensions that make it easy to use database functions
@@ -56,6 +56,13 @@ pg_json_ops :: json-related functions and operators
56
56
  pg_range_ops :: range-related functions and operators
57
57
  pg_row_ops :: row-valued/composite type syntax support
58
58
 
59
+ These extensions aren't Database specific, they are global extensions, so you should
60
+ load them via <tt>Sequel.extension</tt>, after loading support for the specific types
61
+ into the Database instance:
62
+
63
+ DB.extension :pg_array
64
+ Sequel.extension :pg_array_ops
65
+
59
66
  == PostgreSQL-specific DDL Support
60
67
 
61
68
  === Exclusion Constraints
@@ -64,7 +71,7 @@ In +create_table+ blocks, you can use the +exclude+ method to set up exclusion c
64
71
 
65
72
  DB.create_table(:table) do
66
73
  daterange :during
67
- exclude([[:during, '&&']], :name=>:table_during_excl)
74
+ exclude([[:during, '&&']], name: :table_during_excl)
68
75
  end
69
76
  # CREATE TABLE "table" ("during" daterange,
70
77
  # CONSTRAINT "table_during_excl" EXCLUDE USING gist ("during" WITH &&))
@@ -72,20 +79,20 @@ In +create_table+ blocks, you can use the +exclude+ method to set up exclusion c
72
79
  You can also add exclusion constraints in +alter_table+ blocks using add_exclusion_constraint:
73
80
 
74
81
  DB.alter_table(:table) do
75
- add_exclusion_constraint([[:during, '&&']], :name=>:table_during_excl)
82
+ add_exclusion_constraint([[:during, '&&']], name: :table_during_excl)
76
83
  end
77
84
  # ALTER TABLE "table" ADD CONSTRAINT "table_during_excl" EXCLUDE USING gist ("during" WITH &&)
78
85
 
79
86
  === Adding Foreign Key and Check Constraints Without Initial Validation
80
87
 
81
- You can add a <tt>:not_valid=>true</tt> option when adding constraints to existing tables so
88
+ You can add a <tt>not_valid: true</tt> option when adding constraints to existing tables so
82
89
  that it doesn't check if all current rows are valid:
83
90
 
84
91
  DB.alter_table(:table) do
85
92
  # Assumes t_id column already exists
86
- add_foreign_key([:t_id], :table, :not_valid=>true, :name=>:table_fk)
93
+ add_foreign_key([:t_id], :table, not_valid: true, name: :table_fk)
87
94
 
88
- constraint({:name=>:col_123, :not_valid=>true}, :col=>[1,2,3])
95
+ constraint({name: :col_123, not_valid: true}, col: [1,2,3])
89
96
  end
90
97
  # ALTER TABLE "table" ADD CONSTRAINT "table_fk" FOREIGN KEY ("t_id") REFERENCES "table" NOT VALID
91
98
  # ALTER TABLE "table" ADD CONSTRAINT "col_123" CHECK (col IN (1, 2, 3)) NOT VALID
@@ -102,14 +109,14 @@ all existing rows have been fixed, you can validate the constraint:
102
109
 
103
110
  === Creating Indexes Concurrently
104
111
 
105
- You can create indexes concurrently using the <tt>:concurrently=>true</tt> option:
112
+ You can create indexes concurrently using the <tt>concurrently: true</tt> option:
106
113
 
107
- DB.add_index(:table, :t_id, :concurrently=>true)
114
+ DB.add_index(:table, :t_id, concurrently: true)
108
115
  # CREATE INDEX CONCURRENTLY "table_t_id_index" ON "table" ("t_id")
109
116
 
110
117
  Similarly, you can drop indexes concurrently as well:
111
118
 
112
- DB.drop_index(:table, :t_id, :concurrently=>true)
119
+ DB.drop_index(:table, :t_id, concurrently: true)
113
120
  # DROP INDEX CONCURRENTLY "table_t_id_index"
114
121
 
115
122
  === Specific Conversions When Altering Column Types
@@ -119,7 +126,7 @@ conversion via a USING clause, and Sequel supports this using the <tt>:using</tt
119
126
 
120
127
  DB.alter_table(:table) do
121
128
  # Assume unix_time column is stored as an integer, and you want to change it to timestamp
122
- set_column_type :unix_time, Time, :using=>(Sequel.cast('epoch', Time) + Sequel.cast('1 second', :interval) * :unix_time)
129
+ set_column_type :unix_time, Time, using: (Sequel.cast('epoch', Time) + Sequel.cast('1 second', :interval) * :unix_time)
123
130
  end
124
131
  # ALTER TABLE "table" ALTER COLUMN "unix_time" TYPE timestamp
125
132
  # USING (CAST('epoch' AS timestamp) + (CAST('1 second' AS interval) * "unix_time"))
@@ -127,9 +134,9 @@ conversion via a USING clause, and Sequel supports this using the <tt>:using</tt
127
134
  === Creating Unlogged Tables
128
135
 
129
136
  PostgreSQL allows users to create unlogged tables, which are faster but not crash safe. Sequel
130
- allows you do create an unlogged table by specifying the <tt>:unlogged=>true</tt> option to +create_table+:
137
+ allows you do create an unlogged table by specifying the <tt>unlogged: true</tt> option to +create_table+:
131
138
 
132
- DB.create_table(:table, :unlogged=>true){Integer :i}
139
+ DB.create_table(:table, unlogged: true){Integer :i}
133
140
  # CREATE UNLOGGED TABLE "table" ("i" integer)
134
141
 
135
142
  === Creating/Dropping Schemas, Languages, Functions, and Triggers
@@ -146,7 +153,7 @@ Sequel has built in support for creating and dropping PostgreSQL schemas, proced
146
153
  DB.drop_language(:plperl)
147
154
  # DROP LANGUAGE plperl
148
155
 
149
- DB.create_function(:set_updated_at, <<-SQL, :language=>:plpgsql, :returns=>:trigger)
156
+ DB.create_function(:set_updated_at, <<-SQL, language: :plpgsql, returns: :trigger)
150
157
  BEGIN
151
158
  NEW.updated_at := CURRENT_TIMESTAMP;
152
159
  RETURN NEW;
@@ -160,11 +167,13 @@ Sequel has built in support for creating and dropping PostgreSQL schemas, proced
160
167
  DB.drop_function(:set_updated_at)
161
168
  # DROP FUNCTION set_updated_at()
162
169
 
163
- DB.create_trigger(:table, :trg_updated_at, :set_updated_at, :events=>:update, :each_row=>true, :when => {Sequel[:new][:updated_at] => Sequel[:old][:updated_at]})
170
+ DB.create_trigger(:table, :trg_updated_at, :set_updated_at, events: :update, each_row: true, when: {Sequel[:new][:updated_at] => Sequel[:old][:updated_at]})
164
171
  # CREATE TRIGGER trg_updated_at BEFORE UPDATE ON "table" FOR EACH ROW WHEN ("new"."updated_at" = "old"."updated_at") EXECUTE PROCEDURE set_updated_at()
165
172
  DB.drop_trigger(:table, :trg_updated_at)
166
173
  # DROP TRIGGER trg_updated_at ON "table"
167
174
 
175
+ However, you may want to consider just use <tt>Database#run</tt> with the necessary SQL code, at least for functions and triggers.
176
+
168
177
  == PostgreSQL-specific DML Support
169
178
 
170
179
  === Returning Rows From Insert, Update, and Delete Statements
@@ -178,12 +187,12 @@ Sequel supports the ability to return rows from insert, update, and delete state
178
187
  DB[:table].returning(:id).delete
179
188
  # DELETE FROM "table" RETURNING "id"
180
189
 
181
- DB[:table].returning(:id, Sequel.*(:id, :id).as(:idsq)).update(:id=>2)
190
+ DB[:table].returning(:id, Sequel.*(:id, :id).as(:idsq)).update(id: 2)
182
191
  # UPDATE "table" SET "id" = 2 RETURNING "id", ("id" * "id") AS "idsq"
183
192
 
184
193
  When returning is used, instead of returning the number of rows affected (for updated/delete)
185
194
  or the serial primary key value (for insert), it will return an array of hashes with the
186
- returned results.
195
+ returning results.
187
196
 
188
197
  === VALUES Support
189
198
 
@@ -203,27 +212,27 @@ Sequel offers support for the +VALUES+ statement using <tt>Database#values</tt>:
203
212
  Starting with PostgreSQL 9.5, you can do an upsert or ignore unique or exclusion constraint
204
213
  violations when inserting using <tt>Dataset#insert_conflict</tt>:
205
214
 
206
- DB[:table].insert_conflict.insert(:a=>1, :b=>2)
215
+ DB[:table].insert_conflict.insert(a: 1, b: 2)
207
216
  # INSERT INTO TABLE (a, b) VALUES (1, 2)
208
217
  # ON CONFLICT DO NOTHING
209
218
 
210
219
  For compatibility with Sequel's MySQL support, you can also use +insert_ignore+:
211
220
 
212
- DB[:table].insert_ignore.insert(:a=>1, :b=>2)
221
+ DB[:table].insert_ignore.insert(a: 1, b: 2)
213
222
  # INSERT INTO TABLE (a, b) VALUES (1, 2)
214
223
  # ON CONFLICT DO NOTHING
215
224
 
216
225
  You can pass a specific constraint name using +:constraint+, to only ignore a specific
217
226
  constraint violation:
218
227
 
219
- DB[:table].insert_conflict(:constraint=>:table_a_uidx).insert(:a=>1, :b=>2)
228
+ DB[:table].insert_conflict(constraint: :table_a_uidx).insert(a: 1, b: 2)
220
229
  # INSERT INTO TABLE (a, b) VALUES (1, 2)
221
230
  # ON CONFLICT ON CONSTRAINT table_a_uidx DO NOTHING
222
231
 
223
232
  If the unique or exclusion constraint covers the whole table (e.g. it isn't a partial unique
224
233
  index), then you can just specify the column using the +:target+ option:
225
234
 
226
- DB[:table].insert_conflict(:target=>:a).insert(:a=>1, :b=>2)
235
+ DB[:table].insert_conflict(target: :a).insert(a: 1, b: 2)
227
236
  # INSERT INTO TABLE (a, b) VALUES (1, 2)
228
237
  # ON CONFLICT (a) DO NOTHING
229
238
 
@@ -231,7 +240,7 @@ If you want to update the existing row instead of ignoring the constraint violat
231
240
  can pass an +:update+ option with a hash of values to update. You must pass either the
232
241
  +:target+ or +:constraint+ options when passing the +:update+ option:
233
242
 
234
- DB[:table].insert_conflict(:target=>:a, :update=>{:b=>Sequel[:excluded][:b]}).insert(:a=>1, :b=>2)
243
+ DB[:table].insert_conflict(target: :a, update: {b: Sequel[:excluded][:b]}).insert(a: 1, b: 2)
235
244
  # INSERT INTO TABLE (a, b) VALUES (1, 2)
236
245
  # ON CONFLICT (a) DO UPDATE SET b = excluded.b
237
246
 
@@ -239,8 +248,9 @@ Additionally, if you only want to do the update in certain cases, you can specif
239
248
  +:update_where+ option, which will be used as a filter. If the row doesn't match the
240
249
  conditions, the constraint violation will be ignored, but the row will not be updated:
241
250
 
242
- DB[:table].insert_conflict(:constraint=>:table_a_uidx,
243
- :update=>{:b=>Sequel[:excluded][:b]}, :update_where=>{Sequel[:table][:status_id]=>1}).insert(:a=>1, :b=>2)
251
+ DB[:table].insert_conflict(constraint::table_a_uidx,
252
+ update: {b: Sequel[:excluded][:b]},
253
+ update_where: {Sequel[:table][:status_id]=>1}).insert(a: 1, b: 2)
244
254
  # INSERT INTO TABLE (a, b) VALUES (1, 2)
245
255
  # ON CONFLICT ON CONSTRAINT table_a_uidx
246
256
  # DO UPDATE SET b = excluded.b WHERE (table.status_id = 1)
@@ -271,19 +281,19 @@ without keeping all rows in memory:
271
281
  This support is used by default when using <tt>Dataset#paged_each</tt>.
272
282
 
273
283
  Using cursors, it is possible to update individual rows of a large dataset
274
- easily using the <tt>:rows_per_fetch=>1</tt> option in conjunction with
284
+ easily using the <tt>rows_per_fetch: 1</tt> option in conjunction with
275
285
  <tt>Dataset#where_current_of</tt>. This is useful if the logic needed to
276
286
  update the rows exists in the application and not in the database:
277
287
 
278
- ds.use_cursor(:rows_per_fetch=>1).each do |row|
279
- ds.where_current_of.update(:col=>new_col_value(row))
288
+ ds.use_cursor(rows_per_fetch: 1).each do |row|
289
+ ds.where_current_of.update(col: new_col_value(row))
280
290
  end
281
291
 
282
292
  === Truncate Modifiers
283
293
 
284
294
  Sequel supports PostgreSQL-specific truncate options:
285
295
 
286
- DB[:table].truncate(:cascade => true, :only=>true, :restart=>true)
296
+ DB[:table].truncate(cascade: true, only: true, restart: true)
287
297
  # TRUNCATE TABLE ONLY "table" RESTART IDENTITY CASCADE
288
298
 
289
299
  === COPY Support <tt>postgres/pg and jdbc/postgres only</tt>
@@ -292,14 +302,14 @@ PostgreSQL's COPY feature is pretty much the fastest way to get data in or out o
292
302
  Sequel supports getting data out of the database via <tt>Database#copy_table</tt>, either for
293
303
  a specific table or for an arbitrary dataset:
294
304
 
295
- DB.copy_table(:table, :format=>:csv)
305
+ DB.copy_table(:table, format: :csv)
296
306
  # COPY "table" TO STDOUT (FORMAT csv)
297
- DB.copy_table(DB[:table], :format=>:csv)
307
+ DB.copy_table(DB[:table], format: :csv)
298
308
  # COPY (SELECT * FROM "table") TO STDOUT (FORMAT csv)
299
309
 
300
310
  It supports putting data into the database via <tt>Database#copy_into</tt>:
301
311
 
302
- DB.copy_into(:table, :format=>:csv, :columns=>[:column1, :column2], :data=>"1,2\n2,3\n")
312
+ DB.copy_into(:table, format: :csv, columns: [:column1, :column2], data: "1,2\n2,3\n")
303
313
  # COPY "table"("column1", "column2") FROM STDIN (FORMAT csv)
304
314
 
305
315
  === Anonymous Function Execution
@@ -336,7 +346,7 @@ this blocks until the listening thread is notified:
336
346
  Note that +listen+ by default only listens for a single notification. If you want to loop and process
337
347
  notifications:
338
348
 
339
- DB.listen(:channel, :loop=>true){|channel| p channel}
349
+ DB.listen(:channel, loop: true){|channel| p channel}
340
350
 
341
351
  The +pg_static_cache_updater+ extension uses this support to automatically update
342
352
  the caches for models using the +static_cache+ plugin. Look at the documentation of that
@@ -348,7 +358,7 @@ Sequel makes it easy to lock tables, though it is generally better to let the da
348
358
  handle locking:
349
359
 
350
360
  DB[:table].lock('EXCLUSIVE') do
351
- DB[:table].insert(:id=>DB[:table].max(:id)+1)
361
+ DB[:table].insert(id: DB[:table].max(:id)+1)
352
362
  end
353
363
  # BEGIN;
354
364
  # LOCK TABLE "table" IN EXCLUSIVE MODE;
@@ -360,14 +370,14 @@ handle locking:
360
370
 
361
371
  When the postgres adapter is used with the pg driver, Sequel automatically checks for sequel_pg, and
362
372
  loads it if it is available. sequel_pg is a C extension that optimizes the fetching of rows, generally
363
- resulting in a 2-6x speedup. It is highly recommended to install sequel_pg if you are using the
373
+ resulting in a ~2x speedup. It is highly recommended to install sequel_pg if you are using the
364
374
  postgres adapter with pg.
365
375
 
366
- sequel_pg has additional optimizations when using the Dataset +map+, +to_hash+,
376
+ sequel_pg has additional optimizations when using the Dataset +map+, +as_hash+,
367
377
  +to_hash_groups+, +select_hash+, +select_hash_groups+, +select_map+, and +select_order_map+ methods,
368
378
  which avoids creating intermediate hashes and can add further speedups.
369
379
 
370
- In addition to optimization, sequel_pg also adds streaming support if used on PostgreSQL 9.2. Streaming
380
+ In addition to optimization, sequel_pg also adds streaming support if used on PostgreSQL 9.2+. Streaming
371
381
  support is similar to using a cursor, but it is faster and more transparent.
372
382
 
373
383
  You can enable the streaming support:
@@ -14,7 +14,7 @@ the following adapters:
14
14
  * sqlite
15
15
  * tinytds
16
16
 
17
- Support on other adapters is emulated via string interpolation.
17
+ Support on other adapters is emulated.
18
18
 
19
19
  You can use the prepared_statements model plugin to automatically use prepared
20
20
  statements for some common model actions such as saving or deleting a model
@@ -29,7 +29,7 @@ significantly for placeholders (e.g. :name, $1, ?). Sequel abstracts all of
29
29
  that and allows you to specify placeholders by using the :$name format for
30
30
  placeholders, e.g.:
31
31
 
32
- ds = DB[:items].where(:name=>:$n)
32
+ ds = DB[:items].where(name: :$n)
33
33
 
34
34
  You can use these placeholders in most places where you can use the value
35
35
  directly. For example, if you want to use placeholders while also using
@@ -41,45 +41,49 @@ raw SQL, you can do:
41
41
 
42
42
  Using bound variables for this query is simple:
43
43
 
44
- ds.call(:select, :n=>'Jim')
44
+ ds.call(:select, n: 'Jim')
45
45
 
46
46
  This will do the equivalent of selecting records that have the name 'Jim'. It
47
47
  returns all records, and can take a block that is passed to <tt>Dataset#all</tt>.
48
48
 
49
49
  Deleting or returning the first record works similarly:
50
50
 
51
- ds.call(:first, :n=>'Jim') # First record with name 'Jim'
52
- ds.call(:delete, :n=>'Jim') # Delete records with name 'Jim'
51
+ ds.call(:first, n: 'Jim') # First record with name 'Jim'
52
+ ds.call(:delete, n: 'Jim') # Delete records with name 'Jim'
53
53
 
54
54
  For inserting/updating records, you should also specify a value hash, which
55
55
  may itself contain placeholders:
56
56
 
57
57
  # Insert record with 'Jim', note that the previous filter is ignored
58
- ds.call(:insert, {:n=>'Jim'}, :name=>:$n)
58
+ ds.call(:insert, {n: 'Jim'}, name: :$n)
59
59
  # Change name to 'Bob' for all records with name of 'Jim'
60
- ds.call(:update, {:n=>'Jim', :new_n=>'Bob'}, :name=>:$new_n)
60
+ ds.call(:update, {n: 'Jim', new_n: 'Bob'}, name: :$new_n)
61
61
 
62
62
  == Prepared Statements
63
63
 
64
64
  Prepared statement support is similar to bound variable support, but you
65
65
  use <tt>Dataset#prepare</tt> with a name, and <tt>Dataset#call</tt> or <tt>Database#call</tt> later with the values:
66
66
 
67
- ds = DB[:items].where(:name=>:$n)
67
+ ds = DB[:items].where(name: :$n)
68
68
  ps = ds.prepare(:select, :select_by_name)
69
- ps.call(:n=>'Jim')
70
- DB.call(:select_by_name, :n=>'Jim') # same as above
69
+
70
+ ps.call(n: 'Jim')
71
+ DB.call(:select_by_name, n: 'Jim') # same
71
72
 
72
73
  The <tt>Dataset#prepare</tt> method returns a prepared statement, and also stores a
73
74
  copy of the prepared statement in the database for later use. For insert
74
75
  and update queries, the hash to insert/update is passed to +prepare+:
75
76
 
76
- ps1 = DB[:items].prepare(:insert, :insert_with_name, :name=>:$n)
77
- ps1.call(:n=>'Jim')
78
- DB.call(:insert_with_name, :n=>'Jim') # same as above
79
- ds = DB[:items].where(:name=>:$n)
80
- ps2 = ds.prepare(:update, :update_name, :name=>:$new_n)
81
- ps2.call(:n=>'Jim', :new_n=>'Bob')
82
- DB.call(:update_name, :n=>'Jim', :new_n=>'Bob') # same as above
77
+ ps1 = DB[:items].prepare(:insert, :insert_with_name, name: :$n)
78
+
79
+ ps1.call(n: 'Jim')
80
+ DB.call(:insert_with_name, n: 'Jim') # same
81
+
82
+ ds = DB[:items].where(name: :$n)
83
+ ps2 = ds.prepare(:update, :update_name, name: :$new_n)
84
+
85
+ ps2.call(n: 'Jim', new_n: 'Bob')
86
+ DB.call(:update_name, n: 'Jim', new_n: 'Bob') # same
83
87
 
84
88
  == Implementation Issues
85
89
 
@@ -92,7 +96,7 @@ to create prepared statements dynamically at runtime.
92
96
 
93
97
  === PostgreSQL
94
98
 
95
- If you are using the ruby-postgres or postgres-pr driver, PostgreSQL uses the
99
+ If you are using the postgres-pr driver, PostgreSQL uses the
96
100
  default emulated support. If you are using ruby-pg, there is native support
97
101
  for both prepared statements and bound variables. Prepared statements are
98
102
  always server side.
@@ -103,9 +107,10 @@ SQLite supports both prepared statements and bound variables.
103
107
 
104
108
  === MySQL/Mysql2
105
109
 
106
- The MySQL/Mysql2 ruby drivers do not support bound variables, so the bound
107
- variable methods fall back to string interpolation. It uses server side
108
- prepared statements.
110
+ The MySQL and Mysql2 <0.4 ruby drivers do not support bound variables, so the bound
111
+ variable methods are emulated. It uses server side prepared statements.
112
+
113
+ Mysql2 0.4+ supports both prepared statements and bound variables.
109
114
 
110
115
  === JDBC
111
116
 
@@ -136,4 +141,4 @@ not currently supported.
136
141
 
137
142
  === All Others
138
143
 
139
- Support is emulated using interpolation.
144
+ Support is emulated.
@@ -4,15 +4,15 @@ This guide is based on http://guides.rubyonrails.org/active_record_querying.html
4
4
 
5
5
  == Purpose of this Guide
6
6
 
7
- Sequel is a simple to use, very flexible, and powerful database library
7
+ Sequel is a flexible and powerful database library
8
8
  that supports a wide variety of different querying methods. This guide
9
- aims to be a gentle introduction to Sequel's querying support.
9
+ aims to be a introduction to Sequel's querying support.
10
10
 
11
- While you can easily use raw SQL with Sequel, a large part of the
11
+ While you can use raw SQL with Sequel, a large part of the
12
12
  advantage you get from using Sequel is Sequel's ability to abstract
13
- SQL from you and give you a much nicer interface. Sequel also ships with
13
+ SQL from you and give you a pure-ruby interface. Sequel also ships with
14
14
  a {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
15
- which better integrates Sequel's DSL into the ruby language.
15
+ which adds methods to core ruby types to work with Sequel.
16
16
 
17
17
  == Retrieving Objects
18
18
 
@@ -39,7 +39,7 @@ by its primary key value:
39
39
 
40
40
  # Find artist with primary key (id) 1
41
41
  artist = Artist[1]
42
- # SELECT * FROM artists WHERE id = 1
42
+ # SELECT * FROM artists WHERE (id = 1)
43
43
  # => #<Artist @values={:name=>"YJM", :id=>1}>
44
44
 
45
45
  If there is no record with the given primary key, nil will be returned. If you want
@@ -58,7 +58,7 @@ If you just want the first record in the dataset,
58
58
 
59
59
  Any options you pass to +first+ will be used as a filter:
60
60
 
61
- artist = Artist.first(:name => 'YJM')
61
+ artist = Artist.first(name: 'YJM')
62
62
  # SELECT * FROM artists WHERE (name = 'YJM') LIMIT 1
63
63
  # => #<Artist @values={:name=>"YJM", :id=>1}>
64
64
 
@@ -72,7 +72,7 @@ raise an exception instead, use <tt>first!</tt>.
72
72
  <tt>Sequel::Dataset#[]</tt> is basically an alias for +first+, except it
73
73
  requires an argument:
74
74
 
75
- DB[:artists][:name => 'YJM']
75
+ DB[:artists][{name: 'YJM'}]
76
76
  # SELECT * FROM artists WHERE (name = 'YJM') LIMIT 1
77
77
  # => {:name=>"YJM", :id=>1}
78
78
 
@@ -109,6 +109,15 @@ you want:
109
109
  # SELECT name FROM artists LIMIT 1
110
110
  # => "YJM"
111
111
 
112
+ ==== Retrieving a Multiple Column Values
113
+
114
+ If you want the value for multiple columns, you can pass an array to
115
+ <tt>Sequel::Dataset#get</tt>:
116
+
117
+ artist_id, artist_name, = Artist.get([:id, :name])
118
+ # SELECT name FROM artists LIMIT 1
119
+ # => [1, "YJM"]
120
+
112
121
  === Retrieving Multiple Objects
113
122
 
114
123
  ==== As an Array of Hashes or Model Objects
@@ -181,21 +190,21 @@ an array of arrays of values will be returned:
181
190
  ==== As a Hash
182
191
 
183
192
  Sequel makes it easy to take an SQL query and return it as a ruby hash,
184
- using the +to_hash+ method:
193
+ using the +as_hash+ method:
185
194
 
186
- artist_names = Artist.to_hash(:id, :name)
195
+ artist_names = Artist.as_hash(:id, :name)
187
196
  # SELECT * FROM artists
188
197
  # => {1=>"YJM", 2=>"AS"}
189
198
 
190
- As you can see, the +to_hash+ method uses the first symbol as the key
199
+ As you can see, the +as_hash+ method uses the first symbol as the key
191
200
  and the second symbol as the value. So if you swap the two arguments the hash
192
201
  will have its keys and values transposed:
193
202
 
194
- artist_names = Artist.to_hash(:name, :id)
203
+ artist_names = Artist.as_hash(:name, :id)
195
204
  # SELECT * FROM artists
196
205
  # => {"YJM"=>1, "AS"=>2}
197
206
 
198
- Now what if you have multiple values for the same key? By default, +to_hash+
207
+ Now what if you have multiple values for the same key? By default, +as_hash+
199
208
  will just have the last matching value. If you care about all matching values,
200
209
  use +to_hash_groups+, which makes the values of the array an array of matching
201
210
  values, in the order they were received:
@@ -204,10 +213,10 @@ values, in the order they were received:
204
213
  # SELECT * FROM artists
205
214
  # => {"YJM"=>[1, 10, ...], "AS"=>[2, 20, ...]}
206
215
 
207
- If you only provide one argument to +to_hash+, it uses the entire hash
216
+ If you only provide one argument to +as_hash+, it uses the entire hash
208
217
  or model object as the value:
209
218
 
210
- artist_names = DB[:artists].to_hash(:name)
219
+ artist_names = DB[:artists].as_hash(:name)
211
220
  # SELECT * FROM artists
212
221
  # => {"YJM"=>{:id=>1, :name=>"YJM"}, "AS"=>{:id=>2, :name=>"AS"}}
213
222
 
@@ -217,12 +226,12 @@ and +to_hash_groups+ works similarly:
217
226
  # SELECT * FROM artists
218
227
  # => {"YJM"=>[{:id=>1, :name=>"YJM"}, {:id=>10, :name=>"YJM"}], ...}
219
228
 
220
- Model datasets have a +to_hash+ method that can be called without any
229
+ Model datasets have a +as_hash+ method that can be called without any
221
230
  arguments, in which case it will use the primary key as the key and
222
231
  the model object as the value. This can be used to easily create an
223
232
  identity map:
224
233
 
225
- artist_names = Artist.to_hash
234
+ artist_names = Artist.as_hash
226
235
  # SELECT * FROM artists
227
236
  # => {1=>#<Artist @values={:id=>1, :name=>"YGM"}>,
228
237
  # 2=>#<Artist @values={:id=>2, :name=>"AS"}>}
@@ -230,7 +239,7 @@ identity map:
230
239
  There is no equivalent handling to +to_hash_groups+, since there would
231
240
  only be one matching record, as the primary key must be unique.
232
241
 
233
- Note that +to_hash+ never modifies the columns selected. However, just
242
+ Note that +as_hash+ never modifies the columns selected. However, just
234
243
  like Sequel has a +select_map+ method to modify the columns selected and
235
244
  return an array, Sequel also has a +select_hash+ method to modify the
236
245
  columns selected and return a hash:
@@ -260,8 +269,8 @@ be using:
260
269
  1. Methods that return row(s), discussed above
261
270
  2. Methods that return modified datasets, discussed below
262
271
 
263
- Sequel uses a method chaining, functional style API to
264
- modify datasets. Let's start with a simple example.
272
+ Sequel datasets are frozen and use a method chaining, functional style API
273
+ that returns modified datasets. Let's start with a simple example.
265
274
 
266
275
  This is a basic dataset that includes all records in the
267
276
  table +artists+:
@@ -273,7 +282,7 @@ Let's say we are only interested in the artists whose names
273
282
  start with "A":
274
283
 
275
284
  ds2 = ds1.where(Sequel.like(:name, 'A%'))
276
- # SELECT * FROM artists WHERE name LIKE 'A%' ESCAPE '\'
285
+ # SELECT * FROM artists WHERE (name LIKE 'A%' ESCAPE '\')
277
286
 
278
287
  Here we see that +where+ returns a dataset that adds a +WHERE+
279
288
  clause to the query. It's important to note that +where+ does
@@ -282,10 +291,9 @@ not modify the receiver:
282
291
  ds1
283
292
  # SELECT * FROM artists
284
293
  ds2
285
- # SELECT * FROM artists WHERE name LIKE 'A%' ESCAPE '\'
294
+ # SELECT * FROM artists WHERE (name LIKE 'A%' ESCAPE '\')
286
295
 
287
- In Sequel, most dataset methods that you will be using will
288
- not modify the dataset itself, so you can freely use the dataset in multiple
296
+ In Sequel, dataset methods do not modify the dataset itself, so you can freely use the dataset in multiple
289
297
  places without worrying that its usage in one place will affect its usage
290
298
  in another place. This is what is meant by a functional style API.
291
299
 
@@ -293,7 +301,7 @@ Let's say we only want to select the id and name columns, and that
293
301
  we want to order by name:
294
302
 
295
303
  ds3 = ds2.order(:name).select(:id, :name)
296
- # SELECT id, name FROM artists WHERE name LIKE 'A%' ESCAPE '\' ORDER BY name
304
+ # SELECT id, name FROM artists WHERE (name LIKE 'A%' ESCAPE '\') ORDER BY name
297
305
 
298
306
  Note how you don't need to assign the returned value of order to a variable,
299
307
  and then call select on that. Because order just returns a dataset, you can
@@ -315,54 +323,57 @@ below.
315
323
  === Hashes
316
324
 
317
325
  The most common format for providing filters is via a hash. In general, Sequel
318
- treats conditions specified with a hash as equality or inclusion. What type
326
+ treats conditions specified with a hash as equality, inclusion, or identity. What type
319
327
  of condition is used depends on the values in the hash.
320
328
 
321
329
  Unless Sequel has special support for the value's class, it uses a simple
322
330
  equality statement:
323
331
 
324
- Artist.where(:id=>1)
325
- # SELECT * FROM artists WHERE id = 1
332
+ Artist.where(id: 1)
333
+ # SELECT * FROM artists WHERE (id = 1)
326
334
 
327
- Artist.where(:name=>'YJM')
328
- # SELECT * FROM artists WHERE name = 'YJM'
335
+ Artist.where(name: 'YJM')
336
+ # SELECT * FROM artists WHERE (name = 'YJM')
329
337
 
330
- For arrays, Sequel uses the IN operator.
338
+ For arrays, Sequel uses the IN operator with a value list:
331
339
 
332
- Artist.where(:id=>[1, 2])
333
- # SELECT * FROM artists WHERE id IN (1, 2)
340
+ Artist.where(id: [1, 2])
341
+ # SELECT * FROM artists WHERE (id IN (1, 2))
334
342
 
335
343
  For datasets, Sequel uses the IN operator with a subselect:
336
344
 
337
- Artist.where(:id=>Album.select(:artist_id))
338
- # SELECT * FROM artists WHERE id IN (
339
- # SELECT artist_id FROM albums)
345
+ Artist.where(id: Album.select(:artist_id))
346
+ # SELECT * FROM artists WHERE (id IN (
347
+ # SELECT artist_id FROM albums))
340
348
 
341
349
  For boolean values such as nil, true, and false, Sequel uses the IS operator:
342
350
 
343
- Artist.where(:id=>nil)
344
- # SELECT * FROM artists WHERE id IS NULL
351
+ Artist.where(id: nil)
352
+ # SELECT * FROM artists WHERE (id IS NULL)
345
353
 
346
354
  For ranges, Sequel uses a pair of inequality statements:
347
355
 
348
- Artist.where(:id=>1..5)
349
- # SELECT * FROM artists WHERE id >= 1 AND id <= 5
356
+ Artist.where(id: 1..5)
357
+ # SELECT * FROM artists WHERE ((id >= 1) AND (id <= 5))
358
+
359
+ Artist.where(id: 1...5)
360
+ # SELECT * FROM artists WHERE ((id >= 1) AND (id < 5))
350
361
 
351
362
  Finally, for regexps, Sequel uses an SQL regular expression. Note that this
352
363
  is probably only supported on PostgreSQL and MySQL.
353
364
 
354
- Artist.where(:name=>/JM$/)
355
- # SELECT * FROM artists WHERE name ~ 'JM$'
365
+ Artist.where(name: /JM$/)
366
+ # SELECT * FROM artists WHERE (name ~ 'JM$')
356
367
 
357
368
  If there are multiple arguments in the hash, the filters are ANDed together:
358
369
 
359
- Artist.where(:id=>1, :name=>/JM$/)
360
- # SELECT * FROM artists WHERE id = 1 AND name ~ 'JM$'
370
+ Artist.where(id: 1, name: /JM$/)
371
+ # SELECT * FROM artists WHERE ((id = 1) AND (name ~ 'JM$'))
361
372
 
362
373
  This works the same as if you used two separate +where+ calls:
363
374
 
364
- Artist.where(:id=>1).where(:name=>/JM$/)
365
- # SELECT * FROM artists WHERE id = 1 AND name ~ 'JM$'
375
+ Artist.where(id: 1).where(name: /JM$/)
376
+ # SELECT * FROM artists WHERE ((id = 1) AND (name ~ 'JM$'))
366
377
 
367
378
  === Array of Two Element Arrays
368
379
 
@@ -371,28 +382,28 @@ advantage to using an array of two element arrays is that it allows you to
371
382
  duplicate keys, so you can do:
372
383
 
373
384
  Artist.where([[:name, /JM$/], [:name, /^YJ/]])
374
- # SELECT * FROM artists WHERE name ~ 'JM$' AND name ~ '^YJ'
385
+ # SELECT * FROM artists WHERE ((name ~ 'JM$')) AND ((name ~ '^YJ'))
375
386
 
376
387
  === Virtual Row Blocks
377
388
 
378
389
  If a block is passed to a filter, it is treated as a virtual row block:
379
390
 
380
391
  Artist.where{id > 5}
381
- # SELECT * FROM artists WHERE id > 5
392
+ # SELECT * FROM artists WHERE (id > 5)
382
393
 
383
394
  You can learn more about virtual row blocks in the {"Virtual Rows" guide}[rdoc-ref:doc/virtual_rows.rdoc].
384
395
 
385
396
  You can provide both regular arguments and a block, in which case the results
386
397
  will be ANDed together:
387
398
 
388
- Artist.where(:name=>'A'...'M'){id > 5}
389
- # SELECT * FROM artists WHERE name >= 'A' AND name < 'M' AND id > 5
399
+ Artist.where(name: 'A'...'M'){id > 5}
400
+ # SELECT * FROM artists WHERE ((name >= 'A') AND (name < 'M') AND (id > 5))
390
401
 
391
402
  Using virtual row blocks, what you can do with single entry hash or an array with
392
403
  a single two element array can also be done using the =~ method:
393
404
 
394
405
  Artist.where{id =~ 5}
395
- # SELECT * FROM artists WHERE id = 5
406
+ # SELECT * FROM artists WHERE (id = 5)
396
407
 
397
408
  === Symbols
398
409
 
@@ -420,43 +431,44 @@ method is Sequel.[], which takes any object and wraps it in a SQL::Expression
420
431
  object. In most cases, the SQL::Expression returned supports the & operator for
421
432
  +AND+, the | operator for +OR+, and the ~ operator for inversion:
422
433
 
423
- Artist.where(Sequel.like(:name, 'Y%') & (Sequel[:b=>1] | Sequel.~(:c=>3)))
424
- # SELECT * FROM artists WHERE name LIKE 'Y%' ESCAPE '\' AND (b = 1 OR c != 3)
434
+ Artist.where(Sequel.like(:name, 'Y%') & (Sequel[{b: 1}] | Sequel.~(c: 3)))
435
+ # SELECT * FROM artists WHERE ((name LIKE 'Y%' ESCAPE '\') AND ((b = 1) OR (c != 3)))
425
436
 
426
437
  You can combine these expression operators with the virtual row support:
427
438
 
428
439
  Artist.where{(a > 1) & ~((b(c) < 1) | d)}
429
- # SELECT * FROM artists WHERE a > 1 AND b(c) >= 1 AND NOT d
440
+ # SELECT * FROM artists WHERE ((a > 1) AND (b(c) >= 1) AND NOT d)
430
441
 
431
442
  Note the use of parentheses when using the & and | operators, as they have lower
432
443
  precedence than other operators. The following will not work:
433
444
 
434
445
  Artist.where{a > 1 & ~(b(c) < 1 | d)}
435
- # Raises a TypeError, as it calls Integer#| with a Sequel::SQL::Identifier
446
+ # Raises a TypeError
436
447
 
437
448
  === Strings with Placeholders
438
449
 
439
- Assuming you want to get your hands dirty and write some SQL, Sequel allows you
440
- to use strings using placeholders for the values:
450
+ Assuming you want to get your hands dirty and use SQL fragments in filters, Sequel allows you
451
+ to do so if you explicitly mark the strings as literal strings using +Sequel.lit+. You can
452
+ use placeholders in the string and pass arguments for the placeholders:
441
453
 
442
- Artist.where("name LIKE ?", 'Y%')
443
- # SELECT * FROM artists WHERE name LIKE 'Y%'
454
+ Artist.where(Sequel.lit("name LIKE ?", 'Y%'))
455
+ # SELECT * FROM artists WHERE (name LIKE 'Y%')
444
456
 
445
457
  This is the most common type of placeholder, where each question mark is substituted
446
458
  with the next argument:
447
459
 
448
- Artist.where("name LIKE ? AND id = ?", 'Y%', 5)
449
- # SELECT * FROM artists WHERE name LIKE 'Y%' AND id = 5
460
+ Artist.where(Sequel.lit("name LIKE ? AND id = ?", 'Y%', 5))
461
+ # SELECT * FROM artists WHERE (name LIKE 'Y%' AND id = 5)
450
462
 
451
463
  You can also use named placeholders with a hash, where the named placeholders use
452
464
  colons before the placeholder names:
453
465
 
454
- Artist.where("name LIKE :name AND id = :id", :name=>'Y%', :id=>5)
455
- # SELECT * FROM artists WHERE name LIKE 'Y%' AND id = 5
466
+ Artist.where(Sequel.lit("name LIKE :name AND id = :id", name: 'Y%', id: 5))
467
+ # SELECT * FROM artists WHERE (name LIKE 'Y%' AND id = 5)
456
468
 
457
469
  You don't have to provide any placeholders if you don't want to:
458
470
 
459
- Artist.where("id = 2")
471
+ Artist.where(Sequel.lit("id = 2"))
460
472
  # SELECT * FROM artists WHERE id = 2
461
473
 
462
474
  However, if you are using any untrusted input, you should definitely be using placeholders.
@@ -464,9 +476,9 @@ In general, unless you are hardcoding values in the strings, you should use plac
464
476
  You should never pass a string that has been built using interpolation, unless you are
465
477
  sure of what you are doing.
466
478
 
467
- Artist.where("id = #{params[:id]}") # Don't do this!
468
- Artist.where("id = ?", params[:id]) # Do this instead
469
- Artist.where(:id=>params[:id].to_i) # Even better
479
+ Artist.where(Sequel.lit("id = #{params[:id]}")) # Don't do this!
480
+ Artist.where(Sequel.lit("id = ?", params[:id])) # Do this instead
481
+ Artist.where(id: params[:id].to_i) # Even better
470
482
 
471
483
  === Inverting
472
484
 
@@ -474,53 +486,53 @@ You may be wondering how to specify a not equals condition in Sequel, or the NOT
474
486
  operator. Sequel has generic support for inverting conditions, so to write a not
475
487
  equals condition, you write an equals condition, and invert it:
476
488
 
477
- Artist.where(:id=>5).invert
478
- # SELECT * FROM artists WHERE id != 5
489
+ Artist.where(id: 5).invert
490
+ # SELECT * FROM artists WHERE (id != 5)
479
491
 
480
492
  Note that +invert+ inverts the entire filter:
481
493
 
482
- Artist.where(:id=>5).where{name > 'A'}.invert
483
- # SELECT * FROM artists WHERE id != 5 OR name <= 'A'
494
+ Artist.where(id: 5).where{name > 'A'}.invert
495
+ # SELECT * FROM artists WHERE ((id != 5) OR (name <= 'A'))
484
496
 
485
497
  In general, +invert+ is used rarely, since +exclude+ allows you to invert only specific
486
498
  filters:
487
499
 
488
- Artist.exclude(:id=>5)
489
- # SELECT * FROM artists WHERE id != 5
500
+ Artist.exclude(id: 5)
501
+ # SELECT * FROM artists WHERE (id != 5)
490
502
 
491
- Artist.where(:id=>5).exclude{name > 'A'}
492
- # SELECT * FROM artists WHERE id = 5 OR name <= 'A'
503
+ Artist.where(id: 5).exclude{name > 'A'}
504
+ # SELECT * FROM artists WHERE ((id = 5) OR (name <= 'A')
493
505
 
494
506
  So to do a NOT IN with an array:
495
507
 
496
- Artist.exclude(:id=>[1, 2])
497
- # SELECT * FROM artists WHERE id NOT IN (1, 2)
508
+ Artist.exclude(id: [1, 2])
509
+ # SELECT * FROM artists WHERE (id NOT IN (1, 2))
498
510
 
499
511
  Or to use the NOT LIKE operator:
500
512
 
501
513
  Artist.exclude(Sequel.like(:name, '%J%'))
502
- # SELECT * FROM artists WHERE name NOT LIKE '%J%' ESCAPE '\'
514
+ # SELECT * FROM artists WHERE (name NOT LIKE '%J%' ESCAPE '\')
503
515
 
504
516
  You can use Sequel.~ to negate expressions:
505
517
 
506
- Artist.where(Sequel.~(:id=>5))
518
+ Artist.where(Sequel.~(id: 5))
507
519
  # SELECT * FROM artists WHERE id != 5
508
520
 
509
521
  On Sequel expression objects, you can use ~ to negate them:
510
522
 
511
523
  Artist.where(~Sequel.like(:name, '%J%'))
512
- # SELECT * FROM artists WHERE name NOT LIKE '%J%' ESCAPE '\'
524
+ # SELECT * FROM artists WHERE (name NOT LIKE '%J%' ESCAPE '\')
513
525
 
514
- On Ruby 1.9+, you can use !~ on Sequel expressions to create negated expressions:
526
+ You can use !~ on Sequel expressions to create negated expressions:
515
527
 
516
- Artist.where{ id !~ 5}
517
- # SELECT * FROM artists WHERE id != 5
528
+ Artist.where{id !~ 5}
529
+ # SELECT * FROM artists WHERE (id != 5)
518
530
 
519
531
  === Removing
520
532
 
521
533
  To remove all existing filters, use +unfiltered+:
522
534
 
523
- Artist.where(:id=>1).unfiltered
535
+ Artist.where(id: 1).unfiltered
524
536
  # SELECT * FROM artists
525
537
 
526
538
  == Ordering
@@ -555,14 +567,17 @@ If you want to add a column to the beginning of the existing order:
555
567
  === Reversing
556
568
 
557
569
  Just like you can invert an existing filter, you can reverse an existing
558
- order, using +reverse+:
570
+ order, using +reverse+ without an order:
559
571
 
560
572
  Artist.order(:id).reverse
561
573
  # SELECT FROM artists ORDER BY id DESC
562
574
 
563
- As you might expect, +reverse+ is not used all that much. In general,
564
- <tt>Sequel.desc</tt> is used more commonly to specify a descending order
565
- for columns:
575
+ Alternatively, you can provide reverse with the order:
576
+
577
+ Artist.reverse(:id)
578
+ # SELECT FROM artists ORDER BY id DESC
579
+
580
+ To specify a single entry be reversed, <tt>Sequel.desc</tt> can be used:
566
581
 
567
582
  Artist.order(Sequel.desc(:id))
568
583
  # SELECT FROM artists ORDER BY id DESC
@@ -658,7 +673,7 @@ You can also call the +offset+ method separately:
658
673
  Either of these would return the 11th through 15th records in the original
659
674
  dataset.
660
675
 
661
- To remove a limit from a dataset, use +unlimited+:
676
+ To remove a limit and offset from a dataset, use +unlimited+:
662
677
 
663
678
  Artist.limit(5, 10).unlimited
664
679
  # SELECT * FROM artists
@@ -709,50 +724,46 @@ filters the results after the grouping has been applied, instead of
709
724
  before. One possible use is if you only wanted to return artists
710
725
  who had at least 10 albums:
711
726
 
712
- Album.group_and_count(:artist_id).having{count(:*){} >= 10}
727
+ Album.group_and_count(:artist_id).having{count.function.* >= 10}
713
728
  # SELECT artist_id, count(*) AS count FROM albums
714
- # GROUP BY artist_id HAVING count(*) >= 10
729
+ # GROUP BY artist_id HAVING (count(*) >= 10)
715
730
 
716
731
  Both the WHERE clause and the HAVING clause are removed by +unfiltered+:
717
732
 
718
- Album.group_and_count(:artist_id).having{count(:*){} >= 10}.
733
+ Album.group_and_count(:artist_id).having{count.function.* >= 10}.
719
734
  where(:name.like('A%')).unfiltered
720
735
  # SELECT artist_id, count(*) AS count FROM albums GROUP BY artist_id
721
736
 
722
737
  == Joins
723
738
 
724
- Sequel makes it very easy to join a dataset to another table or dataset.
739
+ Sequel has support for many different SQL join types.
725
740
  The underlying method used is +join_table+:
726
741
 
727
- Album.join_table(:inner, :artists, :id=>:artist_id)
742
+ Album.join_table(:inner, :artists, id: :artist_id)
728
743
  # SELECT * FROM albums
729
- # INNER JOIN artists ON artists.id = albums.artist_id
744
+ # INNER JOIN artists ON (artists.id = albums.artist_id)
730
745
 
731
746
  In most cases, you won't call +join_table+ directly, as Sequel provides
732
747
  shortcuts for all common (and most uncommon) join types. For example
733
748
  +join+ does an inner join:
734
749
 
735
- Album.join(:artists, :id=>:artist_id)
750
+ Album.join(:artists, id: :artist_id)
736
751
  # SELECT * FROM albums
737
- # INNER JOIN artists ON artists.id = albums.artist_id
752
+ # INNER JOIN artists ON (artists.id = albums.artist_id))))
738
753
 
739
754
  And +left_join+ does a LEFT JOIN:
740
755
 
741
- Album.left_join(:artists, :id=>:artist_id)
756
+ Album.left_join(:artists, id: :artist_id)
742
757
  # SELECT * FROM albums
743
- # LEFT JOIN artists ON artists.id = albums.artist_id
758
+ # LEFT JOIN artists ON (artists.id = albums.artist_id)
744
759
 
745
760
  === Table/Dataset to Join
746
761
 
747
762
  For all of these specialized join methods, the first argument is
748
763
  generally the name of the table to which you are joining. However, you
749
- can also provide a model class:
750
-
751
- Album.join(Artist, :id=>:artist_id)
752
-
753
- Or a dataset, in which case a subselect is used:
764
+ can also provide a dataset, in which case a subselect is used:
754
765
 
755
- Album.join(Artist.where{name < 'A'}, :id=>:artist_id)
766
+ Album.join(Artist.where{name < 'A'}, id: :artist_id)
756
767
  # SELECT * FROM albums
757
768
  # INNER JOIN (SELECT * FROM artists WHERE (name < 'A')) AS t1
758
769
  # ON (t1.id = albums.artist_id)
@@ -768,80 +779,78 @@ a few minor exceptions.
768
779
  A hash used as the join conditions operates similarly to a filter,
769
780
  except that unqualified symbol keys are automatically qualified
770
781
  with the table from the first argument, and unqualified symbol values
771
- are automatically qualified with the first table or the last table
772
- joined. This implicit qualification is one of the reasons that joins
773
- in Sequel are easy to specify:
782
+ are automatically qualified with the last table joined (or the first
783
+ table in the dataset if there hasn't been a previous join):
774
784
 
775
- Album.join(:artists, :id=>:artist_id)
785
+ Album.join(:artists, id: :artist_id)
776
786
  # SELECT * FROM albums
777
- # INNER JOIN artists ON artists.id = albums.artist_id
787
+ # INNER JOIN artists ON (artists.id = albums.artist_id)
778
788
 
779
- Note how the <tt>:id</tt> symbol is automatically qualified with +artists+,
789
+ Note how the +id+ symbol is automatically qualified with +artists+,
780
790
  while the +artist_id+ symbol is automatically qualified with +albums+.
781
791
 
782
792
  Because Sequel uses the last joined table for implicit qualifications
783
793
  of values, you can do things like:
784
794
 
785
- Album.join(:artists, :id=>:artist_id).
786
- join(:members, :artist_id=>:id)
795
+ Album.join(:artists, id: :artist_id).
796
+ join(:members, artist_id: :id)
787
797
  # SELECT * FROM albums
788
- # INNER JOIN artists ON artists.id = albums.artist_id
789
- # INNER JOIN members ON members.artist_id = artists.id
798
+ # INNER JOIN artists ON (artists.id = albums.artist_id)
799
+ # INNER JOIN members ON (members.artist_id = artists.id)
790
800
 
791
801
  Note that when joining to the +members+ table, +artist_id+ is qualified
792
802
  with +members+ and +id+ is qualified with +artists+.
793
803
 
794
804
  While a good default, implicit qualification is not always correct:
795
805
 
796
- Album.join(:artists, :id=>:artist_id).
797
- join(:tracks, :album_id=>:id)
806
+ Album.join(:artists, id: :artist_id).
807
+ join(:tracks, album_id: :id)
798
808
  # SELECT * FROM albums
799
- # INNER JOIN artists ON artists.id = albums.artist_id
800
- # INNER JOIN tracks ON tracks.album_id = artists.id
809
+ # INNER JOIN artists ON (artists.id = albums.artist_id)
810
+ # INNER JOIN tracks ON (tracks.album_id = artists.id)
801
811
 
802
812
  Note here how +id+ is qualified with +artists+ instead of +albums+. This
803
813
  is wrong as the foreign key <tt>tracks.album_id</tt> refers to <tt>albums.id</tt>, not
804
814
  <tt>artists.id</tt>. To fix this, you need to explicitly qualify when joining:
805
815
 
806
- Album.join(:artists, :id=>:artist_id).
807
- join(:tracks, :album_id=>Sequel[:albums][:id])
816
+ Album.join(:artists, id: :artist_id).
817
+ join(:tracks, album_id: Sequel[:albums][:id])
808
818
  # SELECT * FROM albums
809
- # INNER JOIN artists ON artists.id = albums.artist_id
810
- # INNER JOIN tracks ON tracks.album_id = albums.id
819
+ # INNER JOIN artists ON (artists.id = albums.artist_id)
820
+ # INNER JOIN tracks ON (tracks.album_id = albums.id)
811
821
 
812
822
  Just like in filters, an array of two element arrays is treated the same
813
823
  as a hash, but allows for duplicate keys:
814
824
 
815
825
  Album.join(:artists, [[:id, :artist_id], [:id, 1..5]])
816
826
  # SELECT * FROM albums INNER JOIN artists
817
- # ON artists.id = albums.artist_id
818
- # AND artists.id >= 1 AND artists.id <= 5
827
+ # ON ((artists.id = albums.artist_id)
828
+ # AND (artists.id >= 1) AND (artists.id <= 5))
819
829
 
820
830
  And just like in the hash case, unqualified symbol elements in the
821
831
  array are implicitly qualified.
822
832
 
823
833
  By default, Sequel only qualifies unqualified symbols in the conditions. However,
824
- You can provide an options hash with a <tt>:qualify=>:deep</tt> option to do a deep
834
+ You can provide an options hash with a <tt>qualify: :deep</tt> option to do a deep
825
835
  qualification, which can qualify subexpressions. For example, let's say you are doing
826
836
  a JOIN using case insensitive string comparison:
827
837
 
828
838
  Album.join(:artists, {Sequel.function(:lower, :name) =>
829
839
  Sequel.function(:lower, :artist_name)},
830
- :qualify => :deep)
840
+ qualify: :deep)
831
841
  # SELECT * FROM albums INNER JOIN artists
832
842
  # ON (lower(artists.name) = lower(albums.artist_name))
833
843
 
834
- Note how the arguments to lower were qualified correctly in both cases. Starting in Sequel 4,
835
- the <tt>:qualify=>:deep</tt> option is going to become the default.
844
+ Note how the arguments to lower were qualified correctly in both cases.
836
845
 
837
846
  ==== USING Joins
838
847
 
839
848
  The most common type of join conditions is a JOIN ON, as displayed
840
849
  above. However, the SQL standard allows for join conditions to be
841
- specified with JOIN USING, which Sequel makes easy to use.
850
+ specified with JOIN USING, assuming the column name is the same in
851
+ both tables.
842
852
 
843
- JOIN USING is useful when the columns you are using have the same
844
- names in both tables. For example, if instead of having a primary
853
+ For example, if instead of having a primary
845
854
  column named +id+ in all of your tables, you use +artist_id+ in your
846
855
  +artists+ table and +album_id+ in your +albums+ table, you could do:
847
856
 
@@ -852,7 +861,7 @@ See here how you specify the USING columns as an array of symbols.
852
861
 
853
862
  ==== NATURAL Joins
854
863
 
855
- NATURAL Joins take it one step further than USING joins, by assuming
864
+ NATURAL joins take it one step further than USING joins, by assuming
856
865
  that all columns with the same names in both tables should be
857
866
  used for joining:
858
867
 
@@ -875,12 +884,12 @@ being used. For example, lets say you wanted to join the albums
875
884
  and artists tables, but only want albums where the artist's name
876
885
  comes before the album's name.
877
886
 
878
- Album.join(:artists, :id=>:artist_id) do |j, lj, js|
887
+ Album.join(:artists, id: :artist_id) do |j, lj, js|
879
888
  Sequel[j][:name] < Sequel[lj][:name]
880
889
  end
881
890
  # SELECT * FROM albums INNER JOIN artists
882
- # ON artists.id = albums.artist_id
883
- # AND artists.name < albums.name
891
+ # ON ((artists.id = albums.artist_id)
892
+ # AND (artists.name < albums.name))
884
893
 
885
894
  Because greater than can't be expressed with a hash in Sequel, you
886
895
  need to use a block and qualify the tables manually.
@@ -905,7 +914,7 @@ Using multiple FROM tables and setting conditions in the WHERE clause is
905
914
  an old-school way of joining tables:
906
915
 
907
916
  DB.from(:albums, :artists).where{{artists[:id]=>albums[:artist_id]}}
908
- # SELECT * FROM albums, artists WHERE artists.id = albums.artist_id
917
+ # SELECT * FROM albums, artists WHERE (artists.id = albums.artist_id)
909
918
 
910
919
  === Using the current dataset in a subselect
911
920
 
@@ -916,7 +925,7 @@ Here's an example using +from_self+:
916
925
  # SELECT * FROM (SELECT * FROM albums ORDER BY artist_id LIMIT 100)
917
926
  # AS t1 GROUP BY artist_id
918
927
 
919
- This is slightly different than without +from_self+:
928
+ This is different than without +from_self+:
920
929
 
921
930
  Album.order(:artist_id).limit(100).group(:artist_id)
922
931
  # SELECT * FROM albums GROUP BY artist_id ORDER BY name LIMIT 100
@@ -937,8 +946,8 @@ current transaction commits. You just use the +for_update+ dataset
937
946
  method when returning the rows:
938
947
 
939
948
  DB.transaction do
940
- album = Album.for_update.first(:id=>1)
941
- # SELECT * FROM albums WHERE id = 1 FOR UPDATE
949
+ album = Album.for_update.first(id: 1)
950
+ # SELECT * FROM albums WHERE (id = 1) FOR UPDATE
942
951
  album.num_tracks += 1
943
952
  album.save
944
953
  end
@@ -956,7 +965,7 @@ stateless nature.
956
965
 
957
966
  == Custom SQL
958
967
 
959
- Sequel makes it easy to use custom SQL by providing it to the <tt>Database#[]</tt>
968
+ Sequel makes it easy to use custom SQL for the query by providing it to the <tt>Database#[]</tt>
960
969
  method as a string:
961
970
 
962
971
  DB["SELECT * FROM artists"]
@@ -973,7 +982,7 @@ With either of these methods, you can use placeholders:
973
982
  DB["SELECT * FROM artists WHERE id = ?", 5]
974
983
  # SELECT * FROM artists WHERE id = 5
975
984
 
976
- DB[:albums].with_sql("SELECT * FROM artists WHERE id = :id", :id=>5)
985
+ DB[:albums].with_sql("SELECT * FROM artists WHERE id = :id", id: 5)
977
986
  # SELECT * FROM artists WHERE id = 5
978
987
 
979
988
  Note that if you specify the dataset using custom SQL, you can still call the dataset
@@ -982,6 +991,13 @@ modification methods, but in many cases they will appear to have no affect:
982
991
  DB["SELECT * FROM artists"].select(:name).order(:id)
983
992
  # SELECT * FROM artists
984
993
 
994
+ You can use the implicit_subquery extension to automatically wrap queries that use
995
+ custom SQL in subqueries if a method is called that would modify the SQL:
996
+
997
+ DB.extension :implicit_subquery
998
+ DB["SELECT * FROM artists"].select(:name).order(:id)
999
+ # SELECT name FROM (SELECT * FROM artists) AS t1 ORDER BY id"
1000
+
985
1001
  If you must drop down to using custom SQL, it's recommended that you only do so for
986
1002
  specific parts of a query. For example, if the reason you are using custom SQL is
987
1003
  to use a custom operator in the database in the SELECT clause:
@@ -1003,12 +1019,12 @@ If you just want to know whether the current dataset would return any rows, use
1003
1019
  # SELECT 1 FROM albums LIMIT 1
1004
1020
  # => false
1005
1021
 
1006
- Album.where(:id=>0).empty?
1007
- # SELECT 1 FROM albums WHERE id = 0 LIMIT 1
1022
+ Album.where(id: 0).empty?
1023
+ # SELECT 1 FROM albums WHERE (id = 0) LIMIT 1
1008
1024
  # => true
1009
1025
 
1010
1026
  Album.where(Sequel.like(:name, 'R%')).empty?
1011
- # SELECT 1 FROM albums WHERE name LIKE 'R%' ESCAPE '\' LIMIT 1
1027
+ # SELECT 1 FROM albums WHERE (name LIKE 'R%' ESCAPE '\') LIMIT 1
1012
1028
  # => false
1013
1029
 
1014
1030
  == Aggregate Calculations
@@ -1022,22 +1038,29 @@ for each of these aggregate functions.
1022
1038
  Album.count
1023
1039
  # SELECT count(*) AS count FROM albums LIMIT 1
1024
1040
  # => 2
1025
-
1041
+
1042
+ If you pass an expression to count, it will return the number of records where
1043
+ that expression in not NULL:
1044
+
1045
+ Album.count(:artist_id)
1046
+ # SELECT count(artist_id) AS count FROM albums LIMIT 1
1047
+ # => 1
1048
+
1026
1049
  The other methods take a column argument and call the aggregate function with
1027
1050
  the argument:
1028
1051
 
1029
1052
  Album.sum(:id)
1030
- # SELECT sum(id) FROM albums LIMIT 1
1053
+ # SELECT sum(id) AS sum FROM albums LIMIT 1
1031
1054
  # => 3
1032
1055
 
1033
1056
  Album.avg(:id)
1034
- # SELECT avg(id) FROM albums LIMIT 1
1057
+ # SELECT avg(id) AS avg FROM albums LIMIT 1
1035
1058
  # => 1.5
1036
1059
 
1037
1060
  Album.min(:id)
1038
- # SELECT min(id) FROM albums LIMIT 1
1061
+ # SELECT min(id) AS min FROM albums LIMIT 1
1039
1062
  # => 1
1040
1063
 
1041
1064
  Album.max(:id)
1042
- # SELECT max(id) FROM albums LIMIT 1
1065
+ # SELECT max(id) AS max FROM albums LIMIT 1
1043
1066
  # => 2