sequel 5.29.0 → 5.30.0

Sign up to get free protection for your applications and to get access to all the features.
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