sequel 3.21.0 → 3.39.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 (352) hide show
  1. data/CHANGELOG +1061 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +103 -63
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +67 -51
  7. data/doc/advanced_associations.rdoc +189 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/cheat_sheet.rdoc +21 -21
  10. data/doc/core_extensions.rdoc +374 -0
  11. data/doc/dataset_basics.rdoc +10 -10
  12. data/doc/dataset_filtering.rdoc +54 -42
  13. data/doc/mass_assignment.rdoc +56 -0
  14. data/doc/migration.rdoc +89 -557
  15. data/doc/model_hooks.rdoc +80 -29
  16. data/doc/object_model.rdoc +547 -0
  17. data/doc/opening_databases.rdoc +114 -53
  18. data/doc/prepared_statements.rdoc +41 -15
  19. data/doc/querying.rdoc +137 -56
  20. data/doc/reflection.rdoc +36 -10
  21. data/doc/release_notes/3.22.0.txt +39 -0
  22. data/doc/release_notes/3.23.0.txt +172 -0
  23. data/doc/release_notes/3.24.0.txt +420 -0
  24. data/doc/release_notes/3.25.0.txt +88 -0
  25. data/doc/release_notes/3.26.0.txt +88 -0
  26. data/doc/release_notes/3.27.0.txt +82 -0
  27. data/doc/release_notes/3.28.0.txt +304 -0
  28. data/doc/release_notes/3.29.0.txt +459 -0
  29. data/doc/release_notes/3.30.0.txt +135 -0
  30. data/doc/release_notes/3.31.0.txt +146 -0
  31. data/doc/release_notes/3.32.0.txt +202 -0
  32. data/doc/release_notes/3.33.0.txt +157 -0
  33. data/doc/release_notes/3.34.0.txt +671 -0
  34. data/doc/release_notes/3.35.0.txt +144 -0
  35. data/doc/release_notes/3.36.0.txt +245 -0
  36. data/doc/release_notes/3.37.0.txt +338 -0
  37. data/doc/release_notes/3.38.0.txt +234 -0
  38. data/doc/release_notes/3.39.0.txt +237 -0
  39. data/doc/schema_modification.rdoc +585 -0
  40. data/doc/sharding.rdoc +99 -8
  41. data/doc/sql.rdoc +154 -112
  42. data/doc/testing.rdoc +169 -0
  43. data/doc/thread_safety.rdoc +17 -0
  44. data/doc/transactions.rdoc +137 -0
  45. data/doc/validations.rdoc +1 -1
  46. data/doc/virtual_rows.rdoc +78 -43
  47. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  48. data/lib/sequel/adapters/ado.rb +40 -18
  49. data/lib/sequel/adapters/amalgalite.rb +17 -9
  50. data/lib/sequel/adapters/db2.rb +175 -86
  51. data/lib/sequel/adapters/dbi.rb +15 -15
  52. data/lib/sequel/adapters/do/mysql.rb +17 -11
  53. data/lib/sequel/adapters/do/postgres.rb +2 -61
  54. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  55. data/lib/sequel/adapters/do.rb +18 -36
  56. data/lib/sequel/adapters/firebird.rb +27 -208
  57. data/lib/sequel/adapters/ibmdb.rb +453 -0
  58. data/lib/sequel/adapters/informix.rb +6 -23
  59. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  60. data/lib/sequel/adapters/jdbc/db2.rb +56 -0
  61. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  62. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  63. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  64. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  65. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  66. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  67. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  68. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  69. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  70. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  71. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  73. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  74. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  75. data/lib/sequel/adapters/jdbc.rb +279 -97
  76. data/lib/sequel/adapters/mock.rb +372 -0
  77. data/lib/sequel/adapters/mysql.rb +125 -222
  78. data/lib/sequel/adapters/mysql2.rb +65 -56
  79. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  80. data/lib/sequel/adapters/odbc.rb +28 -9
  81. data/lib/sequel/adapters/openbase.rb +3 -5
  82. data/lib/sequel/adapters/oracle.rb +349 -53
  83. data/lib/sequel/adapters/postgres.rb +368 -138
  84. data/lib/sequel/adapters/shared/access.rb +32 -9
  85. data/lib/sequel/adapters/shared/db2.rb +343 -0
  86. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  87. data/lib/sequel/adapters/shared/informix.rb +53 -0
  88. data/lib/sequel/adapters/shared/mssql.rb +401 -116
  89. data/lib/sequel/adapters/shared/mysql.rb +424 -89
  90. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  91. data/lib/sequel/adapters/shared/oracle.rb +257 -45
  92. data/lib/sequel/adapters/shared/postgres.rb +675 -279
  93. data/lib/sequel/adapters/shared/progress.rb +5 -8
  94. data/lib/sequel/adapters/shared/sqlite.rb +285 -96
  95. data/lib/sequel/adapters/sqlite.rb +101 -39
  96. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  97. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  98. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  99. data/lib/sequel/adapters/swift.rb +28 -19
  100. data/lib/sequel/adapters/tinytds.rb +174 -22
  101. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  102. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  103. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  104. data/lib/sequel/ast_transformer.rb +194 -0
  105. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  106. data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
  107. data/lib/sequel/connection_pool/single.rb +5 -0
  108. data/lib/sequel/connection_pool/threaded.rb +43 -14
  109. data/lib/sequel/connection_pool.rb +10 -2
  110. data/lib/sequel/core.rb +143 -11
  111. data/lib/sequel/database/connecting.rb +38 -28
  112. data/lib/sequel/database/dataset.rb +4 -4
  113. data/lib/sequel/database/dataset_defaults.rb +63 -2
  114. data/lib/sequel/database/logging.rb +7 -2
  115. data/lib/sequel/database/misc.rb +190 -46
  116. data/lib/sequel/database/query.rb +272 -110
  117. data/lib/sequel/database/schema_generator.rb +103 -36
  118. data/lib/sequel/database/schema_methods.rb +300 -67
  119. data/lib/sequel/dataset/actions.rb +344 -90
  120. data/lib/sequel/dataset/features.rb +101 -8
  121. data/lib/sequel/dataset/graph.rb +42 -15
  122. data/lib/sequel/dataset/misc.rb +52 -25
  123. data/lib/sequel/dataset/mutation.rb +12 -7
  124. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  125. data/lib/sequel/dataset/query.rb +305 -54
  126. data/lib/sequel/dataset/sql.rb +720 -292
  127. data/lib/sequel/dataset.rb +8 -0
  128. data/lib/sequel/exceptions.rb +4 -0
  129. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  130. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  131. data/lib/sequel/extensions/blank.rb +4 -0
  132. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  133. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  134. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  135. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  136. data/lib/sequel/extensions/inflector.rb +4 -0
  137. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  138. data/lib/sequel/extensions/migration.rb +100 -11
  139. data/lib/sequel/extensions/named_timezones.rb +9 -0
  140. data/lib/sequel/extensions/null_dataset.rb +94 -0
  141. data/lib/sequel/extensions/pagination.rb +4 -0
  142. data/lib/sequel/extensions/pg_array.rb +537 -0
  143. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  144. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  145. data/lib/sequel/extensions/pg_hstore.rb +313 -0
  146. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  147. data/lib/sequel/extensions/pg_inet.rb +113 -0
  148. data/lib/sequel/extensions/pg_interval.rb +191 -0
  149. data/lib/sequel/extensions/pg_json.rb +208 -0
  150. data/lib/sequel/extensions/pg_range.rb +512 -0
  151. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  152. data/lib/sequel/extensions/pg_row.rb +572 -0
  153. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  154. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  155. data/lib/sequel/extensions/pretty_table.rb +17 -72
  156. data/lib/sequel/extensions/query.rb +8 -4
  157. data/lib/sequel/extensions/query_literals.rb +79 -0
  158. data/lib/sequel/extensions/schema_caching.rb +76 -0
  159. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  160. data/lib/sequel/extensions/select_remove.rb +39 -0
  161. data/lib/sequel/extensions/server_block.rb +140 -0
  162. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  163. data/lib/sequel/extensions/sql_expr.rb +8 -110
  164. data/lib/sequel/extensions/string_date_time.rb +4 -0
  165. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  166. data/lib/sequel/extensions/to_dot.rb +99 -83
  167. data/lib/sequel/model/associations.rb +1263 -409
  168. data/lib/sequel/model/base.rb +624 -171
  169. data/lib/sequel/model/errors.rb +1 -1
  170. data/lib/sequel/model/exceptions.rb +24 -2
  171. data/lib/sequel/model/inflections.rb +1 -1
  172. data/lib/sequel/model.rb +30 -11
  173. data/lib/sequel/no_core_ext.rb +2 -0
  174. data/lib/sequel/plugins/active_model.rb +13 -1
  175. data/lib/sequel/plugins/association_pks.rb +22 -4
  176. data/lib/sequel/plugins/caching.rb +25 -18
  177. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  178. data/lib/sequel/plugins/composition.rb +44 -12
  179. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  180. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  181. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  182. data/lib/sequel/plugins/dirty.rb +214 -0
  183. data/lib/sequel/plugins/eager_each.rb +59 -0
  184. data/lib/sequel/plugins/force_encoding.rb +6 -6
  185. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  186. data/lib/sequel/plugins/identity_map.rb +134 -15
  187. data/lib/sequel/plugins/instance_filters.rb +10 -0
  188. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  189. data/lib/sequel/plugins/json_serializer.rb +58 -6
  190. data/lib/sequel/plugins/list.rb +13 -2
  191. data/lib/sequel/plugins/many_through_many.rb +103 -51
  192. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  193. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  194. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  195. data/lib/sequel/plugins/pg_row.rb +121 -0
  196. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  197. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  198. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  199. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  200. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  201. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  202. data/lib/sequel/plugins/schema.rb +8 -3
  203. data/lib/sequel/plugins/serialization.rb +98 -49
  204. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  205. data/lib/sequel/plugins/sharding.rb +21 -54
  206. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  207. data/lib/sequel/plugins/static_cache.rb +99 -0
  208. data/lib/sequel/plugins/subclasses.rb +29 -3
  209. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  210. data/lib/sequel/plugins/timestamps.rb +1 -1
  211. data/lib/sequel/plugins/tree.rb +3 -3
  212. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  213. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  214. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  215. data/lib/sequel/plugins/validation_helpers.rb +55 -4
  216. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  217. data/lib/sequel/sql.rb +649 -122
  218. data/lib/sequel/timezones.rb +67 -40
  219. data/lib/sequel/version.rb +1 -1
  220. data/spec/adapters/db2_spec.rb +146 -0
  221. data/spec/adapters/firebird_spec.rb +1 -1
  222. data/spec/adapters/mssql_spec.rb +194 -66
  223. data/spec/adapters/mysql_spec.rb +475 -306
  224. data/spec/adapters/oracle_spec.rb +92 -117
  225. data/spec/adapters/postgres_spec.rb +1982 -325
  226. data/spec/adapters/spec_helper.rb +9 -6
  227. data/spec/adapters/sqlite_spec.rb +203 -75
  228. data/spec/core/connection_pool_spec.rb +218 -93
  229. data/spec/core/database_spec.rb +956 -522
  230. data/spec/core/dataset_spec.rb +1631 -1242
  231. data/spec/core/expression_filters_spec.rb +690 -334
  232. data/spec/core/mock_adapter_spec.rb +453 -0
  233. data/spec/core/object_graph_spec.rb +88 -129
  234. data/spec/core/schema_generator_spec.rb +4 -4
  235. data/spec/core/schema_spec.rb +556 -53
  236. data/spec/core/spec_helper.rb +7 -48
  237. data/spec/core_extensions_spec.rb +626 -0
  238. data/spec/extensions/active_model_spec.rb +13 -0
  239. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  240. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  241. data/spec/extensions/association_dependencies_spec.rb +15 -25
  242. data/spec/extensions/association_pks_spec.rb +66 -32
  243. data/spec/extensions/association_proxies_spec.rb +4 -4
  244. data/spec/extensions/boolean_readers_spec.rb +25 -25
  245. data/spec/extensions/caching_spec.rb +47 -51
  246. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  247. data/spec/extensions/columns_introspection_spec.rb +91 -0
  248. data/spec/extensions/composition_spec.rb +18 -13
  249. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  250. data/spec/extensions/constraint_validations_spec.rb +316 -0
  251. data/spec/extensions/dataset_associations_spec.rb +199 -0
  252. data/spec/extensions/defaults_setter_spec.rb +88 -0
  253. data/spec/extensions/dirty_spec.rb +155 -0
  254. data/spec/extensions/eager_each_spec.rb +34 -0
  255. data/spec/extensions/eval_inspect_spec.rb +67 -0
  256. data/spec/extensions/force_encoding_spec.rb +4 -2
  257. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  258. data/spec/extensions/identity_map_spec.rb +142 -24
  259. data/spec/extensions/inflector_spec.rb +0 -4
  260. data/spec/extensions/instance_filters_spec.rb +11 -21
  261. data/spec/extensions/instance_hooks_spec.rb +72 -0
  262. data/spec/extensions/json_serializer_spec.rb +49 -12
  263. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  264. data/spec/extensions/list_spec.rb +49 -40
  265. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  266. data/spec/extensions/many_through_many_spec.rb +368 -254
  267. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  268. data/spec/extensions/migration_spec.rb +140 -35
  269. data/spec/extensions/named_timezones_spec.rb +29 -11
  270. data/spec/extensions/nested_attributes_spec.rb +268 -89
  271. data/spec/extensions/null_dataset_spec.rb +85 -0
  272. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  273. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  274. data/spec/extensions/pg_array_spec.rb +320 -0
  275. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  276. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  277. data/spec/extensions/pg_hstore_spec.rb +194 -0
  278. data/spec/extensions/pg_inet_spec.rb +47 -0
  279. data/spec/extensions/pg_interval_spec.rb +72 -0
  280. data/spec/extensions/pg_json_spec.rb +99 -0
  281. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  282. data/spec/extensions/pg_range_spec.rb +395 -0
  283. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  284. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  285. data/spec/extensions/pg_row_spec.rb +323 -0
  286. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  287. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  288. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  289. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  290. data/spec/extensions/prepared_statements_spec.rb +87 -0
  291. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  292. data/spec/extensions/pretty_table_spec.rb +7 -6
  293. data/spec/extensions/query_literals_spec.rb +167 -0
  294. data/spec/extensions/query_spec.rb +9 -3
  295. data/spec/extensions/rcte_tree_spec.rb +50 -43
  296. data/spec/extensions/schema_caching_spec.rb +41 -0
  297. data/spec/extensions/schema_dumper_spec.rb +434 -49
  298. data/spec/extensions/schema_spec.rb +30 -49
  299. data/spec/extensions/select_remove_spec.rb +38 -0
  300. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  301. data/spec/extensions/serialization_spec.rb +86 -48
  302. data/spec/extensions/server_block_spec.rb +90 -0
  303. data/spec/extensions/sharding_spec.rb +69 -143
  304. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  305. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  306. data/spec/extensions/spec_helper.rb +34 -67
  307. data/spec/extensions/split_array_nil_spec.rb +24 -0
  308. data/spec/extensions/sql_expr_spec.rb +29 -60
  309. data/spec/extensions/static_cache_spec.rb +145 -0
  310. data/spec/extensions/subclasses_spec.rb +14 -0
  311. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  312. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  313. data/spec/extensions/timestamps_spec.rb +6 -6
  314. data/spec/extensions/to_dot_spec.rb +8 -11
  315. data/spec/extensions/touch_spec.rb +13 -14
  316. data/spec/extensions/tree_spec.rb +11 -26
  317. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  318. data/spec/extensions/update_primary_key_spec.rb +30 -24
  319. data/spec/extensions/validation_class_methods_spec.rb +58 -67
  320. data/spec/extensions/validation_helpers_spec.rb +31 -37
  321. data/spec/extensions/xml_serializer_spec.rb +29 -4
  322. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  323. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  324. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  325. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  326. data/spec/integration/associations_test.rb +659 -21
  327. data/spec/integration/database_test.rb +11 -5
  328. data/spec/integration/dataset_test.rb +717 -129
  329. data/spec/integration/eager_loader_test.rb +38 -54
  330. data/spec/integration/migrator_test.rb +2 -3
  331. data/spec/integration/model_test.rb +81 -2
  332. data/spec/integration/plugin_test.rb +604 -147
  333. data/spec/integration/prepared_statement_test.rb +272 -128
  334. data/spec/integration/schema_test.rb +367 -57
  335. data/spec/integration/spec_helper.rb +42 -32
  336. data/spec/integration/timezone_test.rb +38 -12
  337. data/spec/integration/transaction_test.rb +183 -8
  338. data/spec/integration/type_test.rb +31 -8
  339. data/spec/model/association_reflection_spec.rb +207 -8
  340. data/spec/model/associations_spec.rb +1206 -693
  341. data/spec/model/base_spec.rb +334 -100
  342. data/spec/model/dataset_methods_spec.rb +45 -27
  343. data/spec/model/eager_loading_spec.rb +828 -692
  344. data/spec/model/hooks_spec.rb +355 -67
  345. data/spec/model/model_spec.rb +251 -179
  346. data/spec/model/plugins_spec.rb +24 -13
  347. data/spec/model/record_spec.rb +506 -232
  348. data/spec/model/spec_helper.rb +16 -77
  349. data/spec/model/validations_spec.rb +38 -2
  350. data/spec/rcov.opts +2 -0
  351. metadata +209 -80
  352. data/spec/core/core_sql_spec.rb +0 -451
@@ -84,7 +84,9 @@ describe "A connection pool handling connections" do
84
84
  end
85
85
 
86
86
  specify "#make_new should not make more than max_size connections" do
87
- 50.times{Thread.new{@cpool.hold{sleep 0.001}}}
87
+ q = Queue.new
88
+ 50.times{Thread.new{@cpool.hold{q.pop}}}
89
+ 50.times{q.push nil}
88
90
  @cpool.created_count.should <= @max_size
89
91
  end
90
92
 
@@ -96,7 +98,8 @@ describe "A connection pool handling connections" do
96
98
 
97
99
  specify "#hold should remove the connection if a DatabaseDisconnectError is raised" do
98
100
  @cpool.created_count.should == 0
99
- @cpool.hold{Thread.new{@cpool.hold{}}; sleep 0.03}
101
+ q, q1 = Queue.new, Queue.new
102
+ @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
103
  @cpool.created_count.should == 2
101
104
  proc{@cpool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::DatabaseDisconnectError)
102
105
  @cpool.created_count.should == 1
@@ -121,36 +124,30 @@ describe "A connection pool handling connection errors" do
121
124
  end
122
125
  end
123
126
 
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
127
  describe "ConnectionPool#hold" do
136
128
  before do
137
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
129
+ value = 0
130
+ @c = Class.new do
131
+ define_method(:initialize){value += 1}
132
+ define_method(:value){value}
133
+ end
134
+ @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS){@c.new}
138
135
  end
139
136
 
140
137
  specify "should pass the result of the connection maker proc to the supplied block" do
141
138
  res = nil
142
139
  @pool.hold {|c| res = c}
143
- res.should be_a_kind_of(DummyConnection)
140
+ res.should be_a_kind_of(@c)
144
141
  res.value.should == 1
145
142
  @pool.hold {|c| res = c}
146
- res.should be_a_kind_of(DummyConnection)
143
+ res.should be_a_kind_of(@c)
147
144
  res.value.should == 1 # the connection maker is invoked only once
148
145
  end
149
146
 
150
147
  specify "should be re-entrant by the same thread" do
151
148
  cc = nil
152
149
  @pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
153
- cc.should be_a_kind_of(DummyConnection)
150
+ cc.should be_a_kind_of(@c)
154
151
  end
155
152
 
156
153
  specify "should catch exceptions and reraise them" do
@@ -166,15 +163,14 @@ describe "A connection pool with a max size of 1" do
166
163
 
167
164
  specify "should let only one thread access the connection at any time" do
168
165
  cc,c1, c2 = nil
169
- m = (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx') ? 30 : 1
166
+ q, q1 = Queue.new, Queue.new
170
167
 
171
- t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.01;end}}
172
- sleep 0.02 * m
168
+ t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; q1.push nil; q.pop}}
169
+ q1.pop
173
170
  cc.should == 'herro'
174
171
  c1.should == 'herro'
175
172
 
176
- t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.01;end}}
177
- sleep 0.02 * m
173
+ t2 = Thread.new {@pool.hold {|c| c2 = c.dup; q1.push nil; q.pop;}}
178
174
 
179
175
  # connection held by t1
180
176
  t1.should be_alive
@@ -186,26 +182,22 @@ describe "A connection pool with a max size of 1" do
186
182
 
187
183
  @pool.available_connections.should be_empty
188
184
  @pool.allocated.should == {t1=>cc}
189
-
185
+
190
186
  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
187
+ q.push nil
188
+ q1.pop
196
189
 
190
+ t1.join
191
+ t2.should be_alive
192
+
197
193
  c2.should == 'hello'
198
194
 
199
195
  @pool.available_connections.should be_empty
200
196
  @pool.allocated.should == {t2=>cc}
201
197
 
202
- cc.gsub!('ll', 'rr')
203
- sleep 0.05 * m
204
-
205
198
  #connection released
206
- t2.should_not be_alive
207
-
208
- cc.should == 'herro'
199
+ q.push nil
200
+ t2.join
209
201
 
210
202
  @invoked_count.should == 1
211
203
  @pool.size.should == 1
@@ -236,34 +228,81 @@ describe "A connection pool with a max size of 1" do
236
228
  end
237
229
 
238
230
  shared_examples_for "A threaded connection pool" do
231
+ specify "should not have all_connections yield connections allocated to other threads" do
232
+ pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:max_connections=>2, :pool_timeout=>0)) {@invoked_count += 1}
233
+ q, q1 = Queue.new, Queue.new
234
+ t = Thread.new do
235
+ pool.hold do |c1|
236
+ q1.push nil
237
+ q.pop
238
+ end
239
+ end
240
+ pool.hold do |c1|
241
+ q1.pop
242
+ pool.all_connections{|c| c.should == c1}
243
+ q.push nil
244
+ end
245
+ t.join
246
+ end
247
+
248
+ specify "should not have all_connections yield all available connections" do
249
+ pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:max_connections=>2, :pool_timeout=>0)){@invoked_count += 1}
250
+ q, q1 = Queue.new, Queue.new
251
+ b = []
252
+ t = Thread.new do
253
+ pool.hold do |c1|
254
+ b << c1
255
+ q1.push nil
256
+ q.pop
257
+ end
258
+ end
259
+ pool.hold do |c1|
260
+ q1.pop
261
+ b << c1
262
+ q.push nil
263
+ end
264
+ t.join
265
+ a = []
266
+ pool.all_connections{|c| a << c}
267
+ a.sort.should == b.sort
268
+ end
269
+
270
+ specify "should raise a PoolTimeout error if a connection couldn't be acquired before timeout" do
271
+ x = nil
272
+ q, q1 = Queue.new, Queue.new
273
+ pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:max_connections=>1, :pool_timeout=>0)) {@invoked_count += 1}
274
+ t = Thread.new{pool.hold{|c| q1.push nil; q.pop}}
275
+ q1.pop
276
+ proc{pool.hold{|c|}}.should raise_error(Sequel::PoolTimeout)
277
+ q.push nil
278
+ t.join
279
+ end
280
+
281
+ it "should not add a disconnected connection back to the pool if the disconnection_proc raises an error" do
282
+ pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:max_connections=>1, :pool_timeout=>0, :disconnection_proc=>proc{|c| raise Sequel::Error})) {@invoked_count += 1}
283
+ proc{pool.hold{raise Sequel::DatabaseDisconnectError}}.should raise_error(Sequel::Error)
284
+ pool.available_connections.length.should == 0
285
+ end
286
+
239
287
  specify "should let five threads simultaneously access separate connections" do
240
288
  cc = {}
241
289
  threads = []
242
- stop = nil
290
+ q, q1, q2 = Queue.new, Queue.new, Queue.new
243
291
 
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
292
+ 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
293
  threads.each {|t| t.should be_alive}
247
294
  cc.size.should == 5
248
295
  @invoked_count.should == 5
249
296
  @pool.size.should == 5
250
297
  @pool.available_connections.should be_empty
251
- i = 0
298
+
252
299
  h = {}
300
+ i = 0
253
301
  threads.each{|t| h[t] = (i+=1)}
254
302
  @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
303
+ @pool.available_connections.should == []
304
+ 5.times{q2.push nil}
305
+ threads.each{|t| t.join}
267
306
 
268
307
  @pool.available_connections.size.should == 5
269
308
  @pool.allocated.should be_empty
@@ -272,16 +311,15 @@ shared_examples_for "A threaded connection pool" do
272
311
  specify "should block threads until a connection becomes available" do
273
312
  cc = {}
274
313
  threads = []
275
- stop = nil
314
+ q, q1 = Queue.new, Queue.new
276
315
 
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
316
+ 5.times{|i| threads << Thread.new{@pool.hold{|c| cc[i] = c; q1.push nil; q.pop}}}
317
+ 5.times{q1.pop}
279
318
  threads.each {|t| t.should be_alive}
280
319
  @pool.available_connections.should be_empty
281
320
 
282
- 3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
321
+ 3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c; q1.push nil}}}
283
322
 
284
- sleep 0.02
285
323
  threads[5].should be_alive
286
324
  threads[6].should be_alive
287
325
  threads[7].should be_alive
@@ -290,8 +328,10 @@ shared_examples_for "A threaded connection pool" do
290
328
  cc[6].should be_nil
291
329
  cc[7].should be_nil
292
330
 
293
- stop = true
294
- sleep 0.1
331
+ 5.times{q.push nil}
332
+ 5.times{|i| threads[i].join}
333
+ 3.times{q1.pop}
334
+ 3.times{|i| threads[i+5].join}
295
335
 
296
336
  threads.each {|t| t.should_not be_alive}
297
337
 
@@ -300,12 +340,60 @@ shared_examples_for "A threaded connection pool" do
300
340
  @pool.available_connections.size.should == 5
301
341
  @pool.allocated.should be_empty
302
342
  end
343
+
344
+ specify "should store connections in a stack by default" do
345
+ c2 = nil
346
+ c = @pool.hold{|cc| Thread.new{@pool.hold{|cc2| c2 = cc2}}.join; cc}
347
+ @pool.size.should == 2
348
+ @pool.hold{|cc| cc.should == c}
349
+ @pool.hold{|cc| cc.should == c}
350
+ @pool.hold do |cc|
351
+ cc.should == c
352
+ Thread.new{@pool.hold{|cc2| cc2.should == c2}}
353
+ end
354
+ end
355
+
356
+ specify "should store connections in a queue if :connection_handling=>:queue" do
357
+ @pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:connection_handling=>:queue)){@invoked_count += 1}
358
+ c2 = nil
359
+ c = @pool.hold{|cc| Thread.new{@pool.hold{|cc2| c2 = cc2}}.join; cc}
360
+ @pool.size.should == 2
361
+ @pool.hold{|cc| cc.should == c2}
362
+ @pool.hold{|cc| cc.should == c}
363
+ @pool.hold do |cc|
364
+ cc.should == c2
365
+ Thread.new{@pool.hold{|cc2| cc2.should == c}}
366
+ end
367
+ end
368
+
369
+ specify "should not store connections if :connection_handling=>:disconnect" do
370
+ @pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:connection_handling=>:disconnect)){@invoked_count += 1}
371
+ d = []
372
+ @pool.disconnection_proc = proc{|c| d << c}
373
+ c = @pool.hold do |cc|
374
+ cc.should == 1
375
+ Thread.new{@pool.hold{|cc2| cc2.should == 2}}.join
376
+ d.should == [2]
377
+ @pool.hold{|cc3| cc3.should == 1}
378
+ end
379
+ @pool.size.should == 0
380
+ d.should == [2, 1]
381
+
382
+ @pool.hold{|cc| cc.should == 3}
383
+ @pool.size.should == 0
384
+ d.should == [2, 1, 3]
385
+
386
+ @pool.hold{|cc| cc.should == 4}
387
+ @pool.size.should == 0
388
+ d.should == [2, 1, 3, 4]
389
+ end
303
390
  end
304
391
 
305
392
  describe "Threaded Unsharded Connection Pool" do
306
393
  before do
307
394
  @invoked_count = 0
308
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
395
+ @cp_opts = CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)
396
+ @pool = Sequel::ConnectionPool.get_pool(@cp_opts) {@invoked_count += 1}
309
397
  end
310
398
 
311
399
  it_should_behave_like "A threaded connection pool"
@@ -314,7 +402,8 @@ end
314
402
  describe "Threaded Sharded Connection Pool" do
315
403
  before do
316
404
  @invoked_count = 0
317
- @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{})) {@invoked_count += 1}
405
+ @cp_opts = CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{})
406
+ @pool = Sequel::ConnectionPool.get_pool(@cp_opts) {@invoked_count += 1}
318
407
  end
319
408
 
320
409
  it_should_behave_like "A threaded connection pool"
@@ -324,19 +413,15 @@ describe "ConnectionPool#disconnect" do
324
413
  before do
325
414
  @count = 0
326
415
  @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5, :servers=>{})) {{:id => @count += 1}}
416
+ threads = []
417
+ q, q1 = Queue.new, Queue.new
418
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| q1.push nil; q.pop}}}
419
+ 5.times{q1.pop}
420
+ 5.times{q.push nil}
421
+ threads.each {|t| t.join}
327
422
  end
328
423
 
329
424
  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
425
  @pool.size.should == 5
341
426
  @pool.available_connections.size.should == 5
342
427
  @pool.available_connections.each {|c| c[:id].should_not be_nil}
@@ -346,34 +431,13 @@ describe "ConnectionPool#disconnect" do
346
431
  end
347
432
 
348
433
  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
434
  @pool.size.should == 5
360
435
  @pool.disconnect
361
436
  @pool.size.should == 0
362
437
  end
363
438
 
364
439
  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
440
  @pool.size.should == 5
376
-
377
441
  @pool.hold do |conn|
378
442
  @pool.available_connections.size.should == 4
379
443
  @pool.available_connections.each {|c| c.should_not be(conn)}
@@ -392,6 +456,16 @@ describe "A connection pool with multiple servers" do
392
456
  @pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:servers=>{:read_only=>{}})){|server| "#{server}#{@invoked_counts[server] += 1}"}
393
457
  end
394
458
 
459
+ specify "#all_connections should return connections for all servers" do
460
+ @pool.hold{}
461
+ @pool.all_connections{|c1| c1.should == "default1"}
462
+ a = []
463
+ @pool.hold(:read_only) do |c|
464
+ @pool.all_connections{|c1| a << c1}
465
+ end
466
+ a.sort_by{|c| c.to_s}.should == ["default1", "read_only1"]
467
+ end
468
+
395
469
  specify "#servers should return symbols for all servers" do
396
470
  @pool.servers.sort_by{|s| s.to_s}.should == [:default, :read_only]
397
471
  end
@@ -556,9 +630,10 @@ describe "A connection pool with multiple servers" do
556
630
  specify "#remove_servers should disconnect available connections immediately" do
557
631
  pool = Sequel::ConnectionPool.get_pool(:max_connections=>5, :servers=>{:server1=>{}}){|s| s}
558
632
  threads = []
559
- stop = nil
560
- 5.times {|i| threads << Thread.new{pool.hold(:server1){|c| sleep 0.05}}}
561
- sleep 0.1
633
+ q, q1 = Queue.new, Queue.new
634
+ 5.times {|i| threads << Thread.new {pool.hold(:server1){|c| q1.push nil; q.pop}}}
635
+ 5.times{q1.pop}
636
+ 5.times{q.push nil}
562
637
  threads.each {|t| t.join}
563
638
 
564
639
  pool.size(:server1).should == 5
@@ -645,6 +720,16 @@ describe "A single threaded pool with multiple servers" do
645
720
  @pool = Sequel::ConnectionPool.get_pool(ST_CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| @max_size=3}, :servers=>{:read_only=>{}})){|server| server}
646
721
  end
647
722
 
723
+ specify "#all_connections should return connections for all servers" do
724
+ @pool.hold{}
725
+ @pool.all_connections{|c1| c1.should == :default}
726
+ a = []
727
+ @pool.hold(:read_only) do
728
+ @pool.all_connections{|c1| a << c1}
729
+ end
730
+ a.sort_by{|c| c.to_s}.should == [:default, :read_only]
731
+ end
732
+
648
733
  specify "#servers should return symbols for all servers" do
649
734
  @pool.servers.sort_by{|s| s.to_s}.should == [:default, :read_only]
650
735
  end
@@ -751,6 +836,32 @@ describe "A single threaded pool with multiple servers" do
751
836
  end
752
837
 
753
838
  shared_examples_for "All connection pools classes" do
839
+ specify "should have all_connections yield current and available connections" do
840
+ p = @class.new({}){123}
841
+ p.hold{|c| p.all_connections{|c1| c.should == c1}}
842
+ end
843
+
844
+ specify "should be able to modify after_connect proc after the pool is created" do
845
+ a = []
846
+ p = @class.new({}){123}
847
+ p.after_connect = pr = proc{|c| a << c}
848
+ p.after_connect.should == pr
849
+ a.should == []
850
+ p.hold{}
851
+ a.should == [123]
852
+ end
853
+
854
+ specify "should be able to modify disconnection_proc after the pool is created" do
855
+ a = []
856
+ p = @class.new({}){123}
857
+ p.disconnection_proc = pr = proc{|c| a << c}
858
+ p.disconnection_proc.should == pr
859
+ p.hold{}
860
+ a.should == []
861
+ p.disconnect
862
+ a.should == [123]
863
+ end
864
+
754
865
  specify "should not raise an error when disconnecting twice" do
755
866
  c = @class.new({}){123}
756
867
  proc{c.disconnect}.should_not raise_error
@@ -808,6 +919,20 @@ shared_examples_for "All connection pools classes" do
808
919
  y.should == 123
809
920
  end
810
921
 
922
+ specify "should have a reentrent hold method" do
923
+ o = Object.new
924
+ c = @class.new({}){o}
925
+ c.hold do |x|
926
+ x.should == o
927
+ c.hold do |x1|
928
+ x1.should == o
929
+ c.hold do |x2|
930
+ x2.should == o
931
+ end
932
+ end
933
+ end
934
+ end
935
+
811
936
  specify "should have a servers method that returns an array of shard/server symbols" do
812
937
  @class.new({}){123}.servers.should == [:default]
813
938
  end