sequel 5.20.0 → 5.49.0

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