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,28 +1,33 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
2
 
3
- # H2 and MSSQL don't support USING joins
4
- unless [:h2, :mssql].include?(INTEGRATION_DB.database_type)
3
+ # DB2 does not seem to support USING joins in every version; it seems to be
4
+ # valid expression in DB2 iSeries UDB though.
5
+ unless !INTEGRATION_DB.dataset.supports_join_using? || Sequel.guarded?(:db2)
5
6
  describe "Class Table Inheritance Plugin" do
6
- before do
7
+ before(:all) do
7
8
  @db = INTEGRATION_DB
8
9
  @db.instance_variable_set(:@schemas, {})
9
- @db.create_table!(:employees) do
10
+ @db.drop_table?(:staff, :executives, :managers, :employees)
11
+ @db.create_table(:employees) do
10
12
  primary_key :id
11
13
  String :name
12
14
  String :kind
13
15
  end
14
- @db.create_table!(:managers) do
16
+ @db.create_table(:managers) do
15
17
  foreign_key :id, :employees, :primary_key=>true
16
18
  Integer :num_staff
17
19
  end
18
- @db.create_table!(:executives) do
20
+ @db.create_table(:executives) do
19
21
  foreign_key :id, :managers, :primary_key=>true
20
22
  Integer :num_managers
21
23
  end
22
- @db.create_table!(:staff) do
24
+ @db.create_table(:staff) do
23
25
  foreign_key :id, :employees, :primary_key=>true
24
26
  foreign_key :manager_id, :managers
25
27
  end
28
+ end
29
+ before do
30
+ [:staff, :executives, :managers, :employees].each{|t| @db[t].delete}
26
31
  class ::Employee < Sequel::Model(@db)
27
32
  plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}
28
33
  end
@@ -32,7 +37,7 @@ describe "Class Table Inheritance Plugin" do
32
37
  class ::Executive < Manager
33
38
  end
34
39
  class ::Staff < Employee
35
- many_to_one :manager
40
+ many_to_one :manager, :qualify=>false
36
41
  end
37
42
 
38
43
  @i1 =@db[:employees].insert(:name=>'E', :kind=>'Employee')
@@ -43,13 +48,13 @@ describe "Class Table Inheritance Plugin" do
43
48
  @db[:managers].insert(:id=>@i4, :num_staff=>5)
44
49
  @db[:executives].insert(:id=>@i4, :num_managers=>6)
45
50
  @db[:staff].insert(:id=>@i2, :manager_id=>@i4)
46
-
47
- clear_sqls
48
51
  end
49
52
  after do
50
- @db.drop_table :staff, :executives, :managers, :employees
51
53
  [:Executive, :Manager, :Staff, :Employee].each{|s| Object.send(:remove_const, s)}
52
54
  end
55
+ after(:all) do
56
+ @db.drop_table? :staff, :executives, :managers, :employees
57
+ end
53
58
 
54
59
  specify "should return rows as subclass instances" do
55
60
  Employee.order(:id).all.should == [
@@ -94,8 +99,7 @@ describe "Class Table Inheritance Plugin" do
94
99
  Employee.filter(:id=>@i2).all.first.manager.id.should == @i4
95
100
  end
96
101
 
97
- # See http://www.sqlite.org/src/tktview/3338b3fa19ac4abee6c475126a2e6d9d61f26ab1
98
- cspecify "should insert rows into all tables", :sqlite do
102
+ cspecify "should insert rows into all tables", [proc{|db| db.sqlite_version < 30709}, :sqlite] do
99
103
  e = Executive.create(:name=>'Ex2', :num_managers=>8, :num_staff=>9)
100
104
  i = e.id
101
105
  @db[:employees][:id=>i].should == {:id=>i, :name=>'Ex2', :kind=>'Executive'}
@@ -110,17 +114,17 @@ describe "Class Table Inheritance Plugin" do
110
114
  @db[:executives][:id=>@i4].should == {:id=>@i4, :num_managers=>8}
111
115
  end
112
116
 
113
- cspecify "should handle many_to_one relationships", :sqlite do
117
+ specify "should handle many_to_one relationships" do
114
118
  m = Staff.first.manager
115
119
  m.should == Manager[@i4]
116
120
  m.should be_a_kind_of(Executive)
117
121
  end
118
122
 
119
- cspecify "should handle eagerly loading many_to_one relationships", :sqlite do
123
+ specify "should handle eagerly loading many_to_one relationships" do
120
124
  Staff.limit(1).eager(:manager).all.map{|x| x.manager}.should == [Manager[@i4]]
121
125
  end
122
126
 
123
- cspecify "should handle eagerly graphing many_to_one relationships", :sqlite do
127
+ specify "should handle eagerly graphing many_to_one relationships" do
124
128
  ss = Staff.eager_graph(:manager).all
125
129
  ss.should == [Staff[@i2]]
126
130
  ss.map{|x| x.manager}.should == [Manager[@i4]]
@@ -134,7 +138,7 @@ describe "Class Table Inheritance Plugin" do
134
138
  Executive.limit(1).eager(:staff_members).first.staff_members.should == [Staff[@i2]]
135
139
  end
136
140
 
137
- cspecify "should handle eagerly graphing one_to_many relationships", :sqlite do
141
+ cspecify "should handle eagerly graphing one_to_many relationships", [proc{|db| db.sqlite_version < 30709}, :sqlite] do
138
142
  es = Executive.limit(1).eager_graph(:staff_members).all
139
143
  es.should == [Executive[@i4]]
140
144
  es.map{|x| x.staff_members}.should == [[Staff[@i2]]]
@@ -143,21 +147,25 @@ end
143
147
  end
144
148
 
145
149
  describe "Many Through Many Plugin" do
146
- before do
150
+ before(:all) do
147
151
  @db = INTEGRATION_DB
148
152
  @db.instance_variable_set(:@schemas, {})
149
- @db.create_table!(:albums) do
153
+ @db.drop_table?(:albums_artists, :albums, :artists)
154
+ @db.create_table(:albums) do
150
155
  primary_key :id
151
156
  String :name
152
157
  end
153
- @db.create_table!(:artists) do
158
+ @db.create_table(:artists) do
154
159
  primary_key :id
155
160
  String :name
156
161
  end
157
- @db.create_table!(:albums_artists) do
162
+ @db.create_table(:albums_artists) do
158
163
  foreign_key :album_id, :albums
159
164
  foreign_key :artist_id, :artists
160
165
  end
166
+ end
167
+ before do
168
+ [:albums_artists, :albums, :artists].each{|t| @db[t].delete}
161
169
  class ::Album < Sequel::Model(@db)
162
170
  many_to_many :artists
163
171
  end
@@ -181,21 +189,31 @@ describe "Many Through Many Plugin" do
181
189
  @album4 = Album.create(:name=>'D')
182
190
  @album4.add_artist(@artist1)
183
191
  @album4.add_artist(@artist4)
184
-
185
- clear_sqls
186
192
  end
187
193
  after do
188
- @db.drop_table :albums_artists, :albums, :artists
189
194
  [:Album, :Artist].each{|s| Object.send(:remove_const, s)}
190
195
  end
196
+ after(:all) do
197
+ @db.drop_table? :albums_artists, :albums, :artists
198
+ end
191
199
 
200
+ def self_join(c)
201
+ c.join(Sequel.as(c.table_name, :b), Array(c.primary_key).zip(Array(c.primary_key))).select_all(c.table_name)
202
+ end
203
+
192
204
  specify "should handle super simple case with 1 join table" do
193
205
  Artist.many_through_many :albums, [[:albums_artists, :artist_id, :album_id]]
194
- Artist[1].albums.map{|x| x.name}.sort.should == %w'A D'
195
- Artist[2].albums.map{|x| x.name}.sort.should == %w'A C'
196
- Artist[3].albums.map{|x| x.name}.sort.should == %w'B C'
197
- Artist[4].albums.map{|x| x.name}.sort.should == %w'B D'
206
+ Artist[@artist1.id].albums.map{|x| x.name}.sort.should == %w'A D'
207
+ Artist[@artist2.id].albums.map{|x| x.name}.sort.should == %w'A C'
208
+ Artist[@artist3.id].albums.map{|x| x.name}.sort.should == %w'B C'
209
+ Artist[@artist4.id].albums.map{|x| x.name}.sort.should == %w'B D'
198
210
 
211
+ Artist.plugin :prepared_statements_associations
212
+ Artist[@artist1.id].albums.map{|x| x.name}.sort.should == %w'A D'
213
+ Artist[@artist2.id].albums.map{|x| x.name}.sort.should == %w'A C'
214
+ Artist[@artist3.id].albums.map{|x| x.name}.sort.should == %w'B C'
215
+ Artist[@artist4.id].albums.map{|x| x.name}.sort.should == %w'B D'
216
+
199
217
  Artist.filter(:id=>1).eager(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'A D'
200
218
  Artist.filter(:id=>2).eager(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'A C'
201
219
  Artist.filter(:id=>3).eager(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'B C'
@@ -205,24 +223,102 @@ describe "Many Through Many Plugin" do
205
223
  Artist.filter(:artists__id=>2).eager_graph(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'A C'
206
224
  Artist.filter(:artists__id=>3).eager_graph(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'B C'
207
225
  Artist.filter(:artists__id=>4).eager_graph(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'B D'
226
+
227
+ Artist.filter(:albums=>@album1).all.map{|a| a.name}.sort.should == %w'1 2'
228
+ Artist.filter(:albums=>@album2).all.map{|a| a.name}.sort.should == %w'3 4'
229
+ Artist.filter(:albums=>@album3).all.map{|a| a.name}.sort.should == %w'2 3'
230
+ Artist.filter(:albums=>@album4).all.map{|a| a.name}.sort.should == %w'1 4'
231
+
232
+ Artist.exclude(:albums=>@album1).all.map{|a| a.name}.sort.should == %w'3 4'
233
+ Artist.exclude(:albums=>@album2).all.map{|a| a.name}.sort.should == %w'1 2'
234
+ Artist.exclude(:albums=>@album3).all.map{|a| a.name}.sort.should == %w'1 4'
235
+ Artist.exclude(:albums=>@album4).all.map{|a| a.name}.sort.should == %w'2 3'
236
+
237
+ Artist.filter(:albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'1 2 3'
238
+ Artist.filter(:albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w'1 3 4'
239
+
240
+ Artist.exclude(:albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'4'
241
+ Artist.exclude(:albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w'2'
242
+
243
+ Artist.filter(:albums=>Album.filter(:id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'1 2 3'
244
+ Artist.exclude(:albums=>Album.filter(:id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'4'
245
+
246
+ c = self_join(Artist)
247
+ c.filter(:albums=>@album1).all.map{|a| a.name}.sort.should == %w'1 2'
248
+ c.filter(:albums=>@album2).all.map{|a| a.name}.sort.should == %w'3 4'
249
+ c.filter(:albums=>@album3).all.map{|a| a.name}.sort.should == %w'2 3'
250
+ c.filter(:albums=>@album4).all.map{|a| a.name}.sort.should == %w'1 4'
251
+
252
+ c.exclude(:albums=>@album1).all.map{|a| a.name}.sort.should == %w'3 4'
253
+ c.exclude(:albums=>@album2).all.map{|a| a.name}.sort.should == %w'1 2'
254
+ c.exclude(:albums=>@album3).all.map{|a| a.name}.sort.should == %w'1 4'
255
+ c.exclude(:albums=>@album4).all.map{|a| a.name}.sort.should == %w'2 3'
256
+
257
+ c.filter(:albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'1 2 3'
258
+ c.filter(:albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w'1 3 4'
259
+
260
+ c.exclude(:albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'4'
261
+ c.exclude(:albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w'2'
262
+
263
+ c.filter(:albums=>self_join(Album).filter(:albums__id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'1 2 3'
264
+ c.exclude(:albums=>self_join(Album).filter(:albums__id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'4'
208
265
  end
209
266
 
210
267
  specify "should handle typical case with 3 join tables" do
211
268
  Artist.many_through_many :related_artists, [[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_artists, :album_id, :artist_id]], :class=>Artist, :distinct=>true
212
- Artist[1].related_artists.map{|x| x.name}.sort.should == %w'1 2 4'
213
- Artist[2].related_artists.map{|x| x.name}.sort.should == %w'1 2 3'
214
- Artist[3].related_artists.map{|x| x.name}.sort.should == %w'2 3 4'
215
- Artist[4].related_artists.map{|x| x.name}.sort.should == %w'1 3 4'
269
+ Artist[@artist1.id].related_artists.map{|x| x.name}.sort.should == %w'1 2 4'
270
+ Artist[@artist2.id].related_artists.map{|x| x.name}.sort.should == %w'1 2 3'
271
+ Artist[@artist3.id].related_artists.map{|x| x.name}.sort.should == %w'2 3 4'
272
+ Artist[@artist4.id].related_artists.map{|x| x.name}.sort.should == %w'1 3 4'
273
+
274
+ Artist.plugin :prepared_statements_associations
275
+ Artist[@artist1.id].related_artists.map{|x| x.name}.sort.should == %w'1 2 4'
276
+ Artist[@artist2.id].related_artists.map{|x| x.name}.sort.should == %w'1 2 3'
277
+ Artist[@artist3.id].related_artists.map{|x| x.name}.sort.should == %w'2 3 4'
278
+ Artist[@artist4.id].related_artists.map{|x| x.name}.sort.should == %w'1 3 4'
216
279
 
217
- Artist.filter(:id=>1).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 4'
218
- Artist.filter(:id=>2).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 3'
219
- Artist.filter(:id=>3).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'2 3 4'
220
- Artist.filter(:id=>4).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 3 4'
280
+ Artist.filter(:id=>@artist1.id).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 4'
281
+ Artist.filter(:id=>@artist2.id).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 3'
282
+ Artist.filter(:id=>@artist3.id).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'2 3 4'
283
+ Artist.filter(:id=>@artist4.id).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 3 4'
221
284
 
222
- Artist.filter(:artists__id=>1).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 4'
223
- Artist.filter(:artists__id=>2).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 3'
224
- Artist.filter(:artists__id=>3).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'2 3 4'
225
- Artist.filter(:artists__id=>4).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 3 4'
285
+ Artist.filter(:artists__id=>@artist1.id).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 4'
286
+ Artist.filter(:artists__id=>@artist2.id).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 3'
287
+ Artist.filter(:artists__id=>@artist3.id).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'2 3 4'
288
+ Artist.filter(:artists__id=>@artist4.id).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 3 4'
289
+
290
+ Artist.filter(:related_artists=>@artist1).all.map{|a| a.name}.sort.should == %w'1 2 4'
291
+ Artist.filter(:related_artists=>@artist2).all.map{|a| a.name}.sort.should == %w'1 2 3'
292
+ Artist.filter(:related_artists=>@artist3).all.map{|a| a.name}.sort.should == %w'2 3 4'
293
+ Artist.filter(:related_artists=>@artist4).all.map{|a| a.name}.sort.should == %w'1 3 4'
294
+
295
+ Artist.exclude(:related_artists=>@artist1).all.map{|a| a.name}.sort.should == %w'3'
296
+ Artist.exclude(:related_artists=>@artist2).all.map{|a| a.name}.sort.should == %w'4'
297
+ Artist.exclude(:related_artists=>@artist3).all.map{|a| a.name}.sort.should == %w'1'
298
+ Artist.exclude(:related_artists=>@artist4).all.map{|a| a.name}.sort.should == %w'2'
299
+
300
+ Artist.filter(:related_artists=>[@artist1, @artist4]).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
301
+ Artist.exclude(:related_artists=>[@artist1, @artist4]).all.map{|a| a.name}.sort.should == %w''
302
+
303
+ Artist.filter(:related_artists=>Artist.filter(:id=>@artist1.id)).all.map{|a| a.name}.sort.should == %w'1 2 4'
304
+ Artist.exclude(:related_artists=>Artist.filter(:id=>@artist1.id)).all.map{|a| a.name}.sort.should == %w'3'
305
+
306
+ c = self_join(Artist)
307
+ c.filter(:related_artists=>@artist1).all.map{|a| a.name}.sort.should == %w'1 2 4'
308
+ c.filter(:related_artists=>@artist2).all.map{|a| a.name}.sort.should == %w'1 2 3'
309
+ c.filter(:related_artists=>@artist3).all.map{|a| a.name}.sort.should == %w'2 3 4'
310
+ c.filter(:related_artists=>@artist4).all.map{|a| a.name}.sort.should == %w'1 3 4'
311
+
312
+ c.exclude(:related_artists=>@artist1).all.map{|a| a.name}.sort.should == %w'3'
313
+ c.exclude(:related_artists=>@artist2).all.map{|a| a.name}.sort.should == %w'4'
314
+ c.exclude(:related_artists=>@artist3).all.map{|a| a.name}.sort.should == %w'1'
315
+ c.exclude(:related_artists=>@artist4).all.map{|a| a.name}.sort.should == %w'2'
316
+
317
+ c.filter(:related_artists=>[@artist1, @artist4]).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
318
+ c.exclude(:related_artists=>[@artist1, @artist4]).all.map{|a| a.name}.sort.should == %w''
319
+
320
+ c.filter(:related_artists=>c.filter(:artists__id=>@artist1.id)).all.map{|a| a.name}.sort.should == %w'1 2 4'
321
+ c.exclude(:related_artists=>c.filter(:artists__id=>@artist1.id)).all.map{|a| a.name}.sort.should == %w'3'
226
322
  end
227
323
 
228
324
  specify "should handle extreme case with 5 join tables" do
@@ -236,38 +332,84 @@ describe "Many Through Many Plugin" do
236
332
  @album4.add_artist(@artist3)
237
333
  @album4.add_artist(@artist4)
238
334
 
239
- Artist[1].related_albums.map{|x| x.name}.sort.should == %w'A B C'
240
- Artist[2].related_albums.map{|x| x.name}.sort.should == %w'A B C D'
241
- Artist[3].related_albums.map{|x| x.name}.sort.should == %w'A B D'
242
- Artist[4].related_albums.map{|x| x.name}.sort.should == %w'B D'
335
+ Artist[@artist1.id].related_albums.map{|x| x.name}.sort.should == %w'A B C'
336
+ Artist[@artist2.id].related_albums.map{|x| x.name}.sort.should == %w'A B C D'
337
+ Artist[@artist3.id].related_albums.map{|x| x.name}.sort.should == %w'A B D'
338
+ Artist[@artist4.id].related_albums.map{|x| x.name}.sort.should == %w'B D'
243
339
 
244
- Artist.filter(:id=>1).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C'
245
- Artist.filter(:id=>2).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C D'
246
- Artist.filter(:id=>3).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B D'
247
- Artist.filter(:id=>4).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'B D'
340
+ Artist.plugin :prepared_statements_associations
341
+ Artist[@artist1.id].related_albums.map{|x| x.name}.sort.should == %w'A B C'
342
+ Artist[@artist2.id].related_albums.map{|x| x.name}.sort.should == %w'A B C D'
343
+ Artist[@artist3.id].related_albums.map{|x| x.name}.sort.should == %w'A B D'
344
+ Artist[@artist4.id].related_albums.map{|x| x.name}.sort.should == %w'B D'
248
345
 
249
- Artist.filter(:artists__id=>1).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C'
250
- Artist.filter(:artists__id=>2).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C D'
251
- Artist.filter(:artists__id=>3).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B D'
252
- Artist.filter(:artists__id=>4).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'B D'
346
+ Artist.filter(:id=>@artist1.id).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C'
347
+ Artist.filter(:id=>@artist2.id).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C D'
348
+ Artist.filter(:id=>@artist3.id).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B D'
349
+ Artist.filter(:id=>@artist4.id).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'B D'
350
+
351
+ Artist.filter(:artists__id=>@artist1.id).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C'
352
+ Artist.filter(:artists__id=>@artist2.id).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C D'
353
+ Artist.filter(:artists__id=>@artist3.id).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B D'
354
+ Artist.filter(:artists__id=>@artist4.id).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'B D'
355
+
356
+ Artist.filter(:related_albums=>@album1).all.map{|a| a.name}.sort.should == %w'1 2 3'
357
+ Artist.filter(:related_albums=>@album2).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
358
+ Artist.filter(:related_albums=>@album3).all.map{|a| a.name}.sort.should == %w'1 2'
359
+ Artist.filter(:related_albums=>@album4).all.map{|a| a.name}.sort.should == %w'2 3 4'
360
+
361
+ Artist.exclude(:related_albums=>@album1).all.map{|a| a.name}.sort.should == %w'4'
362
+ Artist.exclude(:related_albums=>@album2).all.map{|a| a.name}.sort.should == %w''
363
+ Artist.exclude(:related_albums=>@album3).all.map{|a| a.name}.sort.should == %w'3 4'
364
+ Artist.exclude(:related_albums=>@album4).all.map{|a| a.name}.sort.should == %w'1'
365
+
366
+ Artist.filter(:related_albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'1 2 3'
367
+ Artist.filter(:related_albums=>[@album3, @album4]).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
368
+
369
+ Artist.exclude(:related_albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'4'
370
+ Artist.exclude(:related_albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w''
371
+
372
+ Artist.filter(:related_albums=>Album.filter(:id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'1 2 3'
373
+ Artist.exclude(:related_albums=>Album.filter(:id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'4'
374
+
375
+ c = self_join(Artist)
376
+ c.filter(:related_albums=>@album1).all.map{|a| a.name}.sort.should == %w'1 2 3'
377
+ c.filter(:related_albums=>@album2).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
378
+ c.filter(:related_albums=>@album3).all.map{|a| a.name}.sort.should == %w'1 2'
379
+ c.filter(:related_albums=>@album4).all.map{|a| a.name}.sort.should == %w'2 3 4'
380
+
381
+ c.exclude(:related_albums=>@album1).all.map{|a| a.name}.sort.should == %w'4'
382
+ c.exclude(:related_albums=>@album2).all.map{|a| a.name}.sort.should == %w''
383
+ c.exclude(:related_albums=>@album3).all.map{|a| a.name}.sort.should == %w'3 4'
384
+ c.exclude(:related_albums=>@album4).all.map{|a| a.name}.sort.should == %w'1'
385
+
386
+ c.filter(:related_albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'1 2 3'
387
+ c.filter(:related_albums=>[@album3, @album4]).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
388
+
389
+ c.exclude(:related_albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'4'
390
+ c.exclude(:related_albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w''
391
+
392
+ c.filter(:related_albums=>self_join(Album).filter(:albums__id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'1 2 3'
393
+ c.exclude(:related_albums=>self_join(Album).filter(:albums__id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'4'
253
394
  end
254
395
  end
255
396
 
256
397
  describe "Lazy Attributes plugin" do
257
- before do
398
+ before(:all) do
258
399
  @db = INTEGRATION_DB
259
400
  @db.create_table!(:items) do
260
401
  primary_key :id
261
402
  String :name
262
403
  Integer :num
263
404
  end
405
+ @db[:items].delete
264
406
  class ::Item < Sequel::Model(@db)
265
407
  plugin :lazy_attributes, :num
266
408
  end
267
409
  Item.create(:name=>'J', :num=>1)
268
410
  end
269
- after do
270
- @db.drop_table(:items)
411
+ after(:all) do
412
+ @db.drop_table?(:items)
271
413
  Object.send(:remove_const, :Item)
272
414
  end
273
415
 
@@ -299,7 +441,7 @@ describe "Lazy Attributes plugin" do
299
441
  end
300
442
 
301
443
  describe "Tactical Eager Loading Plugin" do
302
- before do
444
+ before(:all) do
303
445
  @db = INTEGRATION_DB
304
446
  @db.instance_variable_set(:@schemas, {})
305
447
  @db.create_table!(:artists) do
@@ -311,6 +453,10 @@ describe "Tactical Eager Loading Plugin" do
311
453
  String :name
312
454
  foreign_key :artist_id, :artists
313
455
  end
456
+ end
457
+ before do
458
+ @db[:albums].delete
459
+ @db[:artists].delete
314
460
  class ::Album < Sequel::Model(@db)
315
461
  plugin :tactical_eager_loading
316
462
  many_to_one :artist
@@ -328,13 +474,13 @@ describe "Tactical Eager Loading Plugin" do
328
474
  @album2 = Album.create(:name=>'B', :artist=>@artist1)
329
475
  @album3 = Album.create(:name=>'C', :artist=>@artist2)
330
476
  @album4 = Album.create(:name=>'D', :artist=>@artist3)
331
-
332
- clear_sqls
333
477
  end
334
478
  after do
335
- @db.drop_table :albums, :artists
336
479
  [:Album, :Artist].each{|s| Object.send(:remove_const, s)}
337
480
  end
481
+ after(:all) do
482
+ @db.drop_table? :albums, :artists
483
+ end
338
484
 
339
485
  specify "should eagerly load associations for all items when accessing any item" do
340
486
  a = Artist.order(:name).all
@@ -363,7 +509,7 @@ describe "Identity Map plugin" do
363
509
  Item.create(:name=>'J', :num=>3)
364
510
  end
365
511
  after do
366
- @db.drop_table(:items)
512
+ @db.drop_table?(:items)
367
513
  Object.send(:remove_const, :Item)
368
514
  end
369
515
 
@@ -382,56 +528,91 @@ describe "Identity Map plugin" do
382
528
  end
383
529
 
384
530
  describe "Touch plugin" do
385
- before do
531
+ before(:all) do
386
532
  @db = INTEGRATION_DB
387
- @db.instance_variable_set(:@schemas, {})
388
- @db.create_table!(:artists) do
533
+ @db.drop_table? :albums_artists, :albums, :artists
534
+ @db.create_table(:artists) do
389
535
  primary_key :id
390
536
  String :name
391
537
  DateTime :updated_at
392
538
  end
393
- @db.create_table!(:albums) do
539
+ @db.create_table(:albums) do
394
540
  primary_key :id
395
541
  String :name
396
542
  foreign_key :artist_id, :artists
397
543
  DateTime :updated_at
398
544
  end
545
+ @db.create_join_table({:album_id=>:albums, :artist_id=>:artists}, :no_index=>true)
546
+ end
547
+ before do
548
+ @db[:albums].delete
549
+ @db[:artists].delete
399
550
  class ::Album < Sequel::Model(@db)
400
- many_to_one :artist
401
- plugin :touch, :associations=>:artist
402
551
  end
403
552
  class ::Artist < Sequel::Model(@db)
404
553
  end
405
554
 
406
555
  @artist = Artist.create(:name=>'1')
407
- @album = Album.create(:name=>'A', :artist=>@artist)
556
+ @album = Album.create(:name=>'A', :artist_id=>@artist.id)
408
557
  end
409
558
  after do
410
- @db.drop_table :albums, :artists
411
559
  [:Album, :Artist].each{|s| Object.send(:remove_const, s)}
412
560
  end
561
+ after(:all) do
562
+ @db.drop_table? :albums_artists, :albums, :artists
563
+ end
413
564
 
414
565
  specify "should update the timestamp column when touching the record" do
566
+ Album.plugin :touch
415
567
  @album.updated_at.should == nil
416
568
  @album.touch
417
569
  @album.updated_at.to_i.should be_within(2).of(Time.now.to_i)
418
570
  end
419
571
 
420
- cspecify "should update the timestamp column for associated records when the record is updated or destroyed", [:do, :sqlite], [:jdbc, :sqlite] do
572
+ cspecify "should update the timestamp column for many_to_one associated records when the record is updated or destroyed", [:do, :sqlite], [:jdbc, :sqlite], [:swift] do
573
+ Album.many_to_one :artist
574
+ Album.plugin :touch, :associations=>:artist
421
575
  @artist.updated_at.should == nil
422
576
  @album.update(:name=>'B')
423
577
  ua = @artist.reload.updated_at
424
578
  if ua.is_a?(Time)
425
- ua.to_i.should be_within(2).of(Time.now.to_i)
579
+ ua.to_i.should be_within(60).of(Time.now.to_i)
426
580
  else
427
- (DateTime.now - ua).should be_within(2.0/86400).of(0)
581
+ (DateTime.now - ua).should be_within(60.0/86400).of(0)
428
582
  end
429
583
  @artist.update(:updated_at=>nil)
430
584
  @album.destroy
431
585
  if ua.is_a?(Time)
432
- ua.to_i.should be_within(2).of(Time.now.to_i)
586
+ ua.to_i.should be_within(60).of(Time.now.to_i)
587
+ else
588
+ (DateTime.now - ua).should be_within(60.0/86400).of(0)
589
+ end
590
+ end
591
+
592
+ cspecify "should update the timestamp column for one_to_many associated records when the record is updated", [:do, :sqlite], [:jdbc, :sqlite], [:swift] do
593
+ Artist.one_to_many :albums
594
+ Artist.plugin :touch, :associations=>:albums
595
+ @album.updated_at.should == nil
596
+ @artist.update(:name=>'B')
597
+ ua = @album.reload.updated_at
598
+ if ua.is_a?(Time)
599
+ ua.to_i.should be_within(60).of(Time.now.to_i)
600
+ else
601
+ (DateTime.now - ua).should be_within(60.0/86400).of(0)
602
+ end
603
+ end
604
+
605
+ cspecify "should update the timestamp column for many_to_many associated records when the record is updated", [:do, :sqlite], [:jdbc, :sqlite], [:swift] do
606
+ Artist.many_to_many :albums
607
+ Artist.plugin :touch, :associations=>:albums
608
+ @artist.add_album(@album)
609
+ @album.updated_at.should == nil
610
+ @artist.update(:name=>'B')
611
+ ua = @album.reload.updated_at
612
+ if ua.is_a?(Time)
613
+ ua.to_i.should be_within(60).of(Time.now.to_i)
433
614
  else
434
- (DateTime.now - ua).should be_within(2.0/86400).of(0)
615
+ (DateTime.now - ua).should be_within(60.0/86400).of(0)
435
616
  end
436
617
  end
437
618
  end
@@ -448,7 +629,7 @@ describe "Serialization plugin" do
448
629
  end
449
630
  end
450
631
  after do
451
- @db.drop_table(:items)
632
+ @db.drop_table?(:items)
452
633
  Object.send(:remove_const, :Item)
453
634
  end
454
635
 
@@ -464,7 +645,7 @@ describe "Serialization plugin" do
464
645
  end
465
646
 
466
647
  describe "OptimisticLocking plugin" do
467
- before do
648
+ before(:all) do
468
649
  @db = INTEGRATION_DB
469
650
  @db.create_table!(:people) do
470
651
  primary_key :id
@@ -473,30 +654,33 @@ describe "OptimisticLocking plugin" do
473
654
  end
474
655
  class ::Person < Sequel::Model(@db)
475
656
  plugin :optimistic_locking
476
- create(:name=>'John')
477
657
  end
478
658
  end
479
- after do
480
- @db.drop_table(:people)
659
+ before do
660
+ @db[:people].delete
661
+ @p = Person.create(:name=>'John')
662
+ end
663
+ after(:all) do
664
+ @db.drop_table?(:people)
481
665
  Object.send(:remove_const, :Person)
482
666
  end
483
667
 
484
668
  specify "should raise an error when updating a stale record" do
485
- p1 = Person[1]
486
- p2 = Person[1]
669
+ p1 = Person[@p.id]
670
+ p2 = Person[@p.id]
487
671
  p1.update(:name=>'Jim')
488
672
  proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
489
673
  end
490
674
 
491
675
  specify "should raise an error when destroying a stale record" do
492
- p1 = Person[1]
493
- p2 = Person[1]
676
+ p1 = Person[@p.id]
677
+ p2 = Person[@p.id]
494
678
  p1.update(:name=>'Jim')
495
679
  proc{p2.destroy}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
496
680
  end
497
681
 
498
682
  specify "should not raise an error when updating the same record twice" do
499
- p1 = Person[1]
683
+ p1 = Person[@p.id]
500
684
  p1.update(:name=>'Jim')
501
685
  proc{p1.update(:name=>'Bob')}.should_not raise_error
502
686
  end
@@ -525,10 +709,10 @@ describe "Composition plugin" do
525
709
  composition :date, :mapping=>[:year, :month, :day]
526
710
  end
527
711
  @e1 = Event.create(:year=>2010, :month=>2, :day=>15)
528
- @e2 = Event.create({})
712
+ @e2 = Event.create(:year=>nil)
529
713
  end
530
714
  after do
531
- @db.drop_table(:events)
715
+ @db.drop_table?(:events)
532
716
  Object.send(:remove_const, :Event)
533
717
  end
534
718
 
@@ -555,9 +739,10 @@ describe "Composition plugin" do
555
739
  end
556
740
  end
557
741
 
558
- if INTEGRATION_DB.dataset.supports_cte?
742
+ # DB2's implemention of CTE is too limited to use this plugin
743
+ if INTEGRATION_DB.dataset.supports_cte? and !Sequel.guarded?(:db2)
559
744
  describe "RcteTree Plugin" do
560
- before do
745
+ before(:all) do
561
746
  @db = INTEGRATION_DB
562
747
  @db.create_table!(:nodes) do
563
748
  primary_key :id
@@ -568,22 +753,26 @@ if INTEGRATION_DB.dataset.supports_cte?
568
753
  plugin :rcte_tree, :order=>:name
569
754
  end
570
755
 
571
- @a = Node.create(:name=>'a')
572
- @b = Node.create(:name=>'b')
573
- @aa = Node.create(:name=>'aa', :parent=>@a)
574
- @ab = Node.create(:name=>'ab', :parent=>@a)
575
- @ba = Node.create(:name=>'ba', :parent=>@b)
576
- @bb = Node.create(:name=>'bb', :parent=>@b)
577
- @aaa = Node.create(:name=>'aaa', :parent=>@aa)
578
- @aab = Node.create(:name=>'aab', :parent=>@aa)
579
- @aba = Node.create(:name=>'aba', :parent=>@ab)
580
- @abb = Node.create(:name=>'abb', :parent=>@ab)
581
- @aaaa = Node.create(:name=>'aaaa', :parent=>@aaa)
582
- @aaab = Node.create(:name=>'aaab', :parent=>@aaa)
583
- @aaaaa = Node.create(:name=>'aaaaa', :parent=>@aaaa)
584
- end
585
- after do
586
- @db.drop_table :nodes
756
+ @nodes = []
757
+ @nodes << @a = Node.create(:name=>'a')
758
+ @nodes << @b = Node.create(:name=>'b')
759
+ @nodes << @aa = Node.create(:name=>'aa', :parent=>@a)
760
+ @nodes << @ab = Node.create(:name=>'ab', :parent=>@a)
761
+ @nodes << @ba = Node.create(:name=>'ba', :parent=>@b)
762
+ @nodes << @bb = Node.create(:name=>'bb', :parent=>@b)
763
+ @nodes << @aaa = Node.create(:name=>'aaa', :parent=>@aa)
764
+ @nodes << @aab = Node.create(:name=>'aab', :parent=>@aa)
765
+ @nodes << @aba = Node.create(:name=>'aba', :parent=>@ab)
766
+ @nodes << @abb = Node.create(:name=>'abb', :parent=>@ab)
767
+ @nodes << @aaaa = Node.create(:name=>'aaaa', :parent=>@aaa)
768
+ @nodes << @aaab = Node.create(:name=>'aaab', :parent=>@aaa)
769
+ @nodes << @aaaaa = Node.create(:name=>'aaaaa', :parent=>@aaaa)
770
+ end
771
+ before do
772
+ @nodes.each{|n| n.associations.clear}
773
+ end
774
+ after(:all) do
775
+ @db.drop_table? :nodes
587
776
  Object.send(:remove_const, :Node)
588
777
  end
589
778
 
@@ -659,13 +848,15 @@ if INTEGRATION_DB.dataset.supports_cte?
659
848
  end
660
849
 
661
850
  specify "should work correctly if not all columns are selected" do
662
- Node.plugin :lazy_attributes, :name
663
- @aaaa.descendants.should == [Node.load(:parent_id=>11, :id=>13)]
664
- @aa.ancestors.should == [Node.load(:parent_id=>nil, :id=>1)]
665
- nodes = Node.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:ancestors, :descendants).all
666
- nodes.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>3, :id=>7}, {:parent_id=>nil, :id=>2}].map{|x| Node.load(x)}
667
- nodes[2].descendants.should == [{:parent_id=>2, :id=>5}, {:parent_id=>2, :id=>6}].map{|x| Node.load(x)}
668
- nodes[1].ancestors.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>1, :id=>3}].map{|x| Node.load(x)}
851
+ c = Class.new(Sequel::Model(@db[:nodes]))
852
+ c.plugin :rcte_tree, :order=>:name
853
+ c.plugin :lazy_attributes, :name
854
+ c[:name=>'aaaa'].descendants.should == [c.load(:parent_id=>11, :id=>13)]
855
+ c[:name=>'aa'].ancestors.should == [c.load(:parent_id=>nil, :id=>1)]
856
+ nodes = c.filter(:id=>[@a.id, @b.id, @aaa.id]).order(:name).eager(:ancestors, :descendants).all
857
+ nodes.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>3, :id=>7}, {:parent_id=>nil, :id=>2}].map{|x| c.load(x)}
858
+ nodes[2].descendants.should == [{:parent_id=>2, :id=>5}, {:parent_id=>2, :id=>6}].map{|x| c.load(x)}
859
+ nodes[1].ancestors.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>1, :id=>3}].map{|x| c.load(x)}
669
860
  end
670
861
 
671
862
  specify "should eagerly load descendants to a given level" do
@@ -751,7 +942,7 @@ if INTEGRATION_DB.dataset.supports_cte?
751
942
  nodes[0].associations.fetch(:parent, 1).should == nil
752
943
  nodes[1].associations[:parent].should == @aa
753
944
  nodes[1].associations[:parent].associations[:parent].should == @a
754
- nodes[1].associations[:parent].associations[:parent].associations.fetch(:parent, 1) == nil
945
+ nodes[1].associations[:parent].associations[:parent].associations.fetch(:parent, 1).should == nil
755
946
  nodes[2].associations[:parent].should == @aaaa
756
947
  nodes[2].associations[:parent].associations[:parent].should == @aaa
757
948
  nodes[2].associations[:parent].associations[:parent].associations[:parent].should == @aa
@@ -783,7 +974,7 @@ if INTEGRATION_DB.dataset.supports_cte?
783
974
  end
784
975
 
785
976
  describe "Instance Filters plugin" do
786
- before do
977
+ before(:all) do
787
978
  @db = INTEGRATION_DB
788
979
  @db.create_table!(:items) do
789
980
  primary_key :id
@@ -794,12 +985,15 @@ describe "Instance Filters plugin" do
794
985
  class ::Item < Sequel::Model(@db)
795
986
  plugin :instance_filters
796
987
  end
988
+ end
989
+ before do
990
+ @db[:items].delete
797
991
  @i = Item.create(:name=>'J', :number=>1, :cost=>2)
798
992
  @i.instance_filter(:number=>1)
799
993
  @i.set(:name=>'K')
800
994
  end
801
- after do
802
- @db.drop_table(:items)
995
+ after(:all) do
996
+ @db.drop_table?(:items)
803
997
  Object.send(:remove_const, :Item)
804
998
  end
805
999
 
@@ -843,21 +1037,24 @@ describe "Instance Filters plugin" do
843
1037
  end
844
1038
 
845
1039
  describe "UpdatePrimaryKey plugin" do
846
- before do
1040
+ before(:all) do
847
1041
  @db = INTEGRATION_DB
848
1042
  @db.create_table!(:t) do
849
1043
  Integer :a, :primary_key=>true
850
1044
  Integer :b
851
1045
  end
852
1046
  @ds = @db[:t]
853
- @ds.insert(:a=>1, :b=>3)
854
1047
  @c = Class.new(Sequel::Model(@ds))
855
1048
  @c.set_primary_key(:a)
856
1049
  @c.unrestrict_primary_key
857
1050
  @c.plugin :update_primary_key
858
1051
  end
859
- after do
860
- @db.drop_table(:t)
1052
+ before do
1053
+ @ds.delete
1054
+ @ds.insert(:a=>1, :b=>3)
1055
+ end
1056
+ after(:all) do
1057
+ @db.drop_table?(:t)
861
1058
  end
862
1059
 
863
1060
  specify "should handle regular updates" do
@@ -898,25 +1095,66 @@ describe "UpdatePrimaryKey plugin" do
898
1095
  end
899
1096
 
900
1097
  describe "AssociationPks plugin" do
901
- before do
1098
+ before(:all) do
902
1099
  @db = INTEGRATION_DB
903
- @db.create_table!(:artists) do
1100
+ @db.drop_table?(:albums_tags, :albums_vocalists, :vocalists_instruments, :vocalists_hits, :hits, :instruments, :vocalists, :tags, :albums, :artists)
1101
+ @db.create_table(:artists) do
904
1102
  primary_key :id
905
1103
  String :name
906
1104
  end
907
- @db.create_table!(:albums) do
1105
+ @db.create_table(:albums) do
908
1106
  primary_key :id
909
1107
  String :name
910
1108
  foreign_key :artist_id, :artists
911
1109
  end
912
- @db.create_table!(:tags) do
1110
+ @db.create_table(:tags) do
913
1111
  primary_key :id
914
1112
  String :name
915
1113
  end
916
- @db.create_table!(:albums_tags) do
1114
+ @db.create_table(:albums_tags) do
917
1115
  foreign_key :album_id, :albums
918
1116
  foreign_key :tag_id, :tags
919
1117
  end
1118
+ @db.create_table(:vocalists) do
1119
+ String :first
1120
+ String :last
1121
+ primary_key [:first, :last]
1122
+ foreign_key :album_id, :albums
1123
+ end
1124
+ @db.create_table(:albums_vocalists) do
1125
+ foreign_key :album_id, :albums
1126
+ String :first
1127
+ String :last
1128
+ foreign_key [:first, :last], :vocalists
1129
+ end
1130
+ @db.create_table(:instruments) do
1131
+ primary_key :id
1132
+ String :first
1133
+ String :last
1134
+ foreign_key [:first, :last], :vocalists
1135
+ end
1136
+ @db.create_table(:vocalists_instruments) do
1137
+ String :first
1138
+ String :last
1139
+ foreign_key [:first, :last], :vocalists
1140
+ foreign_key :instrument_id, :instruments
1141
+ end
1142
+ @db.create_table(:hits) do
1143
+ Integer :year
1144
+ Integer :week
1145
+ primary_key [:year, :week]
1146
+ String :first
1147
+ String :last
1148
+ foreign_key [:first, :last], :vocalists
1149
+ end
1150
+ @db.create_table(:vocalists_hits) do
1151
+ String :first
1152
+ String :last
1153
+ foreign_key [:first, :last], :vocalists
1154
+ Integer :year
1155
+ Integer :week
1156
+ foreign_key [:year, :week], :hits
1157
+ end
920
1158
  class ::Artist < Sequel::Model
921
1159
  plugin :association_pks
922
1160
  one_to_many :albums, :order=>:id
@@ -927,7 +1165,19 @@ describe "AssociationPks plugin" do
927
1165
  end
928
1166
  class ::Tag < Sequel::Model
929
1167
  end
930
-
1168
+ class ::Vocalist < Sequel::Model
1169
+ set_primary_key [:first, :last]
1170
+ plugin :association_pks
1171
+ end
1172
+ class ::Instrument < Sequel::Model
1173
+ plugin :association_pks
1174
+ end
1175
+ class ::Hit < Sequel::Model
1176
+ set_primary_key [:year, :week]
1177
+ end
1178
+ end
1179
+ before do
1180
+ [:albums_tags, :albums_vocalists, :vocalists_instruments, :vocalists_hits, :hits, :instruments, :vocalists, :tags, :albums, :artists].each{|t| @db[t].delete}
931
1181
  @ar1 =@db[:artists].insert(:name=>'YJM')
932
1182
  @ar2 =@db[:artists].insert(:name=>'AS')
933
1183
  @al1 =@db[:albums].insert(:name=>'RF', :artist_id=>@ar1)
@@ -939,10 +1189,34 @@ describe "AssociationPks plugin" do
939
1189
  {@al1=>[@t1, @t2, @t3], @al2=>[@t2]}.each do |aid, tids|
940
1190
  tids.each{|tid| @db[:albums_tags].insert([aid, tid])}
941
1191
  end
1192
+ @v1 = ['F1', 'L1']
1193
+ @v2 = ['F2', 'L2']
1194
+ @v3 = ['F3', 'L3']
1195
+ @db[:vocalists].insert(@v1 + [@al1])
1196
+ @db[:vocalists].insert(@v2 + [@al1])
1197
+ @db[:vocalists].insert(@v3 + [@al1])
1198
+ @i1 = @db[:instruments].insert([:first, :last], @v1)
1199
+ @i2 = @db[:instruments].insert([:first, :last], @v1)
1200
+ @i3 = @db[:instruments].insert([:first, :last], @v1)
1201
+ @h1 = [1997, 1]
1202
+ @h2 = [1997, 2]
1203
+ @h3 = [1997, 3]
1204
+ @db[:hits].insert(@h1 + @v1)
1205
+ @db[:hits].insert(@h2 + @v1)
1206
+ @db[:hits].insert(@h3 + @v1)
1207
+ {@al1=>[@v1, @v2, @v3], @al2=>[@v2]}.each do |aid, vids|
1208
+ vids.each{|vid| @db[:albums_vocalists].insert([aid] + vid)}
1209
+ end
1210
+ {@v1=>[@i1, @i2, @i3], @v2=>[@i2]}.each do |vid, iids|
1211
+ iids.each{|iid| @db[:vocalists_instruments].insert(vid + [iid])}
1212
+ end
1213
+ {@v1=>[@h1, @h2, @h3], @v2=>[@h2]}.each do |vid, hids|
1214
+ hids.each{|hid| @db[:vocalists_hits].insert(vid + hid)}
1215
+ end
942
1216
  end
943
- after do
944
- @db.drop_table :albums_tags, :tags, :albums, :artists
945
- [:Artist, :Album, :Tag].each{|s| Object.send(:remove_const, s)}
1217
+ after(:all) do
1218
+ @db.drop_table? :albums_tags, :albums_vocalists, :vocalists_instruments, :vocalists_hits, :hits, :instruments, :vocalists, :tags, :albums, :artists
1219
+ [:Artist, :Album, :Tag, :Vocalist, :Instrument, :Hit].each{|s| Object.send(:remove_const, s)}
946
1220
  end
947
1221
 
948
1222
  specify "should return correct associated pks for one_to_many associations" do
@@ -953,6 +1227,36 @@ describe "AssociationPks plugin" do
953
1227
  Album.order(:id).all.map{|a| a.tag_pks.sort}.should == [[@t1, @t2, @t3], [@t2], []]
954
1228
  end
955
1229
 
1230
+ specify "should return correct associated right-side cpks for one_to_many associations" do
1231
+ Album.one_to_many :vocalists, :order=>:first
1232
+ Album.order(:id).all.map{|a| a.vocalist_pks.sort}.should == [[@v1, @v2, @v3], [], []]
1233
+ end
1234
+
1235
+ specify "should return correct associated right-side cpks for many_to_many associations" do
1236
+ Album.many_to_many :vocalists, :join_table=>:albums_vocalists, :right_key=>[:first, :last], :order=>:first
1237
+ Album.order(:id).all.map{|a| a.vocalist_pks.sort}.should == [[@v1, @v2, @v3], [@v2], []]
1238
+ end
1239
+
1240
+ specify "should return correct associated pks for left-side cpks for one_to_many associations" do
1241
+ Vocalist.one_to_many :instruments, :key=>[:first, :last], :order=>:id
1242
+ Vocalist.order(:first, :last).all.map{|a| a.instrument_pks.sort}.should == [[@i1, @i2, @i3], [], []]
1243
+ end
1244
+
1245
+ specify "should return correct associated pks for left-side cpks for many_to_many associations" do
1246
+ Vocalist.many_to_many :instruments, :join_table=>:vocalists_instruments, :left_key=>[:first, :last], :order=>:id
1247
+ Vocalist.order(:first, :last).all.map{|a| a.instrument_pks.sort}.should == [[@i1, @i2, @i3], [@i2], []]
1248
+ end
1249
+
1250
+ specify "should return correct associated right-side cpks for left-side cpks for one_to_many associations" do
1251
+ Vocalist.one_to_many :hits, :key=>[:first, :last], :order=>:week
1252
+ Vocalist.order(:first, :last).all.map{|a| a.hit_pks.sort}.should == [[@h1, @h2, @h3], [], []]
1253
+ end
1254
+
1255
+ specify "should return correct associated right-side cpks for left-side cpks for many_to_many associations" do
1256
+ Vocalist.many_to_many :hits, :join_table=>:vocalists_hits, :left_key=>[:first, :last], :right_key=>[:year, :week], :order=>:week
1257
+ Vocalist.order(:first, :last).all.map{|a| a.hit_pks.sort}.should == [[@h1, @h2, @h3], [@h2], []]
1258
+ end
1259
+
956
1260
  specify "should set associated pks correctly for a one_to_many association" do
957
1261
  Artist.use_transactions = true
958
1262
  Album.order(:id).select_map(:artist_id).should == [@ar1, @ar1, @ar1]
@@ -990,13 +1294,135 @@ describe "AssociationPks plugin" do
990
1294
  Album[@al3].tag_pks = []
991
1295
  @db[:albums_tags].filter(:album_id=>@al1).select_order_map(:tag_id).should == []
992
1296
  end
993
- end
994
1297
 
1298
+ specify "should set associated right-side cpks correctly for a one_to_many association" do
1299
+ Album.use_transactions = true
1300
+ Album.one_to_many :vocalists, :order=>:first
1301
+ Album.order(:id).all.map{|a| a.vocalist_pks.sort}.should == [[@v1, @v2, @v3], [], []]
1302
+
1303
+ Album[@al2].vocalist_pks = [@v1, @v3]
1304
+ Album[@al1].vocalist_pks.should == [@v2]
1305
+ Vocalist.order(:first, :last).select_map(:album_id).should == [@al2, @al1, @al2]
1306
+
1307
+ Album[@al1].vocalist_pks = [@v1]
1308
+ Album[@al2].vocalist_pks.should == [@v3]
1309
+ Vocalist.order(:first, :last).select_map(:album_id).should == [@al1, nil, @al2]
1310
+
1311
+ Album[@al1].vocalist_pks = [@v1, @v2]
1312
+ Album[@al2].vocalist_pks.should == [@v3]
1313
+ Vocalist.order(:first, :last).select_map(:album_id).should == [@al1, @al1, @al2]
1314
+ end
1315
+
1316
+ specify "should set associated right-side cpks correctly for a many_to_many association" do
1317
+ Album.use_transactions = true
1318
+ Album.many_to_many :vocalists, :join_table=>:albums_vocalists, :right_key=>[:first, :last], :order=>:first
1319
+
1320
+ @db[:albums_vocalists].filter(:album_id=>@al1).select_order_map([:first, :last]).should == [@v1, @v2, @v3]
1321
+ Album[@al1].vocalist_pks = [@v1, @v3]
1322
+ @db[:albums_vocalists].filter(:album_id=>@al1).select_order_map([:first, :last]).should == [@v1, @v3]
1323
+ Album[@al1].vocalist_pks = []
1324
+ @db[:albums_vocalists].filter(:album_id=>@al1).select_order_map([:first, :last]).should == []
1325
+
1326
+ @db[:albums_vocalists].filter(:album_id=>@al2).select_order_map([:first, :last]).should == [@v2]
1327
+ Album[@al2].vocalist_pks = [@v1, @v2]
1328
+ @db[:albums_vocalists].filter(:album_id=>@al2).select_order_map([:first, :last]).should == [@v1, @v2]
1329
+ Album[@al2].vocalist_pks = []
1330
+ @db[:albums_vocalists].filter(:album_id=>@al1).select_order_map([:first, :last]).should == []
1331
+
1332
+ @db[:albums_vocalists].filter(:album_id=>@al3).select_order_map([:first, :last]).should == []
1333
+ Album[@al3].vocalist_pks = [@v1, @v3]
1334
+ @db[:albums_vocalists].filter(:album_id=>@al3).select_order_map([:first, :last]).should == [@v1, @v3]
1335
+ Album[@al3].vocalist_pks = []
1336
+ @db[:albums_vocalists].filter(:album_id=>@al1).select_order_map([:first, :last]).should == []
1337
+ end
1338
+
1339
+ specify "should set associated pks correctly with left-side cpks for a one_to_many association" do
1340
+ Vocalist.use_transactions = true
1341
+ Vocalist.one_to_many :instruments, :key=>[:first, :last], :order=>:id
1342
+ Vocalist.order(:first, :last).all.map{|a| a.instrument_pks.sort}.should == [[@i1, @i2, @i3], [], []]
1343
+
1344
+ Vocalist[@v2].instrument_pks = [@i1, @i3]
1345
+ Vocalist[@v1].instrument_pks.should == [@i2]
1346
+ Instrument.order(:id).select_map([:first, :last]).should == [@v2, @v1, @v2]
1347
+
1348
+ Vocalist[@v1].instrument_pks = [@i1]
1349
+ Vocalist[@v2].instrument_pks.should == [@i3]
1350
+ Instrument.order(:id).select_map([:first, :last]).should == [@v1, [nil, nil], @v2]
1351
+
1352
+ Vocalist[@v1].instrument_pks = [@i1, @i2]
1353
+ Vocalist[@v2].instrument_pks.should == [@i3]
1354
+ Instrument.order(:id).select_map([:first, :last]).should == [@v1, @v1, @v2]
1355
+ end
1356
+
1357
+ specify "should set associated pks correctly with left-side cpks for a many_to_many association" do
1358
+ Vocalist.use_transactions = true
1359
+ Vocalist.many_to_many :instruments, :join_table=>:vocalists_instruments, :left_key=>[:first, :last], :order=>:id
1360
+
1361
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v1]).select_order_map(:instrument_id).should == [@i1, @i2, @i3]
1362
+ Vocalist[@v1].instrument_pks = [@i1, @i3]
1363
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v1]).select_order_map(:instrument_id).should == [@i1, @i3]
1364
+ Vocalist[@v1].instrument_pks = []
1365
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v1]).select_order_map(:instrument_id).should == []
1366
+
1367
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v2]).select_order_map(:instrument_id).should == [@i2]
1368
+ Vocalist[@v2].instrument_pks = [@i1, @i2]
1369
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v2]).select_order_map(:instrument_id).should == [@i1, @i2]
1370
+ Vocalist[@v2].instrument_pks = []
1371
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v1]).select_order_map(:instrument_id).should == []
1372
+
1373
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v3]).select_order_map(:instrument_id).should == []
1374
+ Vocalist[@v3].instrument_pks = [@i1, @i3]
1375
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v3]).select_order_map(:instrument_id).should == [@i1, @i3]
1376
+ Vocalist[@v3].instrument_pks = []
1377
+ @db[:vocalists_instruments].filter([:first, :last]=>[@v1]).select_order_map(:instrument_id).should == []
1378
+ end
1379
+
1380
+ specify "should set associated right-side cpks correctly with left-side cpks for a one_to_many association" do
1381
+ Vocalist.use_transactions = true
1382
+ Vocalist.one_to_many :hits, :key=>[:first, :last], :order=>:week
1383
+ Vocalist.order(:first, :last).all.map{|a| a.hit_pks.sort}.should == [[@h1, @h2, @h3], [], []]
1384
+
1385
+ Vocalist[@v2].hit_pks = [@h1, @h3]
1386
+ Vocalist[@v1].hit_pks.should == [@h2]
1387
+ Hit.order(:year, :week).select_map([:first, :last]).should == [@v2, @v1, @v2]
1388
+
1389
+ Vocalist[@v1].hit_pks = [@h1]
1390
+ Vocalist[@v2].hit_pks.should == [@h3]
1391
+ Hit.order(:year, :week).select_map([:first, :last]).should == [@v1, [nil, nil], @v2]
1392
+
1393
+ Vocalist[@v1].hit_pks = [@h1, @h2]
1394
+ Vocalist[@v2].hit_pks.should == [@h3]
1395
+ Hit.order(:year, :week).select_map([:first, :last]).should == [@v1, @v1, @v2]
1396
+ end
1397
+
1398
+ specify "should set associated right-side cpks correctly with left-side cpks for a many_to_many association" do
1399
+ Vocalist.use_transactions = true
1400
+ Vocalist.many_to_many :hits, :join_table=>:vocalists_hits, :left_key=>[:first, :last], :right_key=>[:year, :week], :order=>:week
1401
+
1402
+ @db[:vocalists_hits].filter([:first, :last]=>[@v1]).select_order_map([:year, :week]).should == [@h1, @h2, @h3]
1403
+ Vocalist[@v1].hit_pks = [@h1, @h3]
1404
+ @db[:vocalists_hits].filter([:first, :last]=>[@v1]).select_order_map([:year, :week]).should == [@h1, @h3]
1405
+ Vocalist[@v1].hit_pks = []
1406
+ @db[:vocalists_hits].filter([:first, :last]=>[@v1]).select_order_map([:year, :week]).should == []
1407
+
1408
+ @db[:vocalists_hits].filter([:first, :last]=>[@v2]).select_order_map([:year, :week]).should == [@h2]
1409
+ Vocalist[@v2].hit_pks = [@h1, @h2]
1410
+ @db[:vocalists_hits].filter([:first, :last]=>[@v2]).select_order_map([:year, :week]).should == [@h1, @h2]
1411
+ Vocalist[@v2].hit_pks = []
1412
+ @db[:vocalists_hits].filter([:first, :last]=>[@v1]).select_order_map([:year, :week]).should == []
1413
+
1414
+ @db[:vocalists_hits].filter([:first, :last]=>[@v3]).select_order_map([:year, :week]).should == []
1415
+ Vocalist[@v3].hit_pks = [@h1, @h3]
1416
+ @db[:vocalists_hits].filter([:first, :last]=>[@v3]).select_order_map([:year, :week]).should == [@h1, @h3]
1417
+ Vocalist[@v3].hit_pks = []
1418
+ @db[:vocalists_hits].filter([:first, :last]=>[@v1]).select_order_map([:year, :week]).should == []
1419
+ end
1420
+ end
995
1421
 
996
1422
  describe "List plugin without a scope" do
997
- before do
1423
+ before(:all) do
998
1424
  @db = INTEGRATION_DB
999
- @db.create_table :sites do
1425
+ @db.create_table!(:sites) do
1000
1426
  primary_key :id
1001
1427
  String :name
1002
1428
  Integer :position
@@ -1004,14 +1430,15 @@ describe "List plugin without a scope" do
1004
1430
 
1005
1431
  @c = Class.new(Sequel::Model(@db[:sites]))
1006
1432
  @c.plugin :list
1433
+ end
1434
+ before do
1007
1435
  @c.delete
1008
- @c.create :name => "hig", :position => 3
1009
- @c.create :name => "def", :position => 2
1010
- @c.create :name => "abc", :position => 1
1436
+ @c.create :name => "abc"
1437
+ @c.create :name => "def"
1438
+ @c.create :name => "hig"
1011
1439
  end
1012
-
1013
- after do
1014
- @db.drop_table(:sites)
1440
+ after(:all) do
1441
+ @db.drop_table?(:sites)
1015
1442
  end
1016
1443
 
1017
1444
  it "should return rows in order of position" do
@@ -1067,9 +1494,9 @@ describe "List plugin without a scope" do
1067
1494
  end
1068
1495
 
1069
1496
  describe "List plugin with a scope" do
1070
- before do
1497
+ before(:all) do
1071
1498
  @db = INTEGRATION_DB
1072
- @db.create_table :pages do
1499
+ @db.create_table!(:pages) do
1073
1500
  primary_key :id
1074
1501
  String :name
1075
1502
  Integer :pos
@@ -1078,19 +1505,21 @@ describe "List plugin with a scope" do
1078
1505
 
1079
1506
  @c = Class.new(Sequel::Model(@db[:pages]))
1080
1507
  @c.plugin :list, :field => :pos, :scope => :parent_id
1081
- p1 = @c.create :name => "Hm", :pos => 1, :parent_id => 0
1082
- p2 = @c.create :name => "Ps", :pos => 1, :parent_id => p1.id
1083
- @c.create :name => "P1", :pos => 1, :parent_id => p2.id
1084
- @c.create :name => "P2", :pos => 2, :parent_id => p2.id
1085
- @c.create :name => "P3", :pos => 3, :parent_id => p2.id
1086
- @c.create :name => "Au", :pos => 2, :parent_id => p1.id
1087
1508
  end
1088
-
1089
- after do
1090
- @db.drop_table(:pages)
1509
+ before do
1510
+ @c.delete
1511
+ p1 = @c.create :name => "Hm", :parent_id => 0
1512
+ p2 = @c.create :name => "Ps", :parent_id => p1.id
1513
+ @c.create :name => "P1", :parent_id => p2.id
1514
+ @c.create :name => "P2", :parent_id => p2.id
1515
+ @c.create :name => "P3", :parent_id => p2.id
1516
+ @c.create :name => "Au", :parent_id => p1.id
1517
+ end
1518
+ after(:all) do
1519
+ @db.drop_table?(:pages)
1091
1520
  end
1092
1521
 
1093
- it "should return rows in order of position" do
1522
+ specify "should return rows in order of position" do
1094
1523
  @c.map(:name).should == %w[ Hm Ps Au P1 P2 P3 ]
1095
1524
  end
1096
1525
 
@@ -1111,7 +1540,7 @@ describe "List plugin with a scope" do
1111
1540
  @c[:name => "P3"].next.should == nil
1112
1541
  end
1113
1542
 
1114
- it "should define move_to" do
1543
+ specify "should define move_to" do
1115
1544
  @c[:name => "P2"].move_to(1)
1116
1545
  @c.map(:name).should == %w[ Hm Ps Au P2 P1 P3 ]
1117
1546
 
@@ -1122,7 +1551,7 @@ describe "List plugin with a scope" do
1122
1551
  proc { @c[:name => "P2"].move_to(10) }.should raise_error(Sequel::Error)
1123
1552
  end
1124
1553
 
1125
- it "should define move_to_top and move_to_bottom" do
1554
+ specify "should define move_to_top and move_to_bottom" do
1126
1555
  @c[:name => "Au"].move_to_top
1127
1556
  @c.map(:name).should == %w[ Hm Au Ps P1 P2 P3 ]
1128
1557
 
@@ -1130,7 +1559,7 @@ describe "List plugin with a scope" do
1130
1559
  @c.map(:name).should == %w[ Hm Ps Au P1 P2 P3 ]
1131
1560
  end
1132
1561
 
1133
- it "should define move_up and move_down" do
1562
+ specify "should define move_up and move_down" do
1134
1563
  @c[:name => "P2"].move_up
1135
1564
  @c.map(:name).should == %w[ Hm Ps Au P2 P1 P3 ]
1136
1565
 
@@ -1143,12 +1572,12 @@ describe "List plugin with a scope" do
1143
1572
  end
1144
1573
 
1145
1574
  describe "Sequel::Plugins::Tree" do
1146
- before do
1575
+ before(:all) do
1147
1576
  @db = INTEGRATION_DB
1148
1577
  end
1149
1578
 
1150
1579
  describe "with natural database order" do
1151
- before do
1580
+ before(:all) do
1152
1581
  @db.create_table!(:nodes) do
1153
1582
  Integer :id, :primary_key=>true
1154
1583
  String :name
@@ -1174,8 +1603,8 @@ describe "Sequel::Plugins::Tree" do
1174
1603
  plugin :tree
1175
1604
  end
1176
1605
  end
1177
- after do
1178
- @db.drop_table(:nodes)
1606
+ after(:all) do
1607
+ @db.drop_table?(:nodes)
1179
1608
  Object.send(:remove_const, :Node)
1180
1609
  end
1181
1610
 
@@ -1249,12 +1678,12 @@ describe "Sequel::Plugins::Tree" do
1249
1678
  end
1250
1679
 
1251
1680
  describe "Nodes in specified order" do
1252
- before do
1681
+ before(:all) do
1253
1682
  class ::OrderedNode < Sequel::Model(:nodes)
1254
1683
  plugin :tree, :order => :position
1255
1684
  end
1256
1685
  end
1257
- after do
1686
+ after(:all) do
1258
1687
  Object.send(:remove_const, :OrderedNode)
1259
1688
  end
1260
1689
 
@@ -1272,7 +1701,7 @@ describe "Sequel::Plugins::Tree" do
1272
1701
  end
1273
1702
 
1274
1703
  describe "Lorems in specified order" do
1275
- before do
1704
+ before(:all) do
1276
1705
  @db.create_table!(:lorems) do
1277
1706
  Integer :id, :primary_key=>true
1278
1707
  String :name
@@ -1290,8 +1719,8 @@ describe "Sequel::Plugins::Tree" do
1290
1719
  plugin :tree, :key => :ipsum_id, :order => :neque
1291
1720
  end
1292
1721
  end
1293
- after do
1294
- @db.drop_table(:lorems)
1722
+ after(:all) do
1723
+ @db.drop_table?(:lorems)
1295
1724
  Object.send(:remove_const, :Lorem)
1296
1725
  end
1297
1726
 
@@ -1306,3 +1735,285 @@ describe "Sequel::Plugins::Tree" do
1306
1735
  end
1307
1736
  end
1308
1737
  end
1738
+
1739
+ describe "Sequel::Plugins::PreparedStatements" do
1740
+ before(:all) do
1741
+ @db = INTEGRATION_DB
1742
+ @db.create_table!(:ps_test) do
1743
+ primary_key :id
1744
+ String :name
1745
+ Integer :i
1746
+ end
1747
+ @c = Class.new(Sequel::Model(@db[:ps_test]))
1748
+ @c.plugin :prepared_statements_with_pk
1749
+ end
1750
+ before do
1751
+ @c.delete
1752
+ @foo = @c.create(:name=>'foo', :i=>10)
1753
+ @bar = @c.create(:name=>'bar', :i=>20)
1754
+ end
1755
+ after(:all) do
1756
+ @db.drop_table?(:ps_test)
1757
+ end
1758
+
1759
+ it "should work with looking up using Model.[]" do
1760
+ @c[@foo.id].should == @foo
1761
+ @c[@bar.id].should == @bar
1762
+ @c[0].should == nil
1763
+ @c[nil].should == nil
1764
+ end
1765
+
1766
+ it "should work with looking up using Dataset#with_pk" do
1767
+ @c.dataset.with_pk(@foo.id).should == @foo
1768
+ @c.dataset.with_pk(@bar.id).should == @bar
1769
+ @c.dataset.with_pk(0).should == nil
1770
+ @c.dataset.with_pk(nil).should == nil
1771
+
1772
+ @c.dataset.filter(:i=>0).with_pk(@foo.id).should == nil
1773
+ @c.dataset.filter(:i=>10).with_pk(@foo.id).should == @foo
1774
+ @c.dataset.filter(:i=>20).with_pk(@bar.id).should == @bar
1775
+ @c.dataset.filter(:i=>10).with_pk(nil).should == nil
1776
+ @c.dataset.filter(:name=>'foo').with_pk(@foo.id).should == @foo
1777
+ @c.dataset.filter(:name=>'bar').with_pk(@bar.id).should == @bar
1778
+ @c.dataset.filter(:name=>'baz').with_pk(@bar.id).should == nil
1779
+ @c.dataset.filter(:name=>'bar').with_pk(nil).should == nil
1780
+ end
1781
+
1782
+ it "should work with Model#destroy" do
1783
+ @foo.destroy
1784
+ @bar.destroy
1785
+ @c[@foo.id].should == nil
1786
+ @c[@bar.id].should == nil
1787
+ end
1788
+
1789
+ it "should work with Model#update" do
1790
+ @foo.update(:name=>'foo2', :i=>30)
1791
+ @c[@foo.id].should == @c.load(:id=>@foo.id, :name=>'foo2', :i=>30)
1792
+ @foo.update(:name=>'foo3')
1793
+ @c[@foo.id].should == @c.load(:id=>@foo.id, :name=>'foo3', :i=>30)
1794
+ @foo.update(:i=>40)
1795
+ @c[@foo.id].should == @c.load(:id=>@foo.id, :name=>'foo3', :i=>40)
1796
+ @foo.update(:i=>nil)
1797
+ @c[@foo.id].should == @c.load(:id=>@foo.id, :name=>'foo3', :i=>nil)
1798
+ end
1799
+
1800
+ it "should work with Model#create" do
1801
+ o = @c.create(:name=>'foo2', :i=>30)
1802
+ @c[o.id].should == @c.load(:id=>o.id, :name=>'foo2', :i=>30)
1803
+ o = @c.create(:name=>'foo2')
1804
+ @c[o.id].should == @c.load(:id=>o.id, :name=>'foo2', :i=>nil)
1805
+ o = @c.create(:i=>30)
1806
+ @c[o.id].should == @c.load(:id=>o.id, :name=>nil, :i=>30)
1807
+ o = @c.create(:name=>nil, :i=>40)
1808
+ @c[o.id].should == @c.load(:id=>o.id, :name=>nil, :i=>40)
1809
+ end
1810
+ end
1811
+
1812
+ describe "Caching plugins" do
1813
+ before(:all) do
1814
+ @db = INTEGRATION_DB
1815
+ @db.drop_table?(:albums, :artists)
1816
+ @db.create_table(:artists) do
1817
+ primary_key :id
1818
+ end
1819
+ @db.create_table(:albums) do
1820
+ primary_key :id
1821
+ foreign_key :artist_id, :artists
1822
+ end
1823
+ @db[:artists].insert
1824
+ @db[:albums].insert(:artist_id=>1)
1825
+ end
1826
+ before do
1827
+ @Album = Class.new(Sequel::Model(@db[:albums]))
1828
+ @Album.plugin :many_to_one_pk_lookup
1829
+ end
1830
+ after(:all) do
1831
+ @db.drop_table?(:albums, :artists)
1832
+ end
1833
+
1834
+ shared_examples_for "a caching plugin" do
1835
+ it "should work with looking up using Model.[]" do
1836
+ @Artist[1].should equal(@Artist[1])
1837
+ @Artist[:id=>1].should == @Artist[1]
1838
+ @Artist[0].should == nil
1839
+ @Artist[nil].should == nil
1840
+ end
1841
+
1842
+ it "should work with lookup up many_to_one associated objects" do
1843
+ a = @Artist[1]
1844
+ @Album.first.artist.should equal(a)
1845
+ end
1846
+ end
1847
+
1848
+ describe "caching plugin" do
1849
+ before do
1850
+ @cache_class = Class.new(Hash) do
1851
+ def set(k, v, ttl) self[k] = v end
1852
+ alias get []
1853
+ end
1854
+ @cache = @cache_class.new
1855
+
1856
+ @Artist = Class.new(Sequel::Model(@db[:artists]))
1857
+ @Artist.plugin :caching, @cache
1858
+ @Album.many_to_one :artist, :class=>@Artist
1859
+ end
1860
+
1861
+ it_should_behave_like "a caching plugin"
1862
+ end
1863
+
1864
+ describe "static_cache plugin" do
1865
+ before do
1866
+ @Artist = Class.new(Sequel::Model(@db[:artists]))
1867
+ @Artist.plugin :static_cache
1868
+ @Album.many_to_one :artist, :class=>@Artist
1869
+ end
1870
+
1871
+ it_should_behave_like "a caching plugin"
1872
+ end
1873
+ end
1874
+
1875
+ describe "Sequel::Plugins::ConstraintValidations" do
1876
+ before(:all) do
1877
+ @db = INTEGRATION_DB
1878
+ @db.extension(:constraint_validations)
1879
+ @db.create_constraint_validations_table
1880
+ @ds = @db[:cv_test]
1881
+ @regexp = regexp = @db.dataset.supports_regexp?
1882
+ @validate_block = proc do
1883
+ presence :pre, :name=>:p
1884
+ exact_length 5, :exactlen, :name=>:el
1885
+ min_length 5, :minlen, :name=>:minl
1886
+ max_length 5, :maxlen, :name=>:maxl
1887
+ length_range 3..5, :lenrange, :name=>:lr
1888
+ if regexp
1889
+ format /^foo\d+/, :form, :name=>:f
1890
+ end
1891
+ like 'foo%', :lik, :name=>:l
1892
+ ilike 'foo%', :ilik, :name=>:il
1893
+ includes %w'abc def', :inc, :name=>:i
1894
+ unique :uniq, :name=>:u
1895
+ max_length 6, :minlen, :name=>:maxl2
1896
+ end
1897
+ @valid_row = {:pre=>'a', :exactlen=>'12345', :minlen=>'12345', :maxlen=>'12345', :lenrange=>'1234', :lik=>'fooabc', :ilik=>'FooABC', :inc=>'abc', :uniq=>'u'}
1898
+ @violations = [
1899
+ [:pre, [nil, '', ' ']],
1900
+ [:exactlen, [nil, '', '1234', '123456']],
1901
+ [:minlen, [nil, '', '1234']],
1902
+ [:maxlen, [nil, '123456']],
1903
+ [:lenrange, [nil, '', '12', '123456']],
1904
+ [:lik, [nil, '', 'fo', 'fotabc', 'FOOABC']],
1905
+ [:ilik, [nil, '', 'fo', 'fotabc']],
1906
+ [:inc, [nil, '', 'ab', 'abcd']],
1907
+ ]
1908
+
1909
+ if @regexp
1910
+ @valid_row[:form] = 'foo1'
1911
+ @violations << [:form, [nil, '', 'foo', 'fooa']]
1912
+ end
1913
+ end
1914
+ after(:all) do
1915
+ @db.drop_constraint_validations_table
1916
+ end
1917
+
1918
+ shared_examples_for "constraint validations" do
1919
+ cspecify "should set up constraints that work even outside the model", :mysql do
1920
+ proc{@ds.insert(@valid_row)}.should_not raise_error
1921
+
1922
+ # Test for unique constraint
1923
+ proc{@ds.insert(@valid_row)}.should raise_error(Sequel::DatabaseError)
1924
+
1925
+ @ds.delete
1926
+ @violations.each do |col, vals|
1927
+ try = @valid_row.dup
1928
+ vals += ['1234567'] if col == :minlen
1929
+ vals.each do |val|
1930
+ try[col] = val
1931
+ proc{@ds.insert(try)}.should raise_error(Sequel::DatabaseError)
1932
+ end
1933
+ end
1934
+
1935
+ # Test for dropping of constraint
1936
+ @db.alter_table(:cv_test){validate{drop :maxl2}}
1937
+ proc{@ds.insert(@valid_row.merge(:minlen=>'1234567'))}.should_not raise_error
1938
+ end
1939
+
1940
+ it "should set up automatic validations inside the model" do
1941
+ c = Class.new(Sequel::Model(@ds))
1942
+ c.plugin :constraint_validations
1943
+ c.delete
1944
+ proc{c.create(@valid_row)}.should_not raise_error
1945
+
1946
+ # Test for unique validation
1947
+ c.new(@valid_row).should_not be_valid
1948
+
1949
+ c.delete
1950
+ @violations.each do |col, vals|
1951
+ try = @valid_row.dup
1952
+ vals.each do |val|
1953
+ try[col] = val
1954
+ c.new(try).should_not be_valid
1955
+ end
1956
+ end
1957
+ end
1958
+ end
1959
+
1960
+ describe "via create_table" do
1961
+ before(:all) do
1962
+ regexp = @regexp
1963
+ validate_block = @validate_block
1964
+ @db.create_table!(:cv_test) do
1965
+ primary_key :id
1966
+ String :pre
1967
+ String :exactlen
1968
+ String :minlen
1969
+ String :maxlen
1970
+ String :lenrange
1971
+ if regexp
1972
+ String :form
1973
+ end
1974
+ String :lik
1975
+ String :ilik
1976
+ String :inc
1977
+ String :uniq, :null=>false
1978
+ validate(&validate_block)
1979
+ end
1980
+ end
1981
+ after(:all) do
1982
+ @db.drop_table?(:cv_test)
1983
+ @db.drop_constraint_validations_for(:table=>:cv_test)
1984
+ end
1985
+
1986
+ it_should_behave_like "constraint validations"
1987
+ end
1988
+
1989
+ describe "via alter_table" do
1990
+ before(:all) do
1991
+ regexp = @regexp
1992
+ validate_block = @validate_block
1993
+ @db.create_table!(:cv_test) do
1994
+ primary_key :id
1995
+ String :lik
1996
+ String :ilik
1997
+ String :inc
1998
+ String :uniq, :null=>false
1999
+ end
2000
+ @db.alter_table(:cv_test) do
2001
+ add_column :pre, String
2002
+ add_column :exactlen, String
2003
+ add_column :minlen, String
2004
+ add_column :maxlen, String
2005
+ add_column :lenrange, String
2006
+ if regexp
2007
+ add_column :form, String
2008
+ end
2009
+ validate(&validate_block)
2010
+ end
2011
+ end
2012
+ after(:all) do
2013
+ @db.drop_table?(:cv_test)
2014
+ @db.drop_constraint_validations_for(:table=>:cv_test)
2015
+ end
2016
+
2017
+ it_should_behave_like "constraint validations"
2018
+ end
2019
+ end