sequel 3.21.0 → 3.41.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 (363) hide show
  1. data/CHANGELOG +1131 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +106 -65
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +68 -52
  7. data/doc/advanced_associations.rdoc +201 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/bin_sequel.rdoc +144 -0
  10. data/doc/cheat_sheet.rdoc +21 -21
  11. data/doc/core_extensions.rdoc +374 -0
  12. data/doc/dataset_basics.rdoc +10 -10
  13. data/doc/dataset_filtering.rdoc +54 -42
  14. data/doc/mass_assignment.rdoc +56 -0
  15. data/doc/migration.rdoc +89 -557
  16. data/doc/model_hooks.rdoc +80 -29
  17. data/doc/object_model.rdoc +576 -0
  18. data/doc/opening_databases.rdoc +121 -53
  19. data/doc/prepared_statements.rdoc +41 -15
  20. data/doc/querying.rdoc +137 -56
  21. data/doc/reflection.rdoc +36 -10
  22. data/doc/release_notes/3.22.0.txt +39 -0
  23. data/doc/release_notes/3.23.0.txt +172 -0
  24. data/doc/release_notes/3.24.0.txt +420 -0
  25. data/doc/release_notes/3.25.0.txt +88 -0
  26. data/doc/release_notes/3.26.0.txt +88 -0
  27. data/doc/release_notes/3.27.0.txt +82 -0
  28. data/doc/release_notes/3.28.0.txt +304 -0
  29. data/doc/release_notes/3.29.0.txt +459 -0
  30. data/doc/release_notes/3.30.0.txt +135 -0
  31. data/doc/release_notes/3.31.0.txt +146 -0
  32. data/doc/release_notes/3.32.0.txt +202 -0
  33. data/doc/release_notes/3.33.0.txt +157 -0
  34. data/doc/release_notes/3.34.0.txt +671 -0
  35. data/doc/release_notes/3.35.0.txt +144 -0
  36. data/doc/release_notes/3.36.0.txt +245 -0
  37. data/doc/release_notes/3.37.0.txt +338 -0
  38. data/doc/release_notes/3.38.0.txt +234 -0
  39. data/doc/release_notes/3.39.0.txt +237 -0
  40. data/doc/release_notes/3.40.0.txt +73 -0
  41. data/doc/release_notes/3.41.0.txt +155 -0
  42. data/doc/schema_modification.rdoc +585 -0
  43. data/doc/sharding.rdoc +99 -8
  44. data/doc/sql.rdoc +154 -112
  45. data/doc/testing.rdoc +169 -0
  46. data/doc/thread_safety.rdoc +17 -0
  47. data/doc/transactions.rdoc +137 -0
  48. data/doc/validations.rdoc +1 -1
  49. data/doc/virtual_rows.rdoc +78 -43
  50. data/lib/sequel/adapters/ado/access.rb +334 -0
  51. data/lib/sequel/adapters/ado/mssql.rb +18 -12
  52. data/lib/sequel/adapters/ado.rb +69 -21
  53. data/lib/sequel/adapters/amalgalite.rb +17 -14
  54. data/lib/sequel/adapters/cubrid.rb +143 -0
  55. data/lib/sequel/adapters/db2.rb +178 -85
  56. data/lib/sequel/adapters/dbi.rb +19 -21
  57. data/lib/sequel/adapters/do/mysql.rb +17 -11
  58. data/lib/sequel/adapters/do/postgres.rb +2 -61
  59. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  60. data/lib/sequel/adapters/do.rb +20 -39
  61. data/lib/sequel/adapters/firebird.rb +33 -210
  62. data/lib/sequel/adapters/ibmdb.rb +452 -0
  63. data/lib/sequel/adapters/informix.rb +6 -29
  64. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  65. data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
  66. data/lib/sequel/adapters/jdbc/db2.rb +78 -0
  67. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  68. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  69. data/lib/sequel/adapters/jdbc/h2.rb +68 -31
  70. data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -0
  71. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  73. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  74. data/lib/sequel/adapters/jdbc/mysql.rb +16 -28
  75. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  76. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  77. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  78. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  79. data/lib/sequel/adapters/jdbc/sqlserver.rb +72 -0
  80. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  81. data/lib/sequel/adapters/jdbc.rb +308 -114
  82. data/lib/sequel/adapters/mock.rb +372 -0
  83. data/lib/sequel/adapters/mysql.rb +130 -230
  84. data/lib/sequel/adapters/mysql2.rb +64 -63
  85. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  86. data/lib/sequel/adapters/odbc.rb +29 -10
  87. data/lib/sequel/adapters/openbase.rb +7 -11
  88. data/lib/sequel/adapters/oracle.rb +364 -57
  89. data/lib/sequel/adapters/postgres.rb +379 -145
  90. data/lib/sequel/adapters/shared/access.rb +236 -11
  91. data/lib/sequel/adapters/shared/cubrid.rb +216 -0
  92. data/lib/sequel/adapters/shared/db2.rb +353 -0
  93. data/lib/sequel/adapters/shared/firebird.rb +231 -0
  94. data/lib/sequel/adapters/shared/informix.rb +53 -0
  95. data/lib/sequel/adapters/shared/mssql.rb +412 -116
  96. data/lib/sequel/adapters/shared/mysql.rb +396 -89
  97. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
  98. data/lib/sequel/adapters/shared/oracle.rb +262 -45
  99. data/lib/sequel/adapters/shared/postgres.rb +688 -279
  100. data/lib/sequel/adapters/shared/progress.rb +5 -8
  101. data/lib/sequel/adapters/shared/sqlite.rb +317 -96
  102. data/lib/sequel/adapters/sqlite.rb +109 -46
  103. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  104. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  105. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  106. data/lib/sequel/adapters/swift.rb +31 -27
  107. data/lib/sequel/adapters/tinytds.rb +177 -25
  108. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  109. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  110. data/lib/sequel/adapters/utils/split_alter_table.rb +36 -0
  111. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  112. data/lib/sequel/ast_transformer.rb +194 -0
  113. data/lib/sequel/connection_pool/sharded_single.rb +23 -13
  114. data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
  115. data/lib/sequel/connection_pool/single.rb +11 -3
  116. data/lib/sequel/connection_pool/threaded.rb +69 -20
  117. data/lib/sequel/connection_pool.rb +20 -18
  118. data/lib/sequel/core.rb +143 -11
  119. data/lib/sequel/database/connecting.rb +66 -29
  120. data/lib/sequel/database/dataset.rb +4 -4
  121. data/lib/sequel/database/dataset_defaults.rb +63 -2
  122. data/lib/sequel/database/logging.rb +7 -2
  123. data/lib/sequel/database/misc.rb +192 -51
  124. data/lib/sequel/database/query.rb +299 -114
  125. data/lib/sequel/database/schema_generator.rb +103 -36
  126. data/lib/sequel/database/schema_methods.rb +310 -69
  127. data/lib/sequel/dataset/actions.rb +344 -90
  128. data/lib/sequel/dataset/features.rb +101 -8
  129. data/lib/sequel/dataset/graph.rb +42 -15
  130. data/lib/sequel/dataset/misc.rb +52 -25
  131. data/lib/sequel/dataset/mutation.rb +12 -7
  132. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  133. data/lib/sequel/dataset/query.rb +322 -68
  134. data/lib/sequel/dataset/sql.rb +716 -293
  135. data/lib/sequel/dataset.rb +8 -0
  136. data/lib/sequel/exceptions.rb +4 -0
  137. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  138. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  139. data/lib/sequel/extensions/blank.rb +4 -0
  140. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  141. data/lib/sequel/extensions/connection_validator.rb +109 -0
  142. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  143. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  144. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  145. data/lib/sequel/extensions/inflector.rb +4 -0
  146. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  147. data/lib/sequel/extensions/migration.rb +100 -11
  148. data/lib/sequel/extensions/named_timezones.rb +9 -0
  149. data/lib/sequel/extensions/null_dataset.rb +94 -0
  150. data/lib/sequel/extensions/pagination.rb +4 -0
  151. data/lib/sequel/extensions/pg_array.rb +539 -0
  152. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  153. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  154. data/lib/sequel/extensions/pg_hstore.rb +334 -0
  155. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  156. data/lib/sequel/extensions/pg_inet.rb +113 -0
  157. data/lib/sequel/extensions/pg_interval.rb +191 -0
  158. data/lib/sequel/extensions/pg_json.rb +212 -0
  159. data/lib/sequel/extensions/pg_range.rb +513 -0
  160. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  161. data/lib/sequel/extensions/pg_row.rb +576 -0
  162. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  163. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  164. data/lib/sequel/extensions/pretty_table.rb +17 -72
  165. data/lib/sequel/extensions/query.rb +8 -4
  166. data/lib/sequel/extensions/query_literals.rb +79 -0
  167. data/lib/sequel/extensions/schema_caching.rb +76 -0
  168. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  169. data/lib/sequel/extensions/select_remove.rb +39 -0
  170. data/lib/sequel/extensions/server_block.rb +140 -0
  171. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  172. data/lib/sequel/extensions/sql_expr.rb +8 -110
  173. data/lib/sequel/extensions/string_date_time.rb +4 -0
  174. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  175. data/lib/sequel/extensions/to_dot.rb +99 -83
  176. data/lib/sequel/model/associations.rb +1263 -409
  177. data/lib/sequel/model/base.rb +624 -171
  178. data/lib/sequel/model/errors.rb +1 -1
  179. data/lib/sequel/model/exceptions.rb +24 -2
  180. data/lib/sequel/model/inflections.rb +1 -1
  181. data/lib/sequel/model.rb +30 -11
  182. data/lib/sequel/no_core_ext.rb +2 -0
  183. data/lib/sequel/plugins/active_model.rb +13 -1
  184. data/lib/sequel/plugins/association_pks.rb +137 -16
  185. data/lib/sequel/plugins/caching.rb +25 -18
  186. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  187. data/lib/sequel/plugins/composition.rb +44 -12
  188. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  189. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  190. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  191. data/lib/sequel/plugins/dirty.rb +214 -0
  192. data/lib/sequel/plugins/eager_each.rb +59 -0
  193. data/lib/sequel/plugins/force_encoding.rb +6 -6
  194. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  195. data/lib/sequel/plugins/identity_map.rb +134 -15
  196. data/lib/sequel/plugins/instance_filters.rb +10 -0
  197. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  198. data/lib/sequel/plugins/json_serializer.rb +77 -6
  199. data/lib/sequel/plugins/list.rb +13 -2
  200. data/lib/sequel/plugins/many_through_many.rb +103 -51
  201. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  202. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  203. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  204. data/lib/sequel/plugins/pg_row.rb +121 -0
  205. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  206. data/lib/sequel/plugins/prepared_statements.rb +168 -0
  207. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  208. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  209. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  210. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  211. data/lib/sequel/plugins/schema.rb +8 -3
  212. data/lib/sequel/plugins/serialization.rb +98 -49
  213. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  214. data/lib/sequel/plugins/sharding.rb +21 -54
  215. data/lib/sequel/plugins/single_table_inheritance.rb +57 -12
  216. data/lib/sequel/plugins/static_cache.rb +99 -0
  217. data/lib/sequel/plugins/subclasses.rb +29 -3
  218. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  219. data/lib/sequel/plugins/timestamps.rb +1 -1
  220. data/lib/sequel/plugins/touch.rb +18 -6
  221. data/lib/sequel/plugins/tree.rb +3 -3
  222. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  223. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  224. data/lib/sequel/plugins/validation_class_methods.rb +2 -1
  225. data/lib/sequel/plugins/validation_helpers.rb +57 -4
  226. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  227. data/lib/sequel/sql.rb +721 -141
  228. data/lib/sequel/timezones.rb +67 -40
  229. data/lib/sequel/version.rb +1 -1
  230. data/spec/adapters/db2_spec.rb +146 -0
  231. data/spec/adapters/firebird_spec.rb +53 -39
  232. data/spec/adapters/mssql_spec.rb +261 -66
  233. data/spec/adapters/mysql_spec.rb +597 -352
  234. data/spec/adapters/oracle_spec.rb +92 -117
  235. data/spec/adapters/postgres_spec.rb +2103 -341
  236. data/spec/adapters/spec_helper.rb +16 -6
  237. data/spec/adapters/sqlite_spec.rb +237 -76
  238. data/spec/core/connection_pool_spec.rb +270 -141
  239. data/spec/core/database_spec.rb +980 -524
  240. data/spec/core/dataset_spec.rb +1658 -1243
  241. data/spec/core/expression_filters_spec.rb +741 -334
  242. data/spec/core/mock_adapter_spec.rb +453 -0
  243. data/spec/core/object_graph_spec.rb +88 -129
  244. data/spec/core/schema_generator_spec.rb +4 -4
  245. data/spec/core/schema_spec.rb +556 -53
  246. data/spec/core/spec_helper.rb +7 -48
  247. data/spec/core_extensions_spec.rb +626 -0
  248. data/spec/extensions/active_model_spec.rb +13 -0
  249. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  250. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  251. data/spec/extensions/association_dependencies_spec.rb +15 -25
  252. data/spec/extensions/association_pks_spec.rb +227 -33
  253. data/spec/extensions/association_proxies_spec.rb +4 -4
  254. data/spec/extensions/boolean_readers_spec.rb +25 -25
  255. data/spec/extensions/caching_spec.rb +47 -51
  256. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  257. data/spec/extensions/columns_introspection_spec.rb +91 -0
  258. data/spec/extensions/composition_spec.rb +18 -13
  259. data/spec/extensions/connection_validator_spec.rb +118 -0
  260. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  261. data/spec/extensions/constraint_validations_spec.rb +316 -0
  262. data/spec/extensions/dataset_associations_spec.rb +199 -0
  263. data/spec/extensions/defaults_setter_spec.rb +88 -0
  264. data/spec/extensions/dirty_spec.rb +155 -0
  265. data/spec/extensions/eager_each_spec.rb +34 -0
  266. data/spec/extensions/eval_inspect_spec.rb +67 -0
  267. data/spec/extensions/force_encoding_spec.rb +4 -2
  268. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  269. data/spec/extensions/identity_map_spec.rb +142 -24
  270. data/spec/extensions/inflector_spec.rb +0 -4
  271. data/spec/extensions/instance_filters_spec.rb +11 -21
  272. data/spec/extensions/instance_hooks_spec.rb +72 -0
  273. data/spec/extensions/json_serializer_spec.rb +49 -12
  274. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  275. data/spec/extensions/list_spec.rb +49 -40
  276. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  277. data/spec/extensions/many_through_many_spec.rb +368 -254
  278. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  279. data/spec/extensions/migration_spec.rb +140 -35
  280. data/spec/extensions/named_timezones_spec.rb +29 -11
  281. data/spec/extensions/nested_attributes_spec.rb +268 -89
  282. data/spec/extensions/null_dataset_spec.rb +85 -0
  283. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  284. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  285. data/spec/extensions/pg_array_spec.rb +324 -0
  286. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  287. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  288. data/spec/extensions/pg_hstore_spec.rb +200 -0
  289. data/spec/extensions/pg_inet_spec.rb +47 -0
  290. data/spec/extensions/pg_interval_spec.rb +72 -0
  291. data/spec/extensions/pg_json_spec.rb +99 -0
  292. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  293. data/spec/extensions/pg_range_spec.rb +395 -0
  294. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  295. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  296. data/spec/extensions/pg_row_spec.rb +340 -0
  297. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  298. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  299. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  300. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  301. data/spec/extensions/prepared_statements_spec.rb +87 -0
  302. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  303. data/spec/extensions/pretty_table_spec.rb +7 -6
  304. data/spec/extensions/query_literals_spec.rb +167 -0
  305. data/spec/extensions/query_spec.rb +9 -3
  306. data/spec/extensions/rcte_tree_spec.rb +50 -43
  307. data/spec/extensions/schema_caching_spec.rb +41 -0
  308. data/spec/extensions/schema_dumper_spec.rb +434 -49
  309. data/spec/extensions/schema_spec.rb +30 -49
  310. data/spec/extensions/select_remove_spec.rb +38 -0
  311. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  312. data/spec/extensions/serialization_spec.rb +86 -48
  313. data/spec/extensions/server_block_spec.rb +90 -0
  314. data/spec/extensions/sharding_spec.rb +69 -143
  315. data/spec/extensions/single_table_inheritance_spec.rb +65 -29
  316. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  317. data/spec/extensions/spec_helper.rb +34 -67
  318. data/spec/extensions/split_array_nil_spec.rb +24 -0
  319. data/spec/extensions/sql_expr_spec.rb +29 -60
  320. data/spec/extensions/static_cache_spec.rb +145 -0
  321. data/spec/extensions/subclasses_spec.rb +14 -0
  322. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  323. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  324. data/spec/extensions/timestamps_spec.rb +6 -6
  325. data/spec/extensions/to_dot_spec.rb +8 -11
  326. data/spec/extensions/touch_spec.rb +53 -14
  327. data/spec/extensions/tree_spec.rb +11 -26
  328. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  329. data/spec/extensions/update_primary_key_spec.rb +30 -24
  330. data/spec/extensions/validation_class_methods_spec.rb +77 -68
  331. data/spec/extensions/validation_helpers_spec.rb +48 -37
  332. data/spec/extensions/xml_serializer_spec.rb +29 -4
  333. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  334. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  335. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  336. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  337. data/spec/integration/associations_test.rb +659 -21
  338. data/spec/integration/database_test.rb +25 -5
  339. data/spec/integration/dataset_test.rb +729 -141
  340. data/spec/integration/eager_loader_test.rb +38 -54
  341. data/spec/integration/migrator_test.rb +2 -3
  342. data/spec/integration/model_test.rb +81 -2
  343. data/spec/integration/plugin_test.rb +871 -160
  344. data/spec/integration/prepared_statement_test.rb +272 -128
  345. data/spec/integration/schema_test.rb +377 -57
  346. data/spec/integration/spec_helper.rb +49 -32
  347. data/spec/integration/timezone_test.rb +38 -12
  348. data/spec/integration/transaction_test.rb +183 -8
  349. data/spec/integration/type_test.rb +40 -8
  350. data/spec/model/association_reflection_spec.rb +207 -8
  351. data/spec/model/associations_spec.rb +1206 -693
  352. data/spec/model/base_spec.rb +334 -100
  353. data/spec/model/dataset_methods_spec.rb +45 -27
  354. data/spec/model/eager_loading_spec.rb +828 -692
  355. data/spec/model/hooks_spec.rb +355 -67
  356. data/spec/model/model_spec.rb +251 -179
  357. data/spec/model/plugins_spec.rb +24 -13
  358. data/spec/model/record_spec.rb +506 -232
  359. data/spec/model/spec_helper.rb +16 -77
  360. data/spec/model/validations_spec.rb +38 -2
  361. data/spec/rcov.opts +2 -0
  362. metadata +223 -81
  363. data/spec/core/core_sql_spec.rb +0 -451
@@ -1,9 +1,18 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
  CONNECTION_POOL_DEFAULTS = {:pool_timeout=>5, :pool_sleep_time=>0.001, :max_connections=>4}
3
3
 
4
+ mock_db = lambda do |*a, &b|
5
+ db = Sequel.mock
6
+ db.meta_def(:connect){|c| b.arity == 1 ? b.call(c) : b.call} if b
7
+ if b2 = a.shift
8
+ db.meta_def(:disconnect_connection){|c| b2.arity == 1 ? b2.call(c) : b2.call}
9
+ end
10
+ db
11
+ end
12
+
4
13
  describe "An empty ConnectionPool" do
5
14
  before do
6
- @cpool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS){}
15
+ @cpool = Sequel::ConnectionPool.get_pool(mock_db.call, CONNECTION_POOL_DEFAULTS)
7
16
  end
8
17
 
9
18
  specify "should have no available connections" do
@@ -21,24 +30,25 @@ end
21
30
 
22
31
  describe "ConnectionPool options" do
23
32
  specify "should support string option values" do
24
- cpool = Sequel::ConnectionPool.get_pool({:max_connections=>'5', :pool_timeout=>'3', :pool_sleep_time=>'0.01'}){}
33
+ cpool = Sequel::ConnectionPool.get_pool(mock_db.call, {:max_connections=>'5', :pool_timeout=>'3', :pool_sleep_time=>'0.01'})
25
34
  cpool.max_size.should == 5
26
35
  cpool.instance_variable_get(:@timeout).should == 3
27
36
  cpool.instance_variable_get(:@sleep_time).should == 0.01
28
37
  end
29
38
 
30
39
  specify "should raise an error unless size is positive" do
31
- lambda{Sequel::ConnectionPool.get_pool(:max_connections=>0)}.should raise_error(Sequel::Error)
32
- lambda{Sequel::ConnectionPool.get_pool(:max_connections=>-10)}.should raise_error(Sequel::Error)
33
- lambda{Sequel::ConnectionPool.get_pool(:max_connections=>'-10')}.should raise_error(Sequel::Error)
34
- lambda{Sequel::ConnectionPool.get_pool(:max_connections=>'0')}.should raise_error(Sequel::Error)
40
+ lambda{Sequel::ConnectionPool.get_pool(mock_db.call{1}, :max_connections=>0)}.should raise_error(Sequel::Error)
41
+ lambda{Sequel::ConnectionPool.get_pool(mock_db.call{1}, :max_connections=>-10)}.should raise_error(Sequel::Error)
42
+ lambda{Sequel::ConnectionPool.get_pool(mock_db.call{1}, :max_connections=>'-10')}.should raise_error(Sequel::Error)
43
+ lambda{Sequel::ConnectionPool.get_pool(mock_db.call{1}, :max_connections=>'0')}.should raise_error(Sequel::Error)
35
44
  end
36
45
  end
37
46
 
38
47
  describe "A connection pool handling connections" do
39
48
  before do
40
49
  @max_size = 2
41
- @cpool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| @max_size=3}, :max_connections=>@max_size)) {:got_connection}
50
+ msp = proc{@max_size=3}
51
+ @cpool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| msp.call}){:got_connection}, CONNECTION_POOL_DEFAULTS.merge(:max_connections=>@max_size))
42
52
  end
43
53
 
44
54
  specify "#hold should increment #created_count" do
@@ -84,7 +94,9 @@ describe "A connection pool handling connections" do
84
94
  end
85
95
 
86
96
  specify "#make_new should not make more than max_size connections" do
87
- 50.times{Thread.new{@cpool.hold{sleep 0.001}}}
97
+ q = Queue.new
98
+ 50.times{Thread.new{@cpool.hold{q.pop}}}
99
+ 50.times{q.push nil}
88
100
  @cpool.created_count.should <= @max_size
89
101
  end
90
102
 
@@ -96,7 +108,8 @@ describe "A connection pool handling connections" do
96
108
 
97
109
  specify "#hold should remove the connection if a DatabaseDisconnectError is raised" do
98
110
  @cpool.created_count.should == 0
99
- @cpool.hold{Thread.new{@cpool.hold{}}; sleep 0.03}
111
+ q, q1 = Queue.new, Queue.new
112
+ @cpool.hold{Thread.new{@cpool.hold{q1.pop; q.push nil}; q1.pop; q.push nil}; q1.push nil; q.pop; q1.push nil; q.pop}
100
113
  @cpool.created_count.should == 2
101
114
  proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
102
115
  @cpool.created_count.should == 1
@@ -121,36 +134,30 @@ describe "A connection pool handling connection errors" do
121
134
  end
122
135
  end
123
136
 
124
- class DummyConnection
125
- @@value = 0
126
- def initialize
127
- @@value += 1
128
- end
129
-
130
- def value
131
- @@value
132
- end
133
- end
134
-
135
137
  describe "ConnectionPool#hold" do
136
138
  before do
137
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
139
+ value = 0
140
+ c = @c = Class.new do
141
+ define_method(:initialize){value += 1}
142
+ define_method(:value){value}
143
+ end
144
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call{c.new}, CONNECTION_POOL_DEFAULTS)
138
145
  end
139
146
 
140
147
  specify "should pass the result of the connection maker proc to the supplied block" do
141
148
  res = nil
142
149
  @pool.hold {|c| res = c}
143
- res.should be_a_kind_of(DummyConnection)
150
+ res.should be_a_kind_of(@c)
144
151
  res.value.should == 1
145
152
  @pool.hold {|c| res = c}
146
- res.should be_a_kind_of(DummyConnection)
153
+ res.should be_a_kind_of(@c)
147
154
  res.value.should == 1 # the connection maker is invoked only once
148
155
  end
149
156
 
150
157
  specify "should be re-entrant by the same thread" do
151
158
  cc = nil
152
159
  @pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
153
- cc.should be_a_kind_of(DummyConnection)
160
+ cc.should be_a_kind_of(@c)
154
161
  end
155
162
 
156
163
  specify "should catch exceptions and reraise them" do
@@ -161,20 +168,20 @@ end
161
168
  describe "A connection pool with a max size of 1" do
162
169
  before do
163
170
  @invoked_count = 0
164
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1)) {@invoked_count += 1; 'herro'}
171
+ icp = proc{@invoked_count += 1}
172
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call{icp.call; 'herro'}, CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1))
165
173
  end
166
174
 
167
175
  specify "should let only one thread access the connection at any time" do
168
176
  cc,c1, c2 = nil
169
- m = (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx') ? 30 : 1
177
+ q, q1 = Queue.new, Queue.new
170
178
 
171
- t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.01;end}}
172
- sleep 0.02 * m
179
+ t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; q1.push nil; q.pop}}
180
+ q1.pop
173
181
  cc.should == 'herro'
174
182
  c1.should == 'herro'
175
183
 
176
- t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.01;end}}
177
- sleep 0.02 * m
184
+ t2 = Thread.new {@pool.hold {|c| c2 = c.dup; q1.push nil; q.pop;}}
178
185
 
179
186
  # connection held by t1
180
187
  t1.should be_alive
@@ -186,26 +193,22 @@ describe "A connection pool with a max size of 1" do
186
193
 
187
194
  @pool.available_connections.should be_empty
188
195
  @pool.allocated.should == {t1=>cc}
189
-
196
+
190
197
  cc.gsub!('rr', 'll')
191
- sleep 0.05 * m
192
-
193
- # connection held by t2
194
- t1.should_not be_alive
195
- t2.should be_alive
198
+ q.push nil
199
+ q1.pop
196
200
 
201
+ t1.join
202
+ t2.should be_alive
203
+
197
204
  c2.should == 'hello'
198
205
 
199
206
  @pool.available_connections.should be_empty
200
207
  @pool.allocated.should == {t2=>cc}
201
208
 
202
- cc.gsub!('ll', 'rr')
203
- sleep 0.05 * m
204
-
205
209
  #connection released
206
- t2.should_not be_alive
207
-
208
- cc.should == 'herro'
210
+ q.push nil
211
+ t2.join
209
212
 
210
213
  @invoked_count.should == 1
211
214
  @pool.size.should == 1
@@ -236,34 +239,81 @@ describe "A connection pool with a max size of 1" do
236
239
  end
237
240
 
238
241
  shared_examples_for "A threaded connection pool" do
242
+ specify "should not have all_connections yield connections allocated to other threads" do
243
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>2, :pool_timeout=>0))
244
+ q, q1 = Queue.new, Queue.new
245
+ t = Thread.new do
246
+ pool.hold do |c1|
247
+ q1.push nil
248
+ q.pop
249
+ end
250
+ end
251
+ pool.hold do |c1|
252
+ q1.pop
253
+ pool.all_connections{|c| c.should == c1}
254
+ q.push nil
255
+ end
256
+ t.join
257
+ end
258
+
259
+ specify "should not have all_connections yield all available connections" do
260
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>2, :pool_timeout=>0))
261
+ q, q1 = Queue.new, Queue.new
262
+ b = []
263
+ t = Thread.new do
264
+ pool.hold do |c1|
265
+ b << c1
266
+ q1.push nil
267
+ q.pop
268
+ end
269
+ end
270
+ pool.hold do |c1|
271
+ q1.pop
272
+ b << c1
273
+ q.push nil
274
+ end
275
+ t.join
276
+ a = []
277
+ pool.all_connections{|c| a << c}
278
+ a.sort.should == b.sort
279
+ end
280
+
281
+ specify "should raise a PoolTimeout error if a connection couldn't be acquired before timeout" do
282
+ x = nil
283
+ q, q1 = Queue.new, Queue.new
284
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>1, :pool_timeout=>0))
285
+ t = Thread.new{pool.hold{|c| q1.push nil; q.pop}}
286
+ q1.pop
287
+ proc{pool.hold{|c|}}.should raise_error(Sequel::PoolTimeout)
288
+ q.push nil
289
+ t.join
290
+ end
291
+
292
+ it "should not add a disconnected connection back to the pool if the disconnection_proc raises an error" do
293
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| raise Sequel::Error}, &@icpp), @cp_opts.merge(:max_connections=>1, :pool_timeout=>0))
294
+ proc{pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::Error)
295
+ pool.available_connections.length.should == 0
296
+ end
297
+
239
298
  specify "should let five threads simultaneously access separate connections" do
240
299
  cc = {}
241
300
  threads = []
242
- stop = nil
301
+ q, q1, q2 = Queue.new, Queue.new, Queue.new
243
302
 
244
- 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.02;end}}; sleep 0.02}
245
- sleep 0.04
303
+ 5.times{|i| threads << Thread.new{@pool.hold{|c| q.pop; cc[i] = c; q1.push nil; q2.pop}}; q.push nil; q1.pop}
246
304
  threads.each {|t| t.should be_alive}
247
305
  cc.size.should == 5
248
306
  @invoked_count.should == 5
249
307
  @pool.size.should == 5
250
308
  @pool.available_connections.should be_empty
251
- i = 0
309
+
252
310
  h = {}
311
+ i = 0
253
312
  threads.each{|t| h[t] = (i+=1)}
254
313
  @pool.allocated.should == h
255
-
256
- threads[0].raise "your'e dead"
257
- sleep 0.02
258
- threads[3].raise "your'e dead too"
259
-
260
- sleep 0.02
261
-
262
- @pool.available_connections.should == [1, 4]
263
- @pool.allocated.should == {threads[1]=>2, threads[2]=>3, threads[4]=>5}
264
-
265
- stop = true
266
- sleep 0.04
314
+ @pool.available_connections.should == []
315
+ 5.times{q2.push nil}
316
+ threads.each{|t| t.join}
267
317
 
268
318
  @pool.available_connections.size.should == 5
269
319
  @pool.allocated.should be_empty
@@ -272,16 +322,15 @@ shared_examples_for "A threaded connection pool" do
272
322
  specify "should block threads until a connection becomes available" do
273
323
  cc = {}
274
324
  threads = []
275
- stop = nil
325
+ q, q1 = Queue.new, Queue.new
276
326
 
277
- 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.01;end}}; sleep 0.01}
278
- sleep 0.02
327
+ 5.times{|i| threads << Thread.new{@pool.hold{|c| cc[i] = c; q1.push nil; q.pop}}}
328
+ 5.times{q1.pop}
279
329
  threads.each {|t| t.should be_alive}
280
330
  @pool.available_connections.should be_empty
281
331
 
282
- 3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
332
+ 3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c; q1.push nil}}}
283
333
 
284
- sleep 0.02
285
334
  threads[5].should be_alive
286
335
  threads[6].should be_alive
287
336
  threads[7].should be_alive
@@ -290,8 +339,10 @@ shared_examples_for "A threaded connection pool" do
290
339
  cc[6].should be_nil
291
340
  cc[7].should be_nil
292
341
 
293
- stop = true
294
- sleep 0.1
342
+ 5.times{q.push nil}
343
+ 5.times{|i| threads[i].join}
344
+ 3.times{q1.pop}
345
+ 3.times{|i| threads[i+5].join}
295
346
 
296
347
  threads.each {|t| t.should_not be_alive}
297
348
 
@@ -300,12 +351,61 @@ shared_examples_for "A threaded connection pool" do
300
351
  @pool.available_connections.size.should == 5
301
352
  @pool.allocated.should be_empty
302
353
  end
354
+
355
+ specify "should store connections in a stack by default" do
356
+ c2 = nil
357
+ c = @pool.hold{|cc| Thread.new{@pool.hold{|cc2| c2 = cc2}}.join; cc}
358
+ @pool.size.should == 2
359
+ @pool.hold{|cc| cc.should == c}
360
+ @pool.hold{|cc| cc.should == c}
361
+ @pool.hold do |cc|
362
+ cc.should == c
363
+ Thread.new{@pool.hold{|cc2| cc2.should == c2}}
364
+ end
365
+ end
366
+
367
+ specify "should store connections in a queue if :connection_handling=>:queue" do
368
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:connection_handling=>:queue))
369
+ c2 = nil
370
+ c = @pool.hold{|cc| Thread.new{@pool.hold{|cc2| c2 = cc2}}.join; cc}
371
+ @pool.size.should == 2
372
+ @pool.hold{|cc| cc.should == c2}
373
+ @pool.hold{|cc| cc.should == c}
374
+ @pool.hold do |cc|
375
+ cc.should == c2
376
+ Thread.new{@pool.hold{|cc2| cc2.should == c}}
377
+ end
378
+ end
379
+
380
+ specify "should not store connections if :connection_handling=>:disconnect" do
381
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:connection_handling=>:disconnect))
382
+ d = []
383
+ @pool.db.meta_def(:disconnect_connection){|c| d << c}
384
+ c = @pool.hold do |cc|
385
+ cc.should == 1
386
+ Thread.new{@pool.hold{|cc2| cc2.should == 2}}.join
387
+ d.should == [2]
388
+ @pool.hold{|cc3| cc3.should == 1}
389
+ end
390
+ @pool.size.should == 0
391
+ d.should == [2, 1]
392
+
393
+ @pool.hold{|cc| cc.should == 3}
394
+ @pool.size.should == 0
395
+ d.should == [2, 1, 3]
396
+
397
+ @pool.hold{|cc| cc.should == 4}
398
+ @pool.size.should == 0
399
+ d.should == [2, 1, 3, 4]
400
+ end
303
401
  end
304
402
 
305
403
  describe "Threaded Unsharded Connection Pool" do
306
404
  before do
307
405
  @invoked_count = 0
308
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
406
+ @icpp = proc{@invoked_count += 1}
407
+ @cp_opts = CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)
408
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts)
309
409
  end
310
410
 
311
411
  it_should_behave_like "A threaded connection pool"
@@ -314,7 +414,9 @@ end
314
414
  describe "Threaded Sharded Connection Pool" do
315
415
  before do
316
416
  @invoked_count = 0
317
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{})) {@invoked_count += 1}
417
+ @icpp = proc{@invoked_count += 1}
418
+ @cp_opts = CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{})
419
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts)
318
420
  end
319
421
 
320
422
  it_should_behave_like "A threaded connection pool"
@@ -323,62 +425,40 @@ end
323
425
  describe "ConnectionPool#disconnect" do
324
426
  before do
325
427
  @count = 0
326
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{})) {{:id => @count += 1}}
428
+ cp = proc{@count += 1}
429
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call{{:id => cp.call}}, CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{}))
430
+ threads = []
431
+ q, q1 = Queue.new, Queue.new
432
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| q1.push nil; q.pop}}}
433
+ 5.times{q1.pop}
434
+ 5.times{q.push nil}
435
+ threads.each {|t| t.join}
327
436
  end
328
437
 
329
438
  specify "should invoke the given block for each available connection" do
330
- threads = []
331
- stop = nil
332
- 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
333
- while @pool.size < 5
334
- sleep 0.02
335
- end
336
- stop = true
337
- sleep 0.1
338
- threads.each {|t| t.join}
339
-
340
439
  @pool.size.should == 5
341
440
  @pool.available_connections.size.should == 5
342
441
  @pool.available_connections.each {|c| c[:id].should_not be_nil}
343
442
  conns = []
344
- @pool.disconnect {|c| conns << c}
443
+ @pool.db.meta_def(:disconnect_connection){|c| conns << c}
444
+ @pool.disconnect
345
445
  conns.size.should == 5
346
446
  end
347
447
 
348
448
  specify "should remove all available connections" do
349
- threads = []
350
- stop = nil
351
- 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
352
- while @pool.size < 5
353
- sleep 0.02
354
- end
355
- stop = true
356
- sleep 0.1
357
- threads.each {|t| t.join}
358
-
359
449
  @pool.size.should == 5
360
450
  @pool.disconnect
361
451
  @pool.size.should == 0
362
452
  end
363
453
 
364
454
  specify "should disconnect connections in use as soon as they are no longer in use" do
365
- threads = []
366
- stop = nil
367
- 5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.01;end}}; sleep 0.01}
368
- while @pool.size < 5
369
- sleep 0.02
370
- end
371
- stop = true
372
- sleep 0.1
373
- threads.each {|t| t.join}
374
-
375
455
  @pool.size.should == 5
376
-
377
456
  @pool.hold do |conn|
378
457
  @pool.available_connections.size.should == 4
379
458
  @pool.available_connections.each {|c| c.should_not be(conn)}
380
459
  conns = []
381
- @pool.disconnect {|c| conns << c}
460
+ @pool.db.meta_def(:disconnect_connection){|c| conns << c}
461
+ @pool.disconnect
382
462
  conns.size.should == 4
383
463
  @pool.size.should == 1
384
464
  end
@@ -388,8 +468,18 @@ end
388
468
 
389
469
  describe "A connection pool with multiple servers" do
390
470
  before do
391
- @invoked_counts = Hash.new(0)
392
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:servers=>{:read_only=>{}})){|server| "#{server}#{@invoked_counts[server] += 1}"}
471
+ ic = @invoked_counts = Hash.new(0)
472
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call{|server| "#{server}#{ic[server] += 1}"}, CONNECTION_POOL_DEFAULTS.merge(:servers=>{:read_only=>{}}))
473
+ end
474
+
475
+ specify "#all_connections should return connections for all servers" do
476
+ @pool.hold{}
477
+ @pool.all_connections{|c1| c1.should == "default1"}
478
+ a = []
479
+ @pool.hold(:read_only) do |c|
480
+ @pool.all_connections{|c1| a << c1}
481
+ end
482
+ a.sort_by{|c| c.to_s}.should == ["default1", "read_only1"]
393
483
  end
394
484
 
395
485
  specify "#servers should return symbols for all servers" do
@@ -420,7 +510,8 @@ describe "A connection pool with multiple servers" do
420
510
  end
421
511
 
422
512
  specify "should support a :servers_hash option used for converting the server argument" do
423
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:servers_hash=>Hash.new(:read_only), :servers=>{:read_only=>{}})){|server| "#{server}#{@invoked_counts[server] += 1}"}
513
+ ic = @invoked_counts
514
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call{|server| "#{server}#{ic[server] += 1}"}, CONNECTION_POOL_DEFAULTS.merge(:servers_hash=>Hash.new(:read_only), :servers=>{:read_only=>{}}))
424
515
  @pool.hold(:blah) do |c1|
425
516
  c1.should == "read_only1"
426
517
  @pool.hold(:blah) do |c2|
@@ -431,7 +522,7 @@ describe "A connection pool with multiple servers" do
431
522
  end
432
523
  end
433
524
 
434
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:servers_hash=>Hash.new{|h,k| raise Sequel::Error}, :servers=>{:read_only=>{}})){|server| "#{server}#{@invoked_counts[server] += 1}"}
525
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call{|server| "#{server}#{ic[server] += 1}"}, CONNECTION_POOL_DEFAULTS.merge(:servers_hash=>Hash.new{|h,k| raise Sequel::Error}, :servers=>{:read_only=>{}}))
435
526
  proc{@pool.hold(:blah){|c1|}}.should raise_error(Sequel::Error)
436
527
  end
437
528
 
@@ -468,7 +559,8 @@ describe "A connection pool with multiple servers" do
468
559
  conns = []
469
560
  @pool.size.should == 1
470
561
  @pool.size(:read_only).should == 1
471
- @pool.disconnect{|c| conns << c}
562
+ @pool.db.meta_def(:disconnect_connection){|c| conns << c}
563
+ @pool.disconnect
472
564
  conns.sort.should == %w'default1 read_only1'
473
565
  @pool.size.should == 0
474
566
  @pool.size(:read_only).should == 0
@@ -477,7 +569,7 @@ describe "A connection pool with multiple servers" do
477
569
  end
478
570
 
479
571
  specify "#add_servers should add new servers to the pool" do
480
- pool = Sequel::ConnectionPool.get_pool(:servers=>{:server1=>{}}){|s| s}
572
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :servers=>{:server1=>{}})
481
573
 
482
574
  pool.hold{}
483
575
  pool.hold(:server2){}
@@ -508,7 +600,7 @@ describe "A connection pool with multiple servers" do
508
600
  end
509
601
 
510
602
  specify "#add_servers should ignore existing keys" do
511
- pool = Sequel::ConnectionPool.get_pool(:servers=>{:server1=>{}}){|s| s}
603
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :servers=>{:server1=>{}})
512
604
 
513
605
  pool.allocated.length.should == 0
514
606
  pool.allocated(:server1).length.should == 0
@@ -554,11 +646,12 @@ describe "A connection pool with multiple servers" do
554
646
  end
555
647
 
556
648
  specify "#remove_servers should disconnect available connections immediately" do
557
- pool = Sequel::ConnectionPool.get_pool(:max_connections=>5, :servers=>{:server1=>{}}){|s| s}
649
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :max_connections=>5, :servers=>{:server1=>{}})
558
650
  threads = []
559
- stop = nil
560
- 5.times {|i| threads << Thread.new{pool.hold(:server1){|c| sleep 0.05}}}
561
- sleep 0.1
651
+ q, q1 = Queue.new, Queue.new
652
+ 5.times {|i| threads << Thread.new {pool.hold(:server1){|c| q1.push nil; q.pop}}}
653
+ 5.times{q1.pop}
654
+ 5.times{q.push nil}
562
655
  threads.each {|t| t.join}
563
656
 
564
657
  pool.size(:server1).should == 5
@@ -568,7 +661,7 @@ describe "A connection pool with multiple servers" do
568
661
 
569
662
  specify "#remove_servers should disconnect connections in use as soon as they are returned to the pool" do
570
663
  dc = []
571
- pool = Sequel::ConnectionPool.get_pool(:servers=>{:server1=>{}}, :disconnection_proc=>proc{|c| dc << c}){|s| s}
664
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| dc << c}){|c| c}, :servers=>{:server1=>{}})
572
665
  c1 = nil
573
666
  pool.hold(:server1) do |c|
574
667
  pool.size(:server1).should == 1
@@ -583,7 +676,7 @@ describe "A connection pool with multiple servers" do
583
676
  end
584
677
 
585
678
  specify "#remove_servers should remove server related data structures immediately" do
586
- pool = Sequel::ConnectionPool.get_pool(:servers=>{:server1=>{}}){|s| s}
679
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :servers=>{:server1=>{}})
587
680
  pool.available_connections(:server1).should == []
588
681
  pool.allocated(:server1).should == {}
589
682
  pool.remove_servers([:server1])
@@ -592,14 +685,14 @@ describe "A connection pool with multiple servers" do
592
685
  end
593
686
 
594
687
  specify "#remove_servers should not allow the removal of the default server" do
595
- pool = Sequel::ConnectionPool.get_pool(:servers=>{:server1=>{}}){|s| s}
688
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call{|s| s}, :servers=>{:server1=>{}})
596
689
  proc{pool.remove_servers([:server1])}.should_not raise_error
597
690
  proc{pool.remove_servers([:default])}.should raise_error(Sequel::Error)
598
691
  end
599
692
 
600
693
  specify "#remove_servers should ignore servers that have already been removed" do
601
694
  dc = []
602
- pool = Sequel::ConnectionPool.get_pool(:servers=>{:server1=>{}}, :disconnection_proc=>proc{|c| dc << c}){|s| s}
695
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| dc << c}){|c| c}, :servers=>{:server1=>{}})
603
696
  c1 = nil
604
697
  pool.hold(:server1) do |c|
605
698
  pool.size(:server1).should == 1
@@ -619,7 +712,7 @@ ST_CONNECTION_POOL_DEFAULTS = CONNECTION_POOL_DEFAULTS.merge(:single_threaded=>t
619
712
 
620
713
  describe "SingleConnectionPool" do
621
714
  before do
622
- @pool = Sequel::ConnectionPool.get_pool(ST_CONNECTION_POOL_DEFAULTS){1234}
715
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call{1234}, ST_CONNECTION_POOL_DEFAULTS)
623
716
  end
624
717
 
625
718
  specify "should provide a #hold method" do
@@ -631,7 +724,7 @@ describe "SingleConnectionPool" do
631
724
  specify "should provide a #disconnect method" do
632
725
  conn = nil
633
726
  x = nil
634
- pool = Sequel::ConnectionPool.get_pool(ST_CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| conn = c})){1234}
727
+ pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| conn = c}){1234}, ST_CONNECTION_POOL_DEFAULTS)
635
728
  pool.hold{|c| x = c}
636
729
  x.should == 1234
637
730
  pool.disconnect
@@ -642,7 +735,18 @@ end
642
735
  describe "A single threaded pool with multiple servers" do
643
736
  before do
644
737
  @max_size=2
645
- @pool = Sequel::ConnectionPool.get_pool(ST_CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| @max_size=3}, :servers=>{:read_only=>{}})){|server| server}
738
+ msp = proc{@max_size += 1}
739
+ @pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| msp.call}){|c| c}, ST_CONNECTION_POOL_DEFAULTS.merge(:servers=>{:read_only=>{}}))
740
+ end
741
+
742
+ specify "#all_connections should return connections for all servers" do
743
+ @pool.hold{}
744
+ @pool.all_connections{|c1| c1.should == :default}
745
+ a = []
746
+ @pool.hold(:read_only) do
747
+ @pool.all_connections{|c1| a << c1}
748
+ end
749
+ a.sort_by{|c| c.to_s}.should == [:default, :read_only]
646
750
  end
647
751
 
648
752
  specify "#servers should return symbols for all servers" do
@@ -726,11 +830,10 @@ describe "A single threaded pool with multiple servers" do
726
830
  specify "#disconnect should disconnect from all servers" do
727
831
  @pool.hold(:read_only){}
728
832
  @pool.hold{}
729
- conns = []
730
833
  @pool.conn.should == :default
731
834
  @pool.conn(:read_only).should == :read_only
732
- @pool.disconnect{|c| conns << c}
733
- conns.sort_by{|x| x.to_s}.should == [:default, :read_only]
835
+ @pool.disconnect
836
+ @max_size.should == 4
734
837
  @pool.conn.should == nil
735
838
  @pool.conn(:read_only).should == nil
736
839
  end
@@ -751,69 +854,92 @@ describe "A single threaded pool with multiple servers" do
751
854
  end
752
855
 
753
856
  shared_examples_for "All connection pools classes" do
857
+ specify "should have pool_type return a symbol" do
858
+ @class.new(mock_db.call{123}, {}).pool_type.should be_a_kind_of(Symbol)
859
+ end
860
+
861
+ specify "should have all_connections yield current and available connections" do
862
+ p = @class.new(mock_db.call{123}, {})
863
+ p.hold{|c| p.all_connections{|c1| c.should == c1}}
864
+ end
865
+
866
+ specify "should be able to modify after_connect proc after the pool is created" do
867
+ a = []
868
+ p = @class.new(mock_db.call{123}, {})
869
+ p.after_connect = pr = proc{|c| a << c}
870
+ p.after_connect.should == pr
871
+ a.should == []
872
+ p.hold{}
873
+ a.should == [123]
874
+ end
875
+
754
876
  specify "should not raise an error when disconnecting twice" do
755
- c = @class.new({}){123}
877
+ c = @class.new(mock_db.call{123}, {})
756
878
  proc{c.disconnect}.should_not raise_error
757
879
  proc{c.disconnect}.should_not raise_error
758
880
  end
759
881
 
760
882
  specify "should yield a connection created by the initialize block to hold" do
761
883
  x = nil
762
- @class.new({}){123}.hold{|c| x = c}
884
+ @class.new(mock_db.call{123}, {}).hold{|c| x = c}
763
885
  x.should == 123
764
886
  end
765
887
 
766
888
  specify "should have the initialize block accept a shard/server argument" do
767
889
  x = nil
768
- @class.new({}){|c| [c, c]}.hold{|c| x = c}
890
+ @class.new(mock_db.call{|c| [c, c]}, {}).hold{|c| x = c}
769
891
  x.should == [:default, :default]
770
892
  end
771
893
 
772
894
  specify "should have respect an :after_connect proc that is called with each newly created connection" do
773
895
  x = nil
774
- @class.new(:after_connect=>proc{|c| x = [c, c]}){|c| 123}.hold{}
896
+ @class.new(mock_db.call{123}, :after_connect=>proc{|c| x = [c, c]}).hold{}
775
897
  x.should == [123, 123]
776
898
  end
777
899
 
778
900
  specify "should raise a DatabaseConnectionError if the connection raises an exception" do
779
- proc{@class.new({}){|c| raise Exception}.hold{}}.should raise_error(Sequel::DatabaseConnectionError)
901
+ proc{@class.new(mock_db.call{|c| raise Exception}, {}).hold{}}.should raise_error(Sequel::DatabaseConnectionError)
780
902
  end
781
903
 
782
904
  specify "should raise a DatabaseConnectionError if the initialize block returns nil" do
783
- proc{@class.new({}){}.hold{}}.should raise_error(Sequel::DatabaseConnectionError)
905
+ proc{@class.new(mock_db.call{}, {}).hold{}}.should raise_error(Sequel::DatabaseConnectionError)
784
906
  end
785
907
 
786
908
  specify "should call the disconnection_proc option if the hold block raises a DatabaseDisconnectError" do
787
909
  x = nil
788
- proc{@class.new(:disconnection_proc=>proc{|c| x = c}){123}.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
910
+ proc{c = @class.new(mock_db.call(proc{|c| x = c}){123}).hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
789
911
  x.should == 123
790
912
  end
791
913
 
792
- specify "should have a disconnect method that calls the :disconnection_proc option with the connection" do
914
+ specify "should have a disconnect method that disconnects the connection" do
793
915
  x = nil
794
- c = @class.new(:disconnection_proc=>proc{|c| x = c}){123}
916
+ c = @class.new(mock_db.call(proc{|c| x = c}){123})
795
917
  c.hold{}
796
918
  x.should == nil
797
919
  c.disconnect
798
920
  x.should == 123
799
921
  end
800
922
 
801
- specify "should have a disconnect method that calls the given block with the connection" do
802
- x = nil
803
- y = nil
804
- c = @class.new(:disconnection_proc=>proc{|c| x = c}){123}
805
- c.hold{}
806
- c.disconnect{|c| y = c}
807
- x.should == nil
808
- y.should == 123
923
+ specify "should have a reentrent hold method" do
924
+ o = Object.new
925
+ c = @class.new(mock_db.call{o}, {})
926
+ c.hold do |x|
927
+ x.should == o
928
+ c.hold do |x1|
929
+ x1.should == o
930
+ c.hold do |x2|
931
+ x2.should == o
932
+ end
933
+ end
934
+ end
809
935
  end
810
936
 
811
937
  specify "should have a servers method that returns an array of shard/server symbols" do
812
- @class.new({}){123}.servers.should == [:default]
938
+ @class.new(mock_db.call{123}, {}).servers.should == [:default]
813
939
  end
814
940
 
815
941
  specify "should have a servers method that returns an array of shard/server symbols" do
816
- c = @class.new({}){123}
942
+ c = @class.new(mock_db.call{123}, {})
817
943
  c.size.should == 0
818
944
  c.hold{}
819
945
  c.size.should == 1
@@ -823,6 +949,9 @@ end
823
949
  Sequel::ConnectionPool::CONNECTION_POOL_MAP.keys.each do |k, v|
824
950
  opts = {:single_threaded=>k, :servers=>(v ? {} : nil)}
825
951
  describe "Connection pool with #{opts.inspect}" do
952
+ before(:all) do
953
+ Sequel::ConnectionPool.send(:get_pool, mock_db.call, opts)
954
+ end
826
955
  before do
827
956
  @class = Sequel::ConnectionPool.send(:connection_pool_class, opts)
828
957
  end