sequel 3.21.0 → 3.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. data/CHANGELOG +1131 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +106 -65
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +68 -52
  7. data/doc/advanced_associations.rdoc +201 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/bin_sequel.rdoc +144 -0
  10. data/doc/cheat_sheet.rdoc +21 -21
  11. data/doc/core_extensions.rdoc +374 -0
  12. data/doc/dataset_basics.rdoc +10 -10
  13. data/doc/dataset_filtering.rdoc +54 -42
  14. data/doc/mass_assignment.rdoc +56 -0
  15. data/doc/migration.rdoc +89 -557
  16. data/doc/model_hooks.rdoc +80 -29
  17. data/doc/object_model.rdoc +576 -0
  18. data/doc/opening_databases.rdoc +121 -53
  19. data/doc/prepared_statements.rdoc +41 -15
  20. data/doc/querying.rdoc +137 -56
  21. data/doc/reflection.rdoc +36 -10
  22. data/doc/release_notes/3.22.0.txt +39 -0
  23. data/doc/release_notes/3.23.0.txt +172 -0
  24. data/doc/release_notes/3.24.0.txt +420 -0
  25. data/doc/release_notes/3.25.0.txt +88 -0
  26. data/doc/release_notes/3.26.0.txt +88 -0
  27. data/doc/release_notes/3.27.0.txt +82 -0
  28. data/doc/release_notes/3.28.0.txt +304 -0
  29. data/doc/release_notes/3.29.0.txt +459 -0
  30. data/doc/release_notes/3.30.0.txt +135 -0
  31. data/doc/release_notes/3.31.0.txt +146 -0
  32. data/doc/release_notes/3.32.0.txt +202 -0
  33. data/doc/release_notes/3.33.0.txt +157 -0
  34. data/doc/release_notes/3.34.0.txt +671 -0
  35. data/doc/release_notes/3.35.0.txt +144 -0
  36. data/doc/release_notes/3.36.0.txt +245 -0
  37. data/doc/release_notes/3.37.0.txt +338 -0
  38. data/doc/release_notes/3.38.0.txt +234 -0
  39. data/doc/release_notes/3.39.0.txt +237 -0
  40. data/doc/release_notes/3.40.0.txt +73 -0
  41. data/doc/release_notes/3.41.0.txt +155 -0
  42. data/doc/schema_modification.rdoc +585 -0
  43. data/doc/sharding.rdoc +99 -8
  44. data/doc/sql.rdoc +154 -112
  45. data/doc/testing.rdoc +169 -0
  46. data/doc/thread_safety.rdoc +17 -0
  47. data/doc/transactions.rdoc +137 -0
  48. data/doc/validations.rdoc +1 -1
  49. data/doc/virtual_rows.rdoc +78 -43
  50. data/lib/sequel/adapters/ado/access.rb +334 -0
  51. data/lib/sequel/adapters/ado/mssql.rb +18 -12
  52. data/lib/sequel/adapters/ado.rb +69 -21
  53. data/lib/sequel/adapters/amalgalite.rb +17 -14
  54. data/lib/sequel/adapters/cubrid.rb +143 -0
  55. data/lib/sequel/adapters/db2.rb +178 -85
  56. data/lib/sequel/adapters/dbi.rb +19 -21
  57. data/lib/sequel/adapters/do/mysql.rb +17 -11
  58. data/lib/sequel/adapters/do/postgres.rb +2 -61
  59. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  60. data/lib/sequel/adapters/do.rb +20 -39
  61. data/lib/sequel/adapters/firebird.rb +33 -210
  62. data/lib/sequel/adapters/ibmdb.rb +452 -0
  63. data/lib/sequel/adapters/informix.rb +6 -29
  64. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  65. data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
  66. data/lib/sequel/adapters/jdbc/db2.rb +78 -0
  67. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  68. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  69. data/lib/sequel/adapters/jdbc/h2.rb +68 -31
  70. data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -0
  71. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  73. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  74. data/lib/sequel/adapters/jdbc/mysql.rb +16 -28
  75. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  76. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  77. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  78. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  79. data/lib/sequel/adapters/jdbc/sqlserver.rb +72 -0
  80. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  81. data/lib/sequel/adapters/jdbc.rb +308 -114
  82. data/lib/sequel/adapters/mock.rb +372 -0
  83. data/lib/sequel/adapters/mysql.rb +130 -230
  84. data/lib/sequel/adapters/mysql2.rb +64 -63
  85. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  86. data/lib/sequel/adapters/odbc.rb +29 -10
  87. data/lib/sequel/adapters/openbase.rb +7 -11
  88. data/lib/sequel/adapters/oracle.rb +364 -57
  89. data/lib/sequel/adapters/postgres.rb +379 -145
  90. data/lib/sequel/adapters/shared/access.rb +236 -11
  91. data/lib/sequel/adapters/shared/cubrid.rb +216 -0
  92. data/lib/sequel/adapters/shared/db2.rb +353 -0
  93. data/lib/sequel/adapters/shared/firebird.rb +231 -0
  94. data/lib/sequel/adapters/shared/informix.rb +53 -0
  95. data/lib/sequel/adapters/shared/mssql.rb +412 -116
  96. data/lib/sequel/adapters/shared/mysql.rb +396 -89
  97. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
  98. data/lib/sequel/adapters/shared/oracle.rb +262 -45
  99. data/lib/sequel/adapters/shared/postgres.rb +688 -279
  100. data/lib/sequel/adapters/shared/progress.rb +5 -8
  101. data/lib/sequel/adapters/shared/sqlite.rb +317 -96
  102. data/lib/sequel/adapters/sqlite.rb +109 -46
  103. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  104. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  105. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  106. data/lib/sequel/adapters/swift.rb +31 -27
  107. data/lib/sequel/adapters/tinytds.rb +177 -25
  108. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  109. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  110. data/lib/sequel/adapters/utils/split_alter_table.rb +36 -0
  111. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  112. data/lib/sequel/ast_transformer.rb +194 -0
  113. data/lib/sequel/connection_pool/sharded_single.rb +23 -13
  114. data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
  115. data/lib/sequel/connection_pool/single.rb +11 -3
  116. data/lib/sequel/connection_pool/threaded.rb +69 -20
  117. data/lib/sequel/connection_pool.rb +20 -18
  118. data/lib/sequel/core.rb +143 -11
  119. data/lib/sequel/database/connecting.rb +66 -29
  120. data/lib/sequel/database/dataset.rb +4 -4
  121. data/lib/sequel/database/dataset_defaults.rb +63 -2
  122. data/lib/sequel/database/logging.rb +7 -2
  123. data/lib/sequel/database/misc.rb +192 -51
  124. data/lib/sequel/database/query.rb +299 -114
  125. data/lib/sequel/database/schema_generator.rb +103 -36
  126. data/lib/sequel/database/schema_methods.rb +310 -69
  127. data/lib/sequel/dataset/actions.rb +344 -90
  128. data/lib/sequel/dataset/features.rb +101 -8
  129. data/lib/sequel/dataset/graph.rb +42 -15
  130. data/lib/sequel/dataset/misc.rb +52 -25
  131. data/lib/sequel/dataset/mutation.rb +12 -7
  132. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  133. data/lib/sequel/dataset/query.rb +322 -68
  134. data/lib/sequel/dataset/sql.rb +716 -293
  135. data/lib/sequel/dataset.rb +8 -0
  136. data/lib/sequel/exceptions.rb +4 -0
  137. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  138. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  139. data/lib/sequel/extensions/blank.rb +4 -0
  140. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  141. data/lib/sequel/extensions/connection_validator.rb +109 -0
  142. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  143. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  144. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  145. data/lib/sequel/extensions/inflector.rb +4 -0
  146. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  147. data/lib/sequel/extensions/migration.rb +100 -11
  148. data/lib/sequel/extensions/named_timezones.rb +9 -0
  149. data/lib/sequel/extensions/null_dataset.rb +94 -0
  150. data/lib/sequel/extensions/pagination.rb +4 -0
  151. data/lib/sequel/extensions/pg_array.rb +539 -0
  152. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  153. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  154. data/lib/sequel/extensions/pg_hstore.rb +334 -0
  155. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  156. data/lib/sequel/extensions/pg_inet.rb +113 -0
  157. data/lib/sequel/extensions/pg_interval.rb +191 -0
  158. data/lib/sequel/extensions/pg_json.rb +212 -0
  159. data/lib/sequel/extensions/pg_range.rb +513 -0
  160. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  161. data/lib/sequel/extensions/pg_row.rb +576 -0
  162. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  163. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  164. data/lib/sequel/extensions/pretty_table.rb +17 -72
  165. data/lib/sequel/extensions/query.rb +8 -4
  166. data/lib/sequel/extensions/query_literals.rb +79 -0
  167. data/lib/sequel/extensions/schema_caching.rb +76 -0
  168. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  169. data/lib/sequel/extensions/select_remove.rb +39 -0
  170. data/lib/sequel/extensions/server_block.rb +140 -0
  171. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  172. data/lib/sequel/extensions/sql_expr.rb +8 -110
  173. data/lib/sequel/extensions/string_date_time.rb +4 -0
  174. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  175. data/lib/sequel/extensions/to_dot.rb +99 -83
  176. data/lib/sequel/model/associations.rb +1263 -409
  177. data/lib/sequel/model/base.rb +624 -171
  178. data/lib/sequel/model/errors.rb +1 -1
  179. data/lib/sequel/model/exceptions.rb +24 -2
  180. data/lib/sequel/model/inflections.rb +1 -1
  181. data/lib/sequel/model.rb +30 -11
  182. data/lib/sequel/no_core_ext.rb +2 -0
  183. data/lib/sequel/plugins/active_model.rb +13 -1
  184. data/lib/sequel/plugins/association_pks.rb +137 -16
  185. data/lib/sequel/plugins/caching.rb +25 -18
  186. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  187. data/lib/sequel/plugins/composition.rb +44 -12
  188. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  189. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  190. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  191. data/lib/sequel/plugins/dirty.rb +214 -0
  192. data/lib/sequel/plugins/eager_each.rb +59 -0
  193. data/lib/sequel/plugins/force_encoding.rb +6 -6
  194. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  195. data/lib/sequel/plugins/identity_map.rb +134 -15
  196. data/lib/sequel/plugins/instance_filters.rb +10 -0
  197. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  198. data/lib/sequel/plugins/json_serializer.rb +77 -6
  199. data/lib/sequel/plugins/list.rb +13 -2
  200. data/lib/sequel/plugins/many_through_many.rb +103 -51
  201. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  202. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  203. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  204. data/lib/sequel/plugins/pg_row.rb +121 -0
  205. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  206. data/lib/sequel/plugins/prepared_statements.rb +168 -0
  207. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  208. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  209. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  210. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  211. data/lib/sequel/plugins/schema.rb +8 -3
  212. data/lib/sequel/plugins/serialization.rb +98 -49
  213. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  214. data/lib/sequel/plugins/sharding.rb +21 -54
  215. data/lib/sequel/plugins/single_table_inheritance.rb +57 -12
  216. data/lib/sequel/plugins/static_cache.rb +99 -0
  217. data/lib/sequel/plugins/subclasses.rb +29 -3
  218. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  219. data/lib/sequel/plugins/timestamps.rb +1 -1
  220. data/lib/sequel/plugins/touch.rb +18 -6
  221. data/lib/sequel/plugins/tree.rb +3 -3
  222. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  223. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  224. data/lib/sequel/plugins/validation_class_methods.rb +2 -1
  225. data/lib/sequel/plugins/validation_helpers.rb +57 -4
  226. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  227. data/lib/sequel/sql.rb +721 -141
  228. data/lib/sequel/timezones.rb +67 -40
  229. data/lib/sequel/version.rb +1 -1
  230. data/spec/adapters/db2_spec.rb +146 -0
  231. data/spec/adapters/firebird_spec.rb +53 -39
  232. data/spec/adapters/mssql_spec.rb +261 -66
  233. data/spec/adapters/mysql_spec.rb +597 -352
  234. data/spec/adapters/oracle_spec.rb +92 -117
  235. data/spec/adapters/postgres_spec.rb +2103 -341
  236. data/spec/adapters/spec_helper.rb +16 -6
  237. data/spec/adapters/sqlite_spec.rb +237 -76
  238. data/spec/core/connection_pool_spec.rb +270 -141
  239. data/spec/core/database_spec.rb +980 -524
  240. data/spec/core/dataset_spec.rb +1658 -1243
  241. data/spec/core/expression_filters_spec.rb +741 -334
  242. data/spec/core/mock_adapter_spec.rb +453 -0
  243. data/spec/core/object_graph_spec.rb +88 -129
  244. data/spec/core/schema_generator_spec.rb +4 -4
  245. data/spec/core/schema_spec.rb +556 -53
  246. data/spec/core/spec_helper.rb +7 -48
  247. data/spec/core_extensions_spec.rb +626 -0
  248. data/spec/extensions/active_model_spec.rb +13 -0
  249. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  250. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  251. data/spec/extensions/association_dependencies_spec.rb +15 -25
  252. data/spec/extensions/association_pks_spec.rb +227 -33
  253. data/spec/extensions/association_proxies_spec.rb +4 -4
  254. data/spec/extensions/boolean_readers_spec.rb +25 -25
  255. data/spec/extensions/caching_spec.rb +47 -51
  256. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  257. data/spec/extensions/columns_introspection_spec.rb +91 -0
  258. data/spec/extensions/composition_spec.rb +18 -13
  259. data/spec/extensions/connection_validator_spec.rb +118 -0
  260. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  261. data/spec/extensions/constraint_validations_spec.rb +316 -0
  262. data/spec/extensions/dataset_associations_spec.rb +199 -0
  263. data/spec/extensions/defaults_setter_spec.rb +88 -0
  264. data/spec/extensions/dirty_spec.rb +155 -0
  265. data/spec/extensions/eager_each_spec.rb +34 -0
  266. data/spec/extensions/eval_inspect_spec.rb +67 -0
  267. data/spec/extensions/force_encoding_spec.rb +4 -2
  268. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  269. data/spec/extensions/identity_map_spec.rb +142 -24
  270. data/spec/extensions/inflector_spec.rb +0 -4
  271. data/spec/extensions/instance_filters_spec.rb +11 -21
  272. data/spec/extensions/instance_hooks_spec.rb +72 -0
  273. data/spec/extensions/json_serializer_spec.rb +49 -12
  274. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  275. data/spec/extensions/list_spec.rb +49 -40
  276. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  277. data/spec/extensions/many_through_many_spec.rb +368 -254
  278. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  279. data/spec/extensions/migration_spec.rb +140 -35
  280. data/spec/extensions/named_timezones_spec.rb +29 -11
  281. data/spec/extensions/nested_attributes_spec.rb +268 -89
  282. data/spec/extensions/null_dataset_spec.rb +85 -0
  283. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  284. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  285. data/spec/extensions/pg_array_spec.rb +324 -0
  286. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  287. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  288. data/spec/extensions/pg_hstore_spec.rb +200 -0
  289. data/spec/extensions/pg_inet_spec.rb +47 -0
  290. data/spec/extensions/pg_interval_spec.rb +72 -0
  291. data/spec/extensions/pg_json_spec.rb +99 -0
  292. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  293. data/spec/extensions/pg_range_spec.rb +395 -0
  294. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  295. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  296. data/spec/extensions/pg_row_spec.rb +340 -0
  297. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  298. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  299. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  300. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  301. data/spec/extensions/prepared_statements_spec.rb +87 -0
  302. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  303. data/spec/extensions/pretty_table_spec.rb +7 -6
  304. data/spec/extensions/query_literals_spec.rb +167 -0
  305. data/spec/extensions/query_spec.rb +9 -3
  306. data/spec/extensions/rcte_tree_spec.rb +50 -43
  307. data/spec/extensions/schema_caching_spec.rb +41 -0
  308. data/spec/extensions/schema_dumper_spec.rb +434 -49
  309. data/spec/extensions/schema_spec.rb +30 -49
  310. data/spec/extensions/select_remove_spec.rb +38 -0
  311. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  312. data/spec/extensions/serialization_spec.rb +86 -48
  313. data/spec/extensions/server_block_spec.rb +90 -0
  314. data/spec/extensions/sharding_spec.rb +69 -143
  315. data/spec/extensions/single_table_inheritance_spec.rb +65 -29
  316. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  317. data/spec/extensions/spec_helper.rb +34 -67
  318. data/spec/extensions/split_array_nil_spec.rb +24 -0
  319. data/spec/extensions/sql_expr_spec.rb +29 -60
  320. data/spec/extensions/static_cache_spec.rb +145 -0
  321. data/spec/extensions/subclasses_spec.rb +14 -0
  322. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  323. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  324. data/spec/extensions/timestamps_spec.rb +6 -6
  325. data/spec/extensions/to_dot_spec.rb +8 -11
  326. data/spec/extensions/touch_spec.rb +53 -14
  327. data/spec/extensions/tree_spec.rb +11 -26
  328. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  329. data/spec/extensions/update_primary_key_spec.rb +30 -24
  330. data/spec/extensions/validation_class_methods_spec.rb +77 -68
  331. data/spec/extensions/validation_helpers_spec.rb +48 -37
  332. data/spec/extensions/xml_serializer_spec.rb +29 -4
  333. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  334. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  335. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  336. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  337. data/spec/integration/associations_test.rb +659 -21
  338. data/spec/integration/database_test.rb +25 -5
  339. data/spec/integration/dataset_test.rb +729 -141
  340. data/spec/integration/eager_loader_test.rb +38 -54
  341. data/spec/integration/migrator_test.rb +2 -3
  342. data/spec/integration/model_test.rb +81 -2
  343. data/spec/integration/plugin_test.rb +871 -160
  344. data/spec/integration/prepared_statement_test.rb +272 -128
  345. data/spec/integration/schema_test.rb +377 -57
  346. data/spec/integration/spec_helper.rb +49 -32
  347. data/spec/integration/timezone_test.rb +38 -12
  348. data/spec/integration/transaction_test.rb +183 -8
  349. data/spec/integration/type_test.rb +40 -8
  350. data/spec/model/association_reflection_spec.rb +207 -8
  351. data/spec/model/associations_spec.rb +1206 -693
  352. data/spec/model/base_spec.rb +334 -100
  353. data/spec/model/dataset_methods_spec.rb +45 -27
  354. data/spec/model/eager_loading_spec.rb +828 -692
  355. data/spec/model/hooks_spec.rb +355 -67
  356. data/spec/model/model_spec.rb +251 -179
  357. data/spec/model/plugins_spec.rb +24 -13
  358. data/spec/model/record_spec.rb +506 -232
  359. data/spec/model/spec_helper.rb +16 -77
  360. data/spec/model/validations_spec.rb +38 -2
  361. data/spec/rcov.opts +2 -0
  362. metadata +223 -81
  363. data/spec/core/core_sql_spec.rb +0 -451
@@ -1,9 +1,4 @@
1
1
  require 'sqlite3'
2
- begin
3
- SQLite3::Database.instance_method(:type_translation)
4
- rescue
5
- raise(Sequel::Error, "SQLite3::Database#type_translation is not defined. If you are using the sqlite3 gem, please install the sqlite3-ruby gem.")
6
- end
7
2
  Sequel.require 'adapters/shared/sqlite'
8
3
 
9
4
  module Sequel
@@ -11,21 +6,62 @@ module Sequel
11
6
  # for Sequel.
12
7
  module SQLite
13
8
  TYPE_TRANSLATOR = tt = Class.new do
14
- FALSE_VALUES = %w'0 false f no n'.freeze
15
- def boolean(s) !FALSE_VALUES.include?(s.downcase) end
16
- def blob(s) ::Sequel::SQL::Blob.new(s) end
17
- def integer(s) s.to_i end
18
- def float(s) s.to_f end
19
- def numeric(s) ::BigDecimal.new(s) rescue s end
20
- def date(s) ::Sequel.string_to_date(s) end
21
- def time(s) ::Sequel.string_to_time(s) end
22
- def timestamp(s) ::Sequel.database_to_application_timestamp(s) end
9
+ FALSE_VALUES = (%w'0 false f no n' + [0]).freeze
10
+
11
+ def blob(s)
12
+ Sequel::SQL::Blob.new(s.to_s)
13
+ end
14
+
15
+ def boolean(s)
16
+ s = s.downcase if s.is_a?(String)
17
+ !FALSE_VALUES.include?(s)
18
+ end
19
+
20
+ def date(s)
21
+ case s
22
+ when String
23
+ Sequel.string_to_date(s)
24
+ when Integer
25
+ Date.jd(s)
26
+ when Float
27
+ Date.jd(s.to_i)
28
+ else
29
+ raise Sequel::Error, "unhandled type when converting to date: #{s.inspect} (#{s.class.inspect})"
30
+ end
31
+ end
32
+
33
+ def integer(s)
34
+ s.to_i
35
+ end
36
+
37
+ def float(s)
38
+ s.to_f
39
+ end
40
+
41
+ def numeric(s)
42
+ s = s.to_s unless s.is_a?(String)
43
+ ::BigDecimal.new(s) rescue s
44
+ end
45
+
46
+ def time(s)
47
+ case s
48
+ when String
49
+ Sequel.string_to_time(s)
50
+ when Integer
51
+ Sequel::SQLTime.create(s/3600, (s % 3600)/60, s % 60)
52
+ when Float
53
+ s, f = s.divmod(1)
54
+ Sequel::SQLTime.create(s/3600, (s % 3600)/60, s % 60, (f*1000000).round)
55
+ else
56
+ raise Sequel::Error, "unhandled type when converting to date: #{s.inspect} (#{s.class.inspect})"
57
+ end
58
+ end
59
+
23
60
  end.new
24
61
 
25
62
  # Hash with string keys and callable values for converting SQLite types.
26
63
  SQLITE_TYPES = {}
27
64
  {
28
- %w'timestamp datetime' => tt.method(:timestamp),
29
65
  %w'date' => tt.method(:date),
30
66
  %w'time' => tt.method(:time),
31
67
  %w'bit bool boolean' => tt.method(:boolean),
@@ -51,6 +87,16 @@ module Sequel
51
87
  end
52
88
 
53
89
  private_class_method :uri_to_options
90
+
91
+ # The conversion procs to use for this database
92
+ attr_reader :conversion_procs
93
+
94
+ def initialize(opts={})
95
+ super
96
+ @conversion_procs = SQLITE_TYPES.dup
97
+ @conversion_procs['datetime'] = @conversion_procs['timestamp'] = method(:to_application_timestamp)
98
+ set_integer_booleans
99
+ end
54
100
 
55
101
  # Connect to the database. Since SQLite is a file based database,
56
102
  # the only options available are :database (to specify the database
@@ -71,10 +117,11 @@ module Sequel
71
117
 
72
118
  db
73
119
  end
74
-
75
- # Return instance of Sequel::SQLite::Dataset with the given options.
76
- def dataset(opts = nil)
77
- SQLite::Dataset.new(self, opts)
120
+
121
+ # Disconnect given connections from the database.
122
+ def disconnect_connection(c)
123
+ c.prepared_statements.each_value{|v| v.first.close}
124
+ c.close
78
125
  end
79
126
 
80
127
  # Run the given SQL with the given arguments and yield each row.
@@ -103,11 +150,20 @@ module Sequel
103
150
  _execute(:insert, sql, opts)
104
151
  end
105
152
 
106
- # Run the given SQL with the given arguments and return the first value of the first row.
107
- def single_value(sql, opts={})
108
- _execute(:single_value, sql, opts)
153
+ # Handle Integer and Float arguments, since SQLite can store timestamps as integers and floats.
154
+ def to_application_timestamp(s)
155
+ case s
156
+ when String
157
+ super
158
+ when Integer
159
+ super(Time.at(s).to_s)
160
+ when Float
161
+ super(DateTime.jd(s).to_s)
162
+ else
163
+ raise Sequel::Error, "unhandled type when converting to : #{s.inspect} (#{s.class.inspect})"
164
+ end
109
165
  end
110
-
166
+
111
167
  private
112
168
 
113
169
  # Yield an available connection. Rescue
@@ -117,12 +173,11 @@ module Sequel
117
173
  synchronize(opts[:server]) do |conn|
118
174
  return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
119
175
  log_args = opts[:arguments]
120
- args = opts.fetch(:arguments, [])
176
+ args = {}
177
+ opts.fetch(:arguments, {}).each{|k, v| args[k] = prepared_statement_argument(v)}
121
178
  case type
122
179
  when :select
123
180
  log_yield(sql, log_args){conn.query(sql, args, &block)}
124
- when :single_value
125
- log_yield(sql, log_args){conn.get_first_value(sql, args)}
126
181
  when :insert
127
182
  log_yield(sql, log_args){conn.execute(sql, args)}
128
183
  conn.last_insert_row_id
@@ -160,7 +215,7 @@ module Sequel
160
215
 
161
216
  # Execute a prepared statement on the database using the given name.
162
217
  def execute_prepared_statement(conn, type, name, opts, &block)
163
- ps = prepared_statements[name]
218
+ ps = prepared_statement(name)
164
219
  sql = ps.prepared_sql
165
220
  args = opts[:arguments]
166
221
  ps_args = {}
@@ -173,13 +228,19 @@ module Sequel
173
228
  end
174
229
  end
175
230
  unless cps
176
- cps = conn.prepare(sql)
231
+ cps = log_yield("PREPARE #{name}: #{sql}"){conn.prepare(sql)}
177
232
  conn.prepared_statements[name] = [cps, sql]
178
233
  end
234
+ log_sql = "EXECUTE #{name}"
235
+ if ps.log_sql
236
+ log_sql << " ("
237
+ log_sql << sql
238
+ log_sql << ")"
239
+ end
179
240
  if block
180
- log_yield("Executing prepared statement #{name}", args){cps.execute(ps_args, &block)}
241
+ log_yield(log_sql, args){cps.execute(ps_args, &block)}
181
242
  else
182
- log_yield("Executing prepared statement #{name}", args){cps.execute!(ps_args){|r|}}
243
+ log_yield(log_sql, args){cps.execute!(ps_args){|r|}}
183
244
  case type
184
245
  when :insert
185
246
  conn.last_insert_row_id
@@ -189,21 +250,18 @@ module Sequel
189
250
  end
190
251
  end
191
252
 
192
- # The main error class that SQLite3 raises
253
+ # SQLite3 raises ArgumentError in addition to SQLite3::Exception in
254
+ # some cases, such as operations on a closed database.
193
255
  def database_error_classes
194
- [SQLite3::Exception]
195
- end
196
-
197
- # Disconnect given connections from the database.
198
- def disconnect_connection(c)
199
- c.prepared_statements.each_value{|v| v.first.close}
200
- c.close
256
+ [SQLite3::Exception, ArgumentError]
201
257
  end
202
258
  end
203
259
 
204
260
  # Dataset class for SQLite datasets that use the ruby-sqlite3 driver.
205
261
  class Dataset < Sequel::Dataset
206
262
  include ::Sequel::SQLite::DatasetMethods
263
+
264
+ Database::DatasetClass = self
207
265
 
208
266
  PREPARED_ARG_PLACEHOLDER = ':'.freeze
209
267
 
@@ -217,7 +275,7 @@ module Sequel
217
275
  # but with the keys converted to strings.
218
276
  def map_to_prepared_args(hash)
219
277
  args = {}
220
- hash.each{|k,v| args[k.to_s] = v}
278
+ hash.each{|k,v| args[k.to_s.gsub('.', '__')] = v}
221
279
  args
222
280
  end
223
281
 
@@ -226,7 +284,12 @@ module Sequel
226
284
  # SQLite uses a : before the name of the argument for named
227
285
  # arguments.
228
286
  def prepared_arg(k)
229
- LiteralString.new("#{prepared_arg_placeholder}#{k}")
287
+ LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}")
288
+ end
289
+
290
+ # Always assume a prepared argument.
291
+ def prepared_arg?(k)
292
+ true
230
293
  end
231
294
  end
232
295
 
@@ -287,14 +350,15 @@ module Sequel
287
350
  def fetch_rows(sql)
288
351
  execute(sql) do |result|
289
352
  i = -1
290
- type_procs = result.types.map{|t| SQLITE_TYPES[base_type_name(t)]}
353
+ cps = db.conversion_procs
354
+ type_procs = result.types.map{|t| cps[base_type_name(t)]}
291
355
  cols = result.columns.map{|c| i+=1; [output_identifier(c), i, type_procs[i]]}
292
356
  @columns = cols.map{|c| c.first}
293
357
  result.each do |values|
294
358
  row = {}
295
359
  cols.each do |name,i,type_proc|
296
360
  v = values[i]
297
- if type_proc && v.is_a?(String)
361
+ if type_proc && v
298
362
  v = type_proc.call(v)
299
363
  end
300
364
  row[name] = v
@@ -312,9 +376,8 @@ module Sequel
312
376
  ps.extend(PreparedStatementMethods)
313
377
  if name
314
378
  ps.prepared_statement_name = name
315
- db.prepared_statements[name] = ps
379
+ db.set_prepared_statement(name, ps)
316
380
  end
317
- ps.prepared_sql
318
381
  ps
319
382
  end
320
383
 
@@ -326,8 +389,8 @@ module Sequel
326
389
  end
327
390
 
328
391
  # Quote the string using the adapter class method.
329
- def literal_string(v)
330
- "'#{::SQLite3::Database.quote(v)}'"
392
+ def literal_string_append(sql, v)
393
+ sql << "'" << ::SQLite3::Database.quote(v) << "'"
331
394
  end
332
395
 
333
396
  # SQLite uses a : before the name of the argument as a placeholder.
@@ -1,3 +1,4 @@
1
+ require 'swift/db/mysql'
1
2
  Sequel.require 'adapters/shared/mysql'
2
3
 
3
4
  module Sequel
@@ -9,11 +10,6 @@ module Sequel
9
10
  module DatabaseMethods
10
11
  include Sequel::MySQL::DatabaseMethods
11
12
 
12
- # Return instance of Sequel::Swift::MySQL::Dataset with the given opts.
13
- def dataset(opts=nil)
14
- Sequel::Swift::MySQL::Dataset.new(self, opts)
15
- end
16
-
17
13
  private
18
14
 
19
15
  # The database name for the given database.
@@ -25,22 +21,24 @@ module Sequel
25
21
  def schema_column_type(db_type)
26
22
  db_type == 'tinyint(1)' ? :boolean : super
27
23
  end
24
+
25
+ # Apply the connectiong setting SQLs for every new connection.
26
+ def setup_connection(conn)
27
+ mysql_connection_setting_sqls.each{|sql| log_yield(sql){conn.execute(sql)}}
28
+ super
29
+ end
28
30
  end
29
31
 
30
32
  # Dataset class for MySQL datasets accessed via Swift.
31
33
  class Dataset < Swift::Dataset
32
34
  include Sequel::MySQL::DatasetMethods
33
-
34
- # Use execute_insert to execute the replace_sql.
35
- def replace(*args)
36
- execute_insert(replace_sql(*args))
37
- end
35
+ APOS = Dataset::APOS
38
36
 
39
37
  private
40
38
 
41
39
  # Use Swift's escape method for quoting.
42
- def literal_string(s)
43
- db.synchronize{|c| "'#{c.escape(s)}'"}
40
+ def literal_string_append(sql, s)
41
+ sql << APOS << db.synchronize{|c| c.escape(s)} << APOS
44
42
  end
45
43
  end
46
44
  end
@@ -1,33 +1,13 @@
1
+ require 'swift/db/postgres'
1
2
  Sequel.require 'adapters/shared/postgres'
2
3
 
3
4
  module Sequel
4
- Postgres::CONVERTED_EXCEPTIONS << ::SwiftError
5
+ Postgres::CONVERTED_EXCEPTIONS << ::Swift::Error
5
6
 
6
7
  module Swift
7
8
  # Adapter, Database, and Dataset support for accessing a PostgreSQL
8
9
  # database via Swift.
9
10
  module Postgres
10
- # Methods to add to the Swift adapter/connection to allow it to work
11
- # with the shared PostgreSQL code.
12
- module AdapterMethods
13
- include Sequel::Postgres::AdapterMethods
14
-
15
- # Log all SQL that goes through the execute method to the related
16
- # database object.
17
- def execute(sql, *args)
18
- @db.log_yield(sql){super}
19
- rescue SwiftError => e
20
- @db.send(:raise_error, e)
21
- end
22
-
23
- private
24
-
25
- # Swift specific method of getting specific values from a result set.
26
- def single_value(row)
27
- row.values.at(0)
28
- end
29
- end
30
-
31
11
  # Methods to add to Database instances that access PostgreSQL via Swift.
32
12
  module DatabaseMethods
33
13
  include Sequel::Postgres::DatabaseMethods
@@ -35,75 +15,29 @@ module Sequel
35
15
  # Add the primary_keys and primary_key_sequences instance variables,
36
16
  # so we can get the correct return values for inserted rows.
37
17
  def self.extended(db)
38
- db.instance_eval do
39
- @primary_keys = {}
40
- @primary_key_sequences = {}
41
- end
42
- end
43
-
44
- # Return instance of Sequel::Swift::Postgres::Dataset with the given opts.
45
- def dataset(opts=nil)
46
- Sequel::Swift::Postgres::Dataset.new(self, opts)
47
- end
48
-
49
- # Run the SELECT SQL on the database and yield the rows
50
- def execute(sql, opts={})
51
- synchronize(opts[:server]) do |conn|
52
- begin
53
- res = conn.execute(sql)
54
- yield res if block_given?
55
- nil
56
- rescue SwiftError => e
57
- raise_error(e)
58
- end
59
- end
60
- end
61
-
62
- # Run the DELETE/UPDATE SQL on the database and return the number
63
- # of matched rows.
64
- def execute_dui(sql, opts={})
65
- synchronize(opts[:server]) do |conn|
66
- begin
67
- conn.execute(sql).rows
68
- rescue SwiftError => e
69
- raise_error(e)
70
- end
71
- end
72
- end
73
-
74
- # Run the INSERT SQL on the database and return the primary key
75
- # for the record.
76
- def execute_insert(sql, opts={})
77
- synchronize(opts[:server]) do |conn|
78
- begin
79
- conn.execute(sql)
80
- insert_result(conn, opts[:table], opts[:values])
81
- rescue SwiftError => e
82
- raise_error(e)
83
- end
84
- end
18
+ db.send(:initialize_postgres_adapter)
85
19
  end
86
20
 
87
21
  private
88
22
 
89
- # Execute SQL on the connection.
90
- def log_connection_execute(conn, sql)
91
- conn.execute(sql)
23
+ # Remove all other options except for ones specifically handled, as
24
+ # otherwise swift passes them to dbic++ which passes them to PostgreSQL
25
+ # which can raise an error.
26
+ def server_opts(o)
27
+ o = super
28
+ so = {}
29
+ [:db, :user, :password, :host, :port].each{|s| so[s] = o[s] if o.has_key?(s)}
30
+ so
92
31
  end
93
32
 
94
33
  # Extend the adapter with the Swift PostgreSQL AdapterMethods.
95
34
  def setup_connection(conn)
96
35
  conn = super(conn)
97
- conn.extend(Sequel::Swift::Postgres::AdapterMethods)
98
- conn.db = self
99
- conn.apply_connection_settings
36
+ conn.native_bind_format = true
37
+ connection_configuration_sqls.each{|sql| log_yield(sql){conn.execute(sql)}}
100
38
  conn
101
39
  end
102
40
  end
103
-
104
- class Dataset < Swift::Dataset
105
- include Sequel::Postgres::DatasetMethods
106
- end
107
41
  end
108
42
  end
109
43
  end
@@ -1,3 +1,4 @@
1
+ require 'swift/db/sqlite3'
1
2
  Sequel.require 'adapters/shared/sqlite'
2
3
 
3
4
  module Sequel
@@ -8,10 +9,12 @@ module Sequel
8
9
  # Database instance methods for SQLite databases accessed via Swift.
9
10
  module DatabaseMethods
10
11
  include Sequel::SQLite::DatabaseMethods
11
-
12
- # Return instance of Sequel::Swift::SQL::Dataset with the given opts.
13
- def dataset(opts=nil)
14
- Sequel::Swift::SQLite::Dataset.new(self, opts)
12
+
13
+ # Set the correct pragmas on the connection.
14
+ def connect(opts)
15
+ c = super
16
+ connection_pragmas.each{|s| log_yield(s){c.execute(s)}}
17
+ c
15
18
  end
16
19
  end
17
20
 
@@ -22,8 +25,8 @@ module Sequel
22
25
  private
23
26
 
24
27
  # Use Swift's escape method for quoting.
25
- def literal_string(s)
26
- db.synchronize{|c| "#{c.escape(s)}"}
28
+ def literal_string_append(sql, s)
29
+ sql << APOS << db.synchronize{|c| c.escape(s)} << APOS
27
30
  end
28
31
  end
29
32
  end
@@ -1,11 +1,8 @@
1
- require 'swift'
2
-
3
1
  module Sequel
4
- # Module holding the Swift support for Sequel. Swift is a
5
- # ruby front-end for dbic++, a fast database access library
6
- # written in C++.
2
+ # Module holding the Swift DB support for Sequel. Swift DB is a
3
+ # collection of drivers used in Swift ORM.
7
4
  #
8
- # The Swift adapter currently supports PostgreSQL and MySQL:
5
+ # The Swift adapter currently supports PostgreSQL, MySQL and SQLite3
9
6
  #
10
7
  # Sequel.connect('swift://user:password@host/database?db_type=postgres')
11
8
  # Sequel.connect('swift://user:password@host/database?db_type=mysql')
@@ -15,17 +12,21 @@ module Sequel
15
12
  DATABASE_SETUP = {:postgres=>proc do |db|
16
13
  Sequel.ts_require 'adapters/swift/postgres'
17
14
  db.extend(Sequel::Swift::Postgres::DatabaseMethods)
15
+ db.extend_datasets Sequel::Postgres::DatasetMethods
18
16
  db.swift_class = ::Swift::DB::Postgres
19
17
  end,
20
18
  :mysql=>proc do |db|
21
19
  Sequel.ts_require 'adapters/swift/mysql'
22
20
  db.extend(Sequel::Swift::MySQL::DatabaseMethods)
21
+ db.dataset_class = Sequel::Swift::MySQL::Dataset
23
22
  db.swift_class = ::Swift::DB::Mysql
24
23
  end,
25
24
  :sqlite=>proc do |db|
26
25
  Sequel.ts_require 'adapters/swift/sqlite'
27
26
  db.extend(Sequel::Swift::SQLite::DatabaseMethods)
27
+ db.dataset_class = Sequel::Swift::SQLite::Dataset
28
28
  db.swift_class = ::Swift::DB::Sqlite3
29
+ db.set_integer_booleans
29
30
  end,
30
31
  }
31
32
 
@@ -56,14 +57,11 @@ module Sequel
56
57
 
57
58
  # Create an instance of swift_class for the given options.
58
59
  def connect(server)
59
- setup_connection(swift_class.new(server_opts(server)))
60
+ opts = server_opts(server)
61
+ opts[:pass] = opts[:password]
62
+ setup_connection(swift_class.new(opts))
60
63
  end
61
64
 
62
- # Return a Sequel::Swift::Dataset object for this database.
63
- def dataset(opts = nil)
64
- Swift::Dataset.new(self, opts)
65
- end
66
-
67
65
  # Execute the given SQL, yielding a Swift::Result if a block is given.
68
66
  def execute(sql, opts={})
69
67
  synchronize(opts[:server]) do |conn|
@@ -71,7 +69,7 @@ module Sequel
71
69
  res = log_yield(sql){conn.execute(sql)}
72
70
  yield res if block_given?
73
71
  nil
74
- rescue SwiftError => e
72
+ rescue ::Swift::Error => e
75
73
  raise_error(e)
76
74
  end
77
75
  end
@@ -82,8 +80,8 @@ module Sequel
82
80
  def execute_dui(sql, opts={})
83
81
  synchronize(opts[:server]) do |conn|
84
82
  begin
85
- log_yield(sql){conn.execute(sql).rows}
86
- rescue SwiftError => e
83
+ log_yield(sql){conn.execute(sql).affected_rows}
84
+ rescue ::Swift::Error => e
87
85
  raise_error(e)
88
86
  end
89
87
  end
@@ -95,7 +93,7 @@ module Sequel
95
93
  synchronize(opts[:server]) do |conn|
96
94
  begin
97
95
  log_yield(sql){conn.execute(sql).insert_id}
98
- rescue SwiftError => e
96
+ rescue ::Swift::Error => e
99
97
  raise_error(e)
100
98
  end
101
99
  end
@@ -109,15 +107,10 @@ module Sequel
109
107
  :execute
110
108
  end
111
109
 
112
- # Close the given database connection.
113
- def disconnect_connection(c)
114
- end
115
-
116
- # Execute SQL on the connection
117
- def log_connection_execute(conn, sql)
118
- log_yield(sql){conn.execute(sql)}
110
+ def database_error_classes
111
+ [::Swift::Error]
119
112
  end
120
-
113
+
121
114
  # Set the :db entry to the same as the :database entry, since
122
115
  # Swift uses :db.
123
116
  def server_opts(o)
@@ -134,11 +127,22 @@ module Sequel
134
127
  end
135
128
 
136
129
  class Dataset < Sequel::Dataset
130
+ Database::DatasetClass = self
131
+
137
132
  # Set the columns and yield the hashes to the block.
138
- def fetch_rows(sql, &block)
133
+ def fetch_rows(sql)
139
134
  execute(sql) do |res|
140
- @columns = res.fields
141
- res.each(&block)
135
+ col_map = {}
136
+ @columns = res.fields.map do |c|
137
+ col_map[c] = output_identifier(c)
138
+ end
139
+ res.each do |r|
140
+ h = {}
141
+ r.each do |k, v|
142
+ h[col_map[k]] = v.is_a?(StringIO) ? SQL::Blob.new(v.read) : v
143
+ end
144
+ yield h
145
+ end
142
146
  end
143
147
  self
144
148
  end