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,18 +1,15 @@
1
1
  # A ShardedSingleConnectionPool is a single threaded connection pool that
2
2
  # works with multiple shards/servers.
3
3
  class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
4
- # Initializes the instance with the supplied block as the connection_proc.
5
- #
6
4
  # The single threaded pool takes the following options:
7
5
  #
8
6
  # * :servers - A hash of servers to use. Keys should be symbols. If not
9
- # present, will use a single :default server. The server name symbol will
10
- # be passed to the connection_proc.
7
+ # present, will use a single :default server.
11
8
  # * :servers_hash - The base hash to use for the servers. By default,
12
9
  # Sequel uses Hash.new(:default). You can use a hash with a default proc
13
10
  # that raises an error if you want to catch all cases where a nonexistent
14
11
  # server is used.
15
- def initialize(opts={}, &block)
12
+ def initialize(db, opts={})
16
13
  super
17
14
  @conns = {}
18
15
  @servers = opts.fetch(:servers_hash, Hash.new(:default))
@@ -26,6 +23,11 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
26
23
  def add_servers(servers)
27
24
  servers.each{|s| @servers[s] = s}
28
25
  end
26
+
27
+ # Yield all of the currently established connections
28
+ def all_connections
29
+ @conns.values.each{|c| yield c}
30
+ end
29
31
 
30
32
  # The connection for the given server.
31
33
  def conn(server=:default)
@@ -36,19 +38,18 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
36
38
  # #hold, the connection is reestablished. Options:
37
39
  # * :server - Should be a symbol specifing the server to disconnect from,
38
40
  # or an array of symbols to specify multiple servers.
39
- def disconnect(opts={}, &block)
40
- block ||= @disconnection_proc
41
- (opts[:server] ? Array(opts[:server]) : servers).each{|s| disconnect_server(s, &block)}
41
+ def disconnect(opts={})
42
+ (opts[:server] ? Array(opts[:server]) : servers).each{|s| disconnect_server(s)}
42
43
  end
43
44
 
44
45
  # Yields the connection to the supplied block for the given server.
45
46
  # This method simulates the ConnectionPool#hold API.
46
47
  def hold(server=:default)
47
48
  begin
48
- server = @servers[server]
49
+ server = pick_server(server)
49
50
  yield(@conns[server] ||= make_new(server))
50
51
  rescue Sequel::DatabaseDisconnectError
51
- disconnect_server(server, &@disconnection_proc)
52
+ disconnect_server(server)
52
53
  raise
53
54
  end
54
55
  end
@@ -60,7 +61,7 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
60
61
  def remove_servers(servers)
61
62
  raise(Sequel::Error, "cannot remove default server") if servers.include?(:default)
62
63
  servers.each do |server|
63
- disconnect_server(server, &@disconnection_proc)
64
+ disconnect_server(server)
64
65
  @servers.delete(server)
65
66
  end
66
67
  end
@@ -75,14 +76,23 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
75
76
  @conns.length
76
77
  end
77
78
 
79
+ def pool_type
80
+ :sharded_single
81
+ end
82
+
78
83
  private
79
84
 
80
85
  # Disconnect from the given server, if connected.
81
- def disconnect_server(server, &block)
86
+ def disconnect_server(server)
82
87
  if conn = @conns.delete(server)
83
- block.call(conn) if block
88
+ db.disconnect_connection(conn)
84
89
  end
85
90
  end
91
+
92
+ # If the server given is in the hash, return it, otherwise, return the default server.
93
+ def pick_server(server)
94
+ @servers[server]
95
+ end
86
96
 
87
97
  CONNECTION_POOL_MAP[[true, true]] = self
88
98
  end
@@ -8,13 +8,12 @@ Sequel.require 'connection_pool/threaded'
8
8
  class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
9
9
  # The following additional options are respected:
10
10
  # * :servers - A hash of servers to use. Keys should be symbols. If not
11
- # present, will use a single :default server. The server name symbol will
12
- # be passed to the connection_proc.
11
+ # present, will use a single :default server.
13
12
  # * :servers_hash - The base hash to use for the servers. By default,
14
13
  # Sequel uses Hash.new(:default). You can use a hash with a default proc
15
14
  # that raises an error if you want to catch all cases where a nonexistent
16
15
  # server is used.
17
- def initialize(opts = {}, &block)
16
+ def initialize(db, opts = {})
18
17
  super
19
18
  @available_connections = {}
20
19
  @connections_to_remove = []
@@ -45,6 +44,23 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
45
44
  @allocated[server]
46
45
  end
47
46
 
47
+ # Yield all of the available connections, and the ones currently allocated to
48
+ # this thread. This will not yield connections currently allocated to other
49
+ # threads, as it is not safe to operate on them. This holds the mutex while
50
+ # it is yielding all of the connections, which means that until
51
+ # the method's block returns, the pool is locked.
52
+ def all_connections
53
+ t = Thread.current
54
+ sync do
55
+ @allocated.values.each do |threads|
56
+ threads.each do |thread, conn|
57
+ yield conn if t == thread
58
+ end
59
+ end
60
+ @available_connections.values.each{|v| v.each{|c| yield c}}
61
+ end
62
+ end
63
+
48
64
  # An array of connections opened but not currently used, for the given
49
65
  # server. Nonexistent servers will return nil. Treat this as read only, do
50
66
  # not modify the resulting object.
@@ -70,11 +86,10 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
70
86
  # creates new connections to the database. Options:
71
87
  # * :server - Should be a symbol specifing the server to disconnect from,
72
88
  # or an array of symbols to specify multiple servers.
73
- def disconnect(opts={}, &block)
74
- block ||= @disconnection_proc
89
+ def disconnect(opts={})
75
90
  sync do
76
91
  (opts[:server] ? Array(opts[:server]) : @servers.keys).each do |s|
77
- disconnect_server(s, &block)
92
+ disconnect_server(s)
78
93
  end
79
94
  end
80
95
  end
@@ -94,7 +109,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
94
109
  # connection can be acquired, a Sequel::PoolTimeout is
95
110
  # raised.
96
111
  def hold(server=:default)
97
- sync{server = @servers[server]}
112
+ server = pick_server(server)
98
113
  t = Thread.current
99
114
  if conn = owned_connection(t, server)
100
115
  return yield(conn)
@@ -128,7 +143,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
128
143
  raise(Sequel::Error, "cannot remove default server") if servers.include?(:default)
129
144
  servers.each do |server|
130
145
  if @servers.include?(server)
131
- disconnect_server(server, &@disconnection_proc)
146
+ disconnect_server(server)
132
147
  @available_connections.delete(server)
133
148
  @allocated.delete(server)
134
149
  @servers.delete(server)
@@ -142,6 +157,10 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
142
157
  sync{@servers.keys}
143
158
  end
144
159
 
160
+ def pool_type
161
+ :sharded_threaded
162
+ end
163
+
145
164
  private
146
165
 
147
166
  # Assigns a connection to the supplied thread for the given server, if one
@@ -159,16 +178,30 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
159
178
  # available, tries to create a new connection. The calling code should already
160
179
  # have the mutex before calling this.
161
180
  def available(server)
162
- available_connections(server).pop || make_new(server)
181
+ next_available(server) || make_new(server)
182
+ end
183
+
184
+ # Return a connection to the pool of available connections for the server,
185
+ # returns the connection. The calling code should already have the mutex
186
+ # before calling this.
187
+ def checkin_connection(server, conn)
188
+ case @connection_handling
189
+ when :queue
190
+ available_connections(server).unshift(conn)
191
+ else
192
+ available_connections(server) << conn
193
+ end
194
+
195
+ conn
163
196
  end
164
197
 
165
198
  # Disconnect from the given server. Disconnects available connections
166
199
  # immediately, and schedules currently allocated connections for disconnection
167
200
  # as soon as they are returned to the pool. The calling code should already
168
201
  # have the mutex before calling this.
169
- def disconnect_server(server, &block)
202
+ def disconnect_server(server)
170
203
  if conns = available_connections(server)
171
- conns.each{|conn| block.call(conn)} if block
204
+ conns.each{|conn| db.disconnect_connection(conn)}
172
205
  conns.clear
173
206
  end
174
207
  @connections_to_remove.concat(allocated(server).values)
@@ -184,12 +217,24 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
184
217
  end
185
218
  default_make_new(server) if (n || size(server)) < @max_size
186
219
  end
220
+
221
+ # Return the next available connection in the pool for the given server, or nil
222
+ # if there is not currently an available connection for the server.
223
+ # The calling code should already have the mutex before calling this.
224
+ def next_available(server)
225
+ available_connections(server).pop
226
+ end
187
227
 
188
228
  # Returns the connection owned by the supplied thread for the given server,
189
229
  # if any. The calling code should NOT already have the mutex before calling this.
190
230
  def owned_connection(thread, server)
191
231
  sync{@allocated[server][thread]}
192
232
  end
233
+
234
+ # If the server given is in the hash, return it, otherwise, return the default server.
235
+ def pick_server(server)
236
+ sync{@servers[server]}
237
+ end
193
238
 
194
239
  # Releases the connection assigned to the supplied thread and server. If the
195
240
  # server or connection given is scheduled for disconnection, remove the
@@ -199,7 +244,13 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
199
244
  if @connections_to_remove.include?(conn)
200
245
  remove(thread, conn, server)
201
246
  else
202
- available_connections(server) << allocated(server).delete(thread)
247
+ conn = allocated(server).delete(thread)
248
+
249
+ if @connection_handling == :disconnect
250
+ db.disconnect_connection(conn)
251
+ else
252
+ checkin_connection(server, conn)
253
+ end
203
254
  end
204
255
  end
205
256
 
@@ -208,7 +259,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
208
259
  def remove(thread, conn, server)
209
260
  @connections_to_remove.delete(conn)
210
261
  allocated(server).delete(thread) if @servers.include?(server)
211
- @disconnection_proc.call(conn) if @disconnection_proc
262
+ db.disconnect_connection(conn)
212
263
  end
213
264
 
214
265
  CONNECTION_POOL_MAP[[false, true]] = self
@@ -8,11 +8,15 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
8
8
  @conn ? 1 : 0
9
9
  end
10
10
 
11
+ # Yield the connection if one has been made.
12
+ def all_connections
13
+ yield @conn if @conn
14
+ end
15
+
11
16
  # Disconnect the connection from the database.
12
- def disconnect(opts=nil, &block)
17
+ def disconnect(opts=nil)
13
18
  return unless @conn
14
- block ||= @disconnection_proc
15
- block.call(@conn) if block
19
+ db.disconnect_connection(@conn)
16
20
  @conn = nil
17
21
  end
18
22
 
@@ -26,5 +30,9 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
26
30
  end
27
31
  end
28
32
 
33
+ def pool_type
34
+ :single
35
+ end
36
+
29
37
  CONNECTION_POOL_MAP[[true, false]] = self
30
38
  end
@@ -13,45 +13,65 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
13
13
  attr_reader :allocated
14
14
 
15
15
  # The following additional options are respected:
16
+ # * :connection_handling - Set how to handle available connections. By default,
17
+ # uses a a stack for performance. Can be set to :queue to use a queue, which reduces
18
+ # the chances of connections becoming stale.
16
19
  # * :max_connections - The maximum number of connections the connection pool
17
20
  # will open (default 4)
18
21
  # * :pool_sleep_time - The amount of time to sleep before attempting to acquire
19
22
  # a connection again (default 0.001)
20
23
  # * :pool_timeout - The amount of seconds to wait to acquire a connection
21
24
  # before raising a PoolTimeoutError (default 5)
22
- def initialize(opts = {}, &block)
25
+ def initialize(db, opts = {})
23
26
  super
24
27
  @max_size = Integer(opts[:max_connections] || 4)
25
28
  raise(Sequel::Error, ':max_connections must be positive') if @max_size < 1
26
29
  @mutex = Mutex.new
30
+ @connection_handling = opts[:connection_handling]
27
31
  @available_connections = []
28
32
  @allocated = {}
29
33
  @timeout = Integer(opts[:pool_timeout] || 5)
30
34
  @sleep_time = Float(opts[:pool_sleep_time] || 0.001)
31
35
  end
32
36
 
33
- # The total number of connections opened for the given server, should
34
- # be equal to available_connections.length + allocated.length.
37
+ # The total number of connections opened, either available or allocated.
38
+ # This may not be completely accurate as it isn't protected by the mutex.
35
39
  def size
36
40
  @allocated.length + @available_connections.length
37
41
  end
38
42
 
39
- # Removes all connections currently available on all servers, optionally
43
+ # Yield all of the available connections, and the one currently allocated to
44
+ # this thread. This will not yield connections currently allocated to other
45
+ # threads, as it is not safe to operate on them. This holds the mutex while
46
+ # it is yielding all of the available connections, which means that until
47
+ # the method's block returns, the pool is locked.
48
+ def all_connections
49
+ hold do |c|
50
+ sync do
51
+ yield c
52
+ @available_connections.each{|c| yield c}
53
+ end
54
+ end
55
+ end
56
+
57
+ # Removes all connections currently available, optionally
40
58
  # yielding each connection to the given block. This method has the effect of
41
59
  # disconnecting from the database, assuming that no connections are currently
42
- # being used.
60
+ # being used. If you want to be able to disconnect connections that are
61
+ # currently in use, use the ShardedThreadedConnectionPool, which can do that.
62
+ # This connection pool does not, for performance reasons. To use the sharded pool,
63
+ # pass the <tt>:servers=>{}</tt> option when connecting to the database.
43
64
  #
44
65
  # Once a connection is requested using #hold, the connection pool
45
66
  # creates new connections to the database.
46
- def disconnect(opts={}, &block)
47
- block ||= @disconnection_proc
67
+ def disconnect(opts={})
48
68
  sync do
49
- @available_connections.each{|conn| block.call(conn)} if block
69
+ @available_connections.each{|conn| db.disconnect_connection(conn)}
50
70
  @available_connections.clear
51
71
  end
52
72
  end
53
73
 
54
- # Chooses the first available connection to the given server, or if none are
74
+ # Chooses the first available connection, or if none are
55
75
  # available, creates a new connection. Passes the connection to the supplied
56
76
  # block:
57
77
  #
@@ -83,18 +103,23 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
83
103
  end
84
104
  yield conn
85
105
  rescue Sequel::DatabaseDisconnectError
86
- @disconnection_proc.call(conn) if @disconnection_proc && conn
87
- @allocated.delete(t)
106
+ oconn = conn
88
107
  conn = nil
108
+ db.disconnect_connection(oconn) if oconn
109
+ @allocated.delete(t)
89
110
  raise
90
111
  ensure
91
112
  sync{release(t)} if conn
92
113
  end
93
114
  end
115
+
116
+ def pool_type
117
+ :threaded
118
+ end
94
119
 
95
120
  private
96
121
 
97
- # Assigns a connection to the supplied thread for the given server, if one
122
+ # Assigns a connection to the supplied thread, if one
98
123
  # is available. The calling code should NOT already have the mutex when
99
124
  # calling this.
100
125
  def acquire(thread)
@@ -105,11 +130,24 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
105
130
  end
106
131
  end
107
132
 
108
- # Returns an available connection to the given server. If no connection is
133
+ # Returns an available connection. If no connection is
109
134
  # available, tries to create a new connection. The calling code should already
110
135
  # have the mutex before calling this.
111
136
  def available
112
- @available_connections.pop || make_new(DEFAULT_SERVER)
137
+ next_available || make_new(DEFAULT_SERVER)
138
+ end
139
+
140
+ # Return a connection to the pool of available connections, returns the connection.
141
+ # The calling code should already have the mutex before calling this.
142
+ def checkin_connection(conn)
143
+ case @connection_handling
144
+ when :queue
145
+ @available_connections.unshift(conn)
146
+ else
147
+ @available_connections << conn
148
+ end
149
+
150
+ conn
113
151
  end
114
152
 
115
153
  # Alias the default make_new method, so subclasses can call it directly.
@@ -125,19 +163,30 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
125
163
  end
126
164
  super if (n || size) < @max_size
127
165
  end
128
-
129
- # Returns the connection owned by the supplied thread for the given server,
166
+
167
+ # Return the next available connection in the pool, or nil if there
168
+ # is not currently an available connection. The calling code should already
169
+ # have the mutex before calling this.
170
+ def next_available
171
+ @available_connections.pop
172
+ end
173
+
174
+ # Returns the connection owned by the supplied thread,
130
175
  # if any. The calling code should NOT already have the mutex before calling this.
131
176
  def owned_connection(thread)
132
177
  sync{@allocated[thread]}
133
178
  end
134
179
 
135
- # Releases the connection assigned to the supplied thread and server. If the
136
- # server or connection given is scheduled for disconnection, remove the
137
- # connection instead of releasing it back to the pool.
180
+ # Releases the connection assigned to the supplied thread back to the pool.
138
181
  # The calling code should already have the mutex before calling this.
139
182
  def release(thread)
140
- @available_connections << @allocated.delete(thread)
183
+ conn = @allocated.delete(thread)
184
+
185
+ if @connection_handling == :disconnect
186
+ db.disconnect_connection(conn)
187
+ else
188
+ checkin_connection(conn)
189
+ end
141
190
  end
142
191
 
143
192
  # Yield to the block while inside the mutex. The calling code should NOT
@@ -2,15 +2,13 @@
2
2
  # on. This class is not instantiated directly, but subclasses should at
3
3
  # the very least implement the following API:
4
4
  #
5
- # initialize(Hash, &block) :: The +block+ is used as the connection proc,
6
- # which should accept a single symbol argument.
5
+ # initialize(Database, Hash) :: Initialize using the passed Sequel::Database
6
+ # object and options hash.
7
7
  # hold(Symbol, &block) :: Yield a connection object (obtained from calling
8
8
  # the block passed to +initialize+) to the current block. For sharded
9
9
  # connection pools, the Symbol passed is the shard/server to use.
10
- # disconnect(Symbol, &block) :: Disconnect the connection object. If a
11
- # block is given, pass the connection option to it, otherwise use the
12
- # <tt>:disconnection_proc</tt> option in the hash passed to initialize. For sharded
13
- # connection pools, the Symbol passed is the shard/server to use.
10
+ # disconnect(Symbol) :: Disconnect the connection object. For sharded
11
+ # connection pools, the Symbol passed is the shard/server to use.
14
12
  # servers :: An array of shard/server symbols for all shards/servers that this
15
13
  # connection pool recognizes.
16
14
  # size :: an integer representing the total number of connections in the pool,
@@ -39,13 +37,13 @@ class Sequel::ConnectionPool
39
37
  # option is provided is provided, use that pool class, otherwise
40
38
  # use a new instance of an appropriate pool subclass based on the
41
39
  # <tt>:single_threaded</tt> and <tt>:servers</tt> options.
42
- def get_pool(opts = {}, &block)
40
+ def get_pool(db, opts = {})
43
41
  case v = connection_pool_class(opts)
44
42
  when Class
45
- v.new(opts, &block)
43
+ v.new(db, opts)
46
44
  when Symbol
47
45
  Sequel.ts_require("connection_pool/#{v}")
48
- connection_pool_class(opts).new(opts, &block) || raise(Sequel::Error, "No connection pool class found")
46
+ connection_pool_class(opts).new(db, opts) || raise(Sequel::Error, "No connection pool class found")
49
47
  end
50
48
  end
51
49
 
@@ -53,11 +51,18 @@ class Sequel::ConnectionPool
53
51
 
54
52
  # Return a connection pool class based on the given options.
55
53
  def connection_pool_class(opts)
56
- opts[:pool_class] || CONNECTION_POOL_MAP[[!!opts[:single_threaded], !!opts[:servers]]]
54
+ CONNECTION_POOL_MAP[opts[:pool_class]] || opts[:pool_class] || CONNECTION_POOL_MAP[[!!opts[:single_threaded], !!opts[:servers]]]
57
55
  end
58
56
  end
59
57
  extend ClassMethods
60
-
58
+
59
+ # The after_connect proc used for this pool. This is called with each new
60
+ # connection made, and is usually used to set custom per-connection settings.
61
+ attr_accessor :after_connect
62
+
63
+ # The Sequel::Database object tied to this connection pool.
64
+ attr_accessor :db
65
+
61
66
  # Instantiates a connection pool with the given options. The block is called
62
67
  # with a single symbol (specifying the server/shard to use) every time a new
63
68
  # connection is needed. The following options are respected for all connection
@@ -65,11 +70,8 @@ class Sequel::ConnectionPool
65
70
  # :after_connect :: The proc called after each new connection is made, with the
66
71
  # connection object, useful for customizations that you want to apply to all
67
72
  # connections.
68
- # :disconnection_proc :: The proc called when removing connections from the pool,
69
- # which is passed the connection to disconnect.
70
- def initialize(opts={}, &block)
71
- raise(Sequel::Error, "No connection proc specified") unless @connection_proc = block
72
- @disconnection_proc = opts[:disconnection_proc]
73
+ def initialize(db, opts={})
74
+ @db = db
73
75
  @after_connect = opts[:after_connect]
74
76
  end
75
77
 
@@ -80,7 +82,7 @@ class Sequel::ConnectionPool
80
82
 
81
83
  # An array of symbols for all shards/servers, which is a single <tt>:default</tt> by default.
82
84
  def servers
83
- [:default]
85
+ [DEFAULT_SERVER]
84
86
  end
85
87
 
86
88
  private
@@ -89,7 +91,7 @@ class Sequel::ConnectionPool
89
91
  # and checking for connection errors.
90
92
  def make_new(server)
91
93
  begin
92
- conn = @connection_proc.call(server)
94
+ conn = @db.connect(server)
93
95
  @after_connect.call(conn) if @after_connect
94
96
  rescue Exception=>exception
95
97
  raise Sequel.convert_exception_class(exception, Sequel::DatabaseConnectionError)