sequel 4.26.0 → 5.37.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (692) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +405 -5656
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +232 -157
  5. data/bin/sequel +32 -9
  6. data/doc/advanced_associations.rdoc +252 -188
  7. data/doc/association_basics.rdoc +231 -273
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +75 -48
  10. data/doc/code_order.rdoc +28 -10
  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/mass_assignment.rdoc +74 -31
  16. data/doc/migration.rdoc +72 -46
  17. data/doc/model_dataset_method_design.rdoc +129 -0
  18. data/doc/model_hooks.rdoc +15 -25
  19. data/doc/model_plugins.rdoc +12 -12
  20. data/doc/mssql_stored_procedures.rdoc +3 -3
  21. data/doc/object_model.rdoc +59 -69
  22. data/doc/opening_databases.rdoc +84 -94
  23. data/doc/postgresql.rdoc +268 -38
  24. data/doc/prepared_statements.rdoc +29 -24
  25. data/doc/querying.rdoc +184 -164
  26. data/doc/reflection.rdoc +5 -6
  27. data/doc/release_notes/5.0.0.txt +159 -0
  28. data/doc/release_notes/5.1.0.txt +31 -0
  29. data/doc/release_notes/5.10.0.txt +84 -0
  30. data/doc/release_notes/5.11.0.txt +83 -0
  31. data/doc/release_notes/5.12.0.txt +141 -0
  32. data/doc/release_notes/5.13.0.txt +27 -0
  33. data/doc/release_notes/5.14.0.txt +63 -0
  34. data/doc/release_notes/5.15.0.txt +39 -0
  35. data/doc/release_notes/5.16.0.txt +110 -0
  36. data/doc/release_notes/5.17.0.txt +31 -0
  37. data/doc/release_notes/5.18.0.txt +69 -0
  38. data/doc/release_notes/5.19.0.txt +28 -0
  39. data/doc/release_notes/5.2.0.txt +33 -0
  40. data/doc/release_notes/5.20.0.txt +89 -0
  41. data/doc/release_notes/5.21.0.txt +87 -0
  42. data/doc/release_notes/5.22.0.txt +48 -0
  43. data/doc/release_notes/5.23.0.txt +56 -0
  44. data/doc/release_notes/5.24.0.txt +56 -0
  45. data/doc/release_notes/5.25.0.txt +32 -0
  46. data/doc/release_notes/5.26.0.txt +35 -0
  47. data/doc/release_notes/5.27.0.txt +21 -0
  48. data/doc/release_notes/5.28.0.txt +16 -0
  49. data/doc/release_notes/5.29.0.txt +22 -0
  50. data/doc/release_notes/5.3.0.txt +121 -0
  51. data/doc/release_notes/5.30.0.txt +20 -0
  52. data/doc/release_notes/5.31.0.txt +148 -0
  53. data/doc/release_notes/5.32.0.txt +46 -0
  54. data/doc/release_notes/5.33.0.txt +24 -0
  55. data/doc/release_notes/5.34.0.txt +40 -0
  56. data/doc/release_notes/5.35.0.txt +56 -0
  57. data/doc/release_notes/5.36.0.txt +60 -0
  58. data/doc/release_notes/5.37.0.txt +30 -0
  59. data/doc/release_notes/5.4.0.txt +80 -0
  60. data/doc/release_notes/5.5.0.txt +61 -0
  61. data/doc/release_notes/5.6.0.txt +31 -0
  62. data/doc/release_notes/5.7.0.txt +108 -0
  63. data/doc/release_notes/5.8.0.txt +170 -0
  64. data/doc/release_notes/5.9.0.txt +99 -0
  65. data/doc/schema_modification.rdoc +102 -77
  66. data/doc/security.rdoc +160 -87
  67. data/doc/sharding.rdoc +74 -47
  68. data/doc/sql.rdoc +135 -122
  69. data/doc/testing.rdoc +34 -18
  70. data/doc/thread_safety.rdoc +2 -4
  71. data/doc/transactions.rdoc +101 -19
  72. data/doc/validations.rdoc +64 -51
  73. data/doc/virtual_rows.rdoc +90 -109
  74. data/lib/sequel.rb +3 -1
  75. data/lib/sequel/adapters/ado.rb +154 -22
  76. data/lib/sequel/adapters/ado/access.rb +21 -21
  77. data/lib/sequel/adapters/ado/mssql.rb +8 -15
  78. data/lib/sequel/adapters/amalgalite.rb +17 -25
  79. data/lib/sequel/adapters/ibmdb.rb +52 -58
  80. data/lib/sequel/adapters/jdbc.rb +149 -127
  81. data/lib/sequel/adapters/jdbc/db2.rb +32 -40
  82. data/lib/sequel/adapters/jdbc/derby.rb +56 -58
  83. data/lib/sequel/adapters/jdbc/h2.rb +40 -30
  84. data/lib/sequel/adapters/jdbc/hsqldb.rb +22 -33
  85. data/lib/sequel/adapters/jdbc/jtds.rb +4 -10
  86. data/lib/sequel/adapters/jdbc/mssql.rb +6 -12
  87. data/lib/sequel/adapters/jdbc/mysql.rb +17 -18
  88. data/lib/sequel/adapters/jdbc/oracle.rb +25 -19
  89. data/lib/sequel/adapters/jdbc/postgresql.rb +90 -69
  90. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +14 -24
  91. data/lib/sequel/adapters/jdbc/sqlite.rb +50 -12
  92. data/lib/sequel/adapters/jdbc/sqlserver.rb +36 -9
  93. data/lib/sequel/adapters/jdbc/transactions.rb +25 -39
  94. data/lib/sequel/adapters/mock.rb +104 -113
  95. data/lib/sequel/adapters/mysql.rb +42 -61
  96. data/lib/sequel/adapters/mysql2.rb +126 -35
  97. data/lib/sequel/adapters/odbc.rb +21 -28
  98. data/lib/sequel/adapters/odbc/db2.rb +3 -1
  99. data/lib/sequel/adapters/odbc/mssql.rb +11 -15
  100. data/lib/sequel/adapters/odbc/oracle.rb +11 -0
  101. data/lib/sequel/adapters/oracle.rb +62 -68
  102. data/lib/sequel/adapters/postgres.rb +257 -311
  103. data/lib/sequel/adapters/postgresql.rb +3 -1
  104. data/lib/sequel/adapters/shared/access.rb +75 -79
  105. data/lib/sequel/adapters/shared/db2.rb +96 -74
  106. data/lib/sequel/adapters/shared/mssql.rb +258 -213
  107. data/lib/sequel/adapters/shared/mysql.rb +284 -216
  108. data/lib/sequel/adapters/shared/oracle.rb +175 -60
  109. data/lib/sequel/adapters/shared/postgres.rb +829 -383
  110. data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -127
  111. data/lib/sequel/adapters/shared/sqlite.rb +382 -159
  112. data/lib/sequel/adapters/sqlanywhere.rb +53 -38
  113. data/lib/sequel/adapters/sqlite.rb +111 -105
  114. data/lib/sequel/adapters/tinytds.rb +38 -46
  115. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -9
  116. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -5
  117. data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
  118. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
  119. data/lib/sequel/adapters/utils/replace.rb +3 -4
  120. data/lib/sequel/adapters/utils/split_alter_table.rb +2 -0
  121. data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
  122. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
  123. data/lib/sequel/ast_transformer.rb +13 -89
  124. data/lib/sequel/connection_pool.rb +54 -26
  125. data/lib/sequel/connection_pool/sharded_single.rb +19 -12
  126. data/lib/sequel/connection_pool/sharded_threaded.rb +160 -111
  127. data/lib/sequel/connection_pool/single.rb +21 -12
  128. data/lib/sequel/connection_pool/threaded.rb +137 -119
  129. data/lib/sequel/core.rb +352 -320
  130. data/lib/sequel/database.rb +19 -2
  131. data/lib/sequel/database/connecting.rb +70 -55
  132. data/lib/sequel/database/dataset.rb +15 -5
  133. data/lib/sequel/database/dataset_defaults.rb +20 -102
  134. data/lib/sequel/database/features.rb +20 -4
  135. data/lib/sequel/database/logging.rb +25 -7
  136. data/lib/sequel/database/misc.rb +132 -118
  137. data/lib/sequel/database/query.rb +51 -28
  138. data/lib/sequel/database/schema_generator.rb +188 -75
  139. data/lib/sequel/database/schema_methods.rb +161 -92
  140. data/lib/sequel/database/transactions.rb +260 -58
  141. data/lib/sequel/dataset.rb +28 -12
  142. data/lib/sequel/dataset/actions.rb +354 -170
  143. data/lib/sequel/dataset/dataset_module.rb +46 -0
  144. data/lib/sequel/dataset/features.rb +81 -34
  145. data/lib/sequel/dataset/graph.rb +82 -58
  146. data/lib/sequel/dataset/misc.rb +139 -47
  147. data/lib/sequel/dataset/placeholder_literalizer.rb +66 -26
  148. data/lib/sequel/dataset/prepared_statements.rb +188 -85
  149. data/lib/sequel/dataset/query.rb +428 -214
  150. data/lib/sequel/dataset/sql.rb +446 -339
  151. data/lib/sequel/deprecated.rb +14 -2
  152. data/lib/sequel/exceptions.rb +48 -16
  153. data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
  154. data/lib/sequel/extensions/_model_pg_row.rb +43 -0
  155. data/lib/sequel/extensions/_pretty_table.rb +10 -9
  156. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  157. data/lib/sequel/extensions/arbitrary_servers.rb +15 -11
  158. data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  159. data/lib/sequel/extensions/blank.rb +2 -0
  160. data/lib/sequel/extensions/caller_logging.rb +79 -0
  161. data/lib/sequel/extensions/columns_introspection.rb +9 -4
  162. data/lib/sequel/extensions/connection_expiration.rb +99 -0
  163. data/lib/sequel/extensions/connection_validator.rb +26 -13
  164. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  165. data/lib/sequel/extensions/constraint_validations.rb +93 -38
  166. data/lib/sequel/extensions/core_extensions.rb +45 -53
  167. data/lib/sequel/extensions/core_refinements.rb +44 -46
  168. data/lib/sequel/extensions/current_datetime_timestamp.rb +5 -4
  169. data/lib/sequel/extensions/dataset_source_alias.rb +4 -0
  170. data/lib/sequel/extensions/date_arithmetic.rb +42 -16
  171. data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
  172. data/lib/sequel/extensions/duplicate_columns_handler.rb +94 -0
  173. data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -3
  174. data/lib/sequel/extensions/error_sql.rb +7 -3
  175. data/lib/sequel/extensions/escaped_like.rb +100 -0
  176. data/lib/sequel/extensions/eval_inspect.rb +14 -15
  177. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  178. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  179. data/lib/sequel/extensions/freeze_datasets.rb +3 -0
  180. data/lib/sequel/extensions/from_block.rb +2 -31
  181. data/lib/sequel/extensions/graph_each.rb +19 -6
  182. data/lib/sequel/extensions/identifier_mangling.rb +180 -0
  183. data/lib/sequel/extensions/implicit_subquery.rb +48 -0
  184. data/lib/sequel/extensions/index_caching.rb +109 -0
  185. data/lib/sequel/extensions/inflector.rb +8 -4
  186. data/lib/sequel/extensions/integer64.rb +32 -0
  187. data/lib/sequel/extensions/looser_typecasting.rb +19 -9
  188. data/lib/sequel/extensions/migration.rb +132 -80
  189. data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +4 -0
  190. data/lib/sequel/extensions/named_timezones.rb +88 -23
  191. data/lib/sequel/extensions/no_auto_literal_strings.rb +4 -0
  192. data/lib/sequel/extensions/null_dataset.rb +12 -8
  193. data/lib/sequel/extensions/pagination.rb +35 -28
  194. data/lib/sequel/extensions/pg_array.rb +227 -316
  195. data/lib/sequel/extensions/pg_array_ops.rb +19 -7
  196. data/lib/sequel/extensions/pg_enum.rb +69 -24
  197. data/lib/sequel/extensions/pg_extended_date_support.rb +250 -0
  198. data/lib/sequel/extensions/pg_hstore.rb +50 -59
  199. data/lib/sequel/extensions/pg_hstore_ops.rb +9 -3
  200. data/lib/sequel/extensions/pg_inet.rb +34 -15
  201. data/lib/sequel/extensions/pg_inet_ops.rb +5 -1
  202. data/lib/sequel/extensions/pg_interval.rb +26 -26
  203. data/lib/sequel/extensions/pg_json.rb +422 -141
  204. data/lib/sequel/extensions/pg_json_ops.rb +248 -9
  205. data/lib/sequel/extensions/pg_loose_count.rb +5 -1
  206. data/lib/sequel/extensions/pg_range.rb +162 -146
  207. data/lib/sequel/extensions/pg_range_ops.rb +10 -5
  208. data/lib/sequel/extensions/pg_row.rb +53 -87
  209. data/lib/sequel/extensions/pg_row_ops.rb +36 -13
  210. data/lib/sequel/extensions/pg_static_cache_updater.rb +6 -2
  211. data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
  212. data/lib/sequel/extensions/pretty_table.rb +4 -0
  213. data/lib/sequel/extensions/query.rb +12 -7
  214. data/lib/sequel/extensions/round_timestamps.rb +6 -9
  215. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  216. data/lib/sequel/extensions/s.rb +59 -0
  217. data/lib/sequel/extensions/schema_caching.rb +14 -1
  218. data/lib/sequel/extensions/schema_dumper.rb +83 -55
  219. data/lib/sequel/extensions/select_remove.rb +8 -4
  220. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
  221. data/lib/sequel/extensions/server_block.rb +50 -17
  222. data/lib/sequel/extensions/server_logging.rb +61 -0
  223. data/lib/sequel/extensions/split_array_nil.rb +8 -4
  224. data/lib/sequel/extensions/sql_comments.rb +96 -0
  225. data/lib/sequel/extensions/sql_expr.rb +4 -1
  226. data/lib/sequel/extensions/string_agg.rb +181 -0
  227. data/lib/sequel/extensions/string_date_time.rb +2 -0
  228. data/lib/sequel/extensions/symbol_aref.rb +53 -0
  229. data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
  230. data/lib/sequel/extensions/symbol_as.rb +23 -0
  231. data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
  232. data/lib/sequel/extensions/synchronize_sql.rb +45 -0
  233. data/lib/sequel/extensions/thread_local_timezones.rb +4 -0
  234. data/lib/sequel/extensions/to_dot.rb +15 -5
  235. data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
  236. data/lib/sequel/model.rb +36 -126
  237. data/lib/sequel/model/associations.rb +850 -257
  238. data/lib/sequel/model/base.rb +652 -764
  239. data/lib/sequel/model/dataset_module.rb +13 -10
  240. data/lib/sequel/model/default_inflections.rb +3 -1
  241. data/lib/sequel/model/errors.rb +3 -3
  242. data/lib/sequel/model/exceptions.rb +12 -12
  243. data/lib/sequel/model/inflections.rb +8 -19
  244. data/lib/sequel/model/plugins.rb +111 -0
  245. data/lib/sequel/plugins/accessed_columns.rb +2 -0
  246. data/lib/sequel/plugins/active_model.rb +32 -7
  247. data/lib/sequel/plugins/after_initialize.rb +3 -1
  248. data/lib/sequel/plugins/association_dependencies.rb +27 -18
  249. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  250. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  251. data/lib/sequel/plugins/association_pks.rb +181 -83
  252. data/lib/sequel/plugins/association_proxies.rb +33 -9
  253. data/lib/sequel/plugins/auto_validations.rb +58 -23
  254. data/lib/sequel/plugins/before_after_save.rb +8 -0
  255. data/lib/sequel/plugins/blacklist_security.rb +23 -12
  256. data/lib/sequel/plugins/boolean_readers.rb +9 -6
  257. data/lib/sequel/plugins/boolean_subsets.rb +64 -0
  258. data/lib/sequel/plugins/caching.rb +27 -16
  259. data/lib/sequel/plugins/class_table_inheritance.rb +192 -94
  260. data/lib/sequel/plugins/column_conflicts.rb +18 -3
  261. data/lib/sequel/plugins/column_select.rb +9 -5
  262. data/lib/sequel/plugins/columns_updated.rb +42 -0
  263. data/lib/sequel/plugins/composition.rb +36 -24
  264. data/lib/sequel/plugins/constraint_validations.rb +37 -16
  265. data/lib/sequel/plugins/csv_serializer.rb +58 -35
  266. data/lib/sequel/plugins/dataset_associations.rb +60 -18
  267. data/lib/sequel/plugins/def_dataset_method.rb +90 -0
  268. data/lib/sequel/plugins/defaults_setter.rb +74 -13
  269. data/lib/sequel/plugins/delay_add_association.rb +4 -1
  270. data/lib/sequel/plugins/dirty.rb +65 -24
  271. data/lib/sequel/plugins/eager_each.rb +27 -3
  272. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  273. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  274. data/lib/sequel/plugins/error_splitter.rb +19 -12
  275. data/lib/sequel/plugins/finder.rb +246 -0
  276. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  277. data/lib/sequel/plugins/force_encoding.rb +9 -12
  278. data/lib/sequel/plugins/hook_class_methods.rb +39 -54
  279. data/lib/sequel/plugins/input_transformer.rb +20 -10
  280. data/lib/sequel/plugins/insert_conflict.rb +72 -0
  281. data/lib/sequel/plugins/insert_returning_select.rb +4 -2
  282. data/lib/sequel/plugins/instance_filters.rb +12 -8
  283. data/lib/sequel/plugins/instance_hooks.rb +36 -17
  284. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  285. data/lib/sequel/plugins/inverted_subsets.rb +24 -13
  286. data/lib/sequel/plugins/json_serializer.rb +123 -47
  287. data/lib/sequel/plugins/lazy_attributes.rb +20 -14
  288. data/lib/sequel/plugins/list.rb +40 -26
  289. data/lib/sequel/plugins/many_through_many.rb +28 -12
  290. data/lib/sequel/plugins/modification_detection.rb +17 -5
  291. data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -5
  292. data/lib/sequel/plugins/nested_attributes.rb +55 -28
  293. data/lib/sequel/plugins/optimistic_locking.rb +5 -3
  294. data/lib/sequel/plugins/pg_array_associations.rb +52 -18
  295. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +348 -0
  296. data/lib/sequel/plugins/pg_row.rb +7 -51
  297. data/lib/sequel/plugins/prepared_statements.rb +53 -72
  298. data/lib/sequel/plugins/prepared_statements_safe.rb +13 -5
  299. data/lib/sequel/plugins/rcte_tree.rb +43 -63
  300. data/lib/sequel/plugins/serialization.rb +37 -44
  301. data/lib/sequel/plugins/serialization_modification_detection.rb +3 -1
  302. data/lib/sequel/plugins/sharding.rb +17 -10
  303. data/lib/sequel/plugins/single_table_inheritance.rb +62 -28
  304. data/lib/sequel/plugins/singular_table_names.rb +2 -0
  305. data/lib/sequel/plugins/skip_create_refresh.rb +5 -3
  306. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  307. data/lib/sequel/plugins/split_values.rb +13 -6
  308. data/lib/sequel/plugins/static_cache.rb +79 -53
  309. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  310. data/lib/sequel/plugins/string_stripper.rb +5 -3
  311. data/lib/sequel/plugins/subclasses.rb +20 -2
  312. data/lib/sequel/plugins/subset_conditions.rb +48 -0
  313. data/lib/sequel/plugins/table_select.rb +4 -2
  314. data/lib/sequel/plugins/tactical_eager_loading.rb +120 -6
  315. data/lib/sequel/plugins/throw_failures.rb +110 -0
  316. data/lib/sequel/plugins/timestamps.rb +22 -8
  317. data/lib/sequel/plugins/touch.rb +21 -8
  318. data/lib/sequel/plugins/tree.rb +57 -30
  319. data/lib/sequel/plugins/typecast_on_load.rb +14 -4
  320. data/lib/sequel/plugins/unlimited_update.rb +3 -7
  321. data/lib/sequel/plugins/update_or_create.rb +6 -4
  322. data/lib/sequel/plugins/update_primary_key.rb +3 -1
  323. data/lib/sequel/plugins/update_refresh.rb +28 -15
  324. data/lib/sequel/plugins/uuid.rb +70 -0
  325. data/lib/sequel/plugins/validate_associated.rb +20 -0
  326. data/lib/sequel/plugins/validation_class_methods.rb +40 -19
  327. data/lib/sequel/plugins/validation_contexts.rb +49 -0
  328. data/lib/sequel/plugins/validation_helpers.rb +49 -31
  329. data/lib/sequel/plugins/whitelist_security.rb +122 -0
  330. data/lib/sequel/plugins/xml_serializer.rb +31 -30
  331. data/lib/sequel/sql.rb +479 -329
  332. data/lib/sequel/timezones.rb +62 -32
  333. data/lib/sequel/version.rb +10 -3
  334. metadata +177 -477
  335. data/Rakefile +0 -165
  336. data/doc/active_record.rdoc +0 -912
  337. data/doc/release_notes/1.0.txt +0 -38
  338. data/doc/release_notes/1.1.txt +0 -143
  339. data/doc/release_notes/1.3.txt +0 -101
  340. data/doc/release_notes/1.4.0.txt +0 -53
  341. data/doc/release_notes/1.5.0.txt +0 -155
  342. data/doc/release_notes/2.0.0.txt +0 -298
  343. data/doc/release_notes/2.1.0.txt +0 -271
  344. data/doc/release_notes/2.10.0.txt +0 -328
  345. data/doc/release_notes/2.11.0.txt +0 -215
  346. data/doc/release_notes/2.12.0.txt +0 -534
  347. data/doc/release_notes/2.2.0.txt +0 -253
  348. data/doc/release_notes/2.3.0.txt +0 -88
  349. data/doc/release_notes/2.4.0.txt +0 -106
  350. data/doc/release_notes/2.5.0.txt +0 -137
  351. data/doc/release_notes/2.6.0.txt +0 -157
  352. data/doc/release_notes/2.7.0.txt +0 -166
  353. data/doc/release_notes/2.8.0.txt +0 -171
  354. data/doc/release_notes/2.9.0.txt +0 -97
  355. data/doc/release_notes/3.0.0.txt +0 -221
  356. data/doc/release_notes/3.1.0.txt +0 -406
  357. data/doc/release_notes/3.10.0.txt +0 -286
  358. data/doc/release_notes/3.11.0.txt +0 -254
  359. data/doc/release_notes/3.12.0.txt +0 -304
  360. data/doc/release_notes/3.13.0.txt +0 -210
  361. data/doc/release_notes/3.14.0.txt +0 -118
  362. data/doc/release_notes/3.15.0.txt +0 -78
  363. data/doc/release_notes/3.16.0.txt +0 -45
  364. data/doc/release_notes/3.17.0.txt +0 -58
  365. data/doc/release_notes/3.18.0.txt +0 -120
  366. data/doc/release_notes/3.19.0.txt +0 -67
  367. data/doc/release_notes/3.2.0.txt +0 -268
  368. data/doc/release_notes/3.20.0.txt +0 -41
  369. data/doc/release_notes/3.21.0.txt +0 -87
  370. data/doc/release_notes/3.22.0.txt +0 -39
  371. data/doc/release_notes/3.23.0.txt +0 -172
  372. data/doc/release_notes/3.24.0.txt +0 -420
  373. data/doc/release_notes/3.25.0.txt +0 -88
  374. data/doc/release_notes/3.26.0.txt +0 -88
  375. data/doc/release_notes/3.27.0.txt +0 -82
  376. data/doc/release_notes/3.28.0.txt +0 -304
  377. data/doc/release_notes/3.29.0.txt +0 -459
  378. data/doc/release_notes/3.3.0.txt +0 -192
  379. data/doc/release_notes/3.30.0.txt +0 -135
  380. data/doc/release_notes/3.31.0.txt +0 -146
  381. data/doc/release_notes/3.32.0.txt +0 -202
  382. data/doc/release_notes/3.33.0.txt +0 -157
  383. data/doc/release_notes/3.34.0.txt +0 -671
  384. data/doc/release_notes/3.35.0.txt +0 -144
  385. data/doc/release_notes/3.36.0.txt +0 -245
  386. data/doc/release_notes/3.37.0.txt +0 -338
  387. data/doc/release_notes/3.38.0.txt +0 -234
  388. data/doc/release_notes/3.39.0.txt +0 -237
  389. data/doc/release_notes/3.4.0.txt +0 -325
  390. data/doc/release_notes/3.40.0.txt +0 -73
  391. data/doc/release_notes/3.41.0.txt +0 -155
  392. data/doc/release_notes/3.42.0.txt +0 -74
  393. data/doc/release_notes/3.43.0.txt +0 -105
  394. data/doc/release_notes/3.44.0.txt +0 -152
  395. data/doc/release_notes/3.45.0.txt +0 -179
  396. data/doc/release_notes/3.46.0.txt +0 -122
  397. data/doc/release_notes/3.47.0.txt +0 -270
  398. data/doc/release_notes/3.48.0.txt +0 -477
  399. data/doc/release_notes/3.5.0.txt +0 -510
  400. data/doc/release_notes/3.6.0.txt +0 -366
  401. data/doc/release_notes/3.7.0.txt +0 -179
  402. data/doc/release_notes/3.8.0.txt +0 -151
  403. data/doc/release_notes/3.9.0.txt +0 -233
  404. data/doc/release_notes/4.0.0.txt +0 -262
  405. data/doc/release_notes/4.1.0.txt +0 -85
  406. data/doc/release_notes/4.10.0.txt +0 -226
  407. data/doc/release_notes/4.11.0.txt +0 -147
  408. data/doc/release_notes/4.12.0.txt +0 -105
  409. data/doc/release_notes/4.13.0.txt +0 -169
  410. data/doc/release_notes/4.14.0.txt +0 -68
  411. data/doc/release_notes/4.15.0.txt +0 -56
  412. data/doc/release_notes/4.16.0.txt +0 -36
  413. data/doc/release_notes/4.17.0.txt +0 -38
  414. data/doc/release_notes/4.18.0.txt +0 -36
  415. data/doc/release_notes/4.19.0.txt +0 -45
  416. data/doc/release_notes/4.2.0.txt +0 -129
  417. data/doc/release_notes/4.20.0.txt +0 -79
  418. data/doc/release_notes/4.21.0.txt +0 -94
  419. data/doc/release_notes/4.22.0.txt +0 -72
  420. data/doc/release_notes/4.23.0.txt +0 -65
  421. data/doc/release_notes/4.24.0.txt +0 -99
  422. data/doc/release_notes/4.25.0.txt +0 -181
  423. data/doc/release_notes/4.26.0.txt +0 -44
  424. data/doc/release_notes/4.3.0.txt +0 -40
  425. data/doc/release_notes/4.4.0.txt +0 -92
  426. data/doc/release_notes/4.5.0.txt +0 -34
  427. data/doc/release_notes/4.6.0.txt +0 -30
  428. data/doc/release_notes/4.7.0.txt +0 -103
  429. data/doc/release_notes/4.8.0.txt +0 -175
  430. data/doc/release_notes/4.9.0.txt +0 -190
  431. data/lib/sequel/adapters/cubrid.rb +0 -142
  432. data/lib/sequel/adapters/do.rb +0 -156
  433. data/lib/sequel/adapters/do/mysql.rb +0 -64
  434. data/lib/sequel/adapters/do/postgres.rb +0 -42
  435. data/lib/sequel/adapters/do/sqlite3.rb +0 -40
  436. data/lib/sequel/adapters/jdbc/as400.rb +0 -82
  437. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -62
  438. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -34
  439. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -31
  440. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -31
  441. data/lib/sequel/adapters/odbc/progress.rb +0 -8
  442. data/lib/sequel/adapters/shared/cubrid.rb +0 -243
  443. data/lib/sequel/adapters/shared/firebird.rb +0 -245
  444. data/lib/sequel/adapters/shared/informix.rb +0 -52
  445. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -150
  446. data/lib/sequel/adapters/shared/progress.rb +0 -38
  447. data/lib/sequel/adapters/swift.rb +0 -158
  448. data/lib/sequel/adapters/swift/mysql.rb +0 -47
  449. data/lib/sequel/adapters/swift/postgres.rb +0 -45
  450. data/lib/sequel/adapters/swift/sqlite.rb +0 -47
  451. data/lib/sequel/adapters/utils/pg_types.rb +0 -68
  452. data/lib/sequel/dataset/mutation.rb +0 -109
  453. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -3
  454. data/lib/sequel/extensions/filter_having.rb +0 -59
  455. data/lib/sequel/extensions/hash_aliases.rb +0 -45
  456. data/lib/sequel/extensions/meta_def.rb +0 -31
  457. data/lib/sequel/extensions/query_literals.rb +0 -80
  458. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -22
  459. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -118
  460. data/lib/sequel/extensions/set_overrides.rb +0 -72
  461. data/lib/sequel/no_core_ext.rb +0 -1
  462. data/lib/sequel/plugins/association_autoreloading.rb +0 -7
  463. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -7
  464. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -78
  465. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -117
  466. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -59
  467. data/lib/sequel/plugins/schema.rb +0 -80
  468. data/lib/sequel/plugins/scissors.rb +0 -33
  469. data/spec/adapters/db2_spec.rb +0 -160
  470. data/spec/adapters/firebird_spec.rb +0 -411
  471. data/spec/adapters/informix_spec.rb +0 -100
  472. data/spec/adapters/mssql_spec.rb +0 -706
  473. data/spec/adapters/mysql_spec.rb +0 -1287
  474. data/spec/adapters/oracle_spec.rb +0 -313
  475. data/spec/adapters/postgres_spec.rb +0 -3725
  476. data/spec/adapters/spec_helper.rb +0 -43
  477. data/spec/adapters/sqlanywhere_spec.rb +0 -170
  478. data/spec/adapters/sqlite_spec.rb +0 -653
  479. data/spec/bin_spec.rb +0 -254
  480. data/spec/core/connection_pool_spec.rb +0 -1016
  481. data/spec/core/database_spec.rb +0 -2531
  482. data/spec/core/dataset_spec.rb +0 -5098
  483. data/spec/core/deprecated_spec.rb +0 -70
  484. data/spec/core/expression_filters_spec.rb +0 -1243
  485. data/spec/core/mock_adapter_spec.rb +0 -462
  486. data/spec/core/object_graph_spec.rb +0 -303
  487. data/spec/core/placeholder_literalizer_spec.rb +0 -163
  488. data/spec/core/schema_generator_spec.rb +0 -179
  489. data/spec/core/schema_spec.rb +0 -1659
  490. data/spec/core/spec_helper.rb +0 -34
  491. data/spec/core/version_spec.rb +0 -7
  492. data/spec/core_extensions_spec.rb +0 -699
  493. data/spec/extensions/accessed_columns_spec.rb +0 -51
  494. data/spec/extensions/active_model_spec.rb +0 -123
  495. data/spec/extensions/after_initialize_spec.rb +0 -24
  496. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  497. data/spec/extensions/association_dependencies_spec.rb +0 -117
  498. data/spec/extensions/association_pks_spec.rb +0 -365
  499. data/spec/extensions/association_proxies_spec.rb +0 -86
  500. data/spec/extensions/auto_validations_spec.rb +0 -192
  501. data/spec/extensions/blacklist_security_spec.rb +0 -88
  502. data/spec/extensions/blank_spec.rb +0 -69
  503. data/spec/extensions/boolean_readers_spec.rb +0 -93
  504. data/spec/extensions/caching_spec.rb +0 -270
  505. data/spec/extensions/class_table_inheritance_spec.rb +0 -420
  506. data/spec/extensions/column_conflicts_spec.rb +0 -60
  507. data/spec/extensions/column_select_spec.rb +0 -108
  508. data/spec/extensions/columns_introspection_spec.rb +0 -91
  509. data/spec/extensions/composition_spec.rb +0 -242
  510. data/spec/extensions/connection_validator_spec.rb +0 -120
  511. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -274
  512. data/spec/extensions/constraint_validations_spec.rb +0 -325
  513. data/spec/extensions/core_refinements_spec.rb +0 -519
  514. data/spec/extensions/csv_serializer_spec.rb +0 -173
  515. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  516. data/spec/extensions/dataset_associations_spec.rb +0 -311
  517. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  518. data/spec/extensions/date_arithmetic_spec.rb +0 -150
  519. data/spec/extensions/defaults_setter_spec.rb +0 -101
  520. data/spec/extensions/delay_add_association_spec.rb +0 -52
  521. data/spec/extensions/dirty_spec.rb +0 -180
  522. data/spec/extensions/eager_each_spec.rb +0 -42
  523. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  524. data/spec/extensions/error_splitter_spec.rb +0 -18
  525. data/spec/extensions/error_sql_spec.rb +0 -20
  526. data/spec/extensions/eval_inspect_spec.rb +0 -73
  527. data/spec/extensions/filter_having_spec.rb +0 -40
  528. data/spec/extensions/force_encoding_spec.rb +0 -114
  529. data/spec/extensions/from_block_spec.rb +0 -21
  530. data/spec/extensions/graph_each_spec.rb +0 -109
  531. data/spec/extensions/hash_aliases_spec.rb +0 -24
  532. data/spec/extensions/hook_class_methods_spec.rb +0 -429
  533. data/spec/extensions/inflector_spec.rb +0 -183
  534. data/spec/extensions/input_transformer_spec.rb +0 -54
  535. data/spec/extensions/insert_returning_select_spec.rb +0 -46
  536. data/spec/extensions/instance_filters_spec.rb +0 -79
  537. data/spec/extensions/instance_hooks_spec.rb +0 -276
  538. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  539. data/spec/extensions/json_serializer_spec.rb +0 -291
  540. data/spec/extensions/lazy_attributes_spec.rb +0 -170
  541. data/spec/extensions/list_spec.rb +0 -267
  542. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  543. data/spec/extensions/many_through_many_spec.rb +0 -2172
  544. data/spec/extensions/meta_def_spec.rb +0 -21
  545. data/spec/extensions/migration_spec.rb +0 -712
  546. data/spec/extensions/modification_detection_spec.rb +0 -80
  547. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
  548. data/spec/extensions/named_timezones_spec.rb +0 -108
  549. data/spec/extensions/nested_attributes_spec.rb +0 -697
  550. data/spec/extensions/null_dataset_spec.rb +0 -85
  551. data/spec/extensions/optimistic_locking_spec.rb +0 -128
  552. data/spec/extensions/pagination_spec.rb +0 -118
  553. data/spec/extensions/pg_array_associations_spec.rb +0 -736
  554. data/spec/extensions/pg_array_ops_spec.rb +0 -143
  555. data/spec/extensions/pg_array_spec.rb +0 -395
  556. data/spec/extensions/pg_enum_spec.rb +0 -92
  557. data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
  558. data/spec/extensions/pg_hstore_spec.rb +0 -206
  559. data/spec/extensions/pg_inet_ops_spec.rb +0 -101
  560. data/spec/extensions/pg_inet_spec.rb +0 -52
  561. data/spec/extensions/pg_interval_spec.rb +0 -76
  562. data/spec/extensions/pg_json_ops_spec.rb +0 -229
  563. data/spec/extensions/pg_json_spec.rb +0 -218
  564. data/spec/extensions/pg_loose_count_spec.rb +0 -17
  565. data/spec/extensions/pg_range_ops_spec.rb +0 -58
  566. data/spec/extensions/pg_range_spec.rb +0 -404
  567. data/spec/extensions/pg_row_ops_spec.rb +0 -60
  568. data/spec/extensions/pg_row_plugin_spec.rb +0 -62
  569. data/spec/extensions/pg_row_spec.rb +0 -360
  570. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
  571. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
  572. data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
  573. data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
  574. data/spec/extensions/prepared_statements_spec.rb +0 -103
  575. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
  576. data/spec/extensions/pretty_table_spec.rb +0 -92
  577. data/spec/extensions/query_literals_spec.rb +0 -183
  578. data/spec/extensions/query_spec.rb +0 -102
  579. data/spec/extensions/rcte_tree_spec.rb +0 -392
  580. data/spec/extensions/round_timestamps_spec.rb +0 -43
  581. data/spec/extensions/schema_caching_spec.rb +0 -41
  582. data/spec/extensions/schema_dumper_spec.rb +0 -789
  583. data/spec/extensions/schema_spec.rb +0 -117
  584. data/spec/extensions/scissors_spec.rb +0 -26
  585. data/spec/extensions/select_remove_spec.rb +0 -38
  586. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
  587. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  588. data/spec/extensions/serialization_spec.rb +0 -362
  589. data/spec/extensions/server_block_spec.rb +0 -90
  590. data/spec/extensions/set_overrides_spec.rb +0 -61
  591. data/spec/extensions/sharding_spec.rb +0 -198
  592. data/spec/extensions/shared_caching_spec.rb +0 -175
  593. data/spec/extensions/single_table_inheritance_spec.rb +0 -297
  594. data/spec/extensions/singular_table_names_spec.rb +0 -22
  595. data/spec/extensions/skip_create_refresh_spec.rb +0 -17
  596. data/spec/extensions/spec_helper.rb +0 -71
  597. data/spec/extensions/split_array_nil_spec.rb +0 -24
  598. data/spec/extensions/split_values_spec.rb +0 -22
  599. data/spec/extensions/sql_expr_spec.rb +0 -60
  600. data/spec/extensions/static_cache_spec.rb +0 -361
  601. data/spec/extensions/string_date_time_spec.rb +0 -95
  602. data/spec/extensions/string_stripper_spec.rb +0 -68
  603. data/spec/extensions/subclasses_spec.rb +0 -66
  604. data/spec/extensions/table_select_spec.rb +0 -71
  605. data/spec/extensions/tactical_eager_loading_spec.rb +0 -82
  606. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  607. data/spec/extensions/timestamps_spec.rb +0 -175
  608. data/spec/extensions/to_dot_spec.rb +0 -154
  609. data/spec/extensions/touch_spec.rb +0 -203
  610. data/spec/extensions/tree_spec.rb +0 -274
  611. data/spec/extensions/typecast_on_load_spec.rb +0 -80
  612. data/spec/extensions/unlimited_update_spec.rb +0 -20
  613. data/spec/extensions/update_or_create_spec.rb +0 -87
  614. data/spec/extensions/update_primary_key_spec.rb +0 -100
  615. data/spec/extensions/update_refresh_spec.rb +0 -53
  616. data/spec/extensions/validate_associated_spec.rb +0 -52
  617. data/spec/extensions/validation_class_methods_spec.rb +0 -1027
  618. data/spec/extensions/validation_helpers_spec.rb +0 -541
  619. data/spec/extensions/xml_serializer_spec.rb +0 -207
  620. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  621. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  622. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  623. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  624. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  625. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  626. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  627. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  628. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  629. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  630. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  631. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  632. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  633. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  634. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  635. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  636. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  637. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  638. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  639. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  640. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  641. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  642. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  643. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  644. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  645. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  646. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  647. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  648. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  649. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  650. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  651. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  652. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  653. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  654. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  655. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  656. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  657. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  658. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  659. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  660. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  661. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  662. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  663. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  664. data/spec/guards_helper.rb +0 -55
  665. data/spec/integration/associations_test.rb +0 -2454
  666. data/spec/integration/database_test.rb +0 -113
  667. data/spec/integration/dataset_test.rb +0 -1808
  668. data/spec/integration/eager_loader_test.rb +0 -687
  669. data/spec/integration/migrator_test.rb +0 -240
  670. data/spec/integration/model_test.rb +0 -226
  671. data/spec/integration/plugin_test.rb +0 -2240
  672. data/spec/integration/prepared_statement_test.rb +0 -467
  673. data/spec/integration/schema_test.rb +0 -817
  674. data/spec/integration/spec_helper.rb +0 -48
  675. data/spec/integration/timezone_test.rb +0 -86
  676. data/spec/integration/transaction_test.rb +0 -374
  677. data/spec/integration/type_test.rb +0 -133
  678. data/spec/model/association_reflection_spec.rb +0 -525
  679. data/spec/model/associations_spec.rb +0 -4426
  680. data/spec/model/base_spec.rb +0 -759
  681. data/spec/model/class_dataset_methods_spec.rb +0 -146
  682. data/spec/model/dataset_methods_spec.rb +0 -149
  683. data/spec/model/eager_loading_spec.rb +0 -2137
  684. data/spec/model/hooks_spec.rb +0 -604
  685. data/spec/model/inflector_spec.rb +0 -26
  686. data/spec/model/model_spec.rb +0 -982
  687. data/spec/model/plugins_spec.rb +0 -299
  688. data/spec/model/record_spec.rb +0 -2147
  689. data/spec/model/spec_helper.rb +0 -46
  690. data/spec/model/validations_spec.rb +0 -193
  691. data/spec/sequel_coverage.rb +0 -15
  692. data/spec/spec_config.rb +0 -10
@@ -1,3 +1,5 @@
1
+ # frozen-string-literal: true
2
+
1
3
  module Sequel
2
4
  class Dataset
3
5
  # ---------------------
@@ -10,30 +12,31 @@ module Sequel
10
12
  # in the extension).
11
13
  EXTENSIONS = {}
12
14
 
13
- # The dataset options that require the removal of cached columns
14
- # if changed.
15
+ EMPTY_ARRAY = [].freeze
16
+
17
+ # The dataset options that require the removal of cached columns if changed.
15
18
  COLUMN_CHANGE_OPTS = [:select, :sql, :from, :join].freeze
16
19
 
17
20
  # Which options don't affect the SQL generation. Used by simple_select_all?
18
21
  # to determine if this is a simple SELECT * FROM table.
19
- NON_SQL_OPTIONS = [:server, :defaults, :overrides, :graph, :eager, :eager_graph, :graph_aliases]
22
+ NON_SQL_OPTIONS = [:server, :graph, :row_proc, :quote_identifiers, :skip_symbol_cache].freeze
20
23
 
21
24
  # These symbols have _join methods created (e.g. inner_join) that
22
25
  # call join_table with the symbol, passing along the arguments and
23
26
  # block from the method call.
24
- CONDITIONED_JOIN_TYPES = [:inner, :full_outer, :right_outer, :left_outer, :full, :right, :left]
27
+ CONDITIONED_JOIN_TYPES = [:inner, :full_outer, :right_outer, :left_outer, :full, :right, :left].freeze
25
28
 
26
29
  # These symbols have _join methods created (e.g. natural_join).
27
30
  # They accept a table argument and options hash which is passed to join_table,
28
31
  # and they raise an error if called with a block.
29
- UNCONDITIONED_JOIN_TYPES = [:natural, :natural_left, :natural_right, :natural_full, :cross]
32
+ UNCONDITIONED_JOIN_TYPES = [:natural, :natural_left, :natural_right, :natural_full, :cross].freeze
30
33
 
31
34
  # All methods that return modified datasets with a joined table added.
32
- JOIN_METHODS = (CONDITIONED_JOIN_TYPES + UNCONDITIONED_JOIN_TYPES).map{|x| "#{x}_join".to_sym} + [:join, :join_table]
35
+ JOIN_METHODS = ((CONDITIONED_JOIN_TYPES + UNCONDITIONED_JOIN_TYPES).map{|x| "#{x}_join".to_sym} + [:join, :join_table]).freeze
33
36
 
34
37
  # Methods that return modified datasets
35
- QUERY_METHODS = (<<-METHS).split.map(&:to_sym) + JOIN_METHODS
36
- add_graph_aliases and distinct except exclude exclude_having exclude_where
38
+ QUERY_METHODS = ((<<-METHS).split.map(&:to_sym) + JOIN_METHODS).freeze
39
+ add_graph_aliases distinct except exclude exclude_having
37
40
  filter for_update from from_self graph grep group group_and_count group_append group_by having intersect invert
38
41
  limit lock_style naked offset or order order_append order_by order_more order_prepend qualify
39
42
  reverse reverse_order select select_all select_append select_group select_more server
@@ -62,24 +65,44 @@ module Sequel
62
65
  Sequel.synchronize{EXTENSIONS[ext] = block}
63
66
  end
64
67
 
65
- # Alias for where.
66
- def and(*cond, &block)
67
- where(*cond, &block)
68
- end
69
-
70
- # Returns a new clone of the dataset with the given options merged.
71
- # If the options changed include options in COLUMN_CHANGE_OPTS, the cached
72
- # columns are deleted. This method should generally not be called
73
- # directly by user code.
74
- def clone(opts = nil)
75
- c = super()
76
- if opts
77
- c.instance_variable_set(:@opts, Hash[@opts].merge!(opts))
78
- c.instance_variable_set(:@columns, nil) if @columns && !opts.each_key{|o| break if COLUMN_CHANGE_OPTS.include?(o)}
79
- else
80
- c.instance_variable_set(:@opts, Hash[@opts])
68
+ # On Ruby 2.4+, use clone(:freeze=>false) to create clones, because
69
+ # we use true freezing in that case, and we need to modify the opts
70
+ # in the frozen copy.
71
+ #
72
+ # On Ruby <2.4, just use Object#clone directly, since we don't
73
+ # use true freezing as it isn't possible.
74
+ if TRUE_FREEZE
75
+ # Save original clone implementation, as some other methods need
76
+ # to call it internally.
77
+ alias _clone clone
78
+ private :_clone
79
+
80
+ # Returns a new clone of the dataset with the given options merged.
81
+ # If the options changed include options in COLUMN_CHANGE_OPTS, the cached
82
+ # columns are deleted. This method should generally not be called
83
+ # directly by user code.
84
+ def clone(opts = nil || (return self))
85
+ # return self used above because clone is called by almost all
86
+ # other query methods, and it is the fastest approach
87
+ c = super(:freeze=>false)
88
+ c.opts.merge!(opts)
89
+ unless opts.each_key{|o| break if COLUMN_CHANGE_OPTS.include?(o)}
90
+ c.clear_columns_cache
91
+ end
92
+ c.freeze
93
+ end
94
+ else
95
+ # :nocov:
96
+ def clone(opts = OPTS) # :nodoc:
97
+ c = super()
98
+ c.opts.merge!(opts)
99
+ unless opts.each_key{|o| break if COLUMN_CHANGE_OPTS.include?(o)}
100
+ c.clear_columns_cache
101
+ end
102
+ c.opts.freeze
103
+ c
81
104
  end
82
- c
105
+ # :nocov:
83
106
  end
84
107
 
85
108
  # Returns a copy of the dataset with the SQL DISTINCT clause. The DISTINCT
@@ -92,10 +115,19 @@ module Sequel
92
115
  # DB[:items].distinct # SQL: SELECT DISTINCT * FROM items
93
116
  # DB[:items].order(:id).distinct(:id) # SQL: SELECT DISTINCT ON (id) * FROM items ORDER BY id
94
117
  # DB[:items].order(:id).distinct{func(:id)} # SQL: SELECT DISTINCT ON (func(id)) * FROM items ORDER BY id
118
+ #
119
+ # There is support for emualting the DISTINCT ON support in MySQL, but it
120
+ # does not support the ORDER of the dataset, and also doesn't work in many
121
+ # cases if the ONLY_FULL_GROUP_BY sql_mode is used, which is the default on
122
+ # MySQL 5.7.5+.
95
123
  def distinct(*args, &block)
96
124
  virtual_row_columns(args, block)
97
- raise(InvalidOperation, "DISTINCT ON not supported") if !args.empty? && !supports_distinct_on?
98
- clone(:distinct => args)
125
+ if args.empty?
126
+ cached_dataset(:_distinct_ds){clone(:distinct => EMPTY_ARRAY)}
127
+ else
128
+ raise(InvalidOperation, "DISTINCT ON not supported") unless supports_distinct_on?
129
+ clone(:distinct => args.freeze)
130
+ end
99
131
  end
100
132
 
101
133
  # Adds an EXCEPT clause using a second dataset object.
@@ -110,10 +142,10 @@ module Sequel
110
142
  # DB[:items].except(DB[:other_items])
111
143
  # # SELECT * FROM (SELECT * FROM items EXCEPT SELECT * FROM other_items) AS t1
112
144
  #
113
- # DB[:items].except(DB[:other_items], :all=>true, :from_self=>false)
145
+ # DB[:items].except(DB[:other_items], all: true, from_self: false)
114
146
  # # SELECT * FROM items EXCEPT ALL SELECT * FROM other_items
115
147
  #
116
- # DB[:items].except(DB[:other_items], :alias=>:i)
148
+ # DB[:items].except(DB[:other_items], alias: :i)
117
149
  # # SELECT * FROM (SELECT * FROM items EXCEPT SELECT * FROM other_items) AS i
118
150
  def except(dataset, opts=OPTS)
119
151
  raise(InvalidOperation, "EXCEPT not supported") unless supports_intersect_except?
@@ -124,31 +156,59 @@ module Sequel
124
156
  # Performs the inverse of Dataset#where. Note that if you have multiple filter
125
157
  # conditions, this is not the same as a negation of all conditions.
126
158
  #
127
- # DB[:items].exclude(:category => 'software')
159
+ # DB[:items].exclude(category: 'software')
128
160
  # # SELECT * FROM items WHERE (category != 'software')
129
161
  #
130
- # DB[:items].exclude(:category => 'software', :id=>3)
162
+ # DB[:items].exclude(category: 'software', id: 3)
131
163
  # # SELECT * FROM items WHERE ((category != 'software') OR (id != 3))
164
+ #
165
+ # Also note that SQL uses 3-valued boolean logic (+true+, +false+, +NULL+), so
166
+ # the inverse of a true condition is a false condition, and will still
167
+ # not match rows that were NULL originally. If you take the earlier
168
+ # example:
169
+ #
170
+ # DB[:items].exclude(category: 'software')
171
+ # # SELECT * FROM items WHERE (category != 'software')
172
+ #
173
+ # Note that this does not match rows where +category+ is +NULL+. This
174
+ # is because +NULL+ is an unknown value, and you do not know whether
175
+ # or not the +NULL+ category is +software+. You can explicitly
176
+ # specify how to handle +NULL+ values if you want:
177
+ #
178
+ # DB[:items].exclude(Sequel.~(category: nil) & {category: 'software'})
179
+ # # SELECT * FROM items WHERE ((category IS NULL) OR (category != 'software'))
132
180
  def exclude(*cond, &block)
133
- _filter_or_exclude(true, :where, *cond, &block)
181
+ add_filter(:where, cond, true, &block)
134
182
  end
135
183
 
136
184
  # Inverts the given conditions and adds them to the HAVING clause.
137
185
  #
138
186
  # DB[:items].select_group(:name).exclude_having{count(name) < 2}
139
187
  # # SELECT name FROM items GROUP BY name HAVING (count(name) >= 2)
188
+ #
189
+ # See documentation for exclude for how inversion is handled in regards
190
+ # to SQL 3-valued boolean logic.
140
191
  def exclude_having(*cond, &block)
141
- _filter_or_exclude(true, :having, *cond, &block)
142
- end
143
-
144
- # Alias for exclude.
145
- def exclude_where(*cond, &block)
146
- exclude(*cond, &block)
192
+ add_filter(:having, cond, true, &block)
147
193
  end
148
194
 
149
- # Return a clone of the dataset loaded with the extensions, see #extension!.
150
- def extension(*exts)
151
- clone.extension!(*exts)
195
+ if TRUE_FREEZE
196
+ # Return a clone of the dataset loaded with the given dataset extensions.
197
+ # If no related extension file exists or the extension does not have
198
+ # specific support for Dataset objects, an Error will be raised.
199
+ def extension(*a)
200
+ c = _clone(:freeze=>false)
201
+ c.send(:_extension!, a)
202
+ c.freeze
203
+ end
204
+ else
205
+ # :nocov:
206
+ def extension(*exts) # :nodoc:
207
+ c = clone
208
+ c.send(:_extension!, exts)
209
+ c
210
+ end
211
+ # :nocov:
152
212
  end
153
213
 
154
214
  # Alias for where.
@@ -160,7 +220,7 @@ module Sequel
160
220
  #
161
221
  # DB[:table].for_update # SELECT * FROM table FOR UPDATE
162
222
  def for_update
163
- lock_style(:update)
223
+ cached_dataset(:_for_update_ds){lock_style(:update)}
164
224
  end
165
225
 
166
226
  # Returns a copy of the dataset with the source changed. If no
@@ -197,14 +257,17 @@ module Sequel
197
257
  s
198
258
  end
199
259
  end
200
- o = {:from=>source.empty? ? nil : source}
201
- o[:with] = (opts[:with] || []) + ctes if ctes
260
+ o = {:from=>source.empty? ? nil : source.freeze}
261
+ o[:with] = ((opts[:with] || EMPTY_ARRAY) + ctes).freeze if ctes
202
262
  o[:num_dataset_sources] = table_alias_num if table_alias_num > 0
203
263
  clone(o)
204
264
  end
205
265
 
206
266
  # Returns a dataset selecting from the current dataset.
207
- # Supplying the :alias option controls the alias of the result.
267
+ # Options:
268
+ # :alias :: Controls the alias of the table
269
+ # :column_aliases :: Also aliases columns, using derived column lists.
270
+ # Only used in conjunction with :alias.
208
271
  #
209
272
  # ds = DB[:items].order(:name).select(:id, :name)
210
273
  # # SELECT id,name FROM items ORDER BY name
@@ -212,21 +275,29 @@ module Sequel
212
275
  # ds.from_self
213
276
  # # SELECT * FROM (SELECT id, name FROM items ORDER BY name) AS t1
214
277
  #
215
- # ds.from_self(:alias=>:foo)
278
+ # ds.from_self(alias: :foo)
216
279
  # # SELECT * FROM (SELECT id, name FROM items ORDER BY name) AS foo
217
280
  #
218
- # ds.from_self(:alias=>:foo, :column_aliases=>[:c1, :c2])
281
+ # ds.from_self(alias: :foo, column_aliases: [:c1, :c2])
219
282
  # # SELECT * FROM (SELECT id, name FROM items ORDER BY name) AS foo(c1, c2)
220
283
  def from_self(opts=OPTS)
221
284
  fs = {}
222
- @opts.keys.each{|k| fs[k] = nil unless NON_SQL_OPTIONS.include?(k)}
223
- clone(fs).from(opts[:alias] ? as(opts[:alias], opts[:column_aliases]) : self)
285
+ @opts.keys.each{|k| fs[k] = nil unless non_sql_option?(k)}
286
+ pr = proc do
287
+ c = clone(fs).from(opts[:alias] ? as(opts[:alias], opts[:column_aliases]) : self)
288
+ if cols = _columns
289
+ c.send(:columns=, cols)
290
+ end
291
+ c
292
+ end
293
+
294
+ opts.empty? ? cached_dataset(:_from_self_ds, &pr) : pr.call
224
295
  end
225
296
 
226
297
  # Match any of the columns to any of the patterns. The terms can be
227
- # strings (which use LIKE) or regular expressions (which are only
228
- # supported on MySQL and PostgreSQL). Note that the total number of
229
- # pattern matches will be Array(columns).length * Array(terms).length,
298
+ # strings (which use LIKE) or regular expressions if the database supports that.
299
+ # Note that the total number of pattern matches will be
300
+ # Array(columns).length * Array(terms).length,
230
301
  # which could cause performance issues.
231
302
  #
232
303
  # Options (all are boolean):
@@ -247,28 +318,29 @@ module Sequel
247
318
  # # SELECT * FROM items WHERE ((a LIKE '%test%' ESCAPE '\') OR (a LIKE 'foo' ESCAPE '\')
248
319
  # # OR (b LIKE '%test%' ESCAPE '\') OR (b LIKE 'foo' ESCAPE '\'))
249
320
  #
250
- # dataset.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true)
321
+ # dataset.grep([:a, :b], %w'%foo% %bar%', all_patterns: true)
251
322
  # # SELECT * FROM a WHERE (((a LIKE '%foo%' ESCAPE '\') OR (b LIKE '%foo%' ESCAPE '\'))
252
323
  # # AND ((a LIKE '%bar%' ESCAPE '\') OR (b LIKE '%bar%' ESCAPE '\')))
253
324
  #
254
- # dataset.grep([:a, :b], %w'%foo% %bar%', :all_columns=>true)
325
+ # dataset.grep([:a, :b], %w'%foo% %bar%', all_columns: true)
255
326
  # # SELECT * FROM a WHERE (((a LIKE '%foo%' ESCAPE '\') OR (a LIKE '%bar%' ESCAPE '\'))
256
327
  # # AND ((b LIKE '%foo%' ESCAPE '\') OR (b LIKE '%bar%' ESCAPE '\')))
257
328
  #
258
- # dataset.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true, :all_columns=>true)
329
+ # dataset.grep([:a, :b], %w'%foo% %bar%', all_patterns: true, all_columns: true)
259
330
  # # SELECT * FROM a WHERE ((a LIKE '%foo%' ESCAPE '\') AND (b LIKE '%foo%' ESCAPE '\')
260
331
  # # AND (a LIKE '%bar%' ESCAPE '\') AND (b LIKE '%bar%' ESCAPE '\'))
261
332
  def grep(columns, patterns, opts=OPTS)
333
+ column_op = opts[:all_columns] ? :AND : :OR
262
334
  if opts[:all_patterns]
263
335
  conds = Array(patterns).map do |pat|
264
- SQL::BooleanExpression.new(opts[:all_columns] ? :AND : :OR, *Array(columns).map{|c| SQL::StringExpression.like(c, pat, opts)})
336
+ SQL::BooleanExpression.new(column_op, *Array(columns).map{|c| SQL::StringExpression.like(c, pat, opts)})
265
337
  end
266
- where(SQL::BooleanExpression.new(opts[:all_patterns] ? :AND : :OR, *conds))
338
+ where(SQL::BooleanExpression.new(:AND, *conds))
267
339
  else
268
340
  conds = Array(columns).map do |c|
269
341
  SQL::BooleanExpression.new(:OR, *Array(patterns).map{|pat| SQL::StringExpression.like(c, pat, opts)})
270
342
  end
271
- where(SQL::BooleanExpression.new(opts[:all_columns] ? :AND : :OR, *conds))
343
+ where(SQL::BooleanExpression.new(column_op, *conds))
272
344
  end
273
345
  end
274
346
 
@@ -281,7 +353,7 @@ module Sequel
281
353
  # DB[:items].group{[a, sum(b)]} # SELECT * FROM items GROUP BY a, sum(b)
282
354
  def group(*columns, &block)
283
355
  virtual_row_columns(columns, block)
284
- clone(:group => (columns.compact.empty? ? nil : columns))
356
+ clone(:group => (columns.compact.empty? ? nil : columns.freeze))
285
357
  end
286
358
 
287
359
  # Alias of group
@@ -303,15 +375,15 @@ module Sequel
303
375
  # # SELECT first_name, last_name, count(*) AS count FROM items GROUP BY first_name, last_name
304
376
  # # => [{:first_name=>'a', :last_name=>'b', :count=>1}, ...]
305
377
  #
306
- # DB[:items].group_and_count(:first_name___name).all
378
+ # DB[:items].group_and_count(Sequel[:first_name].as(:name)).all
307
379
  # # SELECT first_name AS name, count(*) AS count FROM items GROUP BY first_name
308
380
  # # => [{:name=>'a', :count=>1}, ...]
309
381
  #
310
- # DB[:items].group_and_count{substr(first_name, 1, 1).as(initial)}.all
382
+ # DB[:items].group_and_count{substr(:first_name, 1, 1).as(:initial)}.all
311
383
  # # SELECT substr(first_name, 1, 1) AS initial, count(*) AS count FROM items GROUP BY substr(first_name, 1, 1)
312
384
  # # => [{:initial=>'a', :count=>1}, ...]
313
385
  def group_and_count(*columns, &block)
314
- select_group(*columns, &block).select_more(COUNT_OF_ALL_AS_COUNT)
386
+ select_group(*columns, &block).select_append(COUNT_OF_ALL_AS_COUNT)
315
387
  end
316
388
 
317
389
  # Returns a copy of the dataset with the given columns added to the list of
@@ -345,10 +417,10 @@ module Sequel
345
417
 
346
418
  # Returns a copy of the dataset with the HAVING conditions changed. See #where for argument types.
347
419
  #
348
- # DB[:items].group(:sum).having(:sum=>10)
420
+ # DB[:items].group(:sum).having(sum: 10)
349
421
  # # SELECT * FROM items GROUP BY sum HAVING (sum = 10)
350
422
  def having(*cond, &block)
351
- _filter(:having, *cond, &block)
423
+ add_filter(:having, cond, &block)
352
424
  end
353
425
 
354
426
  # Adds an INTERSECT clause using a second dataset object.
@@ -363,10 +435,10 @@ module Sequel
363
435
  # DB[:items].intersect(DB[:other_items])
364
436
  # # SELECT * FROM (SELECT * FROM items INTERSECT SELECT * FROM other_items) AS t1
365
437
  #
366
- # DB[:items].intersect(DB[:other_items], :all=>true, :from_self=>false)
438
+ # DB[:items].intersect(DB[:other_items], all: true, from_self: false)
367
439
  # # SELECT * FROM items INTERSECT ALL SELECT * FROM other_items
368
440
  #
369
- # DB[:items].intersect(DB[:other_items], :alias=>:i)
441
+ # DB[:items].intersect(DB[:other_items], alias: :i)
370
442
  # # SELECT * FROM (SELECT * FROM items INTERSECT SELECT * FROM other_items) AS i
371
443
  def intersect(dataset, opts=OPTS)
372
444
  raise(InvalidOperation, "INTERSECT not supported") unless supports_intersect_except?
@@ -377,20 +449,25 @@ module Sequel
377
449
  # Inverts the current WHERE and HAVING clauses. If there is neither a
378
450
  # WHERE or HAVING clause, adds a WHERE clause that is always false.
379
451
  #
380
- # DB[:items].where(:category => 'software').invert
452
+ # DB[:items].where(category: 'software').invert
381
453
  # # SELECT * FROM items WHERE (category != 'software')
382
454
  #
383
- # DB[:items].where(:category => 'software', :id=>3).invert
455
+ # DB[:items].where(category: 'software', id: 3).invert
384
456
  # # SELECT * FROM items WHERE ((category != 'software') OR (id != 3))
457
+ #
458
+ # See documentation for exclude for how inversion is handled in regards
459
+ # to SQL 3-valued boolean logic.
385
460
  def invert
386
- having, where = @opts.values_at(:having, :where)
387
- if having.nil? && where.nil?
388
- where(false)
389
- else
390
- o = {}
391
- o[:having] = SQL::BooleanExpression.invert(having) if having
392
- o[:where] = SQL::BooleanExpression.invert(where) if where
393
- clone(o)
461
+ cached_dataset(:_invert_ds) do
462
+ having, where = @opts.values_at(:having, :where)
463
+ if having.nil? && where.nil?
464
+ where(false)
465
+ else
466
+ o = {}
467
+ o[:having] = SQL::BooleanExpression.invert(having) if having
468
+ o[:where] = SQL::BooleanExpression.invert(where) if where
469
+ clone(o)
470
+ end
394
471
  end
395
472
  end
396
473
 
@@ -447,10 +524,10 @@ module Sequel
447
524
  # DB[:a].join_table(:cross, :b)
448
525
  # # SELECT * FROM a CROSS JOIN b
449
526
  #
450
- # DB[:a].join_table(:inner, DB[:b], :c=>d)
527
+ # DB[:a].join_table(:inner, DB[:b], c: d)
451
528
  # # SELECT * FROM a INNER JOIN (SELECT * FROM b) AS t1 ON (t1.c = a.d)
452
529
  #
453
- # DB[:a].join_table(:left, :b___c, [:d])
530
+ # DB[:a].join_table(:left, Sequel[:b].as(:c), [:d])
454
531
  # # SELECT * FROM a LEFT JOIN b AS c USING (d)
455
532
  #
456
533
  # DB[:a].natural_join(:b).join_table(:inner, :c) do |ta, jta, js|
@@ -472,8 +549,6 @@ module Sequel
472
549
  end
473
550
 
474
551
  table_alias = options[:table_alias]
475
- last_alias = options[:implicit_qualifier]
476
- qualify_type = options[:qualify]
477
552
 
478
553
  if table.is_a?(SQL::AliasedExpression)
479
554
  table_expr = if table_alias
@@ -503,16 +578,17 @@ module Sequel
503
578
  raise(Sequel::Error, "can't use a block if providing an array of symbols as expr") if block
504
579
  SQL::JoinUsingClause.new(expr, type, table_expr)
505
580
  else
506
- last_alias ||= @opts[:last_joined_table] || first_source_alias
581
+ last_alias = options[:implicit_qualifier] || @opts[:last_joined_table] || first_source_alias
582
+ qualify_type = options[:qualify]
507
583
  if Sequel.condition_specifier?(expr)
508
- expr = expr.collect do |k, v|
584
+ expr = expr.map do |k, v|
509
585
  qualify_type = default_join_table_qualification if qualify_type.nil?
510
586
  case qualify_type
511
587
  when false
512
588
  nil # Do no qualification
513
589
  when :deep
514
- k = Sequel::Qualifier.new(self, table_name).transform(k)
515
- v = Sequel::Qualifier.new(self, last_alias).transform(v)
590
+ k = Sequel::Qualifier.new(table_name).transform(k)
591
+ v = Sequel::Qualifier.new(last_alias).transform(v)
516
592
  else
517
593
  k = qualified_column_name(k, table_name) if k.is_a?(Symbol)
518
594
  v = qualified_column_name(v, last_alias) if v.is_a?(Symbol)
@@ -522,13 +598,13 @@ module Sequel
522
598
  expr = SQL::BooleanExpression.from_value_pairs(expr)
523
599
  end
524
600
  if block
525
- expr2 = yield(table_name, last_alias, @opts[:join] || [])
601
+ expr2 = yield(table_name, last_alias, @opts[:join] || EMPTY_ARRAY)
526
602
  expr = expr ? SQL::BooleanExpression.new(:AND, expr, expr2) : expr2
527
603
  end
528
604
  SQL::JoinOnClause.new(expr, type, table_expr)
529
605
  end
530
606
 
531
- opts = {:join => (@opts[:join] || []) + [join]}
607
+ opts = {:join => ((@opts[:join] || EMPTY_ARRAY) + [join]).freeze}
532
608
  opts[:last_joined_table] = table_name unless options[:reset_implicit_qualifier] == false
533
609
  opts[:num_dataset_sources] = table_alias_num if table_alias_num
534
610
  clone(opts)
@@ -551,10 +627,10 @@ module Sequel
551
627
  # or JOIN clauses, it will surround the subquery with LATERAL to enable it
552
628
  # to deal with previous tables in the query:
553
629
  #
554
- # DB.from(:a, DB[:b].where(:a__c=>:b__d).lateral)
630
+ # DB.from(:a, DB[:b].where(Sequel[:a][:c]=>Sequel[:b][:d]).lateral)
555
631
  # # SELECT * FROM a, LATERAL (SELECT * FROM b WHERE (a.c = b.d))
556
632
  def lateral
557
- clone(:lateral=>true)
633
+ cached_dataset(:_lateral_ds){clone(:lateral=>true)}
558
634
  end
559
635
 
560
636
  # If given an integer, the dataset will contain only the first l results.
@@ -603,14 +679,23 @@ module Sequel
603
679
 
604
680
  # Returns a cloned dataset without a row_proc.
605
681
  #
606
- # ds = DB[:items]
607
- # ds.row_proc = proc(&:invert)
682
+ # ds = DB[:items].with_row_proc(:invert.to_proc)
608
683
  # ds.all # => [{2=>:id}]
609
684
  # ds.naked.all # => [{:id=>2}]
610
685
  def naked
611
- ds = clone
612
- ds.row_proc = nil
613
- ds
686
+ cached_dataset(:_naked_ds){with_row_proc(nil)}
687
+ end
688
+
689
+ # Returns a copy of the dataset that will raise a DatabaseLockTimeout instead
690
+ # of waiting for rows that are locked by another transaction
691
+ #
692
+ # DB[:items].for_update.nowait
693
+ # # SELECT * FROM items FOR UPDATE NOWAIT
694
+ def nowait
695
+ cached_dataset(:_nowait_ds) do
696
+ raise(Error, 'This dataset does not support raises errors instead of waiting for locked rows') unless supports_nowait?
697
+ clone(:nowait=>true)
698
+ end
614
699
  end
615
700
 
616
701
  # Returns a copy of the dataset with a specified order. Can be safely combined with limit.
@@ -626,17 +711,17 @@ module Sequel
626
711
  clone(:offset => o)
627
712
  end
628
713
 
629
- # Adds an alternate filter to an existing filter using OR. If no filter
630
- # exists an +Error+ is raised.
714
+ # Adds an alternate filter to an existing WHERE clause using OR. If there
715
+ # is no WHERE clause, then the default is WHERE true, and OR would be redundant,
716
+ # so return the dataset in that case.
631
717
  #
632
718
  # DB[:items].where(:a).or(:b) # SELECT * FROM items WHERE a OR b
719
+ # DB[:items].or(:b) # SELECT * FROM items
633
720
  def or(*cond, &block)
634
- cond = cond.first if cond.size == 1
635
- v = @opts[:where]
636
- if v.nil? || (cond.respond_to?(:empty?) && cond.empty? && !block)
637
- clone
721
+ if @opts[:where].nil?
722
+ self
638
723
  else
639
- clone(:where => SQL::BooleanExpression.new(:OR, v, filter_expr(cond, &block)))
724
+ add_filter(:where, cond, false, :OR, &block)
640
725
  end
641
726
  end
642
727
 
@@ -649,19 +734,24 @@ module Sequel
649
734
  # DB[:items].order(:name) # SELECT * FROM items ORDER BY name
650
735
  # DB[:items].order(:a, :b) # SELECT * FROM items ORDER BY a, b
651
736
  # DB[:items].order(Sequel.lit('a + b')) # SELECT * FROM items ORDER BY a + b
652
- # DB[:items].order(:a + :b) # SELECT * FROM items ORDER BY (a + b)
737
+ # DB[:items].order(Sequel[:a] + :b) # SELECT * FROM items ORDER BY (a + b)
653
738
  # DB[:items].order(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name DESC
654
739
  # DB[:items].order(Sequel.asc(:name, :nulls=>:last)) # SELECT * FROM items ORDER BY name ASC NULLS LAST
655
740
  # DB[:items].order{sum(name).desc} # SELECT * FROM items ORDER BY sum(name) DESC
656
741
  # DB[:items].order(nil) # SELECT * FROM items
657
742
  def order(*columns, &block)
658
743
  virtual_row_columns(columns, block)
659
- clone(:order => (columns.compact.empty?) ? nil : columns)
744
+ clone(:order => (columns.compact.empty?) ? nil : columns.freeze)
660
745
  end
661
746
 
662
- # Alias of order_more, for naming consistency with order_prepend.
747
+ # Returns a copy of the dataset with the order columns added
748
+ # to the end of the existing order.
749
+ #
750
+ # DB[:items].order(:a).order(:b) # SELECT * FROM items ORDER BY b
751
+ # DB[:items].order(:a).order_append(:b) # SELECT * FROM items ORDER BY a, b
663
752
  def order_append(*columns, &block)
664
- order_more(*columns, &block)
753
+ columns = @opts[:order] + columns if @opts[:order]
754
+ order(*columns, &block)
665
755
  end
666
756
 
667
757
  # Alias of order
@@ -669,14 +759,9 @@ module Sequel
669
759
  order(*columns, &block)
670
760
  end
671
761
 
672
- # Returns a copy of the dataset with the order columns added
673
- # to the end of the existing order.
674
- #
675
- # DB[:items].order(:a).order(:b) # SELECT * FROM items ORDER BY b
676
- # DB[:items].order(:a).order_more(:b) # SELECT * FROM items ORDER BY a, b
762
+ # Alias of order_append.
677
763
  def order_more(*columns, &block)
678
- columns = @opts[:order] + columns if @opts[:order]
679
- order(*columns, &block)
764
+ order_append(*columns, &block)
680
765
  end
681
766
 
682
767
  # Returns a copy of the dataset with the order columns added
@@ -686,25 +771,30 @@ module Sequel
686
771
  # DB[:items].order(:a).order_prepend(:b) # SELECT * FROM items ORDER BY b, a
687
772
  def order_prepend(*columns, &block)
688
773
  ds = order(*columns, &block)
689
- @opts[:order] ? ds.order_more(*@opts[:order]) : ds
774
+ @opts[:order] ? ds.order_append(*@opts[:order]) : ds
690
775
  end
691
776
 
692
777
  # Qualify to the given table, or first source if no table is given.
693
778
  #
694
- # DB[:items].where(:id=>1).qualify
779
+ # DB[:items].where(id: 1).qualify
695
780
  # # SELECT items.* FROM items WHERE (items.id = 1)
696
781
  #
697
- # DB[:items].where(:id=>1).qualify(:i)
782
+ # DB[:items].where(id: 1).qualify(:i)
698
783
  # # SELECT i.* FROM items WHERE (i.id = 1)
699
- def qualify(table=first_source)
784
+ def qualify(table=(cache=true; first_source))
700
785
  o = @opts
701
- return clone if o[:sql]
702
- h = {}
703
- (o.keys & QUALIFY_KEYS).each do |k|
704
- h[k] = qualified_expression(o[k], table)
786
+ return self if o[:sql]
787
+
788
+ pr = proc do
789
+ h = {}
790
+ (o.keys & QUALIFY_KEYS).each do |k|
791
+ h[k] = qualified_expression(o[k], table)
792
+ end
793
+ h[:select] = [SQL::ColumnAll.new(table)].freeze if !o[:select] || o[:select].empty?
794
+ clone(h)
705
795
  end
706
- h[:select] = [SQL::ColumnAll.new(table)] if !o[:select] || o[:select].empty?
707
- clone(h)
796
+
797
+ cache ? cached_dataset(:_qualify_ds, &pr) : pr.call
708
798
  end
709
799
 
710
800
  # Modify the RETURNING clause, only supported on a few databases. If returning
@@ -715,9 +805,26 @@ module Sequel
715
805
  # DB[:items].returning # RETURNING *
716
806
  # DB[:items].returning(nil) # RETURNING NULL
717
807
  # DB[:items].returning(:id, :name) # RETURNING id, name
808
+ #
809
+ # DB[:items].returning.insert(:a=>1) do |hash|
810
+ # # hash for each row inserted, with values for all columns
811
+ # end
812
+ # DB[:items].returning.update(:a=>1) do |hash|
813
+ # # hash for each row updated, with values for all columns
814
+ # end
815
+ # DB[:items].returning.delete(:a=>1) do |hash|
816
+ # # hash for each row deleted, with values for all columns
817
+ # end
718
818
  def returning(*values)
719
- raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
720
- clone(:returning=>values)
819
+ if values.empty?
820
+ cached_dataset(:_returning_ds) do
821
+ raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
822
+ clone(:returning=>EMPTY_ARRAY)
823
+ end
824
+ else
825
+ raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
826
+ clone(:returning=>values.freeze)
827
+ end
721
828
  end
722
829
 
723
830
  # Returns a copy of the dataset with the order reversed. If no order is
@@ -728,8 +835,12 @@ module Sequel
728
835
  # DB[:items].order(:id).reverse # SELECT * FROM items ORDER BY id DESC
729
836
  # DB[:items].order(:id).reverse(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name ASC
730
837
  def reverse(*order, &block)
731
- virtual_row_columns(order, block)
732
- order(*invert_order(order.empty? ? @opts[:order] : order))
838
+ if order.empty? && !block
839
+ cached_dataset(:_reverse_ds){order(*invert_order(@opts[:order]))}
840
+ else
841
+ virtual_row_columns(order, block)
842
+ order(*invert_order(order.empty? ? @opts[:order] : order.freeze))
843
+ end
733
844
  end
734
845
 
735
846
  # Alias of +reverse+
@@ -746,7 +857,7 @@ module Sequel
746
857
  # DB[:items].select{[a, sum(b)]} # SELECT a, sum(b) FROM items
747
858
  def select(*columns, &block)
748
859
  virtual_row_columns(columns, block)
749
- clone(:select => columns)
860
+ clone(:select => columns.freeze)
750
861
  end
751
862
 
752
863
  # Returns a copy of the dataset selecting the wildcard if no arguments
@@ -758,9 +869,9 @@ module Sequel
758
869
  # DB[:items].select_all(:items, :foo) # SELECT items.*, foo.* FROM items
759
870
  def select_all(*tables)
760
871
  if tables.empty?
761
- clone(:select => nil)
872
+ cached_dataset(:_select_all_ds){clone(:select => nil)}
762
873
  else
763
- select(*tables.map{|t| i, a = split_alias(t); a || i}.map{|t| SQL::ColumnAll.new(t)})
874
+ select(*tables.map{|t| i, a = split_alias(t); a || i}.map!{|t| SQL::ColumnAll.new(t)}.freeze)
764
875
  end
765
876
  end
766
877
 
@@ -775,7 +886,7 @@ module Sequel
775
886
  cur_sel = @opts[:select]
776
887
  if !cur_sel || cur_sel.empty?
777
888
  unless supports_select_all_and_column?
778
- return select_all(*(Array(@opts[:from]) + Array(@opts[:join]))).select_more(*columns, &block)
889
+ return select_all(*(Array(@opts[:from]) + Array(@opts[:join]))).select_append(*columns, &block)
779
890
  end
780
891
  cur_sel = [WILDCARD]
781
892
  end
@@ -789,7 +900,7 @@ module Sequel
789
900
  # DB[:items].select_group(:a, :b)
790
901
  # # SELECT a, b FROM items GROUP BY a, b
791
902
  #
792
- # DB[:items].select_group(:c___a){f(c2)}
903
+ # DB[:items].select_group(Sequel[:c].as(:a)){f(c2)}
793
904
  # # SELECT c AS a, f(c2) FROM items GROUP BY c, f(c2)
794
905
  def select_group(*columns, &block)
795
906
  virtual_row_columns(columns, block)
@@ -825,36 +936,35 @@ module Sequel
825
936
  end
826
937
  end
827
938
 
828
- # Unbind bound variables from this dataset's filter and return an array of two
829
- # objects. The first object is a modified dataset where the filter has been
830
- # replaced with one that uses bound variable placeholders. The second object
831
- # is the hash of unbound variables. You can then prepare and execute (or just
832
- # call) the dataset with the bound variables to get results.
833
- #
834
- # ds, bv = DB[:items].where(:a=>1).unbind
835
- # ds # SELECT * FROM items WHERE (a = $a)
836
- # bv # {:a => 1}
837
- # ds.call(:select, bv)
838
- def unbind
839
- u = Unbinder.new
840
- ds = clone(:where=>u.transform(opts[:where]), :join=>u.transform(opts[:join]))
841
- [ds, u.binds]
939
+ # Specify that the check for limits/offsets when updating/deleting be skipped for the dataset.
940
+ def skip_limit_check
941
+ cached_dataset(:_skip_limit_check_ds) do
942
+ clone(:skip_limit_check=>true)
943
+ end
944
+ end
945
+
946
+ # Skip locked rows when returning results from this dataset.
947
+ def skip_locked
948
+ cached_dataset(:_skip_locked_ds) do
949
+ raise(Error, 'This dataset does not support skipping locked rows') unless supports_skip_locked?
950
+ clone(:skip_locked=>true)
951
+ end
842
952
  end
843
953
 
844
954
  # Returns a copy of the dataset with no filters (HAVING or WHERE clause) applied.
845
955
  #
846
- # DB[:items].group(:a).having(:a=>1).where(:b).unfiltered
956
+ # DB[:items].group(:a).having(a: 1).where(:b).unfiltered
847
957
  # # SELECT * FROM items GROUP BY a
848
958
  def unfiltered
849
- clone(:where => nil, :having => nil)
959
+ cached_dataset(:_unfiltered_ds){clone(:where => nil, :having => nil)}
850
960
  end
851
961
 
852
962
  # Returns a copy of the dataset with no grouping (GROUP or HAVING clause) applied.
853
963
  #
854
- # DB[:items].group(:a).having(:a=>1).where(:b).ungrouped
964
+ # DB[:items].group(:a).having(a: 1).where(:b).ungrouped
855
965
  # # SELECT * FROM items WHERE b
856
966
  def ungrouped
857
- clone(:group => nil, :having => nil)
967
+ cached_dataset(:_ungrouped_ds){clone(:group => nil, :having => nil)}
858
968
  end
859
969
 
860
970
  # Adds a UNION clause using a second dataset object.
@@ -868,10 +978,10 @@ module Sequel
868
978
  # DB[:items].union(DB[:other_items])
869
979
  # # SELECT * FROM (SELECT * FROM items UNION SELECT * FROM other_items) AS t1
870
980
  #
871
- # DB[:items].union(DB[:other_items], :all=>true, :from_self=>false)
981
+ # DB[:items].union(DB[:other_items], all: true, from_self: false)
872
982
  # # SELECT * FROM items UNION ALL SELECT * FROM other_items
873
983
  #
874
- # DB[:items].union(DB[:other_items], :alias=>:i)
984
+ # DB[:items].union(DB[:other_items], alias: :i)
875
985
  # # SELECT * FROM (SELECT * FROM items UNION SELECT * FROM other_items) AS i
876
986
  def union(dataset, opts=OPTS)
877
987
  compound_clone(:union, dataset, opts)
@@ -881,32 +991,24 @@ module Sequel
881
991
  #
882
992
  # DB[:items].limit(10, 20).unlimited # SELECT * FROM items
883
993
  def unlimited
884
- clone(:limit=>nil, :offset=>nil)
994
+ cached_dataset(:_unlimited_ds){clone(:limit=>nil, :offset=>nil)}
885
995
  end
886
996
 
887
997
  # Returns a copy of the dataset with no order.
888
998
  #
889
999
  # DB[:items].order(:a).unordered # SELECT * FROM items
890
1000
  def unordered
891
- order(nil)
1001
+ cached_dataset(:_unordered_ds){clone(:order=>nil)}
892
1002
  end
893
1003
 
894
1004
  # Returns a copy of the dataset with the given WHERE conditions imposed upon it.
895
1005
  #
896
1006
  # Accepts the following argument types:
897
1007
  #
898
- # Hash :: list of equality/inclusion expressions
899
- # Array :: depends:
900
- # * If first member is a string, assumes the rest of the arguments
901
- # are parameters and interpolates them into the string.
902
- # * If all members are arrays of length two, treats the same way
903
- # as a hash, except it allows for duplicate keys to be
904
- # specified.
905
- # * Otherwise, treats each argument as a separate condition.
906
- # String :: taken literally
1008
+ # Hash, Array of pairs :: list of equality/inclusion expressions
907
1009
  # Symbol :: taken as a boolean column argument (e.g. WHERE active)
908
- # Sequel::SQL::BooleanExpression :: an existing condition expression,
909
- # probably created using the Sequel expression filter DSL.
1010
+ # Sequel::SQL::BooleanExpression, Sequel::LiteralString :: an existing condition expression, probably created
1011
+ # using the Sequel expression filter DSL.
910
1012
  #
911
1013
  # where also accepts a block, which should return one of the above argument
912
1014
  # types, and is treated the same way. This block yields a virtual row object,
@@ -917,16 +1019,16 @@ module Sequel
917
1019
  #
918
1020
  # Examples:
919
1021
  #
920
- # DB[:items].where(:id => 3)
1022
+ # DB[:items].where(id: 3)
921
1023
  # # SELECT * FROM items WHERE (id = 3)
922
1024
  #
923
- # DB[:items].where('price < ?', 100)
1025
+ # DB[:items].where(Sequel.lit('price < ?', 100))
924
1026
  # # SELECT * FROM items WHERE price < 100
925
1027
  #
926
1028
  # DB[:items].where([[:id, [1,2,3]], [:id, 0..10]])
927
1029
  # # SELECT * FROM items WHERE ((id IN (1, 2, 3)) AND ((id >= 0) AND (id <= 10)))
928
1030
  #
929
- # DB[:items].where('price < 100')
1031
+ # DB[:items].where(Sequel.lit('price < 100'))
930
1032
  # # SELECT * FROM items WHERE price < 100
931
1033
  #
932
1034
  # DB[:items].where(:active)
@@ -937,21 +1039,35 @@ module Sequel
937
1039
  #
938
1040
  # Multiple where calls can be chained for scoping:
939
1041
  #
940
- # software = dataset.where(:category => 'software').where{price < 100}
1042
+ # software = dataset.where(category: 'software').where{price < 100}
941
1043
  # # SELECT * FROM items WHERE ((category = 'software') AND (price < 100))
942
1044
  #
943
1045
  # See the {"Dataset Filtering" guide}[rdoc-ref:doc/dataset_filtering.rdoc] for more examples and details.
944
1046
  def where(*cond, &block)
945
- _filter(:where, *cond, &block)
1047
+ add_filter(:where, cond, &block)
946
1048
  end
947
1049
 
1050
+ # Return a clone of the dataset with an addition named window that can be
1051
+ # referenced in window functions. See Sequel::SQL::Window for a list of
1052
+ # options that can be passed in. Example:
1053
+ #
1054
+ # DB[:items].window(:w, :partition=>:c1, :order=>:c2)
1055
+ # # SELECT * FROM items WINDOW w AS (PARTITION BY c1 ORDER BY c2)
1056
+ def window(name, opts)
1057
+ clone(:window=>((@opts[:window]||EMPTY_ARRAY) + [[name, SQL::Window.new(opts)].freeze]).freeze)
1058
+ end
1059
+
948
1060
  # Add a common table expression (CTE) with the given name and a dataset that defines the CTE.
949
1061
  # A common table expression acts as an inline view for the query.
950
1062
  # Options:
951
1063
  # :args :: Specify the arguments/columns for the CTE, should be an array of symbols.
952
1064
  # :recursive :: Specify that this is a recursive CTE
953
1065
  #
954
- # DB[:items].with(:items, DB[:syx].where(:name.like('A%')))
1066
+ # PostgreSQL Specific Options:
1067
+ # :materialized :: Set to false to force inlining of the CTE, or true to force not inlining
1068
+ # the CTE (PostgreSQL 12+).
1069
+ #
1070
+ # DB[:items].with(:items, DB[:syx].where(Sequel[:name].like('A%')))
955
1071
  # # WITH items AS (SELECT * FROM syx WHERE (name LIKE 'A%' ESCAPE '\')) SELECT * FROM items
956
1072
  def with(name, dataset, opts=OPTS)
957
1073
  raise(Error, 'This dataset does not support common table expressions') unless supports_cte?
@@ -959,7 +1075,7 @@ module Sequel
959
1075
  s, ds = hoist_cte(dataset)
960
1076
  s.with(name, ds, opts)
961
1077
  else
962
- clone(:with=>(@opts[:with]||[]) + [Hash[opts].merge!(:name=>name, :dataset=>dataset)])
1078
+ clone(:with=>((@opts[:with]||EMPTY_ARRAY) + [Hash[opts].merge!(:name=>name, :dataset=>dataset)]).freeze)
963
1079
  end
964
1080
  end
965
1081
 
@@ -970,17 +1086,17 @@ module Sequel
970
1086
  # :union_all :: Set to false to use UNION instead of UNION ALL combining the nonrecursive and recursive parts.
971
1087
  #
972
1088
  # DB[:t].with_recursive(:t,
973
- # DB[:i1].select(:id, :parent_id).where(:parent_id=>nil),
974
- # DB[:i1].join(:t, :id=>:parent_id).select(:i1__id, :i1__parent_id),
1089
+ # DB[:i1].select(:id, :parent_id).where(parent_id: nil),
1090
+ # DB[:i1].join(:t, id: :parent_id).select(Sequel[:i1][:id], Sequel[:i1][:parent_id]),
975
1091
  # :args=>[:id, :parent_id])
976
1092
  #
977
- # # WITH RECURSIVE "t"("id", "parent_id") AS (
978
- # # SELECT "id", "parent_id" FROM "i1" WHERE ("parent_id" IS NULL)
1093
+ # # WITH RECURSIVE t(id, parent_id) AS (
1094
+ # # SELECT id, parent_id FROM i1 WHERE (parent_id IS NULL)
979
1095
  # # UNION ALL
980
- # # SELECT "i1"."id", "i1"."parent_id" FROM "i1" INNER JOIN "t" ON ("t"."id" = "i1"."parent_id")
981
- # # ) SELECT * FROM "t"
1096
+ # # SELECT i1.id, i1.parent_id FROM i1 INNER JOIN t ON (t.id = i1.parent_id)
1097
+ # # ) SELECT * FROM t
982
1098
  def with_recursive(name, nonrecursive, recursive, opts=OPTS)
983
- raise(Error, 'This datatset does not support common table expressions') unless supports_cte?
1099
+ raise(Error, 'This dataset does not support common table expressions') unless supports_cte?
984
1100
  if hoist_cte?(nonrecursive)
985
1101
  s, ds = hoist_cte(nonrecursive)
986
1102
  s.with_recursive(name, ds, recursive, opts)
@@ -988,10 +1104,42 @@ module Sequel
988
1104
  s, ds = hoist_cte(recursive)
989
1105
  s.with_recursive(name, nonrecursive, ds, opts)
990
1106
  else
991
- clone(:with=>(@opts[:with]||[]) + [Hash[opts].merge!(:recursive=>true, :name=>name, :dataset=>nonrecursive.union(recursive, {:all=>opts[:union_all] != false, :from_self=>false}))])
1107
+ clone(:with=>((@opts[:with]||EMPTY_ARRAY) + [Hash[opts].merge!(:recursive=>true, :name=>name, :dataset=>nonrecursive.union(recursive, {:all=>opts[:union_all] != false, :from_self=>false}))]).freeze)
992
1108
  end
993
1109
  end
994
1110
 
1111
+ if TRUE_FREEZE
1112
+ # Return a clone of the dataset extended with the given modules.
1113
+ # Note that like Object#extend, when multiple modules are provided
1114
+ # as arguments the cloned dataset is extended with the modules in reverse
1115
+ # order. If a block is provided, a DatasetModule is created using the block and
1116
+ # the clone is extended with that module after any modules given as arguments.
1117
+ def with_extend(*mods, &block)
1118
+ c = _clone(:freeze=>false)
1119
+ c.extend(*mods) unless mods.empty?
1120
+ c.extend(DatasetModule.new(&block)) if block
1121
+ c.freeze
1122
+ end
1123
+ else
1124
+ # :nocov:
1125
+ def with_extend(*mods, &block) # :nodoc:
1126
+ c = clone
1127
+ c.extend(*mods) unless mods.empty?
1128
+ c.extend(DatasetModule.new(&block)) if block
1129
+ c
1130
+ end
1131
+ # :nocov:
1132
+ end
1133
+
1134
+ # Returns a cloned dataset with the given row_proc.
1135
+ #
1136
+ # ds = DB[:items]
1137
+ # ds.all # => [{:id=>2}]
1138
+ # ds.with_row_proc(:invert.to_proc).all # => [{2=>:id}]
1139
+ def with_row_proc(callable)
1140
+ clone(:row_proc=>callable)
1141
+ end
1142
+
995
1143
  # Returns a copy of the dataset with the static SQL used. This is useful if you want
996
1144
  # to keep the same row_proc/graph, but change the SQL used to custom SQL.
997
1145
  #
@@ -1004,9 +1152,27 @@ module Sequel
1004
1152
  # You can also provide a method name and arguments to call to get the SQL:
1005
1153
  #
1006
1154
  # DB[:items].with_sql(:insert_sql, :b=>1) # INSERT INTO items (b) VALUES (1)
1155
+ #
1156
+ # Note that datasets that specify custom SQL using this method will generally
1157
+ # ignore future dataset methods that modify the SQL used, as specifying custom SQL
1158
+ # overrides Sequel's SQL generator. You should probably limit yourself to the following
1159
+ # dataset methods when using this method, or use the implicit_subquery extension:
1160
+ #
1161
+ # * each
1162
+ # * all
1163
+ # * single_record (if only one record could be returned)
1164
+ # * single_value (if only one record could be returned, and a single column is selected)
1165
+ # * map
1166
+ # * as_hash
1167
+ # * to_hash
1168
+ # * to_hash_groups
1169
+ # * delete (if a DELETE statement)
1170
+ # * update (if an UPDATE statement, with no arguments)
1171
+ # * insert (if an INSERT statement, with no arguments)
1172
+ # * truncate (if a TRUNCATE statement, with no arguments)
1007
1173
  def with_sql(sql, *args)
1008
1174
  if sql.is_a?(Symbol)
1009
- sql = send(sql, *args)
1175
+ sql = public_send(sql, *args)
1010
1176
  else
1011
1177
  sql = SQL::PlaceholderLiteralString.new(sql, args) unless args.empty?
1012
1178
  end
@@ -1017,26 +1183,33 @@ module Sequel
1017
1183
 
1018
1184
  # Add the dataset to the list of compounds
1019
1185
  def compound_clone(type, dataset, opts)
1020
- if hoist_cte?(dataset)
1186
+ if dataset.is_a?(Dataset) && dataset.opts[:with] && !supports_cte_in_compounds?
1021
1187
  s, ds = hoist_cte(dataset)
1022
1188
  return s.compound_clone(type, ds, opts)
1023
1189
  end
1024
- ds = compound_from_self.clone(:compounds=>Array(@opts[:compounds]).map(&:dup) + [[type, dataset.compound_from_self, opts[:all]]])
1190
+ ds = compound_from_self.clone(:compounds=>(Array(@opts[:compounds]).map(&:dup) + [[type, dataset.compound_from_self, opts[:all]].freeze]).freeze)
1025
1191
  opts[:from_self] == false ? ds : ds.from_self(opts)
1026
1192
  end
1027
1193
 
1028
1194
  # Return true if the dataset has a non-nil value for any key in opts.
1029
1195
  def options_overlap(opts)
1030
- !(@opts.collect{|k,v| k unless v.nil?}.compact & opts).empty?
1196
+ !(@opts.map{|k,v| k unless v.nil?}.compact & opts).empty?
1031
1197
  end
1032
1198
 
1199
+ # From types allowed to be considered a simple_select_all
1200
+ SIMPLE_SELECT_ALL_ALLOWED_FROM = [Symbol, SQL::Identifier, SQL::QualifiedIdentifier].freeze
1201
+
1033
1202
  # Whether this dataset is a simple select from an underlying table, such as:
1034
1203
  #
1035
1204
  # SELECT * FROM table
1036
1205
  # SELECT table.* FROM table
1037
1206
  def simple_select_all?
1038
- o = @opts.reject{|k,v| v.nil? || NON_SQL_OPTIONS.include?(k)}
1039
- if (f = o[:from]) && f.length == 1 && (f.first.is_a?(Symbol) || f.first.is_a?(SQL::AliasedExpression))
1207
+ return false unless (f = @opts[:from]) && f.length == 1
1208
+ o = @opts.reject{|k,v| v.nil? || non_sql_option?(k)}
1209
+ from = f.first
1210
+ from = from.expression if from.is_a?(SQL::AliasedExpression)
1211
+
1212
+ if SIMPLE_SELECT_ALL_ALLOWED_FROM.any?{|x| from.is_a?(x)}
1040
1213
  case o.length
1041
1214
  when 1
1042
1215
  true
@@ -1052,23 +1225,61 @@ module Sequel
1052
1225
 
1053
1226
  private
1054
1227
 
1055
- # Internal filtering method so it works on either the WHERE or HAVING clauses, with or
1056
- # without inversion.
1057
- def _filter_or_exclude(invert, clause, *cond, &block)
1058
- cond = cond.first if cond.size == 1
1059
- if cond.respond_to?(:empty?) && cond.empty? && !block
1060
- clone
1228
+ # Load the extensions into the receiver, without checking if the receiver is frozen.
1229
+ def _extension!(exts)
1230
+ Sequel.extension(*exts)
1231
+ exts.each do |ext|
1232
+ if pr = Sequel.synchronize{EXTENSIONS[ext]}
1233
+ pr.call(self)
1234
+ else
1235
+ raise(Error, "Extension #{ext} does not have specific support handling individual datasets (try: Sequel.extension #{ext.inspect})")
1236
+ end
1237
+ end
1238
+ self
1239
+ end
1240
+
1241
+ # If invert is true, invert the condition.
1242
+ def _invert_filter(cond, invert)
1243
+ if invert
1244
+ SQL::BooleanExpression.invert(cond)
1061
1245
  else
1062
- cond = filter_expr(cond, &block)
1063
- cond = SQL::BooleanExpression.invert(cond) if invert
1064
- cond = SQL::BooleanExpression.new(:AND, @opts[clause], cond) if @opts[clause]
1065
- clone(clause => cond)
1246
+ cond
1066
1247
  end
1067
1248
  end
1068
1249
 
1069
- # Internal filter method so it works on either the having or where clauses.
1070
- def _filter(clause, *cond, &block)
1071
- _filter_or_exclude(false, clause, *cond, &block)
1250
+ # Add the given filter condition. Arguments:
1251
+ # clause :: Symbol or which SQL clause to effect, should be :where or :having
1252
+ # cond :: The filter condition to add
1253
+ # invert :: Whether the condition should be inverted (true or false)
1254
+ # combine :: How to combine the condition with an existing condition, should be :AND or :OR
1255
+ def add_filter(clause, cond, invert=false, combine=:AND, &block)
1256
+ if cond == EMPTY_ARRAY && !block
1257
+ raise Error, "must provide an argument to a filtering method if not passing a block"
1258
+ end
1259
+
1260
+ cond = cond.first if cond.size == 1
1261
+
1262
+ empty = cond == OPTS || cond == EMPTY_ARRAY
1263
+
1264
+ if empty && !block
1265
+ self
1266
+ else
1267
+ if cond == nil
1268
+ cond = Sequel::NULL
1269
+ end
1270
+ if empty && block
1271
+ cond = nil
1272
+ end
1273
+
1274
+ cond = _invert_filter(filter_expr(cond, &block), invert)
1275
+ cond = SQL::BooleanExpression.new(combine, @opts[clause], cond) if @opts[clause]
1276
+
1277
+ if cond.nil?
1278
+ cond = Sequel::NULL
1279
+ end
1280
+
1281
+ clone(clause => cond)
1282
+ end
1072
1283
  end
1073
1284
 
1074
1285
  # The default :qualify option to use for join tables if one is not specified.
@@ -1078,29 +1289,27 @@ module Sequel
1078
1289
 
1079
1290
  # SQL expression object based on the expr type. See +where+.
1080
1291
  def filter_expr(expr = nil, &block)
1081
- expr = nil if expr == []
1292
+ expr = nil if expr == EMPTY_ARRAY
1082
1293
 
1083
- if expr && block
1084
- return SQL::BooleanExpression.new(:AND, filter_expr(expr), filter_expr(block))
1085
- elsif block
1086
- expr = block
1294
+ if block
1295
+ cond = filter_expr(Sequel.virtual_row(&block))
1296
+ cond = SQL::BooleanExpression.new(:AND, filter_expr(expr), cond) if expr
1297
+ return cond
1087
1298
  end
1088
1299
 
1089
1300
  case expr
1090
1301
  when Hash
1091
1302
  SQL::BooleanExpression.from_value_pairs(expr)
1092
1303
  when Array
1093
- if (sexpr = expr.at(0)).is_a?(String)
1094
- SQL::PlaceholderLiteralString.new(sexpr, expr[1..-1], true)
1095
- elsif Sequel.condition_specifier?(expr)
1304
+ if Sequel.condition_specifier?(expr)
1096
1305
  SQL::BooleanExpression.from_value_pairs(expr)
1097
1306
  else
1098
- SQL::BooleanExpression.new(:AND, *expr.map{|x| filter_expr(x)})
1307
+ raise Error, "Invalid filter expression: #{expr.inspect}"
1099
1308
  end
1100
- when Proc
1101
- filter_expr(Sequel.virtual_row(&expr))
1102
- when Numeric, SQL::NumericExpression, SQL::StringExpression
1103
- raise(Error, "Invalid filter expression: #{expr.inspect}")
1309
+ when LiteralString
1310
+ LiteralString.new("(#{expr})")
1311
+ when Numeric, SQL::NumericExpression, SQL::StringExpression, Proc, String
1312
+ raise Error, "Invalid filter expression: #{expr.inspect}"
1104
1313
  when TrueClass, FalseClass
1105
1314
  if supports_where_true?
1106
1315
  SQL::BooleanExpression.new(:NOOP, expr)
@@ -1109,10 +1318,10 @@ module Sequel
1109
1318
  else
1110
1319
  SQL::Constants::SQLFALSE
1111
1320
  end
1112
- when String
1113
- LiteralString.new("(#{expr})")
1114
1321
  when PlaceholderLiteralizer::Argument
1115
1322
  expr.transform{|v| filter_expr(v)}
1323
+ when SQL::PlaceholderLiteralString
1324
+ expr.with_parens
1116
1325
  else
1117
1326
  expr
1118
1327
  end
@@ -1122,7 +1331,7 @@ module Sequel
1122
1331
  # clause from the given dataset added to it, and the second a clone of
1123
1332
  # the given dataset with the WITH clause removed.
1124
1333
  def hoist_cte(ds)
1125
- [clone(:with => (opts[:with] || []) + ds.opts[:with]), ds.clone(:with => nil)]
1334
+ [clone(:with => ((opts[:with] || EMPTY_ARRAY) + ds.opts[:with]).freeze), ds.clone(:with => nil)]
1126
1335
  end
1127
1336
 
1128
1337
  # Whether CTEs need to be hoisted from the given ds into the current ds.
@@ -1136,7 +1345,7 @@ module Sequel
1136
1345
  # DB[:items].invert_order([Sequel.desc(:id)]]) #=> [Sequel.asc(:id)]
1137
1346
  # DB[:items].invert_order([:category, Sequel.desc(:price)]) #=> [Sequel.desc(:category), Sequel.asc(:price)]
1138
1347
  def invert_order(order)
1139
- return nil unless order
1348
+ return unless order
1140
1349
  order.map do |f|
1141
1350
  case f
1142
1351
  when SQL::OrderedExpression
@@ -1153,6 +1362,11 @@ module Sequel
1153
1362
  server?(:default)
1154
1363
  end
1155
1364
 
1365
+ # Whether the given option key does not affect the generated SQL.
1366
+ def non_sql_option?(key)
1367
+ NON_SQL_OPTIONS.include?(key)
1368
+ end
1369
+
1156
1370
  # Treat the +block+ as a virtual_row block if not +nil+ and
1157
1371
  # add the resulting columns to the +columns+ array (modifies +columns+).
1158
1372
  def virtual_row_columns(columns, block)