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,2915 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "A new Database" do
4
- before do
5
- @db = Sequel::Database.new(1 => 2, :logger => 3)
6
- end
7
-
8
- it "should not allow dup/clone" do
9
- proc{@db.dup}.must_raise NoMethodError
10
- proc{@db.clone}.must_raise NoMethodError
11
- end
12
-
13
- it "should receive options" do
14
- @db.opts[1].must_equal 2
15
- @db.opts[:logger].must_equal 3
16
- end
17
-
18
- it "should set the logger from opts[:logger] and opts[:loggers]" do
19
- @db.loggers.must_equal [3]
20
- Sequel::Database.new(1 => 2, :loggers => 3).loggers.must_equal [3]
21
- Sequel::Database.new(1 => 2, :loggers => [3]).loggers.must_equal [3]
22
- Sequel::Database.new(1 => 2, :logger => 4, :loggers => 3).loggers.must_equal [4,3]
23
- Sequel::Database.new(1 => 2, :logger => [4], :loggers => [3]).loggers.must_equal [4,3]
24
- end
25
-
26
- it "should support :preconnect option to preconnect to database" do
27
- @db.pool.size.must_equal 0
28
- c = Class.new(Sequel::Database) do
29
- def dataset_class_default; Sequel::Dataset end
30
- def connect(_)
31
- :connect
32
- end
33
- end
34
- db = c.new(1 => 2, :logger => 3, :preconnect=>true)
35
- db.pool.size.must_equal db.pool.max_size
36
- db = c.new(1 => 2, :logger => 3, :preconnect=>:concurrently)
37
- db.pool.size.must_equal db.pool.max_size
38
- end
39
-
40
- it "should handle the default string column size" do
41
- @db.default_string_column_size.must_equal 255
42
- db = Sequel::Database.new(:default_string_column_size=>50)
43
- db.default_string_column_size.must_equal 50
44
- db.default_string_column_size = 2
45
- db.default_string_column_size.must_equal 2
46
- end
47
-
48
- it "should set the sql_log_level from opts[:sql_log_level]" do
49
- Sequel::Database.new(1 => 2, :sql_log_level=>:debug).sql_log_level.must_equal :debug
50
- Sequel::Database.new(1 => 2, :sql_log_level=>'debug').sql_log_level.must_equal :debug
51
- end
52
-
53
- it "should create a connection pool" do
54
- @db.pool.must_be_kind_of(Sequel::ConnectionPool)
55
- @db.pool.max_size.must_equal 4
56
-
57
- Sequel::Database.new(:max_connections => 10).pool.max_size.must_equal 10
58
- end
59
-
60
- it "should have the connection pool use the connect method to get connections" do
61
- cc = nil
62
- d = Sequel::Database.new
63
- d.define_singleton_method(:connect){|c| 1234}
64
- d.synchronize {|c| cc = c}
65
- cc.must_equal 1234
66
- end
67
-
68
- it "should respect the :single_threaded option" do
69
- db = Sequel::Database.new(:single_threaded=>true){123}
70
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
71
- db = Sequel::Database.new(:single_threaded=>'t'){123}
72
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
73
- db = Sequel::Database.new(:single_threaded=>'1'){123}
74
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
75
- db = Sequel::Database.new(:single_threaded=>false){123}
76
- db.pool.must_be_kind_of(Sequel::ConnectionPool)
77
- db = Sequel::Database.new(:single_threaded=>'f'){123}
78
- db.pool.must_be_kind_of(Sequel::ConnectionPool)
79
- db = Sequel::Database.new(:single_threaded=>'0'){123}
80
- db.pool.must_be_kind_of(Sequel::ConnectionPool)
81
- end
82
-
83
- it "should just use a :uri option for jdbc with the full connection string" do
84
- db = Sequel::Database.stub(:adapter_class, Class.new(Sequel::Database){def connect(*); Object.new end}) do
85
- Sequel.connect('jdbc:test://host/db_name')
86
- end
87
- db.must_be_kind_of(Sequel::Database)
88
- db.opts[:uri].must_equal 'jdbc:test://host/db_name'
89
- end
90
-
91
- it "should populate :adapter option when using connection string" do
92
- Sequel.connect('mock:/').opts[:adapter].must_equal "mock"
93
- end
94
-
95
- it "should respect the :keep_reference option for not keeping a reference in Sequel::DATABASES" do
96
- db = Sequel.connect('mock:///?keep_reference=f')
97
- Sequel::DATABASES.wont_include(db)
98
- end
99
-
100
- it 'should strip square brackets for ipv6 hosts' do
101
- Sequel.connect('mock://[::1]').opts[:host].must_equal "::1"
102
- end
103
- end
104
-
105
- describe "Database :connect_sqls option" do
106
- it "should issue the each sql query for each new connection" do
107
- db = Sequel.mock(:connect_sqls=>['SELECT 1', 'SELECT 2'])
108
- db.sqls.must_equal ['SELECT 1', 'SELECT 2']
109
- db['SELECT 3'].get
110
- db.sqls.must_equal ['SELECT 3']
111
- db.disconnect
112
- db['SELECT 3'].get
113
- db.sqls.must_equal ['SELECT 1', 'SELECT 2', 'SELECT 3']
114
- end
115
- end
116
-
117
- describe "Database#freeze" do
118
- before do
119
- @db = Sequel.mock.freeze
120
- end
121
-
122
- it "should freeze internal structures" do
123
- @db.instance_exec do
124
- frozen?.must_equal true
125
- opts.frozen?.must_equal true
126
- pool.frozen?.must_equal true
127
- loggers.frozen?.must_equal true
128
- @dataset_class.frozen?.must_equal true
129
- @dataset_modules.frozen?.must_equal true
130
- @schema_type_classes.frozen?.must_equal true
131
- from(:a).frozen?.must_equal true
132
- metadata_dataset.frozen?.must_equal true
133
- end
134
-
135
- proc{@db.extend_datasets{}}.must_raise RuntimeError, TypeError
136
- end
137
- end
138
-
139
- describe "Database#disconnect" do
140
- it "should call pool.disconnect" do
141
- d = Sequel::Database.new
142
- p = d.pool
143
- def p.disconnect(h)
144
- raise unless h == {}
145
- 2
146
- end
147
- d.disconnect.must_equal 2
148
- end
149
- end
150
-
151
- describe "Sequel.extension" do
152
- it "should attempt to load the given extension" do
153
- proc{Sequel.extension :blah}.must_raise(LoadError)
154
- end
155
- end
156
-
157
- describe "Database#log_info" do
158
- before do
159
- @o = Object.new
160
- def @o.logs; @logs || []; end
161
- def @o.to_ary; [self]; end
162
- def @o.method_missing(*args); (@logs ||= []) << args; end
163
- @db = Sequel::Database.new(:logger=>@o)
164
- end
165
-
166
- it "should log message at info level to all loggers" do
167
- @db.log_info('blah')
168
- @o.logs.must_equal [[:info, 'blah']]
169
- end
170
-
171
- it "should log message with args at info level to all loggers" do
172
- @db.log_info('blah', [1, 2])
173
- @o.logs.must_equal [[:info, 'blah; [1, 2]']]
174
- end
175
- end
176
-
177
- describe "Database#log_connection_yield" do
178
- before do
179
- @o = Object.new
180
- def @o.logs; @logs || []; end
181
- def @o.to_ary; [self]; end
182
- def @o.warn(*args); (@logs ||= []) << [:warn] + args; end
183
- def @o.method_missing(*args); (@logs ||= []) << args; end
184
- @conn = Object.new
185
- @db = Sequel::Database.new(:logger=>@o)
186
- end
187
-
188
- it "should log SQL to the loggers" do
189
- @db.log_connection_yield("some SQL", @conn){}
190
- @o.logs.length.must_equal 1
191
- @o.logs.first.length.must_equal 2
192
- @o.logs.first.first.must_equal :info
193
- @o.logs.first.last.must_match(/some SQL\z/)
194
- @o.logs.first.last.wont_match(/\(conn: -?\d+\) some SQL\z/)
195
- end
196
-
197
- it "should include connection information when logging" do
198
- @db.log_connection_info = true
199
- @db.log_connection_yield("some SQL", @conn){}
200
- @o.logs.length.must_equal 1
201
- @o.logs.first.length.must_equal 2
202
- @o.logs.first.first.must_equal :info
203
- @o.logs.first.last.must_match(/\(conn: -?\d+\) some SQL\z/)
204
- end
205
-
206
- it "should yield to the passed block" do
207
- a = nil
208
- @db.log_connection_yield('blah', @conn){a = 1}
209
- a.must_equal 1
210
- end
211
-
212
- it "should raise an exception if a block is not passed" do
213
- proc{@db.log_connection_yield('blah', @conn)}.must_raise LocalJumpError
214
- end
215
-
216
- it "should log message with duration at info level to all loggers" do
217
- @db.log_connection_yield('blah', @conn){}
218
- @o.logs.length.must_equal 1
219
- @o.logs.first.length.must_equal 2
220
- @o.logs.first.first.must_equal :info
221
- @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
222
- end
223
-
224
- it "should respect sql_log_level setting" do
225
- @db.sql_log_level = :debug
226
- @db.log_connection_yield('blah', @conn){}
227
- @o.logs.length.must_equal 1
228
- @o.logs.first.length.must_equal 2
229
- @o.logs.first.first.must_equal :debug
230
- @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
231
- end
232
-
233
- it "should log message with duration at warn level if duration greater than log_warn_duration" do
234
- @db.log_warn_duration = 0
235
- @db.log_connection_yield('blah', @conn){}
236
- @o.logs.length.must_equal 1
237
- @o.logs.first.length.must_equal 2
238
- @o.logs.first.first.must_equal :warn
239
- @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
240
- end
241
-
242
- it "should log message with duration at info level if duration less than log_warn_duration" do
243
- @db.log_warn_duration = 1000
244
- @db.log_connection_yield('blah', @conn){}
245
- @o.logs.length.must_equal 1
246
- @o.logs.first.length.must_equal 2
247
- @o.logs.first.first.must_equal :info
248
- @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
249
- end
250
-
251
- it "should log message at error level if block raises an error" do
252
- @db.log_warn_duration = 0
253
- proc{@db.log_connection_yield('blah', @conn){raise Sequel::Error, 'adsf'}}.must_raise Sequel::Error
254
- @o.logs.length.must_equal 1
255
- @o.logs.first.length.must_equal 2
256
- @o.logs.first.first.must_equal :error
257
- @o.logs.first.last.must_match(/\ASequel::Error: adsf: blah\z/)
258
- end
259
-
260
- it "should include args with message if args passed" do
261
- @db.log_connection_yield('blah', @conn, [1, 2]){}
262
- @o.logs.length.must_equal 1
263
- @o.logs.first.length.must_equal 2
264
- @o.logs.first.first.must_equal :info
265
- @o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah; \[1, 2\]\z/)
266
- end
267
-
268
- it "should log without a logger defined by forcing skip_logging? to return false" do
269
- @db.logger = nil
270
- @db.extend(Module.new do
271
- def skip_logging?
272
- false
273
- end
274
-
275
- def log_duration(*)
276
- self.did_log = true
277
- end
278
-
279
- attr_accessor :did_log
280
- end)
281
-
282
- @db.log_connection_yield('some sql', @conn) {}
283
-
284
- @db.did_log.must_equal true
285
- end
286
- end
287
-
288
- describe "Database#uri" do
289
- before do
290
- @c = Class.new(Sequel::Database) do
291
- def dataset_class_default; Sequel::Dataset end
292
- def connect(*); Object.new end
293
- set_adapter_scheme :mau
294
- end
295
-
296
- @db = Sequel.connect('mau://user:pass@localhost:9876/maumau')
297
- end
298
-
299
- it "should return the connection URI for the database" do
300
- @db.uri.must_equal 'mau://user:pass@localhost:9876/maumau'
301
- end
302
-
303
- it "should return nil if a connection uri was not used" do
304
- Sequel.mock.uri.must_be_nil
305
- end
306
-
307
- it "should be aliased as #url" do
308
- @db.url.must_equal 'mau://user:pass@localhost:9876/maumau'
309
- end
310
- end
311
-
312
- describe "Database.adapter_scheme and #adapter_scheme" do
313
- it "should return the database scheme" do
314
- Sequel::Database.adapter_scheme.must_be_nil
315
-
316
- @c = Class.new(Sequel::Database) do
317
- def dataset_class_default; Sequel::Dataset end
318
- set_adapter_scheme :mau
319
- end
320
-
321
- @c.adapter_scheme.must_equal :mau
322
- @c.new({}).adapter_scheme.must_equal :mau
323
- end
324
- end
325
-
326
- describe "Database#dataset" do
327
- before do
328
- @db = Sequel.mock
329
- @ds = @db.dataset
330
- end
331
-
332
- it "should provide a blank dataset through #dataset" do
333
- @ds.must_be_kind_of(Sequel::Dataset)
334
- @ds.opts.must_equal({})
335
- @ds.db.must_be_same_as(@db)
336
- end
337
-
338
- it "should provide a #from dataset" do
339
- d = @db.from(:mau)
340
- d.must_be_kind_of(Sequel::Dataset)
341
- d.sql.must_equal 'SELECT * FROM mau'
342
-
343
- e = @db[:miu]
344
- e.must_be_kind_of(Sequel::Dataset)
345
- e.sql.must_equal 'SELECT * FROM miu'
346
- end
347
-
348
- it "should provide a #from dataset that supports virtual row blocks" do
349
- @db.from{a(b)}.sql.must_equal 'SELECT * FROM a(b)'
350
- end
351
-
352
- it "should provide a #select dataset" do
353
- d = @db.select(:a, :b, :c).from(:mau)
354
- d.must_be_kind_of(Sequel::Dataset)
355
- d.sql.must_equal 'SELECT a, b, c FROM mau'
356
- end
357
-
358
- it "should allow #select to take a block" do
359
- d = @db.select(:a, :b){c}.from(:mau)
360
- d.must_be_kind_of(Sequel::Dataset)
361
- d.sql.must_equal 'SELECT a, b, c FROM mau'
362
- end
363
- end
364
-
365
- describe "Database#dataset_class" do
366
- before do
367
- @db = Sequel::Database.new
368
- @dsc = Class.new(Sequel::Dataset)
369
- end
370
-
371
- it "should have setter set the class to use to create datasets" do
372
- @db.dataset_class = @dsc
373
- ds = @db.dataset
374
- ds.must_be_kind_of(@dsc)
375
- ds.opts.must_equal({})
376
- ds.db.must_be_same_as(@db)
377
- end
378
-
379
- it "should have getter return the class to use to create datasets" do
380
- [@db.dataset_class, @db.dataset_class.superclass].must_include(Sequel::Dataset)
381
- @db.dataset_class = @dsc
382
- [@db.dataset_class, @db.dataset_class.superclass].must_include(@dsc)
383
- end
384
- end
385
-
386
- describe "Database#extend_datasets" do
387
- before do
388
- @db = Sequel::Database.new
389
- @m = Module.new{def foo() [3] end}
390
- @m2 = Module.new{def foo() [4] + super end}
391
- @db.extend_datasets(@m)
392
- end
393
-
394
- it "should clear a cached dataset" do
395
- @db = Sequel::Database.new
396
- @db.literal(1).must_equal '1'
397
- @db.extend_datasets{def literal(v) '2' end}
398
- @db.literal(1).must_equal '2'
399
- end
400
-
401
- it "should change the dataset class to a subclass the first time it is called" do
402
- @db.dataset_class.superclass.must_equal Sequel::Dataset
403
- end
404
-
405
- it "should not create a subclass of the dataset class if called more than once" do
406
- @db.extend_datasets(@m2)
407
- @db.dataset_class.superclass.must_equal Sequel::Dataset
408
- end
409
-
410
- it "should make the dataset class include the module" do
411
- @db.dataset_class.ancestors.must_include(@m)
412
- @db.dataset_class.ancestors.wont_include(@m2)
413
- @db.extend_datasets(@m2)
414
- @db.dataset_class.ancestors.must_include(@m)
415
- @db.dataset_class.ancestors.must_include(@m2)
416
- end
417
-
418
- it "should have datasets respond to the module's methods" do
419
- @db.dataset.foo.must_equal [3]
420
- @db.extend_datasets(@m2)
421
- @db.dataset.foo.must_equal [4, 3]
422
- end
423
-
424
- it "should take a block and create a module from it to use" do
425
- @db.dataset.foo.must_equal [3]
426
- @db.extend_datasets{def foo() [5] + super end}
427
- @db.dataset.foo.must_equal [5, 3]
428
- end
429
-
430
- it "should raise an error if both a module and a block are provided" do
431
- proc{@db.extend_datasets(@m2){def foo() [5] + super end}}.must_raise(Sequel::Error)
432
- end
433
-
434
- it "should be able to override methods defined in the original Dataset class" do
435
- @db.extend_datasets do
436
- def select(*a, &block) super.order(*a, &block) end
437
- def input_identifier(v) v.to_s end
438
- end
439
- @db[:t].with_quote_identifiers(false).select(:a, :b).sql.must_equal 'SELECT a, b FROM t ORDER BY a, b'
440
- end
441
-
442
- it "should reapply settings if dataset_class is changed" do
443
- c = Class.new(Sequel::Dataset)
444
- @db.dataset_class = c
445
- @db.dataset_class.superclass.must_equal c
446
- @db.dataset_class.ancestors.must_include(@m)
447
- @db.dataset.foo.must_equal [3]
448
- end
449
- end
450
-
451
- describe "Database#extend_datasets custom methods" do
452
- before do
453
- @db = Sequel.mock
454
- end
455
-
456
- def ds
457
- @db[:items]
458
- end
459
-
460
- it "should have dataset_module support a where method" do
461
- @db.extend_datasets{where :released, :released}
462
- ds.released.sql.must_equal 'SELECT * FROM items WHERE released'
463
- ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND released)'
464
- end
465
-
466
- it "should have dataset_module support a having method" do
467
- @db.extend_datasets{having(:released){released}}
468
- ds.released.sql.must_equal 'SELECT * FROM items HAVING released'
469
- ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE foo HAVING released'
470
- end
471
-
472
- it "should have dataset_module support an exclude method" do
473
- @db.extend_datasets{exclude :released, :released}
474
- ds.released.sql.must_equal 'SELECT * FROM items WHERE NOT released'
475
- ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE (foo AND NOT released)'
476
- end
477
-
478
- it "should have dataset_module support an exclude_having method" do
479
- @db.extend_datasets{exclude_having :released, :released}
480
- ds.released.sql.must_equal 'SELECT * FROM items HAVING NOT released'
481
- ds.where(:foo).released.sql.must_equal 'SELECT * FROM items WHERE foo HAVING NOT released'
482
- end
483
-
484
- it "should have dataset_module support a distinct method" do
485
- @db.extend_datasets{def supports_distinct_on?; true end; distinct :foo, :baz}
486
- ds.foo.sql.must_equal 'SELECT DISTINCT ON (baz) * FROM items'
487
- ds.where(:bar).foo.sql.must_equal 'SELECT DISTINCT ON (baz) * FROM items WHERE bar'
488
- end
489
-
490
- it "should have dataset_module support a grep method" do
491
- @db.extend_datasets{grep :foo, :baz, 'quux%'}
492
- ds.foo.sql.must_equal 'SELECT * FROM items WHERE ((baz LIKE \'quux%\' ESCAPE \'\\\'))'
493
- ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE (bar AND ((baz LIKE \'quux%\' ESCAPE \'\\\')))'
494
- end
495
-
496
- it "should have dataset_module support a group method" do
497
- @db.extend_datasets{group :foo, :baz}
498
- ds.foo.sql.must_equal 'SELECT * FROM items GROUP BY baz'
499
- ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar GROUP BY baz'
500
- end
501
-
502
- it "should have dataset_module support a group_and_count method" do
503
- @db.extend_datasets{group_and_count :foo, :baz}
504
- ds.foo.sql.must_equal 'SELECT baz, count(*) AS count FROM items GROUP BY baz'
505
- ds.where(:bar).foo.sql.must_equal 'SELECT baz, count(*) AS count FROM items WHERE bar GROUP BY baz'
506
- end
507
-
508
- it "should have dataset_module support a group_append method" do
509
- @db.extend_datasets{group_append :foo, :baz}
510
- ds.foo.sql.must_equal 'SELECT * FROM items GROUP BY baz'
511
- ds.group(:bar).foo.sql.must_equal 'SELECT * FROM items GROUP BY bar, baz'
512
- end
513
-
514
- it "should have dataset_module support a limit method" do
515
- @db.extend_datasets{limit :foo, 1}
516
- ds.foo.sql.must_equal 'SELECT * FROM items LIMIT 1'
517
- ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar LIMIT 1'
518
- end
519
-
520
- it "should have dataset_module support a offset method" do
521
- @db.extend_datasets{offset :foo, 1}
522
- ds.foo.sql.must_equal 'SELECT * FROM items OFFSET 1'
523
- ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar OFFSET 1'
524
- end
525
-
526
- it "should have dataset_module support a order method" do
527
- @db.extend_datasets{order(:foo){:baz}}
528
- ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
529
- ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar ORDER BY baz'
530
- end
531
-
532
- it "should have dataset_module support a order_append method" do
533
- @db.extend_datasets{order_append :foo, :baz}
534
- ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
535
- ds.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY bar, baz'
536
- end
537
-
538
- it "should have dataset_module support a order_prepend method" do
539
- @db.extend_datasets{order_prepend :foo, :baz}
540
- ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz'
541
- ds.order(:bar).foo.sql.must_equal 'SELECT * FROM items ORDER BY baz, bar'
542
- end
543
-
544
- it "should have dataset_module support a reverse method" do
545
- @db.extend_datasets{reverse(:foo){:baz}}
546
- ds.foo.sql.must_equal 'SELECT * FROM items ORDER BY baz DESC'
547
- ds.where(:bar).foo.sql.must_equal 'SELECT * FROM items WHERE bar ORDER BY baz DESC'
548
- end
549
-
550
- it "should have dataset_module support a select method" do
551
- @db.extend_datasets{select :foo, :baz}
552
- ds.foo.sql.must_equal 'SELECT baz FROM items'
553
- ds.where(:bar).foo.sql.must_equal 'SELECT baz FROM items WHERE bar'
554
- end
555
-
556
- it "should have dataset_module support a select_all method" do
557
- @db.extend_datasets{select_all :foo, :baz}
558
- ds.foo.sql.must_equal 'SELECT baz.* FROM items'
559
- ds.where(:bar).foo.sql.must_equal 'SELECT baz.* FROM items WHERE bar'
560
- end
561
-
562
- it "should have dataset_module support a select_append method" do
563
- @db.extend_datasets{select_append :foo, :baz}
564
- ds.foo.sql.must_equal 'SELECT *, baz FROM items'
565
- ds.where(:bar).foo.sql.must_equal 'SELECT *, baz FROM items WHERE bar'
566
- end
567
-
568
- it "should have dataset_module support a select_group method" do
569
- @db.extend_datasets{select_group :foo, :baz}
570
- ds.foo.sql.must_equal 'SELECT baz FROM items GROUP BY baz'
571
- ds.where(:bar).foo.sql.must_equal 'SELECT baz FROM items WHERE bar GROUP BY baz'
572
- end
573
-
574
- it "should have dataset_module support a server method" do
575
- @db.extend_datasets{server :foo, :baz}
576
- ds.foo.opts[:server].must_equal :baz
577
- ds.where(:bar).foo.opts[:server].must_equal :baz
578
- end
579
- end
580
-
581
- describe "Database#disconnect_connection" do
582
- it "should call close on the connection" do
583
- o = Object.new
584
- def o.close() @closed=true end
585
- Sequel::Database.new.disconnect_connection(o)
586
- o.instance_variable_get(:@closed).must_equal true
587
- end
588
- end
589
-
590
- describe "Database#valid_connection?" do
591
- it "should issue a query to validate the connection" do
592
- db = Sequel.mock
593
- db.synchronize{|c| db.valid_connection?(c)}.must_equal true
594
- db.synchronize do |c|
595
- def c.execute(*) raise Sequel::DatabaseError, "error" end
596
- db.valid_connection?(c)
597
- end.must_equal false
598
- end
599
- end
600
-
601
- describe "Database#run" do
602
- before do
603
- @db = Sequel.mock(:servers=>{:s1=>{}})
604
- end
605
-
606
- it "should execute the code on the database" do
607
- @db.run("DELETE FROM items")
608
- @db.sqls.must_equal ["DELETE FROM items"]
609
- end
610
-
611
- it "should handle placeholder literal strings" do
612
- @db.run(Sequel.lit("DELETE FROM ?", :items))
613
- @db.sqls.must_equal ["DELETE FROM items"]
614
- end
615
-
616
- it "should return nil" do
617
- @db.run("DELETE FROM items").must_be_nil
618
- end
619
-
620
- it "should accept options passed to execute_ddl" do
621
- @db.run("DELETE FROM items", :server=>:s1)
622
- @db.sqls.must_equal ["DELETE FROM items -- s1"]
623
- end
624
- end
625
-
626
- describe "Database#<<" do
627
- before do
628
- @db = Sequel.mock
629
- end
630
-
631
- it "should execute the code on the database" do
632
- @db << "DELETE FROM items"
633
- @db.sqls.must_equal ["DELETE FROM items"]
634
- end
635
-
636
- it "should handle placeholder literal strings" do
637
- @db << Sequel.lit("DELETE FROM ?", :items)
638
- @db.sqls.must_equal ["DELETE FROM items"]
639
- end
640
-
641
- it "should be chainable" do
642
- @db << "DELETE FROM items" << "DELETE FROM items2"
643
- @db.sqls.must_equal ["DELETE FROM items", "DELETE FROM items2"]
644
- end
645
- end
646
-
647
- describe "Database#synchronize" do
648
- before do
649
- @db = Sequel::Database.new(:max_connections => 1)
650
- @db.define_singleton_method(:connect){|c| 12345}
651
- end
652
-
653
- it "should wrap the supplied block in pool.hold" do
654
- q, q1, q2 = Queue.new, Queue.new, Queue.new
655
- c1, c2 = nil
656
- t1 = Thread.new{@db.synchronize{|c| c1 = c; q.push nil; q1.pop}; q.push nil}
657
- q.pop
658
- c1.must_equal 12345
659
- t2 = Thread.new{@db.synchronize{|c| c2 = c; q2.push nil}}
660
- @db.pool.available_connections.must_be :empty?
661
- c2.must_be_nil
662
- q1.push nil
663
- q.pop
664
- q2.pop
665
- c2.must_equal 12345
666
- t1.join
667
- t2.join
668
- end
669
- end
670
-
671
- describe "Database#test_connection" do
672
- before do
673
- @db = Sequel::Database.new
674
- pr = proc{@test = rand(100)}
675
- @db.define_singleton_method(:connect){|c| pr.call}
676
- end
677
-
678
- it "should attempt to get a connection" do
679
- @db.test_connection
680
- @test.wont_equal nil
681
- end
682
-
683
- it "should return true if successful" do
684
- @db.test_connection.must_equal true
685
- end
686
-
687
- it "should raise an error if the attempting to connect raises an error" do
688
- def @db.connect(*) raise Sequel::Error end
689
- proc{@db.test_connection}.must_raise(Sequel::DatabaseConnectionError)
690
- end
691
- end
692
-
693
- describe "Database#table_exists?" do
694
- it "should test existence by selecting a row from the table's dataset" do
695
- db = Sequel.mock(:fetch=>[Sequel::Error, [], [{:a=>1}]])
696
- db.table_exists?(:a).must_equal false
697
- db.sqls.must_equal ["SELECT NULL AS nil FROM a LIMIT 1"]
698
- db.table_exists?(:b).must_equal true
699
- db.table_exists?(:c).must_equal true
700
- end
701
-
702
- it "should use a savepoint if inside a transaction" do
703
- db = Sequel.mock(:fetch=>[Sequel::Error, [], [{:a=>1}]])
704
- def db.supports_savepoints?; true end
705
- db.transaction do
706
- db.table_exists?(:a).must_equal false
707
- end
708
- db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SELECT NULL AS nil FROM a LIMIT 1", "ROLLBACK TO SAVEPOINT autopoint_1", "COMMIT"]
709
- db.table_exists?(:b).must_equal true
710
- db.table_exists?(:c).must_equal true
711
- end
712
- end
713
-
714
- DatabaseTransactionSpecs = shared_description do
715
- it "should wrap the supplied block with BEGIN + COMMIT statements" do
716
- @db.transaction{@db.execute 'DROP TABLE test;'}
717
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
718
- end
719
-
720
- it "should support transaction isolation levels" do
721
- @db.define_singleton_method(:supports_transaction_isolation_levels?){true}
722
- [:uncommitted, :committed, :repeatable, :serializable].each do |l|
723
- @db.transaction(:isolation=>l){@db.run "DROP TABLE #{l}"}
724
- end
725
- @db.sqls.must_equal ['BEGIN', 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', 'DROP TABLE uncommitted', 'COMMIT',
726
- 'BEGIN', 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', 'DROP TABLE committed', 'COMMIT',
727
- 'BEGIN', 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ', 'DROP TABLE repeatable', 'COMMIT',
728
- 'BEGIN', 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', 'DROP TABLE serializable', 'COMMIT']
729
- end
730
-
731
- it "should allow specifying a default transaction isolation level" do
732
- @db.define_singleton_method(:supports_transaction_isolation_levels?){true}
733
- [:uncommitted, :committed, :repeatable, :serializable].each do |l|
734
- @db.transaction_isolation_level = l
735
- @db.transaction{@db.run "DROP TABLE #{l}"}
736
- end
737
- @db.sqls.must_equal ['BEGIN', 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', 'DROP TABLE uncommitted', 'COMMIT',
738
- 'BEGIN', 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', 'DROP TABLE committed', 'COMMIT',
739
- 'BEGIN', 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ', 'DROP TABLE repeatable', 'COMMIT',
740
- 'BEGIN', 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', 'DROP TABLE serializable', 'COMMIT']
741
- end
742
-
743
- it "should support :retry_on option for automatically retrying transactions" do
744
- a = []
745
- @db.transaction(:retry_on=>Sequel::DatabaseDisconnectError){a << 1; raise Sequel::DatabaseDisconnectError if a.length < 2}
746
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'BEGIN', 'COMMIT']
747
- a.must_equal [1, 1]
748
-
749
- a = []
750
- @db.transaction(:retry_on=>[Sequel::ConstraintViolation, Sequel::SerializationFailure]) do
751
- a << 1
752
- raise Sequel::SerializationFailure if a.length == 1
753
- raise Sequel::ConstraintViolation if a.length == 2
754
- end
755
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'BEGIN', 'ROLLBACK', 'BEGIN', 'COMMIT']
756
- a.must_equal [1, 1, 1]
757
- end
758
-
759
- it "should support :num_retries option for limiting the number of retry times" do
760
- a = []
761
- lambda do
762
- @db.transaction(:num_retries=>1, :retry_on=>[Sequel::ConstraintViolation, Sequel::SerializationFailure]) do
763
- a << 1
764
- raise Sequel::SerializationFailure if a.length == 1
765
- raise Sequel::ConstraintViolation if a.length == 2
766
- end
767
- end.must_raise(Sequel::ConstraintViolation)
768
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'BEGIN', 'ROLLBACK']
769
- a.must_equal [1, 1]
770
- end
771
-
772
- it "should support :num_retries=>nil option to retry indefinitely" do
773
- a = []
774
- lambda do
775
- @db.transaction(:num_retries=>nil, :retry_on=>[Sequel::ConstraintViolation]) do
776
- a << 1
777
- raise Sequel::SerializationFailure if a.length >= 100
778
- raise Sequel::ConstraintViolation
779
- end
780
- end.must_raise(Sequel::SerializationFailure)
781
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK'] * 100
782
- a.must_equal [1] * 100
783
- end
784
-
785
- it "should support :before_retry option for invoking callback before retrying" do
786
- a, errs, calls = [], [], []
787
- retryer = proc{|n, err| calls << n; errs << err }
788
- @db.transaction(:retry_on=>Sequel::DatabaseDisconnectError, :before_retry => retryer) do
789
- a << 1; raise Sequel::DatabaseDisconnectError if a.length < 3
790
- end
791
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'BEGIN', 'ROLLBACK', 'BEGIN', 'COMMIT']
792
- a.must_equal [1, 1, 1]
793
- errs.count.must_equal 2
794
- errs.each { |e| e.class.must_equal Sequel::DatabaseDisconnectError }
795
- calls.must_equal [1, 2]
796
- end
797
-
798
- it "should raise an error if attempting to use :retry_on inside another transaction" do
799
- proc{@db.transaction{@db.transaction(:retry_on=>Sequel::ConstraintViolation){}}}.must_raise(Sequel::Error)
800
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
801
- end
802
-
803
- it "should handle returning inside of the block by committing" do
804
- def @db.ret_commit
805
- transaction do
806
- execute 'DROP TABLE test;'
807
- return
808
- end
809
- end
810
- @db.ret_commit
811
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
812
- end
813
-
814
- it "should issue ROLLBACK if an exception is raised, and re-raise" do
815
- @db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
816
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
817
-
818
- proc {@db.transaction {raise RuntimeError}}.must_raise(RuntimeError)
819
- end
820
-
821
- it "should handle errors when sending BEGIN" do
822
- ec = Class.new(StandardError)
823
- @db.define_singleton_method(:database_error_classes){[ec]}
824
- @db.define_singleton_method(:log_connection_execute){|c, sql| sql =~ /BEGIN/ ? raise(ec, 'bad') : super(c, sql)}
825
- begin
826
- @db.transaction{@db.execute 'DROP TABLE test;'}
827
- rescue Sequel::DatabaseError => e
828
- end
829
- e.wont_equal nil
830
- e.wrapped_exception.must_be_kind_of(ec)
831
- @db.sqls.must_equal ['ROLLBACK']
832
- end
833
-
834
- it "should handle errors when sending COMMIT" do
835
- ec = Class.new(StandardError)
836
- @db.define_singleton_method(:database_error_classes){[ec]}
837
- @db.define_singleton_method(:log_connection_execute){|c, sql| sql =~ /COMMIT/ ? raise(ec, 'bad') : super(c, sql)}
838
- begin
839
- @db.transaction{@db.execute 'DROP TABLE test;'}
840
- rescue Sequel::DatabaseError => e
841
- end
842
- e.wont_equal nil
843
- e.wrapped_exception.must_be_kind_of(ec)
844
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'ROLLBACK']
845
- end
846
-
847
- it "should raise original exception if there is an exception raised when rolling back" do
848
- ec = Class.new(StandardError)
849
- @db.define_singleton_method(:database_error_classes){[ec]}
850
- @db.define_singleton_method(:log_connection_execute){|c, sql| sql =~ /ROLLBACK/ ? raise(ec, 'bad') : super(c, sql)}
851
- begin
852
- @db.transaction{raise ArgumentError, 'asdf'}
853
- rescue => e
854
- end
855
- e.must_be_kind_of(ArgumentError)
856
- @db.sqls.must_equal ['BEGIN']
857
- end
858
-
859
- it "should raise original exception if there is an exception raised when rolling back when using :rollback=>:always" do
860
- ec = Class.new(StandardError)
861
- @db.define_singleton_method(:database_error_classes){[ec]}
862
- @db.define_singleton_method(:log_connection_execute){|c, sql| sql =~ /ROLLBACK/ ? raise(ec, 'bad') : super(c, sql)}
863
- begin
864
- @db.transaction(:rollback=>:always){}
865
- rescue => e
866
- end
867
- e.must_be_kind_of(ec)
868
- @db.sqls.must_equal ['BEGIN']
869
- end
870
-
871
- it "should issue ROLLBACK if Sequel::Rollback is called in the transaction" do
872
- @db.transaction do
873
- @db.drop_table(:a)
874
- raise Sequel::Rollback
875
- @db.drop_table(:b)
876
- end
877
-
878
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
879
- end
880
-
881
- it "should have in_transaction? return true if inside a transaction" do
882
- c = nil
883
- @db.transaction{c = @db.in_transaction?}
884
- c.must_equal true
885
- end
886
-
887
- it "should have in_transaction? handle sharding correctly" do
888
- c = []
889
- @db.transaction(:server=>:test){c << @db.in_transaction?}
890
- @db.transaction(:server=>:test){c << @db.in_transaction?(:server=>:test)}
891
- c.must_equal [false, true]
892
- end
893
-
894
- it "should have in_transaction? return false if not in a transaction" do
895
- @db.in_transaction?.must_equal false
896
- end
897
-
898
- it "should have rollback_checker return a proc which returns whether the transaction was rolled back" do
899
- proc{@db.rollback_checker}.must_raise Sequel::Error
900
- proc{@db.transaction(:server=>:test){@db.rollback_checker}}.must_raise Sequel::Error
901
-
902
- rbc = nil
903
- @db.transaction do
904
- rbc = @db.rollback_checker
905
- rbc.call.must_be_nil
906
- end
907
- rbc.call.must_equal false
908
-
909
- @db.transaction(:rollback=>:always) do
910
- rbc = @db.rollback_checker
911
- rbc.call.must_be_nil
912
- end
913
- rbc.call.must_equal true
914
-
915
- proc do
916
- @db.transaction do
917
- rbc = @db.rollback_checker
918
- raise
919
- end
920
- end.must_raise RuntimeError
921
- rbc.call.must_equal true
922
-
923
- @db.transaction(:server=>:test){rbc = @db.rollback_checker(:server=>:test)}
924
- rbc.call.must_equal false
925
- end
926
-
927
- it "should return nil if Sequel::Rollback is called in the transaction" do
928
- @db.transaction{raise Sequel::Rollback}.must_be_nil
929
- end
930
-
931
- it "should reraise Sequel::Rollback errors when using :rollback=>:reraise option is given" do
932
- proc {@db.transaction(:rollback=>:reraise){raise Sequel::Rollback}}.must_raise(Sequel::Rollback)
933
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
934
- proc {@db.transaction(:rollback=>:reraise){raise ArgumentError}}.must_raise(ArgumentError)
935
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
936
- @db.transaction(:rollback=>:reraise){1}.must_equal 1
937
- @db.sqls.must_equal ['BEGIN', 'COMMIT']
938
- end
939
-
940
- it "should always rollback if :rollback=>:always option is given" do
941
- proc {@db.transaction(:rollback=>:always){raise ArgumentError}}.must_raise(ArgumentError)
942
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
943
- @db.transaction(:rollback=>:always){raise Sequel::Rollback}.must_be_nil
944
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
945
- @db.transaction(:rollback=>:always){1}.must_equal 1
946
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
947
- catch(:foo) do
948
- @db.transaction(:rollback=>:always){throw :foo}
949
- end
950
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
951
- end
952
-
953
- it "should raise database errors when commiting a transaction as Sequel::DatabaseError" do
954
- @db.define_singleton_method(:commit_transaction){raise ArgumentError}
955
- lambda{@db.transaction{}}.must_raise(ArgumentError)
956
-
957
- @db.define_singleton_method(:database_error_classes){[ArgumentError]}
958
- lambda{@db.transaction{}}.must_raise(Sequel::DatabaseError)
959
- end
960
-
961
- it "should be re-entrant" do
962
- q, q1 = Queue.new, Queue.new
963
- cc = nil
964
- t = Thread.new do
965
- @db.transaction {@db.transaction {@db.transaction {|c|
966
- cc = c
967
- q.pop
968
- q1.push nil
969
- q.pop
970
- }}}
971
- end
972
- q.push nil
973
- q1.pop
974
- cc.must_be_kind_of(Sequel::Mock::Connection)
975
- tr = @db.instance_variable_get(:@transactions)
976
- tr.keys.must_equal [cc]
977
- q.push nil
978
- t.join
979
- tr.must_be :empty?
980
- end
981
-
982
- it "should correctly handle nested transaction use with separate shards" do
983
- @db.transaction do |c1|
984
- @db.transaction(:server=>:test) do |c2|
985
- c1.wont_equal c2
986
- @db.execute 'DROP TABLE test;'
987
- end
988
- end
989
- @db.sqls.must_equal ['BEGIN', 'BEGIN -- test', 'DROP TABLE test;', 'COMMIT -- test', 'COMMIT']
990
- end
991
-
992
- if (!defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby') and !RUBY_VERSION.start_with?('1.9')
993
- it "should handle Thread#kill for transactions inside threads" do
994
- q = Queue.new
995
- q1 = Queue.new
996
- t = Thread.new do
997
- @db.transaction do
998
- @db.execute 'DROP TABLE test'
999
- q1.push nil
1000
- q.pop
1001
- @db.execute 'DROP TABLE test2'
1002
- end
1003
- end
1004
- q1.pop
1005
- t.kill
1006
- t.join
1007
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
1008
- end
1009
- end
1010
-
1011
- it "should raise an Error if after_commit or after_rollback is called without a block" do
1012
- proc{@db.after_commit}.must_raise(Sequel::Error)
1013
- proc{@db.after_rollback}.must_raise(Sequel::Error)
1014
- end
1015
-
1016
- it "should have after_commit and after_rollback respect :server option" do
1017
- @db.transaction(:server=>:test){@db.after_commit(:server=>:test){@db.execute('foo', :server=>:test)}}
1018
- @db.sqls.must_equal ['BEGIN -- test', 'COMMIT -- test', 'foo -- test']
1019
- @db.transaction(:server=>:test){@db.after_rollback(:server=>:test){@db.execute('foo', :server=>:test)}; raise Sequel::Rollback}
1020
- @db.sqls.must_equal ['BEGIN -- test', 'ROLLBACK -- test', 'foo -- test']
1021
- end
1022
-
1023
- it "should execute after_commit outside transactions" do
1024
- @db.after_commit{@db.execute('foo')}
1025
- @db.sqls.must_equal ['foo']
1026
- end
1027
-
1028
- it "should ignore after_rollback outside transactions" do
1029
- @db.after_rollback{@db.execute('foo')}
1030
- @db.sqls.must_equal []
1031
- end
1032
-
1033
- it "should support after_commit inside transactions" do
1034
- @db.transaction{@db.after_commit{@db.execute('foo')}}
1035
- @db.sqls.must_equal ['BEGIN', 'COMMIT', 'foo']
1036
- end
1037
-
1038
- it "should support after_rollback inside transactions" do
1039
- @db.transaction{@db.after_rollback{@db.execute('foo')}}
1040
- @db.sqls.must_equal ['BEGIN', 'COMMIT']
1041
- end
1042
-
1043
- it "should have transaction inside after_commit work correctly" do
1044
- @db.transaction{@db.after_commit{@db.transaction{@db.execute('foo')}}}
1045
- @db.sqls.must_equal ['BEGIN', 'COMMIT', 'BEGIN', 'foo', 'COMMIT']
1046
- end
1047
-
1048
- it "should have transaction inside after_rollback work correctly" do
1049
- @db.transaction(:rollback=>:always){@db.after_rollback{@db.transaction{@db.execute('foo')}}}
1050
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'BEGIN', 'foo', 'COMMIT']
1051
- end
1052
-
1053
- it "should not call after_commit if the transaction rolls back" do
1054
- @db.transaction{@db.after_commit{@db.execute('foo')}; raise Sequel::Rollback}
1055
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1056
- end
1057
-
1058
- it "should call after_rollback if the transaction rolls back" do
1059
- @db.transaction{@db.after_rollback{@db.execute('foo')}; raise Sequel::Rollback}
1060
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'foo']
1061
- end
1062
-
1063
- it "should call multiple after_commit blocks in order if called inside transactions" do
1064
- @db.transaction{@db.after_commit{@db.execute('foo')}; @db.after_commit{@db.execute('bar')}}
1065
- @db.sqls.must_equal ['BEGIN', 'COMMIT', 'foo', 'bar']
1066
- end
1067
-
1068
- it "should call multiple after_rollback blocks in order if called inside transactions" do
1069
- @db.transaction{@db.after_rollback{@db.execute('foo')}; @db.after_rollback{@db.execute('bar')}; raise Sequel::Rollback}
1070
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'foo', 'bar']
1071
- end
1072
-
1073
- it "should support after_commit inside nested transactions" do
1074
- @db.transaction{@db.transaction{@db.after_commit{@db.execute('foo')}}}
1075
- @db.sqls.must_equal ['BEGIN', 'COMMIT', 'foo']
1076
- end
1077
-
1078
- it "should support after_rollback inside nested transactions" do
1079
- @db.transaction{@db.transaction{@db.after_rollback{@db.execute('foo')}}; raise Sequel::Rollback}
1080
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK', 'foo']
1081
- end
1082
-
1083
- it "should raise an error if you attempt to use after_commit inside a prepared transaction" do
1084
- @db.define_singleton_method(:supports_prepared_transactions?){true}
1085
- proc{@db.transaction(:prepare=>'XYZ'){@db.after_commit{@db.execute('foo')}}}.must_raise(Sequel::Error)
1086
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1087
- end
1088
-
1089
- it "should raise an error if you attempt to use after_rollback inside a prepared transaction" do
1090
- @db.define_singleton_method(:supports_prepared_transactions?){true}
1091
- proc{@db.transaction(:prepare=>'XYZ'){@db.after_rollback{@db.execute('foo')}}}.must_raise(Sequel::Error)
1092
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1093
- end
1094
-
1095
- it "should have rollback_on_exit cause the transaction to rollback on exit" do
1096
- @db.transaction{@db.rollback_on_exit}.must_be_nil
1097
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1098
- catch(:foo){@db.transaction{@db.rollback_on_exit; throw :foo}}
1099
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1100
- lambda{@db.transaction{@db.rollback_on_exit; return true}}.call
1101
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1102
- end
1103
-
1104
- it "should have rollback_on_exit with :cancel option will cause the transaction to commit on exit" do
1105
- @db.transaction{@db.rollback_on_exit(:cancel=>true)}.must_be_nil
1106
- @db.sqls.must_equal ['BEGIN', 'COMMIT']
1107
- @db.transaction{@db.rollback_on_exit; @db.rollback_on_exit(:cancel=>true)}.must_be_nil
1108
- @db.sqls.must_equal ['BEGIN', 'COMMIT']
1109
- end
1110
- end
1111
-
1112
- describe "Database#transaction with savepoint support" do
1113
- before do
1114
- @db = Sequel.mock(:servers=>{:test=>{}})
1115
- end
1116
-
1117
- include DatabaseTransactionSpecs
1118
-
1119
- it "should support :retry_on option for automatically retrying transactions when using :savepoint option" do
1120
- a = []
1121
- @db.transaction do
1122
- @db.transaction(:retry_on=>Sequel::SerializationFailure, :savepoint=>true) do
1123
- a << 1
1124
- raise Sequel::SerializationFailure if a.length == 1
1125
- end
1126
- end
1127
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "ROLLBACK TO SAVEPOINT autopoint_1", "SAVEPOINT autopoint_1", "RELEASE SAVEPOINT autopoint_1", "COMMIT"]
1128
- a.must_equal [1, 1]
1129
- end
1130
-
1131
- it "should automatically use a savepoint if :rollback=>:always given inside a transaction" do
1132
- @db.transaction do
1133
- @db.transaction(:rollback=>:always) do
1134
- @db.get(1)
1135
- end
1136
- end
1137
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SELECT 1 AS v LIMIT 1", "ROLLBACK TO SAVEPOINT autopoint_1", "COMMIT"]
1138
- end
1139
-
1140
- it "should support :retry_on option for automatically retrying transactions inside an :auto_savepoint transaction" do
1141
- a = []
1142
- @db.transaction(:auto_savepoint=>true) do
1143
- @db.transaction(:retry_on=>Sequel::SerializationFailure) do
1144
- a << 1
1145
- raise Sequel::SerializationFailure if a.length == 1
1146
- end
1147
- end
1148
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "ROLLBACK TO SAVEPOINT autopoint_1", "SAVEPOINT autopoint_1", "RELEASE SAVEPOINT autopoint_1", "COMMIT"]
1149
- a.must_equal [1, 1]
1150
- end
1151
-
1152
- it "should support after_commit inside savepoints" do
1153
- @db.transaction do
1154
- @db.after_commit{@db.execute('foo')}
1155
- @db.transaction(:savepoint=>true){@db.after_commit{@db.execute('bar')}}
1156
- @db.after_commit{@db.execute('baz')}
1157
- end
1158
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT', 'foo', 'bar', 'baz']
1159
- end
1160
-
1161
- it "should support after_rollback inside savepoints" do
1162
- @db.transaction(:rollback=>:always) do
1163
- @db.after_rollback{@db.execute('foo')}
1164
- @db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('bar')}}
1165
- @db.after_rollback{@db.execute('baz')}
1166
- end
1167
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
1168
- end
1169
-
1170
- it "should run after_commit if savepoint rolled back" do
1171
- @db.transaction do
1172
- @db.after_commit{@db.execute('foo')}
1173
- @db.transaction(:savepoint=>true, :rollback=>:always){@db.after_commit{@db.execute('bar')}}
1174
- end
1175
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT', 'foo', 'bar']
1176
- end
1177
-
1178
- it "should not run after_commit if savepoint rolled back and :savepoint option used" do
1179
- @db.transaction do
1180
- @db.after_commit{@db.execute('foo')}
1181
- @db.transaction(:savepoint=>true, :rollback=>:always){@db.after_commit(:savepoint=>true){@db.execute('bar')}}
1182
- end
1183
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT', 'foo']
1184
- end
1185
-
1186
- it "should not run after_commit if higher-level savepoint rolled back and :savepoint option used" do
1187
- @db.transaction do
1188
- @db.after_commit{@db.execute('foo')}
1189
- @db.transaction(:savepoint=>true, :rollback=>:always){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){@db.execute('bar')}}}
1190
- end
1191
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "ROLLBACK TO SAVEPOINT autopoint_1", "COMMIT", "foo"]
1192
- end
1193
-
1194
- it "should not run after_commit if transaction rolled back and :savepoint option used" do
1195
- @db.transaction(:rollback=>:always) do
1196
- @db.after_commit{@db.execute('foo')}
1197
- @db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_commit(:savepoint=>true){@db.execute('bar')}}}
1198
- end
1199
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_1", "ROLLBACK"]
1200
- end
1201
-
1202
- it "should run after_rollback if savepoint rolls back" do
1203
- @db.transaction(:rollback=>:always) do
1204
- @db.after_rollback{@db.execute('foo')}
1205
- @db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback{@db.execute('bar')}}
1206
- @db.after_rollback{@db.execute('baz')}
1207
- end
1208
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
1209
- end
1210
-
1211
- it "should run after_rollback when savepoint rolls back if :savepoint option used" do
1212
- @db.transaction(:rollback=>:always) do
1213
- @db.after_rollback{@db.execute('foo')}
1214
- @db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}
1215
- @db.after_rollback{@db.execute('baz')}
1216
- end
1217
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'bar', 'ROLLBACK', 'foo', 'baz']
1218
- end
1219
-
1220
- it "should run after_rollback if savepoint rolled back and :savepoint option used, even if transaction commits" do
1221
- @db.transaction do
1222
- @db.after_commit{@db.execute('foo')}
1223
- @db.transaction(:savepoint=>true, :rollback=>:always){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}
1224
- end
1225
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'ROLLBACK TO SAVEPOINT autopoint_1', 'bar', 'COMMIT', 'foo']
1226
- end
1227
-
1228
- it "should run after_rollback if higher-level savepoint rolled back and :savepoint option used" do
1229
- @db.transaction do
1230
- @db.transaction(:savepoint=>true, :rollback=>:always){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}}
1231
- end
1232
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "ROLLBACK TO SAVEPOINT autopoint_1", "bar", "COMMIT"]
1233
- end
1234
-
1235
- it "should run after_rollback if transaction rolled back and :savepoint option used" do
1236
- @db.transaction(:rollback=>:always) do
1237
- @db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.after_rollback(:savepoint=>true){@db.execute('bar')}}}
1238
- end
1239
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_2", "RELEASE SAVEPOINT autopoint_1", "ROLLBACK", "bar"]
1240
- end
1241
-
1242
- it "should raise an error if you attempt to use after_commit inside a savepoint in a prepared transaction" do
1243
- @db.define_singleton_method(:supports_prepared_transactions?){true}
1244
- proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_commit{@db.execute('foo')}}}}.must_raise(Sequel::Error)
1245
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1246
- end
1247
-
1248
- it "should raise an error if you attempt to use after_rollback inside a savepoint in a prepared transaction" do
1249
- @db.define_singleton_method(:supports_prepared_transactions?){true}
1250
- proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('foo')}}}}.must_raise(Sequel::Error)
1251
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1252
- end
1253
-
1254
- it "should create savepoint if inside a transaction when :savepoint=>:only is used" do
1255
- @db.transaction{@db.transaction(:savepoint=>:only){}}
1256
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1257
- end
1258
-
1259
- it "should not create transaction if not inside a transaction when :savepoint=>:only is used" do
1260
- @db.transaction(:savepoint=>:only){}
1261
- @db.sqls.must_equal []
1262
- end
1263
-
1264
- it "should have rollback_on_exit with :savepoint option inside transaction cause the transaction to rollback on exit" do
1265
- @db.transaction{@db.rollback_on_exit(:savepoint=>true)}.must_be_nil
1266
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1267
- catch(:foo){@db.transaction{@db.rollback_on_exit(:savepoint=>true); throw :foo}}
1268
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1269
- lambda{@db.transaction{@db.rollback_on_exit(:savepoint=>true); return true}}.call
1270
- @db.sqls.must_equal ['BEGIN', 'ROLLBACK']
1271
- end
1272
-
1273
- it "should have rollback_on_exit with :savepoint option inside savepoint cause the savepoint to rollback on exit" do
1274
- @db.transaction{@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true)}}.must_be_nil
1275
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
1276
- catch(:foo){@db.transaction{@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); throw :foo}}}
1277
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
1278
- lambda{@db.transaction{@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); return true}}}.call
1279
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
1280
- end
1281
-
1282
- it "should have rollback_on_exit with :savepoint option inside nested savepoint cause the current savepoint to rollback on exit" do
1283
- @db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true)}}}.must_be_nil
1284
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1285
- catch(:foo){@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); throw :foo}}}}
1286
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1287
- lambda{@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); return true}}}}.call
1288
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1289
- end
1290
-
1291
- it "should have rollback_on_exit with :savepoint=>1 option inside nested savepoint cause the current savepoint to rollback on exit" do
1292
- @db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>1)}}}.must_be_nil
1293
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1294
- catch(:foo){@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>1); throw :foo}}}}
1295
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1296
- lambda{@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>1); return true}}}}.call
1297
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1298
- end
1299
-
1300
- it "should have rollback_on_exit with :savepoint=>2 option inside nested savepoint cause the current and next savepoint to rollback on exit" do
1301
- @db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>2)}}}.must_be_nil
1302
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
1303
- catch(:foo){@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>2); throw :foo}}}}
1304
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
1305
- lambda{@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>2); return true}}}}.call
1306
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
1307
- end
1308
-
1309
- it "should have rollback_on_exit with :savepoint=>3 option inside nested savepoint cause the three enclosing savepoints/transaction to rollback on exit" do
1310
- @db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>3)}}}.must_be_nil
1311
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1312
- catch(:foo){@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>3); throw :foo}}}}
1313
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1314
- lambda{@db.transaction{@db.transaction(:savepoint=>true){@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>3); return true}}}}.call
1315
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1316
- end
1317
-
1318
- it "should have rollback_on_exit with :savepoint and :cancel option will cause the transaction to commit on exit" do
1319
- @db.transaction{@db.rollback_on_exit(:savepoint=>true, :cancel=>true)}.must_be_nil
1320
- @db.sqls.must_equal ['BEGIN', 'COMMIT']
1321
- @db.transaction{@db.rollback_on_exit(:savepoint=>true); @db.rollback_on_exit(:savepoint=>true, :cancel=>true)}.must_be_nil
1322
- @db.sqls.must_equal ['BEGIN', 'COMMIT']
1323
- end
1324
-
1325
- it "should have rollback_on_exit with :savepoint option called at different levels work correctly" do
1326
- @db.transaction{@db.rollback_on_exit(:savepoint=>true); @db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true)}}.must_be_nil
1327
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1328
-
1329
- @db.transaction{@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); @db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true)}}}.must_be_nil
1330
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2','ROLLBACK TO SAVEPOINT autopoint_2', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
1331
-
1332
- @db.transaction{@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); @db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true, :cancel=>true)}}}.must_be_nil
1333
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2','RELEASE SAVEPOINT autopoint_2', 'ROLLBACK TO SAVEPOINT autopoint_1', 'COMMIT']
1334
-
1335
- @db.transaction{@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); @db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>2, :cancel=>true)}}}.must_be_nil
1336
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2','RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1337
-
1338
- @db.transaction{@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); @db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>3, :cancel=>true)}}}.must_be_nil
1339
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2','RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1340
-
1341
- @db.transaction{@db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>true); @db.transaction(:savepoint=>true){@db.rollback_on_exit(:savepoint=>4, :cancel=>true)}}}.must_be_nil
1342
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2','RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1343
- end
1344
- end
1345
-
1346
- describe "Database#transaction without savepoint support" do
1347
- before do
1348
- @db = Sequel.mock(:servers=>{:test=>{}})
1349
- @db.define_singleton_method(:supports_savepoints?){false}
1350
- end
1351
-
1352
- it "should not create savepoint if inside a transaction when :savepoint=>:only is used" do
1353
- @db.transaction{@db.transaction(:savepoint=>:only){}}
1354
- @db.sqls.must_equal ['BEGIN', 'COMMIT']
1355
- end
1356
-
1357
- it "should not automatically use a savepoint if :rollback=>:always given inside a transaction" do
1358
- proc do
1359
- @db.transaction do
1360
- @db.transaction(:rollback=>:always) do
1361
- @db.get(1)
1362
- end
1363
- end
1364
- end.must_raise Sequel::Error
1365
- @db.sqls.must_equal ["BEGIN", "ROLLBACK"]
1366
- end
1367
-
1368
- include DatabaseTransactionSpecs
1369
- end
1370
-
1371
- describe "Sequel.transaction" do
1372
- before do
1373
- @sqls = []
1374
- @db1 = Sequel.mock(:append=>'1', :sqls=>@sqls)
1375
- @db2 = Sequel.mock(:append=>'2', :sqls=>@sqls)
1376
- @db3 = Sequel.mock(:append=>'3', :sqls=>@sqls)
1377
- end
1378
-
1379
- it "should run the block inside transacitons on all three databases" do
1380
- Sequel.transaction([@db1, @db2, @db3]){1}.must_equal 1
1381
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
1382
- end
1383
-
1384
- it "should pass options to all the blocks" do
1385
- Sequel.transaction([@db1, @db2, @db3], :rollback=>:always){1}.must_equal 1
1386
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'ROLLBACK -- 3', 'ROLLBACK -- 2', 'ROLLBACK -- 1']
1387
- end
1388
-
1389
- it "should handle Sequel::Rollback exceptions raised by the block to rollback on all databases" do
1390
- Sequel.transaction([@db1, @db2, @db3]){raise Sequel::Rollback}.must_be_nil
1391
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'ROLLBACK -- 3', 'ROLLBACK -- 2', 'ROLLBACK -- 1']
1392
- end
1393
-
1394
- it "should handle nested transactions" do
1395
- Sequel.transaction([@db1, @db2, @db3]){Sequel.transaction([@db1, @db2, @db3]){1}}.must_equal 1
1396
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
1397
- end
1398
-
1399
- it "should handle savepoints" do
1400
- Sequel.transaction([@db1, @db2, @db3]){Sequel.transaction([@db1, @db2, @db3], :savepoint=>true){1}}.must_equal 1
1401
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3',
1402
- 'SAVEPOINT autopoint_1 -- 1', 'SAVEPOINT autopoint_1 -- 2', 'SAVEPOINT autopoint_1 -- 3',
1403
- 'RELEASE SAVEPOINT autopoint_1 -- 3', 'RELEASE SAVEPOINT autopoint_1 -- 2', 'RELEASE SAVEPOINT autopoint_1 -- 1',
1404
- 'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
1405
- end
1406
- end
1407
-
1408
- describe "Database#transaction with savepoints" do
1409
- before do
1410
- @db = Sequel.mock
1411
- end
1412
-
1413
- it "should wrap the supplied block with BEGIN + COMMIT statements" do
1414
- @db.transaction {@db.execute 'DROP TABLE test;'}
1415
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1416
- end
1417
-
1418
- it "should use savepoints if given the :savepoint option" do
1419
- @db.transaction{@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}}
1420
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1421
- end
1422
-
1423
- it "should use savepoints if surrounding transaction uses :auto_savepoint option" do
1424
- @db.transaction(:auto_savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}
1425
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1426
-
1427
- @db.transaction(:auto_savepoint=>true){@db.transaction{@db.transaction{@db.execute 'DROP TABLE test;'}}}
1428
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1429
-
1430
- @db.transaction(:auto_savepoint=>true){@db.transaction(:auto_savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}}
1431
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1432
-
1433
- @db.transaction{@db.transaction(:auto_savepoint=>true, :savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}}
1434
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1435
- end
1436
-
1437
- it "should not use savepoints if surrounding transaction uses :auto_savepoint and current transaction uses :savepoint=>false option" do
1438
- @db.transaction(:auto_savepoint=>true){@db.transaction(:savepoint=>false){@db.execute 'DROP TABLE test;'}}
1439
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1440
- end
1441
-
1442
- it "should not use a savepoint if no transaction is in progress" do
1443
- @db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}
1444
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1445
- end
1446
-
1447
- it "should reuse the current transaction if no :savepoint option is given" do
1448
- @db.transaction{@db.transaction{@db.execute 'DROP TABLE test;'}}
1449
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1450
- end
1451
-
1452
- it "should handle returning inside of the block by committing" do
1453
- def @db.ret_commit
1454
- transaction do
1455
- execute 'DROP TABLE test;'
1456
- return
1457
- end
1458
- end
1459
- @db.ret_commit
1460
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1461
- end
1462
-
1463
- it "should handle returning inside of a savepoint by committing" do
1464
- def @db.ret_commit
1465
- transaction do
1466
- transaction(:savepoint=>true) do
1467
- execute 'DROP TABLE test;'
1468
- return
1469
- end
1470
- end
1471
- end
1472
- @db.ret_commit
1473
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1474
- end
1475
-
1476
- it "should issue ROLLBACK if an exception is raised, and re-raise" do
1477
- @db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
1478
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
1479
-
1480
- proc {@db.transaction {raise RuntimeError}}.must_raise(RuntimeError)
1481
- end
1482
-
1483
- it "should issue ROLLBACK SAVEPOINT if an exception is raised inside a savepoint, and re-raise" do
1484
- @db.transaction{@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test'; raise RuntimeError}} rescue nil
1485
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1486
-
1487
- proc {@db.transaction {raise RuntimeError}}.must_raise(RuntimeError)
1488
- end
1489
-
1490
- it "should issue ROLLBACK if Sequel::Rollback is raised in the transaction" do
1491
- @db.transaction do
1492
- @db.drop_table(:a)
1493
- raise Sequel::Rollback
1494
- @db.drop_table(:b)
1495
- end
1496
-
1497
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
1498
- end
1499
-
1500
- it "should issue ROLLBACK SAVEPOINT if Sequel::Rollback is raised in a savepoint" do
1501
- @db.transaction do
1502
- @db.transaction(:savepoint=>true) do
1503
- @db.drop_table(:a)
1504
- raise Sequel::Rollback
1505
- end
1506
- @db.drop_table(:b)
1507
- end
1508
-
1509
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE a', 'ROLLBACK TO SAVEPOINT autopoint_1', 'DROP TABLE b', 'COMMIT']
1510
- end
1511
-
1512
- it "should raise database errors when commiting a transaction as Sequel::DatabaseError" do
1513
- @db.define_singleton_method(:commit_transaction){raise ArgumentError}
1514
- lambda{@db.transaction{}}.must_raise(ArgumentError)
1515
- lambda{@db.transaction{@db.transaction(:savepoint=>true){}}}.must_raise(ArgumentError)
1516
-
1517
- @db.define_singleton_method(:database_error_classes){[ArgumentError]}
1518
- lambda{@db.transaction{}}.must_raise(Sequel::DatabaseError)
1519
- lambda{@db.transaction{@db.transaction(:savepoint=>true){}}}.must_raise(Sequel::DatabaseError)
1520
- end
1521
- end
1522
-
1523
- describe "A Database adapter with a scheme" do
1524
- before do
1525
- require_relative '../../lib/sequel/adapters/mock'
1526
- @ccc = Class.new(Sequel::Mock::Database)
1527
- @ccc.send(:set_adapter_scheme, :ccc)
1528
- end
1529
-
1530
- it "should be registered in the ADAPTER_MAP" do
1531
- Sequel::ADAPTER_MAP[:ccc].must_equal @ccc
1532
- end
1533
-
1534
- it "should give the database_type as the adapter scheme by default" do
1535
- @ccc.new.database_type.must_equal :ccc
1536
- end
1537
-
1538
- it "should be instantiated when its scheme is specified" do
1539
- c = Sequel::Database.connect('ccc://localhost/db')
1540
- c.must_be_kind_of(@ccc)
1541
- c.opts[:host].must_equal 'localhost'
1542
- c.opts[:database].must_equal 'db'
1543
- end
1544
-
1545
- it "should be accessible through Sequel.connect" do
1546
- c = Sequel.connect 'ccc://localhost/db'
1547
- c.must_be_kind_of(@ccc)
1548
- c.opts[:host].must_equal 'localhost'
1549
- c.opts[:database].must_equal 'db'
1550
- end
1551
-
1552
- it "should be accessible through Sequel.connect via a block" do
1553
- x = nil
1554
- y = nil
1555
- z = nil
1556
- returnValue = 'anything'
1557
-
1558
- p = proc do |c|
1559
- c.must_be_kind_of(@ccc)
1560
- c.opts[:host].must_equal 'localhost'
1561
- c.opts[:database].must_equal 'db'
1562
- z = y
1563
- y = x
1564
- x = c
1565
- returnValue
1566
- end
1567
-
1568
- @ccc.class_eval do
1569
- self::DISCONNECTS = []
1570
- def disconnect
1571
- self.class::DISCONNECTS << self
1572
- end
1573
- end
1574
- Sequel::Database.connect('ccc://localhost/db', &p).must_equal returnValue
1575
- @ccc::DISCONNECTS.must_equal [x]
1576
-
1577
- Sequel.connect('ccc://localhost/db', &p).must_equal returnValue
1578
- @ccc::DISCONNECTS.must_equal [y, x]
1579
-
1580
- Sequel.send(:def_adapter_method, :ccc)
1581
- Sequel.ccc('db', :host=>'localhost', &p).must_equal returnValue
1582
- @ccc::DISCONNECTS.must_equal [z, y, x]
1583
- Sequel.singleton_class.send(:remove_method, :ccc)
1584
- end
1585
-
1586
- it "should be accessible through Sequel.<adapter>" do
1587
- Sequel.send(:def_adapter_method, :ccc)
1588
-
1589
- # invalid parameters
1590
- proc {Sequel.ccc('abc', 'def')}.must_raise(Sequel::Error)
1591
- proc {Sequel.ccc(1)}.must_raise(Sequel::Error)
1592
-
1593
- c = Sequel.ccc('mydb')
1594
- c.must_be_kind_of(@ccc)
1595
- c.opts.values_at(:adapter, :database, :adapter_class).must_equal [:ccc, 'mydb', @ccc]
1596
-
1597
- c = Sequel.ccc('mydb', :host => 'localhost')
1598
- c.must_be_kind_of(@ccc)
1599
- c.opts.values_at(:adapter, :database, :host, :adapter_class).must_equal [:ccc, 'mydb', 'localhost', @ccc]
1600
-
1601
- c = Sequel.ccc
1602
- c.must_be_kind_of(@ccc)
1603
- c.opts.values_at(:adapter, :adapter_class).must_equal [:ccc, @ccc]
1604
-
1605
- c = Sequel.ccc(:database => 'mydb', :host => 'localhost')
1606
- c.must_be_kind_of(@ccc)
1607
- c.opts.values_at(:adapter, :database, :host, :adapter_class).must_equal [:ccc, 'mydb', 'localhost', @ccc]
1608
- Sequel.singleton_class.send(:remove_method, :ccc)
1609
- end
1610
-
1611
- it "should be accessible through Sequel.connect with options" do
1612
- c = Sequel.connect(:adapter => :ccc, :database => 'mydb')
1613
- c.must_be_kind_of(@ccc)
1614
- c.opts[:adapter].must_equal :ccc
1615
- end
1616
-
1617
- it "should be accessible through Sequel.connect with URL parameters" do
1618
- c = Sequel.connect 'ccc:///db?host=/tmp&user=test'
1619
- c.must_be_kind_of(@ccc)
1620
- c.opts[:host].must_equal '/tmp'
1621
- c.opts[:database].must_equal 'db'
1622
- c.opts[:user].must_equal 'test'
1623
- end
1624
-
1625
- it "should have URL parameters take precedence over fixed URL parts" do
1626
- c = Sequel.connect 'ccc://localhost/db?host=a&database=b'
1627
- c.must_be_kind_of(@ccc)
1628
- c.opts[:host].must_equal 'a'
1629
- c.opts[:database].must_equal 'b'
1630
- end
1631
-
1632
- it "should have hash options take predence over URL parameters or parts" do
1633
- c = Sequel.connect 'ccc://localhost/db?host=/tmp', :host=>'a', :database=>'b', :user=>'c'
1634
- c.must_be_kind_of(@ccc)
1635
- c.opts[:host].must_equal 'a'
1636
- c.opts[:database].must_equal 'b'
1637
- c.opts[:user].must_equal 'c'
1638
- end
1639
-
1640
- it "should unescape values of URL parameters and parts" do
1641
- c = Sequel.connect 'ccc:///d%5bb%5d?host=domain%5cinstance'
1642
- c.must_be_kind_of(@ccc)
1643
- c.opts[:database].must_equal 'd[b]'
1644
- c.opts[:host].must_equal 'domain\\instance'
1645
- end
1646
-
1647
- it "should test the connection if test parameter is truthy" do
1648
- @ccc.send(:define_method, :connect){}
1649
- proc{Sequel.connect 'ccc:///d%5bb%5d?test=t'}.must_raise(Sequel::DatabaseConnectionError)
1650
- proc{Sequel.connect 'ccc:///d%5bb%5d?test=1'}.must_raise(Sequel::DatabaseConnectionError)
1651
- proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>true}.must_raise(Sequel::DatabaseConnectionError)
1652
- proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>'t'}.must_raise(Sequel::DatabaseConnectionError)
1653
- end
1654
-
1655
- it "should not test the connection if test parameter is not truthy" do
1656
- Sequel.connect 'ccc:///d%5bb%5d?test=f'
1657
- Sequel.connect 'ccc:///d%5bb%5d?test=0'
1658
- Sequel.connect 'ccc:///d%5bb%5d', :test=>false
1659
- Sequel.connect 'ccc:///d%5bb%5d', :test=>'f'
1660
- end
1661
- end
1662
-
1663
- describe "Sequel::Database.connect" do
1664
- it "should raise an Error if not given a String or Hash" do
1665
- proc{Sequel::Database.connect(nil)}.must_raise(Sequel::Error)
1666
- proc{Sequel::Database.connect(Object.new)}.must_raise(Sequel::Error)
1667
- end
1668
- end
1669
-
1670
- describe "An unknown database scheme" do
1671
- it "should raise an error in Sequel::Database.connect" do
1672
- proc {Sequel::Database.connect('ddd://localhost/db')}.must_raise(Sequel::AdapterNotFound)
1673
- end
1674
-
1675
- it "should raise an error in Sequel.connect" do
1676
- proc {Sequel.connect('ddd://localhost/db')}.must_raise(Sequel::AdapterNotFound)
1677
- end
1678
- end
1679
-
1680
- describe "A broken adapter (lib is there but the class is not)" do
1681
- before do
1682
- @fn = File.join(File.dirname(__FILE__), '../../lib/sequel/adapters/blah.rb')
1683
- File.open(@fn,'a'){}
1684
- end
1685
-
1686
- after do
1687
- File.delete(@fn)
1688
- end
1689
-
1690
- it "should raise an error" do
1691
- proc {Sequel.connect('blah://blow')}.must_raise(Sequel::AdapterNotFound)
1692
- end
1693
- end
1694
-
1695
- describe "Sequel::Database.load_adapter" do
1696
- it "should not raise an error if subadapter does not exist" do
1697
- Sequel::Database.load_adapter(:foo, :subdir=>'bar').must_be_nil
1698
- end
1699
- end
1700
-
1701
- describe "A single threaded database" do
1702
- after do
1703
- Sequel.single_threaded = false
1704
- end
1705
-
1706
- it "should use a SingleConnectionPool instead of a ConnectionPool" do
1707
- db = Sequel::Database.new(:single_threaded => true){123}
1708
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
1709
- end
1710
-
1711
- it "should be constructable using :single_threaded => true option" do
1712
- db = Sequel::Database.new(:single_threaded => true){123}
1713
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
1714
- end
1715
-
1716
- it "should be constructable using Sequel.single_threaded = true" do
1717
- Sequel.single_threaded = true
1718
- Sequel.single_threaded.must_equal true
1719
- db = Sequel::Database.new{123}
1720
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
1721
- end
1722
- end
1723
-
1724
- describe "A single threaded database" do
1725
- before do
1726
- conn = 1234567
1727
- @db = Sequel::Database.new(:single_threaded => true)
1728
- @db.define_singleton_method(:connect) do |c|
1729
- conn += 1
1730
- end
1731
- end
1732
-
1733
- it "should invoke connection_proc only once" do
1734
- @db.pool.hold {|c| c.must_equal 1234568}
1735
- @db.pool.hold {|c| c.must_equal 1234568}
1736
- end
1737
-
1738
- it "should disconnect correctly" do
1739
- def @db.disconnect_connection(c); @dc = c end
1740
- def @db.dc; @dc end
1741
- x = nil
1742
- @db.pool.hold{|c| x = c}
1743
- @db.pool.hold{|c| c.must_equal x}
1744
- @db.disconnect
1745
- @db.dc.must_equal x
1746
- end
1747
-
1748
- it "should convert an Exception on connection into a DatabaseConnectionError" do
1749
- db = Class.new(Sequel::Database){def connect(*) raise Exception end}.new(:single_threaded => true, :servers=>{}, :test=>false)
1750
- proc {db.pool.hold {|c|}}.must_raise(Sequel::DatabaseConnectionError)
1751
- end
1752
-
1753
- it "should raise a DatabaseConnectionError if the connection proc returns nil" do
1754
- db = Class.new(Sequel::Database){def connect(*) end}.new(:single_threaded => true, :servers=>{}, :test=>false)
1755
- proc {db.pool.hold {|c|}}.must_raise(Sequel::DatabaseConnectionError)
1756
- end
1757
- end
1758
-
1759
- describe "A database" do
1760
- after do
1761
- Sequel.single_threaded = false
1762
- end
1763
-
1764
- it "should have single_threaded? respond to true if in single threaded mode" do
1765
- db = Sequel::Database.new(:single_threaded => true){1234}
1766
- db.must_be :single_threaded?
1767
-
1768
- db = Sequel::Database.new(:max_options => 1)
1769
- db.wont_be :single_threaded?
1770
-
1771
- db = Sequel::Database.new
1772
- db.wont_be :single_threaded?
1773
-
1774
- Sequel.single_threaded = true
1775
-
1776
- db = Sequel::Database.new{123}
1777
- db.must_be :single_threaded?
1778
-
1779
- db = Sequel::Database.new(:max_options => 4){123}
1780
- db.must_be :single_threaded?
1781
- end
1782
-
1783
- it "should be able to set loggers via the logger= and loggers= methods" do
1784
- db = Sequel::Database.new
1785
- s = "I'm a logger"
1786
- db.logger = s
1787
- db.loggers.must_equal [s]
1788
- db.logger = nil
1789
- db.loggers.must_equal []
1790
-
1791
- db.loggers = [s]
1792
- db.loggers.must_equal [s]
1793
- db.loggers = []
1794
- db.loggers.must_equal []
1795
-
1796
- t = "I'm also a logger"
1797
- db.loggers = [s, t]
1798
- db.loggers.must_equal [s,t]
1799
- end
1800
- end
1801
-
1802
- describe "Database#fetch" do
1803
- before do
1804
- @db = Sequel.mock(:fetch=>proc{|sql| {:sql => sql}})
1805
- end
1806
-
1807
- it "should create a dataset and invoke its fetch_rows method with the given sql" do
1808
- sql = nil
1809
- @db.fetch('select * from xyz') {|r| sql = r[:sql]}
1810
- sql.must_equal 'select * from xyz'
1811
- end
1812
-
1813
- it "should format the given sql with any additional arguments" do
1814
- sql = nil
1815
- @db.fetch('select * from xyz where x = ? and y = ?', 15, 'abc') {|r| sql = r[:sql]}
1816
- sql.must_equal "select * from xyz where x = 15 and y = 'abc'"
1817
-
1818
- @db.fetch('select name from table where name = ? or id in ?', 'aman', [3,4,7]) {|r| sql = r[:sql]}
1819
- sql.must_equal "select name from table where name = 'aman' or id in (3, 4, 7)"
1820
- end
1821
-
1822
- it "should format the given sql with named arguments" do
1823
- sql = nil
1824
- @db.fetch('select * from xyz where x = :x and y = :y', :x=>15, :y=>'abc') {|r| sql = r[:sql]}
1825
- sql.must_equal "select * from xyz where x = 15 and y = 'abc'"
1826
- end
1827
-
1828
- it "should return the dataset if no block is given" do
1829
- @db.fetch('select * from xyz').must_be_kind_of(Sequel::Dataset)
1830
-
1831
- @db.fetch('select a from b').map {|r| r[:sql]}.must_equal ['select a from b']
1832
-
1833
- @db.fetch('select c from d').inject([]) {|m, r| m << r; m}.must_equal \
1834
- [{:sql => 'select c from d'}]
1835
- end
1836
-
1837
- it "should return a dataset that always uses the given sql for SELECTs" do
1838
- ds = @db.fetch('select * from xyz')
1839
- ds.select_sql.must_equal 'select * from xyz'
1840
- ds.sql.must_equal 'select * from xyz'
1841
-
1842
- ds = ds.where{price.sql_number < 100}
1843
- ds.select_sql.must_equal 'select * from xyz'
1844
- ds.sql.must_equal 'select * from xyz'
1845
- end
1846
- end
1847
-
1848
-
1849
- describe "Database#[]" do
1850
- before do
1851
- @db = Sequel.mock
1852
- end
1853
-
1854
- it "should return a dataset when symbols are given" do
1855
- ds = @db[:items]
1856
- ds.must_be_kind_of(Sequel::Dataset)
1857
- ds.opts[:from].must_equal [:items]
1858
- end
1859
-
1860
- it "should return a dataset when a string is given" do
1861
- @db.fetch = proc{|sql| {:sql=>sql}}
1862
- sql = nil
1863
- @db['select * from xyz where x = ? and y = ?', 15, 'abc'].each {|r| sql = r[:sql]}
1864
- sql.must_equal "select * from xyz where x = 15 and y = 'abc'"
1865
- end
1866
- end
1867
-
1868
- describe "Database#inspect" do
1869
- it "should include the class name and the connection url" do
1870
- Sequel.connect('mock://foo/bar').inspect.must_equal '#<Sequel::Mock::Database: "mock://foo/bar">'
1871
- end
1872
-
1873
- it "should include the class name and the connection options if an options hash was given" do
1874
- Sequel.connect(:adapter=>:mock).inspect.must_equal '#<Sequel::Mock::Database: {:adapter=>:mock}>'
1875
- end
1876
-
1877
- it "should include the class name, uri, and connection options if uri and options hash was given" do
1878
- Sequel.connect('mock://foo', :database=>'bar').inspect.must_equal '#<Sequel::Mock::Database: "mock://foo" {:database=>"bar"}>'
1879
- end
1880
- end
1881
-
1882
- describe "Database#get" do
1883
- before do
1884
- @db = Sequel.mock(:fetch=>{:a=>1})
1885
- end
1886
-
1887
- it "should use Dataset#get to get a single value" do
1888
- @db.get(:a).must_equal 1
1889
- @db.sqls.must_equal ['SELECT a LIMIT 1']
1890
-
1891
- @db.get(Sequel.function(:version).as(:version))
1892
- @db.sqls.must_equal ['SELECT version() AS version LIMIT 1']
1893
- end
1894
-
1895
- it "should accept a block" do
1896
- @db.get{a}
1897
- @db.sqls.must_equal ['SELECT a LIMIT 1']
1898
-
1899
- @db.get{version(a).as(version)}
1900
- @db.sqls.must_equal ['SELECT version(a) AS version LIMIT 1']
1901
- end
1902
-
1903
- it "should work when an alias cannot be determined" do
1904
- @db.get(1).must_equal 1
1905
- @db.sqls.must_equal ['SELECT 1 AS v LIMIT 1']
1906
- end
1907
- end
1908
-
1909
- describe "Database#call" do
1910
- it "should call the prepared statement with the given name" do
1911
- db = Sequel.mock(:fetch=>{:id => 1, :x => 1})
1912
- db[:items].prepare(:select, :select_all)
1913
- db.call(:select_all).must_equal [{:id => 1, :x => 1}]
1914
- db[:items].filter(:n=>:$n).prepare(:select, :select_n)
1915
- db.call(:select_n, :n=>1).must_equal [{:id => 1, :x => 1}]
1916
- db.sqls.must_equal ['SELECT * FROM items', 'SELECT * FROM items WHERE (n = 1)']
1917
- end
1918
- end
1919
-
1920
- describe "Database#server_opts" do
1921
- it "should return the general opts if no :servers option is used" do
1922
- opts = {:host=>1, :database=>2}
1923
- Sequel::Database.new(opts).send(:server_opts, :server1)[:host].must_equal 1
1924
- end
1925
-
1926
- it "should return the general opts if entry for the server is present in the :servers option" do
1927
- opts = {:host=>1, :database=>2, :servers=>{}}
1928
- Sequel::Database.new(opts).send(:server_opts, :server1)[:host].must_equal 1
1929
- end
1930
-
1931
- it "should return the general opts merged with the specific opts if given as a hash" do
1932
- opts = {:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}}}
1933
- Sequel::Database.new(opts).send(:server_opts, :server1)[:host].must_equal 3
1934
- end
1935
-
1936
- it "should return the sgeneral opts merged with the specific opts if given as a proc" do
1937
- opts = {:host=>1, :database=>2, :servers=>{:server1=>proc{|db| {:host=>4}}}}
1938
- Sequel::Database.new(opts).send(:server_opts, :server1)[:host].must_equal 4
1939
- end
1940
-
1941
- it "should raise an error if the specific opts is not a proc or hash" do
1942
- opts = {:host=>1, :database=>2, :servers=>{:server1=>2}}
1943
- proc{Sequel::Database.new(opts).send(:server_opts, :server1)}.must_raise(Sequel::Error)
1944
- end
1945
-
1946
- it "should return the general opts merged with given opts if given opts is a Hash" do
1947
- opts = {:host=>1, :database=>2}
1948
- Sequel::Database.new(opts).send(:server_opts, :host=>2)[:host].must_equal 2
1949
- end
1950
- end
1951
-
1952
- describe "Database#add_servers" do
1953
- before do
1954
- @db = Sequel.mock(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}})
1955
- end
1956
-
1957
- it "should add new servers to the connection pool" do
1958
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1959
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1960
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
1961
-
1962
- @db.add_servers(:server2=>{:host=>6})
1963
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1964
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1965
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 6}
1966
-
1967
- @db.disconnect
1968
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1969
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1970
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 6}
1971
- end
1972
-
1973
- it "should replace options for future connections to existing servers" do
1974
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1975
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1976
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
1977
-
1978
- @db.add_servers(:default=>proc{{:host=>4}}, :server1=>{:host=>8})
1979
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1980
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1981
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
1982
-
1983
- @db.disconnect
1984
- @db.synchronize{|c| c.opts[:host].must_equal 4}
1985
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 8}
1986
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 4}
1987
- end
1988
-
1989
- it "should raise error for unsharded pool" do
1990
- proc{Sequel.mock.add_servers(:server1=>{})}.must_raise Sequel::Error
1991
- end
1992
- end
1993
-
1994
- describe "Database#remove_servers" do
1995
- before do
1996
- @db = Sequel.mock(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}, :server2=>{:host=>4}})
1997
- end
1998
-
1999
- it "should remove servers from the connection pool" do
2000
- @db.synchronize{|c| c.opts[:host].must_equal 1}
2001
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
2002
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 4}
2003
-
2004
- @db.remove_servers(:server1, :server2)
2005
- @db.synchronize{|c| c.opts[:host].must_equal 1}
2006
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 1}
2007
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
2008
- end
2009
-
2010
- it "should accept arrays of symbols" do
2011
- @db.remove_servers([:server1, :server2])
2012
- @db.synchronize{|c| c.opts[:host].must_equal 1}
2013
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 1}
2014
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
2015
- end
2016
-
2017
- it "should allow removal while connections are still open" do
2018
- @db.synchronize do |c1|
2019
- c1.opts[:host].must_equal 1
2020
- @db.synchronize(:server1) do |c2|
2021
- c2.opts[:host].must_equal 3
2022
- @db.synchronize(:server2) do |c3|
2023
- c3.opts[:host].must_equal 4
2024
- @db.remove_servers(:server1, :server2)
2025
- @db.synchronize(:server1) do |c4|
2026
- c4.wont_equal c2
2027
- c4.must_equal c1
2028
- c4.opts[:host].must_equal 1
2029
- @db.synchronize(:server2) do |c5|
2030
- c5.wont_equal c3
2031
- c5.must_equal c1
2032
- c5.opts[:host].must_equal 1
2033
- end
2034
- end
2035
- c3.opts[:host].must_equal 4
2036
- end
2037
- c2.opts[:host].must_equal 3
2038
- end
2039
- c1.opts[:host].must_equal 1
2040
- end
2041
- end
2042
-
2043
- it "should raise error for unsharded pool" do
2044
- proc{Sequel.mock.remove_servers(:server1)}.must_raise Sequel::Error
2045
- end
2046
- end
2047
-
2048
- describe "Database#raise_error" do
2049
- before do
2050
- @db = Sequel.mock
2051
- end
2052
-
2053
- it "should reraise if the exception class is not in opts[:classes]" do
2054
- e = Class.new(StandardError)
2055
- proc{@db.send(:raise_error, e.new(''), :classes=>[])}.must_raise(e)
2056
- end
2057
-
2058
- it "should convert the exception to a DatabaseError if the exception class is in opts[:classes]" do
2059
- proc{@db.send(:raise_error, Interrupt.new(''), :classes=>[Interrupt])}.must_raise(Sequel::DatabaseError)
2060
- end
2061
-
2062
- it "should convert the exception to a DatabaseError if opts[:classes] if not present" do
2063
- proc{@db.send(:raise_error, Interrupt.new(''))}.must_raise(Sequel::DatabaseError)
2064
- end
2065
-
2066
- it "should convert the exception to a DatabaseDisconnectError if opts[:disconnect] is true" do
2067
- proc{@db.send(:raise_error, Interrupt.new(''), :disconnect=>true)}.must_raise(Sequel::DatabaseDisconnectError)
2068
- end
2069
-
2070
- it "should convert the exception to an appropriate error if exception message matches regexp" do
2071
- def @db.database_error_regexps
2072
- {/foo/ => Sequel::DatabaseDisconnectError, /bar/ => Sequel::ConstraintViolation}
2073
- end
2074
- e = Class.new(StandardError)
2075
- proc{@db.send(:raise_error, e.new('foo'))}.must_raise(Sequel::DatabaseDisconnectError)
2076
- proc{@db.send(:raise_error, e.new('bar'))}.must_raise(Sequel::ConstraintViolation)
2077
- end
2078
- end
2079
-
2080
- describe "Database#typecast_value" do
2081
- before do
2082
- @db = Sequel::Database.new
2083
- end
2084
-
2085
- it "should raise an InvalidValue when given an invalid value" do
2086
- proc{@db.typecast_value(:integer, "13a")}.must_raise(Sequel::InvalidValue)
2087
- proc{@db.typecast_value(:float, "4.e2")}.must_raise(Sequel::InvalidValue)
2088
- proc{@db.typecast_value(:decimal, :invalid_value)}.must_raise(Sequel::InvalidValue)
2089
- proc{@db.typecast_value(:date, Object.new)}.must_raise(Sequel::InvalidValue)
2090
- proc{@db.typecast_value(:date, 'a')}.must_raise(Sequel::InvalidValue)
2091
- proc{@db.typecast_value(:time, Date.new)}.must_raise(Sequel::InvalidValue)
2092
- proc{@db.typecast_value(:datetime, 4)}.must_raise(Sequel::InvalidValue)
2093
- end
2094
-
2095
- it "should raise an InvalidValue when given an invalid timezone value" do
2096
- begin
2097
- Sequel.default_timezone = :blah
2098
- proc{@db.typecast_value(:datetime, [2019, 2, 3, 4, 5, 6])}.must_raise(Sequel::InvalidValue)
2099
- Sequel.datetime_class = DateTime
2100
- proc{@db.typecast_value(:datetime, [2019, 2, 3, 4, 5, 6])}.must_raise(Sequel::InvalidValue)
2101
- ensure
2102
- Sequel.default_timezone = nil
2103
- Sequel.datetime_class = Time
2104
- end
2105
- end
2106
-
2107
- it "should handle integers with leading 0 as base 10" do
2108
- @db.typecast_value(:integer, "013").must_equal 13
2109
- @db.typecast_value(:integer, "08").must_equal 8
2110
- @db.typecast_value(:integer, "000013").must_equal 13
2111
- @db.typecast_value(:integer, "000008").must_equal 8
2112
- end
2113
-
2114
- it "should handle integers with leading 0x as base 16" do
2115
- @db.typecast_value(:integer, "0x013").must_equal 19
2116
- @db.typecast_value(:integer, "0x80").must_equal 128
2117
- end
2118
-
2119
- it "should typecast blobs as as Sequel::SQL::Blob" do
2120
- v = @db.typecast_value(:blob, "0x013")
2121
- v.must_be_kind_of(Sequel::SQL::Blob)
2122
- v.must_equal Sequel::SQL::Blob.new("0x013")
2123
- @db.typecast_value(:blob, v).object_id.must_equal v.object_id
2124
- end
2125
-
2126
- it "should typecast boolean values to true, false, or nil" do
2127
- @db.typecast_value(:boolean, false).must_equal false
2128
- @db.typecast_value(:boolean, 0).must_equal false
2129
- @db.typecast_value(:boolean, "0").must_equal false
2130
- @db.typecast_value(:boolean, 'f').must_equal false
2131
- @db.typecast_value(:boolean, 'false').must_equal false
2132
- @db.typecast_value(:boolean, true).must_equal true
2133
- @db.typecast_value(:boolean, 1).must_equal true
2134
- @db.typecast_value(:boolean, '1').must_equal true
2135
- @db.typecast_value(:boolean, 't').must_equal true
2136
- @db.typecast_value(:boolean, 'true').must_equal true
2137
- @db.typecast_value(:boolean, '').must_be_nil
2138
- end
2139
-
2140
- it "should typecast date values to Date" do
2141
- @db.typecast_value(:date, Date.today).must_equal Date.today
2142
- @db.typecast_value(:date, DateTime.now).must_equal Date.today
2143
- @db.typecast_value(:date, Time.now).must_equal Date.today
2144
- @db.typecast_value(:date, Date.today.to_s).must_equal Date.today
2145
- @db.typecast_value(:date, :year=>Date.today.year, :month=>Date.today.month, :day=>Date.today.day).must_equal Date.today
2146
- end
2147
-
2148
- it "should have Sequel.application_to_database_timestamp convert to Sequel.database_timezone" do
2149
- begin
2150
- t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
2151
- t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
2152
- t3 = Time.utc(2011, 1, 2, 3, 4, 5) - (t - t2) # Local Time in UTC Time
2153
- t4 = Time.mktime(2011, 1, 2, 3, 4, 5) + (t - t2) # UTC Time in Local Time
2154
- Sequel.application_timezone = :utc
2155
- Sequel.database_timezone = :local
2156
- Sequel.application_to_database_timestamp(t).must_equal t4
2157
- Sequel.application_timezone = :local
2158
- Sequel.database_timezone = :utc
2159
- Sequel.application_to_database_timestamp(t2).must_equal t3
2160
- ensure
2161
- Sequel.default_timezone = nil
2162
- end
2163
- end
2164
-
2165
- it "should have Database#to_application_timestamp convert values using the database's timezone" do
2166
- begin
2167
- t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
2168
- t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
2169
- t3 = Time.utc(2011, 1, 2, 3, 4, 5) - (t - t2) # Local Time in UTC Time
2170
- t4 = Time.mktime(2011, 1, 2, 3, 4, 5) + (t - t2) # UTC Time in Local Time
2171
- Sequel.default_timezone = :utc
2172
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t
2173
- Sequel.database_timezone = :local
2174
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t3
2175
- Sequel.default_timezone = :local
2176
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t2
2177
- Sequel.database_timezone = :utc
2178
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t4
2179
-
2180
- Sequel.default_timezone = :utc
2181
- @db.timezone = :local
2182
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t3
2183
- Sequel.default_timezone = :local
2184
- @db.timezone = :utc
2185
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t4
2186
- ensure
2187
- Sequel.default_timezone = nil
2188
- end
2189
- end
2190
-
2191
- it "should typecast datetime values to Sequel.datetime_class with correct timezone handling" do
2192
- t = Time.utc(2011, 1, 2, 3, 4, 5, 500000) # UTC Time
2193
- t2 = Time.mktime(2011, 1, 2, 3, 4, 5, 500000) # Local Time
2194
- t3 = Time.utc(2011, 1, 2, 3, 4, 5, 500000) - (t - t2) # Local Time in UTC Time
2195
- t4 = Time.mktime(2011, 1, 2, 3, 4, 5, 500000) + (t - t2) # UTC Time in Local Time
2196
- secs = Rational(11, 2)
2197
- r1 = Rational(t2.utc_offset, 86400)
2198
- r2 = Rational((t - t2).to_i, 86400)
2199
- dt = DateTime.civil(2011, 1, 2, 3, 4, secs)
2200
- dt2 = DateTime.civil(2011, 1, 2, 3, 4, secs, r1)
2201
- dt3 = DateTime.civil(2011, 1, 2, 3, 4, secs) - r2
2202
- dt4 = DateTime.civil(2011, 1, 2, 3, 4, secs, r1) + r2
2203
-
2204
- t.must_equal t4
2205
- t2.must_equal t3
2206
- dt.must_equal dt4
2207
- dt2.must_equal dt3
2208
-
2209
- check = proc do |i, o|
2210
- v = @db.typecast_value(:datetime, i)
2211
- v.must_equal o
2212
- if o.is_a?(Time)
2213
- v.utc_offset.must_equal o.utc_offset
2214
- else
2215
- v.offset.must_equal o.offset
2216
- end
2217
- end
2218
- @db.extend_datasets(Module.new{def supports_timestamp_timezones?; true; end})
2219
- begin
2220
- @db.typecast_value(:datetime, dt).must_equal t
2221
- @db.typecast_value(:datetime, dt2).must_equal t2
2222
- @db.typecast_value(:datetime, t).must_equal t
2223
- @db.typecast_value(:datetime, t2).must_equal t2
2224
- @db.typecast_value(:datetime, @db.literal(dt)[1...-1]).must_equal t
2225
- @db.typecast_value(:datetime, dt.strftime('%F %T.%N')).must_equal t2
2226
- @db.typecast_value(:datetime, Date.civil(2011, 1, 2)).must_equal Time.mktime(2011, 1, 2, 0, 0, 0)
2227
- @db.typecast_value(:datetime, :year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000).must_equal t2
2228
-
2229
- Sequel.datetime_class = DateTime
2230
- @db.typecast_value(:datetime, dt).must_equal dt
2231
- @db.typecast_value(:datetime, dt2).must_equal dt2
2232
- @db.typecast_value(:datetime, t).must_equal dt
2233
- @db.typecast_value(:datetime, t2).must_equal dt2
2234
- @db.typecast_value(:datetime, @db.literal(dt)[1...-1]).must_equal dt
2235
- @db.typecast_value(:datetime, dt.strftime('%F %T.%N')).must_equal dt
2236
- @db.typecast_value(:datetime, Date.civil(2011, 1, 2)).must_equal DateTime.civil(2011, 1, 2, 0, 0, 0)
2237
- @db.typecast_value(:datetime, :year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000).must_equal dt
2238
-
2239
- Sequel.application_timezone = :utc
2240
- Sequel.typecast_timezone = :local
2241
- Sequel.datetime_class = Time
2242
- check[dt, t]
2243
- check[dt2, t3]
2244
- check[t, t]
2245
- check[t2, t3]
2246
- check[@db.literal(dt)[1...-1], t]
2247
- check[dt.strftime('%F %T.%N'), t3]
2248
- check[Date.civil(2011, 1, 2), Time.utc(2011, 1, 2, 0, 0, 0)]
2249
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t3]
2250
-
2251
- Sequel.datetime_class = DateTime
2252
- check[dt, dt]
2253
- check[dt2, dt3]
2254
- check[t, dt]
2255
- check[t2, dt3]
2256
- check[@db.literal(dt)[1...-1], dt]
2257
- check[dt.strftime('%F %T.%N'), dt3]
2258
- check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0)]
2259
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt3]
2260
-
2261
- Sequel.typecast_timezone = :utc
2262
- Sequel.datetime_class = Time
2263
- check[dt, t]
2264
- check[dt2, t3]
2265
- check[t, t]
2266
- check[t2, t3]
2267
- check[@db.literal(dt)[1...-1], t]
2268
- check[dt.strftime('%F %T.%N'), t]
2269
- check[Date.civil(2011, 1, 2), Time.utc(2011, 1, 2, 0, 0, 0)]
2270
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t]
2271
-
2272
- Sequel.datetime_class = DateTime
2273
- check[dt, dt]
2274
- check[dt2, dt3]
2275
- check[t, dt]
2276
- check[t2, dt3]
2277
- check[@db.literal(dt)[1...-1], dt]
2278
- check[dt.strftime('%F %T.%N'), dt]
2279
- check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0)]
2280
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt]
2281
-
2282
- Sequel.application_timezone = :local
2283
- Sequel.datetime_class = Time
2284
- check[dt, t4]
2285
- check[dt2, t2]
2286
- check[t, t4]
2287
- check[t2, t2]
2288
- check[@db.literal(dt)[1...-1], t4]
2289
- check[dt.strftime('%F %T.%N'), t4]
2290
- check[Date.civil(2011, 1, 2), Time.local(2011, 1, 2, 0, 0, 0)]
2291
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t4]
2292
-
2293
- Sequel.datetime_class = DateTime
2294
- check[dt, dt4]
2295
- check[dt2, dt2]
2296
- check[t, dt4]
2297
- check[t2, dt2]
2298
- check[@db.literal(dt)[1...-1], dt4]
2299
- check[dt.strftime('%F %T.%N'), dt4]
2300
- check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0, r1)]
2301
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt4]
2302
-
2303
- Sequel.typecast_timezone = :local
2304
- Sequel.datetime_class = Time
2305
- check[dt, t4]
2306
- check[dt2, t2]
2307
- check[t, t4]
2308
- check[t2, t2]
2309
- check[@db.literal(dt)[1...-1], t4]
2310
- check[dt.strftime('%F %T.%N'), t2]
2311
- check[Date.civil(2011, 1, 2), Time.local(2011, 1, 2, 0, 0, 0)]
2312
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t2]
2313
-
2314
- Sequel.datetime_class = DateTime
2315
- check[dt, dt4]
2316
- check[dt2, dt2]
2317
- check[t, dt4]
2318
- check[t2, dt2]
2319
- check[@db.literal(dt)[1...-1], dt4]
2320
- check[dt.strftime('%F %T.%N'), dt2]
2321
- check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0, r1)]
2322
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt2]
2323
-
2324
- ensure
2325
- Sequel.default_timezone = nil
2326
- Sequel.datetime_class = Time
2327
- end
2328
- end
2329
-
2330
- it "should handle arrays when typecasting timestamps" do
2331
- begin
2332
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14]).must_equal Time.local(2011, 10, 11, 12, 13, 14)
2333
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14, 500000000]).must_equal Time.local(2011, 10, 11, 12, 13, 14, 500000)
2334
-
2335
- Sequel.datetime_class = DateTime
2336
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14]).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14)
2337
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14, 500000000]).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2))
2338
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14, 500000000, Rational(1, 2)]).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), Rational(1, 2))
2339
- ensure
2340
- Sequel.datetime_class = Time
2341
- end
2342
- end
2343
-
2344
- it "should handle hashes when typecasting timestamps" do
2345
- begin
2346
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).must_equal Time.local(2011, 10, 11, 12, 13, 14)
2347
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).must_equal Time.local(2011, 10, 11, 12, 13, 14, 500000)
2348
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).must_equal Time.local(2011, 10, 11, 12, 13, 14)
2349
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).must_equal Time.local(2011, 10, 11, 12, 13, 14, 500000)
2350
-
2351
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :offset=>Rational(1, 2)).must_equal Time.new(2011, 10, 11, 12, 13, 14, 43200)
2352
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000, :offset=>Rational(1, 2)).must_equal Time.new(2011, 10, 11, 12, 13, 14.5, 43200)
2353
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'offset'=>Rational(1, 2)).must_equal Time.new(2011, 10, 11, 12, 13, 14, 43200)
2354
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000, 'offset'=>Rational(1, 2)).must_equal Time.new(2011, 10, 11, 12, 13, 14.5, 43200)
2355
-
2356
- Sequel.default_timezone = :utc
2357
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).must_equal Time.utc(2011, 10, 11, 12, 13, 14)
2358
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).must_equal Time.utc(2011, 10, 11, 12, 13, 14, 500000)
2359
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).must_equal Time.utc(2011, 10, 11, 12, 13, 14)
2360
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).must_equal Time.utc(2011, 10, 11, 12, 13, 14, 500000)
2361
-
2362
- Sequel.datetime_class = DateTime
2363
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14)
2364
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2))
2365
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14)
2366
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2))
2367
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :offset=>Rational(1, 2)).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14, Rational(1, 2))
2368
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000, :offset=>Rational(1, 2)).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), Rational(1, 2))
2369
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'offset'=>Rational(1, 2)).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14, Rational(1, 2))
2370
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000, 'offset'=>Rational(1, 2)).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), Rational(1, 2))
2371
-
2372
- Sequel.default_timezone = :local
2373
- offset = Rational(Time.local(2011, 10, 11, 12, 13, 14).utc_offset, 86400)
2374
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14, offset)
2375
- @db.typecast_value(:datetime, :year=>2011, :month=>10, :day=>11, :hour=>12, :minute=>13, :second=>14, :nanos=>500000000).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), offset)
2376
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14, offset)
2377
- @db.typecast_value(:datetime, 'year'=>2011, 'month'=>10, 'day'=>11, 'hour'=>12, 'minute'=>13, 'second'=>14, 'nanos'=>500000000).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2), offset)
2378
- ensure
2379
- Sequel.datetime_class = Time
2380
- Sequel.default_timezone = nil
2381
- end
2382
- end
2383
-
2384
- it "should typecast decimal values to BigDecimal" do
2385
- [1.0, 1, '1.0', BigDecimal('1.0')].each do |i|
2386
- v = @db.typecast_value(:decimal, i)
2387
- v.must_be_kind_of(BigDecimal)
2388
- v.must_equal BigDecimal('1.0')
2389
- end
2390
- end
2391
-
2392
- it "should typecast float values to Float" do
2393
- [1.0, 1, '1.0', BigDecimal('1.0')].each do |i|
2394
- v = @db.typecast_value(:float, i)
2395
- v.must_be_kind_of(Float)
2396
- v.must_equal 1.0
2397
- end
2398
- end
2399
-
2400
- it "should typecast string values to String" do
2401
- [1.0, '1.0', Sequel.blob('1.0')].each do |i|
2402
- v = @db.typecast_value(:string, i)
2403
- v.must_be_instance_of(String)
2404
- v.must_equal "1.0"
2405
- end
2406
- end
2407
-
2408
- it "should raise errors when typecasting hash and array values to String" do
2409
- [[], {}].each do |i|
2410
- proc{@db.typecast_value(:string, i)}.must_raise(Sequel::InvalidValue)
2411
- end
2412
- end
2413
-
2414
- it "should typecast time values to SQLTime" do
2415
- t = Time.now
2416
- st = Sequel::SQLTime.local(t.year, t.month, t.day, 1, 2, 3)
2417
- [st, Time.utc(t.year, t.month, t.day, 1, 2, 3), Time.local(t.year, t.month, t.day, 1, 2, 3), '01:02:03', {:hour=>1, :minute=>2, :second=>3}].each do |i|
2418
- v = @db.typecast_value(:time, i)
2419
- v.must_be_instance_of(Sequel::SQLTime)
2420
- v.must_equal st
2421
- end
2422
- end
2423
-
2424
- it "should correctly handle time value conversion to SQLTime with fractional seconds" do
2425
- t = Time.now
2426
- st = Sequel::SQLTime.local(t.year, t.month, t.day, 1, 2, 3, 500000)
2427
- t = Time.local(t.year, t.month, t.day, 1, 2, 3, 500000)
2428
- @db.typecast_value(:time, t).must_equal st
2429
- end
2430
-
2431
- it "should have an underlying exception class available at wrapped_exception" do
2432
- begin
2433
- @db.typecast_value(:date, 'a')
2434
- true.must_equal false
2435
- rescue Sequel::InvalidValue => e
2436
- e.wrapped_exception.must_be_kind_of(ArgumentError)
2437
- end
2438
- end
2439
-
2440
- it "should have an underlying exception class available at cause" do
2441
- begin
2442
- @db.typecast_value(:date, 'a')
2443
- true.must_equal false
2444
- rescue Sequel::InvalidValue => e
2445
- e.cause.must_be_kind_of(ArgumentError)
2446
- end
2447
- end if RUBY_VERSION >= '2.1'
2448
-
2449
- it "should have an underlying exception class available at cause when using nested exceptions" do
2450
- begin
2451
- begin
2452
- raise ArgumentError
2453
- rescue => e1
2454
- begin
2455
- raise RuntimeError
2456
- rescue
2457
- @db.send(:raise_error, e1)
2458
- end
2459
- end
2460
- rescue Sequel::DatabaseError => e
2461
- e.cause.must_be_kind_of(ArgumentError)
2462
- end
2463
- end if RUBY_VERSION >= '2.1'
2464
-
2465
- it "should include underlying exception class in #inspect" do
2466
- begin
2467
- @db.typecast_value(:date, 'a')
2468
- true.must_equal false
2469
- rescue Sequel::InvalidValue => e
2470
- e.inspect.must_match(/\A#\<Sequel::InvalidValue: (Argument|Date::)Error: invalid date\>\z/)
2471
- end
2472
- end
2473
- end
2474
-
2475
- describe "Database#blank_object?" do
2476
- it "should return whether the object is considered blank" do
2477
- db = Sequel::Database.new
2478
- c = lambda{|meth, value| Class.new{define_method(meth){value}}.new}
2479
-
2480
- db.send(:blank_object?, "").must_equal true
2481
- db.send(:blank_object?, " ").must_equal true
2482
- db.send(:blank_object?, nil).must_equal true
2483
- db.send(:blank_object?, false).must_equal true
2484
- db.send(:blank_object?, []).must_equal true
2485
- db.send(:blank_object?, {}).must_equal true
2486
- db.send(:blank_object?, c[:empty?, true]).must_equal true
2487
- db.send(:blank_object?, c[:blank?, true]).must_equal true
2488
-
2489
- db.send(:blank_object?, " a ").must_equal false
2490
- db.send(:blank_object?, 1).must_equal false
2491
- db.send(:blank_object?, 1.0).must_equal false
2492
- db.send(:blank_object?, true).must_equal false
2493
- db.send(:blank_object?, [1]).must_equal false
2494
- db.send(:blank_object?, {1.0=>2.0}).must_equal false
2495
- db.send(:blank_object?, c[:empty?, false]).must_equal false
2496
- db.send(:blank_object?, c[:blank?, false]).must_equal false
2497
- end
2498
- end
2499
-
2500
- describe "Database#schema_autoincrementing_primary_key?" do
2501
- it "should indicate whether the parsed schema row indicates a primary key" do
2502
- m = Sequel::Database.new.method(:schema_autoincrementing_primary_key?)
2503
- m.call(:primary_key=>true, :auto_increment=>true).must_equal true
2504
- m.call(:primary_key=>true, :auto_increment=>false).must_equal false
2505
- m.call(:primary_key=>false).must_equal false
2506
- end
2507
- end
2508
-
2509
- describe "Database#supports_schema_parsing?" do
2510
- it "should be false by default" do
2511
- Sequel::Database.new.supports_schema_parsing?.must_equal false
2512
- end
2513
-
2514
- it "should be true if the database implements schema_parse_table" do
2515
- db = Sequel::Database.new
2516
- def db.schema_parse_table(*) end
2517
- db.supports_schema_parsing?.must_equal true
2518
- end
2519
- end
2520
-
2521
- describe "Database#supports_foreign_key_parsing?" do
2522
- it "should be false by default" do
2523
- Sequel::Database.new.supports_foreign_key_parsing?.must_equal false
2524
- end
2525
-
2526
- it "should be true if the database implements foreign_key_list" do
2527
- db = Sequel::Database.new
2528
- def db.foreign_key_list(*) end
2529
- db.supports_foreign_key_parsing?.must_equal true
2530
- end
2531
- end
2532
-
2533
- describe "Database#supports_index_parsing?" do
2534
- it "should be false by default" do
2535
- Sequel::Database.new.supports_index_parsing?.must_equal false
2536
- end
2537
-
2538
- it "should be true if the database implements indexes" do
2539
- db = Sequel::Database.new
2540
- def db.indexes(*) end
2541
- db.supports_index_parsing?.must_equal true
2542
- end
2543
- end
2544
-
2545
- describe "Database#supports_table_listing?" do
2546
- it "should be false by default" do
2547
- Sequel::Database.new.supports_table_listing?.must_equal false
2548
- end
2549
-
2550
- it "should be true if the database implements tables" do
2551
- db = Sequel::Database.new
2552
- def db.tables(*) end
2553
- db.supports_table_listing?.must_equal true
2554
- end
2555
- end
2556
-
2557
- describe "Database#supports_view_listing?" do
2558
- it "should be false by default" do
2559
- Sequel::Database.new.supports_view_listing?.must_equal false
2560
- end
2561
-
2562
- it "should be true if the database implements views" do
2563
- db = Sequel::Database.new
2564
- def db.views(*) end
2565
- db.supports_view_listing?.must_equal true
2566
- end
2567
- end
2568
-
2569
- describe "Database#supports_deferrable_constraints?" do
2570
- it "should be false by default" do
2571
- Sequel::Database.new.supports_deferrable_constraints?.must_equal false
2572
- end
2573
- end
2574
-
2575
- describe "Database#supports_deferrable_foreign_key_constraints?" do
2576
- it "should be false by default" do
2577
- Sequel::Database.new.supports_deferrable_foreign_key_constraints?.must_equal false
2578
- end
2579
- end
2580
-
2581
- describe "Database#supports_transactional_ddl?" do
2582
- it "should be false by default" do
2583
- Sequel::Database.new.supports_transactional_ddl?.must_equal false
2584
- end
2585
- end
2586
-
2587
- describe "Database#global_index_namespace?" do
2588
- it "should be true by default" do
2589
- Sequel::Database.new.global_index_namespace?.must_equal true
2590
- end
2591
- end
2592
-
2593
- describe "Database#supports_savepoints?" do
2594
- it "should be false by default" do
2595
- Sequel::Database.new.supports_savepoints?.must_equal false
2596
- end
2597
- end
2598
-
2599
- describe "Database#supports_views_with_check_option?" do
2600
- it "should be false by default" do
2601
- Sequel::Database.new.supports_views_with_check_option?.must_equal false
2602
- end
2603
- end
2604
-
2605
- describe "Database#supports_views_with_local_check_option?" do
2606
- it "should be false by default" do
2607
- Sequel::Database.new.supports_views_with_local_check_option?.must_equal false
2608
- end
2609
- end
2610
-
2611
- describe "Database#supports_savepoints_in_prepared_transactions?" do
2612
- it "should be false by default" do
2613
- Sequel::Database.new.supports_savepoints_in_prepared_transactions?.must_equal false
2614
- end
2615
-
2616
- it "should be true if both savepoints and prepared transactions are supported" do
2617
- db = Sequel::Database.new
2618
- db.define_singleton_method(:supports_savepoints?){true}
2619
- db.define_singleton_method(:supports_prepared_transactions?){true}
2620
- db.supports_savepoints_in_prepared_transactions?.must_equal true
2621
- end
2622
- end
2623
-
2624
- describe "Database#supports_prepared_transactions?" do
2625
- it "should be false by default" do
2626
- Sequel::Database.new.supports_prepared_transactions?.must_equal false
2627
- end
2628
- end
2629
-
2630
- describe "Database#supports_transaction_isolation_levels?" do
2631
- it "should be false by default" do
2632
- Sequel::Database.new.supports_transaction_isolation_levels?.must_equal false
2633
- end
2634
- end
2635
-
2636
- describe "Database#column_schema_to_ruby_default" do
2637
- it "should handle converting many default formats" do
2638
- db = Sequel::Database.new
2639
- p = lambda{|d,t| db.send(:column_schema_to_ruby_default, d, t)}
2640
- p[nil, :integer].must_be_nil
2641
- p[1, :integer].must_equal 1
2642
- p['1', :integer].must_equal 1
2643
- p['-1', :integer].must_equal(-1)
2644
- p[1.0, :float].must_equal 1.0
2645
- p['1.0', :float].must_equal 1.0
2646
- p['-1.0', :float].must_equal(-1.0)
2647
- p['1.0', :decimal].must_equal BigDecimal('1.0')
2648
- p['-1.0', :decimal].must_equal BigDecimal('-1.0')
2649
- p[true, :boolean].must_equal true
2650
- p[false, :boolean].must_equal false
2651
- p['1', :boolean].must_equal true
2652
- p['0', :boolean].must_equal false
2653
- p['true', :boolean].must_equal true
2654
- p['false', :boolean].must_equal false
2655
- p["'t'", :boolean].must_equal true
2656
- p["'f'", :boolean].must_equal false
2657
- p["'a'", :string].must_equal 'a'
2658
- p["'a'", :blob].must_equal Sequel.blob('a')
2659
- p["'a'", :blob].must_be_kind_of(Sequel::SQL::Blob)
2660
- p["''", :string].must_equal ''
2661
- p["'\\a''b'", :string].must_equal "\\a'b"
2662
- p["'NULL'", :string].must_equal "NULL"
2663
- p[Date.today, :date].must_equal Date.today
2664
- p["'2009-10-29'", :date].must_equal Date.new(2009,10,29)
2665
- p["CURRENT_TIMESTAMP", :date].must_equal Sequel::CURRENT_DATE
2666
- p["CURRENT_DATE", :date].must_equal Sequel::CURRENT_DATE
2667
- p["now()", :date].must_equal Sequel::CURRENT_DATE
2668
- p["getdate()", :date].must_equal Sequel::CURRENT_DATE
2669
- p["CURRENT_TIMESTAMP", :datetime].must_equal Sequel::CURRENT_TIMESTAMP
2670
- p["CURRENT_DATE", :datetime].must_equal Sequel::CURRENT_TIMESTAMP
2671
- p["now()", :datetime].must_equal Sequel::CURRENT_TIMESTAMP
2672
- p["getdate()", :datetime].must_equal Sequel::CURRENT_TIMESTAMP
2673
- p["'2009-10-29T10:20:30-07:00'", :datetime].must_equal DateTime.parse('2009-10-29T10:20:30-07:00')
2674
- p["'2009-10-29 10:20:30'", :datetime].must_equal DateTime.parse('2009-10-29 10:20:30')
2675
- p["'10:20:30'", :time].must_equal Time.parse('10:20:30')
2676
- p["NaN", :float].must_be_nil
2677
-
2678
- db = Sequel.mock(:host=>'postgres')
2679
- p["''::text", :string].must_equal ""
2680
- p["'\\a''b'::character varying", :string].must_equal "\\a'b"
2681
- p["'a'::bpchar", :string].must_equal "a"
2682
- p["(-1)", :integer].must_equal(-1)
2683
- p["(-1.0)", :float].must_equal(-1.0)
2684
- p['(-1.0)', :decimal].must_equal BigDecimal('-1.0')
2685
- p["'a'::bytea", :blob].must_equal Sequel.blob('a')
2686
- p["'a'::bytea", :blob].must_be_kind_of(Sequel::SQL::Blob)
2687
- p["'2009-10-29'::date", :date].must_equal Date.new(2009,10,29)
2688
- p["'2009-10-29 10:20:30.241343'::timestamp without time zone", :datetime].must_equal DateTime.parse('2009-10-29 10:20:30.241343')
2689
- p["'10:20:30'::time without time zone", :time].must_equal Time.parse('10:20:30')
2690
-
2691
- db = Sequel.mock(:host=>'mysql')
2692
- p["\\a'b", :string].must_equal "\\a'b"
2693
- p["a", :string].must_equal "a"
2694
- p["NULL", :string].must_equal "NULL"
2695
- p["-1", :float].must_equal(-1.0)
2696
- p['-1', :decimal].must_equal BigDecimal('-1.0')
2697
- p["2009-10-29", :date].must_equal Date.new(2009,10,29)
2698
- p["2009-10-29 10:20:30", :datetime].must_equal DateTime.parse('2009-10-29 10:20:30')
2699
- p["10:20:30", :time].must_equal Time.parse('10:20:30')
2700
- p["a", :enum].must_equal "a"
2701
- p["a,b", :set].must_equal "a,b"
2702
-
2703
- db = Sequel.mock(:host=>'mssql')
2704
- p["(N'a')", :string].must_equal "a"
2705
- p["((-12))", :integer].must_equal(-12)
2706
- p["((12.1))", :float].must_equal 12.1
2707
- p["((-12.1))", :decimal].must_equal BigDecimal('-12.1')
2708
- end
2709
- end
2710
-
2711
- describe "Database extensions" do
2712
- before(:all) do
2713
- class << Sequel
2714
- alias _extension extension
2715
- remove_method :extension
2716
- def extension(*)
2717
- end
2718
- end
2719
- end
2720
- after(:all) do
2721
- class << Sequel
2722
- remove_method :extension
2723
- alias extension _extension
2724
- remove_method :_extension
2725
- end
2726
- end
2727
- before do
2728
- @db = Sequel.mock
2729
- end
2730
- after do
2731
- Sequel::Database.instance_variable_set(:@initialize_hook, proc{|db| })
2732
- end
2733
-
2734
- it "should be able to register an extension with a module have Database#extension extend the module" do
2735
- Sequel::Database.register_extension(:foo, Module.new{def a; 1; end})
2736
- @db.extension(:foo).a.must_equal 1
2737
- end
2738
-
2739
- it "should not call the block multiple times if extension loaded more than once" do
2740
- @db.opts[:foo] = []
2741
- Sequel::Database.register_extension(:foo){|db| db.opts[:foo] << 1}
2742
- @db.extension(:foo).opts[:foo].must_equal [1]
2743
- @db.extension(:foo).opts[:foo].must_equal [1]
2744
- end
2745
-
2746
- it "should be able to register an extension with a block and have Database#extension call the block" do
2747
- Sequel::Database.register_extension(:foo){|db| db.opts[:foo] = 1}
2748
- @db.extension(:foo).opts[:foo].must_equal 1
2749
- end
2750
-
2751
- it "should be able to register an extension with a callable and Database#extension call the callable" do
2752
- Sequel::Database.register_extension(:foo, proc{|db| db.opts[:foo] = 1})
2753
- @db.extension(:foo).opts[:foo].must_equal 1
2754
- end
2755
-
2756
- it "should be able to load multiple extensions in the same call" do
2757
- a = []
2758
- Sequel::Database.register_extension(:foo, proc{|db| a << db.opts[:foo] = 1})
2759
- Sequel::Database.register_extension(:bar, proc{|db| a << db.opts[:bar] = 2})
2760
- @db.extension(:foo, :bar).opts.values_at(:foo, :bar).must_equal [1, 2]
2761
- a.must_equal [1, 2]
2762
- end
2763
-
2764
- it "should return the receiver" do
2765
- Sequel::Database.register_extension(:foo, Module.new{def a; 1; end})
2766
- @db.extension(:foo).must_be_same_as(@db)
2767
- end
2768
-
2769
- it "should raise an Error if registering with both a module and a block" do
2770
- proc{Sequel::Database.register_extension(:foo, Module.new){}}.must_raise(Sequel::Error)
2771
- end
2772
-
2773
- it "should raise an Error if attempting to load an incompatible extension" do
2774
- proc{@db.extension(:foo2)}.must_raise(Sequel::Error)
2775
- end
2776
-
2777
- it "should be able to load an extension into all future Databases with Database.extension" do
2778
- Sequel::Database.register_extension(:foo, Module.new{def a; 1; end})
2779
- Sequel::Database.register_extension(:bar, Module.new{def b; 2; end})
2780
- Sequel::Database.extension(:foo, :bar)
2781
- @db.wont_respond_to(:a)
2782
- @db.wont_respond_to(:b)
2783
- Sequel.mock.a.must_equal 1
2784
- Sequel.mock.b.must_equal 2
2785
- end
2786
-
2787
- it "should be loadable via the :extensions Database option" do
2788
- Sequel::Database.register_extension(:a, Module.new{def a; 1; end})
2789
- Sequel::Database.register_extension(:b, Module.new{def b; 2; end})
2790
- Sequel.mock(:extensions=>:a).a.must_equal 1
2791
- db = Sequel.mock(:extensions=>'a,b')
2792
- db.a.must_equal 1
2793
- db.b.must_equal 2
2794
- db = Sequel.mock(:extensions=>[:a, :b])
2795
- db.a.must_equal 1
2796
- db.b.must_equal 2
2797
- proc{Sequel.mock(:extensions=>nil).a}.must_raise NoMethodError
2798
- proc{Sequel.mock(:extensions=>Object.new)}.must_raise Sequel::Error
2799
- end
2800
-
2801
- it "should support :preconnect_extensions Database option to load extensions before :preconnect" do
2802
- x = []
2803
- Sequel::Database.register_extension(:a, Module.new{define_singleton_method(:extended){|_| x << :a}})
2804
- Sequel::Database.register_extension(:b, Module.new{define_singleton_method(:extended){|_| x << :b}})
2805
- m = Mutex.new
2806
- c = Class.new(Sequel::Database) do
2807
- def dataset_class_default; Sequel::Dataset end
2808
- define_method(:connect) do |_|
2809
- m.synchronize{x << :c}
2810
- :connect
2811
- end
2812
- end
2813
-
2814
- db = c.new(:max_connections=>2, :preconnect=>true, :preconnect_extensions=>:a, :extensions=>:b)
2815
- db.pool.size.must_equal db.pool.max_size
2816
- x.must_equal [:a, :c, :c, :b]
2817
-
2818
- x.clear
2819
- db = c.new(:max_connections=>3, :preconnect=>:concurrently, :preconnect_extensions=>:b, :extensions=>:a)
2820
- x.must_equal [:b, :c, :c, :c, :a]
2821
- db.pool.size.must_equal db.pool.max_size
2822
- end
2823
-
2824
- end
2825
-
2826
- describe "Database specific exception classes" do
2827
- before do
2828
- @db = Sequel.mock
2829
- class << @db
2830
- attr_accessor :sql_state
2831
-
2832
- def database_exception_sqlstate(exception, opts={})
2833
- @sql_state
2834
- end
2835
- end
2836
- end
2837
-
2838
- it "should use appropriate exception classes for given SQL states" do
2839
- @db.fetch = ArgumentError
2840
- @db.sql_state = '23502'
2841
- proc{@db.get(:a)}.must_raise(Sequel::NotNullConstraintViolation)
2842
- @db.sql_state = '23503'
2843
- proc{@db.get(:a)}.must_raise(Sequel::ForeignKeyConstraintViolation)
2844
- @db.sql_state = '23505'
2845
- proc{@db.get(:a)}.must_raise(Sequel::UniqueConstraintViolation)
2846
- @db.sql_state = '23513'
2847
- proc{@db.get(:a)}.must_raise(Sequel::CheckConstraintViolation)
2848
- @db.sql_state = '40001'
2849
- proc{@db.get(:a)}.must_raise(Sequel::SerializationFailure)
2850
- end
2851
- end
2852
-
2853
- describe "Database.after_initialize" do
2854
- after do
2855
- Sequel::Database.instance_variable_set(:@initialize_hook, proc{|db| })
2856
- end
2857
-
2858
- it "should allow a block to be run after each new instance is created" do
2859
- Sequel::Database.after_initialize{|db| db.sql_log_level = :debug }
2860
- db = Sequel.mock
2861
- db.sql_log_level.must_equal :debug
2862
- end
2863
-
2864
- it "should allow multiple hooks to be registered" do
2865
- Sequel::Database.after_initialize{|db| db.sql_log_level = :debug }
2866
- Sequel::Database.after_initialize{|db| db.loggers << 11 }
2867
-
2868
- db = Sequel.mock
2869
-
2870
- db.sql_log_level.must_equal :debug
2871
- db.loggers.must_include(11)
2872
- end
2873
-
2874
- it "should raise an error if registration is called without a block" do
2875
- proc {
2876
- Sequel::Database.after_initialize
2877
- }.must_raise(Sequel::Error, /must provide block/i)
2878
- end
2879
- end
2880
-
2881
- describe "Database#schema_type_class" do
2882
- it "should return the class or array of classes for the given type symbol" do
2883
- db = Sequel.mock
2884
- {:string=>String, :integer=>Integer, :date=>Date, :datetime=>[Time, DateTime],
2885
- :time=>Sequel::SQLTime, :boolean=>[TrueClass, FalseClass], :float=>Float, :decimal=>BigDecimal,
2886
- :blob=>Sequel::SQL::Blob}.each do |sym, klass|
2887
- db.schema_type_class(sym).must_equal klass
2888
- end
2889
- end
2890
- end
2891
-
2892
- describe "Database#execute_{dui,ddl,insert}" do
2893
- before do
2894
- @db = Sequel::Database.new
2895
- def @db.execute(sql, opts={})
2896
- (@sqls ||= []) << sql
2897
- end
2898
- def @db.sqls
2899
- @sqls
2900
- end
2901
- end
2902
-
2903
- it "should execute the SQL" do
2904
- @db.execute_dui "DELETE FROM table"
2905
- @db.execute_ddl "SET foo"
2906
- @db.execute_insert "INSERT INTO table DEFAULT VALUES"
2907
- @db.sqls.must_equal ["DELETE FROM table", "SET foo", "INSERT INTO table DEFAULT VALUES"]
2908
- end
2909
- end
2910
-
2911
- describe "Dataset identifier folding" do
2912
- it "should fold to uppercase by default, as per SQL" do
2913
- Sequel::Database.new.send(:folds_unquoted_identifiers_to_uppercase?).must_equal true
2914
- end
2915
- end