sequel 5.8.0 → 5.38.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 (510) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +409 -1795
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/bin/sequel +4 -0
  6. data/doc/advanced_associations.rdoc +136 -18
  7. data/doc/association_basics.rdoc +10 -5
  8. data/doc/cheat_sheet.rdoc +1 -0
  9. data/doc/code_order.rdoc +12 -2
  10. data/doc/dataset_filtering.rdoc +17 -2
  11. data/doc/mass_assignment.rdoc +3 -3
  12. data/doc/model_dataset_method_design.rdoc +1 -1
  13. data/doc/model_plugins.rdoc +1 -1
  14. data/doc/opening_databases.rdoc +30 -8
  15. data/doc/postgresql.rdoc +107 -2
  16. data/doc/release_notes/5.10.0.txt +84 -0
  17. data/doc/release_notes/5.11.0.txt +83 -0
  18. data/doc/release_notes/5.12.0.txt +141 -0
  19. data/doc/release_notes/5.13.0.txt +27 -0
  20. data/doc/release_notes/5.14.0.txt +63 -0
  21. data/doc/release_notes/5.15.0.txt +39 -0
  22. data/doc/release_notes/5.16.0.txt +110 -0
  23. data/doc/release_notes/5.17.0.txt +31 -0
  24. data/doc/release_notes/5.18.0.txt +69 -0
  25. data/doc/release_notes/5.19.0.txt +28 -0
  26. data/doc/release_notes/5.20.0.txt +89 -0
  27. data/doc/release_notes/5.21.0.txt +87 -0
  28. data/doc/release_notes/5.22.0.txt +48 -0
  29. data/doc/release_notes/5.23.0.txt +56 -0
  30. data/doc/release_notes/5.24.0.txt +56 -0
  31. data/doc/release_notes/5.25.0.txt +32 -0
  32. data/doc/release_notes/5.26.0.txt +35 -0
  33. data/doc/release_notes/5.27.0.txt +21 -0
  34. data/doc/release_notes/5.28.0.txt +16 -0
  35. data/doc/release_notes/5.29.0.txt +22 -0
  36. data/doc/release_notes/5.30.0.txt +20 -0
  37. data/doc/release_notes/5.31.0.txt +148 -0
  38. data/doc/release_notes/5.32.0.txt +46 -0
  39. data/doc/release_notes/5.33.0.txt +24 -0
  40. data/doc/release_notes/5.34.0.txt +40 -0
  41. data/doc/release_notes/5.35.0.txt +56 -0
  42. data/doc/release_notes/5.36.0.txt +60 -0
  43. data/doc/release_notes/5.37.0.txt +30 -0
  44. data/doc/release_notes/5.38.0.txt +28 -0
  45. data/doc/release_notes/5.9.0.txt +99 -0
  46. data/doc/security.rdoc +10 -0
  47. data/doc/sharding.rdoc +42 -28
  48. data/doc/sql.rdoc +12 -0
  49. data/doc/testing.rdoc +24 -17
  50. data/doc/transactions.rdoc +78 -0
  51. data/doc/validations.rdoc +2 -2
  52. data/lib/sequel/adapters/ado.rb +26 -18
  53. data/lib/sequel/adapters/ado/access.rb +2 -2
  54. data/lib/sequel/adapters/ado/mssql.rb +5 -8
  55. data/lib/sequel/adapters/amalgalite.rb +1 -1
  56. data/lib/sequel/adapters/jdbc.rb +71 -27
  57. data/lib/sequel/adapters/jdbc/mysql.rb +6 -6
  58. data/lib/sequel/adapters/jdbc/oracle.rb +7 -6
  59. data/lib/sequel/adapters/jdbc/postgresql.rb +17 -28
  60. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +5 -6
  61. data/lib/sequel/adapters/jdbc/sqlite.rb +33 -2
  62. data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -3
  63. data/lib/sequel/adapters/jdbc/transactions.rb +14 -28
  64. data/lib/sequel/adapters/mysql.rb +14 -15
  65. data/lib/sequel/adapters/mysql2.rb +5 -3
  66. data/lib/sequel/adapters/odbc.rb +4 -6
  67. data/lib/sequel/adapters/oracle.rb +7 -7
  68. data/lib/sequel/adapters/postgres.rb +52 -16
  69. data/lib/sequel/adapters/shared/access.rb +16 -12
  70. data/lib/sequel/adapters/shared/db2.rb +5 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +41 -18
  72. data/lib/sequel/adapters/shared/mysql.rb +66 -19
  73. data/lib/sequel/adapters/shared/oracle.rb +29 -23
  74. data/lib/sequel/adapters/shared/postgres.rb +341 -95
  75. data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
  76. data/lib/sequel/adapters/shared/sqlite.rb +174 -21
  77. data/lib/sequel/adapters/sqlanywhere.rb +33 -17
  78. data/lib/sequel/adapters/sqlite.rb +78 -68
  79. data/lib/sequel/adapters/tinytds.rb +14 -6
  80. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +2 -5
  81. data/lib/sequel/adapters/utils/mysql_mysql2.rb +5 -1
  82. data/lib/sequel/connection_pool.rb +2 -6
  83. data/lib/sequel/connection_pool/sharded_single.rb +7 -4
  84. data/lib/sequel/connection_pool/sharded_threaded.rb +32 -21
  85. data/lib/sequel/connection_pool/single.rb +1 -1
  86. data/lib/sequel/connection_pool/threaded.rb +26 -11
  87. data/lib/sequel/core.rb +327 -319
  88. data/lib/sequel/database/connecting.rb +7 -8
  89. data/lib/sequel/database/logging.rb +7 -1
  90. data/lib/sequel/database/misc.rb +68 -34
  91. data/lib/sequel/database/query.rb +6 -4
  92. data/lib/sequel/database/schema_generator.rb +31 -11
  93. data/lib/sequel/database/schema_methods.rb +32 -22
  94. data/lib/sequel/database/transactions.rb +129 -25
  95. data/lib/sequel/dataset.rb +4 -2
  96. data/lib/sequel/dataset/actions.rb +34 -23
  97. data/lib/sequel/dataset/features.rb +34 -0
  98. data/lib/sequel/dataset/graph.rb +27 -11
  99. data/lib/sequel/dataset/misc.rb +17 -3
  100. data/lib/sequel/dataset/placeholder_literalizer.rb +50 -21
  101. data/lib/sequel/dataset/prepared_statements.rb +96 -26
  102. data/lib/sequel/dataset/query.rb +43 -8
  103. data/lib/sequel/dataset/sql.rb +189 -41
  104. data/lib/sequel/deprecated.rb +3 -1
  105. data/lib/sequel/exceptions.rb +2 -0
  106. data/lib/sequel/extensions/_pretty_table.rb +1 -2
  107. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  108. data/lib/sequel/extensions/caller_logging.rb +79 -0
  109. data/lib/sequel/extensions/columns_introspection.rb +1 -2
  110. data/lib/sequel/extensions/connection_expiration.rb +6 -6
  111. data/lib/sequel/extensions/connection_validator.rb +7 -6
  112. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  113. data/lib/sequel/extensions/constraint_validations.rb +53 -28
  114. data/lib/sequel/extensions/core_refinements.rb +2 -0
  115. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -0
  116. data/lib/sequel/extensions/escaped_like.rb +100 -0
  117. data/lib/sequel/extensions/eval_inspect.rb +3 -1
  118. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  119. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  120. data/lib/sequel/extensions/index_caching.rb +9 -7
  121. data/lib/sequel/extensions/integer64.rb +3 -1
  122. data/lib/sequel/extensions/looser_typecasting.rb +3 -3
  123. data/lib/sequel/extensions/migration.rb +13 -6
  124. data/lib/sequel/extensions/named_timezones.rb +84 -23
  125. data/lib/sequel/extensions/pg_array.rb +87 -79
  126. data/lib/sequel/extensions/pg_array_ops.rb +14 -6
  127. data/lib/sequel/extensions/pg_enum.rb +34 -18
  128. data/lib/sequel/extensions/pg_extended_date_support.rb +34 -14
  129. data/lib/sequel/extensions/pg_hstore.rb +6 -0
  130. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  131. data/lib/sequel/extensions/pg_inet.rb +15 -5
  132. data/lib/sequel/extensions/pg_interval.rb +2 -0
  133. data/lib/sequel/extensions/pg_json.rb +387 -123
  134. data/lib/sequel/extensions/pg_json_ops.rb +168 -0
  135. data/lib/sequel/extensions/pg_range.rb +20 -10
  136. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  137. data/lib/sequel/extensions/pg_row.rb +3 -2
  138. data/lib/sequel/extensions/pg_row_ops.rb +24 -0
  139. data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
  140. data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
  141. data/lib/sequel/extensions/query.rb +1 -0
  142. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  143. data/lib/sequel/extensions/s.rb +2 -0
  144. data/lib/sequel/extensions/schema_dumper.rb +13 -7
  145. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +4 -2
  146. data/lib/sequel/extensions/server_block.rb +18 -7
  147. data/lib/sequel/extensions/sql_comments.rb +2 -2
  148. data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
  149. data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
  150. data/lib/sequel/extensions/to_dot.rb +9 -3
  151. data/lib/sequel/model.rb +3 -1
  152. data/lib/sequel/model/associations.rb +403 -69
  153. data/lib/sequel/model/base.rb +170 -90
  154. data/lib/sequel/model/plugins.rb +105 -0
  155. data/lib/sequel/plugins/after_initialize.rb +1 -1
  156. data/lib/sequel/plugins/association_dependencies.rb +3 -3
  157. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  158. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  159. data/lib/sequel/plugins/association_pks.rb +74 -22
  160. data/lib/sequel/plugins/association_proxies.rb +6 -2
  161. data/lib/sequel/plugins/auto_validations.rb +36 -17
  162. data/lib/sequel/plugins/blacklist_security.rb +1 -2
  163. data/lib/sequel/plugins/boolean_subsets.rb +4 -1
  164. data/lib/sequel/plugins/caching.rb +3 -0
  165. data/lib/sequel/plugins/class_table_inheritance.rb +62 -34
  166. data/lib/sequel/plugins/composition.rb +13 -9
  167. data/lib/sequel/plugins/csv_serializer.rb +28 -9
  168. data/lib/sequel/plugins/defaults_setter.rb +2 -2
  169. data/lib/sequel/plugins/dirty.rb +60 -22
  170. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  171. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  172. data/lib/sequel/plugins/finder.rb +2 -2
  173. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  174. data/lib/sequel/plugins/hook_class_methods.rb +17 -5
  175. data/lib/sequel/plugins/insert_conflict.rb +72 -0
  176. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  177. data/lib/sequel/plugins/inverted_subsets.rb +2 -2
  178. data/lib/sequel/plugins/json_serializer.rb +21 -14
  179. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  180. data/lib/sequel/plugins/list.rb +22 -10
  181. data/lib/sequel/plugins/many_through_many.rb +1 -1
  182. data/lib/sequel/plugins/nested_attributes.rb +27 -5
  183. data/lib/sequel/plugins/pg_array_associations.rb +12 -9
  184. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +149 -61
  185. data/lib/sequel/plugins/prepared_statements.rb +6 -12
  186. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
  187. data/lib/sequel/plugins/rcte_tree.rb +20 -22
  188. data/lib/sequel/plugins/sharding.rb +13 -7
  189. data/lib/sequel/plugins/single_table_inheritance.rb +20 -15
  190. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  191. data/lib/sequel/plugins/static_cache.rb +36 -17
  192. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  193. data/lib/sequel/plugins/string_stripper.rb +1 -1
  194. data/lib/sequel/plugins/subclasses.rb +2 -0
  195. data/lib/sequel/plugins/subset_conditions.rb +2 -2
  196. data/lib/sequel/plugins/tactical_eager_loading.rb +73 -2
  197. data/lib/sequel/plugins/throw_failures.rb +110 -0
  198. data/lib/sequel/plugins/tree.rb +49 -31
  199. data/lib/sequel/plugins/typecast_on_load.rb +3 -2
  200. data/lib/sequel/plugins/validation_class_methods.rb +11 -5
  201. data/lib/sequel/plugins/validation_helpers.rb +2 -2
  202. data/lib/sequel/sql.rb +120 -30
  203. data/lib/sequel/timezones.rb +55 -14
  204. data/lib/sequel/version.rb +6 -1
  205. metadata +101 -361
  206. data/Rakefile +0 -151
  207. data/doc/release_notes/4.0.0.txt +0 -262
  208. data/doc/release_notes/4.1.0.txt +0 -85
  209. data/doc/release_notes/4.10.0.txt +0 -226
  210. data/doc/release_notes/4.11.0.txt +0 -147
  211. data/doc/release_notes/4.12.0.txt +0 -105
  212. data/doc/release_notes/4.13.0.txt +0 -169
  213. data/doc/release_notes/4.14.0.txt +0 -68
  214. data/doc/release_notes/4.15.0.txt +0 -56
  215. data/doc/release_notes/4.16.0.txt +0 -36
  216. data/doc/release_notes/4.17.0.txt +0 -38
  217. data/doc/release_notes/4.18.0.txt +0 -36
  218. data/doc/release_notes/4.19.0.txt +0 -45
  219. data/doc/release_notes/4.2.0.txt +0 -129
  220. data/doc/release_notes/4.20.0.txt +0 -79
  221. data/doc/release_notes/4.21.0.txt +0 -94
  222. data/doc/release_notes/4.22.0.txt +0 -72
  223. data/doc/release_notes/4.23.0.txt +0 -65
  224. data/doc/release_notes/4.24.0.txt +0 -99
  225. data/doc/release_notes/4.25.0.txt +0 -181
  226. data/doc/release_notes/4.26.0.txt +0 -44
  227. data/doc/release_notes/4.27.0.txt +0 -78
  228. data/doc/release_notes/4.28.0.txt +0 -57
  229. data/doc/release_notes/4.29.0.txt +0 -41
  230. data/doc/release_notes/4.3.0.txt +0 -40
  231. data/doc/release_notes/4.30.0.txt +0 -37
  232. data/doc/release_notes/4.31.0.txt +0 -57
  233. data/doc/release_notes/4.32.0.txt +0 -132
  234. data/doc/release_notes/4.33.0.txt +0 -88
  235. data/doc/release_notes/4.34.0.txt +0 -86
  236. data/doc/release_notes/4.35.0.txt +0 -130
  237. data/doc/release_notes/4.36.0.txt +0 -116
  238. data/doc/release_notes/4.37.0.txt +0 -50
  239. data/doc/release_notes/4.38.0.txt +0 -67
  240. data/doc/release_notes/4.39.0.txt +0 -127
  241. data/doc/release_notes/4.4.0.txt +0 -92
  242. data/doc/release_notes/4.40.0.txt +0 -179
  243. data/doc/release_notes/4.41.0.txt +0 -77
  244. data/doc/release_notes/4.42.0.txt +0 -221
  245. data/doc/release_notes/4.43.0.txt +0 -87
  246. data/doc/release_notes/4.44.0.txt +0 -125
  247. data/doc/release_notes/4.45.0.txt +0 -370
  248. data/doc/release_notes/4.46.0.txt +0 -404
  249. data/doc/release_notes/4.47.0.txt +0 -56
  250. data/doc/release_notes/4.48.0.txt +0 -293
  251. data/doc/release_notes/4.49.0.txt +0 -222
  252. data/doc/release_notes/4.5.0.txt +0 -34
  253. data/doc/release_notes/4.6.0.txt +0 -30
  254. data/doc/release_notes/4.7.0.txt +0 -103
  255. data/doc/release_notes/4.8.0.txt +0 -175
  256. data/doc/release_notes/4.9.0.txt +0 -190
  257. data/spec/adapter_spec.rb +0 -4
  258. data/spec/adapters/db2_spec.rb +0 -170
  259. data/spec/adapters/mssql_spec.rb +0 -804
  260. data/spec/adapters/mysql_spec.rb +0 -1041
  261. data/spec/adapters/oracle_spec.rb +0 -327
  262. data/spec/adapters/postgres_spec.rb +0 -4000
  263. data/spec/adapters/spec_helper.rb +0 -43
  264. data/spec/adapters/sqlanywhere_spec.rb +0 -97
  265. data/spec/adapters/sqlite_spec.rb +0 -600
  266. data/spec/bin_spec.rb +0 -269
  267. data/spec/core/connection_pool_spec.rb +0 -1228
  268. data/spec/core/database_spec.rb +0 -2673
  269. data/spec/core/dataset_spec.rb +0 -5419
  270. data/spec/core/deprecated_spec.rb +0 -70
  271. data/spec/core/expression_filters_spec.rb +0 -1344
  272. data/spec/core/mock_adapter_spec.rb +0 -722
  273. data/spec/core/object_graph_spec.rb +0 -306
  274. data/spec/core/placeholder_literalizer_spec.rb +0 -166
  275. data/spec/core/schema_generator_spec.rb +0 -214
  276. data/spec/core/schema_spec.rb +0 -1820
  277. data/spec/core/spec_helper.rb +0 -23
  278. data/spec/core/version_spec.rb +0 -7
  279. data/spec/core_extensions_spec.rb +0 -762
  280. data/spec/core_model_spec.rb +0 -2
  281. data/spec/core_spec.rb +0 -1
  282. data/spec/deprecation_helper.rb +0 -30
  283. data/spec/extensions/accessed_columns_spec.rb +0 -51
  284. data/spec/extensions/active_model_spec.rb +0 -99
  285. data/spec/extensions/after_initialize_spec.rb +0 -24
  286. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  287. data/spec/extensions/association_dependencies_spec.rb +0 -125
  288. data/spec/extensions/association_pks_spec.rb +0 -423
  289. data/spec/extensions/association_proxies_spec.rb +0 -100
  290. data/spec/extensions/auto_literal_strings_spec.rb +0 -205
  291. data/spec/extensions/auto_validations_spec.rb +0 -202
  292. data/spec/extensions/blacklist_security_spec.rb +0 -95
  293. data/spec/extensions/blank_spec.rb +0 -69
  294. data/spec/extensions/boolean_readers_spec.rb +0 -93
  295. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  296. data/spec/extensions/caching_spec.rb +0 -273
  297. data/spec/extensions/class_table_inheritance_spec.rb +0 -568
  298. data/spec/extensions/column_conflicts_spec.rb +0 -75
  299. data/spec/extensions/column_select_spec.rb +0 -129
  300. data/spec/extensions/columns_introspection_spec.rb +0 -90
  301. data/spec/extensions/columns_updated_spec.rb +0 -35
  302. data/spec/extensions/composition_spec.rb +0 -248
  303. data/spec/extensions/connection_expiration_spec.rb +0 -133
  304. data/spec/extensions/connection_validator_spec.rb +0 -127
  305. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -300
  306. data/spec/extensions/constraint_validations_spec.rb +0 -395
  307. data/spec/extensions/core_refinements_spec.rb +0 -528
  308. data/spec/extensions/csv_serializer_spec.rb +0 -183
  309. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  310. data/spec/extensions/dataset_associations_spec.rb +0 -365
  311. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  312. data/spec/extensions/date_arithmetic_spec.rb +0 -181
  313. data/spec/extensions/datetime_parse_to_time_spec.rb +0 -169
  314. data/spec/extensions/def_dataset_method_spec.rb +0 -100
  315. data/spec/extensions/defaults_setter_spec.rb +0 -141
  316. data/spec/extensions/delay_add_association_spec.rb +0 -73
  317. data/spec/extensions/dirty_spec.rb +0 -189
  318. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -104
  319. data/spec/extensions/eager_each_spec.rb +0 -62
  320. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  321. data/spec/extensions/error_splitter_spec.rb +0 -18
  322. data/spec/extensions/error_sql_spec.rb +0 -20
  323. data/spec/extensions/eval_inspect_spec.rb +0 -74
  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 -380
  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 -275
  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 -840
  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 -109
  348. data/spec/extensions/nested_attributes_spec.rb +0 -703
  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 -165
  356. data/spec/extensions/pg_enum_spec.rb +0 -113
  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 -487
  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 -182
  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 -868
  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 -61
  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 -410
  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 -141
  409. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  410. data/spec/extensions/timestamps_spec.rb +0 -209
  411. data/spec/extensions/to_dot_spec.rb +0 -153
  412. data/spec/extensions/touch_spec.rb +0 -226
  413. data/spec/extensions/tree_spec.rb +0 -284
  414. data/spec/extensions/typecast_on_load_spec.rb +0 -86
  415. data/spec/extensions/unlimited_update_spec.rb +0 -21
  416. data/spec/extensions/update_or_create_spec.rb +0 -83
  417. data/spec/extensions/update_primary_key_spec.rb +0 -105
  418. data/spec/extensions/update_refresh_spec.rb +0 -59
  419. data/spec/extensions/uuid_spec.rb +0 -101
  420. data/spec/extensions/validate_associated_spec.rb +0 -52
  421. data/spec/extensions/validation_class_methods_spec.rb +0 -1040
  422. data/spec/extensions/validation_contexts_spec.rb +0 -31
  423. data/spec/extensions/validation_helpers_spec.rb +0 -525
  424. data/spec/extensions/whitelist_security_spec.rb +0 -157
  425. data/spec/extensions/xml_serializer_spec.rb +0 -213
  426. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  427. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  428. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  429. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  430. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  431. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  432. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  433. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  434. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  435. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  436. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  437. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  438. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  439. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  440. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  441. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  442. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  443. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  444. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  445. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  446. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  447. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  448. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  449. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  450. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  451. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  452. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  453. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  454. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  455. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  456. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  457. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  458. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  459. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  460. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  461. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  462. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  463. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  464. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  465. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  466. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  467. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  468. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  469. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  470. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  471. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  472. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  473. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  474. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  475. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  476. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  477. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  478. data/spec/guards_helper.rb +0 -58
  479. data/spec/integration/associations_test.rb +0 -2513
  480. data/spec/integration/database_test.rb +0 -113
  481. data/spec/integration/dataset_test.rb +0 -1880
  482. data/spec/integration/eager_loader_test.rb +0 -687
  483. data/spec/integration/migrator_test.rb +0 -262
  484. data/spec/integration/model_test.rb +0 -203
  485. data/spec/integration/plugin_test.rb +0 -2302
  486. data/spec/integration/prepared_statement_test.rb +0 -398
  487. data/spec/integration/schema_test.rb +0 -869
  488. data/spec/integration/spec_helper.rb +0 -64
  489. data/spec/integration/timezone_test.rb +0 -86
  490. data/spec/integration/transaction_test.rb +0 -354
  491. data/spec/integration/type_test.rb +0 -127
  492. data/spec/model/association_reflection_spec.rb +0 -803
  493. data/spec/model/associations_spec.rb +0 -4538
  494. data/spec/model/base_spec.rb +0 -817
  495. data/spec/model/class_dataset_methods_spec.rb +0 -146
  496. data/spec/model/dataset_methods_spec.rb +0 -198
  497. data/spec/model/eager_loading_spec.rb +0 -2262
  498. data/spec/model/hooks_spec.rb +0 -370
  499. data/spec/model/inflector_spec.rb +0 -26
  500. data/spec/model/model_spec.rb +0 -953
  501. data/spec/model/plugins_spec.rb +0 -318
  502. data/spec/model/record_spec.rb +0 -2107
  503. data/spec/model/spec_helper.rb +0 -45
  504. data/spec/model/validations_spec.rb +0 -193
  505. data/spec/model_no_assoc_spec.rb +0 -1
  506. data/spec/model_spec.rb +0 -1
  507. data/spec/plugin_spec.rb +0 -1
  508. data/spec/sequel_coverage.rb +0 -15
  509. data/spec/sequel_warning.rb +0 -4
  510. data/spec/spec_config.rb +0 -12
@@ -1,2673 +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
- end
1076
-
1077
- describe "Database#transaction with savepoint support" do
1078
- before do
1079
- @db = Sequel.mock(:servers=>{:test=>{}})
1080
- end
1081
-
1082
- include DatabaseTransactionSpecs
1083
-
1084
- it "should support :retry_on option for automatically retrying transactions when using :savepoint option" do
1085
- a = []
1086
- @db.transaction do
1087
- @db.transaction(:retry_on=>Sequel::SerializationFailure, :savepoint=>true) do
1088
- a << 1
1089
- raise Sequel::SerializationFailure if a.length == 1
1090
- end
1091
- end
1092
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "ROLLBACK TO SAVEPOINT autopoint_1", "SAVEPOINT autopoint_1", "RELEASE SAVEPOINT autopoint_1", "COMMIT"]
1093
- a.must_equal [1, 1]
1094
- end
1095
-
1096
- it "should automatically use a savepoint if :rollback=>:always given inside a transaction" do
1097
- @db.transaction do
1098
- @db.transaction(:rollback=>:always) do
1099
- @db.get(1)
1100
- end
1101
- end
1102
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SELECT 1 AS v LIMIT 1", "ROLLBACK TO SAVEPOINT autopoint_1", "COMMIT"]
1103
- end
1104
-
1105
- it "should support :retry_on option for automatically retrying transactions inside an :auto_savepoint transaction" do
1106
- a = []
1107
- @db.transaction(:auto_savepoint=>true) do
1108
- @db.transaction(:retry_on=>Sequel::SerializationFailure) do
1109
- a << 1
1110
- raise Sequel::SerializationFailure if a.length == 1
1111
- end
1112
- end
1113
- @db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "ROLLBACK TO SAVEPOINT autopoint_1", "SAVEPOINT autopoint_1", "RELEASE SAVEPOINT autopoint_1", "COMMIT"]
1114
- a.must_equal [1, 1]
1115
- end
1116
-
1117
- it "should support after_commit inside savepoints" do
1118
- @db.transaction do
1119
- @db.after_commit{@db.execute('foo')}
1120
- @db.transaction(:savepoint=>true){@db.after_commit{@db.execute('bar')}}
1121
- @db.after_commit{@db.execute('baz')}
1122
- end
1123
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT', 'foo', 'bar', 'baz']
1124
- end
1125
-
1126
- it "should support after_rollback inside savepoints" do
1127
- @db.transaction do
1128
- @db.after_rollback{@db.execute('foo')}
1129
- @db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('bar')}}
1130
- @db.after_rollback{@db.execute('baz')}
1131
- raise Sequel::Rollback
1132
- end
1133
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'RELEASE SAVEPOINT autopoint_1', 'ROLLBACK', 'foo', 'bar', 'baz']
1134
- end
1135
-
1136
- it "should raise an error if you attempt to use after_commit inside a savepoint in a prepared transaction" do
1137
- @db.define_singleton_method(:supports_prepared_transactions?){true}
1138
- proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_commit{@db.execute('foo')}}}}.must_raise(Sequel::Error)
1139
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1140
- end
1141
-
1142
- it "should raise an error if you attempt to use after_rollback inside a savepoint in a prepared transaction" do
1143
- @db.define_singleton_method(:supports_prepared_transactions?){true}
1144
- proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_rollback{@db.execute('foo')}}}}.must_raise(Sequel::Error)
1145
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1146
- end
1147
-
1148
- it "should create savepoint if inside a transaction when :savepoint=>:only is used" do
1149
- @db.transaction{@db.transaction(:savepoint=>:only){}}
1150
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1','RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1151
- end
1152
-
1153
- it "should not create transaction if not inside a transaction when :savepoint=>:only is used" do
1154
- @db.transaction(:savepoint=>:only){}
1155
- @db.sqls.must_equal []
1156
- end
1157
- end
1158
-
1159
- describe "Database#transaction without savepoint support" do
1160
- before do
1161
- @db = Sequel.mock(:servers=>{:test=>{}})
1162
- @db.define_singleton_method(:supports_savepoints?){false}
1163
- end
1164
-
1165
- it "should not create savepoint if inside a transaction when :savepoint=>:only is used" do
1166
- @db.transaction{@db.transaction(:savepoint=>:only){}}
1167
- @db.sqls.must_equal ['BEGIN', 'COMMIT']
1168
- end
1169
-
1170
- it "should automatically use a savepoint if :rollback=>:always given inside a transaction" do
1171
- proc do
1172
- @db.transaction do
1173
- @db.transaction(:rollback=>:always) do
1174
- @db.get(1)
1175
- end
1176
- end
1177
- end.must_raise Sequel::Error
1178
- @db.sqls.must_equal ["BEGIN", "ROLLBACK"]
1179
- end
1180
-
1181
- include DatabaseTransactionSpecs
1182
- end
1183
-
1184
- describe "Sequel.transaction" do
1185
- before do
1186
- @sqls = []
1187
- @db1 = Sequel.mock(:append=>'1', :sqls=>@sqls)
1188
- @db2 = Sequel.mock(:append=>'2', :sqls=>@sqls)
1189
- @db3 = Sequel.mock(:append=>'3', :sqls=>@sqls)
1190
- end
1191
-
1192
- it "should run the block inside transacitons on all three databases" do
1193
- Sequel.transaction([@db1, @db2, @db3]){1}.must_equal 1
1194
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
1195
- end
1196
-
1197
- it "should pass options to all the blocks" do
1198
- Sequel.transaction([@db1, @db2, @db3], :rollback=>:always){1}.must_equal 1
1199
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'ROLLBACK -- 3', 'ROLLBACK -- 2', 'ROLLBACK -- 1']
1200
- end
1201
-
1202
- it "should handle Sequel::Rollback exceptions raised by the block to rollback on all databases" do
1203
- Sequel.transaction([@db1, @db2, @db3]){raise Sequel::Rollback}.must_be_nil
1204
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'ROLLBACK -- 3', 'ROLLBACK -- 2', 'ROLLBACK -- 1']
1205
- end
1206
-
1207
- it "should handle nested transactions" do
1208
- Sequel.transaction([@db1, @db2, @db3]){Sequel.transaction([@db1, @db2, @db3]){1}}.must_equal 1
1209
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3', 'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
1210
- end
1211
-
1212
- it "should handle savepoints" do
1213
- Sequel.transaction([@db1, @db2, @db3]){Sequel.transaction([@db1, @db2, @db3], :savepoint=>true){1}}.must_equal 1
1214
- @sqls.must_equal ['BEGIN -- 1', 'BEGIN -- 2', 'BEGIN -- 3',
1215
- 'SAVEPOINT autopoint_1 -- 1', 'SAVEPOINT autopoint_1 -- 2', 'SAVEPOINT autopoint_1 -- 3',
1216
- 'RELEASE SAVEPOINT autopoint_1 -- 3', 'RELEASE SAVEPOINT autopoint_1 -- 2', 'RELEASE SAVEPOINT autopoint_1 -- 1',
1217
- 'COMMIT -- 3', 'COMMIT -- 2', 'COMMIT -- 1']
1218
- end
1219
- end
1220
-
1221
- describe "Database#transaction with savepoints" do
1222
- before do
1223
- @db = Sequel.mock
1224
- end
1225
-
1226
- it "should wrap the supplied block with BEGIN + COMMIT statements" do
1227
- @db.transaction {@db.execute 'DROP TABLE test;'}
1228
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1229
- end
1230
-
1231
- it "should use savepoints if given the :savepoint option" do
1232
- @db.transaction{@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}}
1233
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1234
- end
1235
-
1236
- it "should use savepoints if surrounding transaction uses :auto_savepoint option" do
1237
- @db.transaction(:auto_savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}
1238
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1239
-
1240
- @db.transaction(:auto_savepoint=>true){@db.transaction{@db.transaction{@db.execute 'DROP TABLE test;'}}}
1241
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1242
-
1243
- @db.transaction(:auto_savepoint=>true){@db.transaction(:auto_savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}}
1244
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1245
-
1246
- @db.transaction{@db.transaction(:auto_savepoint=>true, :savepoint=>true){@db.transaction{@db.execute 'DROP TABLE test;'}}}
1247
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'SAVEPOINT autopoint_2', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_2', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1248
- end
1249
-
1250
- it "should not use savepoints if surrounding transaction uses :auto_savepoint and current transaction uses :savepoint=>false option" do
1251
- @db.transaction(:auto_savepoint=>true){@db.transaction(:savepoint=>false){@db.execute 'DROP TABLE test;'}}
1252
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1253
- end
1254
-
1255
- it "should not use a savepoint if no transaction is in progress" do
1256
- @db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test;'}
1257
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1258
- end
1259
-
1260
- it "should reuse the current transaction if no :savepoint option is given" do
1261
- @db.transaction{@db.transaction{@db.execute 'DROP TABLE test;'}}
1262
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1263
- end
1264
-
1265
- it "should handle returning inside of the block by committing" do
1266
- def @db.ret_commit
1267
- transaction do
1268
- execute 'DROP TABLE test;'
1269
- return
1270
- end
1271
- end
1272
- @db.ret_commit
1273
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test;', 'COMMIT']
1274
- end
1275
-
1276
- it "should handle returning inside of a savepoint by committing" do
1277
- def @db.ret_commit
1278
- transaction do
1279
- transaction(:savepoint=>true) do
1280
- execute 'DROP TABLE test;'
1281
- return
1282
- end
1283
- end
1284
- end
1285
- @db.ret_commit
1286
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test;', 'RELEASE SAVEPOINT autopoint_1', 'COMMIT']
1287
- end
1288
-
1289
- it "should issue ROLLBACK if an exception is raised, and re-raise" do
1290
- @db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
1291
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
1292
-
1293
- proc {@db.transaction {raise RuntimeError}}.must_raise(RuntimeError)
1294
- end
1295
-
1296
- it "should issue ROLLBACK SAVEPOINT if an exception is raised inside a savepoint, and re-raise" do
1297
- @db.transaction{@db.transaction(:savepoint=>true){@db.execute 'DROP TABLE test'; raise RuntimeError}} rescue nil
1298
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE test', 'ROLLBACK TO SAVEPOINT autopoint_1', 'ROLLBACK']
1299
-
1300
- proc {@db.transaction {raise RuntimeError}}.must_raise(RuntimeError)
1301
- end
1302
-
1303
- it "should issue ROLLBACK if Sequel::Rollback is raised in the transaction" do
1304
- @db.transaction do
1305
- @db.drop_table(:a)
1306
- raise Sequel::Rollback
1307
- @db.drop_table(:b)
1308
- end
1309
-
1310
- @db.sqls.must_equal ['BEGIN', 'DROP TABLE a', 'ROLLBACK']
1311
- end
1312
-
1313
- it "should issue ROLLBACK SAVEPOINT if Sequel::Rollback is raised in a savepoint" do
1314
- @db.transaction do
1315
- @db.transaction(:savepoint=>true) do
1316
- @db.drop_table(:a)
1317
- raise Sequel::Rollback
1318
- end
1319
- @db.drop_table(:b)
1320
- end
1321
-
1322
- @db.sqls.must_equal ['BEGIN', 'SAVEPOINT autopoint_1', 'DROP TABLE a', 'ROLLBACK TO SAVEPOINT autopoint_1', 'DROP TABLE b', 'COMMIT']
1323
- end
1324
-
1325
- it "should raise database errors when commiting a transaction as Sequel::DatabaseError" do
1326
- @db.define_singleton_method(:commit_transaction){raise ArgumentError}
1327
- lambda{@db.transaction{}}.must_raise(ArgumentError)
1328
- lambda{@db.transaction{@db.transaction(:savepoint=>true){}}}.must_raise(ArgumentError)
1329
-
1330
- @db.define_singleton_method(:database_error_classes){[ArgumentError]}
1331
- lambda{@db.transaction{}}.must_raise(Sequel::DatabaseError)
1332
- lambda{@db.transaction{@db.transaction(:savepoint=>true){}}}.must_raise(Sequel::DatabaseError)
1333
- end
1334
- end
1335
-
1336
- describe "A Database adapter with a scheme" do
1337
- before do
1338
- require_relative '../../lib/sequel/adapters/mock'
1339
- @ccc = Class.new(Sequel::Mock::Database)
1340
- @ccc.send(:set_adapter_scheme, :ccc)
1341
- end
1342
-
1343
- it "should be registered in the ADAPTER_MAP" do
1344
- Sequel::ADAPTER_MAP[:ccc].must_equal @ccc
1345
- end
1346
-
1347
- it "should give the database_type as the adapter scheme by default" do
1348
- @ccc.new.database_type.must_equal :ccc
1349
- end
1350
-
1351
- it "should be instantiated when its scheme is specified" do
1352
- c = Sequel::Database.connect('ccc://localhost/db')
1353
- c.must_be_kind_of(@ccc)
1354
- c.opts[:host].must_equal 'localhost'
1355
- c.opts[:database].must_equal 'db'
1356
- end
1357
-
1358
- it "should be accessible through Sequel.connect" do
1359
- c = Sequel.connect 'ccc://localhost/db'
1360
- c.must_be_kind_of(@ccc)
1361
- c.opts[:host].must_equal 'localhost'
1362
- c.opts[:database].must_equal 'db'
1363
- end
1364
-
1365
- it "should be accessible through Sequel.connect via a block" do
1366
- x = nil
1367
- y = nil
1368
- z = nil
1369
- returnValue = 'anything'
1370
-
1371
- p = proc do |c|
1372
- c.must_be_kind_of(@ccc)
1373
- c.opts[:host].must_equal 'localhost'
1374
- c.opts[:database].must_equal 'db'
1375
- z = y
1376
- y = x
1377
- x = c
1378
- returnValue
1379
- end
1380
-
1381
- @ccc.class_eval do
1382
- self::DISCONNECTS = []
1383
- def disconnect
1384
- self.class::DISCONNECTS << self
1385
- end
1386
- end
1387
- Sequel::Database.connect('ccc://localhost/db', &p).must_equal returnValue
1388
- @ccc::DISCONNECTS.must_equal [x]
1389
-
1390
- Sequel.connect('ccc://localhost/db', &p).must_equal returnValue
1391
- @ccc::DISCONNECTS.must_equal [y, x]
1392
-
1393
- Sequel.send(:def_adapter_method, :ccc)
1394
- Sequel.ccc('db', :host=>'localhost', &p).must_equal returnValue
1395
- @ccc::DISCONNECTS.must_equal [z, y, x]
1396
- Sequel.singleton_class.send(:remove_method, :ccc)
1397
- end
1398
-
1399
- it "should be accessible through Sequel.<adapter>" do
1400
- Sequel.send(:def_adapter_method, :ccc)
1401
-
1402
- # invalid parameters
1403
- proc {Sequel.ccc('abc', 'def')}.must_raise(Sequel::Error)
1404
- proc {Sequel.ccc(1)}.must_raise(Sequel::Error)
1405
-
1406
- c = Sequel.ccc('mydb')
1407
- c.must_be_kind_of(@ccc)
1408
- c.opts.values_at(:adapter, :database, :adapter_class).must_equal [:ccc, 'mydb', @ccc]
1409
-
1410
- c = Sequel.ccc('mydb', :host => 'localhost')
1411
- c.must_be_kind_of(@ccc)
1412
- c.opts.values_at(:adapter, :database, :host, :adapter_class).must_equal [:ccc, 'mydb', 'localhost', @ccc]
1413
-
1414
- c = Sequel.ccc
1415
- c.must_be_kind_of(@ccc)
1416
- c.opts.values_at(:adapter, :adapter_class).must_equal [:ccc, @ccc]
1417
-
1418
- c = Sequel.ccc(:database => 'mydb', :host => 'localhost')
1419
- c.must_be_kind_of(@ccc)
1420
- c.opts.values_at(:adapter, :database, :host, :adapter_class).must_equal [:ccc, 'mydb', 'localhost', @ccc]
1421
- Sequel.singleton_class.send(:remove_method, :ccc)
1422
- end
1423
-
1424
- it "should be accessible through Sequel.connect with options" do
1425
- c = Sequel.connect(:adapter => :ccc, :database => 'mydb')
1426
- c.must_be_kind_of(@ccc)
1427
- c.opts[:adapter].must_equal :ccc
1428
- end
1429
-
1430
- it "should be accessible through Sequel.connect with URL parameters" do
1431
- c = Sequel.connect 'ccc:///db?host=/tmp&user=test'
1432
- c.must_be_kind_of(@ccc)
1433
- c.opts[:host].must_equal '/tmp'
1434
- c.opts[:database].must_equal 'db'
1435
- c.opts[:user].must_equal 'test'
1436
- end
1437
-
1438
- it "should have URL parameters take precedence over fixed URL parts" do
1439
- c = Sequel.connect 'ccc://localhost/db?host=a&database=b'
1440
- c.must_be_kind_of(@ccc)
1441
- c.opts[:host].must_equal 'a'
1442
- c.opts[:database].must_equal 'b'
1443
- end
1444
-
1445
- it "should have hash options take predence over URL parameters or parts" do
1446
- c = Sequel.connect 'ccc://localhost/db?host=/tmp', :host=>'a', :database=>'b', :user=>'c'
1447
- c.must_be_kind_of(@ccc)
1448
- c.opts[:host].must_equal 'a'
1449
- c.opts[:database].must_equal 'b'
1450
- c.opts[:user].must_equal 'c'
1451
- end
1452
-
1453
- it "should unescape values of URL parameters and parts" do
1454
- c = Sequel.connect 'ccc:///d%5bb%5d?host=domain%5cinstance'
1455
- c.must_be_kind_of(@ccc)
1456
- c.opts[:database].must_equal 'd[b]'
1457
- c.opts[:host].must_equal 'domain\\instance'
1458
- end
1459
-
1460
- it "should test the connection if test parameter is truthy" do
1461
- @ccc.send(:define_method, :connect){}
1462
- proc{Sequel.connect 'ccc:///d%5bb%5d?test=t'}.must_raise(Sequel::DatabaseConnectionError)
1463
- proc{Sequel.connect 'ccc:///d%5bb%5d?test=1'}.must_raise(Sequel::DatabaseConnectionError)
1464
- proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>true}.must_raise(Sequel::DatabaseConnectionError)
1465
- proc{Sequel.connect 'ccc:///d%5bb%5d', :test=>'t'}.must_raise(Sequel::DatabaseConnectionError)
1466
- end
1467
-
1468
- it "should not test the connection if test parameter is not truthy" do
1469
- Sequel.connect 'ccc:///d%5bb%5d?test=f'
1470
- Sequel.connect 'ccc:///d%5bb%5d?test=0'
1471
- Sequel.connect 'ccc:///d%5bb%5d', :test=>false
1472
- Sequel.connect 'ccc:///d%5bb%5d', :test=>'f'
1473
- end
1474
- end
1475
-
1476
- describe "Sequel::Database.connect" do
1477
- it "should raise an Error if not given a String or Hash" do
1478
- proc{Sequel::Database.connect(nil)}.must_raise(Sequel::Error)
1479
- proc{Sequel::Database.connect(Object.new)}.must_raise(Sequel::Error)
1480
- end
1481
- end
1482
-
1483
- describe "An unknown database scheme" do
1484
- it "should raise an error in Sequel::Database.connect" do
1485
- proc {Sequel::Database.connect('ddd://localhost/db')}.must_raise(Sequel::AdapterNotFound)
1486
- end
1487
-
1488
- it "should raise an error in Sequel.connect" do
1489
- proc {Sequel.connect('ddd://localhost/db')}.must_raise(Sequel::AdapterNotFound)
1490
- end
1491
- end
1492
-
1493
- describe "A broken adapter (lib is there but the class is not)" do
1494
- before do
1495
- @fn = File.join(File.dirname(__FILE__), '../../lib/sequel/adapters/blah.rb')
1496
- File.open(@fn,'a'){}
1497
- end
1498
-
1499
- after do
1500
- File.delete(@fn)
1501
- end
1502
-
1503
- it "should raise an error" do
1504
- proc {Sequel.connect('blah://blow')}.must_raise(Sequel::AdapterNotFound)
1505
- end
1506
- end
1507
-
1508
- describe "Sequel::Database.load_adapter" do
1509
- it "should not raise an error if subadapter does not exist" do
1510
- Sequel::Database.load_adapter(:foo, :subdir=>'bar').must_be_nil
1511
- end
1512
- end
1513
-
1514
- describe "A single threaded database" do
1515
- after do
1516
- Sequel.single_threaded = false
1517
- end
1518
-
1519
- it "should use a SingleConnectionPool instead of a ConnectionPool" do
1520
- db = Sequel::Database.new(:single_threaded => true){123}
1521
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
1522
- end
1523
-
1524
- it "should be constructable using :single_threaded => true option" do
1525
- db = Sequel::Database.new(:single_threaded => true){123}
1526
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
1527
- end
1528
-
1529
- it "should be constructable using Sequel.single_threaded = true" do
1530
- Sequel.single_threaded = true
1531
- Sequel.single_threaded.must_equal true
1532
- db = Sequel::Database.new{123}
1533
- db.pool.must_be_kind_of(Sequel::SingleConnectionPool)
1534
- end
1535
- end
1536
-
1537
- describe "A single threaded database" do
1538
- before do
1539
- conn = 1234567
1540
- @db = Sequel::Database.new(:single_threaded => true)
1541
- @db.define_singleton_method(:connect) do |c|
1542
- conn += 1
1543
- end
1544
- end
1545
-
1546
- it "should invoke connection_proc only once" do
1547
- @db.pool.hold {|c| c.must_equal 1234568}
1548
- @db.pool.hold {|c| c.must_equal 1234568}
1549
- end
1550
-
1551
- it "should disconnect correctly" do
1552
- def @db.disconnect_connection(c); @dc = c end
1553
- def @db.dc; @dc end
1554
- x = nil
1555
- @db.pool.hold{|c| x = c}
1556
- @db.pool.hold{|c| c.must_equal x}
1557
- @db.disconnect
1558
- @db.dc.must_equal x
1559
- end
1560
-
1561
- it "should convert an Exception on connection into a DatabaseConnectionError" do
1562
- db = Class.new(Sequel::Database){def connect(*) raise Exception end}.new(:single_threaded => true, :servers=>{}, :test=>false)
1563
- proc {db.pool.hold {|c|}}.must_raise(Sequel::DatabaseConnectionError)
1564
- end
1565
-
1566
- it "should raise a DatabaseConnectionError if the connection proc returns nil" do
1567
- db = Class.new(Sequel::Database){def connect(*) end}.new(:single_threaded => true, :servers=>{}, :test=>false)
1568
- proc {db.pool.hold {|c|}}.must_raise(Sequel::DatabaseConnectionError)
1569
- end
1570
- end
1571
-
1572
- describe "A database" do
1573
- after do
1574
- Sequel.single_threaded = false
1575
- end
1576
-
1577
- it "should have single_threaded? respond to true if in single threaded mode" do
1578
- db = Sequel::Database.new(:single_threaded => true){1234}
1579
- db.must_be :single_threaded?
1580
-
1581
- db = Sequel::Database.new(:max_options => 1)
1582
- db.wont_be :single_threaded?
1583
-
1584
- db = Sequel::Database.new
1585
- db.wont_be :single_threaded?
1586
-
1587
- Sequel.single_threaded = true
1588
-
1589
- db = Sequel::Database.new{123}
1590
- db.must_be :single_threaded?
1591
-
1592
- db = Sequel::Database.new(:max_options => 4){123}
1593
- db.must_be :single_threaded?
1594
- end
1595
-
1596
- it "should be able to set loggers via the logger= and loggers= methods" do
1597
- db = Sequel::Database.new
1598
- s = "I'm a logger"
1599
- db.logger = s
1600
- db.loggers.must_equal [s]
1601
- db.logger = nil
1602
- db.loggers.must_equal []
1603
-
1604
- db.loggers = [s]
1605
- db.loggers.must_equal [s]
1606
- db.loggers = []
1607
- db.loggers.must_equal []
1608
-
1609
- t = "I'm also a logger"
1610
- db.loggers = [s, t]
1611
- db.loggers.must_equal [s,t]
1612
- end
1613
- end
1614
-
1615
- describe "Database#fetch" do
1616
- before do
1617
- @db = Sequel.mock(:fetch=>proc{|sql| {:sql => sql}})
1618
- end
1619
-
1620
- it "should create a dataset and invoke its fetch_rows method with the given sql" do
1621
- sql = nil
1622
- @db.fetch('select * from xyz') {|r| sql = r[:sql]}
1623
- sql.must_equal 'select * from xyz'
1624
- end
1625
-
1626
- it "should format the given sql with any additional arguments" do
1627
- sql = nil
1628
- @db.fetch('select * from xyz where x = ? and y = ?', 15, 'abc') {|r| sql = r[:sql]}
1629
- sql.must_equal "select * from xyz where x = 15 and y = 'abc'"
1630
-
1631
- @db.fetch('select name from table where name = ? or id in ?', 'aman', [3,4,7]) {|r| sql = r[:sql]}
1632
- sql.must_equal "select name from table where name = 'aman' or id in (3, 4, 7)"
1633
- end
1634
-
1635
- it "should format the given sql with named arguments" do
1636
- sql = nil
1637
- @db.fetch('select * from xyz where x = :x and y = :y', :x=>15, :y=>'abc') {|r| sql = r[:sql]}
1638
- sql.must_equal "select * from xyz where x = 15 and y = 'abc'"
1639
- end
1640
-
1641
- it "should return the dataset if no block is given" do
1642
- @db.fetch('select * from xyz').must_be_kind_of(Sequel::Dataset)
1643
-
1644
- @db.fetch('select a from b').map {|r| r[:sql]}.must_equal ['select a from b']
1645
-
1646
- @db.fetch('select c from d').inject([]) {|m, r| m << r; m}.must_equal \
1647
- [{:sql => 'select c from d'}]
1648
- end
1649
-
1650
- it "should return a dataset that always uses the given sql for SELECTs" do
1651
- ds = @db.fetch('select * from xyz')
1652
- ds.select_sql.must_equal 'select * from xyz'
1653
- ds.sql.must_equal 'select * from xyz'
1654
-
1655
- ds = ds.where{price.sql_number < 100}
1656
- ds.select_sql.must_equal 'select * from xyz'
1657
- ds.sql.must_equal 'select * from xyz'
1658
- end
1659
- end
1660
-
1661
-
1662
- describe "Database#[]" do
1663
- before do
1664
- @db = Sequel.mock
1665
- end
1666
-
1667
- it "should return a dataset when symbols are given" do
1668
- ds = @db[:items]
1669
- ds.must_be_kind_of(Sequel::Dataset)
1670
- ds.opts[:from].must_equal [:items]
1671
- end
1672
-
1673
- it "should return a dataset when a string is given" do
1674
- @db.fetch = proc{|sql| {:sql=>sql}}
1675
- sql = nil
1676
- @db['select * from xyz where x = ? and y = ?', 15, 'abc'].each {|r| sql = r[:sql]}
1677
- sql.must_equal "select * from xyz where x = 15 and y = 'abc'"
1678
- end
1679
- end
1680
-
1681
- describe "Database#inspect" do
1682
- it "should include the class name and the connection url" do
1683
- Sequel.connect('mock://foo/bar').inspect.must_equal '#<Sequel::Mock::Database: "mock://foo/bar">'
1684
- end
1685
-
1686
- it "should include the class name and the connection options if an options hash was given" do
1687
- Sequel.connect(:adapter=>:mock).inspect.must_equal '#<Sequel::Mock::Database: {:adapter=>:mock}>'
1688
- end
1689
-
1690
- it "should include the class name, uri, and connection options if uri and options hash was given" do
1691
- Sequel.connect('mock://foo', :database=>'bar').inspect.must_equal '#<Sequel::Mock::Database: "mock://foo" {:database=>"bar"}>'
1692
- end
1693
- end
1694
-
1695
- describe "Database#get" do
1696
- before do
1697
- @db = Sequel.mock(:fetch=>{:a=>1})
1698
- end
1699
-
1700
- it "should use Dataset#get to get a single value" do
1701
- @db.get(:a).must_equal 1
1702
- @db.sqls.must_equal ['SELECT a LIMIT 1']
1703
-
1704
- @db.get(Sequel.function(:version).as(:version))
1705
- @db.sqls.must_equal ['SELECT version() AS version LIMIT 1']
1706
- end
1707
-
1708
- it "should accept a block" do
1709
- @db.get{a}
1710
- @db.sqls.must_equal ['SELECT a LIMIT 1']
1711
-
1712
- @db.get{version(a).as(version)}
1713
- @db.sqls.must_equal ['SELECT version(a) AS version LIMIT 1']
1714
- end
1715
-
1716
- it "should work when an alias cannot be determined" do
1717
- @db.get(1).must_equal 1
1718
- @db.sqls.must_equal ['SELECT 1 AS v LIMIT 1']
1719
- end
1720
- end
1721
-
1722
- describe "Database#call" do
1723
- it "should call the prepared statement with the given name" do
1724
- db = Sequel.mock(:fetch=>{:id => 1, :x => 1})
1725
- db[:items].prepare(:select, :select_all)
1726
- db.call(:select_all).must_equal [{:id => 1, :x => 1}]
1727
- db[:items].filter(:n=>:$n).prepare(:select, :select_n)
1728
- db.call(:select_n, :n=>1).must_equal [{:id => 1, :x => 1}]
1729
- db.sqls.must_equal ['SELECT * FROM items', 'SELECT * FROM items WHERE (n = 1)']
1730
- end
1731
- end
1732
-
1733
- describe "Database#server_opts" do
1734
- it "should return the general opts if no :servers option is used" do
1735
- opts = {:host=>1, :database=>2}
1736
- Sequel::Database.new(opts).send(:server_opts, :server1)[:host].must_equal 1
1737
- end
1738
-
1739
- it "should return the general opts if entry for the server is present in the :servers option" do
1740
- opts = {:host=>1, :database=>2, :servers=>{}}
1741
- Sequel::Database.new(opts).send(:server_opts, :server1)[:host].must_equal 1
1742
- end
1743
-
1744
- it "should return the general opts merged with the specific opts if given as a hash" do
1745
- opts = {:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}}}
1746
- Sequel::Database.new(opts).send(:server_opts, :server1)[:host].must_equal 3
1747
- end
1748
-
1749
- it "should return the sgeneral opts merged with the specific opts if given as a proc" do
1750
- opts = {:host=>1, :database=>2, :servers=>{:server1=>proc{|db| {:host=>4}}}}
1751
- Sequel::Database.new(opts).send(:server_opts, :server1)[:host].must_equal 4
1752
- end
1753
-
1754
- it "should raise an error if the specific opts is not a proc or hash" do
1755
- opts = {:host=>1, :database=>2, :servers=>{:server1=>2}}
1756
- proc{Sequel::Database.new(opts).send(:server_opts, :server1)}.must_raise(Sequel::Error)
1757
- end
1758
-
1759
- it "should return the general opts merged with given opts if given opts is a Hash" do
1760
- opts = {:host=>1, :database=>2}
1761
- Sequel::Database.new(opts).send(:server_opts, :host=>2)[:host].must_equal 2
1762
- end
1763
- end
1764
-
1765
- describe "Database#add_servers" do
1766
- before do
1767
- @db = Sequel.mock(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}})
1768
- end
1769
-
1770
- it "should add new servers to the connection pool" do
1771
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1772
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1773
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
1774
-
1775
- @db.add_servers(:server2=>{:host=>6})
1776
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1777
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1778
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 6}
1779
-
1780
- @db.disconnect
1781
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1782
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1783
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 6}
1784
- end
1785
-
1786
- it "should replace options for future connections to existing servers" do
1787
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1788
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1789
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
1790
-
1791
- @db.add_servers(:default=>proc{{:host=>4}}, :server1=>{:host=>8})
1792
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1793
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1794
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
1795
-
1796
- @db.disconnect
1797
- @db.synchronize{|c| c.opts[:host].must_equal 4}
1798
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 8}
1799
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 4}
1800
- end
1801
-
1802
- it "should raise error for unsharded pool" do
1803
- proc{Sequel.mock.add_servers(:server1=>{})}.must_raise Sequel::Error
1804
- end
1805
- end
1806
-
1807
- describe "Database#remove_servers" do
1808
- before do
1809
- @db = Sequel.mock(:host=>1, :database=>2, :servers=>{:server1=>{:host=>3}, :server2=>{:host=>4}})
1810
- end
1811
-
1812
- it "should remove servers from the connection pool" do
1813
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1814
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 3}
1815
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 4}
1816
-
1817
- @db.remove_servers(:server1, :server2)
1818
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1819
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 1}
1820
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
1821
- end
1822
-
1823
- it "should accept arrays of symbols" do
1824
- @db.remove_servers([:server1, :server2])
1825
- @db.synchronize{|c| c.opts[:host].must_equal 1}
1826
- @db.synchronize(:server1){|c| c.opts[:host].must_equal 1}
1827
- @db.synchronize(:server2){|c| c.opts[:host].must_equal 1}
1828
- end
1829
-
1830
- it "should allow removal while connections are still open" do
1831
- @db.synchronize do |c1|
1832
- c1.opts[:host].must_equal 1
1833
- @db.synchronize(:server1) do |c2|
1834
- c2.opts[:host].must_equal 3
1835
- @db.synchronize(:server2) do |c3|
1836
- c3.opts[:host].must_equal 4
1837
- @db.remove_servers(:server1, :server2)
1838
- @db.synchronize(:server1) do |c4|
1839
- c4.wont_equal c2
1840
- c4.must_equal c1
1841
- c4.opts[:host].must_equal 1
1842
- @db.synchronize(:server2) do |c5|
1843
- c5.wont_equal c3
1844
- c5.must_equal c1
1845
- c5.opts[:host].must_equal 1
1846
- end
1847
- end
1848
- c3.opts[:host].must_equal 4
1849
- end
1850
- c2.opts[:host].must_equal 3
1851
- end
1852
- c1.opts[:host].must_equal 1
1853
- end
1854
- end
1855
-
1856
- it "should raise error for unsharded pool" do
1857
- proc{Sequel.mock.remove_servers(:server1)}.must_raise Sequel::Error
1858
- end
1859
- end
1860
-
1861
- describe "Database#raise_error" do
1862
- before do
1863
- @db = Sequel.mock
1864
- end
1865
-
1866
- it "should reraise if the exception class is not in opts[:classes]" do
1867
- e = Class.new(StandardError)
1868
- proc{@db.send(:raise_error, e.new(''), :classes=>[])}.must_raise(e)
1869
- end
1870
-
1871
- it "should convert the exception to a DatabaseError if the exception class is in opts[:classes]" do
1872
- proc{@db.send(:raise_error, Interrupt.new(''), :classes=>[Interrupt])}.must_raise(Sequel::DatabaseError)
1873
- end
1874
-
1875
- it "should convert the exception to a DatabaseError if opts[:classes] if not present" do
1876
- proc{@db.send(:raise_error, Interrupt.new(''))}.must_raise(Sequel::DatabaseError)
1877
- end
1878
-
1879
- it "should convert the exception to a DatabaseDisconnectError if opts[:disconnect] is true" do
1880
- proc{@db.send(:raise_error, Interrupt.new(''), :disconnect=>true)}.must_raise(Sequel::DatabaseDisconnectError)
1881
- end
1882
-
1883
- it "should convert the exception to an appropriate error if exception message matches regexp" do
1884
- def @db.database_error_regexps
1885
- {/foo/ => Sequel::DatabaseDisconnectError, /bar/ => Sequel::ConstraintViolation}
1886
- end
1887
- e = Class.new(StandardError)
1888
- proc{@db.send(:raise_error, e.new('foo'))}.must_raise(Sequel::DatabaseDisconnectError)
1889
- proc{@db.send(:raise_error, e.new('bar'))}.must_raise(Sequel::ConstraintViolation)
1890
- end
1891
- end
1892
-
1893
- describe "Database#typecast_value" do
1894
- before do
1895
- @db = Sequel::Database.new
1896
- end
1897
-
1898
- it "should raise an InvalidValue when given an invalid value" do
1899
- proc{@db.typecast_value(:integer, "13a")}.must_raise(Sequel::InvalidValue)
1900
- proc{@db.typecast_value(:float, "4.e2")}.must_raise(Sequel::InvalidValue)
1901
- proc{@db.typecast_value(:decimal, :invalid_value)}.must_raise(Sequel::InvalidValue)
1902
- proc{@db.typecast_value(:date, Object.new)}.must_raise(Sequel::InvalidValue)
1903
- proc{@db.typecast_value(:date, 'a')}.must_raise(Sequel::InvalidValue)
1904
- proc{@db.typecast_value(:time, Date.new)}.must_raise(Sequel::InvalidValue)
1905
- proc{@db.typecast_value(:datetime, 4)}.must_raise(Sequel::InvalidValue)
1906
- end
1907
-
1908
- it "should handle integers with leading 0 as base 10" do
1909
- @db.typecast_value(:integer, "013").must_equal 13
1910
- @db.typecast_value(:integer, "08").must_equal 8
1911
- @db.typecast_value(:integer, "000013").must_equal 13
1912
- @db.typecast_value(:integer, "000008").must_equal 8
1913
- end
1914
-
1915
- it "should handle integers with leading 0x as base 16" do
1916
- @db.typecast_value(:integer, "0x013").must_equal 19
1917
- @db.typecast_value(:integer, "0x80").must_equal 128
1918
- end
1919
-
1920
- it "should typecast blobs as as Sequel::SQL::Blob" do
1921
- v = @db.typecast_value(:blob, "0x013")
1922
- v.must_be_kind_of(Sequel::SQL::Blob)
1923
- v.must_equal Sequel::SQL::Blob.new("0x013")
1924
- @db.typecast_value(:blob, v).object_id.must_equal v.object_id
1925
- end
1926
-
1927
- it "should typecast boolean values to true, false, or nil" do
1928
- @db.typecast_value(:boolean, false).must_equal false
1929
- @db.typecast_value(:boolean, 0).must_equal false
1930
- @db.typecast_value(:boolean, "0").must_equal false
1931
- @db.typecast_value(:boolean, 'f').must_equal false
1932
- @db.typecast_value(:boolean, 'false').must_equal false
1933
- @db.typecast_value(:boolean, true).must_equal true
1934
- @db.typecast_value(:boolean, 1).must_equal true
1935
- @db.typecast_value(:boolean, '1').must_equal true
1936
- @db.typecast_value(:boolean, 't').must_equal true
1937
- @db.typecast_value(:boolean, 'true').must_equal true
1938
- @db.typecast_value(:boolean, '').must_be_nil
1939
- end
1940
-
1941
- it "should typecast date values to Date" do
1942
- @db.typecast_value(:date, Date.today).must_equal Date.today
1943
- @db.typecast_value(:date, DateTime.now).must_equal Date.today
1944
- @db.typecast_value(:date, Time.now).must_equal Date.today
1945
- @db.typecast_value(:date, Date.today.to_s).must_equal Date.today
1946
- @db.typecast_value(:date, :year=>Date.today.year, :month=>Date.today.month, :day=>Date.today.day).must_equal Date.today
1947
- end
1948
-
1949
- it "should have Sequel.application_to_database_timestamp convert to Sequel.database_timezone" do
1950
- begin
1951
- t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
1952
- t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
1953
- t3 = Time.utc(2011, 1, 2, 3, 4, 5) - (t - t2) # Local Time in UTC Time
1954
- t4 = Time.mktime(2011, 1, 2, 3, 4, 5) + (t - t2) # UTC Time in Local Time
1955
- Sequel.application_timezone = :utc
1956
- Sequel.database_timezone = :local
1957
- Sequel.application_to_database_timestamp(t).must_equal t4
1958
- Sequel.application_timezone = :local
1959
- Sequel.database_timezone = :utc
1960
- Sequel.application_to_database_timestamp(t2).must_equal t3
1961
- ensure
1962
- Sequel.default_timezone = nil
1963
- end
1964
- end
1965
-
1966
- it "should have Database#to_application_timestamp convert values using the database's timezone" do
1967
- begin
1968
- t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
1969
- t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
1970
- t3 = Time.utc(2011, 1, 2, 3, 4, 5) - (t - t2) # Local Time in UTC Time
1971
- t4 = Time.mktime(2011, 1, 2, 3, 4, 5) + (t - t2) # UTC Time in Local Time
1972
- Sequel.default_timezone = :utc
1973
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t
1974
- Sequel.database_timezone = :local
1975
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t3
1976
- Sequel.default_timezone = :local
1977
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t2
1978
- Sequel.database_timezone = :utc
1979
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t4
1980
-
1981
- Sequel.default_timezone = :utc
1982
- @db.timezone = :local
1983
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t3
1984
- Sequel.default_timezone = :local
1985
- @db.timezone = :utc
1986
- @db.to_application_timestamp('2011-01-02 03:04:05').must_equal t4
1987
- ensure
1988
- Sequel.default_timezone = nil
1989
- end
1990
- end
1991
-
1992
- it "should typecast datetime values to Sequel.datetime_class with correct timezone handling" do
1993
- t = Time.utc(2011, 1, 2, 3, 4, 5, 500000) # UTC Time
1994
- t2 = Time.mktime(2011, 1, 2, 3, 4, 5, 500000) # Local Time
1995
- t3 = Time.utc(2011, 1, 2, 3, 4, 5, 500000) - (t - t2) # Local Time in UTC Time
1996
- t4 = Time.mktime(2011, 1, 2, 3, 4, 5, 500000) + (t - t2) # UTC Time in Local Time
1997
- secs = Rational(11, 2)
1998
- r1 = Rational(t2.utc_offset, 86400)
1999
- r2 = Rational((t - t2).to_i, 86400)
2000
- dt = DateTime.civil(2011, 1, 2, 3, 4, secs)
2001
- dt2 = DateTime.civil(2011, 1, 2, 3, 4, secs, r1)
2002
- dt3 = DateTime.civil(2011, 1, 2, 3, 4, secs) - r2
2003
- dt4 = DateTime.civil(2011, 1, 2, 3, 4, secs, r1) + r2
2004
-
2005
- t.must_equal t4
2006
- t2.must_equal t3
2007
- dt.must_equal dt4
2008
- dt2.must_equal dt3
2009
-
2010
- check = proc do |i, o|
2011
- v = @db.typecast_value(:datetime, i)
2012
- v.must_equal o
2013
- if o.is_a?(Time)
2014
- v.utc_offset.must_equal o.utc_offset
2015
- else
2016
- v.offset.must_equal o.offset
2017
- end
2018
- end
2019
- @db.extend_datasets(Module.new{def supports_timestamp_timezones?; true; end})
2020
- begin
2021
- @db.typecast_value(:datetime, dt).must_equal t
2022
- @db.typecast_value(:datetime, dt2).must_equal t2
2023
- @db.typecast_value(:datetime, t).must_equal t
2024
- @db.typecast_value(:datetime, t2).must_equal t2
2025
- @db.typecast_value(:datetime, @db.literal(dt)[1...-1]).must_equal t
2026
- @db.typecast_value(:datetime, dt.strftime('%F %T.%N')).must_equal t2
2027
- @db.typecast_value(:datetime, Date.civil(2011, 1, 2)).must_equal Time.mktime(2011, 1, 2, 0, 0, 0)
2028
- @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
2029
-
2030
- Sequel.datetime_class = DateTime
2031
- @db.typecast_value(:datetime, dt).must_equal dt
2032
- @db.typecast_value(:datetime, dt2).must_equal dt2
2033
- @db.typecast_value(:datetime, t).must_equal dt
2034
- @db.typecast_value(:datetime, t2).must_equal dt2
2035
- @db.typecast_value(:datetime, @db.literal(dt)[1...-1]).must_equal dt
2036
- @db.typecast_value(:datetime, dt.strftime('%F %T.%N')).must_equal dt
2037
- @db.typecast_value(:datetime, Date.civil(2011, 1, 2)).must_equal DateTime.civil(2011, 1, 2, 0, 0, 0)
2038
- @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
2039
-
2040
- Sequel.application_timezone = :utc
2041
- Sequel.typecast_timezone = :local
2042
- Sequel.datetime_class = Time
2043
- check[dt, t]
2044
- check[dt2, t3]
2045
- check[t, t]
2046
- check[t2, t3]
2047
- check[@db.literal(dt)[1...-1], t]
2048
- check[dt.strftime('%F %T.%N'), t3]
2049
- check[Date.civil(2011, 1, 2), Time.utc(2011, 1, 2, 0, 0, 0)]
2050
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t3]
2051
-
2052
- Sequel.datetime_class = DateTime
2053
- check[dt, dt]
2054
- check[dt2, dt3]
2055
- check[t, dt]
2056
- check[t2, dt3]
2057
- check[@db.literal(dt)[1...-1], dt]
2058
- check[dt.strftime('%F %T.%N'), dt3]
2059
- check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0)]
2060
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt3]
2061
-
2062
- Sequel.typecast_timezone = :utc
2063
- Sequel.datetime_class = Time
2064
- check[dt, t]
2065
- check[dt2, t3]
2066
- check[t, t]
2067
- check[t2, t3]
2068
- check[@db.literal(dt)[1...-1], t]
2069
- check[dt.strftime('%F %T.%N'), t]
2070
- check[Date.civil(2011, 1, 2), Time.utc(2011, 1, 2, 0, 0, 0)]
2071
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t]
2072
-
2073
- Sequel.datetime_class = DateTime
2074
- check[dt, dt]
2075
- check[dt2, dt3]
2076
- check[t, dt]
2077
- check[t2, dt3]
2078
- check[@db.literal(dt)[1...-1], dt]
2079
- check[dt.strftime('%F %T.%N'), dt]
2080
- check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0)]
2081
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt]
2082
-
2083
- Sequel.application_timezone = :local
2084
- Sequel.datetime_class = Time
2085
- check[dt, t4]
2086
- check[dt2, t2]
2087
- check[t, t4]
2088
- check[t2, t2]
2089
- check[@db.literal(dt)[1...-1], t4]
2090
- check[dt.strftime('%F %T.%N'), t4]
2091
- check[Date.civil(2011, 1, 2), Time.local(2011, 1, 2, 0, 0, 0)]
2092
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t4]
2093
-
2094
- Sequel.datetime_class = DateTime
2095
- check[dt, dt4]
2096
- check[dt2, dt2]
2097
- check[t, dt4]
2098
- check[t2, dt2]
2099
- check[@db.literal(dt)[1...-1], dt4]
2100
- check[dt.strftime('%F %T.%N'), dt4]
2101
- check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0, r1)]
2102
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt4]
2103
-
2104
- Sequel.typecast_timezone = :local
2105
- Sequel.datetime_class = Time
2106
- check[dt, t4]
2107
- check[dt2, t2]
2108
- check[t, t4]
2109
- check[t2, t2]
2110
- check[@db.literal(dt)[1...-1], t4]
2111
- check[dt.strftime('%F %T.%N'), t2]
2112
- check[Date.civil(2011, 1, 2), Time.local(2011, 1, 2, 0, 0, 0)]
2113
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, t2]
2114
-
2115
- Sequel.datetime_class = DateTime
2116
- check[dt, dt4]
2117
- check[dt2, dt2]
2118
- check[t, dt4]
2119
- check[t2, dt2]
2120
- check[@db.literal(dt)[1...-1], dt4]
2121
- check[dt.strftime('%F %T.%N'), dt2]
2122
- check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0, r1)]
2123
- check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec, :nanos=>500000000}, dt2]
2124
-
2125
- ensure
2126
- Sequel.default_timezone = nil
2127
- Sequel.datetime_class = Time
2128
- end
2129
- end
2130
-
2131
- it "should handle arrays when typecasting timestamps" do
2132
- begin
2133
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14]).must_equal Time.local(2011, 10, 11, 12, 13, 14)
2134
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14, 500000000]).must_equal Time.local(2011, 10, 11, 12, 13, 14, 500000)
2135
-
2136
- Sequel.datetime_class = DateTime
2137
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14]).must_equal DateTime.civil(2011, 10, 11, 12, 13, 14)
2138
- @db.typecast_value(:datetime, [2011, 10, 11, 12, 13, 14, 500000000]).must_equal DateTime.civil(2011, 10, 11, 12, 13, Rational(29, 2))
2139
- @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))
2140
- ensure
2141
- Sequel.datetime_class = Time
2142
- end
2143
- end
2144
-
2145
- it "should handle hashes when typecasting timestamps" do
2146
- begin
2147
- @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)
2148
- @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)
2149
- @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)
2150
- @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)
2151
-
2152
- Sequel.datetime_class = DateTime
2153
- @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)
2154
- @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))
2155
- @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)
2156
- @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))
2157
- @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))
2158
- @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))
2159
- @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))
2160
- @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))
2161
- ensure
2162
- Sequel.datetime_class = Time
2163
- end
2164
- end
2165
-
2166
- it "should typecast decimal values to BigDecimal" do
2167
- [1.0, 1, '1.0', BigDecimal('1.0')].each do |i|
2168
- v = @db.typecast_value(:decimal, i)
2169
- v.must_be_kind_of(BigDecimal)
2170
- v.must_equal BigDecimal.new('1.0')
2171
- end
2172
- end
2173
-
2174
- it "should typecast float values to Float" do
2175
- [1.0, 1, '1.0', BigDecimal('1.0')].each do |i|
2176
- v = @db.typecast_value(:float, i)
2177
- v.must_be_kind_of(Float)
2178
- v.must_equal 1.0
2179
- end
2180
- end
2181
-
2182
- it "should typecast string values to String" do
2183
- [1.0, '1.0', Sequel.blob('1.0')].each do |i|
2184
- v = @db.typecast_value(:string, i)
2185
- v.must_be_instance_of(String)
2186
- v.must_equal "1.0"
2187
- end
2188
- end
2189
-
2190
- it "should raise errors when typecasting hash and array values to String" do
2191
- [[], {}].each do |i|
2192
- proc{@db.typecast_value(:string, i)}.must_raise(Sequel::InvalidValue)
2193
- end
2194
- end
2195
-
2196
- it "should typecast time values to SQLTime" do
2197
- t = Time.now
2198
- st = Sequel::SQLTime.local(t.year, t.month, t.day, 1, 2, 3)
2199
- [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|
2200
- v = @db.typecast_value(:time, i)
2201
- v.must_be_instance_of(Sequel::SQLTime)
2202
- v.must_equal st
2203
- end
2204
- end
2205
-
2206
- it "should correctly handle time value conversion to SQLTime with fractional seconds" do
2207
- t = Time.now
2208
- st = Sequel::SQLTime.local(t.year, t.month, t.day, 1, 2, 3, 500000)
2209
- t = Time.local(t.year, t.month, t.day, 1, 2, 3, 500000)
2210
- @db.typecast_value(:time, t).must_equal st
2211
- end
2212
-
2213
- it "should have an underlying exception class available at wrapped_exception" do
2214
- begin
2215
- @db.typecast_value(:date, 'a')
2216
- true.must_equal false
2217
- rescue Sequel::InvalidValue => e
2218
- e.wrapped_exception.must_be_kind_of(ArgumentError)
2219
- end
2220
- end
2221
-
2222
- it "should have an underlying exception class available at cause" do
2223
- begin
2224
- @db.typecast_value(:date, 'a')
2225
- true.must_equal false
2226
- rescue Sequel::InvalidValue => e
2227
- e.cause.must_be_kind_of(ArgumentError)
2228
- end
2229
- end if RUBY_VERSION >= '2.1'
2230
-
2231
- it "should have an underlying exception class available at cause when using nested exceptions" do
2232
- begin
2233
- begin
2234
- raise ArgumentError
2235
- rescue => e1
2236
- begin
2237
- raise RuntimeError
2238
- rescue
2239
- @db.send(:raise_error, e1)
2240
- end
2241
- end
2242
- rescue Sequel::DatabaseError => e
2243
- e.cause.must_be_kind_of(ArgumentError)
2244
- end
2245
- end if RUBY_VERSION >= '2.1'
2246
-
2247
- it "should include underlying exception class in #inspect" do
2248
- begin
2249
- @db.typecast_value(:date, 'a')
2250
- true.must_equal false
2251
- rescue Sequel::InvalidValue => e
2252
- e.inspect.must_equal '#<Sequel::InvalidValue: ArgumentError: invalid date>'
2253
- end
2254
- end
2255
- end
2256
-
2257
- describe "Database#blank_object?" do
2258
- it "should return whether the object is considered blank" do
2259
- db = Sequel::Database.new
2260
- c = lambda{|meth, value| Class.new{define_method(meth){value}}.new}
2261
-
2262
- db.send(:blank_object?, "").must_equal true
2263
- db.send(:blank_object?, " ").must_equal true
2264
- db.send(:blank_object?, nil).must_equal true
2265
- db.send(:blank_object?, false).must_equal true
2266
- db.send(:blank_object?, []).must_equal true
2267
- db.send(:blank_object?, {}).must_equal true
2268
- db.send(:blank_object?, c[:empty?, true]).must_equal true
2269
- db.send(:blank_object?, c[:blank?, true]).must_equal true
2270
-
2271
- db.send(:blank_object?, " a ").must_equal false
2272
- db.send(:blank_object?, 1).must_equal false
2273
- db.send(:blank_object?, 1.0).must_equal false
2274
- db.send(:blank_object?, true).must_equal false
2275
- db.send(:blank_object?, [1]).must_equal false
2276
- db.send(:blank_object?, {1.0=>2.0}).must_equal false
2277
- db.send(:blank_object?, c[:empty?, false]).must_equal false
2278
- db.send(:blank_object?, c[:blank?, false]).must_equal false
2279
- end
2280
- end
2281
-
2282
- describe "Database#schema_autoincrementing_primary_key?" do
2283
- it "should indicate whether the parsed schema row indicates a primary key" do
2284
- m = Sequel::Database.new.method(:schema_autoincrementing_primary_key?)
2285
- m.call(:primary_key=>true, :auto_increment=>true).must_equal true
2286
- m.call(:primary_key=>true, :auto_increment=>false).must_equal false
2287
- m.call(:primary_key=>false).must_equal false
2288
- end
2289
- end
2290
-
2291
- describe "Database#supports_schema_parsing?" do
2292
- it "should be false by default" do
2293
- Sequel::Database.new.supports_schema_parsing?.must_equal false
2294
- end
2295
-
2296
- it "should be true if the database implements schema_parse_table" do
2297
- db = Sequel::Database.new
2298
- def db.schema_parse_table(*) end
2299
- db.supports_schema_parsing?.must_equal true
2300
- end
2301
- end
2302
-
2303
- describe "Database#supports_foreign_key_parsing?" do
2304
- it "should be false by default" do
2305
- Sequel::Database.new.supports_foreign_key_parsing?.must_equal false
2306
- end
2307
-
2308
- it "should be true if the database implements foreign_key_list" do
2309
- db = Sequel::Database.new
2310
- def db.foreign_key_list(*) end
2311
- db.supports_foreign_key_parsing?.must_equal true
2312
- end
2313
- end
2314
-
2315
- describe "Database#supports_index_parsing?" do
2316
- it "should be false by default" do
2317
- Sequel::Database.new.supports_index_parsing?.must_equal false
2318
- end
2319
-
2320
- it "should be true if the database implements indexes" do
2321
- db = Sequel::Database.new
2322
- def db.indexes(*) end
2323
- db.supports_index_parsing?.must_equal true
2324
- end
2325
- end
2326
-
2327
- describe "Database#supports_table_listing?" do
2328
- it "should be false by default" do
2329
- Sequel::Database.new.supports_table_listing?.must_equal false
2330
- end
2331
-
2332
- it "should be true if the database implements tables" do
2333
- db = Sequel::Database.new
2334
- def db.tables(*) end
2335
- db.supports_table_listing?.must_equal true
2336
- end
2337
- end
2338
-
2339
- describe "Database#supports_view_listing?" do
2340
- it "should be false by default" do
2341
- Sequel::Database.new.supports_view_listing?.must_equal false
2342
- end
2343
-
2344
- it "should be true if the database implements views" do
2345
- db = Sequel::Database.new
2346
- def db.views(*) end
2347
- db.supports_view_listing?.must_equal true
2348
- end
2349
- end
2350
-
2351
- describe "Database#supports_deferrable_constraints?" do
2352
- it "should be false by default" do
2353
- Sequel::Database.new.supports_deferrable_constraints?.must_equal false
2354
- end
2355
- end
2356
-
2357
- describe "Database#supports_deferrable_foreign_key_constraints?" do
2358
- it "should be false by default" do
2359
- Sequel::Database.new.supports_deferrable_foreign_key_constraints?.must_equal false
2360
- end
2361
- end
2362
-
2363
- describe "Database#supports_transactional_ddl?" do
2364
- it "should be false by default" do
2365
- Sequel::Database.new.supports_transactional_ddl?.must_equal false
2366
- end
2367
- end
2368
-
2369
- describe "Database#global_index_namespace?" do
2370
- it "should be true by default" do
2371
- Sequel::Database.new.global_index_namespace?.must_equal true
2372
- end
2373
- end
2374
-
2375
- describe "Database#supports_savepoints?" do
2376
- it "should be false by default" do
2377
- Sequel::Database.new.supports_savepoints?.must_equal false
2378
- end
2379
- end
2380
-
2381
- describe "Database#supports_views_with_check_option?" do
2382
- it "should be false by default" do
2383
- Sequel::Database.new.supports_views_with_check_option?.must_equal false
2384
- end
2385
- end
2386
-
2387
- describe "Database#supports_views_with_local_check_option?" do
2388
- it "should be false by default" do
2389
- Sequel::Database.new.supports_views_with_local_check_option?.must_equal false
2390
- end
2391
- end
2392
-
2393
- describe "Database#supports_savepoints_in_prepared_transactions?" do
2394
- it "should be false by default" do
2395
- Sequel::Database.new.supports_savepoints_in_prepared_transactions?.must_equal false
2396
- end
2397
-
2398
- it "should be true if both savepoints and prepared transactions are supported" do
2399
- db = Sequel::Database.new
2400
- db.define_singleton_method(:supports_savepoints?){true}
2401
- db.define_singleton_method(:supports_prepared_transactions?){true}
2402
- db.supports_savepoints_in_prepared_transactions?.must_equal true
2403
- end
2404
- end
2405
-
2406
- describe "Database#supports_prepared_transactions?" do
2407
- it "should be false by default" do
2408
- Sequel::Database.new.supports_prepared_transactions?.must_equal false
2409
- end
2410
- end
2411
-
2412
- describe "Database#supports_transaction_isolation_levels?" do
2413
- it "should be false by default" do
2414
- Sequel::Database.new.supports_transaction_isolation_levels?.must_equal false
2415
- end
2416
- end
2417
-
2418
- describe "Database#column_schema_to_ruby_default" do
2419
- it "should handle converting many default formats" do
2420
- db = Sequel::Database.new
2421
- p = lambda{|d,t| db.send(:column_schema_to_ruby_default, d, t)}
2422
- p[nil, :integer].must_be_nil
2423
- p[1, :integer].must_equal 1
2424
- p['1', :integer].must_equal 1
2425
- p['-1', :integer].must_equal(-1)
2426
- p[1.0, :float].must_equal 1.0
2427
- p['1.0', :float].must_equal 1.0
2428
- p['-1.0', :float].must_equal(-1.0)
2429
- p['1.0', :decimal].must_equal BigDecimal.new('1.0')
2430
- p['-1.0', :decimal].must_equal BigDecimal.new('-1.0')
2431
- p[true, :boolean].must_equal true
2432
- p[false, :boolean].must_equal false
2433
- p['1', :boolean].must_equal true
2434
- p['0', :boolean].must_equal false
2435
- p['true', :boolean].must_equal true
2436
- p['false', :boolean].must_equal false
2437
- p["'t'", :boolean].must_equal true
2438
- p["'f'", :boolean].must_equal false
2439
- p["'a'", :string].must_equal 'a'
2440
- p["'a'", :blob].must_equal Sequel.blob('a')
2441
- p["'a'", :blob].must_be_kind_of(Sequel::SQL::Blob)
2442
- p["''", :string].must_equal ''
2443
- p["'\\a''b'", :string].must_equal "\\a'b"
2444
- p["'NULL'", :string].must_equal "NULL"
2445
- p[Date.today, :date].must_equal Date.today
2446
- p["'2009-10-29'", :date].must_equal Date.new(2009,10,29)
2447
- p["CURRENT_TIMESTAMP", :date].must_equal Sequel::CURRENT_DATE
2448
- p["CURRENT_DATE", :date].must_equal Sequel::CURRENT_DATE
2449
- p["now()", :date].must_equal Sequel::CURRENT_DATE
2450
- p["getdate()", :date].must_equal Sequel::CURRENT_DATE
2451
- p["CURRENT_TIMESTAMP", :datetime].must_equal Sequel::CURRENT_TIMESTAMP
2452
- p["CURRENT_DATE", :datetime].must_equal Sequel::CURRENT_TIMESTAMP
2453
- p["now()", :datetime].must_equal Sequel::CURRENT_TIMESTAMP
2454
- p["getdate()", :datetime].must_equal Sequel::CURRENT_TIMESTAMP
2455
- p["'2009-10-29T10:20:30-07:00'", :datetime].must_equal DateTime.parse('2009-10-29T10:20:30-07:00')
2456
- p["'2009-10-29 10:20:30'", :datetime].must_equal DateTime.parse('2009-10-29 10:20:30')
2457
- p["'10:20:30'", :time].must_equal Time.parse('10:20:30')
2458
- p["NaN", :float].must_be_nil
2459
-
2460
- db = Sequel.mock(:host=>'postgres')
2461
- p["''::text", :string].must_equal ""
2462
- p["'\\a''b'::character varying", :string].must_equal "\\a'b"
2463
- p["'a'::bpchar", :string].must_equal "a"
2464
- p["(-1)", :integer].must_equal(-1)
2465
- p["(-1.0)", :float].must_equal(-1.0)
2466
- p['(-1.0)', :decimal].must_equal BigDecimal.new('-1.0')
2467
- p["'a'::bytea", :blob].must_equal Sequel.blob('a')
2468
- p["'a'::bytea", :blob].must_be_kind_of(Sequel::SQL::Blob)
2469
- p["'2009-10-29'::date", :date].must_equal Date.new(2009,10,29)
2470
- p["'2009-10-29 10:20:30.241343'::timestamp without time zone", :datetime].must_equal DateTime.parse('2009-10-29 10:20:30.241343')
2471
- p["'10:20:30'::time without time zone", :time].must_equal Time.parse('10:20:30')
2472
-
2473
- db = Sequel.mock(:host=>'mysql')
2474
- p["\\a'b", :string].must_equal "\\a'b"
2475
- p["a", :string].must_equal "a"
2476
- p["NULL", :string].must_equal "NULL"
2477
- p["-1", :float].must_equal(-1.0)
2478
- p['-1', :decimal].must_equal BigDecimal.new('-1.0')
2479
- p["2009-10-29", :date].must_equal Date.new(2009,10,29)
2480
- p["2009-10-29 10:20:30", :datetime].must_equal DateTime.parse('2009-10-29 10:20:30')
2481
- p["10:20:30", :time].must_equal Time.parse('10:20:30')
2482
- p["a", :enum].must_equal "a"
2483
- p["a,b", :set].must_equal "a,b"
2484
-
2485
- db = Sequel.mock(:host=>'mssql')
2486
- p["(N'a')", :string].must_equal "a"
2487
- p["((-12))", :integer].must_equal(-12)
2488
- p["((12.1))", :float].must_equal 12.1
2489
- p["((-12.1))", :decimal].must_equal BigDecimal.new('-12.1')
2490
- end
2491
- end
2492
-
2493
- describe "Database extensions" do
2494
- before(:all) do
2495
- class << Sequel
2496
- alias _extension extension
2497
- remove_method :extension
2498
- def extension(*)
2499
- end
2500
- end
2501
- end
2502
- after(:all) do
2503
- class << Sequel
2504
- remove_method :extension
2505
- alias extension _extension
2506
- remove_method :_extension
2507
- end
2508
- end
2509
- before do
2510
- @db = Sequel.mock
2511
- end
2512
- after do
2513
- Sequel::Database.instance_variable_set(:@initialize_hook, Proc.new {|db| })
2514
- end
2515
-
2516
- it "should be able to register an extension with a module have Database#extension extend the module" do
2517
- Sequel::Database.register_extension(:foo, Module.new{def a; 1; end})
2518
- @db.extension(:foo).a.must_equal 1
2519
- end
2520
-
2521
- it "should not call the block multiple times if extension loaded more than once" do
2522
- @db.opts[:foo] = []
2523
- Sequel::Database.register_extension(:foo){|db| db.opts[:foo] << 1}
2524
- @db.extension(:foo).opts[:foo].must_equal [1]
2525
- @db.extension(:foo).opts[:foo].must_equal [1]
2526
- end
2527
-
2528
- it "should be able to register an extension with a block and have Database#extension call the block" do
2529
- Sequel::Database.register_extension(:foo){|db| db.opts[:foo] = 1}
2530
- @db.extension(:foo).opts[:foo].must_equal 1
2531
- end
2532
-
2533
- it "should be able to register an extension with a callable and Database#extension call the callable" do
2534
- Sequel::Database.register_extension(:foo, proc{|db| db.opts[:foo] = 1})
2535
- @db.extension(:foo).opts[:foo].must_equal 1
2536
- end
2537
-
2538
- it "should be able to load multiple extensions in the same call" do
2539
- a = []
2540
- Sequel::Database.register_extension(:foo, proc{|db| a << db.opts[:foo] = 1})
2541
- Sequel::Database.register_extension(:bar, proc{|db| a << db.opts[:bar] = 2})
2542
- @db.extension(:foo, :bar).opts.values_at(:foo, :bar).must_equal [1, 2]
2543
- a.must_equal [1, 2]
2544
- end
2545
-
2546
- it "should return the receiver" do
2547
- Sequel::Database.register_extension(:foo, Module.new{def a; 1; end})
2548
- @db.extension(:foo).must_be_same_as(@db)
2549
- end
2550
-
2551
- it "should raise an Error if registering with both a module and a block" do
2552
- proc{Sequel::Database.register_extension(:foo, Module.new){}}.must_raise(Sequel::Error)
2553
- end
2554
-
2555
- it "should raise an Error if attempting to load an incompatible extension" do
2556
- proc{@db.extension(:foo2)}.must_raise(Sequel::Error)
2557
- end
2558
-
2559
- it "should be able to load an extension into all future Databases with Database.extension" do
2560
- Sequel::Database.register_extension(:foo, Module.new{def a; 1; end})
2561
- Sequel::Database.register_extension(:bar, Module.new{def b; 2; end})
2562
- Sequel::Database.extension(:foo, :bar)
2563
- @db.wont_respond_to(:a)
2564
- @db.wont_respond_to(:b)
2565
- Sequel.mock.a.must_equal 1
2566
- Sequel.mock.b.must_equal 2
2567
- end
2568
-
2569
- it "should be loadable via the :extensions Database option" do
2570
- Sequel::Database.register_extension(:a, Module.new{def a; 1; end})
2571
- Sequel::Database.register_extension(:b, Module.new{def b; 2; end})
2572
- Sequel.mock(:extensions=>:a).a.must_equal 1
2573
- db = Sequel.mock(:extensions=>'a,b')
2574
- db.a.must_equal 1
2575
- db.b.must_equal 2
2576
- db = Sequel.mock(:extensions=>[:a, :b])
2577
- db.a.must_equal 1
2578
- db.b.must_equal 2
2579
- proc{Sequel.mock(:extensions=>nil).a}.must_raise NoMethodError
2580
- proc{Sequel.mock(:extensions=>Object.new)}.must_raise Sequel::Error
2581
- end
2582
- end
2583
-
2584
- describe "Database specific exception classes" do
2585
- before do
2586
- @db = Sequel.mock
2587
- class << @db
2588
- attr_accessor :sql_state
2589
-
2590
- def database_exception_sqlstate(exception, opts={})
2591
- @sql_state
2592
- end
2593
- end
2594
- end
2595
-
2596
- it "should use appropriate exception classes for given SQL states" do
2597
- @db.fetch = ArgumentError
2598
- @db.sql_state = '23502'
2599
- proc{@db.get(:a)}.must_raise(Sequel::NotNullConstraintViolation)
2600
- @db.sql_state = '23503'
2601
- proc{@db.get(:a)}.must_raise(Sequel::ForeignKeyConstraintViolation)
2602
- @db.sql_state = '23505'
2603
- proc{@db.get(:a)}.must_raise(Sequel::UniqueConstraintViolation)
2604
- @db.sql_state = '23513'
2605
- proc{@db.get(:a)}.must_raise(Sequel::CheckConstraintViolation)
2606
- @db.sql_state = '40001'
2607
- proc{@db.get(:a)}.must_raise(Sequel::SerializationFailure)
2608
- end
2609
- end
2610
-
2611
- describe "Database.after_initialize" do
2612
- after do
2613
- Sequel::Database.instance_variable_set(:@initialize_hook, Proc.new {|db| })
2614
- end
2615
-
2616
- it "should allow a block to be run after each new instance is created" do
2617
- Sequel::Database.after_initialize{|db| db.sql_log_level = :debug }
2618
- db = Sequel.mock
2619
- db.sql_log_level.must_equal :debug
2620
- end
2621
-
2622
- it "should allow multiple hooks to be registered" do
2623
- Sequel::Database.after_initialize{|db| db.sql_log_level = :debug }
2624
- Sequel::Database.after_initialize{|db| db.loggers << 11 }
2625
-
2626
- db = Sequel.mock
2627
-
2628
- db.sql_log_level.must_equal :debug
2629
- db.loggers.must_include(11)
2630
- end
2631
-
2632
- it "should raise an error if registration is called without a block" do
2633
- proc {
2634
- Sequel::Database.after_initialize
2635
- }.must_raise(Sequel::Error, /must provide block/i)
2636
- end
2637
- end
2638
-
2639
- describe "Database#schema_type_class" do
2640
- it "should return the class or array of classes for the given type symbol" do
2641
- db = Sequel.mock
2642
- {:string=>String, :integer=>Integer, :date=>Date, :datetime=>[Time, DateTime],
2643
- :time=>Sequel::SQLTime, :boolean=>[TrueClass, FalseClass], :float=>Float, :decimal=>BigDecimal,
2644
- :blob=>Sequel::SQL::Blob}.each do |sym, klass|
2645
- db.schema_type_class(sym).must_equal klass
2646
- end
2647
- end
2648
- end
2649
-
2650
- describe "Database#execute_{dui,ddl,insert}" do
2651
- before do
2652
- @db = Sequel::Database.new
2653
- def @db.execute(sql, opts={})
2654
- (@sqls ||= []) << sql
2655
- end
2656
- def @db.sqls
2657
- @sqls
2658
- end
2659
- end
2660
-
2661
- it "should execute the SQL" do
2662
- @db.execute_dui "DELETE FROM table"
2663
- @db.execute_ddl "SET foo"
2664
- @db.execute_insert "INSERT INTO table DEFAULT VALUES"
2665
- @db.sqls.must_equal ["DELETE FROM table", "SET foo", "INSERT INTO table DEFAULT VALUES"]
2666
- end
2667
- end
2668
-
2669
- describe "Dataset identifier folding" do
2670
- it "should fold to uppercase by default, as per SQL" do
2671
- Sequel::Database.new.send(:folds_unquoted_identifiers_to_uppercase?).must_equal true
2672
- end
2673
- end