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
@@ -0,0 +1,334 @@
1
+ Sequel.require 'adapters/shared/access'
2
+ Sequel.require 'adapters/utils/split_alter_table'
3
+
4
+ module Sequel
5
+ module ADO
6
+ # Database and Dataset instance methods for Access specific
7
+ # support via ADO.
8
+ module Access
9
+ class AdoSchema
10
+ QUERY_TYPE = {
11
+ :columns => 4,
12
+ :indexes => 12,
13
+ :tables => 20,
14
+ :views => 23,
15
+ :foreign_keys => 27
16
+ }
17
+
18
+ attr_reader :type, :criteria
19
+
20
+ def initialize(type, crit)
21
+ @type = QUERY_TYPE[type]
22
+ @criteria = Array(crit)
23
+ end
24
+
25
+ class Column
26
+ DATA_TYPE = {
27
+ 2 => "SMALLINT",
28
+ 3 => "INTEGER",
29
+ 4 => "REAL",
30
+ 5 => "DOUBLE",
31
+ 6 => "MONEY",
32
+ 7 => "DATETIME",
33
+ 11 => "BIT",
34
+ 14 => "DECIMAL",
35
+ 16 => "TINYINT",
36
+ 17 => "BYTE",
37
+ 72 => "GUID",
38
+ 128 => "BINARY",
39
+ 130 => "TEXT",
40
+ 131 => "DECIMAL",
41
+ 201 => "TEXT",
42
+ 205 => "IMAGE"
43
+ }
44
+
45
+ def initialize(row)
46
+ @row = row
47
+ end
48
+
49
+ def [](col)
50
+ @row[col]
51
+ end
52
+
53
+ def allow_null
54
+ self["IS_NULLABLE"]
55
+ end
56
+
57
+ def default
58
+ self["COLUMN_DEFAULT"]
59
+ end
60
+
61
+ def db_type
62
+ t = DATA_TYPE[self["DATA_TYPE"]]
63
+ if t == "DECIMAL" && precision
64
+ t + "(#{precision.to_i},#{(scale || 0).to_i})"
65
+ elsif t == "TEXT" && maximum_length && maximum_length > 0
66
+ t + "(#{maximum_length.to_i})"
67
+ else
68
+ t
69
+ end
70
+ end
71
+
72
+ def precision
73
+ self["NUMERIC_PRECISION"]
74
+ end
75
+
76
+ def scale
77
+ self["NUMERIC_SCALE"]
78
+ end
79
+
80
+ def maximum_length
81
+ self["CHARACTER_MAXIMUM_LENGTH"]
82
+ end
83
+ end
84
+ end
85
+
86
+ module DatabaseMethods
87
+ include Sequel::Access::DatabaseMethods
88
+ include Sequel::Database::SplitAlterTable
89
+
90
+ DECIMAL_TYPE_RE = /decimal/io
91
+ LAST_INSERT_ID = "SELECT @@IDENTITY".freeze
92
+
93
+ # Remove cached schema after altering a table, since otherwise it can be cached
94
+ # incorrectly in the rename column case.
95
+ def alter_table(name, *)
96
+ super
97
+ remove_cached_schema(name)
98
+ nil
99
+ end
100
+
101
+ # Access doesn't let you disconnect if inside a transaction, so
102
+ # try rolling back an existing transaction first.
103
+ def disconnect_connection(conn)
104
+ conn.RollbackTrans rescue nil
105
+ super
106
+ end
107
+
108
+ def execute_insert(sql, opts={})
109
+ synchronize(opts[:server]) do |conn|
110
+ begin
111
+ r = log_yield(sql){conn.Execute(sql)}
112
+ res = log_yield(LAST_INSERT_ID){conn.Execute(LAST_INSERT_ID)}
113
+ res.getRows.transpose.each{|r| return r.shift}
114
+ rescue ::WIN32OLERuntimeError => e
115
+ raise_error(e)
116
+ end
117
+ end
118
+ nil
119
+ end
120
+
121
+ def tables(opts={})
122
+ m = output_identifier_meth
123
+ ado_schema_tables.map {|tbl| m.call(tbl['TABLE_NAME'])}
124
+ end
125
+
126
+ def views(opts={})
127
+ m = output_identifier_meth
128
+ ado_schema_views.map {|tbl| m.call(tbl['TABLE_NAME'])}
129
+ end
130
+
131
+ # Note OpenSchema returns compound indexes as multiple rows
132
+ def indexes(table_name,opts={})
133
+ m = output_identifier_meth
134
+ idxs = ado_schema_indexes(table_name).inject({}) do |memo, idx|
135
+ unless idx["PRIMARY_KEY"]
136
+ index = memo[m.call(idx["INDEX_NAME"])] ||= {
137
+ :columns=>[], :unique=>idx["UNIQUE"]
138
+ }
139
+ index[:columns] << m.call(idx["COLUMN_NAME"])
140
+ end
141
+ memo
142
+ end
143
+ idxs
144
+ end
145
+
146
+ # Note OpenSchema returns compound foreign key relationships as multiple rows
147
+ def foreign_key_list(table, opts={})
148
+ m = output_identifier_meth
149
+ fks = ado_schema_foreign_keys(table).inject({}) do |memo, fk|
150
+ name = m.call(fk['FK_NAME'])
151
+ specs = memo[name] ||= {
152
+ :columns => [],
153
+ :table => m.call(fk['PK_TABLE_NAME']),
154
+ :key => [],
155
+ :deferrable => fk['DEFERRABILITY'],
156
+ :name => name,
157
+ :on_delete => fk['DELETE_RULE'],
158
+ :on_update => fk['UPDATE_RULE']
159
+ }
160
+ specs[:columns] << m.call(fk['FK_COLUMN_NAME'])
161
+ specs[:key] << m.call(fk['PK_COLUMN_NAME'])
162
+ memo
163
+ end
164
+ fks.values
165
+ end
166
+
167
+ private
168
+
169
+ # Emulate rename_column by adding the column, copying data from the old
170
+ # column, and dropping the old column.
171
+ def alter_table_sql(table, op)
172
+ case op[:op]
173
+ when :rename_column
174
+ unless sch = op[:schema]
175
+ raise(Error, "can't find existing schema entry for #{op[:name]}") unless sch = op[:schema] || schema(table).find{|c| c.first == op[:name]}
176
+ sch = sch.last
177
+ end
178
+ [
179
+ alter_table_sql(table, :op=>:add_column, :name=>op[:new_name], :default=>sch[:ruby_default], :type=>sch[:db_type], :null=>sch[:allow_null]),
180
+ from(table).update_sql(op[:new_name]=>op[:name]),
181
+ alter_table_sql(table, :op=>:drop_column, :name=>op[:name])
182
+ ]
183
+ when :set_column_null, :set_column_default
184
+ raise(Error, "can't find existing schema entry for #{op[:name]}") unless sch = op[:schema] || schema(table).find{|c| c.first == op[:name]}
185
+ sch = sch.last
186
+
187
+ sch = if op[:op] == :set_column_null
188
+ sch.merge(:allow_null=>op[:null])
189
+ else
190
+ sch.merge(:ruby_default=>op[:default])
191
+ end
192
+
193
+ [
194
+ alter_table_sql(table, :op=>:rename_column, :name=>op[:name], :new_name=>:sequel_access_backup_column, :schema=>sch),
195
+ alter_table_sql(table, :op=>:rename_column, :new_name=>op[:name], :name=>:sequel_access_backup_column, :schema=>sch)
196
+ ]
197
+ else
198
+ super
199
+ end
200
+ end
201
+
202
+ def begin_transaction(conn, opts={})
203
+ log_yield('Transaction.begin'){conn.BeginTrans}
204
+ end
205
+
206
+ def commit_transaction(conn, opts={})
207
+ log_yield('Transaction.commit'){conn.CommitTrans}
208
+ end
209
+
210
+ def rollback_transaction(conn, opts={})
211
+ log_yield('Transaction.rollback'){conn.RollbackTrans}
212
+ end
213
+
214
+ def schema_column_type(db_type)
215
+ case db_type.downcase
216
+ when 'bit'
217
+ :boolean
218
+ when 'byte', 'guid'
219
+ :integer
220
+ when 'image'
221
+ :blob
222
+ else
223
+ super
224
+ end
225
+ end
226
+
227
+ def schema_parse_table(table_name, opts)
228
+ m = output_identifier_meth(opts[:dataset])
229
+ m2 = input_identifier_meth(opts[:dataset])
230
+ tn = m2.call(table_name.to_s)
231
+ idxs = ado_schema_indexes(tn)
232
+ ado_schema_columns(tn).map {|row|
233
+ specs = {
234
+ :allow_null => row.allow_null,
235
+ :db_type => row.db_type,
236
+ :default => row.default,
237
+ :primary_key => !!idxs.find {|idx|
238
+ idx["COLUMN_NAME"] == row["COLUMN_NAME"] &&
239
+ idx["PRIMARY_KEY"]
240
+ },
241
+ :type => if row.db_type =~ DECIMAL_TYPE_RE && row.scale == 0
242
+ :integer
243
+ else
244
+ schema_column_type(row.db_type)
245
+ end,
246
+ :ado_type => row["DATA_TYPE"]
247
+ }
248
+ specs[:default] = nil if blank_object?(specs[:default])
249
+ specs[:allow_null] = specs[:allow_null] && !specs[:primary_key]
250
+ [ m.call(row["COLUMN_NAME"]), specs ]
251
+ }
252
+ end
253
+
254
+ def ado_schema_tables
255
+ rows=[]
256
+ fetch_ado_schema(:tables, [nil,nil,nil,'TABLE']) do |row|
257
+ rows << row
258
+ end
259
+ rows
260
+ end
261
+
262
+ def ado_schema_views
263
+ rows=[]
264
+ fetch_ado_schema(:views, [nil,nil,nil]) do |row|
265
+ rows << row
266
+ end
267
+ rows
268
+ end
269
+
270
+ def ado_schema_indexes(table_name)
271
+ rows=[]
272
+ fetch_ado_schema(:indexes, [nil,nil,nil,nil,table_name.to_s]) do |row|
273
+ rows << row
274
+ end
275
+ rows
276
+ end
277
+
278
+ def ado_schema_columns(table_name)
279
+ rows=[]
280
+ fetch_ado_schema(:columns, [nil,nil,table_name.to_s,nil]) do |row|
281
+ rows << AdoSchema::Column.new(row)
282
+ end
283
+ rows.sort!{|a,b| a["ORDINAL_POSITION"] <=> b["ORDINAL_POSITION"]}
284
+ end
285
+
286
+ def ado_schema_foreign_keys(table_name)
287
+ rows=[]
288
+ fetch_ado_schema(:foreign_keys, [nil,nil,nil,nil,nil,table_name.to_s]) do |row|
289
+ rows << row
290
+ end
291
+ rows.sort!{|a,b| a["ORDINAL"] <=> b["ORDINAL"]}
292
+ end
293
+
294
+ def fetch_ado_schema(type, criteria=[])
295
+ execute_open_ado_schema(type, criteria) do |s|
296
+ cols = s.Fields.extend(Enumerable).map {|c| c.Name}
297
+ s.getRows.transpose.each do |r|
298
+ row = {}
299
+ cols.each{|c| row[c] = r.shift}
300
+ yield row
301
+ end unless s.eof
302
+ end
303
+ end
304
+
305
+ # This is like execute() in that it yields an ADO RecordSet, except
306
+ # instead of an SQL interface there's this OpenSchema call
307
+ # cf. http://msdn.microsoft.com/en-us/library/ee275721(v=bts.10)
308
+ #
309
+ def execute_open_ado_schema(type, criteria=[])
310
+ ado_schema = AdoSchema.new(type, criteria)
311
+ synchronize(opts[:server]) do |conn|
312
+ begin
313
+ r = log_yield("OpenSchema #{type.inspect}, #{criteria.inspect}") {
314
+ if ado_schema.criteria.empty?
315
+ conn.OpenSchema(ado_schema.type)
316
+ else
317
+ conn.OpenSchema(ado_schema.type, ado_schema.criteria)
318
+ end
319
+ }
320
+ yield(r) if block_given?
321
+ rescue ::WIN32OLERuntimeError => e
322
+ raise_error(e)
323
+ end
324
+ end
325
+ nil
326
+ end
327
+ end
328
+
329
+ class Dataset < ADO::Dataset
330
+ include Sequel::Access::DatasetMethods
331
+ end
332
+ end
333
+ end
334
+ end
@@ -11,17 +11,6 @@ module Sequel
11
11
  # delete query.
12
12
  ROWS_AFFECTED = "SELECT @@ROWCOUNT AS AffectedRows"
13
13
 
14
- # Return instance of Sequel::ADO::MSSQL::Dataset with the given opts.
15
- def dataset(opts=nil)
16
- Sequel::ADO::MSSQL::Dataset.new(self, opts)
17
- end
18
-
19
- # Just execute so it doesn't attempt to return the number of rows modified.
20
- def execute_ddl(sql, opts={})
21
- execute(sql, opts)
22
- end
23
- alias execute_insert execute_ddl
24
-
25
14
  # Issue a separate query to get the rows modified. ADO appears to
26
15
  # use pass by reference with an integer variable, which is obviously
27
16
  # not supported directly in ruby, and I'm not aware of a workaround.
@@ -37,11 +26,28 @@ module Sequel
37
26
  end
38
27
  end
39
28
  end
29
+
30
+ private
31
+
32
+ # The ADO adapter's default provider doesn't support transactions, since it
33
+ # creates a new native connection for each query. So Sequel only attempts
34
+ # to use transactions if an explicit :provider is given.
35
+ def begin_transaction(conn, opts={})
36
+ super if @opts[:provider]
37
+ end
38
+
39
+ def commit_transaction(conn, opts={})
40
+ super if @opts[:provider]
41
+ end
42
+
43
+ def rollback_transaction(conn, opts={})
44
+ super if @opts[:provider]
45
+ end
40
46
  end
41
47
 
42
48
  class Dataset < ADO::Dataset
43
49
  include Sequel::MSSQL::DatasetMethods
44
-
50
+
45
51
  # Use a nasty hack of multiple SQL statements in the same call and
46
52
  # having the last one return the most recently inserted id. This
47
53
  # is necessary as ADO's default :provider uses a separate native
@@ -4,20 +4,25 @@ module Sequel
4
4
  # The ADO adapter provides connectivity to ADO databases in Windows.
5
5
  module ADO
6
6
  class Database < Sequel::Database
7
+ DISCONNECT_ERROR_RE = /Communication link failure/
8
+
7
9
  set_adapter_scheme :ado
8
10
 
9
11
  def initialize(opts)
10
12
  super
11
13
  case @opts[:conn_string]
12
14
  when /Microsoft\.(Jet|ACE)\.OLEDB/io
13
- Sequel.ts_require 'adapters/shared/access'
14
- extend Sequel::Access::DatabaseMethods
15
- when nil
15
+ Sequel.ts_require 'adapters/ado/access'
16
+ extend Sequel::ADO::Access::DatabaseMethods
17
+ @dataset_class = ADO::Access::Dataset
18
+ else
16
19
  @opts[:driver] ||= 'SQL Server'
17
20
  case @opts[:driver]
18
21
  when 'SQL Server'
19
22
  Sequel.ts_require 'adapters/ado/mssql'
20
23
  extend Sequel::ADO::MSSQL::DatabaseMethods
24
+ @dataset_class = ADO::MSSQL::Dataset
25
+ set_mssql_unicode_strings
21
26
  end
22
27
  end
23
28
  end
@@ -52,10 +57,36 @@ module Sequel
52
57
  handle
53
58
  end
54
59
 
55
- def dataset(opts = nil)
56
- ADO::Dataset.new(self, opts)
60
+ def disconnect_connection(conn)
61
+ conn.Close
57
62
  end
58
-
63
+
64
+ # Just execute so it doesn't attempt to return the number of rows modified.
65
+ def execute_ddl(sql, opts={})
66
+ execute(sql, opts)
67
+ end
68
+
69
+ # Just execute so it doesn't attempt to return the number of rows modified.
70
+ def execute_insert(sql, opts={})
71
+ execute(sql, opts)
72
+ end
73
+
74
+ # Use pass by reference in WIN32OLE to get the number of affected rows,
75
+ # unless is a provider is in use (since some providers don't seem to
76
+ # return the number of affected rows, but the default provider appears
77
+ # to).
78
+ def execute_dui(sql, opts={})
79
+ return super if opts[:provider]
80
+ synchronize(opts[:server]) do |conn|
81
+ begin
82
+ log_yield(sql){conn.Execute(sql, 1)}
83
+ WIN32OLE::ARGV[1]
84
+ rescue ::WIN32OLERuntimeError => e
85
+ raise_error(e)
86
+ end
87
+ end
88
+ end
89
+
59
90
  def execute(sql, opts={})
60
91
  synchronize(opts[:server]) do |conn|
61
92
  begin
@@ -74,28 +105,45 @@ module Sequel
74
105
  # The ADO adapter's default provider doesn't support transactions, since it
75
106
  # creates a new native connection for each query. So Sequel only attempts
76
107
  # to use transactions if an explicit :provider is given.
77
- def _transaction(conn, o={})
78
- return super if opts[:provider]
79
- th = Thread.current
80
- begin
81
- @transactions << th
82
- yield conn
83
- rescue Sequel::Rollback
84
- ensure
85
- @transactions.delete(th)
86
- end
108
+ def begin_transaction(conn, opts={})
109
+ super if @opts[:provider]
87
110
  end
88
-
89
- def disconnect_connection(conn)
90
- conn.Close
111
+
112
+ def commit_transaction(conn, opts={})
113
+ super if @opts[:provider]
114
+ end
115
+
116
+ def database_error_classes
117
+ [::WIN32OLERuntimeError]
118
+ end
119
+
120
+ def disconnect_error?(e, opts)
121
+ super || (e.is_a?(::WIN32OLERuntimeError) && e.message =~ DISCONNECT_ERROR_RE)
122
+ end
123
+
124
+ def rollback_transaction(conn, opts={})
125
+ super if @opts[:provider]
91
126
  end
92
127
  end
93
128
 
94
129
  class Dataset < Sequel::Dataset
130
+ Database::DatasetClass = self
131
+
95
132
  def fetch_rows(sql)
96
133
  execute(sql) do |s|
97
- @columns = cols = s.Fields.extend(Enumerable).map{|column| output_identifier(column.Name)}
98
- s.getRows.transpose.each{|r| yield cols.inject({}){|m,c| m[c] = r.shift; m}} unless s.eof
134
+ columns = cols = s.Fields.extend(Enumerable).map{|column| output_identifier(column.Name)}
135
+ if opts[:offset] && offset_returns_row_number_column?
136
+ rn = row_number_column
137
+ columns = columns.dup
138
+ columns.delete(rn)
139
+ end
140
+ @columns = columns
141
+ s.getRows.transpose.each do |r|
142
+ row = {}
143
+ cols.each{|c| row[c] = r.shift}
144
+ row.delete(rn) if rn
145
+ yield row
146
+ end unless s.eof
99
147
  end
100
148
  end
101
149
 
@@ -14,6 +14,12 @@ module Sequel
14
14
  'float' => ['float', 'double', 'real', 'double precision'],
15
15
  'decimal' => %w'numeric decimal money'
16
16
  )
17
+
18
+ # Store the related database object, in order to be able to correctly
19
+ # handle the database timezone.
20
+ def initialize(db)
21
+ @db = db
22
+ end
17
23
 
18
24
  # Return blobs as instances of Sequel::SQL::Blob instead of
19
25
  # Amalgamite::Blob
@@ -29,7 +35,11 @@ module Sequel
29
35
 
30
36
  # Return datetime types as instances of Sequel.datetime_class
31
37
  def datetime(s)
32
- Sequel.database_to_application_timestamp(s)
38
+ @db.to_application_timestamp(s)
39
+ end
40
+
41
+ def time(s)
42
+ Sequel.string_to_time(s)
33
43
  end
34
44
 
35
45
  # Don't raise an error if the value is a string and the declared
@@ -68,7 +78,8 @@ module Sequel
68
78
  opts[:database] = ':memory:' if blank_object?(opts[:database])
69
79
  db = ::Amalgalite::Database.new(opts[:database])
70
80
  db.busy_handler(::Amalgalite::BusyTimeout.new(opts.fetch(:timeout, 5000)/50, 50))
71
- db.type_map = SequelTypeMap.new
81
+ db.type_map = SequelTypeMap.new(self)
82
+ connection_pragmas.each{|s| log_yield(s){db.execute_batch(s)}}
72
83
  db
73
84
  end
74
85
 
@@ -77,11 +88,6 @@ module Sequel
77
88
  :sqlite
78
89
  end
79
90
 
80
- # Return instance of Sequel::Amalgalite::Dataset with the given options.
81
- def dataset(opts = nil)
82
- Amalgalite::Dataset.new(self, opts)
83
- end
84
-
85
91
  # Run the given SQL with the given arguments. Returns nil.
86
92
  def execute_ddl(sql, opts={})
87
93
  _execute(sql, opts){|conn| log_yield(sql){conn.execute_batch(sql)}}
@@ -141,16 +147,13 @@ module Sequel
141
147
  def database_error_classes
142
148
  [::Amalgalite::Error, ::Amalgalite::SQLite3::Error]
143
149
  end
144
-
145
- # Disconnect given connections from the database.
146
- def disconnect_connection(c)
147
- c.close
148
- end
149
150
  end
150
151
 
151
152
  # Dataset class for SQLite datasets that use the amalgalite driver.
152
153
  class Dataset < Sequel::Dataset
153
154
  include ::Sequel::SQLite::DatasetMethods
155
+
156
+ Database::DatasetClass = self
154
157
 
155
158
  # Yield a hash for each row in the dataset.
156
159
  def fetch_rows(sql)
@@ -168,8 +171,8 @@ module Sequel
168
171
  private
169
172
 
170
173
  # Quote the string using the adapter instance method.
171
- def literal_string(v)
172
- db.synchronize{|c| c.quote(v)}
174
+ def literal_string_append(sql, v)
175
+ db.synchronize{|c| sql << c.quote(v)}
173
176
  end
174
177
  end
175
178
  end