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