sequel 4.26.0 → 5.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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)