sequel 5.20.0 → 5.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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