sequel 5.8.0 → 5.38.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 (510) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +409 -1795
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/bin/sequel +4 -0
  6. data/doc/advanced_associations.rdoc +136 -18
  7. data/doc/association_basics.rdoc +10 -5
  8. data/doc/cheat_sheet.rdoc +1 -0
  9. data/doc/code_order.rdoc +12 -2
  10. data/doc/dataset_filtering.rdoc +17 -2
  11. data/doc/mass_assignment.rdoc +3 -3
  12. data/doc/model_dataset_method_design.rdoc +1 -1
  13. data/doc/model_plugins.rdoc +1 -1
  14. data/doc/opening_databases.rdoc +30 -8
  15. data/doc/postgresql.rdoc +107 -2
  16. data/doc/release_notes/5.10.0.txt +84 -0
  17. data/doc/release_notes/5.11.0.txt +83 -0
  18. data/doc/release_notes/5.12.0.txt +141 -0
  19. data/doc/release_notes/5.13.0.txt +27 -0
  20. data/doc/release_notes/5.14.0.txt +63 -0
  21. data/doc/release_notes/5.15.0.txt +39 -0
  22. data/doc/release_notes/5.16.0.txt +110 -0
  23. data/doc/release_notes/5.17.0.txt +31 -0
  24. data/doc/release_notes/5.18.0.txt +69 -0
  25. data/doc/release_notes/5.19.0.txt +28 -0
  26. data/doc/release_notes/5.20.0.txt +89 -0
  27. data/doc/release_notes/5.21.0.txt +87 -0
  28. data/doc/release_notes/5.22.0.txt +48 -0
  29. data/doc/release_notes/5.23.0.txt +56 -0
  30. data/doc/release_notes/5.24.0.txt +56 -0
  31. data/doc/release_notes/5.25.0.txt +32 -0
  32. data/doc/release_notes/5.26.0.txt +35 -0
  33. data/doc/release_notes/5.27.0.txt +21 -0
  34. data/doc/release_notes/5.28.0.txt +16 -0
  35. data/doc/release_notes/5.29.0.txt +22 -0
  36. data/doc/release_notes/5.30.0.txt +20 -0
  37. data/doc/release_notes/5.31.0.txt +148 -0
  38. data/doc/release_notes/5.32.0.txt +46 -0
  39. data/doc/release_notes/5.33.0.txt +24 -0
  40. data/doc/release_notes/5.34.0.txt +40 -0
  41. data/doc/release_notes/5.35.0.txt +56 -0
  42. data/doc/release_notes/5.36.0.txt +60 -0
  43. data/doc/release_notes/5.37.0.txt +30 -0
  44. data/doc/release_notes/5.38.0.txt +28 -0
  45. data/doc/release_notes/5.9.0.txt +99 -0
  46. data/doc/security.rdoc +10 -0
  47. data/doc/sharding.rdoc +42 -28
  48. data/doc/sql.rdoc +12 -0
  49. data/doc/testing.rdoc +24 -17
  50. data/doc/transactions.rdoc +78 -0
  51. data/doc/validations.rdoc +2 -2
  52. data/lib/sequel/adapters/ado.rb +26 -18
  53. data/lib/sequel/adapters/ado/access.rb +2 -2
  54. data/lib/sequel/adapters/ado/mssql.rb +5 -8
  55. data/lib/sequel/adapters/amalgalite.rb +1 -1
  56. data/lib/sequel/adapters/jdbc.rb +71 -27
  57. data/lib/sequel/adapters/jdbc/mysql.rb +6 -6
  58. data/lib/sequel/adapters/jdbc/oracle.rb +7 -6
  59. data/lib/sequel/adapters/jdbc/postgresql.rb +17 -28
  60. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +5 -6
  61. data/lib/sequel/adapters/jdbc/sqlite.rb +33 -2
  62. data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -3
  63. data/lib/sequel/adapters/jdbc/transactions.rb +14 -28
  64. data/lib/sequel/adapters/mysql.rb +14 -15
  65. data/lib/sequel/adapters/mysql2.rb +5 -3
  66. data/lib/sequel/adapters/odbc.rb +4 -6
  67. data/lib/sequel/adapters/oracle.rb +7 -7
  68. data/lib/sequel/adapters/postgres.rb +52 -16
  69. data/lib/sequel/adapters/shared/access.rb +16 -12
  70. data/lib/sequel/adapters/shared/db2.rb +5 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +41 -18
  72. data/lib/sequel/adapters/shared/mysql.rb +66 -19
  73. data/lib/sequel/adapters/shared/oracle.rb +29 -23
  74. data/lib/sequel/adapters/shared/postgres.rb +341 -95
  75. data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
  76. data/lib/sequel/adapters/shared/sqlite.rb +174 -21
  77. data/lib/sequel/adapters/sqlanywhere.rb +33 -17
  78. data/lib/sequel/adapters/sqlite.rb +78 -68
  79. data/lib/sequel/adapters/tinytds.rb +14 -6
  80. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +2 -5
  81. data/lib/sequel/adapters/utils/mysql_mysql2.rb +5 -1
  82. data/lib/sequel/connection_pool.rb +2 -6
  83. data/lib/sequel/connection_pool/sharded_single.rb +7 -4
  84. data/lib/sequel/connection_pool/sharded_threaded.rb +32 -21
  85. data/lib/sequel/connection_pool/single.rb +1 -1
  86. data/lib/sequel/connection_pool/threaded.rb +26 -11
  87. data/lib/sequel/core.rb +327 -319
  88. data/lib/sequel/database/connecting.rb +7 -8
  89. data/lib/sequel/database/logging.rb +7 -1
  90. data/lib/sequel/database/misc.rb +68 -34
  91. data/lib/sequel/database/query.rb +6 -4
  92. data/lib/sequel/database/schema_generator.rb +31 -11
  93. data/lib/sequel/database/schema_methods.rb +32 -22
  94. data/lib/sequel/database/transactions.rb +129 -25
  95. data/lib/sequel/dataset.rb +4 -2
  96. data/lib/sequel/dataset/actions.rb +34 -23
  97. data/lib/sequel/dataset/features.rb +34 -0
  98. data/lib/sequel/dataset/graph.rb +27 -11
  99. data/lib/sequel/dataset/misc.rb +17 -3
  100. data/lib/sequel/dataset/placeholder_literalizer.rb +50 -21
  101. data/lib/sequel/dataset/prepared_statements.rb +96 -26
  102. data/lib/sequel/dataset/query.rb +43 -8
  103. data/lib/sequel/dataset/sql.rb +189 -41
  104. data/lib/sequel/deprecated.rb +3 -1
  105. data/lib/sequel/exceptions.rb +2 -0
  106. data/lib/sequel/extensions/_pretty_table.rb +1 -2
  107. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  108. data/lib/sequel/extensions/caller_logging.rb +79 -0
  109. data/lib/sequel/extensions/columns_introspection.rb +1 -2
  110. data/lib/sequel/extensions/connection_expiration.rb +6 -6
  111. data/lib/sequel/extensions/connection_validator.rb +7 -6
  112. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  113. data/lib/sequel/extensions/constraint_validations.rb +53 -28
  114. data/lib/sequel/extensions/core_refinements.rb +2 -0
  115. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -0
  116. data/lib/sequel/extensions/escaped_like.rb +100 -0
  117. data/lib/sequel/extensions/eval_inspect.rb +3 -1
  118. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  119. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  120. data/lib/sequel/extensions/index_caching.rb +9 -7
  121. data/lib/sequel/extensions/integer64.rb +3 -1
  122. data/lib/sequel/extensions/looser_typecasting.rb +3 -3
  123. data/lib/sequel/extensions/migration.rb +13 -6
  124. data/lib/sequel/extensions/named_timezones.rb +84 -23
  125. data/lib/sequel/extensions/pg_array.rb +87 -79
  126. data/lib/sequel/extensions/pg_array_ops.rb +14 -6
  127. data/lib/sequel/extensions/pg_enum.rb +34 -18
  128. data/lib/sequel/extensions/pg_extended_date_support.rb +34 -14
  129. data/lib/sequel/extensions/pg_hstore.rb +6 -0
  130. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  131. data/lib/sequel/extensions/pg_inet.rb +15 -5
  132. data/lib/sequel/extensions/pg_interval.rb +2 -0
  133. data/lib/sequel/extensions/pg_json.rb +387 -123
  134. data/lib/sequel/extensions/pg_json_ops.rb +168 -0
  135. data/lib/sequel/extensions/pg_range.rb +20 -10
  136. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  137. data/lib/sequel/extensions/pg_row.rb +3 -2
  138. data/lib/sequel/extensions/pg_row_ops.rb +24 -0
  139. data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
  140. data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
  141. data/lib/sequel/extensions/query.rb +1 -0
  142. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  143. data/lib/sequel/extensions/s.rb +2 -0
  144. data/lib/sequel/extensions/schema_dumper.rb +13 -7
  145. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +4 -2
  146. data/lib/sequel/extensions/server_block.rb +18 -7
  147. data/lib/sequel/extensions/sql_comments.rb +2 -2
  148. data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
  149. data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
  150. data/lib/sequel/extensions/to_dot.rb +9 -3
  151. data/lib/sequel/model.rb +3 -1
  152. data/lib/sequel/model/associations.rb +403 -69
  153. data/lib/sequel/model/base.rb +170 -90
  154. data/lib/sequel/model/plugins.rb +105 -0
  155. data/lib/sequel/plugins/after_initialize.rb +1 -1
  156. data/lib/sequel/plugins/association_dependencies.rb +3 -3
  157. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  158. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  159. data/lib/sequel/plugins/association_pks.rb +74 -22
  160. data/lib/sequel/plugins/association_proxies.rb +6 -2
  161. data/lib/sequel/plugins/auto_validations.rb +36 -17
  162. data/lib/sequel/plugins/blacklist_security.rb +1 -2
  163. data/lib/sequel/plugins/boolean_subsets.rb +4 -1
  164. data/lib/sequel/plugins/caching.rb +3 -0
  165. data/lib/sequel/plugins/class_table_inheritance.rb +62 -34
  166. data/lib/sequel/plugins/composition.rb +13 -9
  167. data/lib/sequel/plugins/csv_serializer.rb +28 -9
  168. data/lib/sequel/plugins/defaults_setter.rb +2 -2
  169. data/lib/sequel/plugins/dirty.rb +60 -22
  170. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  171. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  172. data/lib/sequel/plugins/finder.rb +2 -2
  173. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  174. data/lib/sequel/plugins/hook_class_methods.rb +17 -5
  175. data/lib/sequel/plugins/insert_conflict.rb +72 -0
  176. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  177. data/lib/sequel/plugins/inverted_subsets.rb +2 -2
  178. data/lib/sequel/plugins/json_serializer.rb +21 -14
  179. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  180. data/lib/sequel/plugins/list.rb +22 -10
  181. data/lib/sequel/plugins/many_through_many.rb +1 -1
  182. data/lib/sequel/plugins/nested_attributes.rb +27 -5
  183. data/lib/sequel/plugins/pg_array_associations.rb +12 -9
  184. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +149 -61
  185. data/lib/sequel/plugins/prepared_statements.rb +6 -12
  186. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
  187. data/lib/sequel/plugins/rcte_tree.rb +20 -22
  188. data/lib/sequel/plugins/sharding.rb +13 -7
  189. data/lib/sequel/plugins/single_table_inheritance.rb +20 -15
  190. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  191. data/lib/sequel/plugins/static_cache.rb +36 -17
  192. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  193. data/lib/sequel/plugins/string_stripper.rb +1 -1
  194. data/lib/sequel/plugins/subclasses.rb +2 -0
  195. data/lib/sequel/plugins/subset_conditions.rb +2 -2
  196. data/lib/sequel/plugins/tactical_eager_loading.rb +73 -2
  197. data/lib/sequel/plugins/throw_failures.rb +110 -0
  198. data/lib/sequel/plugins/tree.rb +49 -31
  199. data/lib/sequel/plugins/typecast_on_load.rb +3 -2
  200. data/lib/sequel/plugins/validation_class_methods.rb +11 -5
  201. data/lib/sequel/plugins/validation_helpers.rb +2 -2
  202. data/lib/sequel/sql.rb +120 -30
  203. data/lib/sequel/timezones.rb +55 -14
  204. data/lib/sequel/version.rb +6 -1
  205. metadata +101 -361
  206. data/Rakefile +0 -151
  207. data/doc/release_notes/4.0.0.txt +0 -262
  208. data/doc/release_notes/4.1.0.txt +0 -85
  209. data/doc/release_notes/4.10.0.txt +0 -226
  210. data/doc/release_notes/4.11.0.txt +0 -147
  211. data/doc/release_notes/4.12.0.txt +0 -105
  212. data/doc/release_notes/4.13.0.txt +0 -169
  213. data/doc/release_notes/4.14.0.txt +0 -68
  214. data/doc/release_notes/4.15.0.txt +0 -56
  215. data/doc/release_notes/4.16.0.txt +0 -36
  216. data/doc/release_notes/4.17.0.txt +0 -38
  217. data/doc/release_notes/4.18.0.txt +0 -36
  218. data/doc/release_notes/4.19.0.txt +0 -45
  219. data/doc/release_notes/4.2.0.txt +0 -129
  220. data/doc/release_notes/4.20.0.txt +0 -79
  221. data/doc/release_notes/4.21.0.txt +0 -94
  222. data/doc/release_notes/4.22.0.txt +0 -72
  223. data/doc/release_notes/4.23.0.txt +0 -65
  224. data/doc/release_notes/4.24.0.txt +0 -99
  225. data/doc/release_notes/4.25.0.txt +0 -181
  226. data/doc/release_notes/4.26.0.txt +0 -44
  227. data/doc/release_notes/4.27.0.txt +0 -78
  228. data/doc/release_notes/4.28.0.txt +0 -57
  229. data/doc/release_notes/4.29.0.txt +0 -41
  230. data/doc/release_notes/4.3.0.txt +0 -40
  231. data/doc/release_notes/4.30.0.txt +0 -37
  232. data/doc/release_notes/4.31.0.txt +0 -57
  233. data/doc/release_notes/4.32.0.txt +0 -132
  234. data/doc/release_notes/4.33.0.txt +0 -88
  235. data/doc/release_notes/4.34.0.txt +0 -86
  236. data/doc/release_notes/4.35.0.txt +0 -130
  237. data/doc/release_notes/4.36.0.txt +0 -116
  238. data/doc/release_notes/4.37.0.txt +0 -50
  239. data/doc/release_notes/4.38.0.txt +0 -67
  240. data/doc/release_notes/4.39.0.txt +0 -127
  241. data/doc/release_notes/4.4.0.txt +0 -92
  242. data/doc/release_notes/4.40.0.txt +0 -179
  243. data/doc/release_notes/4.41.0.txt +0 -77
  244. data/doc/release_notes/4.42.0.txt +0 -221
  245. data/doc/release_notes/4.43.0.txt +0 -87
  246. data/doc/release_notes/4.44.0.txt +0 -125
  247. data/doc/release_notes/4.45.0.txt +0 -370
  248. data/doc/release_notes/4.46.0.txt +0 -404
  249. data/doc/release_notes/4.47.0.txt +0 -56
  250. data/doc/release_notes/4.48.0.txt +0 -293
  251. data/doc/release_notes/4.49.0.txt +0 -222
  252. data/doc/release_notes/4.5.0.txt +0 -34
  253. data/doc/release_notes/4.6.0.txt +0 -30
  254. data/doc/release_notes/4.7.0.txt +0 -103
  255. data/doc/release_notes/4.8.0.txt +0 -175
  256. data/doc/release_notes/4.9.0.txt +0 -190
  257. data/spec/adapter_spec.rb +0 -4
  258. data/spec/adapters/db2_spec.rb +0 -170
  259. data/spec/adapters/mssql_spec.rb +0 -804
  260. data/spec/adapters/mysql_spec.rb +0 -1041
  261. data/spec/adapters/oracle_spec.rb +0 -327
  262. data/spec/adapters/postgres_spec.rb +0 -4000
  263. data/spec/adapters/spec_helper.rb +0 -43
  264. data/spec/adapters/sqlanywhere_spec.rb +0 -97
  265. data/spec/adapters/sqlite_spec.rb +0 -600
  266. data/spec/bin_spec.rb +0 -269
  267. data/spec/core/connection_pool_spec.rb +0 -1228
  268. data/spec/core/database_spec.rb +0 -2673
  269. data/spec/core/dataset_spec.rb +0 -5419
  270. data/spec/core/deprecated_spec.rb +0 -70
  271. data/spec/core/expression_filters_spec.rb +0 -1344
  272. data/spec/core/mock_adapter_spec.rb +0 -722
  273. data/spec/core/object_graph_spec.rb +0 -306
  274. data/spec/core/placeholder_literalizer_spec.rb +0 -166
  275. data/spec/core/schema_generator_spec.rb +0 -214
  276. data/spec/core/schema_spec.rb +0 -1820
  277. data/spec/core/spec_helper.rb +0 -23
  278. data/spec/core/version_spec.rb +0 -7
  279. data/spec/core_extensions_spec.rb +0 -762
  280. data/spec/core_model_spec.rb +0 -2
  281. data/spec/core_spec.rb +0 -1
  282. data/spec/deprecation_helper.rb +0 -30
  283. data/spec/extensions/accessed_columns_spec.rb +0 -51
  284. data/spec/extensions/active_model_spec.rb +0 -99
  285. data/spec/extensions/after_initialize_spec.rb +0 -24
  286. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  287. data/spec/extensions/association_dependencies_spec.rb +0 -125
  288. data/spec/extensions/association_pks_spec.rb +0 -423
  289. data/spec/extensions/association_proxies_spec.rb +0 -100
  290. data/spec/extensions/auto_literal_strings_spec.rb +0 -205
  291. data/spec/extensions/auto_validations_spec.rb +0 -202
  292. data/spec/extensions/blacklist_security_spec.rb +0 -95
  293. data/spec/extensions/blank_spec.rb +0 -69
  294. data/spec/extensions/boolean_readers_spec.rb +0 -93
  295. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  296. data/spec/extensions/caching_spec.rb +0 -273
  297. data/spec/extensions/class_table_inheritance_spec.rb +0 -568
  298. data/spec/extensions/column_conflicts_spec.rb +0 -75
  299. data/spec/extensions/column_select_spec.rb +0 -129
  300. data/spec/extensions/columns_introspection_spec.rb +0 -90
  301. data/spec/extensions/columns_updated_spec.rb +0 -35
  302. data/spec/extensions/composition_spec.rb +0 -248
  303. data/spec/extensions/connection_expiration_spec.rb +0 -133
  304. data/spec/extensions/connection_validator_spec.rb +0 -127
  305. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -300
  306. data/spec/extensions/constraint_validations_spec.rb +0 -395
  307. data/spec/extensions/core_refinements_spec.rb +0 -528
  308. data/spec/extensions/csv_serializer_spec.rb +0 -183
  309. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  310. data/spec/extensions/dataset_associations_spec.rb +0 -365
  311. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  312. data/spec/extensions/date_arithmetic_spec.rb +0 -181
  313. data/spec/extensions/datetime_parse_to_time_spec.rb +0 -169
  314. data/spec/extensions/def_dataset_method_spec.rb +0 -100
  315. data/spec/extensions/defaults_setter_spec.rb +0 -141
  316. data/spec/extensions/delay_add_association_spec.rb +0 -73
  317. data/spec/extensions/dirty_spec.rb +0 -189
  318. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -104
  319. data/spec/extensions/eager_each_spec.rb +0 -62
  320. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  321. data/spec/extensions/error_splitter_spec.rb +0 -18
  322. data/spec/extensions/error_sql_spec.rb +0 -20
  323. data/spec/extensions/eval_inspect_spec.rb +0 -74
  324. data/spec/extensions/finder_spec.rb +0 -260
  325. data/spec/extensions/force_encoding_spec.rb +0 -126
  326. data/spec/extensions/freeze_datasets_spec.rb +0 -31
  327. data/spec/extensions/graph_each_spec.rb +0 -113
  328. data/spec/extensions/hook_class_methods_spec.rb +0 -380
  329. data/spec/extensions/identifier_mangling_spec.rb +0 -201
  330. data/spec/extensions/implicit_subquery_spec.rb +0 -58
  331. data/spec/extensions/index_caching_spec.rb +0 -66
  332. data/spec/extensions/inflector_spec.rb +0 -183
  333. data/spec/extensions/input_transformer_spec.rb +0 -69
  334. data/spec/extensions/insert_returning_select_spec.rb +0 -72
  335. data/spec/extensions/instance_filters_spec.rb +0 -79
  336. data/spec/extensions/instance_hooks_spec.rb +0 -246
  337. data/spec/extensions/integer64_spec.rb +0 -22
  338. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  339. data/spec/extensions/json_serializer_spec.rb +0 -336
  340. data/spec/extensions/lazy_attributes_spec.rb +0 -183
  341. data/spec/extensions/list_spec.rb +0 -275
  342. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  343. data/spec/extensions/many_through_many_spec.rb +0 -2177
  344. data/spec/extensions/migration_spec.rb +0 -840
  345. data/spec/extensions/modification_detection_spec.rb +0 -93
  346. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -92
  347. data/spec/extensions/named_timezones_spec.rb +0 -109
  348. data/spec/extensions/nested_attributes_spec.rb +0 -703
  349. data/spec/extensions/null_dataset_spec.rb +0 -85
  350. data/spec/extensions/optimistic_locking_spec.rb +0 -127
  351. data/spec/extensions/pagination_spec.rb +0 -116
  352. data/spec/extensions/pg_array_associations_spec.rb +0 -802
  353. data/spec/extensions/pg_array_ops_spec.rb +0 -144
  354. data/spec/extensions/pg_array_spec.rb +0 -398
  355. data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -165
  356. data/spec/extensions/pg_enum_spec.rb +0 -113
  357. data/spec/extensions/pg_extended_date_support_spec.rb +0 -126
  358. data/spec/extensions/pg_hstore_ops_spec.rb +0 -238
  359. data/spec/extensions/pg_hstore_spec.rb +0 -219
  360. data/spec/extensions/pg_inet_ops_spec.rb +0 -102
  361. data/spec/extensions/pg_inet_spec.rb +0 -72
  362. data/spec/extensions/pg_interval_spec.rb +0 -103
  363. data/spec/extensions/pg_json_ops_spec.rb +0 -289
  364. data/spec/extensions/pg_json_spec.rb +0 -262
  365. data/spec/extensions/pg_loose_count_spec.rb +0 -23
  366. data/spec/extensions/pg_range_ops_spec.rb +0 -60
  367. data/spec/extensions/pg_range_spec.rb +0 -487
  368. data/spec/extensions/pg_row_ops_spec.rb +0 -61
  369. data/spec/extensions/pg_row_plugin_spec.rb +0 -60
  370. data/spec/extensions/pg_row_spec.rb +0 -363
  371. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -93
  372. data/spec/extensions/pg_timestamptz_spec.rb +0 -17
  373. data/spec/extensions/prepared_statements_safe_spec.rb +0 -66
  374. data/spec/extensions/prepared_statements_spec.rb +0 -182
  375. data/spec/extensions/pretty_table_spec.rb +0 -123
  376. data/spec/extensions/query_spec.rb +0 -94
  377. data/spec/extensions/rcte_tree_spec.rb +0 -381
  378. data/spec/extensions/round_timestamps_spec.rb +0 -39
  379. data/spec/extensions/s_spec.rb +0 -60
  380. data/spec/extensions/schema_caching_spec.rb +0 -64
  381. data/spec/extensions/schema_dumper_spec.rb +0 -868
  382. data/spec/extensions/select_remove_spec.rb +0 -38
  383. data/spec/extensions/sequel_4_dataset_methods_spec.rb +0 -121
  384. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  385. data/spec/extensions/serialization_spec.rb +0 -365
  386. data/spec/extensions/server_block_spec.rb +0 -97
  387. data/spec/extensions/server_logging_spec.rb +0 -45
  388. data/spec/extensions/sharding_spec.rb +0 -189
  389. data/spec/extensions/shared_caching_spec.rb +0 -151
  390. data/spec/extensions/single_table_inheritance_spec.rb +0 -347
  391. data/spec/extensions/singular_table_names_spec.rb +0 -22
  392. data/spec/extensions/skip_create_refresh_spec.rb +0 -18
  393. data/spec/extensions/spec_helper.rb +0 -61
  394. data/spec/extensions/split_array_nil_spec.rb +0 -24
  395. data/spec/extensions/split_values_spec.rb +0 -57
  396. data/spec/extensions/sql_comments_spec.rb +0 -33
  397. data/spec/extensions/sql_expr_spec.rb +0 -59
  398. data/spec/extensions/static_cache_spec.rb +0 -410
  399. data/spec/extensions/string_agg_spec.rb +0 -90
  400. data/spec/extensions/string_date_time_spec.rb +0 -95
  401. data/spec/extensions/string_stripper_spec.rb +0 -68
  402. data/spec/extensions/subclasses_spec.rb +0 -79
  403. data/spec/extensions/subset_conditions_spec.rb +0 -38
  404. data/spec/extensions/symbol_aref_refinement_spec.rb +0 -28
  405. data/spec/extensions/symbol_as_refinement_spec.rb +0 -21
  406. data/spec/extensions/synchronize_sql_spec.rb +0 -124
  407. data/spec/extensions/table_select_spec.rb +0 -83
  408. data/spec/extensions/tactical_eager_loading_spec.rb +0 -141
  409. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  410. data/spec/extensions/timestamps_spec.rb +0 -209
  411. data/spec/extensions/to_dot_spec.rb +0 -153
  412. data/spec/extensions/touch_spec.rb +0 -226
  413. data/spec/extensions/tree_spec.rb +0 -284
  414. data/spec/extensions/typecast_on_load_spec.rb +0 -86
  415. data/spec/extensions/unlimited_update_spec.rb +0 -21
  416. data/spec/extensions/update_or_create_spec.rb +0 -83
  417. data/spec/extensions/update_primary_key_spec.rb +0 -105
  418. data/spec/extensions/update_refresh_spec.rb +0 -59
  419. data/spec/extensions/uuid_spec.rb +0 -101
  420. data/spec/extensions/validate_associated_spec.rb +0 -52
  421. data/spec/extensions/validation_class_methods_spec.rb +0 -1040
  422. data/spec/extensions/validation_contexts_spec.rb +0 -31
  423. data/spec/extensions/validation_helpers_spec.rb +0 -525
  424. data/spec/extensions/whitelist_security_spec.rb +0 -157
  425. data/spec/extensions/xml_serializer_spec.rb +0 -213
  426. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  427. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  428. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  429. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  430. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  431. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  432. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  433. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  434. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  435. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  436. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  437. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  438. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  439. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  440. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  441. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  442. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  443. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  444. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  445. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  446. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  447. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  448. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  449. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  450. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  451. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  452. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  453. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  454. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  455. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  456. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  457. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  458. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  459. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  460. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  461. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  462. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  463. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  464. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  465. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  466. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  467. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  468. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  469. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  470. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  471. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  472. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  473. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  474. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  475. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  476. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  477. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  478. data/spec/guards_helper.rb +0 -58
  479. data/spec/integration/associations_test.rb +0 -2513
  480. data/spec/integration/database_test.rb +0 -113
  481. data/spec/integration/dataset_test.rb +0 -1880
  482. data/spec/integration/eager_loader_test.rb +0 -687
  483. data/spec/integration/migrator_test.rb +0 -262
  484. data/spec/integration/model_test.rb +0 -203
  485. data/spec/integration/plugin_test.rb +0 -2302
  486. data/spec/integration/prepared_statement_test.rb +0 -398
  487. data/spec/integration/schema_test.rb +0 -869
  488. data/spec/integration/spec_helper.rb +0 -64
  489. data/spec/integration/timezone_test.rb +0 -86
  490. data/spec/integration/transaction_test.rb +0 -354
  491. data/spec/integration/type_test.rb +0 -127
  492. data/spec/model/association_reflection_spec.rb +0 -803
  493. data/spec/model/associations_spec.rb +0 -4538
  494. data/spec/model/base_spec.rb +0 -817
  495. data/spec/model/class_dataset_methods_spec.rb +0 -146
  496. data/spec/model/dataset_methods_spec.rb +0 -198
  497. data/spec/model/eager_loading_spec.rb +0 -2262
  498. data/spec/model/hooks_spec.rb +0 -370
  499. data/spec/model/inflector_spec.rb +0 -26
  500. data/spec/model/model_spec.rb +0 -953
  501. data/spec/model/plugins_spec.rb +0 -318
  502. data/spec/model/record_spec.rb +0 -2107
  503. data/spec/model/spec_helper.rb +0 -45
  504. data/spec/model/validations_spec.rb +0 -193
  505. data/spec/model_no_assoc_spec.rb +0 -1
  506. data/spec/model_spec.rb +0 -1
  507. data/spec/plugin_spec.rb +0 -1
  508. data/spec/sequel_coverage.rb +0 -15
  509. data/spec/sequel_warning.rb +0 -4
  510. data/spec/spec_config.rb +0 -12
@@ -1,113 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe Sequel::Database do
4
- before do
5
- @db = DB
6
- end
7
-
8
- it "should provide disconnect functionality" do
9
- @db.disconnect
10
- @db.pool.size.must_equal 0
11
- @db.test_connection
12
- @db.pool.size.must_equal 1
13
- end
14
-
15
- it "should provide disconnect functionality after preparing a statement" do
16
- @db.create_table!(:items){Integer :i}
17
- @db[:items].prepare(:first, :a).call
18
- @db.disconnect
19
- @db.pool.size.must_equal 0
20
- @db.drop_table?(:items)
21
- end
22
-
23
- it "should raise Sequel::DatabaseError on invalid SQL" do
24
- proc{@db << "S"}.must_raise(Sequel::DatabaseError)
25
- end
26
-
27
- it "should have Sequel::DatabaseError#sql give the SQL causing the error" do
28
- (@db << "SELECT") rescue (e = $!)
29
- e.sql.must_equal "SELECT"
30
- end if ENV['SEQUEL_ERROR_SQL']
31
-
32
- describe "constraint violations" do
33
- before do
34
- @db.drop_table?(:test2, :test)
35
- end
36
- after do
37
- @db.drop_table?(:test2, :test)
38
- end
39
-
40
- cspecify "should raise Sequel::UniqueConstraintViolation when a unique constraint is violated", [:jdbc, :sqlite] do
41
- @db.create_table!(:test){String :a, :unique=>true, :null=>false}
42
- @db[:test].insert('1')
43
- proc{@db[:test].insert('1')}.must_raise(Sequel::UniqueConstraintViolation)
44
- @db[:test].insert('2')
45
- proc{@db[:test].update(:a=>'1')}.must_raise(Sequel::UniqueConstraintViolation)
46
- end
47
-
48
- cspecify "should raise Sequel::UniqueConstraintViolation when a unique constraint is violated for composite primary keys", [:jdbc, :sqlite] do
49
- @db.create_table!(:test){String :a; String :b; primary_key [:a, :b]}
50
- @db[:test].insert(:a=>'1', :b=>'2')
51
- proc{@db[:test].insert(:a=>'1', :b=>'2')}.must_raise(Sequel::UniqueConstraintViolation)
52
- @db[:test].insert(:a=>'3', :b=>'4')
53
- proc{@db[:test].update(:a=>'1', :b=>'2')}.must_raise(Sequel::UniqueConstraintViolation)
54
- end
55
-
56
- cspecify "should raise Sequel::CheckConstraintViolation when a check constraint is violated", [proc{|db| !db.mariadb? || db.server_version <= 100200}, :mysql], [proc{|db| db.sqlite_version < 30802}, :sqlite] do
57
- @db.create_table!(:test){String :a; check Sequel.~(:a=>'1')}
58
- proc{@db[:test].insert('1')}.must_raise(Sequel::CheckConstraintViolation)
59
- @db[:test].insert('2')
60
- proc{@db[:test].insert('1')}.must_raise(Sequel::CheckConstraintViolation)
61
- end
62
-
63
- cspecify "should raise Sequel::ForeignKeyConstraintViolation when a foreign key constraint is violated", [:jdbc, :sqlite] do
64
- @db.create_table!(:test, :engine=>:InnoDB){primary_key :id}
65
- @db.create_table!(:test2, :engine=>:InnoDB){foreign_key :tid, :test}
66
- proc{@db[:test2].insert(:tid=>1)}.must_raise(Sequel::ForeignKeyConstraintViolation)
67
- @db[:test].insert
68
- @db[:test2].insert(:tid=>1)
69
- proc{@db[:test2].where(:tid=>1).update(:tid=>3)}.must_raise(Sequel::ForeignKeyConstraintViolation)
70
- proc{@db[:test].where(:id=>1).delete}.must_raise(Sequel::ForeignKeyConstraintViolation)
71
- end
72
-
73
- cspecify "should raise Sequel::NotNullConstraintViolation when a not null constraint is violated", [:jdbc, :sqlite] do
74
- @db.create_table!(:test){Integer :a, :null=>false}
75
- proc{@db[:test].insert(:a=>nil)}.must_raise(Sequel::NotNullConstraintViolation)
76
- unless @db.database_type == :mysql
77
- # Broken mysql silently changes NULL here to 0, and doesn't raise an exception.
78
- @db[:test].insert(2)
79
- proc{@db[:test].update(:a=>nil)}.must_raise(Sequel::NotNullConstraintViolation)
80
- end
81
- end
82
- end
83
-
84
- it "should store underlying wrapped exception in Sequel::DatabaseError" do
85
- begin
86
- @db << "SELECT"
87
- rescue Sequel::DatabaseError=>e
88
- if defined?(Java::JavaLang::Exception)
89
- (e.wrapped_exception.is_a?(Exception) || e.wrapped_exception.is_a?(Java::JavaLang::Exception)).must_equal true
90
- else
91
- e.wrapped_exception.must_be_kind_of(Exception)
92
- end
93
- end
94
- end
95
-
96
- it "should not have the connection pool swallow non-StandardError based exceptions" do
97
- proc{@db.pool.hold{raise Interrupt, "test"}}.must_raise(Interrupt)
98
- end
99
-
100
- it "should be able to disconnect connections more than once without exceptions" do
101
- conn = @db.synchronize{|c| c}
102
- @db.disconnect
103
- @db.disconnect_connection(conn)
104
- @db.disconnect_connection(conn)
105
- end
106
-
107
- it "should provide ability to check connections for validity" do
108
- conn = @db.synchronize{|c| c}
109
- @db.valid_connection?(conn).must_equal true
110
- @db.disconnect
111
- @db.valid_connection?(conn).must_equal false
112
- end
113
- end
@@ -1,1880 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "Simple Dataset operations" do
4
- before do
5
- @db = DB
6
- @db.create_table!(:items) do
7
- primary_key :id
8
- Integer :number
9
- end
10
- @ds = @db[:items]
11
- @ds.insert(:number=>10)
12
- end
13
- after do
14
- @db.drop_table?(:items)
15
- end
16
-
17
- it "should support sequential primary keys" do
18
- @ds.insert(:number=>20)
19
- @ds.insert(:number=>30)
20
- @ds.order(:number).all.must_equal [
21
- {:id => 1, :number=>10},
22
- {:id => 2, :number=>20},
23
- {:id => 3, :number=>30} ]
24
- end
25
-
26
- it "should support sequential primary keys with a Bignum" do
27
- @db.create_table!(:items) do
28
- primary_key :id, :type=>:Bignum
29
- Integer :number
30
- end
31
- @ds.insert(:number=>20)
32
- @ds.insert(:number=>30)
33
- @ds.order(:number).all.must_equal [{:id => 1, :number=>20}, {:id => 2, :number=>30}]
34
- end
35
-
36
- cspecify "should insert with a primary key specified", :db2, :mssql do
37
- @ds.insert(:id=>100, :number=>20)
38
- @ds.count.must_equal 2
39
- @ds.order(:id).all.must_equal [{:id=>1, :number=>10}, {:id=>100, :number=>20}]
40
- end
41
-
42
- it "should have insert return primary key value" do
43
- @ds.insert(:number=>20).must_equal 2
44
- @ds.filter(:id=>2).first[:number].must_equal 20
45
- end
46
-
47
- it "should have insert work correctly with static SQL" do
48
- @db["INSERT INTO #{@ds.literal(:items)} (#{@ds.literal(:number)}) VALUES (20)"].insert
49
- @ds.filter(:id=>2).first[:number].must_equal 20
50
- end
51
-
52
- it "should join correctly" do
53
- @ds.join(Sequel[:items].as(:b), :id=>:id).select_all(:items).all.must_equal [{:id=>1, :number=>10}]
54
- end
55
-
56
- it "should handle LATERAL subqueries correctly" do
57
- @ds.insert(:number=>20)
58
- @ds.from(Sequel[:items].as(:i), @ds.where(Sequel[:items][:number]=>Sequel[:i][:number]).lateral).select_order_map([Sequel[:i][:number].as(:n), Sequel[:t1][:number]]).must_equal [[10, 10], [20, 20]]
59
- @ds.from(Sequel[:items].as(:i)).cross_join(@ds.where(Sequel[:items][:number]=>Sequel[:i][:number]).lateral).select_order_map([Sequel[:i][:number].as(:n), Sequel[:t1][:number]]).must_equal [[10, 10], [20, 20]]
60
- @ds.from(Sequel[:items].as(:i)).join(@ds.where(Sequel[:items][:number]=>Sequel[:i][:number]).lateral, 1=>1).select_order_map([Sequel[:i][:number].as(:n), Sequel[:t1][:number]]).must_equal [[10, 10], [20, 20]]
61
- @ds.from(Sequel[:items].as(:i)).join(@ds.where(Sequel[:items][:number]=>Sequel[:i][:number]).lateral, 1=>0).select_order_map([Sequel[:i][:number].as(:n), Sequel[:t1][:number]]).must_equal []
62
- @ds.from(Sequel[:items].as(:i)).left_join(@ds.from(Sequel[:items].as(:i2)).where(Sequel[:i2][:number]=>Sequel[:i][:number]).lateral, 1=>1).select_order_map([Sequel[:i][:number].as(:n), Sequel[:t1][:number]]).must_equal [[10, 10], [20, 20]]
63
- @ds.from(Sequel[:items].as(:i)).left_join(@ds.from(Sequel[:items].as(:i2)).where(Sequel[:i2][:number]=>Sequel[:i][:number]).lateral, 1=>0).select_order_map([Sequel[:i][:number].as(:n), Sequel[:t1][:number]]).must_equal [[10, nil], [20, nil]]
64
- end if DB.dataset.supports_lateral_subqueries?
65
-
66
- it "should correctly deal with qualified columns and subselects" do
67
- @ds.from_self(:alias=>:a).select(Sequel[:a][:id], Sequel.qualify(:a, :number)).all.must_equal [{:id=>1, :number=>10}]
68
- @ds.join(@ds.as(:a), :id=>:id).select(Sequel[:a][:id], Sequel.qualify(:a, :number)).all.must_equal [{:id=>1, :number=>10}]
69
- end
70
-
71
- it "should graph correctly" do
72
- a = [{:items=>{:id=>1, :number=>10}, :b=>{:id=>1, :number=>10}}]
73
- pr = proc{|t| @ds.graph(t, {:id=>:id}, :table_alias=>:b).extension(:graph_each).all.must_equal a}
74
- pr[:items]
75
- pr[Sequel[:items].as(:foo)]
76
- pr[Sequel.identifier(:items)]
77
- pr[Sequel.identifier('items')]
78
- pr[Sequel.as(:items, :foo)]
79
- pr[Sequel.as(Sequel.identifier('items'), 'foo')]
80
- end
81
-
82
- it "should graph correctly with a subselect" do
83
- @ds.from_self(:alias=>:items).graph(@ds.from_self, {:id=>:id}, :table_alias=>:b).extension(:graph_each).all.must_equal [{:items=>{:id=>1, :number=>10}, :b=>{:id=>1, :number=>10}}]
84
- end
85
-
86
- cspecify "should have insert work correctly when inserting a row with all NULL values", :hsqldb do
87
- @db.create_table!(:items) do
88
- String :name
89
- Integer :number
90
- end
91
- @ds.insert
92
- @ds.all.must_equal [{:name=>nil, :number=>nil}]
93
- end
94
-
95
- it "should delete correctly" do
96
- @ds.filter(1=>1).delete.must_equal 1
97
- @ds.count.must_equal 0
98
- end
99
-
100
- it "should update correctly" do
101
- @ds.update(:number=>Sequel.expr(:number)+1).must_equal 1
102
- @ds.all.must_equal [{:id=>1, :number=>11}]
103
- end
104
-
105
- it "should have update return the number of matched rows" do
106
- @ds.update(:number=>:number).must_equal 1
107
- @ds.filter(:id=>1).update(:number=>:number).must_equal 1
108
- @ds.filter(:id=>2).update(:number=>:number).must_equal 0
109
- @ds.all.must_equal [{:id=>1, :number=>10}]
110
- end
111
-
112
- it "should iterate over records as they come in" do
113
- called = false
114
- @ds.each{|row| called = true; row.must_equal(:id=>1, :number=>10)}
115
- called.must_equal true
116
- end
117
-
118
- it "should support iterating over large numbers of records with paged_each" do
119
- (2..100).each{|i| @ds.insert(:number=>i*10)}
120
-
121
- [:offset, :filter].each do |strategy|
122
- rows = []
123
- @ds.order(:number).paged_each(:rows_per_fetch=>5, :strategy=>strategy){|row| rows << row}
124
- rows.must_equal((1..100).map{|i| {:id=>i, :number=>i*10}})
125
-
126
- rows = []
127
- @ds.order(:number).paged_each(:rows_per_fetch=>3, :strategy=>strategy){|row| rows << row}
128
- rows.must_equal((1..100).map{|i| {:id=>i, :number=>i*10}})
129
-
130
- rows = []
131
- @ds.order(:number, :id).paged_each(:rows_per_fetch=>5, :strategy=>strategy){|row| rows << row}
132
- rows.must_equal((1..100).map{|i| {:id=>i, :number=>i*10}})
133
-
134
- rows = []
135
- @ds.reverse_order(:number).paged_each(:rows_per_fetch=>5, :strategy=>strategy){|row| rows << row}
136
- rows.must_equal((1..100).map{|i| {:id=>i, :number=>i*10}}.reverse)
137
-
138
- rows = []
139
- @ds.order(Sequel.desc(:number), :id).paged_each(:rows_per_fetch=>5, :strategy=>strategy){|row| rows << row}
140
- rows.must_equal((1..100).map{|i| {:id=>i, :number=>i*10}}.reverse)
141
- end
142
-
143
- rows = []
144
- @ds.order(:number).limit(50, 25).paged_each(:rows_per_fetch=>3){|row| rows << row}
145
- rows.must_equal((26..75).map{|i| {:id=>i, :number=>i*10}})
146
-
147
- rows = []
148
- @ds.order(Sequel.*(:number, 2)).paged_each(:rows_per_fetch=>5){|row| rows << row}
149
- rows.must_equal((1..100).map{|i| {:id=>i, :number=>i*10}})
150
-
151
- rows = []
152
- @ds.order(Sequel.*(:number, 2)).paged_each(:rows_per_fetch=>5, :strategy=>:filter, :filter_values=>proc{|row, _| [row[:number] * 2]}){|row| rows << row}
153
- rows.must_equal((1..100).map{|i| {:id=>i, :number=>i*10}})
154
-
155
- if DB.adapter_scheme == :jdbc
156
- # check retrival with varying fetch sizes
157
- array = (1..100).to_a
158
- [1, 2, 5, 10, 33, 50, 100, 1000].each do |i|
159
- @ds.with_fetch_size(i).select_order_map(:id).must_equal array
160
- end
161
- end
162
- end
163
-
164
- it "should fetch all results correctly" do
165
- @ds.all.must_equal [{:id=>1, :number=>10}]
166
- end
167
-
168
- it "should skip locked rows correctly" do
169
- @ds.insert(:number=>10)
170
- q1 = Queue.new
171
- q2 = Queue.new
172
- ds = @ds.order(:id).for_update.skip_locked
173
- begin
174
- t = Thread.new{@db.transaction(:isolation=>:committed){q2.push(ds.get(:id)); q1.pop}}
175
- q2.pop.must_equal 1
176
- # Some databases do row level locking, others do page level locking
177
- [2, nil].must_include @db.transaction(:isolation=>:committed){ds.get(:id)}
178
- ensure
179
- q1.push(nil)
180
- t.join
181
- # Keep only one active connection, as some other specs expect that
182
- @db.disconnect
183
- end
184
- end if DB.dataset.supports_skip_locked?
185
-
186
- it "should raise error instead of waiting for rows correctly" do
187
- @ds.insert(:number=>10)
188
- q1 = Queue.new
189
- q2 = Queue.new
190
- ds = @ds.order(:id).for_update.nowait
191
- begin
192
- t = Thread.new{@db.transaction(:isolation=>:committed){q2.push(ds.get(:id)); q1.pop}}
193
- q2.pop.must_equal 1
194
- # Some databases do row level locking, others do page level locking
195
- proc{@db.transaction(:isolation=>:committed){ds.get(:id)}}.must_raise Sequel::DatabaseLockTimeout
196
- ensure
197
- q1.push(nil)
198
- t.join
199
- # Keep only one active connection, as some other specs expect that
200
- @db.disconnect
201
- end
202
- end if DB.dataset.supports_nowait?
203
-
204
- it "should raise exception if raising on duplication columns" do
205
- proc{@ds.select_map([:id, :id])}.must_raise Sequel::DuplicateColumnError
206
- end if DB.opts[:on_duplicate_columns] == :raise
207
-
208
- it "should fetch a single row correctly" do
209
- @ds.first.must_equal(:id=>1, :number=>10)
210
- @ds.single_record.must_equal(:id=>1, :number=>10)
211
- @ds.single_record!.must_equal(:id=>1, :number=>10)
212
- end
213
-
214
- it "should work correctly when returning from each without iterating over the whole result set" do
215
- @ds.insert(:number=>20)
216
- @ds.order(:id).each{|v| break v}.must_equal(:id=>1, :number=>10)
217
- @ds.reverse(:id).each{|v| break v}.must_equal(:id=>2, :number=>20)
218
- end
219
-
220
- it "should fetch a single value correctly" do
221
- @ds.get(:id).must_equal 1
222
- @ds.select(:id).single_value.must_equal 1
223
- @ds.select(:id).single_value!.must_equal 1
224
- end
225
-
226
- it "should have distinct work with limit" do
227
- @ds.limit(1).distinct.all.must_equal [{:id=>1, :number=>10}]
228
- end
229
-
230
- it "should fetch correctly with a limit" do
231
- @ds.order(:id).limit(2).all.must_equal [{:id=>1, :number=>10}]
232
- @ds.insert(:number=>20)
233
- @ds.order(:id).limit(1).all.must_equal [{:id=>1, :number=>10}]
234
- @ds.order(:id).limit(2).all.must_equal [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
235
- end
236
-
237
- it "should fetch correctly with a limit and offset" do
238
- @ds.order(:id).limit(2, 0).all.must_equal [{:id=>1, :number=>10}]
239
- @ds.order(:id).limit(2, 1).all.must_equal []
240
- @ds.insert(:number=>20)
241
- @ds.order(:id).limit(1, 1).all.must_equal [{:id=>2, :number=>20}]
242
- @ds.order(:id).limit(2, 0).all.must_equal [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
243
- @ds.order(:id).limit(2, 1).all.must_equal [{:id=>2, :number=>20}]
244
- end
245
-
246
- it "should fetch correctly with just offset" do
247
- @ds.order(:id).offset(0).all.must_equal [{:id=>1, :number=>10}]
248
- @ds.order(:id).offset(1).all.must_equal []
249
- @ds.insert(:number=>20)
250
- @ds.order(:id).offset(0).all.must_equal [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
251
- @ds.order(:id).offset(1).all.must_equal [{:id=>2, :number=>20}]
252
- @ds.order(:id).offset(2).all.must_equal []
253
- end
254
-
255
- it "should fetch correctly with a limit and offset using seperate methods" do
256
- @ds.order(:id).limit(2).offset(0).all.must_equal [{:id=>1, :number=>10}]
257
- @ds.order(:id).limit(2).offset(1).all.must_equal []
258
- @ds.insert(:number=>20)
259
- @ds.order(:id).limit(1).offset(1).all.must_equal [{:id=>2, :number=>20}]
260
- @ds.order(:id).limit(2).offset(0).all.must_equal [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
261
- @ds.order(:id).limit(2).offset(1).all.must_equal [{:id=>2, :number=>20}]
262
- end
263
-
264
- it "should provide correct columns when using a limit and offset" do
265
- ds = @ds.order(:id).limit(1, 1)
266
- ds.all
267
- ds.columns.must_equal [:id, :number]
268
- @ds.order(:id).limit(1, 1).columns.must_equal [:id, :number]
269
- end
270
-
271
- it "should fetch correctly with a limit and offset for different combinations of from and join tables" do
272
- @db.create_table!(:items2){primary_key :id2; Integer :number2}
273
- @db[:items2].insert(:number2=>10)
274
- @ds.from(:items, :items2).order(:id).limit(2, 0).all.must_equal [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
275
- @ds.from(Sequel[:items].as(:i), Sequel[:items2].as(:i2)).order(:id).limit(2, 0).all.must_equal [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
276
- @ds.cross_join(:items2).order(:id).limit(2, 0).all.must_equal [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
277
- @ds.from(Sequel[:items].as(:i)).cross_join(Sequel[:items2].as(:i2)).order(:id).limit(2, 0).all.must_equal [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
278
- @ds.cross_join(Sequel[:items2].as(:i)).cross_join(@db[:items2].select(Sequel[:id2].as(:id3), Sequel[:number2].as(:number3))).order(:id).limit(2, 0).all.must_equal [{:id=>1, :number=>10, :id2=>1, :number2=>10, :id3=>1, :number3=>10}]
279
-
280
- @ds.from(:items, :items2).order(:id).limit(2, 1).all.must_equal []
281
- @ds.from(Sequel[:items].as(:i), Sequel[:items2].as(:i2)).order(:id).limit(2, 1).all.must_equal []
282
- @ds.cross_join(:items2).order(:id).limit(2, 1).all.must_equal []
283
- @ds.from(Sequel[:items].as(:i)).cross_join(Sequel[:items2].as(:i2)).order(:id).limit(2, 1).all.must_equal []
284
- @ds.cross_join(Sequel[:items2].as(:i)).cross_join(@db[:items2].select(Sequel[:id2].as(:id3), Sequel[:number2].as(:number3))).order(:id).limit(2, 1).all.must_equal []
285
- @db.drop_table(:items2)
286
- end
287
-
288
- it "should fetch correctly with a limit and offset without an order" do
289
- @ds.limit(2, 1).all.must_equal []
290
- @ds.join(Sequel[:items].as(:i), :id=>:id).select(Sequel[:items][:id].as(:s), Sequel[:i][:id].as(:id2)).limit(2, 1).all.must_equal []
291
- @ds.join(Sequel[:items].as(:i), :id=>:id).select(Sequel[:items][:id]).limit(2, 1).all.must_equal []
292
- @ds.join(Sequel[:items].as(:i), :id=>:id).select(Sequel.qualify(:items, :id)).limit(2, 1).all.must_equal []
293
- @ds.join(Sequel[:items].as(:i), :id=>:id).select(Sequel.qualify(:items, :id).as(:s)).limit(2, 1).all.must_equal []
294
- end
295
-
296
- it "should be orderable by column number" do
297
- @ds.insert(:number=>20)
298
- @ds.insert(:number=>10)
299
- @ds.order(2, 1).select_map([:id, :number]).must_equal [[1, 10], [3, 10], [2, 20]]
300
- end
301
-
302
- it "should fetch correctly with a limit in an IN subselect" do
303
- @ds.where(:id=>@ds.select(:id).order(:id).limit(2)).all.must_equal [{:id=>1, :number=>10}]
304
- @ds.insert(:number=>20)
305
- @ds.where(:id=>@ds.select(:id).order(:id).limit(1)).all.must_equal [{:id=>1, :number=>10}]
306
- @ds.where(:id=>@ds.select(:id).order(:id).limit(2)).order(:id).all.must_equal [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
307
- end
308
-
309
- it "should fetch correctly with a limit and offset in an IN subselect" do
310
- @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 0)).all.must_equal [{:id=>1, :number=>10}]
311
- @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 1)).all.must_equal []
312
- @ds.insert(:number=>20)
313
- @ds.where(:id=>@ds.select(:id).order(:id).limit(1, 1)).all.must_equal [{:id=>2, :number=>20}]
314
- @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 0)).order(:id).all.must_equal [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
315
- @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 1)).all.must_equal [{:id=>2, :number=>20}]
316
- end
317
-
318
- it "should fetch correctly when using limit and offset in a from_self" do
319
- @ds.insert(:number=>20)
320
- ds = @ds.order(:id).limit(1, 1).from_self
321
- ds.all.must_equal [{:number=>20, :id=>2}]
322
- ds.columns.must_equal [:id, :number]
323
- @ds.order(:id).limit(1, 1).columns.must_equal [:id, :number]
324
- end
325
-
326
- it "should fetch correctly when using nested limit and offset in a from_self" do
327
- @ds.insert(:number=>20)
328
- @ds.insert(:number=>30)
329
- ds = @ds.order(:id).limit(2, 1).from_self.reverse_order(:number).limit(1, 1)
330
- ds.all.must_equal [{:number=>20, :id=>2}]
331
- ds.columns.must_equal [:id, :number]
332
- @ds.order(:id).limit(2, 1).from_self.reverse_order(:number).limit(1, 1).columns.must_equal [:id, :number]
333
-
334
- ds = @ds.order(:id).limit(3, 1).from_self.limit(2, 1).from_self.limit(1, 1)
335
- ds.all.must_equal []
336
- ds.columns.must_equal [:id, :number]
337
-
338
- @ds.insert(:number=>40)
339
- ds = @ds.order(:id).limit(3, 1).from_self.reverse_order(:number).limit(2, 1).from_self.reverse_order(:id).limit(1, 1)
340
- ds.all.must_equal [{:number=>20, :id=>2}]
341
- ds.columns.must_equal [:id, :number]
342
- end
343
-
344
- it "should alias columns correctly" do
345
- @ds.select(Sequel[:id].as(:x), Sequel[:number].as(:n)).first.must_equal(:x=>1, :n=>10)
346
- end
347
-
348
- it "should support table aliases with column aliases" do
349
- DB.from(@ds.as(:i, [:x, :n])).first.must_equal(:x=>1, :n=>10)
350
- end if DB.dataset.supports_derived_column_lists?
351
-
352
- it "should handle true/false properly" do
353
- @ds.filter(Sequel::TRUE).select_map(:number).must_equal [10]
354
- @ds.filter(Sequel::FALSE).select_map(:number).must_equal []
355
- @ds.filter(true).select_map(:number).must_equal [10]
356
- @ds.filter(false).select_map(:number).must_equal []
357
- end
358
-
359
- it "should support the sql_comments extension" do
360
- ds = @ds.extension(:sql_comments).comment("Some\rComment\r\nHere")
361
- ds.all.must_equal [{:id=>1, :number=>10}]
362
- ds.insert(:number=>20).must_equal 2
363
- ds.update(:number=>30).must_equal 2
364
- ds.delete.must_equal 2
365
- end
366
- end
367
-
368
- describe "Simple dataset operations with nasty table names" do
369
- before do
370
- @db = DB
371
- @table = :"i`t' [e]\"m\\s"
372
- end
373
-
374
- cspecify "should work correctly", :oracle, :sqlanywhere, [:jdbc, :mssql] do
375
- @db.create_table!(@table) do
376
- primary_key :id
377
- Integer :number
378
- end
379
- @ds = @db[@table]
380
- @ds.insert(:number=>10).must_equal 1
381
- @ds.all.must_equal [{:id=>1, :number=>10}]
382
- @ds.update(:number=>20).must_equal 1
383
- @ds.all.must_equal [{:id=>1, :number=>20}]
384
- @ds.delete.must_equal 1
385
- @ds.count.must_equal 0
386
- @db.drop_table?(@table)
387
- end
388
- end if DB.dataset.quote_identifiers?
389
-
390
- describe Sequel::Dataset do
391
- before do
392
- DB.create_table!(:test) do
393
- String :name
394
- Integer :value
395
- end
396
- @d = DB[:test]
397
- end
398
- after do
399
- DB.drop_table?(:test)
400
- end
401
-
402
- it "should return the correct record count" do
403
- @d.count.must_equal 0
404
- @d.insert(:name => 'abc', :value => 123)
405
- @d.insert(:name => 'abc', :value => 456)
406
- @d.insert(:name => 'def', :value => nil)
407
- 5.times do
408
- @d.count.must_equal 3
409
- @d.count(:name).must_equal 3
410
- @d.count(:value).must_equal 2
411
- end
412
- end
413
-
414
- it "should handle functions with identifier names correctly" do
415
- @d.insert(:name => 'abc', :value => 6)
416
- @d.get{sum.function(:value)}.must_equal 6
417
- end
418
-
419
- it "should handle aggregate methods on limited datasets correctly" do
420
- @d.insert(:name => 'abc', :value => 6)
421
- @d.insert(:name => 'bcd', :value => 12)
422
- @d.insert(:name => 'def', :value => 18)
423
- @d = @d.order(:name).limit(2)
424
- @d.count.must_equal 2
425
- @d.avg(:value).to_i.must_equal 9
426
- @d.min(:value).to_i.must_equal 6
427
- @d.reverse.min(:value).to_i.must_equal 12
428
- @d.max(:value).to_i.must_equal 12
429
- @d.sum(:value).to_i.must_equal 18
430
- @d.extension(:sequel_4_dataset_methods).interval(:value).to_i.must_equal 6
431
- end
432
-
433
- it "should return the correct records" do
434
- @d.to_a.must_equal []
435
- @d.insert(:name => 'abc', :value => 123)
436
- @d.insert(:name => 'abc', :value => 456)
437
- @d.insert(:name => 'def', :value => 789)
438
-
439
- @d.order(:value).to_a.must_equal [
440
- {:name => 'abc', :value => 123},
441
- {:name => 'abc', :value => 456},
442
- {:name => 'def', :value => 789}
443
- ]
444
- end
445
-
446
- it "should update records correctly" do
447
- @d.insert(:name => 'abc', :value => 123)
448
- @d.insert(:name => 'abc', :value => 456)
449
- @d.insert(:name => 'def', :value => 789)
450
- @d.filter(:name => 'abc').update(:value => 530)
451
- @d[:name => 'def'][:value].must_equal 789
452
- @d.filter(:value => 530).count.must_equal 2
453
- end
454
-
455
- it "should delete records correctly" do
456
- @d.insert(:name => 'abc', :value => 123)
457
- @d.insert(:name => 'abc', :value => 456)
458
- @d.insert(:name => 'def', :value => 789)
459
- @d.filter(:name => 'abc').delete
460
- @d.count.must_equal 1
461
- @d.first[:name].must_equal 'def'
462
- end
463
-
464
- it "should be able to truncate the table" do
465
- @d.insert(:name => 'abc', :value => 123)
466
- @d.insert(:name => 'abc', :value => 456)
467
- @d.insert(:name => 'def', :value => 789)
468
- @d.count.must_equal 3
469
- @d.truncate.must_be_nil
470
- @d.count.must_equal 0
471
- end
472
-
473
- it "should be able to literalize booleans" do
474
- @d.literal(true)
475
- @d.literal(false)
476
- end
477
- end
478
-
479
- describe Sequel::Database do
480
- it "should correctly escape strings" do
481
- ["\\\n",
482
- "\\\\\n",
483
- "\\\r\n",
484
- "\\\\\r\n",
485
- "\\\\\n\n",
486
- "\\\\\r\n\r\n",
487
- "\\dingo",
488
- "\\'dingo",
489
- "\\\\''dingo",
490
- ].each do |str|
491
- DB.get(Sequel.cast(str, String)).must_equal str
492
- str = "1#{str}1"
493
- DB.get(Sequel.cast(str, String)).must_equal str
494
- str = "#{str}#{str}"
495
- DB.get(Sequel.cast(str, String)).must_equal str
496
- end
497
- end
498
-
499
- cspecify "should properly escape binary data", [:odbc], [:jdbc, :hsqldb], :oracle do
500
- DB.get(Sequel.cast(Sequel.blob("\1\2\3"), File).as(:a)).must_equal "\1\2\3"
501
- end
502
-
503
- cspecify "should properly handle empty blobs", [:jdbc, :hsqldb], :oracle do
504
- DB.get(Sequel.cast(Sequel.blob(""), File).as(:a)).must_equal ""
505
- end
506
-
507
- cspecify "should properly escape identifiers", :db2, :oracle, :sqlanywhere do
508
- DB.create_table!(:"\\'\"[]"){Integer :id}
509
- DB.drop_table(:"\\'\"[]")
510
- end
511
-
512
- it "should have a working table_exists?" do
513
- t = :basdfdsafsaddsaf
514
- DB.drop_table?(t)
515
- DB.table_exists?(t).must_equal false
516
- DB.create_table(t){Integer :a}
517
- begin
518
- DB.table_exists?(t).must_equal true
519
- ensure
520
- DB.drop_table(t)
521
- end
522
- end
523
- end
524
-
525
- describe Sequel::Dataset do
526
- before do
527
- DB.create_table! :items do
528
- primary_key :id
529
- Integer :value
530
- end
531
- @d = DB[:items]
532
- @d.insert(:value => 123)
533
- @d.insert(:value => 456)
534
- @d.insert(:value => 789)
535
- end
536
- after do
537
- DB.drop_table?(:items)
538
- end
539
-
540
- it "should correctly return avg" do
541
- @d.avg(:value).to_i.must_equal 456
542
- end
543
-
544
- it "should correctly return sum" do
545
- @d.sum(:value).to_i.must_equal 1368
546
- end
547
-
548
- it "should correctly return max" do
549
- @d.max(:value).to_i.must_equal 789
550
- end
551
-
552
- it "should correctly return min" do
553
- @d.min(:value).to_i.must_equal 123
554
- end
555
- end
556
-
557
- describe "Simple Dataset operations" do
558
- before do
559
- DB.create_table!(:items) do
560
- Integer :number
561
- TrueClass :flag
562
- end
563
- @ds = DB[:items]
564
- end
565
- after do
566
- DB.drop_table?(:items)
567
- end
568
-
569
- it "should deal with boolean conditions correctly" do
570
- @ds.insert(:number=>1, :flag=>true)
571
- @ds.insert(:number=>2, :flag=>false)
572
- @ds.insert(:number=>3, :flag=>nil)
573
- @ds = @ds.order(:number)
574
- @ds.filter(:flag=>true).map(:number).must_equal [1]
575
- @ds.filter(:flag=>false).map(:number).must_equal [2]
576
- @ds.filter(:flag=>nil).map(:number).must_equal [3]
577
- @ds.exclude(:flag=>true).map(:number).must_equal [2, 3]
578
- @ds.exclude(:flag=>false).map(:number).must_equal [1, 3]
579
- @ds.exclude(:flag=>nil).map(:number).must_equal [1, 2]
580
- end
581
- end
582
-
583
- describe "Simple Dataset operations in transactions" do
584
- before do
585
- DB.create_table!(:items) do
586
- primary_key :id
587
- integer :number
588
- end
589
- @ds = DB[:items]
590
- end
591
- after do
592
- DB.drop_table?(:items)
593
- end
594
-
595
- cspecify "should insert correctly with a primary key specified inside a transaction", :db2, :mssql do
596
- DB.transaction do
597
- @ds.insert(:id=>100, :number=>20)
598
- @ds.count.must_equal 1
599
- @ds.order(:id).all.must_equal [{:id=>100, :number=>20}]
600
- end
601
- end
602
-
603
- it "should have insert return primary key value inside a transaction" do
604
- DB.transaction do
605
- @ds.insert(:number=>20).must_equal 1
606
- @ds.count.must_equal 1
607
- @ds.order(:id).all.must_equal [{:id=>1, :number=>20}]
608
- end
609
- end
610
-
611
- it "should support for_update" do
612
- DB.transaction{@ds.for_update.all.must_equal []}
613
- end
614
- end
615
-
616
- describe "Dataset UNION, EXCEPT, and INTERSECT" do
617
- before do
618
- DB.create_table!(:i1){integer :number}
619
- DB.create_table!(:i2){integer :number}
620
- @ds1 = DB[:i1]
621
- @ds1.insert(:number=>10)
622
- @ds1.insert(:number=>20)
623
- @ds2 = DB[:i2]
624
- @ds2.insert(:number=>10)
625
- @ds2.insert(:number=>30)
626
- end
627
- after do
628
- DB.drop_table?(:i1, :i2, :i3)
629
- end
630
-
631
- it "should give the correct results for UNION with an existing order" do
632
- @ds1.order(:number).union(@ds2).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 20 30'
633
- end
634
-
635
- it "should give the correct results for simple UNION, EXCEPT, and INTERSECT" do
636
- @ds1.union(@ds2).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 20 30'
637
- if @ds1.supports_intersect_except?
638
- @ds1.except(@ds2).order(:number).map{|x| x[:number].to_s}.must_equal %w'20'
639
- @ds1.intersect(@ds2).order(:number).map{|x| x[:number].to_s}.must_equal %w'10'
640
- end
641
- end
642
-
643
- it "should give the correct results for UNION, EXCEPT, and INTERSECT when used with ordering and limits and offsets" do
644
- [%w'10 30', %w'10 20 30'].must_include @ds1.limit(1).union(@ds2).order(:number).map{|x| x[:number].to_s}
645
- [%w'10 30', %w'10 20 30'].must_include @ds1.offset(1).union(@ds2).order(:number).map{|x| x[:number].to_s}
646
-
647
- @ds1.insert(:number=>8)
648
- @ds2.insert(:number=>9)
649
- @ds1.insert(:number=>38)
650
- @ds2.insert(:number=>39)
651
-
652
- @ds1.reverse_order(:number).union(@ds2).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 9 10 20 30 38 39'
653
- @ds1.union(@ds2.reverse_order(:number)).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 9 10 20 30 38 39'
654
-
655
- @ds1.reverse_order(:number).limit(1).union(@ds2).order(:number).map{|x| x[:number].to_s}.must_equal %w'9 10 30 38 39'
656
- @ds2.reverse_order(:number).limit(1).union(@ds1).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 10 20 38 39'
657
- @ds1.reverse_order(:number).limit(1, 1).union(@ds2).order(:number).map{|x| x[:number].to_s}.must_equal %w'9 10 20 30 39'
658
- @ds2.reverse_order(:number).limit(1, 1).union(@ds1).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 10 20 30 38'
659
- @ds1.reverse_order(:number).offset(1).union(@ds2).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 9 10 20 30 39'
660
- @ds2.reverse_order(:number).offset(1).union(@ds1).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 9 10 20 30 38'
661
-
662
- @ds1.union(@ds2.order(:number).limit(1)).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 9 10 20 38'
663
- @ds2.union(@ds1.order(:number).limit(1)).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 9 10 30 39'
664
- @ds1.union(@ds2.order(:number).limit(1, 1)).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 10 20 38'
665
- @ds2.union(@ds1.order(:number).limit(1, 1)).order(:number).map{|x| x[:number].to_s}.must_equal %w'9 10 30 39'
666
- @ds1.union(@ds2.order(:number).offset(1)).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 10 20 30 38 39'
667
- @ds2.union(@ds1.order(:number).offset(1)).order(:number).map{|x| x[:number].to_s}.must_equal %w'9 10 20 30 38 39'
668
-
669
- @ds1.union(@ds2).limit(2).order(:number).map{|x| x[:number].to_s}.must_equal %w'8 9'
670
- @ds2.union(@ds1).reverse_order(:number).limit(2).map{|x| x[:number].to_s}.must_equal %w'39 38'
671
- @ds1.union(@ds2).limit(2, 1).order(:number).map{|x| x[:number].to_s}.must_equal %w'9 10'
672
- @ds2.union(@ds1).reverse_order(:number).limit(2, 1).map{|x| x[:number].to_s}.must_equal %w'38 30'
673
- @ds1.union(@ds2).offset(1).order(:number).map{|x| x[:number].to_s}.must_equal %w'9 10 20 30 38 39'
674
- @ds2.union(@ds1).reverse_order(:number).offset(1).map{|x| x[:number].to_s}.must_equal %w'38 30 20 10 9 8'
675
-
676
- @ds1.reverse_order(:number).limit(2).union(@ds2.reverse_order(:number).limit(2)).order(:number).limit(3).map{|x| x[:number].to_s}.must_equal %w'20 30 38'
677
- @ds2.order(:number).limit(2).union(@ds1.order(:number).limit(2)).reverse_order(:number).limit(3).map{|x| x[:number].to_s}.must_equal %w'10 9 8'
678
- @ds1.reverse_order(:number).limit(2, 1).union(@ds2.reverse_order(:number).limit(2, 1)).order(:number).limit(3, 1).map{|x| x[:number].to_s}.must_equal %w'20 30'
679
- @ds2.order(:number).limit(2, 1).union(@ds1.order(:number).limit(2, 1)).reverse_order(:number).limit(3, 1).map{|x| x[:number].to_s}.must_equal %w'20 10'
680
- @ds1.reverse_order(:number).offset(1).union(@ds2.reverse_order(:number).offset(1)).order(:number).offset(1).map{|x| x[:number].to_s}.must_equal %w'9 10 20 30'
681
- @ds2.order(:number).offset(1).union(@ds1.order(:number).offset(1)).reverse_order(:number).offset(1).map{|x| x[:number].to_s}.must_equal %w'38 30 20 10'
682
- end
683
-
684
- it "should give the correct results for compound UNION, EXCEPT, and INTERSECT" do
685
- DB.create_table!(:i3){integer :number}
686
- @ds3 = DB[:i3]
687
- @ds3.insert(:number=>10)
688
- @ds3.insert(:number=>40)
689
-
690
- @ds1.union(@ds2).union(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 20 30 40'
691
- @ds1.union(@ds2.union(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 20 30 40'
692
- if @ds1.supports_intersect_except?
693
- @ds1.union(@ds2).except(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w'20 30'
694
- @ds1.union(@ds2.except(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 20 30'
695
- @ds1.union(@ds2).intersect(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 '
696
- @ds1.union(@ds2.intersect(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 20'
697
-
698
- @ds1.except(@ds2).union(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 20 40'
699
- @ds1.except(@ds2.union(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w'20'
700
- @ds1.except(@ds2).except(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w'20'
701
- @ds1.except(@ds2.except(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 20'
702
- @ds1.except(@ds2).intersect(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w''
703
- @ds1.except(@ds2.intersect(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w'20'
704
-
705
- @ds1.intersect(@ds2).union(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w'10 40'
706
- @ds1.intersect(@ds2.union(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w'10'
707
- @ds1.intersect(@ds2).except(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w''
708
- @ds1.intersect(@ds2.except(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w''
709
- @ds1.intersect(@ds2).intersect(@ds3).order(:number).map{|x| x[:number].to_s}.must_equal %w'10'
710
- @ds1.intersect(@ds2.intersect(@ds3)).order(:number).map{|x| x[:number].to_s}.must_equal %w'10'
711
- end
712
- end
713
- end
714
-
715
- if DB.dataset.supports_cte?
716
- describe "Common Table Expressions" do
717
- before(:all) do
718
- @db = DB
719
- @db.create_table!(:i1){Integer :id; Integer :parent_id}
720
- @ds = @db[:i1]
721
- @ds.insert(:id=>1)
722
- @ds.insert(:id=>2)
723
- @ds.insert(:id=>3, :parent_id=>1)
724
- @ds.insert(:id=>4, :parent_id=>1)
725
- @ds.insert(:id=>5, :parent_id=>3)
726
- @ds.insert(:id=>6, :parent_id=>5)
727
- end
728
- after(:all) do
729
- @db.drop_table?(:i1)
730
- end
731
-
732
- it "should give correct results for WITH" do
733
- @db[:t].with(:t, @ds.filter(:parent_id=>nil).select(:id)).order(:id).map(:id).must_equal [1, 2]
734
- end
735
-
736
- cspecify "should give correct results for recursive WITH", :db2 do
737
- ds = @db[:t].select(Sequel[:i].as(:id), Sequel[:pi].as(:parent_id)).with_recursive(:t, @ds.filter(:parent_id=>nil), @ds.join(:t, :i=>:parent_id).select(Sequel[:i1][:id], Sequel[:i1][:parent_id]), :args=>[:i, :pi]).order(:id)
738
- ds.all.must_equal [{:parent_id=>nil, :id=>1}, {:parent_id=>nil, :id=>2}, {:parent_id=>1, :id=>3}, {:parent_id=>1, :id=>4}, {:parent_id=>3, :id=>5}, {:parent_id=>5, :id=>6}]
739
- ps = @db[:t].select(Sequel[:i].as(:id), Sequel[:pi].as(:parent_id)).with_recursive(:t, @ds.filter(:parent_id=>:$n), @ds.join(:t, :i=>:parent_id).filter(Sequel[:t][:i]=>:parent_id).select(Sequel[:i1][:id], Sequel[:i1][:parent_id]), :args=>[:i, :pi]).order(:id).prepare(:select, :cte_sel)
740
- ps.call(:n=>1).must_equal [{:id=>3, :parent_id=>1}, {:id=>4, :parent_id=>1}, {:id=>5, :parent_id=>3}, {:id=>6, :parent_id=>5}]
741
- ps.call(:n=>3).must_equal [{:id=>5, :parent_id=>3}, {:id=>6, :parent_id=>5}]
742
- ps.call(:n=>5).must_equal [{:id=>6, :parent_id=>5}]
743
- end
744
-
745
- it "should support joining a dataset with a CTE" do
746
- @ds.inner_join(@db[:t].with(:t, @ds.filter(:parent_id=>nil)), :id => :id).select(Sequel[:i1][:id]).order(Sequel[:i1][:id]).map(:id).must_equal [1,2]
747
- @db[:t].with(:t, @ds).inner_join(@db[:s].with(:s, @ds.filter(:parent_id=>nil)), :id => :id).select(Sequel[:t][:id]).order(Sequel[:t][:id]).map(:id).must_equal [1,2]
748
- end
749
-
750
- it "should support a subselect in the FROM clause with a CTE" do
751
- @ds.from(@db[:t].with(:t, @ds)).select_order_map(:id).must_equal [1,2,3,4,5,6]
752
- @db[:t].with(:t, @ds).from_self.select_order_map(:id).must_equal [1,2,3,4,5,6]
753
- end
754
-
755
- it "should support using a CTE inside a CTE" do
756
- @db[:s].with(:s, @db[:t].with(:t, @ds)).select_order_map(:id).must_equal [1,2,3,4,5,6]
757
- @db[:s].with_recursive(:s, @db[:t].with(:t, @ds), @db[:t2].with(:t2, @ds)).select_order_map(:id).must_equal [1,1,2,2,3,3,4,4,5,5,6,6]
758
- end
759
-
760
- it "should support using a CTE inside UNION/EXCEPT/INTERSECT" do
761
- @ds.union(@db[:t].with(:t, @ds)).select_order_map(:id).must_equal [1,2,3,4,5,6]
762
- if @ds.supports_intersect_except?
763
- @ds.intersect(@db[:t].with(:t, @ds)).select_order_map(:id).must_equal [1,2,3,4,5,6]
764
- @ds.except(@db[:t].with(:t, @ds)).select_order_map(:id).must_equal []
765
- end
766
- end
767
- end
768
- end
769
-
770
- if DB.dataset.supports_cte?(:insert) || DB.dataset.supports_cte?(:update) || DB.dataset.supports_cte?(:delete)
771
- describe "Common Table Expressions" do
772
- before do
773
- @db = DB
774
- @db.create_table!(:i1){Integer :id}
775
- @ds = @db[:i1]
776
- @ds2 = @ds.with(:t, @ds)
777
- @ds.insert(:id=>1)
778
- @ds.insert(:id=>2)
779
- end
780
- after do
781
- @db.drop_table?(:i1)
782
- end
783
-
784
- it "should give correct results for WITH in insert" do
785
- @ds2.insert(@db[:t])
786
- @ds.select_order_map(:id).must_equal [1, 1, 2, 2]
787
- end if DB.dataset.supports_cte?(:insert)
788
-
789
- it "should give correct results for WITH in update" do
790
- @ds2.filter(:id=>@db[:t].select{max(id)}).update(:id=>Sequel.+(:id, 1))
791
- @ds.select_order_map(:id).must_equal [1, 3]
792
- end if DB.dataset.supports_cte?(:update)
793
-
794
- it "should give correct results for WITH in delete" do
795
- @ds2.filter(:id=>@db[:t].select{max(id)}).delete
796
- @ds.select_order_map(:id).must_equal [1]
797
- end if DB.dataset.supports_cte?(:delete)
798
-
799
- it "should support a subselect in an subquery used for INSERT" do
800
- @db.transaction(:rollback=>:always) do
801
- @ds.insert([:id], @db[:foo].with(:foo, @ds.select{(id + 10).as(:id)}))
802
- @ds.select_order_map(:id).must_equal [1,2,11,12]
803
- end
804
- end
805
- end
806
- end
807
-
808
- if DB.dataset.supports_returning?(:insert)
809
- describe "RETURNING clauses in INSERT" do
810
- before do
811
- @db = DB
812
- @db.create_table!(:i1){Integer :id; Integer :foo}
813
- @ds = @db[:i1]
814
- end
815
- after do
816
- @db.drop_table?(:i1)
817
- end
818
-
819
- it "should give correct results" do
820
- h = {}
821
- @ds.returning(:foo).insert(1, 2){|r| h = r}
822
- h.must_equal(:foo=>2)
823
- @ds.returning(:id).insert(3, 4){|r| h = r}
824
- h.must_equal(:id=>3)
825
- @ds.returning.insert(5, 6){|r| h = r}
826
- h.must_equal(:id=>5, :foo=>6)
827
- @ds.returning(Sequel[:id].as(:foo), Sequel[:foo].as(:id)).insert(7, 8){|r| h = r}
828
- h.must_equal(:id=>8, :foo=>7)
829
- end
830
- end
831
- end
832
-
833
- if DB.dataset.supports_returning?(:update) # Assume DELETE support as well
834
- describe "RETURNING clauses in UPDATE/DELETE" do
835
- before do
836
- @db = DB
837
- @db.create_table!(:i1){Integer :id; Integer :foo}
838
- @ds = @db[:i1]
839
- @ds.insert(1, 2)
840
- end
841
- after do
842
- @db.drop_table?(:i1)
843
- end
844
-
845
- it "should give correct results" do
846
- h = []
847
- @ds.returning(:foo).update(:id=>Sequel.+(:id, 1), :foo=>Sequel.*(:foo, 2)){|r| h << r}
848
- h.must_equal [{:foo=>4}]
849
- h.clear
850
- @ds.returning(:id).update(:id=>Sequel.+(:id, 1), :foo=>Sequel.*(:foo, 2)){|r| h << r}
851
- h.must_equal [{:id=>3}]
852
- h.clear
853
- @ds.returning.update(:id=>Sequel.+(:id, 1), :foo=>Sequel.*(:foo, 2)){|r| h << r}
854
- h.must_equal [{:id=>4, :foo=>16}]
855
- h.clear
856
- @ds.returning(Sequel[:id].as(:foo), Sequel[:foo].as(:id)).update(:id=>Sequel.+(:id, 1), :foo=>Sequel.*(:foo, 2)){|r| h << r}
857
- h.must_equal [{:id=>32, :foo=>5}]
858
- h.clear
859
-
860
- @ds.returning.delete{|r| h << r}
861
- h.must_equal [{:id=>5, :foo=>32}]
862
- h.clear
863
- @ds.returning.delete{|r| h << r}
864
- h.must_equal []
865
- end
866
- end
867
- end
868
-
869
- if DB.dataset.supports_window_functions?
870
- describe "Window Functions" do
871
- before(:all) do
872
- @db = DB
873
- @db.create_table!(:i1){Integer :id; Integer :group_id; Integer :amount}
874
- @ds = @db[:i1].order(:id)
875
- @ds.insert(:id=>1, :group_id=>1, :amount=>1)
876
- @ds.insert(:id=>2, :group_id=>1, :amount=>10)
877
- @ds.insert(:id=>3, :group_id=>1, :amount=>100)
878
- @ds.insert(:id=>4, :group_id=>2, :amount=>1000)
879
- @ds.insert(:id=>5, :group_id=>2, :amount=>10000)
880
- @ds.insert(:id=>6, :group_id=>2, :amount=>100000)
881
- end
882
- after(:all) do
883
- @db.drop_table?(:i1)
884
- end
885
-
886
- it "should give correct results for aggregate window functions" do
887
- @ds.select(:id){sum(:amount).over(:partition=>:group_id).as(:sum)}.all.
888
- must_equal [{:sum=>111, :id=>1}, {:sum=>111, :id=>2}, {:sum=>111, :id=>3}, {:sum=>111000, :id=>4}, {:sum=>111000, :id=>5}, {:sum=>111000, :id=>6}]
889
- @ds.select(:id){sum(:amount).over.as(:sum)}.all.
890
- must_equal [{:sum=>111111, :id=>1}, {:sum=>111111, :id=>2}, {:sum=>111111, :id=>3}, {:sum=>111111, :id=>4}, {:sum=>111111, :id=>5}, {:sum=>111111, :id=>6}]
891
- end
892
-
893
- it "should give correct results for ranking window functions with orders" do
894
- @ds.select(:id){rank.function.over(:partition=>:group_id, :order=>:id).as(:rank)}.all.
895
- must_equal [{:rank=>1, :id=>1}, {:rank=>2, :id=>2}, {:rank=>3, :id=>3}, {:rank=>1, :id=>4}, {:rank=>2, :id=>5}, {:rank=>3, :id=>6}]
896
- @ds.select(:id){rank.function.over(:order=>id).as(:rank)}.all.
897
- must_equal [{:rank=>1, :id=>1}, {:rank=>2, :id=>2}, {:rank=>3, :id=>3}, {:rank=>4, :id=>4}, {:rank=>5, :id=>5}, {:rank=>6, :id=>6}]
898
- end
899
-
900
- it "should give correct results for aggregate window functions with orders" do
901
- @ds.select(:id){sum(:amount).over(:partition=>:group_id, :order=>:id).as(:sum)}.all.
902
- must_equal [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1000, :id=>4}, {:sum=>11000, :id=>5}, {:sum=>111000, :id=>6}]
903
- @ds.select(:id){sum(:amount).over(:order=>:id).as(:sum)}.all.
904
- must_equal [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1111, :id=>4}, {:sum=>11111, :id=>5}, {:sum=>111111, :id=>6}]
905
- end
906
-
907
- it "should give correct results for aggregate window functions with frames" do
908
- @ds.select(:id){sum(:amount).over(:partition=>:group_id, :order=>:id, :frame=>:all).as(:sum)}.all.
909
- must_equal [{:sum=>111, :id=>1}, {:sum=>111, :id=>2}, {:sum=>111, :id=>3}, {:sum=>111000, :id=>4}, {:sum=>111000, :id=>5}, {:sum=>111000, :id=>6}]
910
- @ds.select(:id){sum(:amount).over(:order=>:id, :frame=>:all).as(:sum)}.all.
911
- must_equal [{:sum=>111111, :id=>1}, {:sum=>111111, :id=>2}, {:sum=>111111, :id=>3}, {:sum=>111111, :id=>4}, {:sum=>111111, :id=>5}, {:sum=>111111, :id=>6}]
912
-
913
- @ds.select(:id){sum(:amount).over(:partition=>:group_id, :order=>:id, :frame=>:rows).as(:sum)}.all.
914
- must_equal [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1000, :id=>4}, {:sum=>11000, :id=>5}, {:sum=>111000, :id=>6}]
915
- @ds.select(:id){sum(:amount).over(:order=>:id, :frame=>:rows).as(:sum)}.all.
916
- must_equal [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1111, :id=>4}, {:sum=>11111, :id=>5}, {:sum=>111111, :id=>6}]
917
- end
918
- end
919
- end
920
-
921
- describe Sequel::SQL::Constants do
922
- before do
923
- @db = DB
924
- @ds = @db[:constants]
925
- @c = proc do |v|
926
- case v
927
- when Time
928
- v
929
- when DateTime, String
930
- Time.parse(v.to_s)
931
- else
932
- v
933
- end
934
- end
935
- @c2 = proc{|v| v.is_a?(Date) ? v : Date.parse(v) }
936
- end
937
- after do
938
- @db.drop_table?(:constants)
939
- end
940
-
941
- cspecify "should have working CURRENT_DATE", [:jdbc, :sqlite], :oracle do
942
- @db.create_table!(:constants){Date :d}
943
- @ds.insert(:d=>Sequel::CURRENT_DATE)
944
- d = @c2[@ds.get(:d)]
945
- d.must_be_kind_of(Date)
946
- d.to_s.must_equal Date.today.to_s
947
- end
948
-
949
- cspecify "should have working CURRENT_TIME", [:jdbc, :sqlite], [:mysql2], [:tinytds], [:ado] do
950
- @db.create_table!(:constants){Time :t, :only_time=>true}
951
- @ds.insert(:t=>Sequel::CURRENT_TIME)
952
- (Time.now - @c[@ds.get(:t)]).must_be_close_to 0, 60
953
- end
954
-
955
- cspecify "should have working CURRENT_TIMESTAMP", [:jdbc, :sqlite] do
956
- @db.create_table!(:constants){DateTime :ts}
957
- @ds.insert(:ts=>Sequel::CURRENT_TIMESTAMP)
958
- (Time.now - @c[@ds.get(:ts)]).must_be_close_to 0, 60
959
- end
960
-
961
- cspecify "should have working CURRENT_TIMESTAMP when used as a column default", [:jdbc, :sqlite] do
962
- @db.create_table!(:constants){DateTime :ts, :default=>Sequel::CURRENT_TIMESTAMP}
963
- @ds.insert
964
- (Time.now - @c[@ds.get(:ts)]).must_be_close_to 0, 60
965
- end
966
- end
967
-
968
- describe "Sequel::Dataset#import and #multi_insert" do
969
- before(:all) do
970
- @db = DB
971
- @db.create_table!(:imp){Integer :i}
972
- @ids = @db[:imp].order(:i)
973
- end
974
- before do
975
- @ids.delete
976
- end
977
- after(:all) do
978
- @db.drop_table?(:imp)
979
- end
980
-
981
- it "should import with multi_insert and an array of hashes" do
982
- @ids.multi_insert([{:i=>10}, {:i=>20}])
983
- @ids.all.must_equal [{:i=>10}, {:i=>20}]
984
- end
985
-
986
- it "should import with an array of arrays of values" do
987
- @ids.import([:i], [[10], [20]])
988
- @ids.all.must_equal [{:i=>10}, {:i=>20}]
989
- end
990
-
991
- it "should import with a dataset" do
992
- @db.create_table!(:exp2){Integer :i}
993
- @db[:exp2].import([:i], [[10], [20]])
994
- @ids.import([:i], @db[:exp2])
995
- @ids.all.must_equal [{:i=>10}, {:i=>20}]
996
- @db.drop_table(:exp2)
997
- end
998
-
999
- it "should have import work with the :slice_size option" do
1000
- @ids.import([:i], [[10], [20], [30]], :slice_size=>1)
1001
- @ids.all.must_equal [{:i=>10}, {:i=>20}, {:i=>30}]
1002
- @ids.delete
1003
- @ids.import([:i], [[10], [20], [30]], :slice_size=>2)
1004
- @ids.all.must_equal [{:i=>10}, {:i=>20}, {:i=>30}]
1005
- @ids.delete
1006
- @ids.import([:i], [[10], [20], [30]], :slice_size=>3)
1007
- @ids.all.must_equal [{:i=>10}, {:i=>20}, {:i=>30}]
1008
- end
1009
-
1010
- it "should import many rows at once" do
1011
- @ids.import([:i], (1..1000).to_a.map{|x| [x]})
1012
- @ids.select_order_map(:i).must_equal((1..1000).to_a)
1013
- end
1014
- end
1015
-
1016
- describe "Sequel::Dataset#import and #multi_insert :return=>:primary_key " do
1017
- before do
1018
- @db = DB
1019
- @db.create_table!(:imp){primary_key :id; Integer :i}
1020
- @ds = @db[:imp]
1021
- end
1022
- after do
1023
- @db.drop_table?(:imp)
1024
- end
1025
-
1026
- it "should return primary key values" do
1027
- @ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key).must_equal [1, 2, 3]
1028
- @ds.import([:i], [[40], [50], [60]], :return=>:primary_key).must_equal [4, 5, 6]
1029
- @ds.order(:id).map([:id, :i]).must_equal [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
1030
- end
1031
-
1032
- it "should return primary key values when :slice is used" do
1033
- @ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key, :slice=>2).must_equal [1, 2, 3]
1034
- @ds.import([:i], [[40], [50], [60]], :return=>:primary_key, :slice=>2).must_equal [4, 5, 6]
1035
- @ds.order(:id).map([:id, :i]).must_equal [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
1036
- end
1037
- end
1038
-
1039
- describe "Sequel::Dataset convenience methods" do
1040
- before(:all) do
1041
- @db = DB
1042
- @db.create_table!(:a){Integer :a; Integer :b; Integer :c}
1043
- @ds = @db[:a]
1044
- @ds.insert(1, 3, 5)
1045
- @ds.insert(1, 3, 6)
1046
- @ds.insert(1, 4, 5)
1047
- @ds.insert(2, 3, 5)
1048
- @ds.insert(2, 4, 6)
1049
- end
1050
- after(:all) do
1051
- @db.drop_table?(:a)
1052
- end
1053
-
1054
- it "#group_rollup should include hierarchy of groupings" do
1055
- @ds.group_by(:a).group_rollup.select_map([:a, Sequel.function(:sum, :b).cast(Integer).as(:b), Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.map(&:to_i)}.must_equal [[nil, 17, 27], [1, 10, 16], [2, 7, 11]]
1056
- @ds.group_by(:a, :b).group_rollup.select_map([:a, :b, Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.map(&:to_i)}.must_equal [[nil, nil, 27], [1, nil, 16], [1, 3, 11], [1, 4, 5], [2, nil, 11], [2, 3, 5], [2, 4, 6]]
1057
- end if DB.dataset.supports_group_rollup?
1058
-
1059
- it "#group_cube should include all combinations of groupings" do
1060
- @ds.group_by(:a).group_cube.select_map([:a, Sequel.function(:sum, :b).cast(Integer).as(:b), Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.map(&:to_i)}.must_equal [[nil, 17, 27], [1, 10, 16], [2, 7, 11]]
1061
- @ds.group_by(:a, :b).group_cube.select_map([:a, :b, Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.map(&:to_i)}.must_equal [[nil, nil, 27], [nil, 3, 16], [nil, 4, 11], [1, nil, 16], [1, 3, 11], [1, 4, 5], [2, nil, 11], [2, 3, 5], [2, 4, 6]]
1062
- end if DB.dataset.supports_group_cube?
1063
-
1064
- it "#grouping_sets should include sets specified in group" do
1065
- @ds.group_by(:a, []).grouping_sets.select_map([:a, Sequel.function(:sum, :b).cast(Integer).as(:b), Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.map(&:to_i)}.must_equal [[nil, 17, 27], [1, 10, 16], [2, 7, 11]]
1066
- @ds.group_by([:a, :b], :a, :b, []).grouping_sets.select_map([:a, :b, Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.map(&:to_i)}.must_equal [[nil, nil, 27], [nil, 3, 16], [nil, 4, 11], [1, nil, 16], [1, 3, 11], [1, 4, 5], [2, nil, 11], [2, 3, 5], [2, 4, 6]]
1067
- end if DB.dataset.supports_grouping_sets?
1068
- end
1069
-
1070
- describe "Sequel::Dataset convenience methods" do
1071
- before(:all) do
1072
- @db = DB
1073
- @db.create_table!(:a){Integer :a; Integer :b}
1074
- @ds = @db[:a].order(:a)
1075
- end
1076
- before do
1077
- @ds.delete
1078
- end
1079
- after(:all) do
1080
- @db.drop_table?(:a)
1081
- end
1082
-
1083
- it "#empty? should return whether the dataset returns no rows" do
1084
- @ds.empty?.must_equal true
1085
- @ds.insert(20, 10)
1086
- @ds.empty?.must_equal false
1087
- end
1088
-
1089
- it "#empty? should work correctly for datasets with limits" do
1090
- ds = @ds.limit(1)
1091
- ds.empty?.must_equal true
1092
- ds.insert(20, 10)
1093
- ds.empty?.must_equal false
1094
- end
1095
-
1096
- it "#empty? should work correctly for datasets with limits and offsets" do
1097
- ds = @ds.limit(1, 1)
1098
- ds.empty?.must_equal true
1099
- ds.insert(20, 10)
1100
- ds.empty?.must_equal true
1101
- ds.insert(20, 10)
1102
- ds.empty?.must_equal false
1103
- end
1104
-
1105
- it "#group_and_count should return a grouping by count" do
1106
- @ds.group_and_count(:a).order{count(:a)}.all.must_equal []
1107
- @ds.insert(20, 10)
1108
- @ds.group_and_count(:a).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.must_equal [{:a=>20, :count=>1}]
1109
- @ds.insert(20, 30)
1110
- @ds.group_and_count(:a).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.must_equal [{:a=>20, :count=>2}]
1111
- @ds.insert(30, 30)
1112
- @ds.group_and_count(:a).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.must_equal [{:a=>30, :count=>1}, {:a=>20, :count=>2}]
1113
- end
1114
-
1115
- it "#group_and_count should support column aliases" do
1116
- @ds.group_and_count(Sequel[:a].as(:c)).order{count(:a)}.all.must_equal []
1117
- @ds.insert(20, 10)
1118
- @ds.group_and_count(Sequel[:a].as(:c)).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.must_equal [{:c=>20, :count=>1}]
1119
- @ds.insert(20, 30)
1120
- @ds.group_and_count(Sequel[:a].as(:c)).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.must_equal [{:c=>20, :count=>2}]
1121
- @ds.insert(30, 30)
1122
- @ds.group_and_count(Sequel[:a].as(:c)).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.must_equal [{:c=>30, :count=>1}, {:c=>20, :count=>2}]
1123
- end
1124
-
1125
- it "#range should return the range between the maximum and minimum values" do
1126
- @ds = @ds.unordered.extension(:sequel_4_dataset_methods)
1127
- @ds.insert(20, 10)
1128
- @ds.insert(30, 10)
1129
- @ds.range(:a).must_equal(20..30)
1130
- @ds.range(:b).must_equal(10..10)
1131
- end
1132
-
1133
- it "#interval should return the different between the maximum and minimum values" do
1134
- @ds = @ds.unordered.extension(:sequel_4_dataset_methods)
1135
- @ds.insert(20, 10)
1136
- @ds.insert(30, 10)
1137
- @ds.interval(:a).to_i.must_equal 10
1138
- @ds.interval(:b).to_i.must_equal 0
1139
- end
1140
- end
1141
-
1142
- describe "Sequel::Dataset main SQL methods" do
1143
- before(:all) do
1144
- @db = DB
1145
- @db.create_table!(:d){Integer :a; Integer :b}
1146
- @ds = @db[:d].order(:a)
1147
- end
1148
- before do
1149
- @ds.delete
1150
- end
1151
- after(:all) do
1152
- @db.drop_table?(:d)
1153
- end
1154
-
1155
- it "#exists should return a usable exists clause" do
1156
- @ds.filter(@db[Sequel[:d].as(:c)].filter(Sequel[:c][:a]=>Sequel[:d][:b]).exists).all.must_equal []
1157
- @ds.insert(20, 30)
1158
- @ds.insert(10, 20)
1159
- @ds.filter(@db[Sequel[:d].as(:c)].filter(Sequel[:c][:a]=>Sequel[:d][:b]).exists).all.must_equal [{:a=>10, :b=>20}]
1160
- end
1161
-
1162
- it "#filter and #exclude should work with placeholder strings" do
1163
- @ds.insert(20, 30)
1164
- @ds.filter(Sequel.lit("a > ?", 15)).all.must_equal [{:a=>20, :b=>30}]
1165
- @ds.exclude(Sequel.lit("b < ?", 15)).all.must_equal [{:a=>20, :b=>30}]
1166
- @ds.filter(Sequel.lit("b < ?", 15)).invert.all.must_equal [{:a=>20, :b=>30}]
1167
- end
1168
-
1169
- it "#where and #or should work correctly" do
1170
- @ds.insert(20, 30)
1171
- @ds.filter(:a=>20).where(:b=>30).all.must_equal [{:a=>20, :b=>30}]
1172
- @ds.filter(:a=>20).where(:b=>15).all.must_equal []
1173
- @ds.filter(:a=>20).or(:b=>15).all.must_equal [{:a=>20, :b=>30}]
1174
- @ds.filter(:a=>10).or(:b=>15).all.must_equal []
1175
- end
1176
-
1177
- it "#select_group should work correctly" do
1178
- @ds = @ds.unordered
1179
- @ds.select_group(:a).all.must_equal []
1180
- @ds.insert(20, 30)
1181
- @ds.select_group(:a).all.must_equal [{:a=>20}]
1182
- @ds.select_group(:b).all.must_equal [{:b=>30}]
1183
- @ds.insert(20, 40)
1184
- @ds.select_group(:a).all.must_equal [{:a=>20}]
1185
- @ds.order(:b).select_group(:b).all.must_equal [{:b=>30}, {:b=>40}]
1186
- end
1187
-
1188
- it "#select_group should work correctly when aliasing" do
1189
- @ds = @ds.unordered
1190
- @ds.insert(20, 30)
1191
- @ds.select_group(Sequel[:b].as(:c)).all.must_equal [{:c=>30}]
1192
- end
1193
-
1194
- it "#having should work correctly" do
1195
- @ds = @ds.unordered
1196
- @ds.select{[b, max(a).as(c)]}.group(:b).having{max(a) > 30}.all.must_equal []
1197
- @ds.insert(20, 30)
1198
- @ds.select{[b, max(a).as(c)]}.group(:b).having{max(a) > 30}.all.must_equal []
1199
- @ds.insert(40, 20)
1200
- @ds.select{[b, max(a).as(c)]}.group(:b).having{max(a) > 30}.all.each{|h| h[:c] = h[:c].to_i}.must_equal [{:b=>20, :c=>40}]
1201
- end
1202
-
1203
- cspecify "#having should work without a previous group", :sqlite do
1204
- @ds = @ds.unordered
1205
- @ds.select{max(a).as(c)}.having{max(a) > 30}.all.must_equal []
1206
- @ds.insert(20, 30)
1207
- @ds.select{max(a).as(c)}.having{max(a) > 30}.all.must_equal []
1208
- @ds.insert(40, 20)
1209
- @ds.select{max(a).as(c)}.having{max(a) > 30}.all.each{|h| h[:c] = h[:c].to_i}.must_equal [{:c=>40}]
1210
- end
1211
- end
1212
-
1213
- describe "Sequel::Dataset convenience methods" do
1214
- before(:all) do
1215
- @db = DB
1216
- @db.create_table!(:a){Integer :a; Integer :b; Integer :c; Integer :d}
1217
- @ds = @db[:a].order(:a)
1218
- end
1219
- before do
1220
- @ds.delete
1221
- @ds.insert(1, 2, 3, 4)
1222
- @ds.insert(5, 6, 7, 8)
1223
- end
1224
- after(:all) do
1225
- @db.drop_table?(:a)
1226
- end
1227
-
1228
- it "should have working #map" do
1229
- @ds.map(:a).must_equal [1, 5]
1230
- @ds.map(:b).must_equal [2, 6]
1231
- @ds.map([:a, :b]).must_equal [[1, 2], [5, 6]]
1232
- end
1233
-
1234
- it "should have working #as_hash" do
1235
- @ds.to_hash(:a).must_equal(1=>{:a=>1, :b=>2, :c=>3, :d=>4}, 5=>{:a=>5, :b=>6, :c=>7, :d=>8})
1236
- @ds.as_hash(:a).must_equal(1=>{:a=>1, :b=>2, :c=>3, :d=>4}, 5=>{:a=>5, :b=>6, :c=>7, :d=>8})
1237
- @ds.as_hash(:b).must_equal(2=>{:a=>1, :b=>2, :c=>3, :d=>4}, 6=>{:a=>5, :b=>6, :c=>7, :d=>8})
1238
- @ds.as_hash([:a, :b]).must_equal([1, 2]=>{:a=>1, :b=>2, :c=>3, :d=>4}, [5, 6]=>{:a=>5, :b=>6, :c=>7, :d=>8})
1239
-
1240
- @ds.as_hash(:a, :b).must_equal(1=>2, 5=>6)
1241
- @ds.as_hash([:a, :c], :b).must_equal([1, 3]=>2, [5, 7]=>6)
1242
- @ds.as_hash(:a, [:b, :c]).must_equal(1=>[2, 3], 5=>[6, 7])
1243
- @ds.as_hash([:a, :c], [:b, :d]).must_equal([1, 3]=>[2, 4], [5, 7]=>[6, 8])
1244
- @ds.extension(:null_dataset).nullify.as_hash([:a, :c], [:b, :d]).must_equal({})
1245
-
1246
- @ds.as_hash(:a, :b, :hash => (tmp = {})).must_be_same_as(tmp)
1247
- end
1248
-
1249
- it "should have working #to_hash_groups" do
1250
- ds = @ds.order(*@ds.columns)
1251
- ds.insert(1, 2, 3, 9)
1252
- ds.to_hash_groups(:a).must_equal(1=>[{:a=>1, :b=>2, :c=>3, :d=>4}, {:a=>1, :b=>2, :c=>3, :d=>9}], 5=>[{:a=>5, :b=>6, :c=>7, :d=>8}])
1253
- ds.to_hash_groups(:b).must_equal(2=>[{:a=>1, :b=>2, :c=>3, :d=>4}, {:a=>1, :b=>2, :c=>3, :d=>9}], 6=>[{:a=>5, :b=>6, :c=>7, :d=>8}])
1254
- ds.to_hash_groups([:a, :b]).must_equal([1, 2]=>[{:a=>1, :b=>2, :c=>3, :d=>4}, {:a=>1, :b=>2, :c=>3, :d=>9}], [5, 6]=>[{:a=>5, :b=>6, :c=>7, :d=>8}])
1255
-
1256
- ds.to_hash_groups(:a, :d).must_equal(1=>[4, 9], 5=>[8])
1257
- ds.to_hash_groups([:a, :c], :d).must_equal([1, 3]=>[4, 9], [5, 7]=>[8])
1258
- ds.to_hash_groups(:a, [:b, :d]).must_equal(1=>[[2, 4], [2, 9]], 5=>[[6, 8]])
1259
- ds.to_hash_groups([:a, :c], [:b, :d]).must_equal([1, 3]=>[[2, 4], [2, 9]], [5, 7]=>[[6, 8]])
1260
- @ds.extension(:null_dataset).nullify.to_hash_groups([:a, :c], [:b, :d]).must_equal({})
1261
-
1262
- ds.to_hash_groups(:a, :d, :hash => (tmp = {})).must_be_same_as(tmp)
1263
- end
1264
-
1265
- it "should have working #select_map" do
1266
- @ds.select_map(:a).must_equal [1, 5]
1267
- @ds.select_map(:b).must_equal [2, 6]
1268
- @ds.select_map([:a]).must_equal [[1], [5]]
1269
- @ds.select_map([:a, :b]).must_equal [[1, 2], [5, 6]]
1270
- @ds.extension(:null_dataset).nullify.select_map([:a, :b]).must_equal []
1271
-
1272
- @ds.select_map(Sequel[:a].as(:e)).must_equal [1, 5]
1273
- @ds.select_map(Sequel[:b].as(:e)).must_equal [2, 6]
1274
- @ds.select_map([Sequel[:a].as(:e), Sequel[:b].as(:f)]).must_equal [[1, 2], [5, 6]]
1275
- @ds.select_map([Sequel[:a][:a].as(:e), Sequel[:a][:b].as(:f)]).must_equal [[1, 2], [5, 6]]
1276
- @ds.select_map([Sequel.expr(Sequel[:a][:a]).as(:e), Sequel.expr(Sequel[:a][:b]).as(:f)]).must_equal [[1, 2], [5, 6]]
1277
- @ds.select_map([Sequel.qualify(:a, :a).as(:e), Sequel.qualify(:a, :b).as(:f)]).must_equal [[1, 2], [5, 6]]
1278
- @ds.select_map([Sequel.identifier(:a).qualify(:a).as(:e), Sequel.qualify(:a, :b).as(:f)]).must_equal [[1, 2], [5, 6]]
1279
- end
1280
-
1281
- it "should have working #select_order_map" do
1282
- @ds.select_order_map(:a).must_equal [1, 5]
1283
- @ds.select_order_map(Sequel.desc(Sequel[:a][:b])).must_equal [6, 2]
1284
- @ds.select_order_map(Sequel.desc(Sequel[:a][:b].as(:e))).must_equal [6, 2]
1285
- @ds.select_order_map(Sequel.qualify(:a, :b).as(:e)).must_equal [2, 6]
1286
- @ds.select_order_map([:a]).must_equal [[1], [5]]
1287
- @ds.select_order_map([Sequel.desc(:a), :b]).must_equal [[5, 6], [1, 2]]
1288
- @ds.extension(:null_dataset).nullify.select_order_map(:a).must_equal []
1289
-
1290
- @ds.select_order_map(Sequel[:a].as(:e)).must_equal [1, 5]
1291
- @ds.select_order_map(Sequel[:b].as(:e)).must_equal [2, 6]
1292
- @ds.select_order_map([Sequel.desc(Sequel[:a].as(:e)), Sequel[:b].as(:f)]).must_equal [[5, 6], [1, 2]]
1293
- @ds.select_order_map([Sequel.desc(Sequel[:a][:a].as(:e)), Sequel[:a][:b].as(:f)]).must_equal [[5, 6], [1, 2]]
1294
- @ds.select_order_map([Sequel.desc(Sequel[:a][:a]), Sequel.expr(Sequel[:a][:b]).as(:f)]).must_equal [[5, 6], [1, 2]]
1295
- @ds.select_order_map([Sequel.qualify(:a, :a).desc, Sequel.qualify(:a, :b).as(:f)]).must_equal [[5, 6], [1, 2]]
1296
- @ds.select_order_map([Sequel.identifier(:a).qualify(:a).desc, Sequel.qualify(:a, :b).as(:f)]).must_equal [[5, 6], [1, 2]]
1297
- end
1298
-
1299
- it "should have working #select_hash" do
1300
- @ds.select_hash(:a, :b).must_equal(1=>2, 5=>6)
1301
- @ds.select_hash(Sequel[:a][:a].as(:e), :b).must_equal(1=>2, 5=>6)
1302
- @ds.select_hash(Sequel.expr(Sequel[:a][:a]).as(:e), :b).must_equal(1=>2, 5=>6)
1303
- @ds.select_hash(Sequel.qualify(:a, :a).as(:e), :b).must_equal(1=>2, 5=>6)
1304
- @ds.select_hash(Sequel.identifier(:a).qualify(:a).as(:e), :b).must_equal(1=>2, 5=>6)
1305
- @ds.select_hash([:a, :c], :b).must_equal([1, 3]=>2, [5, 7]=>6)
1306
- @ds.select_hash(:a, [:b, :c]).must_equal(1=>[2, 3], 5=>[6, 7])
1307
- @ds.select_hash([:a, :c], [:b, :d]).must_equal([1, 3]=>[2, 4], [5, 7]=>[6, 8])
1308
- @ds.select_hash(:a, :b, :hash => (tmp = {})).must_be_same_as(tmp)
1309
- @ds.extension(:null_dataset).nullify.select_hash(:a, :b).must_equal({})
1310
- end
1311
-
1312
- it "should have working #select_hash_groups" do
1313
- ds = @ds.order(*@ds.columns)
1314
- ds.insert(1, 2, 3, 9)
1315
- ds.select_hash_groups(:a, :d).must_equal(1=>[4, 9], 5=>[8])
1316
- ds.select_hash_groups(Sequel[:a][:a].as(:e), :d).must_equal(1=>[4, 9], 5=>[8])
1317
- ds.select_hash_groups(Sequel.expr(Sequel[:a][:a]).as(:e), :d).must_equal(1=>[4, 9], 5=>[8])
1318
- ds.select_hash_groups(Sequel.qualify(:a, :a).as(:e), :d).must_equal(1=>[4, 9], 5=>[8])
1319
- ds.select_hash_groups(Sequel.identifier(:a).qualify(:a).as(:e), :d).must_equal(1=>[4, 9], 5=>[8])
1320
- ds.select_hash_groups([:a, :c], :d).must_equal([1, 3]=>[4, 9], [5, 7]=>[8])
1321
- ds.select_hash_groups(:a, [:b, :d]).must_equal(1=>[[2, 4], [2, 9]], 5=>[[6, 8]])
1322
- ds.select_hash_groups([:a, :c], [:b, :d]).must_equal([1, 3]=>[[2, 4], [2, 9]], [5, 7]=>[[6, 8]])
1323
- ds.select_hash_groups(:a, :d, :hash => (tmp = {})).must_be_same_as(tmp)
1324
- @ds.extension(:null_dataset).nullify.select_hash_groups(:a, :d).must_equal({})
1325
- end
1326
- end
1327
-
1328
- describe "Sequel::Dataset DSL support" do
1329
- before(:all) do
1330
- @db = DB
1331
- @db.create_table!(:a){Integer :a; Integer :b}
1332
- @ds = @db[:a].order(:a)
1333
- end
1334
- before do
1335
- @ds.delete
1336
- end
1337
- after(:all) do
1338
- @db.drop_table?(:a)
1339
- end
1340
-
1341
- it "should work with standard mathematical operators" do
1342
- @ds.insert(20, 10)
1343
- @ds.get{a + b}.to_i.must_equal 30
1344
- @ds.get{a - b}.to_i.must_equal 10
1345
- @ds.get{a * b}.to_i.must_equal 200
1346
- @ds.get{a / b}.to_i.must_equal 2
1347
- end
1348
-
1349
- it "should work with exponentiation operator" do
1350
- @ds.insert(:a=>2)
1351
- (-4..4).each do |i|
1352
- # Allow minor differences due to emulation issues on some adapters
1353
- @ds.get{(a / 1.0) ** i}.to_f.must_be_close_to((2**i).to_f)
1354
- end
1355
- end
1356
-
1357
- cspecify "should work with bitwise shift operators", :derby do
1358
- @ds.insert(3, 2)
1359
- b = Sequel[:b]
1360
- b = b.cast(:integer) if @db.database_type == :postgres
1361
- @ds.get{a.sql_number << b}.to_i.must_equal 12
1362
- @ds.get{a.sql_number >> b}.to_i.must_equal 0
1363
- @ds.get{a.sql_number << b << 1}.to_i.must_equal 24
1364
- @ds.delete
1365
- @ds.insert(3, 1)
1366
- @ds.get{a.sql_number << b}.to_i.must_equal 6
1367
- @ds.get{a.sql_number >> b}.to_i.must_equal 1
1368
- @ds.get{a.sql_number >> b >> 1}.to_i.must_equal 0
1369
- end
1370
-
1371
- cspecify "should work with bitwise AND and OR operators", :derby do
1372
- @ds.insert(3, 5)
1373
- @ds.get{a.sql_number | b}.to_i.must_equal 7
1374
- @ds.get{a.sql_number & b}.to_i.must_equal 1
1375
- @ds.get{a.sql_number | b | 8}.to_i.must_equal 15
1376
- @ds.get{a.sql_number & b & 8}.to_i.must_equal 0
1377
- end
1378
-
1379
- it "should work with the bitwise compliment operator" do
1380
- @ds.insert(-3, 3)
1381
- @ds.get{~a.sql_number}.to_i.must_equal 2
1382
- @ds.get{~b.sql_number}.to_i.must_equal(-4)
1383
- end
1384
-
1385
- cspecify "should work with the bitwise xor operator", :derby do
1386
- @ds.insert(3, 5)
1387
- @ds.get{a.sql_number ^ b}.to_i.must_equal 6
1388
- @ds.get{a.sql_number ^ b ^ 1}.to_i.must_equal 7
1389
- end
1390
-
1391
- it "should work with the modulus operator" do
1392
- @ds.insert(3, 5)
1393
- @ds.get{a.sql_number % 4}.to_i.must_equal 3
1394
- @ds.get{b.sql_number % 4}.to_i.must_equal 1
1395
- @ds.get{a.sql_number % 4 % 2}.to_i.must_equal 1
1396
- end
1397
-
1398
- it "should work with inequality operators" do
1399
- @ds.insert(10, 11)
1400
- @ds.insert(11, 11)
1401
- @ds.insert(20, 19)
1402
- @ds.insert(20, 20)
1403
- @ds.filter{a > b}.select_order_map(:a).must_equal [20]
1404
- @ds.filter{a >= b}.select_order_map(:a).must_equal [11, 20, 20]
1405
- @ds.filter{a < b}.select_order_map(:a).must_equal [10]
1406
- @ds.filter{a <= b}.select_order_map(:a).must_equal [10, 11, 20]
1407
- end
1408
-
1409
- it "should work with casting and string concatentation" do
1410
- @ds.insert(20, 20)
1411
- @ds.get{Sequel.cast(a, String).sql_string + Sequel.cast(b, String)}.must_equal '2020'
1412
- end
1413
-
1414
- it "should work with ordering" do
1415
- @ds.insert(10, 20)
1416
- @ds.insert(20, 10)
1417
- @ds.order(:a, :b).all.must_equal [{:a=>10, :b=>20}, {:a=>20, :b=>10}]
1418
- @ds.order(Sequel.asc(:a), Sequel.asc(:b)).all.must_equal [{:a=>10, :b=>20}, {:a=>20, :b=>10}]
1419
- @ds.order(Sequel.desc(:a), Sequel.desc(:b)).all.must_equal [{:a=>20, :b=>10}, {:a=>10, :b=>20}]
1420
- end
1421
-
1422
- it "should work with qualifying" do
1423
- @ds.insert(10, 20)
1424
- @ds.get(Sequel[:a][:b]).must_equal 20
1425
- @ds.get{a[:b]}.must_equal 20
1426
- @ds.get(Sequel.qualify(:a, :b)).must_equal 20
1427
- end
1428
-
1429
- it "should work with aliasing" do
1430
- @ds.insert(10, 20)
1431
- @ds.get(Sequel[:a][:b].as(:c)).must_equal 20
1432
- @ds.get{a[:b].as(c)}.must_equal 20
1433
- @ds.get(Sequel.qualify(:a, :b).as(:c)).must_equal 20
1434
- @ds.get(Sequel.as(:b, :c)).must_equal 20
1435
- end
1436
-
1437
- it "should work with selecting all columns of a table" do
1438
- @ds.insert(20, 10)
1439
- @ds.select_all(:a).all.must_equal [{:a=>20, :b=>10}]
1440
- end
1441
-
1442
- it "should work with ranges as hash values" do
1443
- @ds.insert(20, 10)
1444
- @ds.filter(:a=>(10..30)).all.must_equal [{:a=>20, :b=>10}]
1445
- @ds.filter(:a=>(25..30)).all.must_equal []
1446
- @ds.filter(:a=>(10..15)).all.must_equal []
1447
- @ds.exclude(:a=>(10..30)).all.must_equal []
1448
- @ds.exclude(:a=>(25..30)).all.must_equal [{:a=>20, :b=>10}]
1449
- @ds.exclude(:a=>(10..15)).all.must_equal [{:a=>20, :b=>10}]
1450
- end
1451
-
1452
- it "should work with nil as hash value" do
1453
- @ds.insert(20, nil)
1454
- @ds.filter(:a=>nil).all.must_equal []
1455
- @ds.filter(:b=>nil).all.must_equal [{:a=>20, :b=>nil}]
1456
- @ds.exclude(:b=>nil).all.must_equal []
1457
- @ds.exclude(:a=>nil).all.must_equal [{:a=>20, :b=>nil}]
1458
- end
1459
-
1460
- it "should work with arrays as hash values" do
1461
- @ds.insert(20, 10)
1462
- @ds.filter(:a=>[10]).all.must_equal []
1463
- @ds.filter(:a=>[20, 10]).all.must_equal [{:a=>20, :b=>10}]
1464
- @ds.exclude(:a=>[10]).all.must_equal [{:a=>20, :b=>10}]
1465
- @ds.exclude(:a=>[20, 10]).all.must_equal []
1466
- end
1467
-
1468
- it "should work with ranges as hash values" do
1469
- @ds.insert(20, 10)
1470
- @ds.filter(:a=>(10..30)).all.must_equal [{:a=>20, :b=>10}]
1471
- @ds.filter(:a=>(25..30)).all.must_equal []
1472
- @ds.filter(:a=>(10..15)).all.must_equal []
1473
- @ds.exclude(:a=>(10..30)).all.must_equal []
1474
- @ds.exclude(:a=>(25..30)).all.must_equal [{:a=>20, :b=>10}]
1475
- @ds.exclude(:a=>(10..15)).all.must_equal [{:a=>20, :b=>10}]
1476
- end
1477
-
1478
- it "should work with CASE statements" do
1479
- @ds.insert(20, 10)
1480
- @ds.filter(Sequel.case({{:a=>20}=>20}, 0) > 0).all.must_equal [{:a=>20, :b=>10}]
1481
- @ds.filter(Sequel.case({{:a=>15}=>20}, 0) > 0).all.must_equal []
1482
- @ds.filter(Sequel.case({20=>20}, 0, :a) > 0).all.must_equal [{:a=>20, :b=>10}]
1483
- @ds.filter(Sequel.case({15=>20}, 0, :a) > 0).all.must_equal []
1484
- end
1485
-
1486
- it "should work with multiple value arrays" do
1487
- @ds.insert(20, 10)
1488
- @ds.filter([:a, :b]=>[[20, 10]]).all.must_equal [{:a=>20, :b=>10}]
1489
- @ds.filter([:a, :b]=>[[10, 20]]).all.must_equal []
1490
- @ds.filter([:a, :b]=>[[20, 10], [1, 2]]).all.must_equal [{:a=>20, :b=>10}]
1491
- @ds.filter([:a, :b]=>[[10, 10], [20, 20]]).all.must_equal []
1492
-
1493
- @ds.exclude([:a, :b]=>[[20, 10]]).all.must_equal []
1494
- @ds.exclude([:a, :b]=>[[10, 20]]).all.must_equal [{:a=>20, :b=>10}]
1495
- @ds.exclude([:a, :b]=>[[20, 10], [1, 2]]).all.must_equal []
1496
- @ds.exclude([:a, :b]=>[[10, 10], [20, 20]]).all.must_equal [{:a=>20, :b=>10}]
1497
- end
1498
-
1499
- it "should work with IN/NOT in with datasets" do
1500
- @ds.insert(20, 10)
1501
- ds = @ds.unordered
1502
-
1503
- @ds.filter(:a=>ds.select(:a)).all.must_equal [{:a=>20, :b=>10}]
1504
- @ds.filter(:a=>ds.select(:a).where(:a=>15)).all.must_equal []
1505
- @ds.exclude(:a=>ds.select(:a)).all.must_equal []
1506
- @ds.exclude(:a=>ds.select(:a).where(:a=>15)).all.must_equal [{:a=>20, :b=>10}]
1507
-
1508
- @ds.filter([:a, :b]=>ds.select(:a, :b)).all.must_equal [{:a=>20, :b=>10}]
1509
- @ds.filter([:a, :b]=>ds.select(:b, :a)).all.must_equal []
1510
- @ds.exclude([:a, :b]=>ds.select(:a, :b)).all.must_equal []
1511
- @ds.exclude([:a, :b]=>ds.select(:b, :a)).all.must_equal [{:a=>20, :b=>10}]
1512
-
1513
- @ds.filter([:a, :b]=>ds.select(:a, :b).where(:a=>15)).all.must_equal []
1514
- @ds.exclude([:a, :b]=>ds.select(:a, :b).where(:a=>15)).all.must_equal [{:a=>20, :b=>10}]
1515
- end
1516
-
1517
- it "should work empty arrays" do
1518
- @ds.insert(20, 10)
1519
- @ds.filter(:a=>[]).all.must_equal []
1520
- @ds.exclude(:a=>[]).all.must_equal [{:a=>20, :b=>10}]
1521
- @ds.filter([:a, :b]=>[]).all.must_equal []
1522
- @ds.exclude([:a, :b]=>[]).all.must_equal [{:a=>20, :b=>10}]
1523
- end
1524
-
1525
- it "should work empty arrays with nulls when using empty_array_consider_nulls extension" do
1526
- @ds = @ds.extension(:empty_array_consider_nulls)
1527
- @ds.insert(nil, nil)
1528
- @ds.filter(:a=>[]).all.must_equal []
1529
- @ds.exclude(:a=>[]).all.must_equal []
1530
- @ds.filter([:a, :b]=>[]).all.must_equal []
1531
- @ds.exclude([:a, :b]=>[]).all.must_equal []
1532
-
1533
- unless Sequel.guarded?(:mssql, :oracle, :db2, :sqlanywhere)
1534
- # Some databases don't like boolean results in the select list
1535
- pr = proc{|r| r.is_a?(Integer) ? (r != 0) : r}
1536
- pr[@ds.get(Sequel.expr(:a=>[]))].must_be_nil
1537
- pr[@ds.get(~Sequel.expr(:a=>[]))].must_be_nil
1538
- pr[@ds.get(Sequel.expr([:a, :b]=>[]))].must_be_nil
1539
- pr[@ds.get(~Sequel.expr([:a, :b]=>[]))].must_be_nil
1540
- end
1541
- end
1542
-
1543
- it "should work empty arrays with nulls" do
1544
- ds = @ds
1545
- ds.insert(nil, nil)
1546
- ds.filter(:a=>[]).all.must_equal []
1547
- ds.exclude(:a=>[]).all.must_equal [{:a=>nil, :b=>nil}]
1548
- ds.filter([:a, :b]=>[]).all.must_equal []
1549
- ds.exclude([:a, :b]=>[]).all.must_equal [{:a=>nil, :b=>nil}]
1550
-
1551
- unless Sequel.guarded?(:mssql, :oracle, :db2, :sqlanywhere)
1552
- # Some databases don't like boolean results in the select list
1553
- pr = proc{|r| r.is_a?(Integer) ? (r != 0) : r}
1554
- pr[ds.get(Sequel.expr(:a=>[]))].must_equal false
1555
- pr[ds.get(~Sequel.expr(:a=>[]))].must_equal true
1556
- pr[ds.get(Sequel.expr([:a, :b]=>[]))].must_equal false
1557
- pr[ds.get(~Sequel.expr([:a, :b]=>[]))].must_equal true
1558
- end
1559
- end
1560
-
1561
- it "should work multiple conditions" do
1562
- @ds.insert(20, 10)
1563
- @ds.filter(:a=>20, :b=>10).all.must_equal [{:a=>20, :b=>10}]
1564
- @ds.filter([[:a, 20], [:b, 10]]).all.must_equal [{:a=>20, :b=>10}]
1565
- @ds.filter(Sequel.&({:a=>20}, {:b=>10})).all.must_equal [{:a=>20, :b=>10}]
1566
- @ds.filter(Sequel.|({:a=>20}, {:b=>5})).all.must_equal [{:a=>20, :b=>10}]
1567
- @ds.filter(Sequel.~(:a=>10)).all.must_equal [{:a=>20, :b=>10}]
1568
- end
1569
- end
1570
-
1571
- describe "SQL Extract Function" do
1572
- before do
1573
- @db = DB
1574
- @db.create_table!(:a){DateTime :a}
1575
- @ds = @db[:a].order(:a)
1576
- end
1577
- after do
1578
- @db.drop_table?(:a)
1579
- end
1580
-
1581
- it "should return the part of the datetime asked for" do
1582
- t = Time.now
1583
- @ds = @ds.with_extend{def supports_timestamp_timezones?() false end}
1584
- @ds.insert(t)
1585
- @ds.get{a.extract(:year)}.must_equal t.year
1586
- @ds.get{a.extract(:month)}.must_equal t.month
1587
- @ds.get{a.extract(:day)}.must_equal t.day
1588
- @ds.get{a.extract(:hour)}.must_equal t.hour
1589
- @ds.get{a.extract(:minute)}.must_equal t.min
1590
- @ds.get{a.extract(:second)}.to_i.must_equal t.sec
1591
- end
1592
- end
1593
-
1594
- describe "Dataset string methods" do
1595
- before(:all) do
1596
- @db = DB
1597
- csc = {}
1598
- cic = {}
1599
- if @db.database_type == :mssql
1600
- csc[:collate] = 'Latin1_General_CS_AS'
1601
- cic[:collate] = 'Latin1_General_CI_AS'
1602
- end
1603
- @db.create_table!(:a) do
1604
- String :a, csc
1605
- String :b, cic
1606
- end
1607
- @ds = @db[:a].order(:a)
1608
- end
1609
- before do
1610
- @ds.delete
1611
- end
1612
- after(:all) do
1613
- @db.drop_table?(:a)
1614
- end
1615
-
1616
- it "#grep should return matching rows" do
1617
- @ds.insert('foo', 'bar')
1618
- @ds.grep(:a, 'foo').all.must_equal [{:a=>'foo', :b=>'bar'}]
1619
- @ds.grep(:b, 'foo').all.must_equal []
1620
- @ds.grep(:b, 'bar').all.must_equal [{:a=>'foo', :b=>'bar'}]
1621
- @ds.grep(:a, 'bar').all.must_equal []
1622
- @ds.grep([:a, :b], %w'foo bar').all.must_equal [{:a=>'foo', :b=>'bar'}]
1623
- @ds.grep([:a, :b], %w'boo far').all.must_equal []
1624
- end
1625
-
1626
- it "#grep should work with :all_patterns and :all_columns options" do
1627
- @ds.insert('foo bar', ' ')
1628
- @ds.insert('foo d', 'bar')
1629
- @ds.insert('foo e', ' ')
1630
- @ds.insert(' ', 'bar')
1631
- @ds.insert('foo f', 'baz')
1632
- @ds.insert('foo baz', 'bar baz')
1633
- @ds.insert('foo boo', 'boo foo')
1634
-
1635
- @ds.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true).all.must_equal [{:a=>'foo bar', :b=>' '}, {:a=>'foo baz', :b=>'bar baz'}, {:a=>'foo d', :b=>'bar'}]
1636
- @ds.grep([:a, :b], %w'%foo% %bar% %blob%', :all_patterns=>true).all.must_equal []
1637
-
1638
- @ds.grep([:a, :b], %w'%bar% %foo%', :all_columns=>true).all.must_equal [{:a=>"foo baz", :b=>"bar baz"}, {:a=>"foo boo", :b=>"boo foo"}, {:a=>"foo d", :b=>"bar"}]
1639
- @ds.grep([:a, :b], %w'%baz%', :all_columns=>true).all.must_equal [{:a=>'foo baz', :b=>'bar baz'}]
1640
-
1641
- @ds.grep([:a, :b], %w'%baz% %foo%', :all_columns=>true, :all_patterns=>true).all.must_equal []
1642
- @ds.grep([:a, :b], %w'%boo% %foo%', :all_columns=>true, :all_patterns=>true).all.must_equal [{:a=>'foo boo', :b=>'boo foo'}]
1643
- end
1644
-
1645
- it "#like should return matching rows" do
1646
- @ds.insert('foo', 'bar')
1647
- @ds.filter(Sequel.expr(:a).like('foo')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1648
- @ds.filter(Sequel.expr(:a).like('bar')).all.must_equal []
1649
- @ds.filter(Sequel.expr(:a).like('foo', 'bar')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1650
- @ds.exclude(Sequel.expr(:a).like('foo')).all.must_equal []
1651
- @ds.exclude(Sequel.expr(:a).like('bar')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1652
- @ds.exclude(Sequel.expr(:a).like('foo', 'bar')).all.must_equal []
1653
- end
1654
-
1655
- it "#like should be case sensitive" do
1656
- @ds.insert('foo', 'bar')
1657
- @ds.filter(Sequel.expr(:a).like('Foo')).all.must_equal []
1658
- @ds.filter(Sequel.expr(:b).like('baR')).all.must_equal []
1659
- @ds.filter(Sequel.expr(:a).like('FOO', 'BAR')).all.must_equal []
1660
- @ds.exclude(Sequel.expr(:a).like('Foo')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1661
- @ds.exclude(Sequel.expr(:b).like('baR')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1662
- @ds.exclude(Sequel.expr(:a).like('FOO', 'BAR')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1663
- end
1664
-
1665
- it "#ilike should return matching rows, in a case insensitive manner" do
1666
- @ds.insert('foo', 'bar')
1667
- @ds.filter(Sequel.expr(:a).ilike('Foo')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1668
- @ds.filter(Sequel.expr(:a).ilike('baR')).all.must_equal []
1669
- @ds.filter(Sequel.expr(:a).ilike('FOO', 'BAR')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1670
- @ds.exclude(Sequel.expr(:a).ilike('Foo')).all.must_equal []
1671
- @ds.exclude(Sequel.expr(:a).ilike('baR')).all.must_equal [{:a=>'foo', :b=>'bar'}]
1672
- @ds.exclude(Sequel.expr(:a).ilike('FOO', 'BAR')).all.must_equal []
1673
- end
1674
-
1675
- it "#escape_like should escape any metacharacters" do
1676
- @ds.insert('foo', 'bar')
1677
- @ds.insert('foo.', 'bar..')
1678
- @ds.insert('foo\\..', 'bar\\..')
1679
- @ds.insert('foo\\_', 'bar\\%')
1680
- @ds.insert('foo_', 'bar%')
1681
- @ds.insert('foo_.', 'bar%.')
1682
- @ds.insert('foo_..', 'bar%..')
1683
- @ds.insert('[f#*?oo_]', '[bar%]')
1684
- @ds.filter(Sequel.expr(:a).like(@ds.escape_like('foo_'))).select_order_map(:a).must_equal ['foo_']
1685
- @ds.filter(Sequel.expr(:b).like(@ds.escape_like('bar%'))).select_order_map(:b).must_equal ['bar%']
1686
- @ds.filter(Sequel.expr(:a).like(@ds.escape_like('foo\\_'))).select_order_map(:a).must_equal ['foo\\_']
1687
- @ds.filter(Sequel.expr(:b).like(@ds.escape_like('bar\\%'))).select_order_map(:b).must_equal ['bar\\%']
1688
- @ds.filter(Sequel.expr(:a).like(@ds.escape_like('[f#*?oo_]'))).select_order_map(:a).must_equal ['[f#*?oo_]']
1689
- @ds.filter(Sequel.expr(:b).like(@ds.escape_like('[bar%]'))).select_order_map(:b).must_equal ['[bar%]']
1690
- @ds.filter(Sequel.expr(:b).like("#{@ds.escape_like('bar%')}_")).select_order_map(:b).must_equal ['bar%.']
1691
- @ds.filter(Sequel.expr(:b).like("#{@ds.escape_like('bar%')}%")).select_order_map(:b).must_equal ['bar%', 'bar%.', 'bar%..']
1692
-
1693
- @ds.filter(Sequel.expr(:a).ilike(@ds.escape_like('Foo_'))).select_order_map(:a).must_equal ['foo_']
1694
- @ds.filter(Sequel.expr(:b).ilike(@ds.escape_like('Bar%'))).select_order_map(:b).must_equal ['bar%']
1695
- @ds.filter(Sequel.expr(:a).ilike(@ds.escape_like('Foo\\_'))).select_order_map(:a).must_equal ['foo\\_']
1696
- @ds.filter(Sequel.expr(:b).ilike(@ds.escape_like('Bar\\%'))).select_order_map(:b).must_equal ['bar\\%']
1697
- @ds.filter(Sequel.expr(:a).ilike(@ds.escape_like('[F#*?oo_]'))).select_order_map(:a).must_equal ['[f#*?oo_]']
1698
- @ds.filter(Sequel.expr(:b).ilike(@ds.escape_like('[Bar%]'))).select_order_map(:b).must_equal ['[bar%]']
1699
- @ds.filter(Sequel.expr(:b).ilike("#{@ds.escape_like('Bar%')}_")).select_order_map(:b).must_equal ['bar%.']
1700
- @ds.filter(Sequel.expr(:b).ilike("#{@ds.escape_like('Bar%')}%")).select_order_map(:b).must_equal ['bar%', 'bar%.', 'bar%..']
1701
- end
1702
-
1703
- if DB.dataset.supports_regexp?
1704
- it "#like with regexp return matching rows" do
1705
- @ds.insert('foo', 'bar')
1706
- @ds.filter(Sequel.expr(:a).like(/fo/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1707
- @ds.filter(Sequel.expr(:a).like(/fo$/)).all.must_equal []
1708
- @ds.filter(Sequel.expr(:a).like(/fo/, /ar/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1709
- @ds.exclude(Sequel.expr(:a).like(/fo/)).all.must_equal []
1710
- @ds.exclude(Sequel.expr(:a).like(/fo$/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1711
- @ds.exclude(Sequel.expr(:a).like(/fo/, /ar/)).all.must_equal []
1712
- end
1713
-
1714
- it "#like with regexp should be case sensitive if regexp is case sensitive" do
1715
- @ds.insert('foo', 'bar')
1716
- @ds.filter(Sequel.expr(:a).like(/Fo/)).all.must_equal []
1717
- @ds.filter(Sequel.expr(:b).like(/baR/)).all.must_equal []
1718
- @ds.filter(Sequel.expr(:a).like(/FOO/, /BAR/)).all.must_equal []
1719
- @ds.exclude(Sequel.expr(:a).like(/Fo/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1720
- @ds.exclude(Sequel.expr(:b).like(/baR/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1721
- @ds.exclude(Sequel.expr(:a).like(/FOO/, /BAR/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1722
-
1723
- @ds.filter(Sequel.expr(:a).like(/Fo/i)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1724
- @ds.filter(Sequel.expr(:b).like(/baR/i)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1725
- @ds.filter(Sequel.expr(:a).like(/FOO/i, /BAR/i)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1726
- @ds.exclude(Sequel.expr(:a).like(/Fo/i)).all.must_equal []
1727
- @ds.exclude(Sequel.expr(:b).like(/baR/i)).all.must_equal []
1728
- @ds.exclude(Sequel.expr(:a).like(/FOO/i, /BAR/i)).all.must_equal []
1729
- end
1730
-
1731
- it "#ilike with regexp should return matching rows, in a case insensitive manner" do
1732
- @ds.insert('foo', 'bar')
1733
- @ds.filter(Sequel.expr(:a).ilike(/Fo/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1734
- @ds.filter(Sequel.expr(:b).ilike(/baR/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1735
- @ds.filter(Sequel.expr(:a).ilike(/FOO/, /BAR/)).all.must_equal [{:a=>'foo', :b=>'bar'}]
1736
- @ds.exclude(Sequel.expr(:a).ilike(/Fo/)).all.must_equal []
1737
- @ds.exclude(Sequel.expr(:b).ilike(/baR/)).all.must_equal []
1738
- @ds.exclude(Sequel.expr(:a).ilike(/FOO/, /BAR/)).all.must_equal []
1739
- end
1740
- end
1741
-
1742
- it "should work with strings created with Sequel.join" do
1743
- @ds.insert('foo', 'bar')
1744
- @ds.get(Sequel.join([:a, "bar"])).must_equal 'foobar'
1745
- @ds.get(Sequel.join(["foo", :b], ' ')).must_equal 'foo bar'
1746
- end
1747
- end
1748
-
1749
- describe "Dataset identifier methods" do
1750
- before(:all) do
1751
- class ::String
1752
- def uprev
1753
- upcase.reverse
1754
- end
1755
- end
1756
- @db = DB
1757
- @db.create_table!(:a){Integer :ab}
1758
- @db[:a].insert(1)
1759
- end
1760
- before do
1761
- @ds = @db[:a].order(:ab)
1762
- end
1763
- after(:all) do
1764
- @db.drop_table?(:a)
1765
- end
1766
-
1767
- it "#identifier_output_method should change how identifiers are output" do
1768
- @ds.with_identifier_output_method(:upcase).first.must_equal(:AB=>1)
1769
- @ds.with_identifier_output_method(:uprev).first.must_equal(:BA=>1)
1770
- end
1771
-
1772
- it "should work with a nil identifier_output_method" do
1773
- [{:ab=>1}, {:AB=>1}].must_include(@ds.with_identifier_output_method(nil).first)
1774
- end
1775
-
1776
- it "should work when not quoting identifiers" do
1777
- @ds.with_quote_identifiers(false).first.must_equal(:ab=>1)
1778
- end
1779
- end if IDENTIFIER_MANGLING
1780
-
1781
- if DB.dataset.supports_modifying_joins?
1782
- describe "Modifying joined datasets" do
1783
- before do
1784
- @db = DB
1785
- @db.create_table!(:a){Integer :a; Integer :d}
1786
- @db.create_table!(:b){Integer :b; Integer :e}
1787
- @db.create_table!(:c){Integer :c; Integer :f}
1788
- @ds = @db.from(:a, :b).join(:c, {:c=>Sequel.identifier(:e)}, :qualify=>:symbol).where(:d=>:b, :f=>6)
1789
- @db[:a].insert(1, 2)
1790
- @db[:a].insert(3, 4)
1791
- @db[:b].insert(2, 5)
1792
- @db[:c].insert(5, 6)
1793
- @db[:b].insert(4, 7)
1794
- @db[:c].insert(7, 8)
1795
- end
1796
- after do
1797
- @db.drop_table?(:a, :b, :c)
1798
- end
1799
-
1800
- it "#update should allow updating joined datasets" do
1801
- @ds.update(:a=>10)
1802
- @ds.all.must_equal [{:c=>5, :b=>2, :a=>10, :d=>2, :e=>5, :f=>6}]
1803
- @db[:a].order(:a).all.must_equal [{:a=>3, :d=>4}, {:a=>10, :d=>2}]
1804
- @db[:b].order(:b).all.must_equal [{:b=>2, :e=>5}, {:b=>4, :e=>7}]
1805
- @db[:c].order(:c).all.must_equal [{:c=>5, :f=>6}, {:c=>7, :f=>8}]
1806
- end
1807
-
1808
- it "#delete should allow deleting from joined datasets" do
1809
- @ds.delete
1810
- @ds.all.must_equal []
1811
- @db[:a].order(:a).all.must_equal [{:a=>3, :d=>4}]
1812
- @db[:b].order(:b).all.must_equal [{:b=>2, :e=>5}, {:b=>4, :e=>7}]
1813
- @db[:c].order(:c).all.must_equal [{:c=>5, :f=>6}, {:c=>7, :f=>8}]
1814
- end
1815
- end
1816
- end
1817
-
1818
- describe "Emulated functions" do
1819
- before(:all) do
1820
- @db = DB
1821
- @db.create_table!(:a){String :a}
1822
- @ds = @db[:a]
1823
- end
1824
- after(:all) do
1825
- @db.drop_table?(:a)
1826
- end
1827
- after do
1828
- @ds.delete
1829
- end
1830
-
1831
- it "Sequel.char_length should return the length of characters in the string" do
1832
- @ds.get(Sequel.char_length(:a)).must_be_nil
1833
- @ds.insert(:a=>'foo')
1834
- @ds.get(Sequel.char_length(:a)).must_equal 3
1835
- # Check behavior with leading/trailing blanks
1836
- @ds.update(:a=>' foo22 ')
1837
- @ds.get(Sequel.char_length(:a)).must_equal 7
1838
- end
1839
-
1840
- it "Sequel.trim should return the string with spaces trimmed from both sides" do
1841
- @ds.get(Sequel.trim(:a)).must_be_nil
1842
- @ds.insert(:a=>'foo')
1843
- @ds.get(Sequel.trim(:a)).must_equal 'foo'
1844
- # Check behavior with leading/trailing blanks
1845
- @ds.update(:a=>' foo22 ')
1846
- @ds.get(Sequel.trim(:a)).must_equal 'foo22'
1847
- end
1848
- end
1849
-
1850
- describe "Dataset replace" do
1851
- before do
1852
- DB.create_table!(:items){Integer :id, :unique=>true; Integer :value}
1853
- @d = DB[:items]
1854
- end
1855
-
1856
- after do
1857
- DB.drop_table?(:items)
1858
- end
1859
-
1860
- it "should use support arrays, datasets, and multiple values" do
1861
- @d.replace([1, 2])
1862
- @d.all.must_equal [{:id=>1, :value=>2}]
1863
- @d.replace(1, 2)
1864
- @d.all.must_equal [{:id=>1, :value=>2}]
1865
- @d.replace(@d)
1866
- @d.all.must_equal [{:id=>1, :value=>2}]
1867
- end
1868
-
1869
- it "should create a record if the condition is not met" do
1870
- @d.replace(:id => 111, :value => 333)
1871
- @d.all.must_equal [{:id => 111, :value => 333}]
1872
- end
1873
-
1874
- it "should update a record if the condition is met" do
1875
- @d.insert(:id => 111)
1876
- @d.all.must_equal [{:id => 111, :value => nil}]
1877
- @d.replace(:id => 111, :value => 333)
1878
- @d.all.must_equal [{:id => 111, :value => 333}]
1879
- end
1880
- end if DB.dataset.supports_replace?