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