sequel 4.26.0 → 5.37.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (692) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +405 -5656
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +232 -157
  5. data/bin/sequel +32 -9
  6. data/doc/advanced_associations.rdoc +252 -188
  7. data/doc/association_basics.rdoc +231 -273
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +75 -48
  10. data/doc/code_order.rdoc +28 -10
  11. data/doc/core_extensions.rdoc +104 -63
  12. data/doc/dataset_basics.rdoc +12 -21
  13. data/doc/dataset_filtering.rdoc +99 -86
  14. data/doc/extensions.rdoc +3 -10
  15. data/doc/mass_assignment.rdoc +74 -31
  16. data/doc/migration.rdoc +72 -46
  17. data/doc/model_dataset_method_design.rdoc +129 -0
  18. data/doc/model_hooks.rdoc +15 -25
  19. data/doc/model_plugins.rdoc +12 -12
  20. data/doc/mssql_stored_procedures.rdoc +3 -3
  21. data/doc/object_model.rdoc +59 -69
  22. data/doc/opening_databases.rdoc +84 -94
  23. data/doc/postgresql.rdoc +268 -38
  24. data/doc/prepared_statements.rdoc +29 -24
  25. data/doc/querying.rdoc +184 -164
  26. data/doc/reflection.rdoc +5 -6
  27. data/doc/release_notes/5.0.0.txt +159 -0
  28. data/doc/release_notes/5.1.0.txt +31 -0
  29. data/doc/release_notes/5.10.0.txt +84 -0
  30. data/doc/release_notes/5.11.0.txt +83 -0
  31. data/doc/release_notes/5.12.0.txt +141 -0
  32. data/doc/release_notes/5.13.0.txt +27 -0
  33. data/doc/release_notes/5.14.0.txt +63 -0
  34. data/doc/release_notes/5.15.0.txt +39 -0
  35. data/doc/release_notes/5.16.0.txt +110 -0
  36. data/doc/release_notes/5.17.0.txt +31 -0
  37. data/doc/release_notes/5.18.0.txt +69 -0
  38. data/doc/release_notes/5.19.0.txt +28 -0
  39. data/doc/release_notes/5.2.0.txt +33 -0
  40. data/doc/release_notes/5.20.0.txt +89 -0
  41. data/doc/release_notes/5.21.0.txt +87 -0
  42. data/doc/release_notes/5.22.0.txt +48 -0
  43. data/doc/release_notes/5.23.0.txt +56 -0
  44. data/doc/release_notes/5.24.0.txt +56 -0
  45. data/doc/release_notes/5.25.0.txt +32 -0
  46. data/doc/release_notes/5.26.0.txt +35 -0
  47. data/doc/release_notes/5.27.0.txt +21 -0
  48. data/doc/release_notes/5.28.0.txt +16 -0
  49. data/doc/release_notes/5.29.0.txt +22 -0
  50. data/doc/release_notes/5.3.0.txt +121 -0
  51. data/doc/release_notes/5.30.0.txt +20 -0
  52. data/doc/release_notes/5.31.0.txt +148 -0
  53. data/doc/release_notes/5.32.0.txt +46 -0
  54. data/doc/release_notes/5.33.0.txt +24 -0
  55. data/doc/release_notes/5.34.0.txt +40 -0
  56. data/doc/release_notes/5.35.0.txt +56 -0
  57. data/doc/release_notes/5.36.0.txt +60 -0
  58. data/doc/release_notes/5.37.0.txt +30 -0
  59. data/doc/release_notes/5.4.0.txt +80 -0
  60. data/doc/release_notes/5.5.0.txt +61 -0
  61. data/doc/release_notes/5.6.0.txt +31 -0
  62. data/doc/release_notes/5.7.0.txt +108 -0
  63. data/doc/release_notes/5.8.0.txt +170 -0
  64. data/doc/release_notes/5.9.0.txt +99 -0
  65. data/doc/schema_modification.rdoc +102 -77
  66. data/doc/security.rdoc +160 -87
  67. data/doc/sharding.rdoc +74 -47
  68. data/doc/sql.rdoc +135 -122
  69. data/doc/testing.rdoc +34 -18
  70. data/doc/thread_safety.rdoc +2 -4
  71. data/doc/transactions.rdoc +101 -19
  72. data/doc/validations.rdoc +64 -51
  73. data/doc/virtual_rows.rdoc +90 -109
  74. data/lib/sequel.rb +3 -1
  75. data/lib/sequel/adapters/ado.rb +154 -22
  76. data/lib/sequel/adapters/ado/access.rb +21 -21
  77. data/lib/sequel/adapters/ado/mssql.rb +8 -15
  78. data/lib/sequel/adapters/amalgalite.rb +17 -25
  79. data/lib/sequel/adapters/ibmdb.rb +52 -58
  80. data/lib/sequel/adapters/jdbc.rb +149 -127
  81. data/lib/sequel/adapters/jdbc/db2.rb +32 -40
  82. data/lib/sequel/adapters/jdbc/derby.rb +56 -58
  83. data/lib/sequel/adapters/jdbc/h2.rb +40 -30
  84. data/lib/sequel/adapters/jdbc/hsqldb.rb +22 -33
  85. data/lib/sequel/adapters/jdbc/jtds.rb +4 -10
  86. data/lib/sequel/adapters/jdbc/mssql.rb +6 -12
  87. data/lib/sequel/adapters/jdbc/mysql.rb +17 -18
  88. data/lib/sequel/adapters/jdbc/oracle.rb +25 -19
  89. data/lib/sequel/adapters/jdbc/postgresql.rb +90 -69
  90. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +14 -24
  91. data/lib/sequel/adapters/jdbc/sqlite.rb +50 -12
  92. data/lib/sequel/adapters/jdbc/sqlserver.rb +36 -9
  93. data/lib/sequel/adapters/jdbc/transactions.rb +25 -39
  94. data/lib/sequel/adapters/mock.rb +104 -113
  95. data/lib/sequel/adapters/mysql.rb +42 -61
  96. data/lib/sequel/adapters/mysql2.rb +126 -35
  97. data/lib/sequel/adapters/odbc.rb +21 -28
  98. data/lib/sequel/adapters/odbc/db2.rb +3 -1
  99. data/lib/sequel/adapters/odbc/mssql.rb +11 -15
  100. data/lib/sequel/adapters/odbc/oracle.rb +11 -0
  101. data/lib/sequel/adapters/oracle.rb +62 -68
  102. data/lib/sequel/adapters/postgres.rb +257 -311
  103. data/lib/sequel/adapters/postgresql.rb +3 -1
  104. data/lib/sequel/adapters/shared/access.rb +75 -79
  105. data/lib/sequel/adapters/shared/db2.rb +96 -74
  106. data/lib/sequel/adapters/shared/mssql.rb +258 -213
  107. data/lib/sequel/adapters/shared/mysql.rb +284 -216
  108. data/lib/sequel/adapters/shared/oracle.rb +175 -60
  109. data/lib/sequel/adapters/shared/postgres.rb +829 -383
  110. data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -127
  111. data/lib/sequel/adapters/shared/sqlite.rb +382 -159
  112. data/lib/sequel/adapters/sqlanywhere.rb +53 -38
  113. data/lib/sequel/adapters/sqlite.rb +111 -105
  114. data/lib/sequel/adapters/tinytds.rb +38 -46
  115. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -9
  116. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -5
  117. data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
  118. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
  119. data/lib/sequel/adapters/utils/replace.rb +3 -4
  120. data/lib/sequel/adapters/utils/split_alter_table.rb +2 -0
  121. data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
  122. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
  123. data/lib/sequel/ast_transformer.rb +13 -89
  124. data/lib/sequel/connection_pool.rb +54 -26
  125. data/lib/sequel/connection_pool/sharded_single.rb +19 -12
  126. data/lib/sequel/connection_pool/sharded_threaded.rb +160 -111
  127. data/lib/sequel/connection_pool/single.rb +21 -12
  128. data/lib/sequel/connection_pool/threaded.rb +137 -119
  129. data/lib/sequel/core.rb +352 -320
  130. data/lib/sequel/database.rb +19 -2
  131. data/lib/sequel/database/connecting.rb +70 -55
  132. data/lib/sequel/database/dataset.rb +15 -5
  133. data/lib/sequel/database/dataset_defaults.rb +20 -102
  134. data/lib/sequel/database/features.rb +20 -4
  135. data/lib/sequel/database/logging.rb +25 -7
  136. data/lib/sequel/database/misc.rb +132 -118
  137. data/lib/sequel/database/query.rb +51 -28
  138. data/lib/sequel/database/schema_generator.rb +188 -75
  139. data/lib/sequel/database/schema_methods.rb +161 -92
  140. data/lib/sequel/database/transactions.rb +260 -58
  141. data/lib/sequel/dataset.rb +28 -12
  142. data/lib/sequel/dataset/actions.rb +354 -170
  143. data/lib/sequel/dataset/dataset_module.rb +46 -0
  144. data/lib/sequel/dataset/features.rb +81 -34
  145. data/lib/sequel/dataset/graph.rb +82 -58
  146. data/lib/sequel/dataset/misc.rb +139 -47
  147. data/lib/sequel/dataset/placeholder_literalizer.rb +66 -26
  148. data/lib/sequel/dataset/prepared_statements.rb +188 -85
  149. data/lib/sequel/dataset/query.rb +428 -214
  150. data/lib/sequel/dataset/sql.rb +446 -339
  151. data/lib/sequel/deprecated.rb +14 -2
  152. data/lib/sequel/exceptions.rb +48 -16
  153. data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
  154. data/lib/sequel/extensions/_model_pg_row.rb +43 -0
  155. data/lib/sequel/extensions/_pretty_table.rb +10 -9
  156. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  157. data/lib/sequel/extensions/arbitrary_servers.rb +15 -11
  158. data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  159. data/lib/sequel/extensions/blank.rb +2 -0
  160. data/lib/sequel/extensions/caller_logging.rb +79 -0
  161. data/lib/sequel/extensions/columns_introspection.rb +9 -4
  162. data/lib/sequel/extensions/connection_expiration.rb +99 -0
  163. data/lib/sequel/extensions/connection_validator.rb +26 -13
  164. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  165. data/lib/sequel/extensions/constraint_validations.rb +93 -38
  166. data/lib/sequel/extensions/core_extensions.rb +45 -53
  167. data/lib/sequel/extensions/core_refinements.rb +44 -46
  168. data/lib/sequel/extensions/current_datetime_timestamp.rb +5 -4
  169. data/lib/sequel/extensions/dataset_source_alias.rb +4 -0
  170. data/lib/sequel/extensions/date_arithmetic.rb +42 -16
  171. data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
  172. data/lib/sequel/extensions/duplicate_columns_handler.rb +94 -0
  173. data/lib/sequel/extensions/empty_array_consider_nulls.rb +7 -3
  174. data/lib/sequel/extensions/error_sql.rb +7 -3
  175. data/lib/sequel/extensions/escaped_like.rb +100 -0
  176. data/lib/sequel/extensions/eval_inspect.rb +14 -15
  177. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  178. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  179. data/lib/sequel/extensions/freeze_datasets.rb +3 -0
  180. data/lib/sequel/extensions/from_block.rb +2 -31
  181. data/lib/sequel/extensions/graph_each.rb +19 -6
  182. data/lib/sequel/extensions/identifier_mangling.rb +180 -0
  183. data/lib/sequel/extensions/implicit_subquery.rb +48 -0
  184. data/lib/sequel/extensions/index_caching.rb +109 -0
  185. data/lib/sequel/extensions/inflector.rb +8 -4
  186. data/lib/sequel/extensions/integer64.rb +32 -0
  187. data/lib/sequel/extensions/looser_typecasting.rb +19 -9
  188. data/lib/sequel/extensions/migration.rb +132 -80
  189. data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +4 -0
  190. data/lib/sequel/extensions/named_timezones.rb +88 -23
  191. data/lib/sequel/extensions/no_auto_literal_strings.rb +4 -0
  192. data/lib/sequel/extensions/null_dataset.rb +12 -8
  193. data/lib/sequel/extensions/pagination.rb +35 -28
  194. data/lib/sequel/extensions/pg_array.rb +227 -316
  195. data/lib/sequel/extensions/pg_array_ops.rb +19 -7
  196. data/lib/sequel/extensions/pg_enum.rb +69 -24
  197. data/lib/sequel/extensions/pg_extended_date_support.rb +250 -0
  198. data/lib/sequel/extensions/pg_hstore.rb +50 -59
  199. data/lib/sequel/extensions/pg_hstore_ops.rb +9 -3
  200. data/lib/sequel/extensions/pg_inet.rb +34 -15
  201. data/lib/sequel/extensions/pg_inet_ops.rb +5 -1
  202. data/lib/sequel/extensions/pg_interval.rb +26 -26
  203. data/lib/sequel/extensions/pg_json.rb +422 -141
  204. data/lib/sequel/extensions/pg_json_ops.rb +248 -9
  205. data/lib/sequel/extensions/pg_loose_count.rb +5 -1
  206. data/lib/sequel/extensions/pg_range.rb +162 -146
  207. data/lib/sequel/extensions/pg_range_ops.rb +10 -5
  208. data/lib/sequel/extensions/pg_row.rb +53 -87
  209. data/lib/sequel/extensions/pg_row_ops.rb +36 -13
  210. data/lib/sequel/extensions/pg_static_cache_updater.rb +6 -2
  211. data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
  212. data/lib/sequel/extensions/pretty_table.rb +4 -0
  213. data/lib/sequel/extensions/query.rb +12 -7
  214. data/lib/sequel/extensions/round_timestamps.rb +6 -9
  215. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  216. data/lib/sequel/extensions/s.rb +59 -0
  217. data/lib/sequel/extensions/schema_caching.rb +14 -1
  218. data/lib/sequel/extensions/schema_dumper.rb +83 -55
  219. data/lib/sequel/extensions/select_remove.rb +8 -4
  220. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
  221. data/lib/sequel/extensions/server_block.rb +50 -17
  222. data/lib/sequel/extensions/server_logging.rb +61 -0
  223. data/lib/sequel/extensions/split_array_nil.rb +8 -4
  224. data/lib/sequel/extensions/sql_comments.rb +96 -0
  225. data/lib/sequel/extensions/sql_expr.rb +4 -1
  226. data/lib/sequel/extensions/string_agg.rb +181 -0
  227. data/lib/sequel/extensions/string_date_time.rb +2 -0
  228. data/lib/sequel/extensions/symbol_aref.rb +53 -0
  229. data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
  230. data/lib/sequel/extensions/symbol_as.rb +23 -0
  231. data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
  232. data/lib/sequel/extensions/synchronize_sql.rb +45 -0
  233. data/lib/sequel/extensions/thread_local_timezones.rb +4 -0
  234. data/lib/sequel/extensions/to_dot.rb +15 -5
  235. data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
  236. data/lib/sequel/model.rb +36 -126
  237. data/lib/sequel/model/associations.rb +850 -257
  238. data/lib/sequel/model/base.rb +652 -764
  239. data/lib/sequel/model/dataset_module.rb +13 -10
  240. data/lib/sequel/model/default_inflections.rb +3 -1
  241. data/lib/sequel/model/errors.rb +3 -3
  242. data/lib/sequel/model/exceptions.rb +12 -12
  243. data/lib/sequel/model/inflections.rb +8 -19
  244. data/lib/sequel/model/plugins.rb +111 -0
  245. data/lib/sequel/plugins/accessed_columns.rb +2 -0
  246. data/lib/sequel/plugins/active_model.rb +32 -7
  247. data/lib/sequel/plugins/after_initialize.rb +3 -1
  248. data/lib/sequel/plugins/association_dependencies.rb +27 -18
  249. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  250. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  251. data/lib/sequel/plugins/association_pks.rb +181 -83
  252. data/lib/sequel/plugins/association_proxies.rb +33 -9
  253. data/lib/sequel/plugins/auto_validations.rb +58 -23
  254. data/lib/sequel/plugins/before_after_save.rb +8 -0
  255. data/lib/sequel/plugins/blacklist_security.rb +23 -12
  256. data/lib/sequel/plugins/boolean_readers.rb +9 -6
  257. data/lib/sequel/plugins/boolean_subsets.rb +64 -0
  258. data/lib/sequel/plugins/caching.rb +27 -16
  259. data/lib/sequel/plugins/class_table_inheritance.rb +192 -94
  260. data/lib/sequel/plugins/column_conflicts.rb +18 -3
  261. data/lib/sequel/plugins/column_select.rb +9 -5
  262. data/lib/sequel/plugins/columns_updated.rb +42 -0
  263. data/lib/sequel/plugins/composition.rb +36 -24
  264. data/lib/sequel/plugins/constraint_validations.rb +37 -16
  265. data/lib/sequel/plugins/csv_serializer.rb +58 -35
  266. data/lib/sequel/plugins/dataset_associations.rb +60 -18
  267. data/lib/sequel/plugins/def_dataset_method.rb +90 -0
  268. data/lib/sequel/plugins/defaults_setter.rb +74 -13
  269. data/lib/sequel/plugins/delay_add_association.rb +4 -1
  270. data/lib/sequel/plugins/dirty.rb +65 -24
  271. data/lib/sequel/plugins/eager_each.rb +27 -3
  272. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  273. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  274. data/lib/sequel/plugins/error_splitter.rb +19 -12
  275. data/lib/sequel/plugins/finder.rb +246 -0
  276. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  277. data/lib/sequel/plugins/force_encoding.rb +9 -12
  278. data/lib/sequel/plugins/hook_class_methods.rb +39 -54
  279. data/lib/sequel/plugins/input_transformer.rb +20 -10
  280. data/lib/sequel/plugins/insert_conflict.rb +72 -0
  281. data/lib/sequel/plugins/insert_returning_select.rb +4 -2
  282. data/lib/sequel/plugins/instance_filters.rb +12 -8
  283. data/lib/sequel/plugins/instance_hooks.rb +36 -17
  284. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  285. data/lib/sequel/plugins/inverted_subsets.rb +24 -13
  286. data/lib/sequel/plugins/json_serializer.rb +123 -47
  287. data/lib/sequel/plugins/lazy_attributes.rb +20 -14
  288. data/lib/sequel/plugins/list.rb +40 -26
  289. data/lib/sequel/plugins/many_through_many.rb +28 -12
  290. data/lib/sequel/plugins/modification_detection.rb +17 -5
  291. data/lib/sequel/plugins/mssql_optimistic_locking.rb +8 -5
  292. data/lib/sequel/plugins/nested_attributes.rb +55 -28
  293. data/lib/sequel/plugins/optimistic_locking.rb +5 -3
  294. data/lib/sequel/plugins/pg_array_associations.rb +52 -18
  295. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +348 -0
  296. data/lib/sequel/plugins/pg_row.rb +7 -51
  297. data/lib/sequel/plugins/prepared_statements.rb +53 -72
  298. data/lib/sequel/plugins/prepared_statements_safe.rb +13 -5
  299. data/lib/sequel/plugins/rcte_tree.rb +43 -63
  300. data/lib/sequel/plugins/serialization.rb +37 -44
  301. data/lib/sequel/plugins/serialization_modification_detection.rb +3 -1
  302. data/lib/sequel/plugins/sharding.rb +17 -10
  303. data/lib/sequel/plugins/single_table_inheritance.rb +62 -28
  304. data/lib/sequel/plugins/singular_table_names.rb +2 -0
  305. data/lib/sequel/plugins/skip_create_refresh.rb +5 -3
  306. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  307. data/lib/sequel/plugins/split_values.rb +13 -6
  308. data/lib/sequel/plugins/static_cache.rb +79 -53
  309. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  310. data/lib/sequel/plugins/string_stripper.rb +5 -3
  311. data/lib/sequel/plugins/subclasses.rb +20 -2
  312. data/lib/sequel/plugins/subset_conditions.rb +48 -0
  313. data/lib/sequel/plugins/table_select.rb +4 -2
  314. data/lib/sequel/plugins/tactical_eager_loading.rb +120 -6
  315. data/lib/sequel/plugins/throw_failures.rb +110 -0
  316. data/lib/sequel/plugins/timestamps.rb +22 -8
  317. data/lib/sequel/plugins/touch.rb +21 -8
  318. data/lib/sequel/plugins/tree.rb +57 -30
  319. data/lib/sequel/plugins/typecast_on_load.rb +14 -4
  320. data/lib/sequel/plugins/unlimited_update.rb +3 -7
  321. data/lib/sequel/plugins/update_or_create.rb +6 -4
  322. data/lib/sequel/plugins/update_primary_key.rb +3 -1
  323. data/lib/sequel/plugins/update_refresh.rb +28 -15
  324. data/lib/sequel/plugins/uuid.rb +70 -0
  325. data/lib/sequel/plugins/validate_associated.rb +20 -0
  326. data/lib/sequel/plugins/validation_class_methods.rb +40 -19
  327. data/lib/sequel/plugins/validation_contexts.rb +49 -0
  328. data/lib/sequel/plugins/validation_helpers.rb +49 -31
  329. data/lib/sequel/plugins/whitelist_security.rb +122 -0
  330. data/lib/sequel/plugins/xml_serializer.rb +31 -30
  331. data/lib/sequel/sql.rb +479 -329
  332. data/lib/sequel/timezones.rb +62 -32
  333. data/lib/sequel/version.rb +10 -3
  334. metadata +177 -477
  335. data/Rakefile +0 -165
  336. data/doc/active_record.rdoc +0 -912
  337. data/doc/release_notes/1.0.txt +0 -38
  338. data/doc/release_notes/1.1.txt +0 -143
  339. data/doc/release_notes/1.3.txt +0 -101
  340. data/doc/release_notes/1.4.0.txt +0 -53
  341. data/doc/release_notes/1.5.0.txt +0 -155
  342. data/doc/release_notes/2.0.0.txt +0 -298
  343. data/doc/release_notes/2.1.0.txt +0 -271
  344. data/doc/release_notes/2.10.0.txt +0 -328
  345. data/doc/release_notes/2.11.0.txt +0 -215
  346. data/doc/release_notes/2.12.0.txt +0 -534
  347. data/doc/release_notes/2.2.0.txt +0 -253
  348. data/doc/release_notes/2.3.0.txt +0 -88
  349. data/doc/release_notes/2.4.0.txt +0 -106
  350. data/doc/release_notes/2.5.0.txt +0 -137
  351. data/doc/release_notes/2.6.0.txt +0 -157
  352. data/doc/release_notes/2.7.0.txt +0 -166
  353. data/doc/release_notes/2.8.0.txt +0 -171
  354. data/doc/release_notes/2.9.0.txt +0 -97
  355. data/doc/release_notes/3.0.0.txt +0 -221
  356. data/doc/release_notes/3.1.0.txt +0 -406
  357. data/doc/release_notes/3.10.0.txt +0 -286
  358. data/doc/release_notes/3.11.0.txt +0 -254
  359. data/doc/release_notes/3.12.0.txt +0 -304
  360. data/doc/release_notes/3.13.0.txt +0 -210
  361. data/doc/release_notes/3.14.0.txt +0 -118
  362. data/doc/release_notes/3.15.0.txt +0 -78
  363. data/doc/release_notes/3.16.0.txt +0 -45
  364. data/doc/release_notes/3.17.0.txt +0 -58
  365. data/doc/release_notes/3.18.0.txt +0 -120
  366. data/doc/release_notes/3.19.0.txt +0 -67
  367. data/doc/release_notes/3.2.0.txt +0 -268
  368. data/doc/release_notes/3.20.0.txt +0 -41
  369. data/doc/release_notes/3.21.0.txt +0 -87
  370. data/doc/release_notes/3.22.0.txt +0 -39
  371. data/doc/release_notes/3.23.0.txt +0 -172
  372. data/doc/release_notes/3.24.0.txt +0 -420
  373. data/doc/release_notes/3.25.0.txt +0 -88
  374. data/doc/release_notes/3.26.0.txt +0 -88
  375. data/doc/release_notes/3.27.0.txt +0 -82
  376. data/doc/release_notes/3.28.0.txt +0 -304
  377. data/doc/release_notes/3.29.0.txt +0 -459
  378. data/doc/release_notes/3.3.0.txt +0 -192
  379. data/doc/release_notes/3.30.0.txt +0 -135
  380. data/doc/release_notes/3.31.0.txt +0 -146
  381. data/doc/release_notes/3.32.0.txt +0 -202
  382. data/doc/release_notes/3.33.0.txt +0 -157
  383. data/doc/release_notes/3.34.0.txt +0 -671
  384. data/doc/release_notes/3.35.0.txt +0 -144
  385. data/doc/release_notes/3.36.0.txt +0 -245
  386. data/doc/release_notes/3.37.0.txt +0 -338
  387. data/doc/release_notes/3.38.0.txt +0 -234
  388. data/doc/release_notes/3.39.0.txt +0 -237
  389. data/doc/release_notes/3.4.0.txt +0 -325
  390. data/doc/release_notes/3.40.0.txt +0 -73
  391. data/doc/release_notes/3.41.0.txt +0 -155
  392. data/doc/release_notes/3.42.0.txt +0 -74
  393. data/doc/release_notes/3.43.0.txt +0 -105
  394. data/doc/release_notes/3.44.0.txt +0 -152
  395. data/doc/release_notes/3.45.0.txt +0 -179
  396. data/doc/release_notes/3.46.0.txt +0 -122
  397. data/doc/release_notes/3.47.0.txt +0 -270
  398. data/doc/release_notes/3.48.0.txt +0 -477
  399. data/doc/release_notes/3.5.0.txt +0 -510
  400. data/doc/release_notes/3.6.0.txt +0 -366
  401. data/doc/release_notes/3.7.0.txt +0 -179
  402. data/doc/release_notes/3.8.0.txt +0 -151
  403. data/doc/release_notes/3.9.0.txt +0 -233
  404. data/doc/release_notes/4.0.0.txt +0 -262
  405. data/doc/release_notes/4.1.0.txt +0 -85
  406. data/doc/release_notes/4.10.0.txt +0 -226
  407. data/doc/release_notes/4.11.0.txt +0 -147
  408. data/doc/release_notes/4.12.0.txt +0 -105
  409. data/doc/release_notes/4.13.0.txt +0 -169
  410. data/doc/release_notes/4.14.0.txt +0 -68
  411. data/doc/release_notes/4.15.0.txt +0 -56
  412. data/doc/release_notes/4.16.0.txt +0 -36
  413. data/doc/release_notes/4.17.0.txt +0 -38
  414. data/doc/release_notes/4.18.0.txt +0 -36
  415. data/doc/release_notes/4.19.0.txt +0 -45
  416. data/doc/release_notes/4.2.0.txt +0 -129
  417. data/doc/release_notes/4.20.0.txt +0 -79
  418. data/doc/release_notes/4.21.0.txt +0 -94
  419. data/doc/release_notes/4.22.0.txt +0 -72
  420. data/doc/release_notes/4.23.0.txt +0 -65
  421. data/doc/release_notes/4.24.0.txt +0 -99
  422. data/doc/release_notes/4.25.0.txt +0 -181
  423. data/doc/release_notes/4.26.0.txt +0 -44
  424. data/doc/release_notes/4.3.0.txt +0 -40
  425. data/doc/release_notes/4.4.0.txt +0 -92
  426. data/doc/release_notes/4.5.0.txt +0 -34
  427. data/doc/release_notes/4.6.0.txt +0 -30
  428. data/doc/release_notes/4.7.0.txt +0 -103
  429. data/doc/release_notes/4.8.0.txt +0 -175
  430. data/doc/release_notes/4.9.0.txt +0 -190
  431. data/lib/sequel/adapters/cubrid.rb +0 -142
  432. data/lib/sequel/adapters/do.rb +0 -156
  433. data/lib/sequel/adapters/do/mysql.rb +0 -64
  434. data/lib/sequel/adapters/do/postgres.rb +0 -42
  435. data/lib/sequel/adapters/do/sqlite3.rb +0 -40
  436. data/lib/sequel/adapters/jdbc/as400.rb +0 -82
  437. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -62
  438. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -34
  439. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -31
  440. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -31
  441. data/lib/sequel/adapters/odbc/progress.rb +0 -8
  442. data/lib/sequel/adapters/shared/cubrid.rb +0 -243
  443. data/lib/sequel/adapters/shared/firebird.rb +0 -245
  444. data/lib/sequel/adapters/shared/informix.rb +0 -52
  445. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -150
  446. data/lib/sequel/adapters/shared/progress.rb +0 -38
  447. data/lib/sequel/adapters/swift.rb +0 -158
  448. data/lib/sequel/adapters/swift/mysql.rb +0 -47
  449. data/lib/sequel/adapters/swift/postgres.rb +0 -45
  450. data/lib/sequel/adapters/swift/sqlite.rb +0 -47
  451. data/lib/sequel/adapters/utils/pg_types.rb +0 -68
  452. data/lib/sequel/dataset/mutation.rb +0 -109
  453. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -3
  454. data/lib/sequel/extensions/filter_having.rb +0 -59
  455. data/lib/sequel/extensions/hash_aliases.rb +0 -45
  456. data/lib/sequel/extensions/meta_def.rb +0 -31
  457. data/lib/sequel/extensions/query_literals.rb +0 -80
  458. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -22
  459. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -118
  460. data/lib/sequel/extensions/set_overrides.rb +0 -72
  461. data/lib/sequel/no_core_ext.rb +0 -1
  462. data/lib/sequel/plugins/association_autoreloading.rb +0 -7
  463. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -7
  464. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -78
  465. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -117
  466. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -59
  467. data/lib/sequel/plugins/schema.rb +0 -80
  468. data/lib/sequel/plugins/scissors.rb +0 -33
  469. data/spec/adapters/db2_spec.rb +0 -160
  470. data/spec/adapters/firebird_spec.rb +0 -411
  471. data/spec/adapters/informix_spec.rb +0 -100
  472. data/spec/adapters/mssql_spec.rb +0 -706
  473. data/spec/adapters/mysql_spec.rb +0 -1287
  474. data/spec/adapters/oracle_spec.rb +0 -313
  475. data/spec/adapters/postgres_spec.rb +0 -3725
  476. data/spec/adapters/spec_helper.rb +0 -43
  477. data/spec/adapters/sqlanywhere_spec.rb +0 -170
  478. data/spec/adapters/sqlite_spec.rb +0 -653
  479. data/spec/bin_spec.rb +0 -254
  480. data/spec/core/connection_pool_spec.rb +0 -1016
  481. data/spec/core/database_spec.rb +0 -2531
  482. data/spec/core/dataset_spec.rb +0 -5098
  483. data/spec/core/deprecated_spec.rb +0 -70
  484. data/spec/core/expression_filters_spec.rb +0 -1243
  485. data/spec/core/mock_adapter_spec.rb +0 -462
  486. data/spec/core/object_graph_spec.rb +0 -303
  487. data/spec/core/placeholder_literalizer_spec.rb +0 -163
  488. data/spec/core/schema_generator_spec.rb +0 -179
  489. data/spec/core/schema_spec.rb +0 -1659
  490. data/spec/core/spec_helper.rb +0 -34
  491. data/spec/core/version_spec.rb +0 -7
  492. data/spec/core_extensions_spec.rb +0 -699
  493. data/spec/extensions/accessed_columns_spec.rb +0 -51
  494. data/spec/extensions/active_model_spec.rb +0 -123
  495. data/spec/extensions/after_initialize_spec.rb +0 -24
  496. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  497. data/spec/extensions/association_dependencies_spec.rb +0 -117
  498. data/spec/extensions/association_pks_spec.rb +0 -365
  499. data/spec/extensions/association_proxies_spec.rb +0 -86
  500. data/spec/extensions/auto_validations_spec.rb +0 -192
  501. data/spec/extensions/blacklist_security_spec.rb +0 -88
  502. data/spec/extensions/blank_spec.rb +0 -69
  503. data/spec/extensions/boolean_readers_spec.rb +0 -93
  504. data/spec/extensions/caching_spec.rb +0 -270
  505. data/spec/extensions/class_table_inheritance_spec.rb +0 -420
  506. data/spec/extensions/column_conflicts_spec.rb +0 -60
  507. data/spec/extensions/column_select_spec.rb +0 -108
  508. data/spec/extensions/columns_introspection_spec.rb +0 -91
  509. data/spec/extensions/composition_spec.rb +0 -242
  510. data/spec/extensions/connection_validator_spec.rb +0 -120
  511. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -274
  512. data/spec/extensions/constraint_validations_spec.rb +0 -325
  513. data/spec/extensions/core_refinements_spec.rb +0 -519
  514. data/spec/extensions/csv_serializer_spec.rb +0 -173
  515. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  516. data/spec/extensions/dataset_associations_spec.rb +0 -311
  517. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  518. data/spec/extensions/date_arithmetic_spec.rb +0 -150
  519. data/spec/extensions/defaults_setter_spec.rb +0 -101
  520. data/spec/extensions/delay_add_association_spec.rb +0 -52
  521. data/spec/extensions/dirty_spec.rb +0 -180
  522. data/spec/extensions/eager_each_spec.rb +0 -42
  523. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  524. data/spec/extensions/error_splitter_spec.rb +0 -18
  525. data/spec/extensions/error_sql_spec.rb +0 -20
  526. data/spec/extensions/eval_inspect_spec.rb +0 -73
  527. data/spec/extensions/filter_having_spec.rb +0 -40
  528. data/spec/extensions/force_encoding_spec.rb +0 -114
  529. data/spec/extensions/from_block_spec.rb +0 -21
  530. data/spec/extensions/graph_each_spec.rb +0 -109
  531. data/spec/extensions/hash_aliases_spec.rb +0 -24
  532. data/spec/extensions/hook_class_methods_spec.rb +0 -429
  533. data/spec/extensions/inflector_spec.rb +0 -183
  534. data/spec/extensions/input_transformer_spec.rb +0 -54
  535. data/spec/extensions/insert_returning_select_spec.rb +0 -46
  536. data/spec/extensions/instance_filters_spec.rb +0 -79
  537. data/spec/extensions/instance_hooks_spec.rb +0 -276
  538. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  539. data/spec/extensions/json_serializer_spec.rb +0 -291
  540. data/spec/extensions/lazy_attributes_spec.rb +0 -170
  541. data/spec/extensions/list_spec.rb +0 -267
  542. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  543. data/spec/extensions/many_through_many_spec.rb +0 -2172
  544. data/spec/extensions/meta_def_spec.rb +0 -21
  545. data/spec/extensions/migration_spec.rb +0 -712
  546. data/spec/extensions/modification_detection_spec.rb +0 -80
  547. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
  548. data/spec/extensions/named_timezones_spec.rb +0 -108
  549. data/spec/extensions/nested_attributes_spec.rb +0 -697
  550. data/spec/extensions/null_dataset_spec.rb +0 -85
  551. data/spec/extensions/optimistic_locking_spec.rb +0 -128
  552. data/spec/extensions/pagination_spec.rb +0 -118
  553. data/spec/extensions/pg_array_associations_spec.rb +0 -736
  554. data/spec/extensions/pg_array_ops_spec.rb +0 -143
  555. data/spec/extensions/pg_array_spec.rb +0 -395
  556. data/spec/extensions/pg_enum_spec.rb +0 -92
  557. data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
  558. data/spec/extensions/pg_hstore_spec.rb +0 -206
  559. data/spec/extensions/pg_inet_ops_spec.rb +0 -101
  560. data/spec/extensions/pg_inet_spec.rb +0 -52
  561. data/spec/extensions/pg_interval_spec.rb +0 -76
  562. data/spec/extensions/pg_json_ops_spec.rb +0 -229
  563. data/spec/extensions/pg_json_spec.rb +0 -218
  564. data/spec/extensions/pg_loose_count_spec.rb +0 -17
  565. data/spec/extensions/pg_range_ops_spec.rb +0 -58
  566. data/spec/extensions/pg_range_spec.rb +0 -404
  567. data/spec/extensions/pg_row_ops_spec.rb +0 -60
  568. data/spec/extensions/pg_row_plugin_spec.rb +0 -62
  569. data/spec/extensions/pg_row_spec.rb +0 -360
  570. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
  571. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
  572. data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
  573. data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
  574. data/spec/extensions/prepared_statements_spec.rb +0 -103
  575. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
  576. data/spec/extensions/pretty_table_spec.rb +0 -92
  577. data/spec/extensions/query_literals_spec.rb +0 -183
  578. data/spec/extensions/query_spec.rb +0 -102
  579. data/spec/extensions/rcte_tree_spec.rb +0 -392
  580. data/spec/extensions/round_timestamps_spec.rb +0 -43
  581. data/spec/extensions/schema_caching_spec.rb +0 -41
  582. data/spec/extensions/schema_dumper_spec.rb +0 -789
  583. data/spec/extensions/schema_spec.rb +0 -117
  584. data/spec/extensions/scissors_spec.rb +0 -26
  585. data/spec/extensions/select_remove_spec.rb +0 -38
  586. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
  587. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  588. data/spec/extensions/serialization_spec.rb +0 -362
  589. data/spec/extensions/server_block_spec.rb +0 -90
  590. data/spec/extensions/set_overrides_spec.rb +0 -61
  591. data/spec/extensions/sharding_spec.rb +0 -198
  592. data/spec/extensions/shared_caching_spec.rb +0 -175
  593. data/spec/extensions/single_table_inheritance_spec.rb +0 -297
  594. data/spec/extensions/singular_table_names_spec.rb +0 -22
  595. data/spec/extensions/skip_create_refresh_spec.rb +0 -17
  596. data/spec/extensions/spec_helper.rb +0 -71
  597. data/spec/extensions/split_array_nil_spec.rb +0 -24
  598. data/spec/extensions/split_values_spec.rb +0 -22
  599. data/spec/extensions/sql_expr_spec.rb +0 -60
  600. data/spec/extensions/static_cache_spec.rb +0 -361
  601. data/spec/extensions/string_date_time_spec.rb +0 -95
  602. data/spec/extensions/string_stripper_spec.rb +0 -68
  603. data/spec/extensions/subclasses_spec.rb +0 -66
  604. data/spec/extensions/table_select_spec.rb +0 -71
  605. data/spec/extensions/tactical_eager_loading_spec.rb +0 -82
  606. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  607. data/spec/extensions/timestamps_spec.rb +0 -175
  608. data/spec/extensions/to_dot_spec.rb +0 -154
  609. data/spec/extensions/touch_spec.rb +0 -203
  610. data/spec/extensions/tree_spec.rb +0 -274
  611. data/spec/extensions/typecast_on_load_spec.rb +0 -80
  612. data/spec/extensions/unlimited_update_spec.rb +0 -20
  613. data/spec/extensions/update_or_create_spec.rb +0 -87
  614. data/spec/extensions/update_primary_key_spec.rb +0 -100
  615. data/spec/extensions/update_refresh_spec.rb +0 -53
  616. data/spec/extensions/validate_associated_spec.rb +0 -52
  617. data/spec/extensions/validation_class_methods_spec.rb +0 -1027
  618. data/spec/extensions/validation_helpers_spec.rb +0 -541
  619. data/spec/extensions/xml_serializer_spec.rb +0 -207
  620. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  621. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  622. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  623. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  624. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  625. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  626. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  627. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  628. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  629. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  630. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  631. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  632. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  633. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  634. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  635. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  636. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  637. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  638. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  639. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  640. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  641. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  642. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  643. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  644. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  645. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  646. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  647. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  648. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  649. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  650. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  651. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  652. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  653. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  654. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  655. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  656. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  657. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  658. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  659. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  660. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  661. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  662. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  663. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  664. data/spec/guards_helper.rb +0 -55
  665. data/spec/integration/associations_test.rb +0 -2454
  666. data/spec/integration/database_test.rb +0 -113
  667. data/spec/integration/dataset_test.rb +0 -1808
  668. data/spec/integration/eager_loader_test.rb +0 -687
  669. data/spec/integration/migrator_test.rb +0 -240
  670. data/spec/integration/model_test.rb +0 -226
  671. data/spec/integration/plugin_test.rb +0 -2240
  672. data/spec/integration/prepared_statement_test.rb +0 -467
  673. data/spec/integration/schema_test.rb +0 -817
  674. data/spec/integration/spec_helper.rb +0 -48
  675. data/spec/integration/timezone_test.rb +0 -86
  676. data/spec/integration/transaction_test.rb +0 -374
  677. data/spec/integration/type_test.rb +0 -133
  678. data/spec/model/association_reflection_spec.rb +0 -525
  679. data/spec/model/associations_spec.rb +0 -4426
  680. data/spec/model/base_spec.rb +0 -759
  681. data/spec/model/class_dataset_methods_spec.rb +0 -146
  682. data/spec/model/dataset_methods_spec.rb +0 -149
  683. data/spec/model/eager_loading_spec.rb +0 -2137
  684. data/spec/model/hooks_spec.rb +0 -604
  685. data/spec/model/inflector_spec.rb +0 -26
  686. data/spec/model/model_spec.rb +0 -982
  687. data/spec/model/plugins_spec.rb +0 -299
  688. data/spec/model/record_spec.rb +0 -2147
  689. data/spec/model/spec_helper.rb +0 -46
  690. data/spec/model/validations_spec.rb +0 -193
  691. data/spec/sequel_coverage.rb +0 -15
  692. data/spec/spec_config.rb +0 -10
@@ -1,4426 +0,0 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
-
3
- describe Sequel::Model, "associate" do
4
- it "should use explicit class if given a class, symbol, or string" do
5
- begin
6
- klass = Class.new(Sequel::Model(:nodes))
7
- class ::ParParent < Sequel::Model; end
8
-
9
- klass.associate :many_to_one, :par_parent0, :class=>ParParent
10
- klass.associate :one_to_many, :par_parent1s, :class=>'ParParent'
11
- klass.associate :many_to_many, :par_parent2s, :class=>:ParParent
12
-
13
- klass.association_reflection(:"par_parent0").associated_class.must_equal ParParent
14
- klass.association_reflection(:"par_parent1s").associated_class.must_equal ParParent
15
- klass.association_reflection(:"par_parent2s").associated_class.must_equal ParParent
16
- ensure
17
- Object.send(:remove_const, :ParParent)
18
- end
19
- end
20
-
21
- it "should default to associating to other models in the same scope" do
22
- begin
23
- class ::AssociationModuleTest
24
- class Album < Sequel::Model
25
- many_to_one :artist
26
- many_to_many :tags
27
- end
28
- class Artist< Sequel::Model
29
- one_to_many :albums
30
- end
31
- class Tag < Sequel::Model
32
- many_to_many :albums
33
- end
34
- end
35
-
36
- ::AssociationModuleTest::Album.association_reflection(:artist).associated_class.must_equal ::AssociationModuleTest::Artist
37
- ::AssociationModuleTest::Album.association_reflection(:tags).associated_class.must_equal ::AssociationModuleTest::Tag
38
- ::AssociationModuleTest::Artist.association_reflection(:albums).associated_class.must_equal ::AssociationModuleTest::Album
39
- ::AssociationModuleTest::Tag.association_reflection(:albums).associated_class.must_equal ::AssociationModuleTest::Album
40
- ensure
41
- Object.send(:remove_const, :AssociationModuleTest)
42
- end
43
- end
44
-
45
- it "should add a model_object and association_reflection accessors to the dataset, and return it with the current model object" do
46
- klass = Class.new(Sequel::Model(:nodes)) do
47
- columns :id, :a_id
48
- end
49
- mod = Module.new do
50
- def blah
51
- filter{|o| o.__send__(association_reflection[:key]) > model_object.id*2}
52
- end
53
- end
54
-
55
- klass.associate :many_to_one, :a, :class=>klass
56
- klass.associate :one_to_many, :bs, :key=>:b_id, :class=>klass, :extend=>mod
57
- klass.associate :many_to_many, :cs, :class=>klass
58
-
59
- node = klass.load(:id=>1)
60
- node.a_dataset.model_object.must_equal node
61
- node.bs_dataset.model_object.must_equal node
62
- node.cs_dataset.model_object.must_equal node
63
-
64
- node.a_dataset.association_reflection.must_equal klass.association_reflection(:a)
65
- node.bs_dataset.association_reflection.must_equal klass.association_reflection(:bs)
66
- node.cs_dataset.association_reflection.must_equal klass.association_reflection(:cs)
67
-
68
- node.bs_dataset.blah.sql.must_equal 'SELECT * FROM nodes WHERE ((nodes.b_id = 1) AND (b_id > 2))'
69
- end
70
-
71
- it "should allow extending the dataset with :extend option" do
72
- klass = Class.new(Sequel::Model(:nodes)) do
73
- columns :id, :a_id
74
- end
75
- mod = Module.new do
76
- def blah
77
- 1
78
- end
79
- end
80
- mod2 = Module.new do
81
- def blar
82
- 2
83
- end
84
- end
85
-
86
- klass.associate :many_to_one, :a, :class=>klass, :extend=>mod
87
- klass.associate :one_to_many, :bs, :class=>klass, :extend=>[mod]
88
- klass.associate :many_to_many, :cs, :class=>klass, :extend=>[mod, mod2]
89
-
90
- node = klass.load(:id=>1)
91
- node.a_dataset.blah.must_equal 1
92
- node.bs_dataset.blah.must_equal 1
93
- node.cs_dataset.blah.must_equal 1
94
- node.cs_dataset.blar.must_equal 2
95
- end
96
-
97
- it "should clone an existing association with the :clone option" do
98
- begin
99
- class ::ParParent < Sequel::Model; end
100
- klass = Class.new(Sequel::Model(:nodes))
101
-
102
- klass.many_to_one(:par_parent, :order=>:a){1}
103
- klass.one_to_many(:par_parent1s, :class=>'ParParent', :limit=>12){4}
104
- klass.many_to_many(:par_parent2s, :class=>:ParParent, :uniq=>true){2}
105
-
106
- klass.many_to_one :par, :clone=>:par_parent, :select=>:b
107
- klass.one_to_many :par1s, :clone=>:par_parent1s, :order=>:b, :limit=>10, :block=>nil
108
- klass.many_to_many(:par2s, :clone=>:par_parent2s, :order=>:c){3}
109
- klass.many_to_one :par3, :clone=>:par
110
-
111
- klass.association_reflection(:par).associated_class.must_equal ParParent
112
- klass.association_reflection(:par1s).associated_class.must_equal ParParent
113
- klass.association_reflection(:par2s).associated_class.must_equal ParParent
114
-
115
- klass.association_reflection(:par)[:order].must_equal :a
116
- klass.association_reflection(:par).select.must_equal :b
117
- klass.association_reflection(:par)[:block].call.must_equal 1
118
- klass.association_reflection(:par)[:eager_block].call.must_equal 1
119
- klass.association_reflection(:par1s)[:limit].must_equal 10
120
- klass.association_reflection(:par1s)[:order].must_equal :b
121
- klass.association_reflection(:par1s)[:block].must_equal nil
122
- klass.association_reflection(:par2s)[:after_load].length.must_equal 1
123
- klass.association_reflection(:par2s)[:order].must_equal :c
124
- klass.association_reflection(:par2s)[:block].call.must_equal 3
125
-
126
- klass.association_reflection(:par3)[:block].call.must_equal 1
127
- klass.association_reflection(:par3)[:eager_block].call.must_equal 1
128
- ensure
129
- Object.send(:remove_const, :ParParent)
130
- end
131
- end
132
-
133
- it "should raise an error if attempting to clone an association of differing type" do
134
- c = Class.new(Sequel::Model(:c))
135
- c.many_to_one :c
136
- proc{c.one_to_many :cs, :clone=>:c}.must_raise(Sequel::Error)
137
- end
138
-
139
- it "should allow overriding the :instance_specific option" do
140
- c = Class.new(Sequel::Model(:c))
141
- c.many_to_one :c, :instance_specific=>true
142
- c.association_reflection(:c)[:instance_specific].must_equal true
143
- c.many_to_one :c, :instance_specific=>false do |ds| ds end
144
- c.association_reflection(:c)[:instance_specific].must_equal false
145
- end
146
-
147
- it "should allow cloning of one_to_many to one_to_one associations and vice-versa" do
148
- c = Class.new(Sequel::Model(:c))
149
- c.one_to_one :c
150
- c.one_to_many :cs, :clone=>:c
151
- c.one_to_one :c2, :clone=>:cs
152
- end
153
-
154
- it "should allow cloning of many_to_many to one_through_one associations and vice-versa" do
155
- c = Class.new(Sequel::Model(:c))
156
- c.many_to_many :c
157
- c.one_through_one :cs, :clone=>:c
158
- c.many_to_many :c2, :clone=>:cs
159
- end
160
-
161
- it "should clear associations cache when refreshing object manually" do
162
- c = Class.new(Sequel::Model(:c))
163
- c.many_to_one :c
164
- o = c.new
165
- o.associations[:c] = 1
166
- o.refresh
167
- o.associations.must_equal({})
168
- end
169
-
170
- it "should not clear associations cache when refreshing object after save" do
171
- c = Class.new(Sequel::Model(:c))
172
- c.many_to_one :c
173
- o = c.new
174
- o.associations[:c] = 1
175
- o.save
176
- o.associations.must_equal(:c=>1)
177
- end
178
-
179
- it "should not clear associations cache when saving with insert_select" do
180
- ds = Sequel::Model.db[:c]
181
- def ds.supports_insert_select?() true end
182
- def ds.insert_select(*) {:id=>1} end
183
- c = Class.new(Sequel::Model(ds))
184
- c.many_to_one :c
185
- o = c.new
186
- o.associations[:c] = 1
187
- o.save
188
- o.associations.must_equal(:c=>1)
189
- end
190
-
191
- end
192
-
193
- describe Sequel::Model, "many_to_one" do
194
- before do
195
- @c2 = Class.new(Sequel::Model(:nodes)) do
196
- unrestrict_primary_key
197
- columns :id, :parent_id, :par_parent_id, :blah
198
- end
199
- @dataset = @c2.dataset
200
- DB.reset
201
- end
202
-
203
- it "should raise an error if associated class does not have a primary key, and :primary_key is not specified" do
204
- @c2.no_primary_key
205
- @c2.many_to_one :parent, :class => @c2
206
- d = @c2.new(:id => 1, :parent_id => 234)
207
- proc{d.parent}.must_raise(Sequel::Error)
208
- DB.sqls.must_equal []
209
- end
210
-
211
- it "should raise an error if associated class does not have a primary key, and :primary_key is not specified, with an association block" do
212
- @c2.no_primary_key
213
- @c2.many_to_one :parent, :class => @c2 do |ds| ds end
214
- d = @c2.new(:id => 1, :parent_id => 234)
215
- proc{d.parent}.must_raise(Sequel::Error)
216
- DB.sqls.must_equal []
217
- end
218
-
219
- it "should use implicit key if omitted" do
220
- @c2.many_to_one :parent, :class => @c2
221
-
222
- d = @c2.new(:id => 1, :parent_id => 234)
223
- p = d.parent
224
- p.class.must_equal @c2
225
- p.values.must_equal(:x => 1, :id => 1)
226
-
227
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE id = 234"]
228
- end
229
-
230
- it "should allow association with the same name as the key if :key_column is given" do
231
- @c2.def_column_alias(:parent_id_id, :parent_id)
232
- @c2.many_to_one :parent_id, :key_column=>:parent_id, :class => @c2
233
- d = @c2.load(:id => 1, :parent_id => 234)
234
- d.parent_id_dataset.sql.must_equal "SELECT * FROM nodes WHERE (nodes.id = 234) LIMIT 1"
235
- d.parent_id.must_equal @c2.load(:x => 1, :id => 1)
236
- d.parent_id_id.must_equal 234
237
- d[:parent_id].must_equal 234
238
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE id = 234"]
239
-
240
- d.parent_id_id = 3
241
- d.parent_id_id.must_equal 3
242
- d[:parent_id].must_equal 3
243
- end
244
-
245
- it "should use implicit class if omitted" do
246
- begin
247
- class ::ParParent < Sequel::Model; end
248
- @c2.many_to_one :par_parent
249
- @c2.new(:id => 1, :par_parent_id => 234).par_parent.class.must_equal ParParent
250
- DB.sqls.must_equal ["SELECT * FROM par_parents WHERE id = 234"]
251
- ensure
252
- Object.send(:remove_const, :ParParent)
253
- end
254
- end
255
-
256
- it "should use class inside module if given as a string" do
257
- begin
258
- module ::Par
259
- class Parent < Sequel::Model; end
260
- end
261
- @c2.many_to_one :par_parent, :class=>"Par::Parent"
262
- @c2.new(:id => 1, :par_parent_id => 234).par_parent.class.must_equal Par::Parent
263
- DB.sqls.must_equal ["SELECT * FROM parents WHERE id = 234"]
264
- ensure
265
- Object.send(:remove_const, :Par)
266
- end
267
- end
268
-
269
- it "should use explicit key if given" do
270
- @c2.many_to_one :parent, :class => @c2, :key => :blah
271
-
272
- d = @c2.new(:id => 1, :blah => 567)
273
- p = d.parent
274
- p.class.must_equal @c2
275
- p.values.must_equal(:x => 1, :id => 1)
276
-
277
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE id = 567"]
278
- end
279
-
280
- it "should respect :qualify => false option" do
281
- @c2.many_to_one :parent, :class => @c2, :key => :blah, :qualify=>false
282
- @c2.new(:id => 1, :blah => 567).parent
283
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE id = 567"]
284
- end
285
-
286
- it "should use :primary_key option if given" do
287
- @c2.many_to_one :parent, :class => @c2, :key => :blah, :primary_key => :pk
288
- @c2.new(:id => 1, :blah => 567).parent
289
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (nodes.pk = 567) LIMIT 1"]
290
- end
291
-
292
- it "should support composite keys" do
293
- @c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>[:parent_id, :id]
294
- @c2.new(:id => 1, :parent_id => 234).parent
295
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE ((nodes.parent_id = 1) AND (nodes.id = 234)) LIMIT 1"]
296
- end
297
-
298
- it "should not issue query if not all keys have values" do
299
- @c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>[:parent_id, :id]
300
- @c2.new(:id => 1, :parent_id => nil).parent.must_equal nil
301
- DB.sqls.must_equal []
302
- end
303
-
304
- it "should raise an Error unless same number of composite keys used" do
305
- proc{@c2.many_to_one :parent, :class => @c2, :primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
306
- proc{@c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>:id}.must_raise(Sequel::Error)
307
- proc{@c2.many_to_one :parent, :class => @c2, :key=>:id, :primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
308
- proc{@c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id, :blah], :primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
309
- end
310
-
311
- it "should use :select option if given" do
312
- @c2.many_to_one :parent, :class => @c2, :key => :blah, :select=>[:id, :name]
313
- @c2.new(:id => 1, :blah => 567).parent
314
- DB.sqls.must_equal ["SELECT id, name FROM nodes WHERE (nodes.id = 567) LIMIT 1"]
315
- end
316
-
317
- it "should use :conditions option if given" do
318
- @c2.many_to_one :parent, :class => @c2, :key => :blah, :conditions=>{:a=>32}
319
- @c2.new(:id => 1, :blah => 567).parent
320
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE ((a = 32) AND (nodes.id = 567)) LIMIT 1"]
321
-
322
- @c2.many_to_one :parent, :class => @c2, :key => :blah, :conditions=>:a
323
- @c2.new(:id => 1, :blah => 567).parent
324
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (a AND (nodes.id = 567)) LIMIT 1"]
325
- end
326
-
327
- it "should support :order, :limit (only for offset), and :dataset options, as well as a block" do
328
- @c2.many_to_one :child_20, :class => @c2, :key=>:id, :dataset=>proc{model.filter(:parent_id=>pk)}, :limit=>[10,20], :order=>:name do |ds|
329
- ds.filter{x > 1}
330
- end
331
- @c2.load(:id => 100).child_20
332
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE ((parent_id = 100) AND (x > 1)) ORDER BY name LIMIT 1 OFFSET 20"]
333
- end
334
-
335
- it "should return nil if key value is nil" do
336
- @c2.many_to_one :parent, :class => @c2
337
- @c2.new(:id => 1).parent.must_equal nil
338
- DB.sqls.must_equal []
339
- end
340
-
341
- it "should cache negative lookup" do
342
- @c2.many_to_one :parent, :class => @c2
343
- @c2.dataset._fetch = []
344
- d = @c2.new(:id => 1, :parent_id=>555)
345
- DB.sqls.must_equal []
346
- d.parent.must_equal nil
347
- DB.sqls.must_equal ['SELECT * FROM nodes WHERE id = 555']
348
- d.parent.must_equal nil
349
- DB.sqls.must_equal []
350
- end
351
-
352
- it "should define a setter method" do
353
- @c2.many_to_one :parent, :class => @c2
354
-
355
- d = @c2.new(:id => 1)
356
- d.parent = @c2.new(:id => 4321)
357
- d.values.must_equal(:id => 1, :parent_id => 4321)
358
-
359
- d.parent = nil
360
- d.values.must_equal(:id => 1, :parent_id => nil)
361
-
362
- e = @c2.new(:id => 6677)
363
- d.parent = e
364
- d.values.must_equal(:id => 1, :parent_id => 6677)
365
- end
366
-
367
- it "should have the setter method respect the :primary_key option" do
368
- @c2.many_to_one :parent, :class => @c2, :primary_key=>:blah
369
-
370
- d = @c2.new(:id => 1)
371
- d.parent = @c2.new(:id => 4321, :blah=>444)
372
- d.values.must_equal(:id => 1, :parent_id => 444)
373
-
374
- d.parent = nil
375
- d.values.must_equal(:id => 1, :parent_id => nil)
376
-
377
- e = @c2.new(:id => 6677, :blah=>8)
378
- d.parent = e
379
- d.values.must_equal(:id => 1, :parent_id => 8)
380
- end
381
-
382
- it "should have the setter method respect composite keys" do
383
- @c2.many_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>[:parent_id, :id]
384
-
385
- d = @c2.new(:id => 1, :parent_id=> 234)
386
- d.parent = @c2.new(:id => 4, :parent_id=>52)
387
- d.values.must_equal(:id => 52, :parent_id => 4)
388
-
389
- d.parent = nil
390
- d.values.must_equal(:id => nil, :parent_id => nil)
391
-
392
- e = @c2.new(:id => 6677, :parent_id=>8)
393
- d.parent = e
394
- d.values.must_equal(:id => 8, :parent_id => 6677)
395
- end
396
-
397
- it "should not persist changes until saved" do
398
- @c2.many_to_one :parent, :class => @c2
399
-
400
- d = @c2.load(:id => 1)
401
- DB.reset
402
- d.parent = @c2.new(:id => 345)
403
- DB.sqls.must_equal []
404
- d.save_changes
405
- DB.sqls.must_equal ['UPDATE nodes SET parent_id = 345 WHERE (id = 1)']
406
- end
407
-
408
- it "should populate cache when accessed" do
409
- @c2.many_to_one :parent, :class => @c2
410
-
411
- d = @c2.load(:id => 1)
412
- d.parent_id = 234
413
- d.associations[:parent].must_equal nil
414
- @c2.dataset._fetch = {:id=>234}
415
- e = d.parent
416
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE id = 234"]
417
- d.associations[:parent].must_equal e
418
- end
419
-
420
- it "should populate cache when assigned" do
421
- @c2.many_to_one :parent, :class => @c2
422
-
423
- d = @c2.create(:id => 1)
424
- DB.reset
425
- d.associations[:parent].must_equal nil
426
- d.parent = @c2.new(:id => 234)
427
- e = d.parent
428
- d.associations[:parent].must_equal e
429
- DB.sqls.must_equal []
430
- end
431
-
432
- it "should use cache if available" do
433
- @c2.many_to_one :parent, :class => @c2
434
-
435
- d = @c2.create(:id => 1, :parent_id => 234)
436
- DB.reset
437
- d.associations[:parent] = 42
438
- d.parent.must_equal 42
439
- DB.sqls.must_equal []
440
- end
441
-
442
- it "should not use cache if asked to reload" do
443
- @c2.many_to_one :parent, :class => @c2
444
-
445
- d = @c2.create(:id => 1)
446
- DB.reset
447
- d.parent_id = 234
448
- d.associations[:parent] = 42
449
- d.parent(true).wont_equal 42
450
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE id = 234"]
451
- end
452
-
453
- it "should use a callback if given one as the argument" do
454
- @c2.many_to_one :parent, :class => @c2
455
-
456
- d = @c2.create(:id => 1)
457
- DB.reset
458
- d.parent_id = 234
459
- d.associations[:parent] = 42
460
- d.parent(proc{|ds| ds.filter{name > 'M'}}).wont_equal 42
461
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE ((nodes.id = 234) AND (name > 'M')) LIMIT 1"]
462
- end
463
-
464
- it "should use a block given to the association method as a callback" do
465
- @c2.many_to_one :parent, :class => @c2
466
-
467
- d = @c2.create(:id => 1)
468
- DB.reset
469
- d.parent_id = 234
470
- d.associations[:parent] = 42
471
- d.parent{|ds| ds.filter{name > 'M'}}.wont_equal 42
472
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE ((nodes.id = 234) AND (name > 'M')) LIMIT 1"]
473
- end
474
-
475
- it "should have the setter add to the reciprocal one_to_many cached association array if it exists" do
476
- @c2.many_to_one :parent, :class => @c2
477
- @c2.one_to_many :children, :class => @c2, :key=>:parent_id
478
- @c2.dataset._fetch = []
479
-
480
- d = @c2.new(:id => 1)
481
- e = @c2.new(:id => 2)
482
- DB.sqls.must_equal []
483
- d.parent = e
484
- e.children.wont_include(d)
485
- DB.sqls.must_equal ['SELECT * FROM nodes WHERE (nodes.parent_id = 2)']
486
-
487
- d = @c2.new(:id => 1)
488
- e = @c2.new(:id => 2)
489
- e.children.wont_include(d)
490
- DB.sqls.must_equal ['SELECT * FROM nodes WHERE (nodes.parent_id = 2)']
491
- d.parent = e
492
- e.children.must_include(d)
493
- DB.sqls.must_equal []
494
- end
495
-
496
- it "should have setter deal with a one_to_one reciprocal" do
497
- @c2.many_to_one :parent, :class => @c2, :key=>:parent_id
498
- @c2.one_to_one :child, :class => @c2, :key=>:parent_id
499
-
500
- d = @c2.new(:id => 1)
501
- e = @c2.new(:id => 2)
502
- e.associations[:child] = nil
503
- d.parent = e
504
- e.child.must_equal d
505
- d.parent = nil
506
- e.child.must_equal nil
507
- d.parent = e
508
- e.child.must_equal d
509
-
510
- f = @c2.new(:id => 3)
511
- d.parent = nil
512
- e.child.must_equal nil
513
- e.associations[:child] = f
514
- d.parent = e
515
- e.child.must_equal d
516
- end
517
-
518
- it "should have the setter remove the object from the previous associated object's reciprocal one_to_many cached association array if it exists" do
519
- @c2.many_to_one :parent, :class => @c2
520
- @c2.one_to_many :children, :class => @c2, :key=>:parent_id
521
- @c2.dataset._fetch = []
522
-
523
- d = @c2.new(:id => 1)
524
- e = @c2.new(:id => 2)
525
- f = @c2.new(:id => 3)
526
- e.children.wont_include(d)
527
- f.children.wont_include(d)
528
- DB.reset
529
- d.parent = e
530
- e.children.must_include(d)
531
- d.parent = f
532
- f.children.must_include(d)
533
- e.children.wont_include(d)
534
- d.parent = nil
535
- f.children.wont_include(d)
536
- DB.sqls.must_equal []
537
- end
538
-
539
- it "should have the setter not modify the reciprocal if set to same value as current" do
540
- @c2.many_to_one :parent, :class => @c2
541
- @c2.one_to_many :children, :class => @c2, :key=>:parent_id
542
-
543
- c1 = @c2.load(:id => 1, :parent_id=>nil)
544
- c2 = @c2.load(:id => 2, :parent_id=>1)
545
- c3 = @c2.load(:id => 3, :parent_id=>1)
546
- c1.associations[:children] = [c2, c3]
547
- c2.associations[:parent] = c1
548
- c2.parent = c1
549
- c1.children.must_equal [c2, c3]
550
- DB.sqls.must_equal []
551
- end
552
-
553
- it "should get all matching records and only return the first if :key option is set to nil" do
554
- @c2.one_to_many :children, :class => @c2, :key=>:parent_id
555
- @c2.many_to_one :first_grand_parent, :class => @c2, :key=>nil, :eager_graph=>:children, :dataset=>proc{model.filter(:children_id=>parent_id)}
556
- @c2.dataset.columns(:id, :parent_id, :par_parent_id, :blah)._fetch = [{:id=>1, :parent_id=>0, :par_parent_id=>3, :blah=>4, :children_id=>2, :children_parent_id=>1, :children_par_parent_id=>5, :children_blah=>6}, {}]
557
- p = @c2.new(:parent_id=>2)
558
- fgp = p.first_grand_parent
559
- DB.sqls.must_equal ["SELECT nodes.id, nodes.parent_id, nodes.par_parent_id, nodes.blah, children.id AS children_id, children.parent_id AS children_parent_id, children.par_parent_id AS children_par_parent_id, children.blah AS children_blah FROM nodes LEFT OUTER JOIN nodes AS children ON (children.parent_id = nodes.id) WHERE (children_id = 2)"]
560
- fgp.values.must_equal(:id=>1, :parent_id=>0, :par_parent_id=>3, :blah=>4)
561
- fgp.children.first.values.must_equal(:id=>2, :parent_id=>1, :par_parent_id=>5, :blah=>6)
562
- end
563
-
564
- it "should not create the setter method if :read_only option is used" do
565
- @c2.many_to_one :parent, :class => @c2, :read_only=>true
566
- @c2.instance_methods.collect{|x| x.to_s}.must_include('parent')
567
- @c2.instance_methods.collect{|x| x.to_s}.wont_include('parent=')
568
- end
569
-
570
- it "should not add associations methods directly to class" do
571
- @c2.many_to_one :parent, :class => @c2
572
- @c2.instance_methods.collect{|x| x.to_s}.must_include('parent')
573
- @c2.instance_methods.collect{|x| x.to_s}.must_include('parent=')
574
- @c2.instance_methods(false).collect{|x| x.to_s}.wont_include('parent')
575
- @c2.instance_methods(false).collect{|x| x.to_s}.wont_include('parent=')
576
- end
577
-
578
- it "should add associations methods to the :methods_module option" do
579
- m = Module.new
580
- @c2.many_to_one :parent, :class => @c2, :methods_module=>m
581
- m.instance_methods.collect{|x| x.to_s}.must_include('parent')
582
- m.instance_methods.collect{|x| x.to_s}.must_include('parent=')
583
- @c2.instance_methods.collect{|x| x.to_s}.wont_include('parent')
584
- @c2.instance_methods.collect{|x| x.to_s}.wont_include('parent=')
585
- end
586
-
587
- it "should add associations methods directly to class if :methods_module is the class itself" do
588
- @c2.many_to_one :parent, :class => @c2, :methods_module=>@c2
589
- @c2.instance_methods(false).collect{|x| x.to_s}.must_include('parent')
590
- @c2.instance_methods(false).collect{|x| x.to_s}.must_include('parent=')
591
- end
592
-
593
- it "should raise an error if trying to set a model object that doesn't have a valid primary key" do
594
- @c2.many_to_one :parent, :class => @c2
595
- p = @c2.new
596
- c = @c2.load(:id=>123)
597
- proc{c.parent = p}.must_raise(Sequel::Error)
598
- end
599
-
600
- it "should make the change to the foreign_key value inside a _association= method" do
601
- @c2.many_to_one :parent, :class => @c2
602
- @c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_parent=")
603
- p = @c2.new
604
- c = @c2.load(:id=>123)
605
- def p._parent=(x)
606
- @x = x
607
- end
608
- def p.parent_id=; raise; end
609
- p.parent = c
610
- p.instance_variable_get(:@x).must_equal c
611
- end
612
-
613
- it "should have the :setter option define the _association= method" do
614
- @c2.many_to_one :parent, :class => @c2, :setter=>proc{|x| @x = x}
615
- p = @c2.new
616
- c = @c2.load(:id=>123)
617
- def p.parent_id=; raise; end
618
- p.parent = c
619
- p.instance_variable_get(:@x).must_equal c
620
- end
621
-
622
- it "should support (before|after)_set callbacks" do
623
- h = []
624
- @c2.many_to_one :parent, :class => @c2, :before_set=>[proc{|x,y| h << x.pk; h << (y ? -y.pk : :y)}, :blah], :after_set=>proc{h << 3}
625
- @c2.class_eval do
626
- self::Foo = h
627
- def []=(a, v)
628
- a == :parent_id ? (model::Foo << (v ? 4 : 5)) : super
629
- end
630
- def blah(x)
631
- model::Foo << (x ? x.pk : :x)
632
- end
633
- def blahr(x)
634
- model::Foo << 6
635
- end
636
- end
637
- p = @c2.load(:id=>10)
638
- c = @c2.load(:id=>123)
639
- h.must_equal []
640
- p.parent = c
641
- h.must_equal [10, -123, 123, 4, 3]
642
- p.parent = nil
643
- h.must_equal [10, -123, 123, 4, 3, 10, :y, :x, 5, 3]
644
- end
645
-
646
- it "should support after_load association callback" do
647
- h = []
648
- @c2.many_to_one :parent, :class => @c2, :after_load=>[proc{|x,y| h << [x.pk, y.pk]}, :al]
649
- @c2.class_eval do
650
- self::Foo = h
651
- def al(v)
652
- model::Foo << v.pk
653
- end
654
- dataset._fetch = {:id=>20}
655
- end
656
- p = @c2.load(:id=>10, :parent_id=>20)
657
- parent = p.parent
658
- h.must_equal [[10, 20], 20]
659
- parent.pk.must_equal 20
660
- end
661
-
662
- it "should support after_load association callback that changes the cached object" do
663
- @c2.many_to_one :parent, :class => @c2, :after_load=>:al
664
- @c2.class_eval do
665
- def al(v)
666
- associations[:parent] = :foo
667
- end
668
- end
669
- p = @c2.load(:id=>10, :parent_id=>20)
670
- p.parent.must_equal :foo
671
- p.associations[:parent].must_equal :foo
672
- end
673
-
674
- it "should raise error and not call internal add or remove method if before callback returns false, even if raise_on_save_failure is false" do
675
- p = @c2.new
676
- c = @c2.load(:id=>123)
677
- p.raise_on_save_failure = false
678
- @c2.many_to_one :parent, :class => @c2, :before_set=>:bs
679
- def p.bs(x) false end
680
- def p._parent=; raise; end
681
- proc{p.parent = c}.must_raise(Sequel::HookFailed)
682
-
683
- p.parent.must_equal nil
684
- p.associations[:parent] = c
685
- p.parent.must_equal c
686
- proc{p.parent = nil}.must_raise(Sequel::HookFailed)
687
- end
688
-
689
- it "should raise error and not call internal add or remove method if before callback calls cancel_action, even if raise_on_save_failure is false" do
690
- p = @c2.new
691
- c = @c2.load(:id=>123)
692
- p.raise_on_save_failure = false
693
- @c2.many_to_one :parent, :class => @c2, :before_set=>:bs
694
- def p.bs(x) cancel_action end
695
- def p._parent=; raise; end
696
- proc{p.parent = c}.must_raise(Sequel::HookFailed)
697
-
698
- p.parent.must_equal nil
699
- p.associations[:parent] = c
700
- p.parent.must_equal c
701
- proc{p.parent = nil}.must_raise(Sequel::HookFailed)
702
- end
703
-
704
- it "should raise an error if a callback is not a proc or symbol" do
705
- @c2.many_to_one :parent, :class => @c2, :before_set=>Object.new
706
- proc{@c2.new.parent = @c2.load(:id=>1)}.must_raise(Sequel::Error)
707
- end
708
- end
709
-
710
- describe Sequel::Model, "one_to_one" do
711
- before do
712
- @c1 = Class.new(Sequel::Model(:attributes)) do
713
- unrestrict_primary_key
714
- columns :id, :node_id, :y
715
- end
716
-
717
- @c2 = Class.new(Sequel::Model(:nodes)) do
718
- unrestrict_primary_key
719
- attr_accessor :xxx
720
-
721
- def self.name; 'Node'; end
722
- def self.to_s; 'Node'; end
723
- columns :id, :x, :parent_id, :par_parent_id, :blah, :node_id
724
- end
725
- @dataset = @c2.dataset
726
- @dataset._fetch = {}
727
- @c1.dataset._fetch = {}
728
- DB.reset
729
- end
730
-
731
- it "should have the getter method return a single object if the :one_to_one option is true" do
732
- @c2.one_to_one :attribute, :class => @c1
733
- att = @c2.new(:id => 1234).attribute
734
- DB.sqls.must_equal ['SELECT * FROM attributes WHERE (attributes.node_id = 1234) LIMIT 1']
735
- att.must_be_kind_of(@c1)
736
- att.values.must_equal({})
737
- end
738
-
739
- it "should not add a setter method if the :read_only option is true" do
740
- @c2.one_to_one :attribute, :class => @c1, :read_only=>true
741
- im = @c2.instance_methods.collect{|x| x.to_s}
742
- im.must_include('attribute')
743
- im.wont_include('attribute=')
744
- end
745
-
746
- it "should add a setter method" do
747
- @c2.one_to_one :attribute, :class => @c1
748
- attrib = @c1.new(:id=>3)
749
- @c1.dataset._fetch = @c1.instance_dataset._fetch = {:id=>3}
750
- @c2.new(:id => 1234).attribute = attrib
751
- sqls = DB.sqls
752
- ['INSERT INTO attributes (node_id, id) VALUES (1234, 3)',
753
- 'INSERT INTO attributes (id, node_id) VALUES (3, 1234)'].must_include(sqls.slice! 1)
754
- sqls.must_equal ['UPDATE attributes SET node_id = NULL WHERE (node_id = 1234)', "SELECT * FROM attributes WHERE (id = 3) LIMIT 1"]
755
-
756
- @c2.new(:id => 1234).attribute.must_equal attrib
757
- attrib = @c1.load(:id=>3)
758
- @c2.new(:id => 1234).attribute = attrib
759
- DB.sqls.must_equal ["SELECT * FROM attributes WHERE (attributes.node_id = 1234) LIMIT 1",
760
- 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))',
761
- "UPDATE attributes SET node_id = 1234 WHERE (id = 3)"]
762
- end
763
-
764
- it "should use a transaction in the setter method" do
765
- @c2.one_to_one :attribute, :class => @c1
766
- @c2.use_transactions = true
767
- attrib = @c1.load(:id=>3)
768
- @c2.new(:id => 1234).attribute = attrib
769
- DB.sqls.must_equal ['BEGIN',
770
- 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))',
771
- "UPDATE attributes SET node_id = 1234 WHERE (id = 3)",
772
- 'COMMIT']
773
- end
774
-
775
- it "should have setter method respect association filters" do
776
- @c2.one_to_one :attribute, :class => @c1, :conditions=>{:a=>1} do |ds|
777
- ds.filter(:b=>2)
778
- end
779
- attrib = @c1.load(:id=>3)
780
- @c2.new(:id => 1234).attribute = attrib
781
- DB.sqls.must_equal ['UPDATE attributes SET node_id = NULL WHERE ((a = 1) AND (node_id = 1234) AND (b = 2) AND (id != 3))',
782
- "UPDATE attributes SET node_id = 1234 WHERE (id = 3)"]
783
- end
784
-
785
- it "should have the setter method respect the :primary_key option" do
786
- @c2.one_to_one :attribute, :class => @c1, :primary_key=>:xxx
787
- attrib = @c1.new(:id=>3)
788
- @c1.dataset._fetch = @c1.instance_dataset._fetch = {:id=>3}
789
- @c2.new(:id => 1234, :xxx=>5).attribute = attrib
790
- sqls = DB.sqls
791
- ['INSERT INTO attributes (node_id, id) VALUES (5, 3)',
792
- 'INSERT INTO attributes (id, node_id) VALUES (3, 5)'].must_include(sqls.slice! 1)
793
- sqls.must_equal ['UPDATE attributes SET node_id = NULL WHERE (node_id = 5)', "SELECT * FROM attributes WHERE (id = 3) LIMIT 1"]
794
-
795
- @c2.new(:id => 321, :xxx=>5).attribute.must_equal attrib
796
- attrib = @c1.load(:id=>3)
797
- @c2.new(:id => 621, :xxx=>5).attribute = attrib
798
- DB.sqls.must_equal ["SELECT * FROM attributes WHERE (attributes.node_id = 5) LIMIT 1",
799
- 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))',
800
- 'UPDATE attributes SET node_id = 5 WHERE (id = 3)']
801
- end
802
-
803
- it "should have the setter method respect composite keys" do
804
- @c2.one_to_one :attribute, :class => @c1, :key=>[:node_id, :y], :primary_key=>[:id, :x]
805
- attrib = @c1.load(:id=>3, :y=>6)
806
- @c1.dataset._fetch = {:id=>3, :y=>6}
807
- @c2.load(:id => 1234, :x=>5).attribute = attrib
808
- sqls = DB.sqls
809
- sqls.last.must_match(/UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 3\)/)
810
- sqls.first.must_match(/UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(node_id = 1234\) AND \(y = 5\) AND \(id != 3\)\)/)
811
- sqls.length.must_equal 2
812
- end
813
-
814
- it "should use implicit key if omitted" do
815
- @c2.one_to_one :parent, :class => @c2
816
-
817
- d = @c2.new(:id => 234)
818
- p = d.parent
819
- p.class.must_equal @c2
820
- p.values.must_equal({})
821
-
822
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (nodes.node_id = 234) LIMIT 1"]
823
- end
824
-
825
- it "should use implicit class if omitted" do
826
- begin
827
- class ::ParParent < Sequel::Model; end
828
- @c2.one_to_one :par_parent
829
- @c2.new(:id => 234).par_parent.class.must_equal ParParent
830
- DB.sqls.must_equal ["SELECT * FROM par_parents WHERE (par_parents.node_id = 234) LIMIT 1"]
831
- ensure
832
- Object.send(:remove_const, :ParParent)
833
- end
834
- end
835
-
836
- it "should use class inside module if given as a string" do
837
- begin
838
- module ::Par
839
- class Parent < Sequel::Model; end
840
- end
841
- @c2.one_to_one :par_parent, :class=>"Par::Parent"
842
- @c2.new(:id => 234).par_parent.class.must_equal Par::Parent
843
- DB.sqls.must_equal ["SELECT * FROM parents WHERE (parents.node_id = 234) LIMIT 1"]
844
- ensure
845
- Object.send(:remove_const, :Par)
846
- end
847
- end
848
-
849
- it "should use explicit key if given" do
850
- @c2.one_to_one :parent, :class => @c2, :key => :blah
851
-
852
- d = @c2.new(:id => 234)
853
- p = d.parent
854
- p.class.must_equal @c2
855
- p.values.must_equal({})
856
-
857
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (nodes.blah = 234) LIMIT 1"]
858
- end
859
-
860
- it "should use :primary_key option if given" do
861
- @c2.one_to_one :parent, :class => @c2, :key => :pk, :primary_key => :blah
862
- @c2.new(:id => 1, :blah => 567).parent
863
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (nodes.pk = 567) LIMIT 1"]
864
- end
865
-
866
- it "should support composite keys" do
867
- @c2.one_to_one :parent, :class => @c2, :primary_key=>[:id, :parent_id], :key=>[:parent_id, :id]
868
- @c2.new(:id => 1, :parent_id => 234).parent
869
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE ((nodes.parent_id = 1) AND (nodes.id = 234)) LIMIT 1"]
870
- end
871
-
872
- it "should not issue query if not all keys have values" do
873
- @c2.one_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>[:parent_id, :id]
874
- @c2.new(:id => 1, :parent_id => nil).parent.must_equal nil
875
- DB.sqls.must_equal []
876
- end
877
-
878
- it "should raise an Error unless same number of composite keys used" do
879
- proc{@c2.one_to_one :parent, :class => @c2, :primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
880
- proc{@c2.one_to_one :parent, :class => @c2, :key=>[:id, :parent_id], :primary_key=>:id}.must_raise(Sequel::Error)
881
- proc{@c2.one_to_one :parent, :class => @c2, :key=>:id, :primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
882
- proc{@c2.one_to_one :parent, :class => @c2, :key=>[:id, :parent_id, :blah], :primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
883
- end
884
-
885
- it "should use :select option if given" do
886
- @c2.one_to_one :parent, :class => @c2, :select=>[:id, :name]
887
- @c2.new(:id => 567).parent
888
- DB.sqls.must_equal ["SELECT id, name FROM nodes WHERE (nodes.node_id = 567) LIMIT 1"]
889
- end
890
-
891
- it "should use :conditions option if given" do
892
- @c2.one_to_one :parent, :class => @c2, :conditions=>{:a=>32}
893
- @c2.new(:id => 567).parent
894
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE ((a = 32) AND (nodes.node_id = 567)) LIMIT 1"]
895
-
896
- @c2.one_to_one :parent, :class => @c2, :conditions=>:a
897
- @c2.new(:id => 567).parent
898
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (a AND (nodes.node_id = 567)) LIMIT 1"]
899
- end
900
-
901
- it "should support :order, :limit (only for offset), and :dataset options, as well as a block" do
902
- @c2.one_to_one :child_20, :class => @c2, :key=>:id, :dataset=>proc{model.filter(:parent_id=>pk)}, :limit=>[10,20], :order=>:name do |ds|
903
- ds.filter{x > 1}
904
- end
905
- @c2.load(:id => 100).child_20
906
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE ((parent_id = 100) AND (x > 1)) ORDER BY name LIMIT 1 OFFSET 20"]
907
- end
908
-
909
- it "should return nil if primary_key value is nil" do
910
- @c2.one_to_one :parent, :class => @c2, :primary_key=>:node_id
911
-
912
- @c2.new(:id => 1).parent.must_equal nil
913
- DB.sqls.must_equal []
914
- end
915
-
916
- it "should cache negative lookup" do
917
- @c2.one_to_one :parent, :class => @c2
918
- @c2.dataset._fetch = []
919
- d = @c2.new(:id => 555)
920
- DB.sqls.must_equal []
921
- d.parent.must_equal nil
922
- DB.sqls.must_equal ['SELECT * FROM nodes WHERE (nodes.node_id = 555) LIMIT 1']
923
- d.parent.must_equal nil
924
- DB.sqls.must_equal []
925
- end
926
-
927
- it "should have the setter method respect the :key option" do
928
- @c2.one_to_one :parent, :class => @c2, :key=>:blah
929
- d = @c2.new(:id => 3)
930
- e = @c2.new(:id => 4321, :blah=>444)
931
- @c2.dataset._fetch = @c2.instance_dataset._fetch = {:id => 4321, :blah => 3}
932
- d.parent = e
933
- e.values.must_equal(:id => 4321, :blah => 3)
934
- sqls = DB.sqls
935
- ["INSERT INTO nodes (blah, id) VALUES (3, 4321)",
936
- "INSERT INTO nodes (id, blah) VALUES (4321, 3)"].must_include(sqls.slice! 1)
937
- sqls.must_equal ["UPDATE nodes SET blah = NULL WHERE (blah = 3)", "SELECT * FROM nodes WHERE (id = 4321) LIMIT 1"]
938
- end
939
-
940
- it "should persist changes to associated object when the setter is called" do
941
- @c2.one_to_one :parent, :class => @c2
942
- d = @c2.load(:id => 1)
943
- d.parent = @c2.load(:id => 3, :node_id=>345)
944
- DB.sqls.must_equal ["UPDATE nodes SET node_id = NULL WHERE ((node_id = 1) AND (id != 3))",
945
- "UPDATE nodes SET node_id = 1 WHERE (id = 3)"]
946
- end
947
-
948
- it "should populate cache when accessed" do
949
- @c2.one_to_one :parent, :class => @c2
950
-
951
- d = @c2.load(:id => 1)
952
- d.associations[:parent].must_equal nil
953
- @c2.dataset._fetch = {:id=>234}
954
- e = d.parent
955
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (nodes.node_id = 1) LIMIT 1"]
956
- d.parent
957
- DB.sqls.must_equal []
958
- d.associations[:parent].must_equal e
959
- end
960
-
961
- it "should populate cache when assigned" do
962
- @c2.one_to_one :parent, :class => @c2
963
-
964
- d = @c2.load(:id => 1)
965
- d.associations[:parent].must_equal nil
966
- e = @c2.load(:id => 234)
967
- d.parent = e
968
- f = d.parent
969
- d.associations[:parent].must_equal e
970
- e.must_equal f
971
- end
972
-
973
- it "should use cache if available" do
974
- @c2.one_to_one :parent, :class => @c2
975
- d = @c2.load(:id => 1, :parent_id => 234)
976
- d.associations[:parent] = 42
977
- d.parent.must_equal 42
978
- DB.sqls.must_equal []
979
- end
980
-
981
- it "should not use cache if asked to reload" do
982
- @c2.one_to_one :parent, :class => @c2
983
- d = @c2.load(:id => 1)
984
- d.associations[:parent] = [42]
985
- d.parent(true).wont_equal 42
986
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (nodes.node_id = 1) LIMIT 1"]
987
- end
988
-
989
- it "should have the setter set the reciprocal many_to_one cached association" do
990
- @c2.one_to_one :parent, :class => @c2, :key=>:parent_id
991
- @c2.many_to_one :child, :class => @c2, :key=>:parent_id
992
-
993
- d = @c2.load(:id => 1)
994
- e = @c2.load(:id => 2)
995
- d.parent = e
996
- e.child.must_equal d
997
- DB.sqls.must_equal ["UPDATE nodes SET parent_id = NULL WHERE ((parent_id = 1) AND (id != 2))",
998
- "UPDATE nodes SET parent_id = 1 WHERE (id = 2)"]
999
- d.parent = nil
1000
- e.child.must_equal nil
1001
- DB.sqls.must_equal ["UPDATE nodes SET parent_id = NULL WHERE (parent_id = 1)"]
1002
- end
1003
-
1004
- it "should have the setter remove the object from the previous associated object's reciprocal many_to_one cached association array if it exists" do
1005
- @c2.one_to_one :parent, :class => @c2, :key=>:parent_id
1006
- @c2.many_to_one :child, :class => @c2, :key=>:parent_id
1007
- @c2.dataset._fetch = []
1008
-
1009
- d = @c2.load(:id => 1)
1010
- e = @c2.load(:id => 2)
1011
- f = @c2.load(:id => 3)
1012
- e.child.must_equal nil
1013
- f.child.must_equal nil
1014
- d.parent = e
1015
- e.child.must_equal d
1016
- d.parent = f
1017
- f.child.must_equal d
1018
- e.child.must_equal nil
1019
- d.parent = nil
1020
- f.child.must_equal nil
1021
- end
1022
-
1023
- it "should have the setter not modify the reciprocal if set to same value as current" do
1024
- @c2.one_to_one :parent, :class => @c2, :key=>:parent_id
1025
- @c2.many_to_one :child, :class => @c2, :key=>:parent_id
1026
-
1027
- c1 = @c2.load(:id => 1, :parent_id=>nil)
1028
- c2 = @c2.load(:id => 2, :parent_id=>1)
1029
- c1.associations[:child] = c2
1030
- c2.associations[:parent] = c1
1031
- c2.parent = c1
1032
- c1.child.must_equal c2
1033
- DB.sqls.must_equal []
1034
- end
1035
-
1036
- it "should not add associations methods directly to class" do
1037
- @c2.one_to_one :parent, :class => @c2
1038
- @c2.instance_methods.collect{|x| x.to_s}.must_include('parent')
1039
- @c2.instance_methods.collect{|x| x.to_s}.must_include('parent=')
1040
- @c2.instance_methods(false).collect{|x| x.to_s}.wont_include('parent')
1041
- @c2.instance_methods(false).collect{|x| x.to_s}.wont_include('parent=')
1042
- end
1043
-
1044
- it "should raise an error if the current model object that doesn't have a valid primary key" do
1045
- @c2.one_to_one :parent, :class => @c2
1046
- p = @c2.new
1047
- c = @c2.load(:id=>123)
1048
- proc{p.parent = c}.must_raise(Sequel::Error)
1049
- end
1050
-
1051
- it "should make the change to the foreign_key value inside a _association= method" do
1052
- @c2.one_to_one :parent, :class => @c2
1053
- @c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_parent=")
1054
- c = @c2.new
1055
- p = @c2.load(:id=>123)
1056
- def p._parent=(x)
1057
- @x = x
1058
- end
1059
- def p.parent_id=; raise; end
1060
- p.parent = c
1061
- p.instance_variable_get(:@x).must_equal c
1062
- end
1063
-
1064
- it "should have a :setter option define the _association= method" do
1065
- @c2.one_to_one :parent, :class => @c2, :setter=>proc{|x| @x = x}
1066
- c = @c2.new
1067
- p = @c2.load(:id=>123)
1068
- def p.parent_id=; raise; end
1069
- p.parent = c
1070
- p.instance_variable_get(:@x).must_equal c
1071
- end
1072
-
1073
- it "should support (before|after)_set callbacks" do
1074
- h = []
1075
- @c2.one_to_one :parent, :class => @c2, :before_set=>[proc{|x,y| h << x.pk; h << (y ? -y.pk : :y)}, :blah], :after_set=>proc{h << 3}
1076
- @c2.class_eval do
1077
- self::Foo = h
1078
- def blah(x)
1079
- model::Foo << (x ? x.pk : :x)
1080
- end
1081
- def blahr(x)
1082
- model::Foo << 6
1083
- end
1084
- end
1085
- p = @c2.load(:id=>10)
1086
- c = @c2.load(:id=>123)
1087
- h.must_equal []
1088
- p.parent = c
1089
- h.must_equal [10, -123, 123, 3]
1090
- p.parent = nil
1091
- h.must_equal [10, -123, 123, 3, 10, :y, :x, 3]
1092
- end
1093
-
1094
- it "should support after_load association callback" do
1095
- h = []
1096
- @c2.one_to_one :parent, :class => @c2, :after_load=>[proc{|x,y| h << [x.pk, y.pk]}, :al]
1097
- @c2.class_eval do
1098
- self::Foo = h
1099
- def al(v)
1100
- model::Foo << v.pk
1101
- end
1102
- @dataset._fetch = {:id=>20}
1103
- end
1104
- p = @c2.load(:id=>10)
1105
- parent = p.parent
1106
- h.must_equal [[10, 20], 20]
1107
- parent.pk.must_equal 20
1108
- end
1109
-
1110
- it "should raise error and not call internal add or remove method if before callback returns false, even if raise_on_save_failure is false" do
1111
- p = @c2.load(:id=>321)
1112
- c = @c2.load(:id=>123)
1113
- p.raise_on_save_failure = false
1114
- @c2.one_to_one :parent, :class => @c2, :before_set=>:bs
1115
- def p.bs(x) false end
1116
- def p._parent=; raise; end
1117
- proc{p.parent = c}.must_raise(Sequel::HookFailed)
1118
-
1119
- p.associations[:parent].must_equal nil
1120
- p.associations[:parent] = c
1121
- p.parent.must_equal c
1122
- proc{p.parent = nil}.must_raise(Sequel::HookFailed)
1123
- end
1124
-
1125
- it "should raise error and not call internal add or remove method if before callback returns false, even if raise_on_save_failure is false" do
1126
- p = @c2.load(:id=>321)
1127
- c = @c2.load(:id=>123)
1128
- p.raise_on_save_failure = false
1129
- @c2.one_to_one :parent, :class => @c2, :before_set=>:bs
1130
- def p.bs(x) cancel_action end
1131
- def p._parent=; raise; end
1132
- proc{p.parent = c}.must_raise(Sequel::HookFailed)
1133
-
1134
- p.associations[:parent].must_equal nil
1135
- p.associations[:parent] = c
1136
- p.parent.must_equal c
1137
- proc{p.parent = nil}.must_raise(Sequel::HookFailed)
1138
- end
1139
-
1140
- it "should not validate the associated object in setter if the :validate=>false option is used" do
1141
- @c2.one_to_one :parent, :class => @c2, :validate=>false
1142
- n = @c2.new(:id => 1234)
1143
- a = @c2.new(:id => 2345)
1144
- def a.validate() errors.add(:id, 'foo') end
1145
- (n.parent = a).must_equal a
1146
- end
1147
-
1148
- it "should raise an error if a callback is not a proc or symbol" do
1149
- @c2.one_to_one :parent, :class => @c2, :before_set=>Object.new
1150
- proc{@c2.new.parent = @c2.load(:id=>1)}.must_raise(Sequel::Error)
1151
- end
1152
-
1153
- it "should work_correctly when used with associate" do
1154
- @c2.associate :one_to_one, :parent, :class => @c2
1155
- @c2.load(:id => 567).parent.must_equal @c2.load({})
1156
- DB.sqls.must_equal ["SELECT * FROM nodes WHERE (nodes.node_id = 567) LIMIT 1"]
1157
- end
1158
- end
1159
-
1160
- describe Sequel::Model, "one_to_many" do
1161
- before do
1162
- @c1 = Class.new(Sequel::Model(:attributes)) do
1163
- unrestrict_primary_key
1164
- columns :id, :node_id, :y, :z
1165
- end
1166
-
1167
- @c2 = Class.new(Sequel::Model(:nodes)) do
1168
- def _refresh(ds); end
1169
- unrestrict_primary_key
1170
- attr_accessor :xxx
1171
-
1172
- def self.name; 'Node'; end
1173
- def self.to_s; 'Node'; end
1174
- columns :id, :x
1175
- end
1176
- @dataset = @c2.dataset
1177
- @dataset._fetch = {}
1178
- @c1.dataset._fetch = proc{|sql| sql =~ /SELECT 1/ ? {:a=>1} : {}}
1179
- DB.reset
1180
- end
1181
-
1182
- it "should raise an error if current class does not have a primary key, and :primary_key is not specified" do
1183
- @c2.no_primary_key
1184
- proc{@c2.one_to_many :attributes, :class => @c1}.must_raise(Sequel::Error)
1185
- DB.sqls.must_equal []
1186
- end
1187
-
1188
- it "should use implicit key if omitted" do
1189
- @c2.one_to_many :attributes, :class => @c1
1190
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE (attributes.node_id = 1234)'
1191
- end
1192
-
1193
- it "should use implicit class if omitted" do
1194
- begin
1195
- class ::HistoricalValue < Sequel::Model; end
1196
- @c2.one_to_many :historical_values
1197
-
1198
- v = @c2.new(:id => 1234).historical_values_dataset
1199
- v.must_be_kind_of(Sequel::Dataset)
1200
- v.sql.must_equal 'SELECT * FROM historical_values WHERE (historical_values.node_id = 1234)'
1201
- v.model.must_equal HistoricalValue
1202
- ensure
1203
- Object.send(:remove_const, :HistoricalValue)
1204
- end
1205
- end
1206
-
1207
- it "should use class inside a module if given as a string" do
1208
- begin
1209
- module ::Historical
1210
- class Value < Sequel::Model; end
1211
- end
1212
- @c2.one_to_many :historical_values, :class=>'Historical::Value'
1213
-
1214
- v = @c2.new(:id => 1234).historical_values_dataset
1215
- v.must_be_kind_of(Sequel::Dataset)
1216
- v.sql.must_equal 'SELECT * FROM values WHERE (values.node_id = 1234)'
1217
- v.model.must_equal Historical::Value
1218
- ensure
1219
- Object.send(:remove_const, :Historical)
1220
- end
1221
- end
1222
-
1223
- it "should use a callback if given one as the argument" do
1224
- @c2.one_to_many :attributes, :class => @c1, :key => :nodeid
1225
-
1226
- d = @c2.load(:id => 1234)
1227
- d.associations[:attributes] = []
1228
- d.attributes(proc{|ds| ds.filter{name > 'M'}}).wont_equal []
1229
- DB.sqls.must_equal ["SELECT * FROM attributes WHERE ((attributes.nodeid = 1234) AND (name > 'M'))"]
1230
- end
1231
-
1232
- it "should use explicit key if given" do
1233
- @c2.one_to_many :attributes, :class => @c1, :key => :nodeid
1234
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE (attributes.nodeid = 1234)'
1235
- end
1236
-
1237
- it "should support_composite keys" do
1238
- @c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :id], :primary_key=>[:id, :x]
1239
- @c2.load(:id => 1234, :x=>234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.id = 234))'
1240
- end
1241
-
1242
- it "should not issue query if not all keys have values" do
1243
- @c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :id], :primary_key=>[:id, :x]
1244
- @c2.load(:id => 1234, :x=>nil).attributes.must_equal []
1245
- DB.sqls.must_equal []
1246
- end
1247
-
1248
- it "should raise an Error unless same number of composite keys used" do
1249
- proc{@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :id]}.must_raise(Sequel::Error)
1250
- proc{@c2.one_to_many :attributes, :class => @c1, :primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
1251
- proc{@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :id], :primary_key=>:id}.must_raise(Sequel::Error)
1252
- proc{@c2.one_to_many :attributes, :class => @c1, :key=>:id, :primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
1253
- proc{@c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :id, :x], :primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
1254
- end
1255
-
1256
- it "should define an add_ method that works on existing records" do
1257
- @c2.one_to_many :attributes, :class => @c1
1258
-
1259
- n = @c2.load(:id => 1234)
1260
- a = @c1.load(:id => 2345)
1261
- a.must_equal n.add_attribute(a)
1262
- a.values.must_equal(:node_id => 1234, :id => 2345)
1263
- DB.sqls.must_equal ['UPDATE attributes SET node_id = 1234 WHERE (id = 2345)']
1264
- end
1265
-
1266
- it "should define an add_ method that works on new records" do
1267
- @c2.one_to_many :attributes, :class => @c1
1268
-
1269
- n = @c2.load(:id => 1234)
1270
- a = @c1.new(:id => 234)
1271
- @c1.dataset._fetch = @c1.instance_dataset._fetch = {:node_id => 1234, :id => 234}
1272
- a.must_equal n.add_attribute(a)
1273
- sqls = DB.sqls
1274
- sqls.shift.must_match(/INSERT INTO attributes \((node_)?id, (node_)?id\) VALUES \(1?234, 1?234\)/)
1275
- sqls.must_equal ["SELECT * FROM attributes WHERE (id = 234) LIMIT 1"]
1276
- a.values.must_equal(:node_id => 1234, :id => 234)
1277
- end
1278
-
1279
- it "should define a remove_ method that works on existing records" do
1280
- @c2.one_to_many :attributes, :class => @c1
1281
-
1282
- n = @c2.load(:id => 1234)
1283
- a = @c1.load(:id => 2345, :node_id => 1234)
1284
- a.must_equal n.remove_attribute(a)
1285
- a.values.must_equal(:node_id => nil, :id => 2345)
1286
- DB.sqls.must_equal ["SELECT 1 AS one FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1", 'UPDATE attributes SET node_id = NULL WHERE (id = 2345)']
1287
- end
1288
-
1289
- it "should have the remove_ method raise an error if the passed object is not already associated" do
1290
- @c2.one_to_many :attributes, :class => @c1
1291
-
1292
- n = @c2.new(:id => 1234)
1293
- a = @c1.load(:id => 2345, :node_id => 1234)
1294
- @c1.dataset._fetch = []
1295
- proc{n.remove_attribute(a)}.must_raise(Sequel::Error)
1296
- DB.sqls.must_equal ["SELECT 1 AS one FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1"]
1297
- end
1298
-
1299
- it "should accept a hash for the add_ method and create a new record" do
1300
- @c2.one_to_many :attributes, :class => @c1
1301
- n = @c2.new(:id => 1234)
1302
- DB.reset
1303
- @c1.dataset._fetch = @c1.instance_dataset._fetch = {:node_id => 1234, :id => 234}
1304
- n.add_attribute(:id => 234).must_equal @c1.load(:node_id => 1234, :id => 234)
1305
- sqls = DB.sqls
1306
- sqls.shift.must_match(/INSERT INTO attributes \((node_)?id, (node_)?id\) VALUES \(1?234, 1?234\)/)
1307
- sqls.must_equal ["SELECT * FROM attributes WHERE (id = 234) LIMIT 1"]
1308
- end
1309
-
1310
- it "should accept a primary key for the add_ method" do
1311
- @c2.one_to_many :attributes, :class => @c1
1312
- n = @c2.new(:id => 1234)
1313
- @c1.dataset._fetch = {:id=>234, :node_id=>nil}
1314
- n.add_attribute(234).must_equal @c1.load(:node_id => 1234, :id => 234)
1315
- DB.sqls.must_equal ["SELECT * FROM attributes WHERE id = 234", "UPDATE attributes SET node_id = 1234 WHERE (id = 234)"]
1316
- end
1317
-
1318
- it "should raise an error if the primary key passed to the add_ method does not match an existing record" do
1319
- @c2.one_to_many :attributes, :class => @c1
1320
- n = @c2.new(:id => 1234)
1321
- @c1.dataset._fetch = []
1322
- proc{n.add_attribute(234)}.must_raise(Sequel::NoMatchingRow)
1323
- DB.sqls.must_equal ["SELECT * FROM attributes WHERE id = 234"]
1324
- end
1325
-
1326
- it "should raise an error in the add_ method if the passed associated object is not of the correct type" do
1327
- @c2.one_to_many :attributes, :class => @c1
1328
- proc{@c2.new(:id => 1234).add_attribute(@c2.new)}.must_raise(Sequel::Error)
1329
- end
1330
-
1331
- it "should accept a primary key for the remove_ method and remove an existing record" do
1332
- @c2.one_to_many :attributes, :class => @c1
1333
- n = @c2.new(:id => 1234)
1334
- @c1.dataset._fetch = {:id=>234, :node_id=>1234}
1335
- n.remove_attribute(234).must_equal @c1.load(:node_id => nil, :id => 234)
1336
- DB.sqls.must_equal ['SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.id = 234)) LIMIT 1',
1337
- 'UPDATE attributes SET node_id = NULL WHERE (id = 234)']
1338
- end
1339
-
1340
- it "should raise an error in the remove_ method if the passed associated object is not of the correct type" do
1341
- @c2.one_to_many :attributes, :class => @c1
1342
- proc{@c2.new(:id => 1234).remove_attribute(@c2.new)}.must_raise(Sequel::Error)
1343
- end
1344
-
1345
- it "should have add_ method respect the :primary_key option" do
1346
- @c2.one_to_many :attributes, :class => @c1, :primary_key=>:xxx
1347
-
1348
- n = @c2.new(:id => 1234, :xxx=>5)
1349
- a = @c1.load(:id => 2345)
1350
- n.add_attribute(a).must_equal a
1351
- DB.sqls.must_equal ['UPDATE attributes SET node_id = 5 WHERE (id = 2345)']
1352
- end
1353
-
1354
- it "should have add_ method not add the same object to the cached association array if the object is already in the array" do
1355
- @c2.one_to_many :attributes, :class => @c1
1356
-
1357
- n = @c2.new(:id => 1234)
1358
- a = @c1.load(:id => 2345)
1359
- n.associations[:attributes] = []
1360
- a.must_equal n.add_attribute(a)
1361
- a.must_equal n.add_attribute(a)
1362
- a.values.must_equal(:node_id => 1234, :id => 2345)
1363
- n.attributes.must_equal [a]
1364
- DB.sqls.must_equal ['UPDATE attributes SET node_id = 1234 WHERE (id = 2345)'] * 2
1365
- end
1366
-
1367
- it "should have add_ method respect composite keys" do
1368
- @c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :y], :primary_key=>[:id, :x]
1369
-
1370
- n = @c2.load(:id => 1234, :x=>5)
1371
- a = @c1.load(:id => 2345)
1372
- n.add_attribute(a).must_equal a
1373
- sqls = DB.sqls
1374
- sqls.shift.must_match(/UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 2345\)/)
1375
- sqls.must_equal []
1376
- end
1377
-
1378
- it "should have add_ method accept a composite key" do
1379
- @c1.set_primary_key [:id, :z]
1380
- @c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :y], :primary_key=>[:id, :x]
1381
- @c1.dataset._fetch = {:id => 2345, :z => 8, :node_id => 1234, :y=>5}
1382
-
1383
- n = @c2.load(:id => 1234, :x=>5)
1384
- a = @c1.load(:id => 2345, :z => 8, :node_id => 1234, :y=>5)
1385
- n.add_attribute([2345, 8]).must_equal a
1386
- sqls = DB.sqls
1387
- sqls.shift.must_match(/SELECT \* FROM attributes WHERE \(\((id|z) = (2345|8)\) AND \((id|z) = (2345|8)\)\) LIMIT 1/)
1388
- sqls.shift.must_match(/UPDATE attributes SET (node_id|y) = (1234|5), (node_id|y) = (1234|5) WHERE \(\((id|z) = (2345|8)\) AND \((id|z) = (2345|8)\)\)/)
1389
- sqls.must_equal []
1390
- end
1391
-
1392
- it "should have remove_ method respect composite keys" do
1393
- @c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :y], :primary_key=>[:id, :x]
1394
-
1395
- n = @c2.load(:id => 1234, :x=>5)
1396
- a = @c1.load(:id => 2345, :node_id=>1234, :y=>5)
1397
- n.remove_attribute(a).must_equal a
1398
- sqls = DB.sqls
1399
- sqls.pop.must_match(/UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(id = 2345\)/)
1400
- sqls.must_equal ["SELECT 1 AS one FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.y = 5) AND (id = 2345)) LIMIT 1"]
1401
- end
1402
-
1403
- it "should accept a array of composite primary key values for the remove_ method and remove an existing record" do
1404
- @c1.set_primary_key [:id, :y]
1405
- @c2.one_to_many :attributes, :class => @c1, :key=>:node_id, :primary_key=>:id
1406
- n = @c2.new(:id => 123)
1407
- @c1.dataset._fetch = {:id=>234, :node_id=>123, :y=>5}
1408
- n.remove_attribute([234, 5]).must_equal @c1.load(:node_id => nil, :y => 5, :id => 234)
1409
- sqls = DB.sqls
1410
- sqls.length.must_equal 2
1411
- sqls.first.must_match(/SELECT \* FROM attributes WHERE \(\(attributes.node_id = 123\) AND \(attributes\.(id|y) = (234|5)\) AND \(attributes\.(id|y) = (234|5)\)\) LIMIT 1/)
1412
- sqls.last.must_match(/UPDATE attributes SET node_id = NULL WHERE \(\((id|y) = (234|5)\) AND \((id|y) = (234|5)\)\)/)
1413
- end
1414
-
1415
- it "should raise an error in add_ and remove_ if the passed object returns false to save (is not valid)" do
1416
- @c2.one_to_many :attributes, :class => @c1
1417
- n = @c2.new(:id => 1234)
1418
- a = @c1.new(:id => 2345)
1419
- def a.validate() errors.add(:id, 'foo') end
1420
- proc{n.add_attribute(a)}.must_raise(Sequel::ValidationFailed)
1421
- proc{n.remove_attribute(a)}.must_raise(Sequel::ValidationFailed)
1422
- end
1423
-
1424
- it "should not validate the associated object in add_ and remove_ if the :validate=>false option is used" do
1425
- @c2.one_to_many :attributes, :class => @c1, :validate=>false
1426
- n = @c2.new(:id => 1234)
1427
- a = @c1.new(:id => 2345)
1428
- def a.validate() errors.add(:id, 'foo') end
1429
- n.add_attribute(a).must_equal a
1430
- n.remove_attribute(a).must_equal a
1431
- end
1432
-
1433
- it "should not raise exception in add_ and remove_ if the :raise_on_save_failure=>false option is used" do
1434
- @c2.one_to_many :attributes, :class => @c1, :raise_on_save_failure=>false
1435
- n = @c2.new(:id => 1234)
1436
- a = @c1.new(:id => 2345)
1437
- def a.validate() errors.add(:id, 'foo') end
1438
- n.associations[:attributes] = []
1439
- n.add_attribute(a).must_equal nil
1440
- n.associations[:attributes].must_equal []
1441
- n.remove_attribute(a).must_equal nil
1442
- n.associations[:attributes].must_equal []
1443
- end
1444
-
1445
- it "should raise an error if the model object doesn't have a valid primary key" do
1446
- @c2.one_to_many :attributes, :class => @c1
1447
- a = @c2.new
1448
- n = @c1.load(:id=>123)
1449
- proc{a.attributes_dataset}.must_raise(Sequel::Error)
1450
- proc{a.add_attribute(n)}.must_raise(Sequel::Error)
1451
- proc{a.remove_attribute(n)}.must_raise(Sequel::Error)
1452
- proc{a.remove_all_attributes}.must_raise(Sequel::Error)
1453
- end
1454
-
1455
- it "should use :primary_key option if given" do
1456
- @c1.one_to_many :nodes, :class => @c2, :primary_key => :node_id, :key=>:id
1457
- @c1.load(:id => 1234, :node_id=>4321).nodes_dataset.sql.must_equal "SELECT * FROM nodes WHERE (nodes.id = 4321)"
1458
- end
1459
-
1460
- it "should support a select option" do
1461
- @c2.one_to_many :attributes, :class => @c1, :select => [:id, :name]
1462
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal "SELECT id, name FROM attributes WHERE (attributes.node_id = 1234)"
1463
- end
1464
-
1465
- it "should support a conditions option" do
1466
- @c2.one_to_many :attributes, :class => @c1, :conditions => {:a=>32}
1467
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal "SELECT * FROM attributes WHERE ((a = 32) AND (attributes.node_id = 1234))"
1468
- @c2.one_to_many :attributes, :class => @c1, :conditions => Sequel.~(:a)
1469
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal "SELECT * FROM attributes WHERE (NOT a AND (attributes.node_id = 1234))"
1470
- end
1471
-
1472
- it "should support an order option" do
1473
- @c2.one_to_many :attributes, :class => @c1, :order => :kind
1474
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal "SELECT * FROM attributes WHERE (attributes.node_id = 1234) ORDER BY kind"
1475
- end
1476
-
1477
- it "should support an array for the order option" do
1478
- @c2.one_to_many :attributes, :class => @c1, :order => [:kind1, :kind2]
1479
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal "SELECT * FROM attributes WHERE (attributes.node_id = 1234) ORDER BY kind1, kind2"
1480
- end
1481
-
1482
- it "should have a dataset method for the associated object dataset" do
1483
- @c2.one_to_many :attributes, :class => @c1
1484
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE (attributes.node_id = 1234)'
1485
- end
1486
-
1487
- it "should accept a block" do
1488
- @c2.one_to_many :attributes, :class => @c1 do |ds|
1489
- ds.filter(:xxx => nil)
1490
- end
1491
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (xxx IS NULL))'
1492
- end
1493
-
1494
- it "should support :order option with block" do
1495
- @c2.one_to_many :attributes, :class => @c1, :order => :kind do |ds|
1496
- ds.filter(:xxx => nil)
1497
- end
1498
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (xxx IS NULL)) ORDER BY kind'
1499
- end
1500
-
1501
- it "should have the block argument affect the _dataset method" do
1502
- @c2.one_to_many :attributes, :class => @c1 do |ds|
1503
- ds.filter(:xxx => 456)
1504
- end
1505
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (xxx = 456))'
1506
- end
1507
-
1508
- it "should support a :dataset option that is used instead of the default" do
1509
- c1 = @c1
1510
- @c2.one_to_many :all_other_attributes, :class => @c1, :dataset=>proc{c1.exclude(:nodeid=>pk)}, :order=>:a, :limit=>10 do |ds|
1511
- ds.filter(:xxx => 5)
1512
- end
1513
- @c2.new(:id => 1234).all_other_attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE ((nodeid != 1234) AND (xxx = 5)) ORDER BY a LIMIT 10'
1514
- @c2.new(:id => 1234).all_other_attributes.must_equal [@c1.load({})]
1515
- DB.sqls.must_equal ['SELECT * FROM attributes WHERE ((nodeid != 1234) AND (xxx = 5)) ORDER BY a LIMIT 10']
1516
- end
1517
-
1518
- it "should support a :limit option" do
1519
- @c2.one_to_many :attributes, :class => @c1 , :limit=>10
1520
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE (attributes.node_id = 1234) LIMIT 10'
1521
- @c2.one_to_many :attributes, :class => @c1 , :limit=>[10,10]
1522
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT * FROM attributes WHERE (attributes.node_id = 1234) LIMIT 10 OFFSET 10'
1523
- end
1524
-
1525
- it "should have the :eager option affect the _dataset method" do
1526
- @c2.one_to_many :attributes, :class => @c2 , :eager=>:attributes
1527
- @c2.new(:id => 1234).attributes_dataset.opts[:eager].must_equal(:attributes=>nil)
1528
- end
1529
-
1530
- it "should populate cache when accessed" do
1531
- @c2.one_to_many :attributes, :class => @c1
1532
- n = @c2.new(:id => 1234)
1533
- n.associations.include?(:attributes).must_equal false
1534
- atts = n.attributes
1535
- atts.must_equal n.associations[:attributes]
1536
- DB.sqls.must_equal ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
1537
- end
1538
-
1539
- it "should use cache if available" do
1540
- @c2.one_to_many :attributes, :class => @c1
1541
- n = @c2.new(:id => 1234)
1542
- n.associations[:attributes] = 42
1543
- n.attributes.must_equal 42
1544
- DB.sqls.must_equal []
1545
- end
1546
-
1547
- it "should not use cache if asked to reload" do
1548
- @c2.one_to_many :attributes, :class => @c1
1549
- n = @c2.new(:id => 1234)
1550
- n.associations[:attributes] = 42
1551
- n.attributes(true).wont_equal 42
1552
- DB.sqls.must_equal ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
1553
- end
1554
-
1555
- it "should add item to cache if it exists when calling add_" do
1556
- @c2.one_to_many :attributes, :class => @c1
1557
- n = @c2.new(:id => 1234)
1558
- att = @c1.load(:id => 345)
1559
- a = []
1560
- n.associations[:attributes] = a
1561
- n.add_attribute(att)
1562
- a.must_equal [att]
1563
- end
1564
-
1565
- it "should set object to item's reciprocal cache when calling add_" do
1566
- @c2.one_to_many :attributes, :class => @c1
1567
- @c1.many_to_one :node, :class => @c2
1568
-
1569
- n = @c2.new(:id => 1234)
1570
- att = @c1.new(:id => 345)
1571
- n.add_attribute(att)
1572
- att.node.must_equal n
1573
- end
1574
-
1575
- it "should remove item from cache if it exists when calling remove_" do
1576
- @c2.one_to_many :attributes, :class => @c1
1577
-
1578
- n = @c2.load(:id => 1234)
1579
- att = @c1.load(:id => 345)
1580
- a = [att]
1581
- n.associations[:attributes] = a
1582
- n.remove_attribute(att)
1583
- a.must_equal []
1584
- end
1585
-
1586
- it "should remove item's reciprocal cache calling remove_" do
1587
- @c2.one_to_many :attributes, :class => @c1
1588
- @c1.many_to_one :node, :class => @c2
1589
-
1590
- n = @c2.new(:id => 1234)
1591
- att = @c1.new(:id => 345)
1592
- att.associations[:node] = n
1593
- att.node.must_equal n
1594
- n.remove_attribute(att)
1595
- att.node.must_equal nil
1596
- end
1597
-
1598
- it "should not create the add_, remove_, or remove_all_ methods if :read_only option is used" do
1599
- @c2.one_to_many :attributes, :class => @c1, :read_only=>true
1600
- im = @c2.instance_methods.collect{|x| x.to_s}
1601
- im.must_include('attributes')
1602
- im.must_include('attributes_dataset')
1603
- im.wont_include('add_attribute')
1604
- im.wont_include('remove_attribute')
1605
- im.wont_include('remove_all_attributes')
1606
- end
1607
-
1608
- it "should not add associations methods directly to class" do
1609
- @c2.one_to_many :attributes, :class => @c1
1610
- im = @c2.instance_methods.collect{|x| x.to_s}
1611
- im.must_include('attributes')
1612
- im.must_include('attributes_dataset')
1613
- im.must_include('add_attribute')
1614
- im.must_include('remove_attribute')
1615
- im.must_include('remove_all_attributes')
1616
- im2 = @c2.instance_methods(false).collect{|x| x.to_s}
1617
- im2.wont_include('attributes')
1618
- im2.wont_include('attributes_dataset')
1619
- im2.wont_include('add_attribute')
1620
- im2.wont_include('remove_attribute')
1621
- im2.wont_include('remove_all_attributes')
1622
- end
1623
-
1624
- it "should populate the reciprocal many_to_one cache when loading the one_to_many association" do
1625
- @c2.one_to_many :attributes, :class => @c1, :key => :node_id
1626
- @c1.many_to_one :node, :class => @c2, :key => :node_id
1627
-
1628
- n = @c2.new(:id => 1234)
1629
- atts = n.attributes
1630
- DB.sqls.must_equal ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
1631
- atts.must_equal [@c1.load({})]
1632
- atts.map{|a| a.node}.must_equal [n]
1633
- DB.sqls.must_equal []
1634
- end
1635
-
1636
- it "should use an explicit :reciprocal option if given" do
1637
- @c2.one_to_many :attributes, :class => @c1, :key => :node_id, :reciprocal=>:wxyz
1638
-
1639
- n = @c2.new(:id => 1234)
1640
- atts = n.attributes
1641
- DB.sqls.must_equal ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
1642
- atts.must_equal [@c1.load({})]
1643
- atts.map{|a| a.associations[:wxyz]}.must_equal [n]
1644
- DB.sqls.must_equal []
1645
- end
1646
-
1647
- it "should have an remove_all_ method that removes all associated objects" do
1648
- @c2.one_to_many :attributes, :class => @c1
1649
- @c2.new(:id => 1234).remove_all_attributes
1650
- DB.sqls.must_equal ['UPDATE attributes SET node_id = NULL WHERE (node_id = 1234)']
1651
- end
1652
-
1653
- it "should have remove_all method respect association filters" do
1654
- @c2.one_to_many :attributes, :class => @c1, :conditions=>{:a=>1} do |ds|
1655
- ds.filter(:b=>2)
1656
- end
1657
- @c2.new(:id => 1234).remove_all_attributes
1658
- DB.sqls.must_equal ['UPDATE attributes SET node_id = NULL WHERE ((a = 1) AND (node_id = 1234) AND (b = 2))']
1659
- end
1660
-
1661
- it "should have the remove_all_ method respect the :primary_key option" do
1662
- @c2.one_to_many :attributes, :class => @c1, :primary_key=>:xxx
1663
- @c2.new(:id => 1234, :xxx=>5).remove_all_attributes
1664
- DB.sqls.must_equal ['UPDATE attributes SET node_id = NULL WHERE (node_id = 5)']
1665
- end
1666
-
1667
- it "should have the remove_all_ method respect composite keys" do
1668
- @c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :y], :primary_key=>[:id, :x]
1669
- @c2.new(:id => 1234, :x=>5).remove_all_attributes
1670
- sqls = DB.sqls
1671
- sqls.pop.must_match(/UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(node_id = 1234\) AND \(y = 5\)\)/)
1672
- sqls.must_equal []
1673
- end
1674
-
1675
- it "remove_all should set the cache to []" do
1676
- @c2.one_to_many :attributes, :class => @c1
1677
- node = @c2.new(:id => 1234)
1678
- node.remove_all_attributes
1679
- node.associations[:attributes].must_equal []
1680
- end
1681
-
1682
- it "remove_all should return the array of previously associated items if the cache is populated" do
1683
- @c2.one_to_many :attributes, :class => @c1
1684
- attrib = @c1.new(:id=>3)
1685
- node = @c2.new(:id => 1234)
1686
- @c1.dataset._fetch = [[], [{:id=>3, :node_id=>1234}]]
1687
- node.attributes.must_equal []
1688
- node.add_attribute(attrib)
1689
- node.associations[:attributes].must_equal [attrib]
1690
- node.remove_all_attributes.must_equal [attrib]
1691
- end
1692
-
1693
- it "remove_all should return nil if the cache is not populated" do
1694
- @c2.one_to_many :attributes, :class => @c1
1695
- @c2.new(:id => 1234).remove_all_attributes.must_equal nil
1696
- end
1697
-
1698
- it "remove_all should remove the current item from all reciprocal association caches if they are populated" do
1699
- @c2.one_to_many :attributes, :class => @c1
1700
- @c1.many_to_one :node, :class => @c2
1701
- @c2.dataset._fetch = []
1702
- @c1.dataset._fetch = [[], [{:id=>3, :node_id=>1234}]]
1703
- attrib = @c1.new(:id=>3)
1704
- node = @c2.load(:id => 1234)
1705
- node.attributes.must_equal []
1706
- attrib.node.must_equal nil
1707
- node.add_attribute(attrib)
1708
- attrib.associations[:node].must_equal node
1709
- node.remove_all_attributes
1710
- attrib.associations.fetch(:node, 2).must_equal nil
1711
- end
1712
-
1713
- it "should call an _add_ method internally to add attributes" do
1714
- @c2.one_to_many :attributes, :class => @c1
1715
- @c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_add_attribute")
1716
- p = @c2.load(:id=>10)
1717
- c = @c1.load(:id=>123)
1718
- def p._add_attribute(x)
1719
- @x = x
1720
- end
1721
- def c._node_id=; raise; end
1722
- p.add_attribute(c)
1723
- p.instance_variable_get(:@x).must_equal c
1724
- end
1725
-
1726
- it "should support an :adder option for defining the _add_ method" do
1727
- @c2.one_to_many :attributes, :class => @c1, :adder=>proc{|x| @x = x}
1728
- p = @c2.load(:id=>10)
1729
- c = @c1.load(:id=>123)
1730
- def c._node_id=; raise; end
1731
- p.add_attribute(c)
1732
- p.instance_variable_get(:@x).must_equal c
1733
- end
1734
-
1735
- it "should allow additional arguments given to the add_ method and pass them onwards to the _add_ method" do
1736
- @c2.one_to_many :attributes, :class => @c1
1737
- p = @c2.load(:id=>10)
1738
- c = @c1.load(:id=>123)
1739
- def p._add_attribute(x,*y)
1740
- @x = x
1741
- @y = y
1742
- end
1743
- def c._node_id=; raise; end
1744
- p.add_attribute(c,:foo,:bar=>:baz)
1745
- p.instance_variable_get(:@x).must_equal c
1746
- p.instance_variable_get(:@y).must_equal [:foo,{:bar=>:baz}]
1747
- end
1748
-
1749
- it "should call a _remove_ method internally to remove attributes" do
1750
- @c2.one_to_many :attributes, :class => @c1
1751
- @c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_remove_attribute")
1752
- p = @c2.load(:id=>10)
1753
- c = @c1.load(:id=>123)
1754
- def p._remove_attribute(x)
1755
- @x = x
1756
- end
1757
- def c._node_id=; raise; end
1758
- p.remove_attribute(c)
1759
- p.instance_variable_get(:@x).must_equal c
1760
- end
1761
-
1762
- it "should support a :remover option for defining the _remove_ method" do
1763
- @c2.one_to_many :attributes, :class => @c1, :remover=>proc{|x| @x = x}
1764
- p = @c2.load(:id=>10)
1765
- c = @c1.load(:id=>123)
1766
- def c._node_id=; raise; end
1767
- p.remove_attribute(c)
1768
- p.instance_variable_get(:@x).must_equal c
1769
- end
1770
-
1771
- it "should allow additional arguments given to the remove_ method and pass them onwards to the _remove_ method" do
1772
- @c2.one_to_many :attributes, :class => @c1, :reciprocal=>nil
1773
- p = @c2.load(:id=>10)
1774
- c = @c1.load(:id=>123)
1775
- def p._remove_attribute(x,*y)
1776
- @x = x
1777
- @y = y
1778
- end
1779
- def c._node_id=; raise; end
1780
- p.remove_attribute(c,:foo,:bar=>:baz)
1781
- p.instance_variable_get(:@x).must_equal c
1782
- p.instance_variable_get(:@y).must_equal [:foo,{:bar=>:baz}]
1783
- end
1784
-
1785
- it "should allow additional arguments given to the remove_all_ method and pass them onwards to the _remove_all_ method" do
1786
- @c2.one_to_many :attributes, :class => @c1
1787
- p = @c2.load(:id=>10)
1788
- c = @c1.load(:id=>123)
1789
- def p._remove_all_attributes(*y)
1790
- @y = y
1791
- end
1792
- def c._node_id=; raise; end
1793
- p.remove_all_attributes(:foo,:bar=>:baz)
1794
- p.instance_variable_get(:@y).must_equal [:foo,{:bar=>:baz}]
1795
- end
1796
-
1797
- it "should call a _remove_all_ method internally to remove attributes" do
1798
- @c2.one_to_many :attributes, :class => @c1
1799
- @c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_remove_all_attributes")
1800
- p = @c2.load(:id=>10)
1801
- def p._remove_all_attributes
1802
- @x = :foo
1803
- end
1804
- p.remove_all_attributes
1805
- p.instance_variable_get(:@x).must_equal :foo
1806
- end
1807
-
1808
- it "should support a :clearer option for defining the _remove_all_ method" do
1809
- @c2.one_to_many :attributes, :class => @c1, :clearer=>proc{@x = :foo}
1810
- p = @c2.load(:id=>10)
1811
- p.remove_all_attributes
1812
- p.instance_variable_get(:@x).must_equal :foo
1813
- end
1814
-
1815
- it "should support (before|after)_(add|remove) callbacks" do
1816
- h = []
1817
- @c2.one_to_many :attributes, :class => @c1, :before_add=>[proc{|x,y| h << x.pk; h << -y.pk}, :blah], :after_add=>proc{h << 3}, :before_remove=>:blah, :after_remove=>[:blahr]
1818
- @c2.class_eval do
1819
- self::Foo = h
1820
- def _add_attribute(v)
1821
- model::Foo << 4
1822
- end
1823
- def _remove_attribute(v)
1824
- model::Foo << 5
1825
- end
1826
- def blah(x)
1827
- model::Foo << x.pk
1828
- end
1829
- def blahr(x)
1830
- model::Foo << 6
1831
- end
1832
- end
1833
- p = @c2.load(:id=>10)
1834
- c = @c1.load(:id=>123)
1835
- h.must_equal []
1836
- p.add_attribute(c)
1837
- h.must_equal [10, -123, 123, 4, 3]
1838
- p.remove_attribute(c)
1839
- h.must_equal [10, -123, 123, 4, 3, 123, 5, 6]
1840
- end
1841
-
1842
- it "should support after_load association callback" do
1843
- h = []
1844
- @c2.one_to_many :attributes, :class => @c1, :after_load=>[proc{|x,y| h << [x.pk, y.collect{|z|z.pk}]}, :al]
1845
- @c2.class_eval do
1846
- self::Foo = h
1847
- def al(v)
1848
- v.each{|x| model::Foo << x.pk}
1849
- end
1850
- end
1851
- @c1.dataset._fetch = [{:id=>20}, {:id=>30}]
1852
- p = @c2.load(:id=>10, :parent_id=>20)
1853
- attributes = p.attributes
1854
- h.must_equal [[10, [20, 30]], 20, 30]
1855
- attributes.collect{|a| a.pk}.must_equal [20, 30]
1856
- end
1857
-
1858
- it "should raise error and not call internal add or remove method if before callback returns false if raise_on_save_failure is true" do
1859
- p = @c2.load(:id=>10)
1860
- c = @c1.load(:id=>123)
1861
- @c2.one_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
1862
- def p.ba(c) false end
1863
- def p._add_attribute; raise; end
1864
- def p._remove_attribute; raise; end
1865
- p.associations[:attributes] = []
1866
- proc{p.add_attribute(c)}.must_raise(Sequel::HookFailed)
1867
- p.attributes.must_equal []
1868
- p.associations[:attributes] = [c]
1869
- def p.br(c) false end
1870
- proc{p.remove_attribute(c)}.must_raise(Sequel::HookFailed)
1871
- p.attributes.must_equal [c]
1872
- end
1873
-
1874
- it "should return nil and not call internal add or remove method if before callback returns false if raise_on_save_failure is false" do
1875
- p = @c2.load(:id=>10)
1876
- c = @c1.load(:id=>123)
1877
- p.raise_on_save_failure = false
1878
- @c2.one_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
1879
- def p.ba(c) false end
1880
- def p._add_attribute; raise; end
1881
- def p._remove_attribute; raise; end
1882
- p.associations[:attributes] = []
1883
- p.add_attribute(c).must_equal nil
1884
- p.attributes.must_equal []
1885
- p.associations[:attributes] = [c]
1886
- def p.br(c) false end
1887
- p.remove_attribute(c).must_equal nil
1888
- p.attributes.must_equal [c]
1889
- end
1890
-
1891
- it "should raise error and not call internal add or remove method if before callback calls cancel_action if raise_on_save_failure is true" do
1892
- p = @c2.load(:id=>10)
1893
- c = @c1.load(:id=>123)
1894
- @c2.one_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
1895
- def p.ba(o); cancel_action; end
1896
- def p._add_attribute; raise; end
1897
- def p._remove_attribute; raise; end
1898
- p.associations[:attributes] = []
1899
- proc{p.add_attribute(c)}.must_raise(Sequel::HookFailed)
1900
- p.attributes.must_equal []
1901
- p.associations[:attributes] = [c]
1902
- def p.br(o); cancel_action; end
1903
- proc{p.remove_attribute(c)}.must_raise(Sequel::HookFailed)
1904
- p.attributes.must_equal [c]
1905
- end
1906
-
1907
- it "should return nil and not call internal add or remove method if before callback calls cancel_action if raise_on_save_failure is false" do
1908
- p = @c2.load(:id=>10)
1909
- c = @c1.load(:id=>123)
1910
- p.raise_on_save_failure = false
1911
- @c2.one_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
1912
- def p.ba(o); cancel_action; end
1913
- def p._add_attribute; raise; end
1914
- def p._remove_attribute; raise; end
1915
- p.associations[:attributes] = []
1916
- p.add_attribute(c).must_equal nil
1917
- p.attributes.must_equal []
1918
- p.associations[:attributes] = [c]
1919
- def p.br(o); cancel_action; end
1920
- p.remove_attribute(c).must_equal nil
1921
- p.attributes.must_equal [c]
1922
- end
1923
- end
1924
-
1925
- describe Sequel::Model, "many_to_many" do
1926
- before do
1927
- @c1 = Class.new(Sequel::Model(:attributes)) do
1928
- unrestrict_primary_key
1929
- attr_accessor :yyy
1930
- def self.name; 'Attribute'; end
1931
- def self.to_s; 'Attribute'; end
1932
- columns :id, :y, :z
1933
- end
1934
-
1935
- @c2 = Class.new(Sequel::Model(:nodes)) do
1936
- unrestrict_primary_key
1937
- attr_accessor :xxx
1938
-
1939
- def self.name; 'Node'; end
1940
- def self.to_s; 'Node'; end
1941
- columns :id, :x
1942
- end
1943
- @dataset = @c2.dataset
1944
- @c1.dataset.autoid = 1
1945
-
1946
- [@c1, @c2].each{|c| c.dataset._fetch = {}}
1947
- DB.reset
1948
- end
1949
-
1950
- it "should raise an error if current class does not have a primary key, and :left_primary_key is not specified" do
1951
- @c2.no_primary_key
1952
- proc{@c2.many_to_many :attributes, :class => @c1}.must_raise(Sequel::Error)
1953
- DB.sqls.must_equal []
1954
- end
1955
-
1956
- it "should raise an error if associated class does not have a primary key, and :right_primary_key is not specified" do
1957
- @c1.no_primary_key
1958
- @c2.many_to_many :attributes, :class => @c1
1959
- d = @c2.new(:id => 1234)
1960
- proc{d.attributes}.must_raise(Sequel::Error)
1961
- DB.sqls.must_equal []
1962
- end
1963
-
1964
- it "should use implicit key values and join table if omitted" do
1965
- @c2.many_to_many :attributes, :class => @c1
1966
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
1967
- end
1968
-
1969
- it "should use implicit key values and join table if omitted" do
1970
- @c2.one_through_one :attribute, :class => @c1
1971
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 1'
1972
- end
1973
-
1974
- it "should use implicit class if omitted" do
1975
- begin
1976
- class ::Tag < Sequel::Model; end
1977
- @c2.many_to_many :tags
1978
- @c2.new(:id => 1234).tags_dataset.sql.must_equal 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON (nodes_tags.tag_id = tags.id) WHERE (nodes_tags.node_id = 1234)'
1979
- ensure
1980
- Object.send(:remove_const, :Tag)
1981
- end
1982
- end
1983
-
1984
- it "should use class inside module if given as a string" do
1985
- begin
1986
- module ::Historical
1987
- class Tag < Sequel::Model; end
1988
- end
1989
- @c2.many_to_many :tags, :class=>'::Historical::Tag'
1990
- @c2.new(:id => 1234).tags_dataset.sql.must_equal 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON (nodes_tags.tag_id = tags.id) WHERE (nodes_tags.node_id = 1234)'
1991
- ensure
1992
- Object.send(:remove_const, :Historical)
1993
- end
1994
- end
1995
-
1996
- it "should not override a selection consisting completely of qualified columns using Sequel::SQL::QualifiedIdentifier" do
1997
- @c1.dataset = @c1.dataset.select(Sequel.qualify(:attributes, :id), Sequel.qualify(:attributes, :b))
1998
- @c2.many_to_many :attributes, :class => @c1
1999
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.id, attributes.b FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
2000
- end
2001
-
2002
- it "should not override a selection consisting completely of qualified columns using symbols" do
2003
- @c1.dataset = @c1.dataset.select(:attributes__id, :attributes__b)
2004
- @c2.many_to_many :attributes, :class => @c1
2005
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.id, attributes.b FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
2006
- end
2007
-
2008
- it "should not override a selection consisting completely of qualified columns using Sequel::SQL::AliasedExpression" do
2009
- @c1.dataset = @c1.dataset.select(Sequel.qualify(:attributes, :id).as(:a), Sequel.as(:attributes__b, :c))
2010
- @c2.many_to_many :attributes, :class => @c1
2011
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.id AS a, attributes.b AS c FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
2012
- end
2013
-
2014
- it "should override a selection consisting of non qualified columns" do
2015
- @c1.dataset = @c1.dataset.select{foo(:bar)}
2016
- @c2.many_to_many :attributes, :class => @c1
2017
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
2018
- end
2019
-
2020
- it "should respect :eager_loader_predicate_key when lazily loading" do
2021
- @c2.many_to_many :attributes, :class => @c1, :eager_loading_predicate_key=>Sequel.subscript(:attributes_nodes__node_id, 0)
2022
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id[0] = 1234)'
2023
- end
2024
-
2025
- it "should use explicit key values and join table if given" do
2026
- @c2.many_to_many :attributes, :class => @c1, :left_key => :nodeid, :right_key => :attributeid, :join_table => :attribute2node
2027
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attribute2node ON (attribute2node.attributeid = attributes.id) WHERE (attribute2node.nodeid = 1234)'
2028
- end
2029
-
2030
- it "should support a conditions option" do
2031
- @c2.many_to_many :attributes, :class => @c1, :conditions => {:a=>32}
2032
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((a = 32) AND (attributes_nodes.node_id = 1234))'
2033
-
2034
- @c2.many_to_many :attributes, :class => @c1, :conditions => ['a = ?', 32]
2035
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((a = 32) AND (attributes_nodes.node_id = 1234))'
2036
- @c2.new(:id => 1234).attributes.must_equal [@c1.load({})]
2037
- end
2038
-
2039
- it "should support an order option" do
2040
- @c2.many_to_many :attributes, :class => @c1, :order => :blah
2041
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) ORDER BY blah'
2042
- end
2043
-
2044
- it "should support an array for the order option" do
2045
- @c2.many_to_many :attributes, :class => @c1, :order => [:blah1, :blah2]
2046
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) ORDER BY blah1, blah2'
2047
- end
2048
-
2049
- it "should support :left_primary_key and :right_primary_key options" do
2050
- @c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
2051
- @c2.new(:id => 1234, :xxx=>5).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.yyy) WHERE (attributes_nodes.node_id = 5)'
2052
- end
2053
-
2054
- it "should support composite keys" do
2055
- @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
2056
- @c2.load(:id => 1234, :x=>5).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.r1 = attributes.id) AND (attributes_nodes.r2 = attributes.y)) WHERE ((attributes_nodes.l1 = 1234) AND (attributes_nodes.l2 = 5))'
2057
- end
2058
-
2059
- it "should not issue query if not all keys have values" do
2060
- @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
2061
- @c2.load(:id => 1234, :x=>nil).attributes.must_equal []
2062
- DB.sqls.must_equal []
2063
- end
2064
-
2065
- it "should raise an Error unless same number of composite keys used" do
2066
- proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2067
- proc{@c2.many_to_many :attributes, :class => @c1, :left_primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2068
- proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>[:node_id, :id], :left_primary_key=>:id}.must_raise(Sequel::Error)
2069
- proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>:id, :left_primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2070
- proc{@c2.many_to_many :attributes, :class => @c1, :left_key=>[:node_id, :id, :x], :left_primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
2071
-
2072
- proc{@c2.many_to_many :attributes, :class => @c1, :right_primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2073
- proc{@c2.many_to_many :attributes, :class => @c1, :right_key=>[:node_id, :id], :right_primary_key=>:id}.must_raise(Sequel::Error)
2074
- proc{@c2.many_to_many :attributes, :class => @c1, :right_key=>:id, :left_primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2075
- proc{@c2.many_to_many :attributes, :class => @c1, :right_key=>[:node_id, :id, :x], :right_primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
2076
- end
2077
-
2078
- it "should support a select option" do
2079
- @c2.many_to_many :attributes, :class => @c1, :select => :blah
2080
-
2081
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT blah FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
2082
- end
2083
-
2084
- it "should support an array for the select option" do
2085
- @c2.many_to_many :attributes, :class => @c1, :select => [Sequel::SQL::ColumnAll.new(:attributes), :attribute_nodes__blah2]
2086
-
2087
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.*, attribute_nodes.blah2 FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
2088
- end
2089
-
2090
- it "should accept a block" do
2091
- @c2.many_to_many :attributes, :class => @c1 do |ds|
2092
- ds.filter(:xxx => @xxx)
2093
- end
2094
-
2095
- n = @c2.new(:id => 1234)
2096
- n.xxx = 555
2097
- n.attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((attributes_nodes.node_id = 1234) AND (xxx = 555))'
2098
- end
2099
-
2100
- it "should allow the :order option while accepting a block" do
2101
- @c2.many_to_many :attributes, :class => @c1, :order=>[:blah1, :blah2] do |ds|
2102
- ds.filter(:xxx => @xxx)
2103
- end
2104
-
2105
- n = @c2.new(:id => 1234)
2106
- n.xxx = 555
2107
- n.attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((attributes_nodes.node_id = 1234) AND (xxx = 555)) ORDER BY blah1, blah2'
2108
- end
2109
-
2110
- it "should support a :dataset option that is used instead of the default" do
2111
- c1 = @c1
2112
- @c2.many_to_many :attributes, :class => @c1, :dataset=>proc{c1.join_table(:natural, :an).filter(:an__nodeid=>pk)}, :order=> :a, :limit=>10, :select=>nil do |ds|
2113
- ds.filter(:xxx => @xxx)
2114
- end
2115
-
2116
- n = @c2.new(:id => 1234)
2117
- n.xxx = 555
2118
- n.attributes_dataset.sql.must_equal 'SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 10'
2119
- n.attributes.must_equal [@c1.load({})]
2120
- DB.sqls.must_equal ['SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 10']
2121
- end
2122
-
2123
- it "should support a :dataset option that accepts the reflection as an argument" do
2124
- @c2.many_to_many :attributes, :class => @c1, :dataset=>lambda{|opts| opts.associated_class.natural_join(:an).filter(:an__nodeid=>pk)}, :order=> :a, :limit=>10, :select=>nil do |ds|
2125
- ds.filter(:xxx => @xxx)
2126
- end
2127
-
2128
- n = @c2.new(:id => 1234)
2129
- n.xxx = 555
2130
- n.attributes_dataset.sql.must_equal 'SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 10'
2131
- n.attributes.must_equal [@c1.load({})]
2132
- DB.sqls.must_equal ['SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 10']
2133
- end
2134
-
2135
- it "should support a :limit option" do
2136
- @c2.many_to_many :attributes, :class => @c1 , :limit=>10
2137
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 10'
2138
- @c2.many_to_many :attributes, :class => @c1 , :limit=>[10, 10]
2139
- @c2.new(:id => 1234).attributes_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 10 OFFSET 10'
2140
- end
2141
-
2142
- it "should have the :eager option affect the _dataset method" do
2143
- @c2.many_to_many :attributes, :class => @c2 , :eager=>:attributes
2144
- @c2.new(:id => 1234).attributes_dataset.opts[:eager].must_equal(:attributes=>nil)
2145
- end
2146
-
2147
- it "should handle an aliased join table" do
2148
- @c2.many_to_many :attributes, :class => @c1, :join_table => :attribute2node___attributes_nodes
2149
- n = @c2.load(:id => 1234)
2150
- a = @c1.load(:id => 2345)
2151
- n.attributes_dataset.sql.must_equal "SELECT attributes.* FROM attributes INNER JOIN attribute2node AS attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)"
2152
- a.must_equal n.add_attribute(a)
2153
- a.must_equal n.remove_attribute(a)
2154
- n.remove_all_attributes
2155
- sqls = DB.sqls
2156
- ['INSERT INTO attribute2node (node_id, attribute_id) VALUES (1234, 2345)',
2157
- 'INSERT INTO attribute2node (attribute_id, node_id) VALUES (2345, 1234)'].must_include(sqls.shift)
2158
- ["DELETE FROM attribute2node WHERE ((node_id = 1234) AND (attribute_id = 2345))",
2159
- "DELETE FROM attribute2node WHERE ((attribute_id = 2345) AND (node_id = 1234))"].must_include(sqls.shift)
2160
- sqls.must_equal ["DELETE FROM attribute2node WHERE (node_id = 1234)"]
2161
- end
2162
-
2163
- it "should define an add_ method that works on existing records" do
2164
- @c2.many_to_many :attributes, :class => @c1
2165
-
2166
- n = @c2.load(:id => 1234)
2167
- a = @c1.load(:id => 2345)
2168
- n.add_attribute(a).must_equal a
2169
- sqls = DB.sqls
2170
- ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 2345)',
2171
- 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (2345, 1234)'].must_include(sqls.shift)
2172
- sqls.must_equal []
2173
- end
2174
-
2175
- it "should define an add_ method that works with a primary key" do
2176
- @c2.many_to_many :attributes, :class => @c1
2177
-
2178
- n = @c2.load(:id => 1234)
2179
- a = @c1.load(:id => 2345)
2180
- @c1.dataset._fetch = {:id=>2345}
2181
- n.add_attribute(2345).must_equal a
2182
- sqls = DB.sqls
2183
- ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 2345)',
2184
- 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (2345, 1234)'].must_include(sqls.pop)
2185
- sqls.must_equal ["SELECT * FROM attributes WHERE id = 2345"]
2186
- end
2187
-
2188
- it "should raise an error if the primary key passed to the add_ method does not match an existing record" do
2189
- @c2.many_to_many :attributes, :class => @c1
2190
-
2191
- n = @c2.load(:id => 1234)
2192
- @c1.dataset._fetch = []
2193
- proc{n.add_attribute(2345)}.must_raise(Sequel::NoMatchingRow)
2194
- DB.sqls.must_equal ["SELECT * FROM attributes WHERE id = 2345"]
2195
- end
2196
-
2197
- it "should allow passing a hash to the add_ method which creates a new record" do
2198
- @c2.many_to_many :attributes, :class => @c1
2199
-
2200
- n = @c2.load(:id => 1234)
2201
- @c1.dataset._fetch = @c1.instance_dataset._fetch = {:id=>1}
2202
- n.add_attribute(:id => 1).must_equal @c1.load(:id => 1)
2203
- sqls = DB.sqls
2204
- ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 1)',
2205
- 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (1, 1234)'
2206
- ].must_include(sqls.pop)
2207
- sqls.must_equal ['INSERT INTO attributes (id) VALUES (1)', "SELECT * FROM attributes WHERE (id = 1) LIMIT 1"]
2208
- end
2209
-
2210
- it "should define a remove_ method that works on existing records" do
2211
- @c2.many_to_many :attributes, :class => @c1
2212
-
2213
- n = @c2.new(:id => 1234)
2214
- a = @c1.new(:id => 2345)
2215
- n.remove_attribute(a).must_equal a
2216
- DB.sqls.must_equal ['DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 2345))']
2217
- end
2218
-
2219
- it "should raise an error in the add_ method if the passed associated object is not of the correct type" do
2220
- @c2.many_to_many :attributes, :class => @c1
2221
- proc{@c2.new(:id => 1234).add_attribute(@c2.new)}.must_raise(Sequel::Error)
2222
- end
2223
-
2224
- it "should accept a primary key for the remove_ method and remove an existing record" do
2225
- @c2.many_to_many :attributes, :class => @c1
2226
- n = @c2.new(:id => 1234)
2227
- @c1.dataset._fetch = {:id=>234}
2228
- n.remove_attribute(234).must_equal @c1.load(:id => 234)
2229
- DB.sqls.must_equal ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((attributes_nodes.node_id = 1234) AND (attributes.id = 234)) LIMIT 1",
2230
- "DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 234))"]
2231
- end
2232
-
2233
- it "should raise an error in the remove_ method if the passed associated object is not of the correct type" do
2234
- @c2.many_to_many :attributes, :class => @c1
2235
- proc{@c2.new(:id => 1234).remove_attribute(@c2.new)}.must_raise(Sequel::Error)
2236
- end
2237
-
2238
- it "should have the add_ method respect the :left_primary_key and :right_primary_key options" do
2239
- @c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
2240
-
2241
- n = @c2.load(:id => 1234).set(:xxx=>5)
2242
- a = @c1.load(:id => 2345).set(:yyy=>8)
2243
- n.add_attribute(a).must_equal a
2244
- sqls = DB.sqls
2245
- ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (5, 8)',
2246
- 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (8, 5)'
2247
- ].must_include(sqls.pop)
2248
- sqls.must_equal []
2249
- end
2250
-
2251
- it "should have add_ method not add the same object to the cached association array if the object is already in the array" do
2252
- @c2.many_to_many :attributes, :class => @c1
2253
-
2254
- n = @c2.load(:id => 1234).set(:xxx=>5)
2255
- a = @c1.load(:id => 2345).set(:yyy=>8)
2256
- n.associations[:attributes] = []
2257
- a.must_equal n.add_attribute(a)
2258
- a.must_equal n.add_attribute(a)
2259
- n.attributes.must_equal [a]
2260
- end
2261
-
2262
- it "should have the add_ method respect composite keys" do
2263
- @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :z]
2264
- n = @c2.load(:id => 1234, :x=>5)
2265
- a = @c1.load(:id => 2345, :z=>8)
2266
- a.must_equal n.add_attribute(a)
2267
- sqls = DB.sqls
2268
- m = /INSERT INTO attributes_nodes \((\w+), (\w+), (\w+), (\w+)\) VALUES \((\d+), (\d+), (\d+), (\d+)\)/.match(sqls.pop)
2269
- sqls.must_equal []
2270
- m.wont_equal nil
2271
- map = {'l1'=>1234, 'l2'=>5, 'r1'=>2345, 'r2'=>8}
2272
- %w[l1 l2 r1 r2].each do |x|
2273
- v = false
2274
- 4.times do |i| i += 1
2275
- if m[i] == x
2276
- m[i+4].must_equal map[x].to_s
2277
- v = true
2278
- end
2279
- end
2280
- v.must_equal true
2281
- end
2282
- end
2283
-
2284
- it "should have the add_ method respect composite keys" do
2285
- @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :z]
2286
- @c1.set_primary_key [:id, :z]
2287
- n = @c2.load(:id => 1234, :x=>5)
2288
- a = @c1.load(:id => 2345, :z=>8)
2289
- @c1.dataset._fetch = {:id => 2345, :z=>8}
2290
- n.add_attribute([2345, 8]).must_equal a
2291
- sqls = DB.sqls
2292
- sqls.shift.must_match(/SELECT \* FROM attributes WHERE \(\((id|z) = (8|2345)\) AND \((id|z) = (8|2345)\)\) LIMIT 1/)
2293
- sqls.pop.must_match(/INSERT INTO attributes_nodes \([lr][12], [lr][12], [lr][12], [lr][12]\) VALUES \((1234|5|2345|8), (1234|5|2345|8), (1234|5|2345|8), (1234|5|2345|8)\)/)
2294
- sqls.must_equal []
2295
- end
2296
-
2297
- it "should have the remove_ method respect the :left_primary_key and :right_primary_key options" do
2298
- @c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
2299
-
2300
- n = @c2.new(:id => 1234, :xxx=>5)
2301
- a = @c1.new(:id => 2345, :yyy=>8)
2302
- n.remove_attribute(a).must_equal a
2303
- DB.sqls.must_equal ['DELETE FROM attributes_nodes WHERE ((node_id = 5) AND (attribute_id = 8))']
2304
- end
2305
-
2306
- it "should have the remove_ method respect composite keys" do
2307
- @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :z]
2308
- n = @c2.load(:id => 1234, :x=>5)
2309
- a = @c1.load(:id => 2345, :z=>8)
2310
- a.must_equal n.remove_attribute(a)
2311
- DB.sqls.must_equal ["DELETE FROM attributes_nodes WHERE ((l1 = 1234) AND (l2 = 5) AND (r1 = 2345) AND (r2 = 8))"]
2312
- end
2313
-
2314
- it "should accept a array of composite primary key values for the remove_ method and remove an existing record" do
2315
- @c1.set_primary_key [:id, :y]
2316
- @c2.many_to_many :attributes, :class => @c1
2317
- n = @c2.new(:id => 1234)
2318
- @c1.dataset._fetch = {:id=>234, :y=>8}
2319
- @c1.load(:id => 234, :y=>8).must_equal n.remove_attribute([234, 8])
2320
- sqls = DB.sqls
2321
- ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((attributes_nodes.node_id = 1234) AND (attributes.id = 234) AND (attributes.y = 8)) LIMIT 1",
2322
- "SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((attributes_nodes.node_id = 1234) AND (attributes.y = 8) AND (attributes.id = 234)) LIMIT 1"].must_include(sqls.shift)
2323
- sqls.must_equal ["DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 234))"]
2324
- end
2325
-
2326
- it "should raise an error if the model object doesn't have a valid primary key" do
2327
- @c2.many_to_many :attributes, :class => @c1
2328
- a = @c2.new
2329
- n = @c1.load(:id=>123)
2330
- proc{a.attributes_dataset}.must_raise(Sequel::Error)
2331
- proc{a.add_attribute(n)}.must_raise(Sequel::Error)
2332
- proc{a.remove_attribute(n)}.must_raise(Sequel::Error)
2333
- proc{a.remove_all_attributes}.must_raise(Sequel::Error)
2334
- end
2335
-
2336
- it "should save the associated object first in add_ if passed a new model object" do
2337
- @c2.many_to_many :attributes, :class => @c1
2338
- n = @c1.new
2339
- a = @c2.load(:id=>123)
2340
- n.new?.must_equal true
2341
- @c1.dataset._fetch = {:id=>1}
2342
- a.add_attribute(n)
2343
- n.new?.must_equal false
2344
- end
2345
-
2346
- it "should raise a ValidationFailed in add_ if the associated object is new and invalid" do
2347
- @c2.many_to_many :attributes, :class => @c1
2348
- n = @c1.new
2349
- a = @c2.load(:id=>123)
2350
- def n.validate() errors.add(:id, 'foo') end
2351
- proc{a.add_attribute(n)}.must_raise(Sequel::ValidationFailed)
2352
- end
2353
-
2354
- it "should raise an Error in add_ if the associated object is new and invalid and raise_on_save_failure is false" do
2355
- @c2.many_to_many :attributes, :class => @c1
2356
- n = @c1.new
2357
- n.raise_on_save_failure = false
2358
- a = @c2.load(:id=>123)
2359
- def n.validate() errors.add(:id, 'foo') end
2360
- proc{a.add_attribute(n)}.must_raise(Sequel::Error)
2361
- end
2362
-
2363
- it "should not attempt to validate the associated object in add_ if the :validate=>false option is used" do
2364
- @c2.many_to_many :attributes, :class => @c1, :validate=>false
2365
- n = @c1.new
2366
- a = @c2.load(:id=>123)
2367
- def n.validate() errors.add(:id, 'foo') end
2368
- @c1.dataset._fetch = {:id=>1}
2369
- a.add_attribute(n)
2370
- n.new?.must_equal false
2371
- end
2372
-
2373
- it "should raise an error if trying to remove a model object that doesn't have a valid primary key" do
2374
- @c2.many_to_many :attributes, :class => @c1
2375
- n = @c1.new
2376
- a = @c2.load(:id=>123)
2377
- proc{a.remove_attribute(n)}.must_raise(Sequel::Error)
2378
- end
2379
-
2380
- it "should provide an array with all members of the association" do
2381
- @c2.many_to_many :attributes, :class => @c1
2382
-
2383
- @c2.new(:id => 1234).attributes.must_equal [@c1.load({})]
2384
- DB.sqls.must_equal ['SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)']
2385
- end
2386
-
2387
- it "should populate cache when accessed" do
2388
- @c2.many_to_many :attributes, :class => @c1
2389
-
2390
- n = @c2.new(:id => 1234)
2391
- n.associations.include?(:attributes).must_equal false
2392
- atts = n.attributes
2393
- atts.must_equal n.associations[:attributes]
2394
- end
2395
-
2396
- it "should use cache if available" do
2397
- @c2.many_to_many :attributes, :class => @c1
2398
-
2399
- n = @c2.new(:id => 1234)
2400
- n.associations[:attributes] = 42
2401
- n.attributes.must_equal 42
2402
- DB.sqls.must_equal []
2403
- end
2404
-
2405
- it "should not use cache if asked to reload" do
2406
- @c2.many_to_many :attributes, :class => @c1
2407
-
2408
- n = @c2.new(:id => 1234)
2409
- n.associations[:attributes] = 42
2410
- n.attributes(true).wont_equal 42
2411
- DB.sqls.must_equal ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)"]
2412
- end
2413
-
2414
- it "should add item to cache if it exists when calling add_" do
2415
- @c2.many_to_many :attributes, :class => @c1
2416
-
2417
- n = @c2.new(:id => 1234)
2418
- att = @c1.load(:id => 345)
2419
- a = []
2420
- n.associations[:attributes] = a
2421
- n.add_attribute(att)
2422
- a.must_equal [att]
2423
- end
2424
-
2425
- it "should add item to reciprocal's cache if it exists when calling add_" do
2426
- @c2.many_to_many :attributes, :class => @c1
2427
- @c1.many_to_many :nodes, :class => @c2
2428
-
2429
- n = @c2.new(:id => 1234)
2430
- att = @c1.load(:id => 345)
2431
- att.associations[:nodes] = []
2432
- n.add_attribute(att)
2433
- att.nodes.must_equal [n]
2434
- end
2435
-
2436
- it "should remove item from cache if it exists when calling remove_" do
2437
- @c2.many_to_many :attributes, :class => @c1
2438
-
2439
- n = @c2.new(:id => 1234)
2440
- att = @c1.load(:id => 345)
2441
- a = [att]
2442
- n.associations[:attributes] = a
2443
- n.remove_attribute(att)
2444
- a.must_equal []
2445
- end
2446
-
2447
- it "should remove item from reciprocal's if it exists when calling remove_" do
2448
- @c2.many_to_many :attributes, :class => @c1
2449
- @c1.many_to_many :nodes, :class => @c2
2450
-
2451
- n = @c2.new(:id => 1234)
2452
- att = @c1.new(:id => 345)
2453
- att.associations[:nodes] = [n]
2454
- n.remove_attribute(att)
2455
- att.nodes.must_equal []
2456
- end
2457
-
2458
- it "should not create the add_, remove_, or remove_all_ methods if :read_only option is used" do
2459
- @c2.many_to_many :attributes, :class => @c1, :read_only=>true
2460
- im = @c2.instance_methods.collect{|x| x.to_s}
2461
- im.must_include('attributes')
2462
- im.must_include('attributes_dataset')
2463
- im.wont_include('add_attribute')
2464
- im.wont_include('remove_attribute')
2465
- im.wont_include('remove_all_attributes')
2466
- end
2467
-
2468
- it "should not add associations methods directly to class" do
2469
- @c2.many_to_many :attributes, :class => @c1
2470
- im = @c2.instance_methods.collect{|x| x.to_s}
2471
- im.must_include('attributes')
2472
- im.must_include('attributes_dataset')
2473
- im.must_include('add_attribute')
2474
- im.must_include('remove_attribute')
2475
- im.must_include('remove_all_attributes')
2476
- im2 = @c2.instance_methods(false).collect{|x| x.to_s}
2477
- im2.wont_include('attributes')
2478
- im2.wont_include('attributes_dataset')
2479
- im2.wont_include('add_attribute')
2480
- im2.wont_include('remove_attribute')
2481
- im2.wont_include('remove_all_attributes')
2482
- end
2483
-
2484
- it "should have an remove_all_ method that removes all associations" do
2485
- @c2.many_to_many :attributes, :class => @c1
2486
- @c2.new(:id => 1234).remove_all_attributes
2487
- DB.sqls.must_equal ['DELETE FROM attributes_nodes WHERE (node_id = 1234)']
2488
- end
2489
-
2490
- it "should have the remove_all_ method respect the :left_primary_key option" do
2491
- @c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx
2492
- @c2.new(:id => 1234, :xxx=>5).remove_all_attributes
2493
- DB.sqls.must_equal ['DELETE FROM attributes_nodes WHERE (node_id = 5)']
2494
- end
2495
-
2496
- it "should have the remove_all_ method respect composite keys" do
2497
- @c2.many_to_many :attributes, :class => @c1, :left_primary_key=>[:id, :x], :left_key=>[:l1, :l2]
2498
- @c2.load(:id => 1234, :x=>5).remove_all_attributes
2499
- DB.sqls.must_equal ['DELETE FROM attributes_nodes WHERE ((l1 = 1234) AND (l2 = 5))']
2500
- end
2501
-
2502
- it "remove_all should set the cached instance variable to []" do
2503
- @c2.many_to_many :attributes, :class => @c1
2504
- node = @c2.new(:id => 1234)
2505
- node.remove_all_attributes
2506
- node.associations[:attributes].must_equal []
2507
- end
2508
-
2509
- it "remove_all should return the array of previously associated items if the cached instance variable exists" do
2510
- @c2.many_to_many :attributes, :class => @c1
2511
- attrib = @c1.load(:id=>3)
2512
- node = @c2.load(:id => 1234)
2513
- @c1.dataset._fetch = []
2514
- node.attributes.must_equal []
2515
- node.add_attribute(attrib)
2516
- node.associations[:attributes].must_equal [attrib]
2517
- node.remove_all_attributes.must_equal [attrib]
2518
- end
2519
-
2520
- it "remove_all should return nil if the cached instance variable does not exist" do
2521
- @c2.many_to_many :attributes, :class => @c1
2522
- @c2.new(:id => 1234).remove_all_attributes.must_equal nil
2523
- end
2524
-
2525
- it "remove_all should remove the current item from all reciprocal instance varaibles if it cached instance variable exists" do
2526
- @c2.many_to_many :attributes, :class => @c1
2527
- @c1.many_to_many :nodes, :class => @c2
2528
- @c1.dataset._fetch = []
2529
- @c2.dataset._fetch = []
2530
- attrib = @c1.load(:id=>3)
2531
- node = @c2.new(:id => 1234)
2532
- node.attributes.must_equal []
2533
- attrib.nodes.must_equal []
2534
- node.add_attribute(attrib)
2535
- attrib.associations[:nodes].must_equal [node]
2536
- node.remove_all_attributes
2537
- attrib.associations[:nodes].must_equal []
2538
- end
2539
-
2540
- it "add, remove, and remove_all methods should respect :join_table_block option" do
2541
- @c2.many_to_many :attributes, :class => @c1, :join_table_block=>proc{|ds| ds.filter(:x=>123)}
2542
- o = @c2.load(:id => 1234)
2543
- o.add_attribute(@c1.load(:id=>44))
2544
- o.remove_attribute(@c1.load(:id=>45))
2545
- o.remove_all_attributes
2546
- sqls = DB.sqls
2547
- sqls.shift =~ /INSERT INTO attributes_nodes \((node_id|attribute_id), (node_id|attribute_id)\) VALUES \((1234|44), (1234|44)\)/
2548
- sqls.must_equal ["DELETE FROM attributes_nodes WHERE ((x = 123) AND (node_id = 1234) AND (attribute_id = 45))",
2549
- "DELETE FROM attributes_nodes WHERE ((x = 123) AND (node_id = 1234))"]
2550
- end
2551
-
2552
- it "should call an _add_ method internally to add attributes" do
2553
- @c2.many_to_many :attributes, :class => @c1
2554
- @c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_add_attribute")
2555
- p = @c2.load(:id=>10)
2556
- c = @c1.load(:id=>123)
2557
- def p._add_attribute(x)
2558
- @x = x
2559
- end
2560
- p.add_attribute(c)
2561
- p.instance_variable_get(:@x).must_equal c
2562
- DB.sqls.must_equal []
2563
- end
2564
-
2565
- it "should support an :adder option for defining the _add_ method" do
2566
- @c2.many_to_many :attributes, :class => @c1, :adder=>proc{|x| @x = x}
2567
- p = @c2.load(:id=>10)
2568
- c = @c1.load(:id=>123)
2569
- p.add_attribute(c)
2570
- p.instance_variable_get(:@x).must_equal c
2571
- DB.sqls.must_equal []
2572
- end
2573
-
2574
- it "should allow additional arguments given to the add_ method and pass them onwards to the _add_ method" do
2575
- @c2.many_to_many :attributes, :class => @c1
2576
- p = @c2.load(:id=>10)
2577
- c = @c1.load(:id=>123)
2578
- def p._add_attribute(x,*y)
2579
- @x = x
2580
- @y = y
2581
- end
2582
- p.add_attribute(c,:foo,:bar=>:baz)
2583
- p.instance_variable_get(:@x).must_equal c
2584
- p.instance_variable_get(:@y).must_equal [:foo,{:bar=>:baz}]
2585
- end
2586
-
2587
- it "should call a _remove_ method internally to remove attributes" do
2588
- @c2.many_to_many :attributes, :class => @c1
2589
- @c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_remove_attribute")
2590
- p = @c2.load(:id=>10)
2591
- c = @c1.load(:id=>123)
2592
- def p._remove_attribute(x)
2593
- @x = x
2594
- end
2595
- p.remove_attribute(c)
2596
- p.instance_variable_get(:@x).must_equal c
2597
- DB.sqls.must_equal []
2598
- end
2599
-
2600
- it "should support a :remover option for defining the _remove_ method" do
2601
- @c2.many_to_many :attributes, :class => @c1, :remover=>proc{|x| @x = x}
2602
- p = @c2.load(:id=>10)
2603
- c = @c1.load(:id=>123)
2604
- p.remove_attribute(c)
2605
- p.instance_variable_get(:@x).must_equal c
2606
- DB.sqls.must_equal []
2607
- end
2608
-
2609
- it "should allow additional arguments given to the remove_ method and pass them onwards to the _remove_ method" do
2610
- @c2.many_to_many :attributes, :class => @c1
2611
- p = @c2.load(:id=>10)
2612
- c = @c1.load(:id=>123)
2613
- def p._remove_attribute(x,*y)
2614
- @x = x
2615
- @y = y
2616
- end
2617
- p.remove_attribute(c,:foo,:bar=>:baz)
2618
- p.instance_variable_get(:@x).must_equal c
2619
- p.instance_variable_get(:@y).must_equal [:foo,{:bar=>:baz}]
2620
- end
2621
-
2622
- it "should allow additional arguments given to the remove_all_ method and pass them onwards to the _remove_all_ method" do
2623
- @c2.many_to_many :attributes, :class => @c1
2624
- p = @c2.load(:id=>10)
2625
- def p._remove_all_attributes(*y)
2626
- @y = y
2627
- end
2628
- p.remove_all_attributes(:foo,:bar=>:baz)
2629
- p.instance_variable_get(:@y).must_equal [:foo,{:bar=>:baz}]
2630
- end
2631
-
2632
- it "should call a _remove_all_ method internally to remove attributes" do
2633
- @c2.many_to_many :attributes, :class => @c1
2634
- @c2.private_instance_methods.collect{|x| x.to_s}.sort.must_include("_remove_all_attributes")
2635
- p = @c2.load(:id=>10)
2636
- def p._remove_all_attributes
2637
- @x = :foo
2638
- end
2639
- p.remove_all_attributes
2640
- p.instance_variable_get(:@x).must_equal :foo
2641
- DB.sqls.must_equal []
2642
- end
2643
-
2644
- it "should support a :clearer option for defining the _remove_all_ method" do
2645
- @c2.many_to_many :attributes, :class => @c1, :clearer=>proc{@x = :foo}
2646
- p = @c2.load(:id=>10)
2647
- p.remove_all_attributes
2648
- p.instance_variable_get(:@x).must_equal :foo
2649
- DB.sqls.must_equal []
2650
- end
2651
-
2652
- it "should support (before|after)_(add|remove) callbacks" do
2653
- h = []
2654
- @c2.many_to_many :attributes, :class => @c1, :before_add=>[proc{|x,y| h << x.pk; h << -y.pk}, :blah], :after_add=>proc{h << 3}, :before_remove=>:blah, :after_remove=>[:blahr]
2655
- @c2.class_eval do
2656
- self::Foo = h
2657
- def _add_attribute(v)
2658
- model::Foo << 4
2659
- end
2660
- def _remove_attribute(v)
2661
- model::Foo << 5
2662
- end
2663
- def blah(x)
2664
- model::Foo << x.pk
2665
- end
2666
- def blahr(x)
2667
- model::Foo << 6
2668
- end
2669
- end
2670
- p = @c2.load(:id=>10)
2671
- c = @c1.load(:id=>123)
2672
- h.must_equal []
2673
- p.add_attribute(c)
2674
- h.must_equal [10, -123, 123, 4, 3]
2675
- p.remove_attribute(c)
2676
- h.must_equal [10, -123, 123, 4, 3, 123, 5, 6]
2677
- end
2678
-
2679
- it "should support after_load association callback" do
2680
- h = []
2681
- @c2.many_to_many :attributes, :class => @c1, :after_load=>[proc{|x,y| h << [x.pk, y.collect{|z|z.pk}]}, :al]
2682
- @c2.class_eval do
2683
- self::Foo = h
2684
- def al(v)
2685
- v.each{|x| model::Foo << x.pk}
2686
- end
2687
- end
2688
- @c1.dataset._fetch = [{:id=>20}, {:id=>30}]
2689
- p = @c2.load(:id=>10, :parent_id=>20)
2690
- attributes = p.attributes
2691
- h.must_equal [[10, [20, 30]], 20, 30]
2692
- attributes.collect{|a| a.pk}.must_equal [20, 30]
2693
- end
2694
-
2695
- it "should raise error and not call internal add or remove method if before callback returns false if raise_on_save_failure is true" do
2696
- p = @c2.load(:id=>10)
2697
- c = @c1.load(:id=>123)
2698
- @c2.many_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
2699
- def p.ba(c) false end
2700
- def p._add_attribute; raise; end
2701
- def p._remove_attribute; raise; end
2702
- p.associations[:attributes] = []
2703
- p.raise_on_save_failure = true
2704
- proc{p.add_attribute(c)}.must_raise(Sequel::HookFailed)
2705
- p.attributes.must_equal []
2706
- p.associations[:attributes] = [c]
2707
- def p.br(c) false end
2708
- proc{p.remove_attribute(c)}.must_raise(Sequel::HookFailed)
2709
- p.attributes.must_equal [c]
2710
- end
2711
-
2712
- it "should return nil and not call internal add or remove method if before callback returns false if raise_on_save_failure is false" do
2713
- p = @c2.load(:id=>10)
2714
- c = @c1.load(:id=>123)
2715
- p.raise_on_save_failure = false
2716
- @c2.many_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
2717
- def p.ba(c) false end
2718
- def p._add_attribute; raise; end
2719
- def p._remove_attribute; raise; end
2720
- p.associations[:attributes] = []
2721
- p.add_attribute(c).must_equal nil
2722
- p.attributes.must_equal []
2723
- p.associations[:attributes] = [c]
2724
- def p.br(c) false end
2725
- p.remove_attribute(c).must_equal nil
2726
- p.attributes.must_equal [c]
2727
- end
2728
-
2729
- it "should raise error and not call internal add or remove method if before callback calls cancel_action if raise_on_save_failure is true" do
2730
- p = @c2.load(:id=>10)
2731
- c = @c1.load(:id=>123)
2732
- @c2.many_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
2733
- def p.ba(o) cancel_action end
2734
- def p._add_attribute; raise; end
2735
- def p._remove_attribute; raise; end
2736
- p.associations[:attributes] = []
2737
- p.raise_on_save_failure = true
2738
- proc{p.add_attribute(c)}.must_raise(Sequel::HookFailed)
2739
- p.attributes.must_equal []
2740
- p.associations[:attributes] = [c]
2741
- def p.br(o) cancel_action end
2742
- proc{p.remove_attribute(c)}.must_raise(Sequel::HookFailed)
2743
- p.attributes.must_equal [c]
2744
- end
2745
-
2746
- it "should return nil and not call internal add or remove method if before callback calls cancel_action if raise_on_save_failure is false" do
2747
- p = @c2.load(:id=>10)
2748
- c = @c1.load(:id=>123)
2749
- p.raise_on_save_failure = false
2750
- @c2.many_to_many :attributes, :class => @c1, :before_add=>:ba, :before_remove=>:br
2751
- def p.ba(o) cancel_action end
2752
- def p._add_attribute; raise; end
2753
- def p._remove_attribute; raise; end
2754
- p.associations[:attributes] = []
2755
- p.add_attribute(c).must_equal nil
2756
- p.attributes.must_equal []
2757
- p.associations[:attributes] = [c]
2758
- def p.br(o) cancel_action end
2759
- p.remove_attribute(c).must_equal nil
2760
- p.attributes.must_equal [c]
2761
- end
2762
-
2763
- it "should support a :uniq option that removes duplicates from the association" do
2764
- @c2.many_to_many :attributes, :class => @c1, :uniq=>true
2765
- @c1.dataset._fetch = [{:id=>20}, {:id=>30}, {:id=>20}, {:id=>30}]
2766
- @c2.load(:id=>10, :parent_id=>20).attributes.must_equal [@c1.load(:id=>20), @c1.load(:id=>30)]
2767
- end
2768
-
2769
- it "should support a :distinct option that uses the DISTINCT clause" do
2770
- @c2.many_to_many :attributes, :class => @c1, :distinct=>true
2771
- @c2.load(:id=>10).attributes_dataset.sql.must_equal "SELECT DISTINCT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 10)"
2772
- end
2773
-
2774
- it "should not apply association options when removing all associated records" do
2775
- @c2.many_to_many :attributes, :class => @c1 do |ds|
2776
- ds.filter(:name=>'John')
2777
- end
2778
- @c2.load(:id=>1).remove_all_attributes
2779
- DB.sqls.must_equal ["DELETE FROM attributes_nodes WHERE (node_id = 1)"]
2780
- end
2781
-
2782
- it "should use assocation's dataset when grabbing a record to remove from the assocation by primary key" do
2783
- @c2.many_to_many :attributes, :class => @c1 do |ds|
2784
- ds.filter(:join_table_att=>3)
2785
- end
2786
- @c1.dataset._fetch = {:id=>2}
2787
- @c2.load(:id=>1).remove_attribute(2)
2788
- DB.sqls.must_equal ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((attributes_nodes.node_id = 1) AND (join_table_att = 3) AND (attributes.id = 2)) LIMIT 1",
2789
- "DELETE FROM attributes_nodes WHERE ((node_id = 1) AND (attribute_id = 2))"]
2790
- end
2791
- end
2792
-
2793
- describe Sequel::Model, "one_through_one" do
2794
- before do
2795
- @c1 = Class.new(Sequel::Model(:attributes)) do
2796
- unrestrict_primary_key
2797
- attr_accessor :yyy
2798
- def self.name; 'Attribute'; end
2799
- def self.to_s; 'Attribute'; end
2800
- columns :id, :y, :z
2801
- end
2802
-
2803
- @c2 = Class.new(Sequel::Model(:nodes)) do
2804
- unrestrict_primary_key
2805
- attr_accessor :xxx
2806
-
2807
- def self.name; 'Node'; end
2808
- def self.to_s; 'Node'; end
2809
- columns :id, :x
2810
- end
2811
- @dataset = @c2.dataset
2812
- @c1.dataset.autoid = 1
2813
-
2814
- [@c1, @c2].each{|c| c.dataset._fetch = {}}
2815
- DB.reset
2816
- end
2817
-
2818
- it "should use implicit key values and join table if omitted" do
2819
- @c2.one_through_one :attribute, :class => @c1
2820
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 1'
2821
- end
2822
-
2823
- it "should respect :eager_loader_predicate_key when lazily loading" do
2824
- @c2.one_through_one :attribute, :class => @c1, :eager_loading_predicate_key=>Sequel.subscript(:attributes_nodes__node_id, 0)
2825
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id[0] = 1234) LIMIT 1'
2826
- end
2827
-
2828
- it "should use explicit key values and join table if given" do
2829
- @c2.one_through_one :attribute, :class => @c1, :left_key => :nodeid, :right_key => :attributeid, :join_table => :attribute2node
2830
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attribute2node ON (attribute2node.attributeid = attributes.id) WHERE (attribute2node.nodeid = 1234) LIMIT 1'
2831
- end
2832
-
2833
- it "should support a conditions option" do
2834
- @c2.one_through_one :attribute, :class => @c1, :conditions => {:a=>32}
2835
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((a = 32) AND (attributes_nodes.node_id = 1234)) LIMIT 1'
2836
-
2837
- @c2.one_through_one :attribute, :class => @c1, :conditions => ['a = ?', 32]
2838
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((a = 32) AND (attributes_nodes.node_id = 1234)) LIMIT 1'
2839
- @c2.new(:id => 1234).attribute.must_equal @c1.load({})
2840
- end
2841
-
2842
- it "should support an order option" do
2843
- @c2.one_through_one :attribute, :class => @c1, :order => :blah
2844
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) ORDER BY blah LIMIT 1'
2845
- end
2846
-
2847
- it "should support an array for the order option" do
2848
- @c2.one_through_one :attribute, :class => @c1, :order => [:blah1, :blah2]
2849
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) ORDER BY blah1, blah2 LIMIT 1'
2850
- end
2851
-
2852
- it "should support :left_primary_key and :right_primary_key options" do
2853
- @c2.one_through_one :attribute, :class => @c1, :left_primary_key=>:xxx, :right_primary_key=>:yyy
2854
- @c2.new(:id => 1234, :xxx=>5).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.yyy) WHERE (attributes_nodes.node_id = 5) LIMIT 1'
2855
- end
2856
-
2857
- it "should support composite keys" do
2858
- @c2.one_through_one :attribute, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
2859
- @c2.load(:id => 1234, :x=>5).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.r1 = attributes.id) AND (attributes_nodes.r2 = attributes.y)) WHERE ((attributes_nodes.l1 = 1234) AND (attributes_nodes.l2 = 5)) LIMIT 1'
2860
- end
2861
-
2862
- it "should not issue query if not all keys have values" do
2863
- @c2.one_through_one :attribute, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
2864
- @c2.load(:id => 1234, :x=>nil).attribute.must_equal nil
2865
- DB.sqls.must_equal []
2866
- end
2867
-
2868
- it "should raise an Error unless same number of composite keys used" do
2869
- proc{@c2.one_through_one :attribute, :class => @c1, :left_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2870
- proc{@c2.one_through_one :attribute, :class => @c1, :left_primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2871
- proc{@c2.one_through_one :attribute, :class => @c1, :left_key=>[:node_id, :id], :left_primary_key=>:id}.must_raise(Sequel::Error)
2872
- proc{@c2.one_through_one :attribute, :class => @c1, :left_key=>:id, :left_primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2873
- proc{@c2.one_through_one :attribute, :class => @c1, :left_key=>[:node_id, :id, :x], :left_primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
2874
-
2875
- proc{@c2.one_through_one :attribute, :class => @c1, :right_primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2876
- proc{@c2.one_through_one :attribute, :class => @c1, :right_key=>[:node_id, :id], :right_primary_key=>:id}.must_raise(Sequel::Error)
2877
- proc{@c2.one_through_one :attribute, :class => @c1, :right_key=>:id, :left_primary_key=>[:node_id, :id]}.must_raise(Sequel::Error)
2878
- proc{@c2.one_through_one :attribute, :class => @c1, :right_key=>[:node_id, :id, :x], :right_primary_key=>[:parent_id, :id]}.must_raise(Sequel::Error)
2879
- end
2880
-
2881
- it "should support a select option" do
2882
- @c2.one_through_one :attribute, :class => @c1, :select => :blah
2883
-
2884
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT blah FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 1'
2885
- end
2886
-
2887
- it "should support an array for the select option" do
2888
- @c2.one_through_one :attribute, :class => @c1, :select => [Sequel::SQL::ColumnAll.new(:attributes), :attribute_nodes__blah2]
2889
-
2890
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.*, attribute_nodes.blah2 FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 1'
2891
- end
2892
-
2893
- it "should accept a block" do
2894
- @c2.one_through_one :attribute, :class => @c1 do |ds|
2895
- ds.filter(:xxx => @xxx)
2896
- end
2897
-
2898
- n = @c2.new(:id => 1234)
2899
- n.xxx = 555
2900
- n.attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((attributes_nodes.node_id = 1234) AND (xxx = 555)) LIMIT 1'
2901
- end
2902
-
2903
- it "should allow the :order option while accepting a block" do
2904
- @c2.one_through_one :attribute, :class => @c1, :order=>[:blah1, :blah2] do |ds|
2905
- ds.filter(:xxx => @xxx)
2906
- end
2907
-
2908
- n = @c2.new(:id => 1234)
2909
- n.xxx = 555
2910
- n.attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE ((attributes_nodes.node_id = 1234) AND (xxx = 555)) ORDER BY blah1, blah2 LIMIT 1'
2911
- end
2912
-
2913
- it "should support a :dataset option that is used instead of the default" do
2914
- c1 = @c1
2915
- @c2.one_through_one :attribute, :class => @c1, :dataset=>proc{c1.join_table(:natural, :an).filter(:an__nodeid=>pk)}, :order=> :a, :select=>nil do |ds|
2916
- ds.filter(:xxx => @xxx)
2917
- end
2918
-
2919
- n = @c2.new(:id => 1234)
2920
- n.xxx = 555
2921
- n.attribute_dataset.sql.must_equal 'SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 1'
2922
- n.attribute.must_equal @c1.load({})
2923
- DB.sqls.must_equal ['SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 1']
2924
- end
2925
-
2926
- it "should support a :dataset option that accepts the reflection as an argument" do
2927
- @c2.one_through_one :attribute, :class => @c1, :dataset=>lambda{|opts| opts.associated_class.natural_join(:an).filter(:an__nodeid=>pk)}, :order=> :a, :select=>nil do |ds|
2928
- ds.filter(:xxx => @xxx)
2929
- end
2930
-
2931
- n = @c2.new(:id => 1234)
2932
- n.xxx = 555
2933
- n.attribute_dataset.sql.must_equal 'SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 1'
2934
- n.attribute.must_equal @c1.load({})
2935
- DB.sqls.must_equal ['SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 1']
2936
- end
2937
-
2938
- it "should support a :limit option to specify an offset" do
2939
- @c2.one_through_one :attribute, :class => @c1 , :limit=>[nil, 10]
2940
- @c2.new(:id => 1234).attribute_dataset.sql.must_equal 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 1 OFFSET 10'
2941
- end
2942
-
2943
- it "should have the :eager option affect the _dataset method" do
2944
- @c2.one_through_one :attribute, :class => @c2 , :eager=>:attribute
2945
- @c2.new(:id => 1234).attribute_dataset.opts[:eager].must_equal(:attribute=>nil)
2946
- end
2947
-
2948
- it "should handle an aliased join table" do
2949
- @c2.one_through_one :attribute, :class => @c1, :join_table => :attribute2node___attributes_nodes
2950
- n = @c2.load(:id => 1234)
2951
- n.attribute_dataset.sql.must_equal "SELECT attributes.* FROM attributes INNER JOIN attribute2node AS attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 1"
2952
- end
2953
-
2954
- it "should raise an error if the model object doesn't have a valid primary key" do
2955
- @c2.one_through_one :attribute, :class => @c1
2956
- a = @c2.new
2957
- proc{a.attribute_dataset}.must_raise(Sequel::Error)
2958
- end
2959
-
2960
- it "should provide an array with all members of the association" do
2961
- @c2.one_through_one :attribute, :class => @c1
2962
-
2963
- @c2.new(:id => 1234).attribute.must_equal @c1.load({})
2964
- DB.sqls.must_equal ['SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 1']
2965
- end
2966
-
2967
- it "should populate cache when accessed" do
2968
- @c2.one_through_one :attribute, :class => @c1
2969
-
2970
- n = @c2.new(:id => 1234)
2971
- n.associations.include?(:attribute).must_equal false
2972
- atts = n.attribute
2973
- atts.must_equal n.associations[:attribute]
2974
- end
2975
-
2976
- it "should use cache if available" do
2977
- @c2.one_through_one :attribute, :class => @c1
2978
-
2979
- n = @c2.new(:id => 1234)
2980
- n.associations[:attribute] = 42
2981
- n.attribute.must_equal 42
2982
- DB.sqls.must_equal []
2983
- end
2984
-
2985
- it "should not use cache if asked to reload" do
2986
- @c2.one_through_one :attribute, :class => @c1
2987
-
2988
- n = @c2.new(:id => 1234)
2989
- n.associations[:attribute] = 42
2990
- n.attribute(true).wont_equal 42
2991
- DB.sqls.must_equal ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234) LIMIT 1"]
2992
- end
2993
-
2994
- it "should not add associations methods directly to class" do
2995
- @c2.one_through_one :attribute, :class => @c1
2996
- im = @c2.instance_methods.collect{|x| x.to_s}
2997
- im.must_include('attribute')
2998
- im.must_include('attribute_dataset')
2999
- im2 = @c2.instance_methods(false).collect{|x| x.to_s}
3000
- im2.wont_include('attribute')
3001
- im2.wont_include('attribute_dataset')
3002
- end
3003
-
3004
- it "should support after_load association callback" do
3005
- h = []
3006
- @c2.one_through_one :attribute, :class => @c1, :after_load=>[proc{|x,y| h << [x.pk, y.pk]}, :al]
3007
- @c2.class_eval do
3008
- self::Foo = h
3009
- def al(v)
3010
- model::Foo << v.pk
3011
- end
3012
- end
3013
- @c1.dataset._fetch = [{:id=>20}]
3014
- p = @c2.load(:id=>10, :parent_id=>20)
3015
- attribute = p.attribute
3016
- h.must_equal [[10, 20], 20]
3017
- attribute.pk.must_equal 20
3018
- end
3019
-
3020
- it "should support a :distinct option that uses the DISTINCT clause" do
3021
- @c2.one_through_one :attribute, :class => @c1, :distinct=>true
3022
- @c2.load(:id=>10).attribute_dataset.sql.must_equal "SELECT DISTINCT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 10) LIMIT 1"
3023
- end
3024
- end
3025
-
3026
- describe "Filtering by associations" do
3027
- before(:all) do
3028
- db = Sequel.mock
3029
- db.extend_datasets do
3030
- def supports_window_functions?; true; end
3031
- def supports_distinct_on?; true; end
3032
- end
3033
- @Album = Class.new(Sequel::Model(db[:albums]))
3034
- artist = @Artist = Class.new(Sequel::Model(db[:artists]))
3035
- tag = @Tag = Class.new(Sequel::Model(db[:tags]))
3036
- track = @Track = Class.new(Sequel::Model(db[:tracks]))
3037
- album_info = @AlbumInfo = Class.new(Sequel::Model(db[:album_infos]))
3038
- @Artist.columns :id, :id1, :id2
3039
- @Tag.columns :id, :tid1, :tid2
3040
- @Track.columns :id, :album_id, :album_id1, :album_id2
3041
- @AlbumInfo.columns :id, :album_id, :album_id1, :album_id2
3042
- @Album.class_eval do
3043
- columns :id, :id1, :id2, :artist_id, :artist_id1, :artist_id2
3044
- b = lambda{|ds| ds.where(:name=>'B')}
3045
- c = {:name=>'A'}
3046
-
3047
- many_to_one :artist, :class=>artist, :key=>:artist_id
3048
- one_to_many :tracks, :class=>track, :key=>:album_id
3049
- one_to_one :track, :class=>track, :key=>:album_id
3050
- one_to_one :album_info, :class=>album_info, :key=>:album_id
3051
- many_to_many :tags, :class=>tag, :left_key=>:album_id, :join_table=>:albums_tags, :right_key=>:tag_id
3052
-
3053
- many_to_one :a_artist, :clone=>:artist, :conditions=>c
3054
- one_to_many :a_tracks, :clone=>:tracks, :conditions=>c
3055
- one_to_one :a_album_info, :clone=>:album_info, :conditions=>c
3056
- many_to_many :a_tags, :clone=>:tags, :conditions=>c
3057
-
3058
- many_to_one :b_artist, :clone=>:artist, &b
3059
- one_to_many :b_tracks, :clone=>:tracks, &b
3060
- one_to_one :b_album_info, :clone=>:album_info, &b
3061
- many_to_many :b_tags, :clone=>:tags, &b
3062
-
3063
- one_to_many :l_tracks, :clone=>:tracks, :limit=>10
3064
- one_to_one :l_track, :clone=>:tracks, :order=>:name
3065
- many_to_many :l_tags, :clone=>:tags, :limit=>10
3066
- one_through_one :l_tag, :clone=>:tags, :order=>:name
3067
-
3068
- one_to_many :al_tracks, :clone=>:l_tracks, :conditions=>c
3069
- one_to_one :al_track, :clone=>:l_track, :conditions=>c
3070
- many_to_many :al_tags, :clone=>:l_tags, :conditions=>c
3071
- one_through_one :al_tag, :clone=>:l_tag, :conditions=>c
3072
-
3073
- many_to_one :cartist, :class=>artist, :key=>[:artist_id1, :artist_id2], :primary_key=>[:id1, :id2]
3074
- one_to_many :ctracks, :class=>track, :key=>[:album_id1, :album_id2], :primary_key=>[:id1, :id2]
3075
- one_to_one :calbum_info, :class=>album_info, :key=>[:album_id1, :album_id2], :primary_key=>[:id1, :id2]
3076
- many_to_many :ctags, :class=>tag, :left_key=>[:album_id1, :album_id2], :left_primary_key=>[:id1, :id2], :right_key=>[:tag_id1, :tag_id2], :right_primary_key=>[:tid1, :tid2], :join_table=>:albums_tags
3077
-
3078
- many_to_one :a_cartist, :clone=>:cartist, :conditions=>c
3079
- one_to_many :a_ctracks, :clone=>:ctracks, :conditions=>c
3080
- one_to_one :a_calbum_info, :clone=>:calbum_info, :conditions=>c
3081
- many_to_many :a_ctags, :clone=>:ctags, :conditions=>c
3082
-
3083
- many_to_one :b_cartist, :clone=>:cartist, &b
3084
- one_to_many :b_ctracks, :clone=>:ctracks, &b
3085
- one_to_one :b_calbum_info, :clone=>:calbum_info, &b
3086
- many_to_many :b_ctags, :clone=>:ctags, &b
3087
-
3088
- one_to_many :l_ctracks, :clone=>:ctracks, :limit=>10
3089
- one_to_one :l_ctrack, :clone=>:ctracks, :order=>:name
3090
- many_to_many :l_ctags, :clone=>:ctags, :limit=>10
3091
- one_through_one :l_ctag, :clone=>:ctags, :order=>:name
3092
-
3093
- one_to_many :al_ctracks, :clone=>:l_ctracks, :conditions=>c
3094
- one_to_one :al_ctrack, :clone=>:l_ctrack, :conditions=>c
3095
- many_to_many :al_ctags, :clone=>:l_ctags, :conditions=>c
3096
- one_through_one :al_ctag, :clone=>:l_ctag, :conditions=>c
3097
- end
3098
- end
3099
- after do
3100
- @Album.default_eager_limit_strategy = true
3101
- end
3102
-
3103
- it "should be able to filter on many_to_one associations" do
3104
- @Album.filter(:artist=>@Artist.load(:id=>3)).sql.must_equal 'SELECT * FROM albums WHERE (albums.artist_id = 3)'
3105
- end
3106
-
3107
- it "should be able to filter on one_to_many associations" do
3108
- @Album.filter(:tracks=>@Track.load(:album_id=>3)).sql.must_equal 'SELECT * FROM albums WHERE (albums.id = 3)'
3109
- end
3110
-
3111
- it "should be able to filter on one_to_one associations" do
3112
- @Album.filter(:album_info=>@AlbumInfo.load(:album_id=>3)).sql.must_equal 'SELECT * FROM albums WHERE (albums.id = 3)'
3113
- end
3114
-
3115
- it "should be able to filter on many_to_many associations" do
3116
- @Album.filter(:tags=>@Tag.load(:id=>3)).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM albums_tags WHERE ((albums_tags.tag_id = 3) AND (albums_tags.album_id IS NOT NULL))))'
3117
- end
3118
-
3119
- it "should be able to filter on many_to_one associations with :conditions" do
3120
- @Album.filter(:a_artist=>@Artist.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE ((name = 'A') AND (artists.id IS NOT NULL) AND (artists.id = 3))))"
3121
- end
3122
-
3123
- it "should be able to filter on one_to_many associations with :conditions" do
3124
- @Album.filter(:a_tracks=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'A') AND (tracks.album_id IS NOT NULL) AND (tracks.id = 5))))"
3125
- end
3126
-
3127
- it "should be able to filter on one_to_one associations with :conditions" do
3128
- @Album.filter(:a_album_info=>@AlbumInfo.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id = 5))))"
3129
- end
3130
-
3131
- it "should be able to filter on many_to_many associations with :conditions" do
3132
- @Album.filter(:a_tags=>@Tag.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'A') AND (albums_tags.album_id IS NOT NULL) AND (tags.id = 3))))"
3133
- end
3134
-
3135
- it "should be able to filter on many_to_one associations with block" do
3136
- @Album.filter(:b_artist=>@Artist.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE ((name = 'B') AND (artists.id IS NOT NULL) AND (artists.id = 3))))"
3137
- end
3138
-
3139
- it "should be able to filter on one_to_many associations with block" do
3140
- @Album.filter(:b_tracks=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'B') AND (tracks.album_id IS NOT NULL) AND (tracks.id = 5))))"
3141
- end
3142
-
3143
- it "should be able to filter on one_to_one associations with block" do
3144
- @Album.filter(:b_album_info=>@AlbumInfo.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id = 5))))"
3145
- end
3146
-
3147
- it "should be able to filter on many_to_many associations with block" do
3148
- @Album.filter(:b_tags=>@Tag.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'B') AND (albums_tags.album_id IS NOT NULL) AND (tags.id = 3))))"
3149
- end
3150
-
3151
- it "should be able to filter on one_to_many associations with :limit" do
3152
- @Album.filter(:l_tracks=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks) AS t1 WHERE (x_sequel_row_number_x <= 10))) AND (tracks.id = 5))))"
3153
- end
3154
-
3155
- it "should be able to filter on one_to_one associations with :order" do
3156
- @Album.filter(:l_track=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT DISTINCT ON (tracks.album_id) tracks.id FROM tracks ORDER BY tracks.album_id, name)) AND (tracks.id = 5))))"
3157
- end
3158
-
3159
- it "should be able to filter on one_to_one associations with :filter_limit_strategy" do
3160
- @Album.one_to_one :l_track2, :clone=>:track, :filter_limit_strategy=>:window_function
3161
- @Album.filter(:l_track2=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks) AS t1 WHERE (x_sequel_row_number_x = 1))) AND (tracks.id = 5))))"
3162
- end
3163
-
3164
- it "should be able to filter on one_to_one associations with :eager_limit_strategy" do
3165
- @Album.one_to_one :l_track2, :clone=>:track, :eager_limit_strategy=>:window_function
3166
- @Album.filter(:l_track2=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks) AS t1 WHERE (x_sequel_row_number_x = 1))) AND (tracks.id = 5))))"
3167
- end
3168
-
3169
- it "should be able to filter on one_to_one associations with :order and :filter_limit_strategy" do
3170
- @Album.one_to_one :l_track2, :clone=>:l_track, :filter_limit_strategy=>:window_function
3171
- @Album.filter(:l_track2=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks) AS t1 WHERE (x_sequel_row_number_x = 1))) AND (tracks.id = 5))))"
3172
- end
3173
-
3174
- it "should be able to filter on one_to_one associations with :order and :eager_limit_strategy" do
3175
- @Album.one_to_one :l_track2, :clone=>:l_track, :eager_limit_strategy=>:window_function
3176
- @Album.filter(:l_track2=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks) AS t1 WHERE (x_sequel_row_number_x = 1))) AND (tracks.id = 5))))"
3177
- end
3178
-
3179
- it "should be able to filter on one_to_one associations with :order and Model.default_eager_limit_strategy" do
3180
- @Album.default_eager_limit_strategy = :window_function
3181
- @Album.one_to_one :l_track2, :clone=>:l_track
3182
- @Album.filter(:l_track2=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks) AS t1 WHERE (x_sequel_row_number_x = 1))) AND (tracks.id = 5))))"
3183
- end
3184
-
3185
- it "should be able to filter on one_to_one associations with :order and :eager_limit_strategy=>:union" do
3186
- @Album.one_to_one :l_track2, :clone=>:l_track, :eager_limit_strategy=>:union
3187
- @Album.filter(:l_track2=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT DISTINCT ON (tracks.album_id) tracks.id FROM tracks ORDER BY tracks.album_id, name)) AND (tracks.id = 5))))"
3188
- end
3189
-
3190
- it "should be able to filter on one_to_one associations with :order and :eager_limit_strategy=>:ruby" do
3191
- @Album.one_to_one :l_track2, :clone=>:l_track, :eager_limit_strategy=>:ruby
3192
- @Album.filter(:l_track2=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT DISTINCT ON (tracks.album_id) tracks.id FROM tracks ORDER BY tracks.album_id, name)) AND (tracks.id = 5))))"
3193
- end
3194
-
3195
- it "should be able to filter on one_to_one associations with :filter_limit_strategy :correlated_subquery" do
3196
- @Album.one_to_one :l_track2, :clone=>:track, :filter_limit_strategy=>:correlated_subquery
3197
- @Album.filter(:l_track2=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT t1.id FROM tracks AS t1 WHERE (t1.album_id = tracks.album_id) LIMIT 1)) AND (tracks.id = 5))))"
3198
- end
3199
-
3200
- it "should be able to filter on many_to_many associations with :limit" do
3201
- @Album.filter(:l_tags=>@Tag.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((albums_tags.album_id IS NOT NULL) AND ((albums_tags.album_id, tags.id) IN (SELECT b, c FROM (SELECT albums_tags.album_id AS b, tags.id AS c, row_number() OVER (PARTITION BY albums_tags.album_id) AS x_sequel_row_number_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id)) AS t1 WHERE (x_sequel_row_number_x <= 10))) AND (tags.id = 3))))"
3202
- end
3203
-
3204
- it "should be able to filter on one_through_one associations with :order" do
3205
- @Album.filter(:l_tag=>@Tag.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((albums_tags.album_id IS NOT NULL) AND ((albums_tags.album_id, tags.id) IN (SELECT DISTINCT ON (albums_tags.album_id) albums_tags.album_id, tags.id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) ORDER BY albums_tags.album_id, name)) AND (tags.id = 3))))"
3206
- end
3207
-
3208
- it "should be able to filter on one_to_many associations with :limit and :conditions" do
3209
- @Album.filter(:al_tracks=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'A') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks WHERE (name = 'A')) AS t1 WHERE (x_sequel_row_number_x <= 10))) AND (tracks.id = 5))))"
3210
- end
3211
-
3212
- it "should be able to filter on one_to_one associations with :order and :conditions" do
3213
- @Album.filter(:al_track=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'A') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT DISTINCT ON (tracks.album_id) tracks.id FROM tracks WHERE (name = 'A') ORDER BY tracks.album_id, name)) AND (tracks.id = 5))))"
3214
- end
3215
-
3216
- it "should be able to filter on many_to_many associations with :limit and :conditions" do
3217
- @Album.filter(:al_tags=>@Tag.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'A') AND (albums_tags.album_id IS NOT NULL) AND ((albums_tags.album_id, tags.id) IN (SELECT b, c FROM (SELECT albums_tags.album_id AS b, tags.id AS c, row_number() OVER (PARTITION BY albums_tags.album_id) AS x_sequel_row_number_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE (name = 'A')) AS t1 WHERE (x_sequel_row_number_x <= 10))) AND (tags.id = 3))))"
3218
- end
3219
-
3220
- it "should be able to filter on one_through_one associations with :order and :conditions" do
3221
- @Album.filter(:al_tag=>@Tag.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'A') AND (albums_tags.album_id IS NOT NULL) AND ((albums_tags.album_id, tags.id) IN (SELECT DISTINCT ON (albums_tags.album_id) albums_tags.album_id, tags.id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE (name = 'A') ORDER BY albums_tags.album_id, name)) AND (tags.id = 3))))"
3222
- end
3223
-
3224
- it "should be able to filter on many_to_one associations with composite keys" do
3225
- @Album.filter(:cartist=>@Artist.load(:id1=>3, :id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id1 = 3) AND (albums.artist_id2 = 4))'
3226
- end
3227
-
3228
- it "should be able to filter on one_to_many associations with composite keys" do
3229
- @Album.filter(:ctracks=>@Track.load(:album_id1=>3, :album_id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1 = 3) AND (albums.id2 = 4))'
3230
- end
3231
-
3232
- it "should be able to filter on one_to_one associations with composite keys" do
3233
- @Album.filter(:calbum_info=>@AlbumInfo.load(:album_id1=>3, :album_id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1 = 3) AND (albums.id2 = 4))'
3234
- end
3235
-
3236
- it "should be able to filter on many_to_many associations with composite keys" do
3237
- @Album.filter(:ctags=>@Tag.load(:tid1=>3, :tid2=>4)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE ((albums_tags.tag_id1 = 3) AND (albums_tags.tag_id2 = 4) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL))))'
3238
- end
3239
-
3240
- it "should be able to filter on many_to_one associations with :conditions and composite keys" do
3241
- @Album.filter(:a_cartist=>@Artist.load(:id=>5, :id1=>3, :id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'A') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id = 5))))"
3242
- end
3243
-
3244
- it "should be able to filter on one_to_many associations with :conditions and composite keys" do
3245
- @Album.filter(:a_ctracks=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'A') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id = 5))))"
3246
- end
3247
-
3248
- it "should be able to filter on one_to_one associations with :conditions and composite keys" do
3249
- @Album.filter(:a_calbum_info=>@AlbumInfo.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id = 5))))"
3250
- end
3251
-
3252
- it "should be able to filter on many_to_many associations with block and composite keys" do
3253
- @Album.filter(:a_ctags=>@Tag.load(:id=>5, :tid1=>3, :tid2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'A') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id = 5))))"
3254
- end
3255
-
3256
- it "should be able to filter on many_to_one associations with block and composite keys" do
3257
- @Album.filter(:b_cartist=>@Artist.load(:id=>5, :id1=>3, :id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'B') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id = 5))))"
3258
- end
3259
-
3260
- it "should be able to filter on one_to_many associations with block and composite keys" do
3261
- @Album.filter(:b_ctracks=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'B') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id = 5))))"
3262
- end
3263
-
3264
- it "should be able to filter on one_to_one associations with block and composite keys" do
3265
- @Album.filter(:b_calbum_info=>@AlbumInfo.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id = 5))))"
3266
- end
3267
-
3268
- it "should be able to filter on many_to_many associations with block and composite keys" do
3269
- @Album.filter(:b_ctags=>@Tag.load(:id=>5, :tid1=>3, :tid2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'B') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id = 5))))"
3270
- end
3271
-
3272
- it "should be able to filter on one_to_many associations with :limit and composite keys" do
3273
- @Album.filter(:l_ctracks=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id1, tracks.album_id2) AS x_sequel_row_number_x FROM tracks) AS t1 WHERE (x_sequel_row_number_x <= 10))) AND (tracks.id = 5))))"
3274
- end
3275
-
3276
- it "should be able to filter on one_to_many associations with composite keys and :filter_limit_strategy :correlated_subquery" do
3277
- @Album.one_to_one :l_ctracks2, :clone=>:l_ctracks, :filter_limit_strategy=>:correlated_subquery
3278
- @Album.filter(:l_ctracks2=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT t1.id FROM tracks AS t1 WHERE ((t1.album_id1 = tracks.album_id1) AND (t1.album_id2 = tracks.album_id2)) LIMIT 1)) AND (tracks.id = 5))))"
3279
- end
3280
-
3281
- it "should be able to filter on one_to_one associations with :order and composite keys" do
3282
- @Album.filter(:l_ctrack=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT DISTINCT ON (tracks.album_id1, tracks.album_id2) tracks.id FROM tracks ORDER BY tracks.album_id1, tracks.album_id2, name)) AND (tracks.id = 5))))"
3283
- end
3284
-
3285
- it "should be able to filter on many_to_many associations with :limit and composite keys" do
3286
- @Album.filter(:l_ctags=>@Tag.load(:id=>5, :tid1=>3, :tid2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND ((albums_tags.album_id1, albums_tags.album_id2, tags.id) IN (SELECT b, c, d FROM (SELECT albums_tags.album_id1 AS b, albums_tags.album_id2 AS c, tags.id AS d, row_number() OVER (PARTITION BY albums_tags.album_id1, albums_tags.album_id2) AS x_sequel_row_number_x FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2))) AS t1 WHERE (x_sequel_row_number_x <= 10))) AND (tags.id = 5))))"
3287
- end
3288
-
3289
- it "should be able to filter on one_through_one associations with :order and composite keys" do
3290
- @Album.filter(:l_ctag=>@Tag.load(:id=>5, :tid1=>3, :tid2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND ((albums_tags.album_id1, albums_tags.album_id2, tags.id) IN (SELECT DISTINCT ON (albums_tags.album_id1, albums_tags.album_id2) albums_tags.album_id1, albums_tags.album_id2, tags.id FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) ORDER BY albums_tags.album_id1, albums_tags.album_id2, name)) AND (tags.id = 5))))"
3291
- end
3292
-
3293
- it "should be able to filter on one_to_many associations with :limit and :conditions and composite keys" do
3294
- @Album.filter(:al_ctracks=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'A') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT id FROM (SELECT tracks.id, row_number() OVER (PARTITION BY tracks.album_id1, tracks.album_id2) AS x_sequel_row_number_x FROM tracks WHERE (name = 'A')) AS t1 WHERE (x_sequel_row_number_x <= 10))) AND (tracks.id = 5))))"
3295
- end
3296
-
3297
- it "should be able to filter on one_to_one associations with :order and :conditions and composite keys" do
3298
- @Album.filter(:al_ctrack=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'A') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT DISTINCT ON (tracks.album_id1, tracks.album_id2) tracks.id FROM tracks WHERE (name = 'A') ORDER BY tracks.album_id1, tracks.album_id2, name)) AND (tracks.id = 5))))"
3299
- end
3300
-
3301
- it "should be able to filter on many_to_many associations with :limit and :conditions and composite keys" do
3302
- @Album.filter(:al_ctags=>@Tag.load(:id=>5, :tid1=>3, :tid2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'A') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND ((albums_tags.album_id1, albums_tags.album_id2, tags.id) IN (SELECT b, c, d FROM (SELECT albums_tags.album_id1 AS b, albums_tags.album_id2 AS c, tags.id AS d, row_number() OVER (PARTITION BY albums_tags.album_id1, albums_tags.album_id2) AS x_sequel_row_number_x FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE (name = 'A')) AS t1 WHERE (x_sequel_row_number_x <= 10))) AND (tags.id = 5))))"
3303
- end
3304
-
3305
- it "should be able to filter on one_through_one associations with :order and :conditions and composite keys" do
3306
- @Album.filter(:al_ctag=>@Tag.load(:id=>5, :tid1=>3, :tid2=>4)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'A') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND ((albums_tags.album_id1, albums_tags.album_id2, tags.id) IN (SELECT DISTINCT ON (albums_tags.album_id1, albums_tags.album_id2) albums_tags.album_id1, albums_tags.album_id2, tags.id FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE (name = 'A') ORDER BY albums_tags.album_id1, albums_tags.album_id2, name)) AND (tags.id = 5))))"
3307
- end
3308
-
3309
- it "should work inside a complex filter" do
3310
- artist = @Artist.load(:id=>3)
3311
- @Album.filter{foo & {:artist=>artist}}.sql.must_equal 'SELECT * FROM albums WHERE (foo AND (albums.artist_id = 3))'
3312
- track = @Track.load(:album_id=>4)
3313
- @Album.filter{foo & [[:artist, artist], [:tracks, track]]}.sql.must_equal 'SELECT * FROM albums WHERE (foo AND (albums.artist_id = 3) AND (albums.id = 4))'
3314
- end
3315
-
3316
- it "should raise for an invalid association name" do
3317
- proc{@Album.filter(:foo=>@Artist.load(:id=>3)).sql}.must_raise(Sequel::Error)
3318
- end
3319
-
3320
- it "should raise for an invalid association type" do
3321
- @Album.many_to_many :iatags, :clone=>:tags
3322
- @Album.association_reflection(:iatags)[:type] = :foo
3323
- proc{@Album.filter(:iatags=>@Tag.load(:id=>3)).sql}.must_raise(Sequel::Error)
3324
- end
3325
-
3326
- it "should raise for an invalid associated object class " do
3327
- proc{@Album.filter(:tags=>@Artist.load(:id=>3)).sql}.must_raise(Sequel::Error)
3328
- end
3329
-
3330
- it "should raise for an invalid associated object class when multiple objects are used" do
3331
- proc{@Album.filter(:tags=>[@Tag.load(:id=>3), @Artist.load(:id=>3)]).sql}.must_raise(Sequel::Error)
3332
- end
3333
-
3334
- it "should correctly handle case when a multiple value association is used" do
3335
- proc{@Album.filter(:tags=>[@Tag.load(:id=>3), @Artist.load(:id=>3)]).sql}.must_raise(Sequel::Error)
3336
- end
3337
-
3338
- it "should not affect non-association IN/NOT IN filtering with an empty array" do
3339
- @Album.filter(:tag_id=>[]).sql.must_equal 'SELECT * FROM albums WHERE (1 = 0)'
3340
- @Album.exclude(:tag_id=>[]).sql.must_equal 'SELECT * FROM albums WHERE (1 = 1)'
3341
- end
3342
-
3343
- it "should work correctly in subclasses" do
3344
- c = Class.new(@Album)
3345
- c.many_to_one :sartist, :class=>@Artist
3346
- c.filter(:sartist=>@Artist.load(:id=>3)).sql.must_equal 'SELECT * FROM albums WHERE (albums.sartist_id = 3)'
3347
- end
3348
-
3349
- it "should be able to exclude on many_to_one associations" do
3350
- @Album.exclude(:artist=>@Artist.load(:id=>3)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id != 3) OR (albums.artist_id IS NULL))'
3351
- end
3352
-
3353
- it "should be able to exclude on one_to_many associations" do
3354
- @Album.exclude(:tracks=>@Track.load(:album_id=>3)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id != 3) OR (albums.id IS NULL))'
3355
- end
3356
-
3357
- it "should be able to exclude on one_to_one associations" do
3358
- @Album.exclude(:album_info=>@AlbumInfo.load(:album_id=>3)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id != 3) OR (albums.id IS NULL))'
3359
- end
3360
-
3361
- it "should be able to exclude on many_to_many associations" do
3362
- @Album.exclude(:tags=>@Tag.load(:id=>3)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM albums_tags WHERE ((albums_tags.tag_id = 3) AND (albums_tags.album_id IS NOT NULL)))) OR (albums.id IS NULL))'
3363
- end
3364
-
3365
- it "should be able to exclude on many_to_one associations with :conditions" do
3366
- @Album.exclude(:a_artist=>@Artist.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id NOT IN (SELECT artists.id FROM artists WHERE ((name = 'A') AND (artists.id IS NOT NULL) AND (artists.id = 3)))) OR (albums.artist_id IS NULL))"
3367
- end
3368
-
3369
- it "should be able to exclude on one_to_many associations with :conditions" do
3370
- @Album.exclude(:a_tracks=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'A') AND (tracks.album_id IS NOT NULL) AND (tracks.id = 5)))) OR (albums.id IS NULL))"
3371
- end
3372
-
3373
- it "should be able to exclude on one_to_one associations with :conditions" do
3374
- @Album.exclude(:a_album_info=>@AlbumInfo.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id = 5)))) OR (albums.id IS NULL))"
3375
- end
3376
-
3377
- it "should be able to exclude on many_to_many associations with :conditions" do
3378
- @Album.exclude(:a_tags=>@Tag.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'A') AND (albums_tags.album_id IS NOT NULL) AND (tags.id = 3)))) OR (albums.id IS NULL))"
3379
- end
3380
-
3381
- it "should be able to exclude on many_to_one associations with block" do
3382
- @Album.exclude(:b_artist=>@Artist.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id NOT IN (SELECT artists.id FROM artists WHERE ((name = 'B') AND (artists.id IS NOT NULL) AND (artists.id = 3)))) OR (albums.artist_id IS NULL))"
3383
- end
3384
-
3385
- it "should be able to exclude on one_to_many associations with block" do
3386
- @Album.exclude(:b_tracks=>@Track.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'B') AND (tracks.album_id IS NOT NULL) AND (tracks.id = 5)))) OR (albums.id IS NULL))"
3387
- end
3388
-
3389
- it "should be able to exclude on one_to_one associations with block" do
3390
- @Album.exclude(:b_album_info=>@AlbumInfo.load(:id=>5, :album_id=>3)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id = 5)))) OR (albums.id IS NULL))"
3391
- end
3392
-
3393
- it "should be able to exclude on many_to_many associations with block" do
3394
- @Album.exclude(:b_tags=>@Tag.load(:id=>3)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'B') AND (albums_tags.album_id IS NOT NULL) AND (tags.id = 3)))) OR (albums.id IS NULL))"
3395
- end
3396
-
3397
- it "should be able to exclude on many_to_one associations with composite keys" do
3398
- @Album.exclude(:cartist=>@Artist.load(:id1=>3, :id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id1 != 3) OR (albums.artist_id2 != 4) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))'
3399
- end
3400
-
3401
- it "should be able to exclude on one_to_many associations with composite keys" do
3402
- @Album.exclude(:ctracks=>@Track.load(:album_id1=>3, :album_id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1 != 3) OR (albums.id2 != 4) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3403
- end
3404
-
3405
- it "should be able to exclude on one_to_one associations with composite keys" do
3406
- @Album.exclude(:calbum_info=>@AlbumInfo.load(:album_id1=>3, :album_id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1 != 3) OR (albums.id2 != 4) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3407
- end
3408
-
3409
- it "should be able to exclude on many_to_many associations with composite keys" do
3410
- @Album.exclude(:ctags=>@Tag.load(:tid1=>3, :tid2=>4)).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE ((albums_tags.tag_id1 = 3) AND (albums_tags.tag_id2 = 4) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3411
- end
3412
-
3413
- it "should be able to exclude on many_to_one associations with :conditions and composite keys" do
3414
- @Album.exclude(:a_cartist=>@Artist.load(:id=>5, :id1=>3, :id2=>4)).sql.must_equal "SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'A') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id = 5)))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))"
3415
- end
3416
-
3417
- it "should be able to exclude on one_to_many associations with :conditions and composite keys" do
3418
- @Album.exclude(:a_ctracks=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'A') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id = 5)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3419
- end
3420
-
3421
- it "should be able to exclude on one_to_one associations with :conditions and composite keys" do
3422
- @Album.exclude(:a_calbum_info=>@AlbumInfo.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id = 5)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3423
- end
3424
-
3425
- it "should be able to exclude on many_to_many associations with block and composite keys" do
3426
- @Album.exclude(:a_ctags=>@Tag.load(:id=>5, :tid1=>3, :tid2=>4)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'A') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id = 5)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3427
- end
3428
-
3429
- it "should be able to exclude on many_to_one associations with block and composite keys" do
3430
- @Album.exclude(:b_cartist=>@Artist.load(:id=>5, :id1=>3, :id2=>4)).sql.must_equal "SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'B') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id = 5)))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))"
3431
- end
3432
-
3433
- it "should be able to exclude on one_to_many associations with block and composite keys" do
3434
- @Album.exclude(:b_ctracks=>@Track.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'B') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id = 5)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3435
- end
3436
-
3437
- it "should be able to exclude on one_to_one associations with block and composite keys" do
3438
- @Album.exclude(:b_calbum_info=>@AlbumInfo.load(:id=>5, :album_id1=>3, :album_id2=>4)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id = 5)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3439
- end
3440
-
3441
- it "should be able to exclude on many_to_many associations with block and composite keys" do
3442
- @Album.exclude(:b_ctags=>@Tag.load(:id=>5, :tid1=>3, :tid2=>4)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'B') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id = 5)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3443
- end
3444
-
3445
- it "should be able to filter on multiple many_to_one associations" do
3446
- @Album.filter(:artist=>[@Artist.load(:id=>3), @Artist.load(:id=>4)]).sql.must_equal 'SELECT * FROM albums WHERE (albums.artist_id IN (3, 4))'
3447
- end
3448
-
3449
- it "should be able to filter on multiple one_to_many associations" do
3450
- @Album.filter(:tracks=>[@Track.load(:album_id=>3), @Track.load(:album_id=>4)]).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (3, 4))'
3451
- end
3452
-
3453
- it "should be able to filter on multiple one_to_one associations" do
3454
- @Album.filter(:album_info=>[@AlbumInfo.load(:album_id=>3), @AlbumInfo.load(:album_id=>4)]).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (3, 4))'
3455
- end
3456
-
3457
- it "should be able to filter on multiple many_to_many associations" do
3458
- @Album.filter(:tags=>[@Tag.load(:id=>3), @Tag.load(:id=>4)]).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM albums_tags WHERE ((albums_tags.tag_id IN (3, 4)) AND (albums_tags.album_id IS NOT NULL))))'
3459
- end
3460
-
3461
- it "should be able to filter on multiple many_to_one associations with :conditions" do
3462
- @Album.filter(:a_artist=>[@Artist.load(:id=>3), @Artist.load(:id=>4)]).sql.must_equal "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE ((name = 'A') AND (artists.id IS NOT NULL) AND (artists.id IN (3, 4)))))"
3463
- end
3464
-
3465
- it "should be able to filter on multiple one_to_many associations with :conditions" do
3466
- @Album.filter(:a_tracks=>[@Track.load(:id=>5, :album_id=>3), @Track.load(:id=>6, :album_id=>4)]).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'A') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (5, 6)))))"
3467
- end
3468
-
3469
- it "should be able to filter on multiple one_to_one associations with :conditions" do
3470
- @Album.filter(:a_album_info=>[@AlbumInfo.load(:id=>5, :album_id=>3), @AlbumInfo.load(:id=>6, :album_id=>4)]).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id IN (5, 6)))))"
3471
- end
3472
-
3473
- it "should be able to filter on multiple many_to_many associations with :conditions" do
3474
- @Album.filter(:a_tags=>[@Tag.load(:id=>3), @Tag.load(:id=>4)]).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'A') AND (albums_tags.album_id IS NOT NULL) AND (tags.id IN (3, 4)))))"
3475
- end
3476
-
3477
- it "should be able to filter on multiple many_to_one associations with block" do
3478
- @Album.filter(:b_artist=>[@Artist.load(:id=>3), @Artist.load(:id=>4)]).sql.must_equal "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE ((name = 'B') AND (artists.id IS NOT NULL) AND (artists.id IN (3, 4)))))"
3479
- end
3480
-
3481
- it "should be able to filter on multiple one_to_many associations with block" do
3482
- @Album.filter(:b_tracks=>[@Track.load(:id=>5, :album_id=>3), @Track.load(:id=>6, :album_id=>4)]).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'B') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (5, 6)))))"
3483
- end
3484
-
3485
- it "should be able to filter on multiple one_to_one associations with block" do
3486
- @Album.filter(:b_album_info=>[@AlbumInfo.load(:id=>5, :album_id=>3), @AlbumInfo.load(:id=>6, :album_id=>4)]).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id IN (5, 6)))))"
3487
- end
3488
-
3489
- it "should be able to filter on multiple many_to_many associations with block" do
3490
- @Album.filter(:b_tags=>[@Tag.load(:id=>3), @Tag.load(:id=>4)]).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'B') AND (albums_tags.album_id IS NOT NULL) AND (tags.id IN (3, 4)))))"
3491
- end
3492
-
3493
- it "should be able to filter on multiple many_to_one associations with composite keys" do
3494
- @Album.filter(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.load(:id1=>5, :id2=>6)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN ((3, 4), (5, 6)))'
3495
- end
3496
-
3497
- it "should be able to filter on multiple one_to_many associations with composite keys" do
3498
- @Album.filter(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.load(:album_id1=>5, :album_id2=>6)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN ((3, 4), (5, 6)))'
3499
- end
3500
-
3501
- it "should be able to filter on multiple one_to_one associations with composite keys" do
3502
- @Album.filter(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.load(:album_id1=>5, :album_id2=>6)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN ((3, 4), (5, 6)))'
3503
- end
3504
-
3505
- it "should be able to filter on multiple many_to_many associations with composite keys" do
3506
- @Album.filter(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.load(:tid1=>5, :tid2=>6)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE (((albums_tags.tag_id1, albums_tags.tag_id2) IN ((3, 4), (5, 6))) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL))))'
3507
- end
3508
-
3509
- it "should be able to filter on multiple many_to_one associations with :conditions and composite keys" do
3510
- @Album.filter(:a_cartist=>[@Artist.load(:id=>7, :id1=>3, :id2=>4), @Artist.load(:id=>8, :id1=>5, :id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'A') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id IN (7, 8)))))"
3511
- end
3512
-
3513
- it "should be able to filter on multiple one_to_many associations with :conditions and composite keys" do
3514
- @Album.filter(:a_ctracks=>[@Track.load(:id=>7, :album_id1=>3, :album_id2=>4), @Track.load(:id=>8, :album_id1=>5, :album_id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'A') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (7, 8)))))"
3515
- end
3516
-
3517
- it "should be able to filter on multiple one_to_one associations with :conditions and composite keys" do
3518
- @Album.filter(:a_calbum_info=>[@AlbumInfo.load(:id=>7, :album_id1=>3, :album_id2=>4), @AlbumInfo.load(:id=>8, :album_id1=>5, :album_id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id IN (7, 8)))))"
3519
- end
3520
-
3521
- it "should be able to filter on multiple many_to_many associations with block and composite keys" do
3522
- @Album.filter(:a_ctags=>[@Tag.load(:id=>7, :tid1=>3, :tid2=>4), @Tag.load(:id=>8, :tid1=>5, :tid2=>6)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'A') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id IN (7, 8)))))"
3523
- end
3524
-
3525
- it "should be able to filter on multiple many_to_one associations with block and composite keys" do
3526
- @Album.filter(:b_cartist=>[@Artist.load(:id=>7, :id1=>3, :id2=>4), @Artist.load(:id=>8, :id1=>5, :id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'B') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id IN (7, 8)))))"
3527
- end
3528
-
3529
- it "should be able to filter on multiple one_to_many associations with block and composite keys" do
3530
- @Album.filter(:b_ctracks=>[@Track.load(:id=>7, :album_id1=>3, :album_id2=>4), @Track.load(:id=>8, :album_id1=>5, :album_id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'B') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (7, 8)))))"
3531
- end
3532
-
3533
- it "should be able to filter on multiple one_to_one associations with block and composite keys" do
3534
- @Album.filter(:b_calbum_info=>[@AlbumInfo.load(:id=>7, :album_id1=>3, :album_id2=>4), @AlbumInfo.load(:id=>8, :album_id1=>5, :album_id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id IN (7, 8)))))"
3535
- end
3536
-
3537
- it "should be able to filter on multiple many_to_many associations with block and composite keys" do
3538
- @Album.filter(:b_ctags=>[@Tag.load(:id=>7, :tid1=>3, :tid2=>4), @Tag.load(:id=>8, :tid1=>5, :tid2=>6)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'B') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id IN (7, 8)))))"
3539
- end
3540
-
3541
- it "should be able to exclude on multiple many_to_one associations" do
3542
- @Album.exclude(:artist=>[@Artist.load(:id=>3), @Artist.load(:id=>4)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id NOT IN (3, 4)) OR (albums.artist_id IS NULL))'
3543
- end
3544
-
3545
- it "should be able to exclude on multiple one_to_many associations" do
3546
- @Album.exclude(:tracks=>[@Track.load(:album_id=>3), @Track.load(:album_id=>4)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (3, 4)) OR (albums.id IS NULL))'
3547
- end
3548
-
3549
- it "should be able to exclude on multiple one_to_one associations" do
3550
- @Album.exclude(:album_info=>[@AlbumInfo.load(:album_id=>3), @AlbumInfo.load(:album_id=>4)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (3, 4)) OR (albums.id IS NULL))'
3551
- end
3552
-
3553
- it "should be able to exclude on multiple many_to_many associations" do
3554
- @Album.exclude(:tags=>[@Tag.load(:id=>3), @Tag.load(:id=>4)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM albums_tags WHERE ((albums_tags.tag_id IN (3, 4)) AND (albums_tags.album_id IS NOT NULL)))) OR (albums.id IS NULL))'
3555
- end
3556
-
3557
- it "should be able to exclude on multiple many_to_one associations with :conditions" do
3558
- @Album.exclude(:a_artist=>[@Artist.load(:id=>3), @Artist.load(:id=>4)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id NOT IN (SELECT artists.id FROM artists WHERE ((name = 'A') AND (artists.id IS NOT NULL) AND (artists.id IN (3, 4))))) OR (albums.artist_id IS NULL))"
3559
- end
3560
-
3561
- it "should be able to exclude on multiple one_to_many associations with :conditions" do
3562
- @Album.exclude(:a_tracks=>[@Track.load(:id=>5, :album_id=>3), @Track.load(:id=>6, :album_id=>4)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'A') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (5, 6))))) OR (albums.id IS NULL))"
3563
- end
3564
-
3565
- it "should be able to exclude on multiple one_to_one associations with :conditions" do
3566
- @Album.exclude(:a_album_info=>[@AlbumInfo.load(:id=>5, :album_id=>3), @AlbumInfo.load(:id=>6, :album_id=>4)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id IN (5, 6))))) OR (albums.id IS NULL))"
3567
- end
3568
-
3569
- it "should be able to exclude on multiple many_to_many associations with :conditions" do
3570
- @Album.exclude(:a_tags=>[@Tag.load(:id=>3), @Tag.load(:id=>4)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'A') AND (albums_tags.album_id IS NOT NULL) AND (tags.id IN (3, 4))))) OR (albums.id IS NULL))"
3571
- end
3572
-
3573
- it "should be able to exclude on multiple many_to_one associations with block" do
3574
- @Album.exclude(:b_artist=>[@Artist.load(:id=>3), @Artist.load(:id=>4)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id NOT IN (SELECT artists.id FROM artists WHERE ((name = 'B') AND (artists.id IS NOT NULL) AND (artists.id IN (3, 4))))) OR (albums.artist_id IS NULL))"
3575
- end
3576
-
3577
- it "should be able to exclude on multiple one_to_many associations with block" do
3578
- @Album.exclude(:b_tracks=>[@Track.load(:id=>5, :album_id=>3), @Track.load(:id=>6, :album_id=>4)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'B') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (5, 6))))) OR (albums.id IS NULL))"
3579
- end
3580
-
3581
- it "should be able to exclude on multiple one_to_one associations with block" do
3582
- @Album.exclude(:b_album_info=>[@AlbumInfo.load(:id=>5, :album_id=>3), @AlbumInfo.load(:id=>6, :album_id=>4)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id IN (5, 6))))) OR (albums.id IS NULL))"
3583
- end
3584
-
3585
- it "should be able to exclude on multiple many_to_many associations with block" do
3586
- @Album.exclude(:b_tags=>[@Tag.load(:id=>3), @Tag.load(:id=>4)]).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'B') AND (albums_tags.album_id IS NOT NULL) AND (tags.id IN (3, 4))))) OR (albums.id IS NULL))"
3587
- end
3588
-
3589
- it "should be able to exclude on multiple many_to_one associations with composite keys" do
3590
- @Album.exclude(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.load(:id1=>5, :id2=>6)]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN ((3, 4), (5, 6))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))'
3591
- end
3592
-
3593
- it "should be able to exclude on multiple one_to_many associations with composite keys" do
3594
- @Album.exclude(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.load(:album_id1=>5, :album_id2=>6)]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN ((3, 4), (5, 6))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3595
- end
3596
-
3597
- it "should be able to exclude on multiple one_to_one associations with composite keys" do
3598
- @Album.exclude(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.load(:album_id1=>5, :album_id2=>6)]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN ((3, 4), (5, 6))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3599
- end
3600
-
3601
- it "should be able to exclude on multiple many_to_many associations with composite keys" do
3602
- @Album.exclude(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.load(:tid1=>5, :tid2=>6)]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE (((albums_tags.tag_id1, albums_tags.tag_id2) IN ((3, 4), (5, 6))) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3603
- end
3604
-
3605
- it "should be able to exclude on multiple many_to_one associations with :conditions and composite keys" do
3606
- @Album.exclude(:a_cartist=>[@Artist.load(:id=>7, :id1=>3, :id2=>4), @Artist.load(:id=>8, :id1=>5, :id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'A') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id IN (7, 8))))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))"
3607
- end
3608
-
3609
- it "should be able to exclude on multiple one_to_many associations with :conditions and composite keys" do
3610
- @Album.exclude(:a_ctracks=>[@Track.load(:id=>7, :album_id1=>3, :album_id2=>4), @Track.load(:id=>8, :album_id1=>5, :album_id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'A') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (7, 8))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3611
- end
3612
-
3613
- it "should be able to exclude on multiple one_to_one associations with :conditions and composite keys" do
3614
- @Album.exclude(:a_calbum_info=>[@AlbumInfo.load(:id=>7, :album_id1=>3, :album_id2=>4), @AlbumInfo.load(:id=>8, :album_id1=>5, :album_id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id IN (7, 8))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3615
- end
3616
-
3617
- it "should be able to exclude on multiple many_to_many associations with :conditions and composite keys" do
3618
- @Album.exclude(:a_ctags=>[@Tag.load(:id=>7, :tid1=>3, :tid2=>4), @Tag.load(:id=>8, :tid1=>5, :tid2=>6)]).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'A') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id IN (7, 8))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3619
- end
3620
-
3621
- it "should be able to exclude on multiple many_to_one associations with block and composite keys" do
3622
- @Album.exclude(:b_cartist=>[@Artist.load(:id=>7, :id1=>3, :id2=>4), @Artist.load(:id=>8, :id1=>5, :id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'B') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id IN (7, 8))))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))"
3623
- end
3624
-
3625
- it "should be able to exclude on multiple one_to_many associations with block and composite keys" do
3626
- @Album.exclude(:b_ctracks=>[@Track.load(:id=>7, :album_id1=>3, :album_id2=>4), @Track.load(:id=>8, :album_id1=>5, :album_id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'B') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (7, 8))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3627
- end
3628
-
3629
- it "should be able to exclude on multiple one_to_one associations with block and composite keys" do
3630
- @Album.exclude(:b_calbum_info=>[@AlbumInfo.load(:id=>7, :album_id1=>3, :album_id2=>4), @AlbumInfo.load(:id=>8, :album_id1=>5, :album_id2=>6)]).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id IN (7, 8))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3631
- end
3632
-
3633
- it "should be able to exclude on multiple many_to_many associations with block and composite keys" do
3634
- @Album.exclude(:b_ctags=>[@Tag.load(:id=>7, :tid1=>3, :tid2=>4), @Tag.load(:id=>8, :tid1=>5, :tid2=>6)]).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'B') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id IN (7, 8))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3635
- end
3636
-
3637
- it "should be able to handle NULL values when filtering many_to_one associations" do
3638
- @Album.filter(:artist=>@Artist.new).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3639
- end
3640
-
3641
- it "should be able to handle NULL values when filtering one_to_many associations" do
3642
- @Album.filter(:tracks=>@Track.new).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3643
- end
3644
-
3645
- it "should be able to handle NULL values when filtering one_to_one associations" do
3646
- @Album.filter(:album_info=>@AlbumInfo.new).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3647
- end
3648
-
3649
- it "should be able to handle NULL values when filtering many_to_many associations" do
3650
- @Album.filter(:tags=>@Tag.new).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3651
- end
3652
-
3653
- it "should be able to handle filtering with NULL values for many_to_one associations with composite keys" do
3654
- @Album.filter(:cartist=>@Artist.load(:id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3655
- @Album.filter(:cartist=>@Artist.load(:id1=>3)).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3656
- @Album.filter(:cartist=>@Artist.new).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3657
- end
3658
-
3659
- it "should be able to filter with NULL values for one_to_many associations with composite keys" do
3660
- @Album.filter(:ctracks=>@Track.load(:album_id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3661
- @Album.filter(:ctracks=>@Track.load(:album_id1=>3)).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3662
- @Album.filter(:ctracks=>@Track.new).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3663
- end
3664
-
3665
- it "should be able to filter with NULL values for one_to_one associations with composite keys" do
3666
- @Album.filter(:calbum_info=>@AlbumInfo.load(:album_id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3667
- @Album.filter(:calbum_info=>@AlbumInfo.load(:album_id1=>3)).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3668
- @Album.filter(:calbum_info=>@AlbumInfo.new).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3669
- end
3670
-
3671
- it "should be able to filter with NULL values for many_to_many associations with composite keys" do
3672
- @Album.filter(:ctags=>@Tag.load(:tid1=>3)).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3673
- @Album.filter(:ctags=>@Tag.load(:tid2=>4)).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3674
- @Album.filter(:ctags=>@Tag.new).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3675
- end
3676
-
3677
- it "should be able to handle NULL values when excluding many_to_one associations" do
3678
- @Album.exclude(:artist=>@Artist.new).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3679
- end
3680
-
3681
- it "should be able to handle NULL values when excluding one_to_many associations" do
3682
- @Album.exclude(:tracks=>@Track.new).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3683
- end
3684
-
3685
- it "should be able to handle NULL values when excluding one_to_one associations" do
3686
- @Album.exclude(:album_info=>@AlbumInfo.new).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3687
- end
3688
-
3689
- it "should be able to handle NULL values when excluding many_to_many associations" do
3690
- @Album.exclude(:tags=>@Tag.new).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3691
- end
3692
-
3693
- it "should be able to handle excluding with NULL values for many_to_one associations with composite keys" do
3694
- @Album.exclude(:cartist=>@Artist.load(:id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3695
- @Album.exclude(:cartist=>@Artist.load(:id1=>3)).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3696
- @Album.exclude(:cartist=>@Artist.new).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3697
- end
3698
-
3699
- it "should be able to excluding with NULL values for one_to_many associations with composite keys" do
3700
- @Album.exclude(:ctracks=>@Track.load(:album_id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3701
- @Album.exclude(:ctracks=>@Track.load(:album_id1=>3)).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3702
- @Album.exclude(:ctracks=>@Track.new).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3703
- end
3704
-
3705
- it "should be able to excluding with NULL values for one_to_one associations with composite keys" do
3706
- @Album.exclude(:calbum_info=>@AlbumInfo.load(:album_id2=>4)).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3707
- @Album.exclude(:calbum_info=>@AlbumInfo.load(:album_id1=>3)).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3708
- @Album.exclude(:calbum_info=>@AlbumInfo.new).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3709
- end
3710
-
3711
- it "should be able to excluding with NULL values for many_to_many associations with composite keys" do
3712
- @Album.exclude(:ctags=>@Tag.load(:tid1=>3)).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3713
- @Album.exclude(:ctags=>@Tag.load(:tid2=>4)).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3714
- @Album.exclude(:ctags=>@Tag.new).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3715
- end
3716
-
3717
- it "should be able to handle NULL values when filtering multiple many_to_one associations" do
3718
- @Album.filter(:artist=>[@Artist.load(:id=>3), @Artist.new]).sql.must_equal 'SELECT * FROM albums WHERE (albums.artist_id IN (3))'
3719
- @Album.filter(:artist=>[@Artist.new, @Artist.new]).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3720
- end
3721
-
3722
- it "should be able to handle NULL values when filtering multiple one_to_many associations" do
3723
- @Album.filter(:tracks=>[@Track.load(:album_id=>3), @Track.new]).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (3))'
3724
- @Album.filter(:tracks=>[@Track.new, @Track.new]).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3725
- end
3726
-
3727
- it "should be able to handle NULL values when filtering multiple one_to_one associations" do
3728
- @Album.filter(:album_info=>[@AlbumInfo.load(:album_id=>3), @AlbumInfo.new]).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (3))'
3729
- @Album.filter(:album_info=>[@AlbumInfo.new, @AlbumInfo.new]).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3730
- end
3731
-
3732
- it "should be able to handle NULL values when filtering multiple many_to_many associations" do
3733
- @Album.filter(:tags=>[@Tag.load(:id=>3), @Tag.new]).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM albums_tags WHERE ((albums_tags.tag_id IN (3)) AND (albums_tags.album_id IS NOT NULL))))'
3734
- @Album.filter(:tags=>[@Tag.new, @Tag.new]).sql.must_equal 'SELECT * FROM albums WHERE \'f\''
3735
- end
3736
-
3737
- it "should be able to handle NULL values when filtering multiple many_to_one associations with composite keys" do
3738
- @Album.filter(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.load(:id1=>3)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN ((3, 4)))'
3739
- @Album.filter(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.new]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN ((3, 4)))'
3740
- end
3741
-
3742
- it "should be able handle NULL values when filtering multiple one_to_many associations with composite keys" do
3743
- @Album.filter(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.load(:album_id1=>3)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN ((3, 4)))'
3744
- @Album.filter(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.new]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN ((3, 4)))'
3745
- end
3746
-
3747
- it "should be able to handle NULL values when filtering multiple one_to_one associations with composite keys" do
3748
- @Album.filter(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.load(:album_id1=>5)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN ((3, 4)))'
3749
- @Album.filter(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.new]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN ((3, 4)))'
3750
- end
3751
-
3752
- it "should be able to handle NULL values when filtering multiple many_to_many associations with composite keys" do
3753
- @Album.filter(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.load(:tid1=>5)]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE (((albums_tags.tag_id1, albums_tags.tag_id2) IN ((3, 4))) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL))))'
3754
- @Album.filter(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.new]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE (((albums_tags.tag_id1, albums_tags.tag_id2) IN ((3, 4))) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL))))'
3755
- end
3756
-
3757
- it "should be able to handle NULL values when excluding multiple many_to_one associations" do
3758
- @Album.exclude(:artist=>[@Artist.load(:id=>3), @Artist.new]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id NOT IN (3)) OR (albums.artist_id IS NULL))'
3759
- @Album.exclude(:artist=>[@Artist.new, @Artist.new]).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3760
- end
3761
-
3762
- it "should be able to handle NULL values when excluding multiple one_to_many associations" do
3763
- @Album.exclude(:tracks=>[@Track.load(:album_id=>3), @Track.new]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (3)) OR (albums.id IS NULL))'
3764
- @Album.exclude(:tracks=>[@Track.new, @Track.new]).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3765
- end
3766
-
3767
- it "should be able to handle NULL values when excluding multiple one_to_one associations" do
3768
- @Album.exclude(:album_info=>[@AlbumInfo.load(:album_id=>3), @AlbumInfo.new]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (3)) OR (albums.id IS NULL))'
3769
- @Album.exclude(:album_info=>[@AlbumInfo.new, @AlbumInfo.new]).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3770
- end
3771
-
3772
- it "should be able to handle NULL values when excluding multiple many_to_many associations" do
3773
- @Album.exclude(:tags=>[@Tag.load(:id=>3), @Tag.new]).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM albums_tags WHERE ((albums_tags.tag_id IN (3)) AND (albums_tags.album_id IS NOT NULL)))) OR (albums.id IS NULL))'
3774
- @Album.exclude(:tags=>[@Tag.new, @Tag.new]).sql.must_equal 'SELECT * FROM albums WHERE \'t\''
3775
- end
3776
-
3777
- it "should be able to handle NULL values when excluding multiple many_to_one associations with composite keys" do
3778
- @Album.exclude(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.load(:id1=>3)]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN ((3, 4))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))'
3779
- @Album.exclude(:cartist=>[@Artist.load(:id1=>3, :id2=>4), @Artist.new]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN ((3, 4))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))'
3780
- end
3781
-
3782
- it "should be able handle NULL values when excluding multiple one_to_many associations with composite keys" do
3783
- @Album.exclude(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.load(:album_id1=>3)]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN ((3, 4))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3784
- @Album.exclude(:ctracks=>[@Track.load(:album_id1=>3, :album_id2=>4), @Track.new]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN ((3, 4))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3785
- end
3786
-
3787
- it "should be able to handle NULL values when excluding multiple one_to_one associations with composite keys" do
3788
- @Album.exclude(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.load(:album_id1=>5)]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN ((3, 4))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3789
- @Album.exclude(:calbum_info=>[@AlbumInfo.load(:album_id1=>3, :album_id2=>4), @AlbumInfo.new]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN ((3, 4))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3790
- end
3791
-
3792
- it "should be able to handle NULL values when excluding multiple many_to_many associations with composite keys" do
3793
- @Album.exclude(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.load(:tid1=>5)]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE (((albums_tags.tag_id1, albums_tags.tag_id2) IN ((3, 4))) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3794
- @Album.exclude(:ctags=>[@Tag.load(:tid1=>3, :tid2=>4), @Tag.new]).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE (((albums_tags.tag_id1, albums_tags.tag_id2) IN ((3, 4))) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3795
- end
3796
-
3797
- it "should be able to filter on many_to_one association datasets" do
3798
- @Album.filter(:artist=>@Artist.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE ((x = 1) AND (artists.id IS NOT NULL))))'
3799
- end
3800
-
3801
- it "should be able to filter on one_to_many association datasets" do
3802
- @Album.filter(:tracks=>@Track.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((x = 1) AND (tracks.album_id IS NOT NULL))))'
3803
- end
3804
-
3805
- it "should be able to filter on one_to_one association datasets" do
3806
- @Album.filter(:album_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (SELECT album_infos.album_id FROM album_infos WHERE ((x = 1) AND (album_infos.album_id IS NOT NULL))))'
3807
- end
3808
-
3809
- it "should be able to filter on many_to_many association datasets" do
3810
- @Album.filter(:tags=>@Tag.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM albums_tags WHERE ((albums_tags.tag_id IN (SELECT tags.id FROM tags WHERE ((x = 1) AND (tags.id IS NOT NULL)))) AND (albums_tags.album_id IS NOT NULL))))'
3811
- end
3812
-
3813
- it "should be able to filter on many_to_one association datasets with :conditions" do
3814
- @Album.filter(:a_artist=>@Artist.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE ((name = 'A') AND (artists.id IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (x = 1))))))"
3815
- end
3816
-
3817
- it "should be able to filter on one_to_many association datasets with :conditions" do
3818
- @Album.filter(:a_tracks=>@Track.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'A') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT tracks.id FROM tracks WHERE (x = 1))))))"
3819
- end
3820
-
3821
- it "should be able to filter on one_to_one association datasets with :conditions" do
3822
- @Album.filter(:a_album_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id IN (SELECT album_infos.id FROM album_infos WHERE (x = 1))))))"
3823
- end
3824
-
3825
- it "should be able to filter on many_to_many association datasets with :conditions" do
3826
- @Album.filter(:a_tags=>@Tag.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'A') AND (albums_tags.album_id IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (x = 1))))))"
3827
- end
3828
-
3829
- it "should be able to filter on many_to_one association datasets with block" do
3830
- @Album.filter(:b_artist=>@Artist.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE ((name = 'B') AND (artists.id IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (x = 1))))))"
3831
- end
3832
-
3833
- it "should be able to filter on one_to_many association datasets with block" do
3834
- @Album.filter(:b_tracks=>@Track.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'B') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT tracks.id FROM tracks WHERE (x = 1))))))"
3835
- end
3836
-
3837
- it "should be able to filter on one_to_one association datasets with block" do
3838
- @Album.filter(:b_album_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id IN (SELECT album_infos.id FROM album_infos WHERE (x = 1))))))"
3839
- end
3840
-
3841
- it "should be able to filter on many_to_many association datasets with block" do
3842
- @Album.filter(:b_tags=>@Tag.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (albums.id IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'B') AND (albums_tags.album_id IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (x = 1))))))"
3843
- end
3844
-
3845
- it "should be able to filter on many_to_one association datasets with composite keys" do
3846
- @Album.filter(:cartist=>@Artist.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((x = 1) AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL))))'
3847
- end
3848
-
3849
- it "should be able to filter on one_to_many association datasets with composite keys" do
3850
- @Album.filter(:ctracks=>@Track.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((x = 1) AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL))))'
3851
- end
3852
-
3853
- it "should be able to filter on one_to_one association datasets with composite keys" do
3854
- @Album.filter(:calbum_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((x = 1) AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL))))'
3855
- end
3856
-
3857
- it "should be able to filter on many_to_many association datasets with composite keys" do
3858
- @Album.filter(:ctags=>@Tag.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE (((albums_tags.tag_id1, albums_tags.tag_id2) IN (SELECT tags.tid1, tags.tid2 FROM tags WHERE ((x = 1) AND (tags.tid1 IS NOT NULL) AND (tags.tid2 IS NOT NULL)))) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL))))'
3859
- end
3860
-
3861
- it "should be able to filter on many_to_one association datasets with :conditions and composite keys" do
3862
- @Album.filter(:a_cartist=>@Artist.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'A') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (x = 1))))))"
3863
- end
3864
-
3865
- it "should be able to filter on one_to_many association datasets with :conditions and composite keys" do
3866
- @Album.filter(:a_ctracks=>@Track.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'A') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT tracks.id FROM tracks WHERE (x = 1))))))"
3867
- end
3868
-
3869
- it "should be able to filter on one_to_one association datasets with :conditions and composite keys" do
3870
- @Album.filter(:a_calbum_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id IN (SELECT album_infos.id FROM album_infos WHERE (x = 1))))))"
3871
- end
3872
-
3873
- it "should be able to filter on many_to_many association datasets with :conditions and composite keys" do
3874
- @Album.filter(:a_ctags=>@Tag.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'A') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (x = 1))))))"
3875
- end
3876
-
3877
- it "should be able to filter on many_to_one association datasets with block and composite keys" do
3878
- @Album.filter(:b_cartist=>@Artist.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'B') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (x = 1))))))"
3879
- end
3880
-
3881
- it "should be able to filter on one_to_many association datasets with block and composite keys" do
3882
- @Album.filter(:b_ctracks=>@Track.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'B') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT tracks.id FROM tracks WHERE (x = 1))))))"
3883
- end
3884
-
3885
- it "should be able to filter on one_to_one association datasets with block and composite keys" do
3886
- @Album.filter(:b_calbum_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id IN (SELECT album_infos.id FROM album_infos WHERE (x = 1))))))"
3887
- end
3888
-
3889
- it "should be able to filter on many_to_many association datasets with block and composite keys" do
3890
- @Album.filter(:b_ctags=>@Tag.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id1, albums.id2) IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'B') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (x = 1))))))"
3891
- end
3892
-
3893
- it "should be able to exclude on many_to_one association datasets" do
3894
- @Album.exclude(:artist=>@Artist.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.artist_id NOT IN (SELECT artists.id FROM artists WHERE ((x = 1) AND (artists.id IS NOT NULL)))) OR (albums.artist_id IS NULL))'
3895
- end
3896
-
3897
- it "should be able to exclude on one_to_many association datasets" do
3898
- @Album.exclude(:tracks=>@Track.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT tracks.album_id FROM tracks WHERE ((x = 1) AND (tracks.album_id IS NOT NULL)))) OR (albums.id IS NULL))'
3899
- end
3900
-
3901
- it "should be able to exclude on one_to_one association datasets" do
3902
- @Album.exclude(:album_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT album_infos.album_id FROM album_infos WHERE ((x = 1) AND (album_infos.album_id IS NOT NULL)))) OR (albums.id IS NULL))'
3903
- end
3904
-
3905
- it "should be able to exclude on many_to_many association datasets" do
3906
- @Album.exclude(:tags=>@Tag.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM albums_tags WHERE ((albums_tags.tag_id IN (SELECT tags.id FROM tags WHERE ((x = 1) AND (tags.id IS NOT NULL)))) AND (albums_tags.album_id IS NOT NULL)))) OR (albums.id IS NULL))'
3907
- end
3908
-
3909
- it "should be able to exclude on many_to_one association datasets with :conditions" do
3910
- @Album.exclude(:a_artist=>@Artist.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id NOT IN (SELECT artists.id FROM artists WHERE ((name = 'A') AND (artists.id IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (x = 1)))))) OR (albums.artist_id IS NULL))"
3911
- end
3912
-
3913
- it "should be able to exclude on one_to_many association datasets with :conditions" do
3914
- @Album.exclude(:a_tracks=>@Track.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'A') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT tracks.id FROM tracks WHERE (x = 1)))))) OR (albums.id IS NULL))"
3915
- end
3916
-
3917
- it "should be able to exclude on one_to_one association datasets with :conditions" do
3918
- @Album.exclude(:a_album_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id IN (SELECT album_infos.id FROM album_infos WHERE (x = 1)))))) OR (albums.id IS NULL))"
3919
- end
3920
-
3921
- it "should be able to exclude on many_to_many association datasets with :conditions" do
3922
- @Album.exclude(:a_tags=>@Tag.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'A') AND (albums_tags.album_id IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (x = 1)))))) OR (albums.id IS NULL))"
3923
- end
3924
-
3925
- it "should be able to exclude on many_to_one association datasets with block" do
3926
- @Album.exclude(:b_artist=>@Artist.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.artist_id NOT IN (SELECT artists.id FROM artists WHERE ((name = 'B') AND (artists.id IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (x = 1)))))) OR (albums.artist_id IS NULL))"
3927
- end
3928
-
3929
- it "should be able to exclude on one_to_many association datasets with block" do
3930
- @Album.exclude(:b_tracks=>@Track.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT tracks.album_id FROM tracks WHERE ((name = 'B') AND (tracks.album_id IS NOT NULL) AND (tracks.id IN (SELECT tracks.id FROM tracks WHERE (x = 1)))))) OR (albums.id IS NULL))"
3931
- end
3932
-
3933
- it "should be able to exclude on one_to_one association datasets with block" do
3934
- @Album.exclude(:b_album_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT album_infos.album_id FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id IS NOT NULL) AND (album_infos.id IN (SELECT album_infos.id FROM album_infos WHERE (x = 1)))))) OR (albums.id IS NULL))"
3935
- end
3936
-
3937
- it "should be able to exclude on many_to_many association datasets with block" do
3938
- @Album.exclude(:b_tags=>@Tag.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE ((albums.id NOT IN (SELECT albums_tags.album_id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE ((name = 'B') AND (albums_tags.album_id IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (x = 1)))))) OR (albums.id IS NULL))"
3939
- end
3940
-
3941
- it "should be able to exclude on many_to_one association datasets with composite keys" do
3942
- @Album.exclude(:cartist=>@Artist.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((x = 1) AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL)))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))'
3943
- end
3944
-
3945
- it "should be able to exclude on one_to_many association datasets with composite keys" do
3946
- @Album.exclude(:ctracks=>@Track.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((x = 1) AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3947
- end
3948
-
3949
- it "should be able to exclude on one_to_one association datasets with composite keys" do
3950
- @Album.exclude(:calbum_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((x = 1) AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3951
- end
3952
-
3953
- it "should be able to exclude on many_to_many association datasets with composite keys" do
3954
- @Album.exclude(:ctags=>@Tag.filter(:x=>1)).sql.must_equal 'SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM albums_tags WHERE (((albums_tags.tag_id1, albums_tags.tag_id2) IN (SELECT tags.tid1, tags.tid2 FROM tags WHERE ((x = 1) AND (tags.tid1 IS NOT NULL) AND (tags.tid2 IS NOT NULL)))) AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL)))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))'
3955
- end
3956
-
3957
- it "should be able to exclude on many_to_one association datasets with :conditions and composite keys" do
3958
- @Album.exclude(:a_cartist=>@Artist.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'A') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (x = 1)))))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))"
3959
- end
3960
-
3961
- it "should be able to exclude on one_to_many association datasets with :conditions and composite keys" do
3962
- @Album.exclude(:a_ctracks=>@Track.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'A') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT tracks.id FROM tracks WHERE (x = 1)))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3963
- end
3964
-
3965
- it "should be able to exclude on one_to_one association datasets with :conditions and composite keys" do
3966
- @Album.exclude(:a_calbum_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'A') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id IN (SELECT album_infos.id FROM album_infos WHERE (x = 1)))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3967
- end
3968
-
3969
- it "should be able to exclude on many_to_many association datasets with :conditions and composite keys" do
3970
- @Album.exclude(:a_ctags=>@Tag.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'A') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (x = 1)))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3971
- end
3972
-
3973
- it "should be able to exclude on many_to_one association datasets with block and composite keys" do
3974
- @Album.exclude(:b_cartist=>@Artist.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (((albums.artist_id1, albums.artist_id2) NOT IN (SELECT artists.id1, artists.id2 FROM artists WHERE ((name = 'B') AND (artists.id1 IS NOT NULL) AND (artists.id2 IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (x = 1)))))) OR (albums.artist_id1 IS NULL) OR (albums.artist_id2 IS NULL))"
3975
- end
3976
-
3977
- it "should be able to exclude on one_to_many association datasets with block and composite keys" do
3978
- @Album.exclude(:b_ctracks=>@Track.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT tracks.album_id1, tracks.album_id2 FROM tracks WHERE ((name = 'B') AND (tracks.album_id1 IS NOT NULL) AND (tracks.album_id2 IS NOT NULL) AND (tracks.id IN (SELECT tracks.id FROM tracks WHERE (x = 1)))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3979
- end
3980
-
3981
- it "should be able to exclude on one_to_one association datasets with block and composite keys" do
3982
- @Album.exclude(:b_calbum_info=>@AlbumInfo.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT album_infos.album_id1, album_infos.album_id2 FROM album_infos WHERE ((name = 'B') AND (album_infos.album_id1 IS NOT NULL) AND (album_infos.album_id2 IS NOT NULL) AND (album_infos.id IN (SELECT album_infos.id FROM album_infos WHERE (x = 1)))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3983
- end
3984
-
3985
- it "should be able to exclude on many_to_many association datasets with block and composite keys" do
3986
- @Album.exclude(:b_ctags=>@Tag.filter(:x=>1)).sql.must_equal "SELECT * FROM albums WHERE (((albums.id1, albums.id2) NOT IN (SELECT albums_tags.album_id1, albums_tags.album_id2 FROM tags INNER JOIN albums_tags ON ((albums_tags.tag_id1 = tags.tid1) AND (albums_tags.tag_id2 = tags.tid2)) WHERE ((name = 'B') AND (albums_tags.album_id1 IS NOT NULL) AND (albums_tags.album_id2 IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (x = 1)))))) OR (albums.id1 IS NULL) OR (albums.id2 IS NULL))"
3987
- end
3988
-
3989
- it "should do a regular IN query if the dataset for a different model is used" do
3990
- @Album.filter(:artist=>@Album.select(:x)).sql.must_equal 'SELECT * FROM albums WHERE (artist IN (SELECT x FROM albums))'
3991
- end
3992
-
3993
- it "should do a regular IN query if a non-model dataset is used" do
3994
- @Album.filter(:artist=>@Album.db.from(:albums).select(:x)).sql.must_equal 'SELECT * FROM albums WHERE (artist IN (SELECT x FROM albums))'
3995
- end
3996
- end
3997
-
3998
- describe "Sequel::Model Associations with clashing column names" do
3999
- before do
4000
- @db = Sequel.mock(:fetch=>{:id=>1, :object_id=>2})
4001
- @Foo = Class.new(Sequel::Model(@db[:foos]))
4002
- @Bar = Class.new(Sequel::Model(@db[:bars]))
4003
- @Foo.columns :id, :object_id
4004
- @Bar.columns :id, :object_id
4005
- @Foo.def_column_alias(:obj_id, :object_id)
4006
- @Bar.def_column_alias(:obj_id, :object_id)
4007
- @Foo.one_to_many :bars, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :class=>@Bar
4008
- @Foo.one_to_one :bar, :primary_key=>:obj_id, :primary_key_column=>:object_id, :key=>:object_id, :key_method=>:obj_id, :class=>@Bar
4009
- @Bar.many_to_one :foo, :key=>:obj_id, :key_column=>:object_id, :primary_key=>:object_id, :primary_key_method=>:obj_id, :class=>@Foo
4010
- @Foo.many_to_many :mtmbars, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:foo_id, :right_key=>:object_id, :class=>@Bar
4011
- @Bar.many_to_many :mtmfoos, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>:object_id, :right_primary_key=>:object_id, :right_primary_key_method=>:obj_id, :left_key=>:object_id, :right_key=>:foo_id, :class=>@Foo
4012
- @foo = @Foo.load(:id=>1, :object_id=>2)
4013
- @bar = @Bar.load(:id=>1, :object_id=>2)
4014
- @db.sqls
4015
- end
4016
-
4017
- it "should have working regular association methods" do
4018
- @Bar.first.foo.must_equal @foo
4019
- @db.sqls.must_equal ["SELECT * FROM bars LIMIT 1", "SELECT * FROM foos WHERE (foos.object_id = 2) LIMIT 1"]
4020
- @Foo.first.bars.must_equal [@bar]
4021
- @db.sqls.must_equal ["SELECT * FROM foos LIMIT 1", "SELECT * FROM bars WHERE (bars.object_id = 2)"]
4022
- @Foo.first.bar.must_equal @bar
4023
- @db.sqls.must_equal ["SELECT * FROM foos LIMIT 1", "SELECT * FROM bars WHERE (bars.object_id = 2) LIMIT 1"]
4024
- @Foo.first.mtmbars.must_equal [@bar]
4025
- @db.sqls.must_equal ["SELECT * FROM foos LIMIT 1", "SELECT bars.* FROM bars INNER JOIN bars_foos ON (bars_foos.object_id = bars.object_id) WHERE (bars_foos.foo_id = 2)"]
4026
- @Bar.first.mtmfoos.must_equal [@foo]
4027
- @db.sqls.must_equal ["SELECT * FROM bars LIMIT 1", "SELECT foos.* FROM foos INNER JOIN bars_foos ON (bars_foos.foo_id = foos.object_id) WHERE (bars_foos.object_id = 2)"]
4028
- end
4029
-
4030
- it "should have working eager loading methods" do
4031
- @Bar.eager(:foo).all.map{|o| [o, o.foo]}.must_equal [[@bar, @foo]]
4032
- @db.sqls.must_equal ["SELECT * FROM bars", "SELECT * FROM foos WHERE (foos.object_id IN (2))"]
4033
- @Foo.eager(:bars).all.map{|o| [o, o.bars]}.must_equal [[@foo, [@bar]]]
4034
- @db.sqls.must_equal ["SELECT * FROM foos", "SELECT * FROM bars WHERE (bars.object_id IN (2))"]
4035
- @Foo.eager(:bar).all.map{|o| [o, o.bar]}.must_equal [[@foo, @bar]]
4036
- @db.sqls.must_equal ["SELECT * FROM foos", "SELECT * FROM bars WHERE (bars.object_id IN (2))"]
4037
- @db.fetch = [[{:id=>1, :object_id=>2}], [{:id=>1, :object_id=>2, :x_foreign_key_x=>2}]]
4038
- @Foo.eager(:mtmbars).all.map{|o| [o, o.mtmbars]}.must_equal [[@foo, [@bar]]]
4039
- @db.sqls.must_equal ["SELECT * FROM foos", "SELECT bars.*, bars_foos.foo_id AS x_foreign_key_x FROM bars INNER JOIN bars_foos ON (bars_foos.object_id = bars.object_id) WHERE (bars_foos.foo_id IN (2))"]
4040
- @db.fetch = [[{:id=>1, :object_id=>2}], [{:id=>1, :object_id=>2, :x_foreign_key_x=>2}]]
4041
- @Bar.eager(:mtmfoos).all.map{|o| [o, o.mtmfoos]}.must_equal [[@bar, [@foo]]]
4042
- @db.sqls.must_equal ["SELECT * FROM bars", "SELECT foos.*, bars_foos.object_id AS x_foreign_key_x FROM foos INNER JOIN bars_foos ON (bars_foos.foo_id = foos.object_id) WHERE (bars_foos.object_id IN (2))"]
4043
- end
4044
-
4045
- it "should have working eager graphing methods" do
4046
- @db.fetch = {:id=>1, :object_id=>2, :foo_id=>1, :foo_object_id=>2}
4047
- @Bar.eager_graph(:foo).all.map{|o| [o, o.foo]}.must_equal [[@bar, @foo]]
4048
- @db.sqls.must_equal ["SELECT bars.id, bars.object_id, foo.id AS foo_id, foo.object_id AS foo_object_id FROM bars LEFT OUTER JOIN foos AS foo ON (foo.object_id = bars.object_id)"]
4049
- @db.fetch = {:id=>1, :object_id=>2, :bars_id=>1, :bars_object_id=>2}
4050
- @Foo.eager_graph(:bars).all.map{|o| [o, o.bars]}.must_equal [[@foo, [@bar]]]
4051
- @db.sqls.must_equal ["SELECT foos.id, foos.object_id, bars.id AS bars_id, bars.object_id AS bars_object_id FROM foos LEFT OUTER JOIN bars ON (bars.object_id = foos.object_id)"]
4052
- @db.fetch = {:id=>1, :object_id=>2, :bar_id=>1, :bar_object_id=>2}
4053
- @Foo.eager_graph(:bar).all.map{|o| [o, o.bar]}.must_equal [[@foo, @bar]]
4054
- @db.sqls.must_equal ["SELECT foos.id, foos.object_id, bar.id AS bar_id, bar.object_id AS bar_object_id FROM foos LEFT OUTER JOIN bars AS bar ON (bar.object_id = foos.object_id)"]
4055
- @db.fetch = {:id=>1, :object_id=>2, :mtmfoos_id=>1, :mtmfoos_object_id=>2}
4056
- @Bar.eager_graph(:mtmfoos).all.map{|o| [o, o.mtmfoos]}.must_equal [[@bar, [@foo]]]
4057
- @db.sqls.must_equal ["SELECT bars.id, bars.object_id, mtmfoos.id AS mtmfoos_id, mtmfoos.object_id AS mtmfoos_object_id FROM bars LEFT OUTER JOIN bars_foos ON (bars_foos.object_id = bars.object_id) LEFT OUTER JOIN foos AS mtmfoos ON (mtmfoos.object_id = bars_foos.foo_id)"]
4058
- @db.fetch = {:id=>1, :object_id=>2, :mtmbars_id=>1, :mtmbars_object_id=>2}
4059
- @Foo.eager_graph(:mtmbars).all.map{|o| [o, o.mtmbars]}.must_equal [[@foo, [@bar]]]
4060
- @db.sqls.must_equal ["SELECT foos.id, foos.object_id, mtmbars.id AS mtmbars_id, mtmbars.object_id AS mtmbars_object_id FROM foos LEFT OUTER JOIN bars_foos ON (bars_foos.foo_id = foos.object_id) LEFT OUTER JOIN bars AS mtmbars ON (mtmbars.object_id = bars_foos.object_id)"]
4061
- end
4062
-
4063
- it "should have working filter by associations with model instances" do
4064
- @Bar.first(:foo=>@foo).must_equal @bar
4065
- @db.sqls.must_equal ["SELECT * FROM bars WHERE (bars.object_id = 2) LIMIT 1"]
4066
- @Foo.first(:bars=>@bar).must_equal @foo
4067
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_id = 2) LIMIT 1"]
4068
- @Foo.first(:bar=>@bar).must_equal @foo
4069
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_id = 2) LIMIT 1"]
4070
- @Foo.first(:mtmbars=>@bar).must_equal @foo
4071
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_id IN (SELECT bars_foos.foo_id FROM bars_foos WHERE ((bars_foos.object_id = 2) AND (bars_foos.foo_id IS NOT NULL)))) LIMIT 1"]
4072
- @Bar.first(:mtmfoos=>@foo).must_equal @bar
4073
- @db.sqls.must_equal ["SELECT * FROM bars WHERE (bars.object_id IN (SELECT bars_foos.object_id FROM bars_foos WHERE ((bars_foos.foo_id = 2) AND (bars_foos.object_id IS NOT NULL)))) LIMIT 1"]
4074
- end
4075
-
4076
- it "should have working filter by associations for associations with :conditions with model instances" do
4077
- @Bar.many_to_one :foo, :clone=>:foo, :conditions=>{:name=>'A'}
4078
- @Foo.one_to_many :bars, :clone=>:bars, :conditions=>{:name=>'A'}
4079
- @Foo.one_to_one :bar, :clone=>:bars
4080
- @Foo.many_to_many :mtmbars, :clone=>:mtmbars, :conditions=>{:name=>'A'}
4081
- @Bar.many_to_many :mtmfoos, :clone=>:mtmfoos, :conditions=>{:name=>'A'}
4082
-
4083
- @Bar.where(:foo=>@foo).sql.must_equal "SELECT * FROM bars WHERE (bars.object_id IN (SELECT foos.object_id FROM foos WHERE ((name = 'A') AND (foos.object_id IS NOT NULL) AND (foos.id = 1))))"
4084
- @Foo.where(:bars=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_id IN (SELECT bars.object_id FROM bars WHERE ((name = 'A') AND (bars.object_id IS NOT NULL) AND (bars.id = 1))))"
4085
- @Foo.where(:bar=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_id IN (SELECT bars.object_id FROM bars WHERE ((name = 'A') AND (bars.object_id IS NOT NULL) AND (bars.id = 1))))"
4086
- @Foo.where(:mtmbars=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_id IN (SELECT bars_foos.foo_id FROM bars INNER JOIN bars_foos ON (bars_foos.object_id = bars.object_id) WHERE ((name = 'A') AND (bars_foos.foo_id IS NOT NULL) AND (bars.id = 1))))"
4087
- @Bar.where(:mtmfoos=>@foo).sql.must_equal "SELECT * FROM bars WHERE (bars.object_id IN (SELECT bars_foos.object_id FROM foos INNER JOIN bars_foos ON (bars_foos.foo_id = foos.object_id) WHERE ((name = 'A') AND (bars_foos.object_id IS NOT NULL) AND (foos.id = 1))))"
4088
- end
4089
-
4090
- it "should have working filter by associations for associations with block with model instances" do
4091
- b = lambda{|ds| ds.where(:name=>'A')}
4092
- @Bar.many_to_one :foo, :clone=>:foo, &b
4093
- @Foo.one_to_many :bars, :clone=>:bars, &b
4094
- @Foo.one_to_one :bar, :clone=>:bars
4095
- @Foo.many_to_many :mtmbars, :clone=>:mtmbars, &b
4096
- @Bar.many_to_many :mtmfoos, :clone=>:mtmfoos, &b
4097
-
4098
- @Bar.where(:foo=>@foo).sql.must_equal "SELECT * FROM bars WHERE (bars.object_id IN (SELECT foos.object_id FROM foos WHERE ((name = 'A') AND (foos.object_id IS NOT NULL) AND (foos.id = 1))))"
4099
- @Foo.where(:bars=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_id IN (SELECT bars.object_id FROM bars WHERE ((name = 'A') AND (bars.object_id IS NOT NULL) AND (bars.id = 1))))"
4100
- @Foo.where(:bar=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_id IN (SELECT bars.object_id FROM bars WHERE ((name = 'A') AND (bars.object_id IS NOT NULL) AND (bars.id = 1))))"
4101
- @Foo.where(:mtmbars=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_id IN (SELECT bars_foos.foo_id FROM bars INNER JOIN bars_foos ON (bars_foos.object_id = bars.object_id) WHERE ((name = 'A') AND (bars_foos.foo_id IS NOT NULL) AND (bars.id = 1))))"
4102
- @Bar.where(:mtmfoos=>@foo).sql.must_equal "SELECT * FROM bars WHERE (bars.object_id IN (SELECT bars_foos.object_id FROM foos INNER JOIN bars_foos ON (bars_foos.foo_id = foos.object_id) WHERE ((name = 'A') AND (bars_foos.object_id IS NOT NULL) AND (foos.id = 1))))"
4103
- end
4104
-
4105
- it "should have working modification methods" do
4106
- b = @Bar.load(:id=>2, :object_id=>3)
4107
- f = @Foo.load(:id=>2, :object_id=>3)
4108
- @db.numrows = 1
4109
-
4110
- @bar.foo = f
4111
- @bar.obj_id.must_equal 3
4112
- @foo.bar = @bar
4113
- @bar.obj_id.must_equal 2
4114
-
4115
- @foo.add_bar(b)
4116
- @db.fetch = [[{:id=>1, :object_id=>2}, {:id=>2, :object_id=>2}], [{:id=>1, :object_id=>2}]]
4117
- @foo.bars.must_equal [@bar, b]
4118
- @foo.remove_bar(b)
4119
- @foo.bars.must_equal [@bar]
4120
- @foo.remove_all_bars
4121
- @foo.bars.must_equal []
4122
-
4123
- @db.fetch = [[{:id=>1, :object_id=>2}], [], [{:id=>2, :object_id=>2}]]
4124
- @bar = @Bar.load(:id=>1, :object_id=>2)
4125
- @foo.mtmbars.must_equal [@bar]
4126
- @foo.remove_all_mtmbars
4127
- @foo.mtmbars.must_equal []
4128
- @foo.add_mtmbar(b)
4129
- @foo.mtmbars.must_equal [b]
4130
- @foo.remove_mtmbar(b)
4131
- @foo.mtmbars.must_equal []
4132
-
4133
- @db.fetch = [[{:id=>2, :object_id=>3}], [], [{:id=>2, :object_id=>3}]]
4134
- @bar.add_mtmfoo(f)
4135
- @bar.mtmfoos.must_equal [f]
4136
- @bar.remove_all_mtmfoos
4137
- @bar.mtmfoos.must_equal []
4138
- @bar.add_mtmfoo(f)
4139
- @bar.mtmfoos.must_equal [f]
4140
- @bar.remove_mtmfoo(f)
4141
- @bar.mtmfoos.must_equal []
4142
- end
4143
- end
4144
-
4145
- describe "Sequel::Model Associations with non-column expression keys" do
4146
- before do
4147
- @db = Sequel.mock(:fetch=>{:id=>1, :object_ids=>[2]})
4148
- @Foo = Class.new(Sequel::Model(@db[:foos]))
4149
- @Bar = Class.new(Sequel::Model(@db[:bars]))
4150
- @Foo.columns :id, :object_ids
4151
- @Bar.columns :id, :object_ids
4152
- m = Module.new{def obj_id; object_ids[0]; end}
4153
- @Foo.include m
4154
- @Bar.include m
4155
-
4156
- @Foo.one_to_many :bars, :primary_key=>:obj_id, :primary_key_column=>Sequel.subscript(:object_ids, 0), :key=>Sequel.subscript(:object_ids, 0), :key_method=>:obj_id, :class=>@Bar
4157
- @Foo.one_to_one :bar, :primary_key=>:obj_id, :primary_key_column=>Sequel.subscript(:object_ids, 0), :key=>Sequel.subscript(:object_ids, 0), :key_method=>:obj_id, :class=>@Bar
4158
- @Bar.many_to_one :foo, :key=>:obj_id, :key_column=>Sequel.subscript(:object_ids, 0), :primary_key=>Sequel.subscript(:object_ids, 0), :primary_key_method=>:obj_id, :class=>@Foo
4159
- @Foo.many_to_many :mtmbars, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>Sequel.subscript(:object_ids, 0), :right_primary_key=>Sequel.subscript(:object_ids, 0), :right_primary_key_method=>:obj_id, :left_key=>Sequel.subscript(:foo_ids, 0), :right_key=>Sequel.subscript(:bar_ids, 0), :class=>@Bar
4160
- @Bar.many_to_many :mtmfoos, :join_table=>:bars_foos, :left_primary_key=>:obj_id, :left_primary_key_column=>Sequel.subscript(:object_ids, 0), :right_primary_key=>Sequel.subscript(:object_ids, 0), :right_primary_key_method=>:obj_id, :left_key=>Sequel.subscript(:bar_ids, 0), :right_key=>Sequel.subscript(:foo_ids, 0), :class=>@Foo, :reciprocal=>nil
4161
- @foo = @Foo.load(:id=>1, :object_ids=>[2])
4162
- @bar = @Bar.load(:id=>1, :object_ids=>[2])
4163
- @db.sqls
4164
- end
4165
-
4166
- it "should have working regular association methods" do
4167
- @Bar.first.foo.must_equal @foo
4168
- @db.sqls.must_equal ["SELECT * FROM bars LIMIT 1", "SELECT * FROM foos WHERE (foos.object_ids[0] = 2) LIMIT 1"]
4169
- @Foo.first.bars.must_equal [@bar]
4170
- @db.sqls.must_equal ["SELECT * FROM foos LIMIT 1", "SELECT * FROM bars WHERE (bars.object_ids[0] = 2)"]
4171
- @Foo.first.bar.must_equal @bar
4172
- @db.sqls.must_equal ["SELECT * FROM foos LIMIT 1", "SELECT * FROM bars WHERE (bars.object_ids[0] = 2) LIMIT 1"]
4173
- @Foo.first.mtmbars.must_equal [@bar]
4174
- @db.sqls.must_equal ["SELECT * FROM foos LIMIT 1", "SELECT bars.* FROM bars INNER JOIN bars_foos ON (bars_foos.bar_ids[0] = bars.object_ids[0]) WHERE (bars_foos.foo_ids[0] = 2)"]
4175
- @Bar.first.mtmfoos.must_equal [@foo]
4176
- @db.sqls.must_equal ["SELECT * FROM bars LIMIT 1", "SELECT foos.* FROM foos INNER JOIN bars_foos ON (bars_foos.foo_ids[0] = foos.object_ids[0]) WHERE (bars_foos.bar_ids[0] = 2)"]
4177
- end
4178
-
4179
- it "should have working eager loading methods" do
4180
- @Bar.eager(:foo).all.map{|o| [o, o.foo]}.must_equal [[@bar, @foo]]
4181
- @db.sqls.must_equal ["SELECT * FROM bars", "SELECT * FROM foos WHERE (foos.object_ids[0] IN (2))"]
4182
- @Foo.eager(:bars).all.map{|o| [o, o.bars]}.must_equal [[@foo, [@bar]]]
4183
- @db.sqls.must_equal ["SELECT * FROM foos", "SELECT * FROM bars WHERE (bars.object_ids[0] IN (2))"]
4184
- @Foo.eager(:bar).all.map{|o| [o, o.bar]}.must_equal [[@foo, @bar]]
4185
- @db.sqls.must_equal ["SELECT * FROM foos", "SELECT * FROM bars WHERE (bars.object_ids[0] IN (2))"]
4186
- @db.fetch = [[{:id=>1, :object_ids=>[2]}], [{:id=>1, :object_ids=>[2], :x_foreign_key_x=>2}]]
4187
- @Foo.eager(:mtmbars).all.map{|o| [o, o.mtmbars]}.must_equal [[@foo, [@bar]]]
4188
- @db.sqls.must_equal ["SELECT * FROM foos", "SELECT bars.*, bars_foos.foo_ids[0] AS x_foreign_key_x FROM bars INNER JOIN bars_foos ON (bars_foos.bar_ids[0] = bars.object_ids[0]) WHERE (bars_foos.foo_ids[0] IN (2))"]
4189
- @db.fetch = [[{:id=>1, :object_ids=>[2]}], [{:id=>1, :object_ids=>[2], :x_foreign_key_x=>2}]]
4190
- @Bar.eager(:mtmfoos).all.map{|o| [o, o.mtmfoos]}.must_equal [[@bar, [@foo]]]
4191
- @db.sqls.must_equal ["SELECT * FROM bars", "SELECT foos.*, bars_foos.bar_ids[0] AS x_foreign_key_x FROM foos INNER JOIN bars_foos ON (bars_foos.foo_ids[0] = foos.object_ids[0]) WHERE (bars_foos.bar_ids[0] IN (2))"]
4192
- end
4193
-
4194
- it "should have working eager graphing methods" do
4195
- @db.fetch = {:id=>1, :object_ids=>[2], :foo_id=>1, :foo_object_ids=>[2]}
4196
- @Bar.eager_graph(:foo).all.map{|o| [o, o.foo]}.must_equal [[@bar, @foo]]
4197
- @db.sqls.must_equal ["SELECT bars.id, bars.object_ids, foo.id AS foo_id, foo.object_ids AS foo_object_ids FROM bars LEFT OUTER JOIN foos AS foo ON (foo.object_ids[0] = bars.object_ids[0])"]
4198
- @db.fetch = {:id=>1, :object_ids=>[2], :bars_id=>1, :bars_object_ids=>[2]}
4199
- @Foo.eager_graph(:bars).all.map{|o| [o, o.bars]}.must_equal [[@foo, [@bar]]]
4200
- @db.sqls.must_equal ["SELECT foos.id, foos.object_ids, bars.id AS bars_id, bars.object_ids AS bars_object_ids FROM foos LEFT OUTER JOIN bars ON (bars.object_ids[0] = foos.object_ids[0])"]
4201
- @db.fetch = {:id=>1, :object_ids=>[2], :bar_id=>1, :bar_object_ids=>[2]}
4202
- @Foo.eager_graph(:bar).all.map{|o| [o, o.bar]}.must_equal [[@foo, @bar]]
4203
- @db.sqls.must_equal ["SELECT foos.id, foos.object_ids, bar.id AS bar_id, bar.object_ids AS bar_object_ids FROM foos LEFT OUTER JOIN bars AS bar ON (bar.object_ids[0] = foos.object_ids[0])"]
4204
- @db.fetch = {:id=>1, :object_ids=>[2], :mtmfoos_id=>1, :mtmfoos_object_ids=>[2]}
4205
- @Bar.eager_graph(:mtmfoos).all.map{|o| [o, o.mtmfoos]}.must_equal [[@bar, [@foo]]]
4206
- @db.sqls.must_equal ["SELECT bars.id, bars.object_ids, mtmfoos.id AS mtmfoos_id, mtmfoos.object_ids AS mtmfoos_object_ids FROM bars LEFT OUTER JOIN bars_foos ON (bars_foos.bar_ids[0] = bars.object_ids[0]) LEFT OUTER JOIN foos AS mtmfoos ON (mtmfoos.object_ids[0] = bars_foos.foo_ids[0])"]
4207
- @db.fetch = {:id=>1, :object_ids=>[2], :mtmbars_id=>1, :mtmbars_object_ids=>[2]}
4208
- @Foo.eager_graph(:mtmbars).all.map{|o| [o, o.mtmbars]}.must_equal [[@foo, [@bar]]]
4209
- @db.sqls.must_equal ["SELECT foos.id, foos.object_ids, mtmbars.id AS mtmbars_id, mtmbars.object_ids AS mtmbars_object_ids FROM foos LEFT OUTER JOIN bars_foos ON (bars_foos.foo_ids[0] = foos.object_ids[0]) LEFT OUTER JOIN bars AS mtmbars ON (mtmbars.object_ids[0] = bars_foos.bar_ids[0])"]
4210
- end
4211
-
4212
- it "should have working filter by associations with model instances" do
4213
- @Bar.first(:foo=>@foo).must_equal @bar
4214
- @db.sqls.must_equal ["SELECT * FROM bars WHERE (bars.object_ids[0] = 2) LIMIT 1"]
4215
- @Foo.first(:bars=>@bar).must_equal @foo
4216
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_ids[0] = 2) LIMIT 1"]
4217
- @Foo.first(:bar=>@bar).must_equal @foo
4218
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_ids[0] = 2) LIMIT 1"]
4219
- @Foo.first(:mtmbars=>@bar).must_equal @foo
4220
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars_foos.foo_ids[0] FROM bars_foos WHERE ((bars_foos.bar_ids[0] = 2) AND (bars_foos.foo_ids[0] IS NOT NULL)))) LIMIT 1"]
4221
- @Bar.first(:mtmfoos=>@foo).must_equal @bar
4222
- @db.sqls.must_equal ["SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT bars_foos.bar_ids[0] FROM bars_foos WHERE ((bars_foos.foo_ids[0] = 2) AND (bars_foos.bar_ids[0] IS NOT NULL)))) LIMIT 1"]
4223
- end
4224
-
4225
- it "should have working filter by associations for associations with :conditions with model instances" do
4226
- @Bar.many_to_one :foo, :clone=>:foo, :conditions=>{:name=>'A'}
4227
- @Foo.one_to_many :bars, :clone=>:bars, :conditions=>{:name=>'A'}
4228
- @Foo.one_to_one :bar, :clone=>:bars
4229
- @Foo.many_to_many :mtmbars, :clone=>:mtmbars, :conditions=>{:name=>'A'}
4230
- @Bar.many_to_many :mtmfoos, :clone=>:mtmfoos, :conditions=>{:name=>'A'}
4231
-
4232
- @Bar.where(:foo=>@foo).sql.must_equal "SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT foos.object_ids[0] FROM foos WHERE ((name = 'A') AND (foos.object_ids[0] IS NOT NULL) AND (foos.id = 1))))"
4233
- @Foo.where(:bars=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((name = 'A') AND (bars.object_ids[0] IS NOT NULL) AND (bars.id = 1))))"
4234
- @Foo.where(:bar=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((name = 'A') AND (bars.object_ids[0] IS NOT NULL) AND (bars.id = 1))))"
4235
- @Foo.where(:mtmbars=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars_foos.foo_ids[0] FROM bars INNER JOIN bars_foos ON (bars_foos.bar_ids[0] = bars.object_ids[0]) WHERE ((name = 'A') AND (bars_foos.foo_ids[0] IS NOT NULL) AND (bars.id = 1))))"
4236
- @Bar.where(:mtmfoos=>@foo).sql.must_equal "SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT bars_foos.bar_ids[0] FROM foos INNER JOIN bars_foos ON (bars_foos.foo_ids[0] = foos.object_ids[0]) WHERE ((name = 'A') AND (bars_foos.bar_ids[0] IS NOT NULL) AND (foos.id = 1))))"
4237
- end
4238
-
4239
- it "should have working filter by associations for associations with block with model instances" do
4240
- b = lambda{|ds| ds.where(:name=>'A')}
4241
- @Bar.many_to_one :foo, :clone=>:foo, &b
4242
- @Foo.one_to_many :bars, :clone=>:bars, &b
4243
- @Foo.one_to_one :bar, :clone=>:bars
4244
- @Foo.many_to_many :mtmbars, :clone=>:mtmbars, &b
4245
- @Bar.many_to_many :mtmfoos, :clone=>:mtmfoos, &b
4246
-
4247
- @Bar.where(:foo=>@foo).sql.must_equal "SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT foos.object_ids[0] FROM foos WHERE ((name = 'A') AND (foos.object_ids[0] IS NOT NULL) AND (foos.id = 1))))"
4248
- @Foo.where(:bars=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((name = 'A') AND (bars.object_ids[0] IS NOT NULL) AND (bars.id = 1))))"
4249
- @Foo.where(:bar=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((name = 'A') AND (bars.object_ids[0] IS NOT NULL) AND (bars.id = 1))))"
4250
- @Foo.where(:mtmbars=>@bar).sql.must_equal "SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars_foos.foo_ids[0] FROM bars INNER JOIN bars_foos ON (bars_foos.bar_ids[0] = bars.object_ids[0]) WHERE ((name = 'A') AND (bars_foos.foo_ids[0] IS NOT NULL) AND (bars.id = 1))))"
4251
- @Bar.where(:mtmfoos=>@foo).sql.must_equal "SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT bars_foos.bar_ids[0] FROM foos INNER JOIN bars_foos ON (bars_foos.foo_ids[0] = foos.object_ids[0]) WHERE ((name = 'A') AND (bars_foos.bar_ids[0] IS NOT NULL) AND (foos.id = 1))))"
4252
- end
4253
-
4254
- it "should have working filter by associations with model datasets" do
4255
- @Bar.first(:foo=>@Foo.where(:id=>@foo.id)).must_equal @bar
4256
- @db.sqls.must_equal ["SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT foos.object_ids[0] FROM foos WHERE ((id = 1) AND (foos.object_ids[0] IS NOT NULL)))) LIMIT 1"]
4257
- @Foo.first(:bars=>@Bar.where(:id=>@bar.id)).must_equal @foo
4258
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((id = 1) AND (bars.object_ids[0] IS NOT NULL)))) LIMIT 1"]
4259
- @Foo.first(:bar=>@Bar.where(:id=>@bar.id)).must_equal @foo
4260
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((id = 1) AND (bars.object_ids[0] IS NOT NULL)))) LIMIT 1"]
4261
- @Foo.first(:mtmbars=>@Bar.where(:id=>@bar.id)).must_equal @foo
4262
- @db.sqls.must_equal ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT bars_foos.foo_ids[0] FROM bars_foos WHERE ((bars_foos.bar_ids[0] IN (SELECT bars.object_ids[0] FROM bars WHERE ((id = 1) AND (bars.object_ids[0] IS NOT NULL)))) AND (bars_foos.foo_ids[0] IS NOT NULL)))) LIMIT 1"]
4263
- @Bar.first(:mtmfoos=>@Foo.where(:id=>@foo.id)).must_equal @bar
4264
- @db.sqls.must_equal ["SELECT * FROM bars WHERE (bars.object_ids[0] IN (SELECT bars_foos.bar_ids[0] FROM bars_foos WHERE ((bars_foos.foo_ids[0] IN (SELECT foos.object_ids[0] FROM foos WHERE ((id = 1) AND (foos.object_ids[0] IS NOT NULL)))) AND (bars_foos.bar_ids[0] IS NOT NULL)))) LIMIT 1"]
4265
- end
4266
- end
4267
-
4268
- describe Sequel::Model, "#refresh" do
4269
- before do
4270
- @c = Class.new(Sequel::Model(:items)) do
4271
- unrestrict_primary_key
4272
- columns :id, :x
4273
- end
4274
- DB.reset
4275
- end
4276
-
4277
- it "should remove cached associations" do
4278
- @c.many_to_one :node, :class=>@c
4279
- @m = @c.new(:id => 555)
4280
- @m.associations[:node] = 15
4281
- @m.reload
4282
- @m.associations.must_equal({})
4283
- end
4284
- end
4285
-
4286
- describe "Model#freeze" do
4287
- before do
4288
- class ::Album < Sequel::Model
4289
- columns :id
4290
- class B < Sequel::Model
4291
- columns :id, :album_id
4292
- many_to_one :album, :class=>Album
4293
- end
4294
- one_to_one :b, :key=>:album_id, :class=>B
4295
- end
4296
- @o = Album.load(:id=>1).freeze
4297
- DB.sqls
4298
- end
4299
- after do
4300
- Object.send(:remove_const, :Album)
4301
- end
4302
-
4303
- it "should freeze the object's associations" do
4304
- @o.associations.frozen?.must_equal true
4305
- end
4306
-
4307
- it "should not break associations getters" do
4308
- Album::B.dataset._fetch = {:album_id=>1, :id=>2}
4309
- @o.b.must_equal Album::B.load(:id=>2, :album_id=>1)
4310
- @o.associations[:b].must_equal nil
4311
-
4312
- @o = @o.dup
4313
- @o.b.must_equal Album::B.load(:id=>2, :album_id=>1)
4314
- @o.associations[:b].must_equal Album::B.load(:id=>2, :album_id=>1)
4315
- end
4316
-
4317
- it "should not break reciprocal associations" do
4318
- b = Album::B.load(:id=>2, :album_id=>nil)
4319
- b.album = @o
4320
- @o.associations[:b].must_equal nil
4321
-
4322
- @o = @o.dup
4323
- b = Album::B.load(:id=>2, :album_id=>nil)
4324
- b.album = @o
4325
- @o.associations[:b].must_equal Album::B.load(:id=>2, :album_id=>1)
4326
- end
4327
- end
4328
-
4329
- describe "association autoreloading" do
4330
- before do
4331
- @c = Class.new(Sequel::Model)
4332
- @Artist = Class.new(@c).set_dataset(:artists)
4333
- @Artist.dataset._fetch = {:id=>2, :name=>'Ar'}
4334
- @Album = Class.new(@c).set_dataset(:albums)
4335
- @Artist.columns :id, :name
4336
- @Album.columns :id, :name, :artist_id
4337
- @Album.db_schema[:artist_id][:type] = :integer
4338
- @Album.many_to_one :artist, :class=>@Artist
4339
- DB.reset
4340
- end
4341
-
4342
- it "should reload many_to_one association when foreign key is modified" do
4343
- album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
4344
- album.artist
4345
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 2']
4346
-
4347
- album.artist_id = 1
4348
- album.artist
4349
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 1']
4350
- end
4351
-
4352
- it "should handle multiple many_to_one association with the same foreign key" do
4353
- @Album.many_to_one :artist2, :key=>:artist_id, :class=>@Artist
4354
- album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
4355
- album.artist
4356
- album.artist2
4357
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 2'] * 2
4358
-
4359
- album.artist
4360
- album.artist2
4361
- DB.sqls.must_equal []
4362
-
4363
- album.artist_id = 1
4364
- album.artist
4365
- album.artist2
4366
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 1'] * 2
4367
- end
4368
-
4369
- it "should not reload when value has not changed" do
4370
- album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
4371
- album.artist
4372
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 2']
4373
-
4374
- album.artist_id = 2
4375
- album.artist
4376
- DB.sqls.must_equal []
4377
-
4378
- album.artist_id = "2"
4379
- album.artist
4380
- DB.sqls.must_equal []
4381
- end
4382
-
4383
- it "should reload all associations which use the foreign key" do
4384
- @Album.many_to_one :other_artist, :key => :artist_id, :foreign_key => :id, :class => @Artist
4385
- album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
4386
- album.artist
4387
- album.other_artist
4388
- DB.reset
4389
-
4390
- album.artist_id = 1
4391
- album.artist
4392
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 1']
4393
-
4394
- album.other_artist
4395
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 1']
4396
- end
4397
-
4398
- it "should work with composite keys" do
4399
- @Album.many_to_one :composite_artist, :key => [:artist_id, :name], :primary_key => [:id, :name], :class => @Artist
4400
- album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
4401
- album.composite_artist
4402
- DB.reset
4403
-
4404
- album.artist_id = 1
4405
- album.composite_artist
4406
- DB.sqls.must_equal ["SELECT * FROM artists WHERE ((artists.id = 1) AND (artists.name = 'Al')) LIMIT 1"]
4407
-
4408
- album.name = 'Al2'
4409
- album.composite_artist
4410
- DB.sqls.must_equal ["SELECT * FROM artists WHERE ((artists.id = 1) AND (artists.name = 'Al2')) LIMIT 1"]
4411
- end
4412
-
4413
- it "should work with subclasses" do
4414
- salbum = Class.new(@Album)
4415
- oartist = Class.new(@c).set_dataset(:oartist)
4416
- oartist.columns :id, :name
4417
- salbum.many_to_one :artist2, :class=>oartist, :key=>:artist_id
4418
- album = salbum.load(:id => 1, :name=>'Al', :artist_id=>2)
4419
- album.artist
4420
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 2']
4421
-
4422
- album.artist_id = 1
4423
- album.artist
4424
- DB.sqls.must_equal ['SELECT * FROM artists WHERE id = 1']
4425
- end
4426
- end