sequel 4.26.0 → 5.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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