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,452 @@
1
+ require 'ibm_db'
2
+ Sequel.require 'adapters/shared/db2'
3
+
4
+ module Sequel
5
+
6
+ module IBMDB
7
+ @convert_smallint_to_bool = true
8
+
9
+ class << self
10
+ # Whether to convert smallint values to bool, true by default.
11
+ # Can also be overridden per dataset.
12
+ attr_accessor :convert_smallint_to_bool
13
+ end
14
+
15
+ tt = Class.new do
16
+ def boolean(s) !s.to_i.zero? end
17
+ def int(s) s.to_i end
18
+ end.new
19
+
20
+ # Hash holding type translation methods, used by Dataset#fetch_rows.
21
+ DB2_TYPES = {
22
+ :boolean => tt.method(:boolean),
23
+ :int => tt.method(:int),
24
+ :blob => ::Sequel::SQL::Blob.method(:new),
25
+ :time => ::Sequel.method(:string_to_time),
26
+ :date => ::Sequel.method(:string_to_date)
27
+ }
28
+ DB2_TYPES[:clob] = DB2_TYPES[:blob]
29
+
30
+ # Wraps an underlying connection to DB2 using IBM_DB.
31
+ class Connection
32
+ # A hash with prepared statement name symbol keys, where each value is
33
+ # a two element array with an sql string and cached Statement value.
34
+ attr_accessor :prepared_statements
35
+
36
+ # Error class for exceptions raised by the connection.
37
+ class Error < StandardError
38
+ end
39
+
40
+ # Create the underlying IBM_DB connection.
41
+ def initialize(connection_string)
42
+ @conn = IBM_DB.connect(connection_string, '', '')
43
+ self.autocommit = true
44
+ @prepared_statements = {}
45
+ end
46
+
47
+ # Check whether the connection is in autocommit state or not.
48
+ def autocommit
49
+ IBM_DB.autocommit(@conn) == 1
50
+ end
51
+
52
+ # Turn autocommit on or off for the connection.
53
+ def autocommit=(value)
54
+ IBM_DB.autocommit(@conn, value ? IBM_DB::SQL_AUTOCOMMIT_ON : IBM_DB::SQL_AUTOCOMMIT_OFF)
55
+ end
56
+
57
+ # Close the connection, disconnecting from DB2.
58
+ def close
59
+ IBM_DB.close(@conn)
60
+ end
61
+
62
+ # Commit the currently outstanding transaction on this connection.
63
+ def commit
64
+ IBM_DB.commit(@conn)
65
+ end
66
+
67
+ # Return the related error message for the connection.
68
+ def error_msg
69
+ IBM_DB.getErrormsg(@conn, IBM_DB::DB_CONN)
70
+ end
71
+
72
+ # Execute the given SQL on the database, and return a Statement instance
73
+ # holding the results.
74
+ def execute(sql)
75
+ stmt = IBM_DB.exec(@conn, sql)
76
+ raise Error, error_msg unless stmt
77
+ Statement.new(stmt)
78
+ end
79
+
80
+ # Execute the related prepared statement on the database with the given
81
+ # arguments.
82
+ def execute_prepared(ps_name, *values)
83
+ stmt = @prepared_statements[ps_name].last
84
+ res = stmt.execute(*values)
85
+ unless res
86
+ raise Error, "Error executing statement #{ps_name}: #{error_msg}"
87
+ end
88
+ stmt
89
+ end
90
+
91
+ # Prepare a statement with the given +sql+ on the database, and
92
+ # cache the prepared statement value by name.
93
+ def prepare(sql, ps_name)
94
+ if stmt = IBM_DB.prepare(@conn, sql)
95
+ ps_name = ps_name.to_sym
96
+ stmt = Statement.new(stmt)
97
+ @prepared_statements[ps_name] = [sql, stmt]
98
+ else
99
+ err = error_msg
100
+ err = "Error preparing #{ps_name} with SQL: #{sql}" if error_msg.nil? || error_msg.empty?
101
+ raise Error, err
102
+ end
103
+ end
104
+
105
+ # Rollback the currently outstanding transaction on this connection.
106
+ def rollback
107
+ IBM_DB.rollback(@conn)
108
+ end
109
+ end
110
+
111
+ # Wraps results returned by queries on IBM_DB.
112
+ class Statement
113
+ # Hold the given statement.
114
+ def initialize(stmt)
115
+ @stmt = stmt
116
+ end
117
+
118
+ # Return the number of rows affected.
119
+ def affected
120
+ IBM_DB.num_rows(@stmt)
121
+ end
122
+
123
+ # If this statement is a prepared statement, execute it on the database
124
+ # with the given values.
125
+ def execute(*values)
126
+ IBM_DB.execute(@stmt, values)
127
+ end
128
+
129
+ # Return the results of a query as an array of values.
130
+ def fetch_array
131
+ IBM_DB.fetch_array(@stmt) if @stmt
132
+ end
133
+
134
+ # Return the field name at the given column in the result set.
135
+ def field_name(ind)
136
+ IBM_DB.field_name(@stmt, ind)
137
+ end
138
+
139
+ # Return the field type for the given field name in the result set.
140
+ def field_type(key)
141
+ IBM_DB.field_type(@stmt, key)
142
+ end
143
+
144
+ # Return the field precision for the given field name in the result set.
145
+ def field_precision(key)
146
+ IBM_DB.field_precision(@stmt, key)
147
+ end
148
+
149
+ # Free the memory related to this result set.
150
+ def free
151
+ IBM_DB.free_result(@stmt)
152
+ end
153
+
154
+ # Return the number of fields in the result set.
155
+ def num_fields
156
+ IBM_DB.num_fields(@stmt)
157
+ end
158
+ end
159
+
160
+ class Database < Sequel::Database
161
+ include Sequel::DB2::DatabaseMethods
162
+
163
+ set_adapter_scheme :ibmdb
164
+
165
+ # Hash of connection procs for converting
166
+ attr_reader :conversion_procs
167
+
168
+ def initialize(opts={})
169
+ super
170
+ @conversion_procs = DB2_TYPES.dup
171
+ @conversion_procs[:timestamp] = method(:to_application_timestamp)
172
+ end
173
+
174
+ # REORG the related table whenever it is altered. This is not always
175
+ # required, but it is necessary for compatibilty with other Sequel
176
+ # code in many cases.
177
+ def alter_table(name, generator=nil)
178
+ res = super
179
+ reorg(name)
180
+ res
181
+ end
182
+
183
+ # Create a new connection object for the given server.
184
+ def connect(server)
185
+ opts = server_opts(server)
186
+
187
+ # use uncataloged connection so that host and port can be supported
188
+ connection_string = ( \
189
+ 'Driver={IBM DB2 ODBC DRIVER};' \
190
+ "Database=#{opts[:database]};" \
191
+ "Hostname=#{opts[:host]};" \
192
+ "Port=#{opts[:port] || 50000};" \
193
+ 'Protocol=TCPIP;' \
194
+ "Uid=#{opts[:user]};" \
195
+ "Pwd=#{opts[:password]};" \
196
+ )
197
+
198
+ Connection.new(connection_string)
199
+ end
200
+
201
+ # Execute the given SQL on the database.
202
+ def execute(sql, opts={}, &block)
203
+ if sql.is_a?(Symbol)
204
+ execute_prepared_statement(sql, opts, &block)
205
+ else
206
+ synchronize(opts[:server]){|c| _execute(c, sql, opts, &block)}
207
+ end
208
+ rescue Connection::Error => e
209
+ raise_error(e)
210
+ end
211
+
212
+ # Execute the given SQL on the database, returning the last inserted
213
+ # identity value.
214
+ def execute_insert(sql, opts={})
215
+ synchronize(opts[:server]) do |c|
216
+ if sql.is_a?(Symbol)
217
+ execute_prepared_statement(sql, opts)
218
+ else
219
+ _execute(c, sql, opts)
220
+ end
221
+ _execute(c, "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1", opts){|stmt| i = stmt.fetch_array.first.to_i; stmt.free; i}
222
+ end
223
+ rescue Connection::Error => e
224
+ raise_error(e)
225
+ end
226
+
227
+ # Execute a prepared statement named by name on the database.
228
+ def execute_prepared_statement(ps_name, opts)
229
+ args = opts[:arguments]
230
+ ps = prepared_statement(ps_name)
231
+ sql = ps.prepared_sql
232
+ synchronize(opts[:server]) do |conn|
233
+ unless conn.prepared_statements.fetch(ps_name, []).first == sql
234
+ log_yield("PREPARE #{ps_name}: #{sql}"){conn.prepare(sql, ps_name)}
235
+ end
236
+ args = args.map{|v| v.nil? ? nil : prepared_statement_arg(v)}
237
+ log_sql = "EXECUTE #{ps_name}"
238
+ if ps.log_sql
239
+ log_sql << " ("
240
+ log_sql << sql
241
+ log_sql << ")"
242
+ end
243
+ stmt = log_yield(log_sql, args){conn.execute_prepared(ps_name, *args)}
244
+ if block_given?
245
+ begin
246
+ yield(stmt)
247
+ ensure
248
+ stmt.free
249
+ end
250
+ else
251
+ stmt.affected
252
+ end
253
+ end
254
+ end
255
+
256
+ # Convert smallint type to boolean if convert_smallint_to_bool is true
257
+ def schema_column_type(db_type)
258
+ if Sequel::IBMDB.convert_smallint_to_bool && db_type =~ /smallint/i
259
+ :boolean
260
+ else
261
+ super
262
+ end
263
+ end
264
+
265
+ # On DB2, a table might need to be REORGed if you are testing existence
266
+ # of it. This REORGs automatically if the database raises a specific
267
+ # error that indicates it should be REORGed.
268
+ def table_exists?(name)
269
+ v ||= false # only retry once
270
+ sch, table_name = schema_and_table(name)
271
+ name = SQL::QualifiedIdentifier.new(sch, table_name) if sch
272
+ from(name).first
273
+ true
274
+ rescue DatabaseError => e
275
+ if e.to_s =~ /Operation not allowed for reason code "7" on table/ && v == false
276
+ # table probably needs reorg
277
+ reorg(name)
278
+ v = true
279
+ retry
280
+ end
281
+ false
282
+ end
283
+
284
+ private
285
+
286
+ # Execute the given SQL on the database.
287
+ def _execute(conn, sql, opts)
288
+ stmt = log_yield(sql){conn.execute(sql)}
289
+ if block_given?
290
+ begin
291
+ yield(stmt)
292
+ ensure
293
+ stmt.free
294
+ end
295
+ else
296
+ stmt.affected
297
+ end
298
+ end
299
+
300
+ # IBM_DB uses an autocommit setting instead of sending SQL queries.
301
+ # So starting a transaction just turns autocommit off.
302
+ def begin_transaction(conn, opts={})
303
+ log_yield(TRANSACTION_BEGIN){conn.autocommit = false}
304
+ end
305
+
306
+ # This commits transaction in progress on the
307
+ # connection and sets autocommit back on.
308
+ def commit_transaction(conn, opts={})
309
+ log_yield(TRANSACTION_COMMIT){conn.commit}
310
+ end
311
+
312
+ def database_error_classes
313
+ [Connection::Error]
314
+ end
315
+
316
+ # Don't convert smallint to boolean for the metadata
317
+ # dataset, since the DB2 metadata does not use
318
+ # boolean columns, and some smallint columns are
319
+ # accidently treated as booleans.
320
+ def metadata_dataset
321
+ ds = super
322
+ ds.convert_smallint_to_bool = false
323
+ ds
324
+ end
325
+
326
+ # Format Numeric, Date, and Time types specially for use
327
+ # as IBM_DB prepared statements argument vlaues.
328
+ def prepared_statement_arg(v)
329
+ case v
330
+ when Numeric
331
+ v.to_s
332
+ when Date, Time
333
+ literal(v).gsub("'", '')
334
+ else
335
+ v
336
+ end
337
+ end
338
+
339
+ # Set autocommit back on
340
+ def remove_transaction(conn, committed)
341
+ conn.autocommit = true
342
+ ensure
343
+ super
344
+ end
345
+
346
+ # This rolls back the transaction in progress on the
347
+ # connection and sets autocommit back on.
348
+ def rollback_transaction(conn, opts={})
349
+ log_yield(TRANSACTION_ROLLBACK){conn.rollback}
350
+ end
351
+ end
352
+
353
+ class Dataset < Sequel::Dataset
354
+ include Sequel::DB2::DatasetMethods
355
+
356
+ Database::DatasetClass = self
357
+
358
+ module CallableStatementMethods
359
+ # Extend given dataset with this module so subselects inside subselects in
360
+ # prepared statements work.
361
+ def subselect_sql_append(sql, ds)
362
+ ps = ds.to_prepared_statement(:select).clone(:append_sql=>sql)
363
+ ps.extend(CallableStatementMethods)
364
+ ps = ps.bind(@opts[:bind_vars]) if @opts[:bind_vars]
365
+ ps.prepared_args = prepared_args
366
+ ps.prepared_sql
367
+ end
368
+ end
369
+
370
+ # Methods for DB2 prepared statements using the native driver.
371
+ module PreparedStatementMethods
372
+ include Sequel::Dataset::UnnumberedArgumentMapper
373
+
374
+ private
375
+ # Execute the prepared statement with arguments instead of the given SQL.
376
+ def execute(sql, opts={}, &block)
377
+ super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
378
+ end
379
+
380
+ # Execute the prepared statment with arguments instead of the given SQL.
381
+ def execute_dui(sql, opts={}, &block)
382
+ super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
383
+ end
384
+
385
+ # Execute the prepared statement with arguments instead of the given SQL.
386
+ def execute_insert(sql, opts={}, &block)
387
+ super(prepared_statement_name, {:arguments=>bind_arguments}.merge(opts), &block)
388
+ end
389
+
390
+ end
391
+
392
+ # Emulate support of bind arguments in called statements.
393
+ def call(type, bind_arguments={}, *values, &block)
394
+ ps = to_prepared_statement(type, values)
395
+ ps.extend(CallableStatementMethods)
396
+ ps.call(bind_arguments, &block)
397
+ end
398
+
399
+ # Whether to convert smallint to boolean arguments for this dataset.
400
+ # Defaults to the IBMDB module setting.
401
+ def convert_smallint_to_bool
402
+ defined?(@convert_smallint_to_bool) ? @convert_smallint_to_bool : (@convert_smallint_to_bool = IBMDB.convert_smallint_to_bool)
403
+ end
404
+
405
+ # Override the default IBMDB.convert_smallint_to_bool setting for this dataset.
406
+ attr_writer :convert_smallint_to_bool
407
+
408
+ # Fetch the rows from the database and yield plain hashes.
409
+ def fetch_rows(sql)
410
+ execute(sql) do |stmt|
411
+ offset = @opts[:offset]
412
+ columns = []
413
+ convert = convert_smallint_to_bool
414
+ cps = db.conversion_procs
415
+ stmt.num_fields.times do |i|
416
+ k = stmt.field_name i
417
+ key = output_identifier(k)
418
+ type = stmt.field_type(k).downcase.to_sym
419
+ # decide if it is a smallint from precision
420
+ type = :boolean if type ==:int && convert && stmt.field_precision(k) < 8
421
+ columns << [key, cps[type]]
422
+ end
423
+ cols = columns.map{|c| c.at(0)}
424
+ cols.delete(row_number_column) if offset
425
+ @columns = cols
426
+
427
+ while res = stmt.fetch_array
428
+ row = {}
429
+ res.zip(columns).each do |v, (k, pr)|
430
+ row[k] = ((pr ? pr.call(v) : v) if v)
431
+ end
432
+ row.delete(row_number_column) if offset
433
+ yield row
434
+ end
435
+ end
436
+ self
437
+ end
438
+
439
+ # Store the given type of prepared statement in the associated database
440
+ # with the given name.
441
+ def prepare(type, name=nil, *values)
442
+ ps = to_prepared_statement(type, values)
443
+ ps.extend(PreparedStatementMethods)
444
+ if name
445
+ ps.prepared_statement_name = name
446
+ db.set_prepared_statement(name, ps)
447
+ end
448
+ ps
449
+ end
450
+ end
451
+ end
452
+ end
@@ -1,21 +1,18 @@
1
1
  require 'informix'
2
+ Sequel.require 'adapters/shared/informix'
2
3
 
3
4
  module Sequel
4
5
  module Informix
5
6
  class Database < Sequel::Database
7
+ include DatabaseMethods
8
+
6
9
  set_adapter_scheme :informix
7
10
 
8
- TEMPORARY = 'TEMP '.freeze
9
-
10
11
  def connect(server)
11
12
  opts = server_opts(server)
12
13
  ::Informix.connect(opts[:database], opts[:user], opts[:password])
13
14
  end
14
15
 
15
- def dataset(opts = nil)
16
- Sequel::Informix::Dataset.new(self, opts)
17
- end
18
-
19
16
  # Returns number of rows affected
20
17
  def execute_dui(sql, opts={})
21
18
  synchronize(opts[:server]){|c| log_yield(sql){c.immediate(sql)}}
@@ -26,16 +23,12 @@ module Sequel
26
23
  synchronize(opts[:server]){|c| yield log_yield(sql){c.cursor(sql)}}
27
24
  end
28
25
  alias_method :query, :execute
29
-
30
- private
31
-
32
- def disconnect_connection(c)
33
- c.close
34
- end
35
26
  end
36
27
 
37
28
  class Dataset < Sequel::Dataset
38
- SELECT_CLAUSE_METHODS = clause_methods(:select, %w'limit distinct columns from join where having group compounds order')
29
+ include DatasetMethods
30
+
31
+ Database::DatasetClass = self
39
32
 
40
33
  def fetch_rows(sql)
41
34
  execute(sql) do |cursor|
@@ -56,22 +49,6 @@ module Sequel
56
49
  end
57
50
  self
58
51
  end
59
-
60
- private
61
-
62
- # Informix does not support INTERSECT or EXCEPT
63
- def supports_intersect_except?
64
- false
65
- end
66
-
67
- def select_clause_methods
68
- SELECT_CLAUSE_METHODS
69
- end
70
-
71
- def select_limit_sql(sql)
72
- sql << " SKIP #{@opts[:offset]}" if @opts[:offset]
73
- sql << " FIRST #{@opts[:limit]}" if @opts[:limit]
74
- end
75
52
  end
76
53
  end
77
54
  end
@@ -1,9 +1,13 @@
1
+ Sequel.require 'adapters/jdbc/transactions'
2
+
1
3
  module Sequel
2
4
  module JDBC
3
5
  # Database and Dataset support for AS400 databases accessed via JDBC.
4
6
  module AS400
5
7
  # Instance methods for AS400 Database objects accessed via JDBC.
6
8
  module DatabaseMethods
9
+ include Sequel::JDBC::Transactions
10
+
7
11
  TRANSACTION_BEGIN = 'Transaction.begin'.freeze
8
12
  TRANSACTION_COMMIT = 'Transaction.commit'.freeze
9
13
  TRANSACTION_ROLLBACK = 'Transaction.rollback'.freeze
@@ -13,11 +17,6 @@ module Sequel
13
17
  :as400
14
18
  end
15
19
 
16
- # Return Sequel::JDBC::AS400::Dataset object with the given opts.
17
- def dataset(opts=nil)
18
- Sequel::JDBC::AS400::Dataset.new(self, opts)
19
- end
20
-
21
20
  # TODO: Fix for AS400
22
21
  def last_insert_id(conn, opts={})
23
22
  nil
@@ -33,31 +32,16 @@ module Sequel
33
32
  # Use JDBC connection's setAutoCommit to false to start transactions
34
33
  def begin_transaction(conn, opts={})
35
34
  set_transaction_isolation(conn, opts)
36
- log_yield(TRANSACTION_BEGIN){conn.setAutoCommit(false)}
37
- conn
38
- end
39
-
40
- # Use JDBC connection's commit method to commit transactions
41
- def commit_transaction(conn, opts={})
42
- log_yield(TRANSACTION_COMMIT){conn.commit}
43
- end
44
-
45
- # Use JDBC connection's setAutoCommit to true to enable default
46
- # auto-commit mode
47
- def remove_transaction(conn)
48
- conn.setAutoCommit(true) if conn
49
- @transactions.delete(Thread.current)
50
- end
51
-
52
- # Use JDBC connection's rollback method to rollback transactions
53
- def rollback_transaction(conn, opts={})
54
- log_yield(TRANSACTION_ROLLBACK){conn.rollback}
35
+ super
55
36
  end
56
37
  end
57
38
 
58
39
  # Dataset class for AS400 datasets accessed via JDBC.
59
40
  class Dataset < JDBC::Dataset
60
41
  WILDCARD = Sequel::LiteralString.new('*').freeze
42
+ FETCH_FIRST_ROW_ONLY = " FETCH FIRST ROW ONLY".freeze
43
+ FETCH_FIRST = " FETCH FIRST ".freeze
44
+ ROWS_ONLY = " ROWS ONLY".freeze
61
45
 
62
46
  # AS400 needs to use a couple of subselects for queries with offsets.
63
47
  def select_sql
@@ -79,22 +63,20 @@ module Sequel
79
63
 
80
64
  # Modify the sql to limit the number of rows returned
81
65
  def select_limit_sql(sql)
82
- if @opts[:limit]
83
- sql << " FETCH FIRST ROW ONLY" if @opts[:limit] == 1
84
- sql << " FETCH FIRST #{@opts[:limit]} ROWS ONLY" if @opts[:limit] > 1
66
+ if l = @opts[:limit]
67
+ if l == 1
68
+ sql << FETCH_FIRST_ROW_ONLY
69
+ elsif l > 1
70
+ sql << FETCH_FIRST
71
+ literal_append(sql, l)
72
+ sql << ROWS_ONLY
73
+ end
85
74
  end
86
75
  end
87
76
 
88
77
  def supports_window_functions?
89
78
  true
90
79
  end
91
-
92
- private
93
-
94
- # The alias to use for the row_number column when emulating LIMIT and OFFSET
95
- def row_number_column
96
- :x_sequel_row_number_x
97
- end
98
80
  end
99
81
  end
100
82
  end
@@ -0,0 +1,52 @@
1
+ Sequel.require 'adapters/shared/cubrid'
2
+ Sequel.require 'adapters/jdbc/transactions'
3
+
4
+ module Sequel
5
+ module JDBC
6
+ module Cubrid
7
+ module DatabaseMethods
8
+ include Sequel::Cubrid::DatabaseMethods
9
+ include Sequel::JDBC::Transactions
10
+
11
+ def supports_savepoints?
12
+ false
13
+ end
14
+
15
+ private
16
+
17
+ # Get the last inserted id using LAST_INSERT_ID().
18
+ def last_insert_id(conn, opts={})
19
+ if stmt = opts[:stmt]
20
+ rs = stmt.getGeneratedKeys
21
+ begin
22
+ if rs.next
23
+ rs.getInt(1)
24
+ end
25
+ rescue NativeException
26
+ nil
27
+ ensure
28
+ rs.close
29
+ end
30
+ end
31
+ end
32
+
33
+ # Use execute instead of executeUpdate.
34
+ def execute_prepared_statement_insert(stmt)
35
+ stmt.execute
36
+ end
37
+
38
+ # Return generated keys for insert statements, and use
39
+ # execute intead of executeUpdate as CUBRID doesn't
40
+ # return generated keys in executeUpdate.
41
+ def execute_statement_insert(stmt, sql)
42
+ stmt.execute(sql, JavaSQL::Statement.RETURN_GENERATED_KEYS)
43
+ end
44
+
45
+ # Return generated keys for insert statements.
46
+ def prepare_jdbc_statement(conn, sql, opts)
47
+ opts[:type] == :insert ? conn.prepareStatement(sql, JavaSQL::Statement.RETURN_GENERATED_KEYS) : super
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end