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,2377 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe Sequel::Model, "#eager" do
4
- before do
5
- class ::EagerAlbum < Sequel::Model(:albums)
6
- columns :id, :band_id
7
- many_to_one :band, :class=>'EagerBand', :key=>:band_id
8
- one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id
9
- many_to_many :genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
10
- one_through_one :genre, :clone=>:genres
11
- one_to_many :good_tracks, :class=>'EagerTrack', :reciprocal=>nil, :key=>:album_id do |ds|
12
- ds.filter(:name=>'Good')
13
- end
14
- many_to_one :band_name, :class=>'EagerBand', :key=>:band_id, :select=>[:id, :name]
15
- one_to_many :track_names, :class=>'EagerTrack', :key=>:album_id, :select=>[:id, :name]
16
- many_to_many :genre_names, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :select=>[:id]
17
-
18
- def band_id3
19
- band_id*3
20
- end
21
- end
22
-
23
- class ::EagerBand < Sequel::Model(:bands)
24
- columns :id, :p_k
25
- one_to_many :albums, :class=>'EagerAlbum', :key=>:band_id, :eager=>:tracks, :reciprocal=>:band
26
- one_to_many :graph_albums, :class=>'EagerAlbum', :key=>:band_id, :eager_graph=>:tracks, :reciprocal=>nil
27
- many_to_many :members, :class=>'EagerBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
28
- many_to_many :graph_members, :clone=>:members, :eager_graph=>:bands
29
- one_to_many :good_albums, :class=>'EagerAlbum', :key=>:band_id, :reciprocal=>nil, :eager_block=>proc{|ds| ds.filter(:name=>'good')} do |ds|
30
- ds.filter(:name=>'Good')
31
- end
32
- one_to_many :self_titled_albums, :class=>'EagerAlbum', :key=>:band_id, :allow_eager=>false do |ds|
33
- ds.filter(:name=>name)
34
- end
35
- one_to_many :albums_by_name, :class=>'EagerAlbum', :key=>:band_id, :order=>:name, :allow_eager=>false
36
- one_to_many :top_10_albums, :class=>'EagerAlbum', :key=>:band_id, :limit=>10
37
-
38
- def id3
39
- id/3
40
- end
41
- end
42
-
43
- class ::EagerTrack < Sequel::Model(:tracks)
44
- columns :id, :album_id
45
- many_to_one :album, :class=>'EagerAlbum', :key=>:album_id
46
- end
47
-
48
- class ::EagerGenre < Sequel::Model(:genres)
49
- columns :id, :xxx
50
- many_to_many :albums, :class=>'EagerAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
51
- end
52
-
53
- class ::EagerBandMember < Sequel::Model(:members)
54
- columns :id
55
- many_to_many :bands, :class=>'EagerBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm, :order =>:id
56
- end
57
-
58
- EagerAlbum.dataset = EagerAlbum.dataset.with_fetch(proc do |sql|
59
- h = if sql =~ /101/
60
- {:id => 101, :band_id=> 101}
61
- else
62
- {:id => 1, :band_id=> 2}
63
- end
64
- h[:x_foreign_key_x] = 4 if sql =~ /ag\.genre_id/
65
- h
66
- end)
67
- EagerAlbum.dataset.columns(:id, :band_id)
68
-
69
- EagerBand.dataset = EagerBand.dataset.with_fetch(proc do |sql|
70
- case sql
71
- when /id IN (101)/
72
- # nothing
73
- when /id > 100/
74
- [{:id => 101}, {:id => 102}]
75
- else
76
- h = {:id => 2}
77
- h[:x_foreign_key_x] = 5 if sql =~ /bm\.member_id/
78
- h
79
- end
80
- end)
81
-
82
- EagerTrack.dataset = EagerTrack.dataset.with_fetch(:id => 3, :album_id => 1)
83
-
84
- EagerGenre.dataset = EagerGenre.dataset.with_fetch(proc do |sql|
85
- h = {:id => 4}
86
- h[:x_foreign_key_x] = 1 if sql =~ /ag\.album_id/
87
- h
88
- end)
89
-
90
- EagerBandMember.dataset = EagerBandMember.dataset.with_fetch(proc do |sql|
91
- h = {:id => 5}
92
- h[:x_foreign_key_x] = 2 if sql =~ /bm\.band_id/
93
- h
94
- end)
95
-
96
- DB.reset
97
- end
98
- after do
99
- [:EagerAlbum, :EagerBand, :EagerTrack, :EagerGenre, :EagerBandMember].each{|x| Object.send(:remove_const, x)}
100
- end
101
-
102
- it "should populate :key_hash and :id_map option correctly for custom eager loaders" do
103
- khs = {}
104
- pr = proc{|a, m| proc{|h| khs[a] = h[:key_hash][m]; h[:id_map].must_equal h[:key_hash][m]}}
105
- EagerAlbum.many_to_one :sband, :clone=>:band, :eager_loader=>pr.call(:sband, :band_id)
106
- EagerAlbum.one_to_many :stracks, :clone=>:tracks, :eager_loader=>pr.call(:stracks, :id)
107
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :eager_loader=>pr.call(:sgenres, :id)
108
- EagerAlbum.eager(:sband, :stracks, :sgenres).all
109
- khs.must_equal(:sband=>{2=>[EagerAlbum.load(:band_id=>2, :id=>1)]}, :stracks=>{1=>[EagerAlbum.load(:band_id=>2, :id=>1)]}, :sgenres=>{1=>[EagerAlbum.load(:band_id=>2, :id=>1)]})
110
- end
111
-
112
- it "should populate :key_hash using the method symbol" do
113
- khs = {}
114
- pr = proc{|a, m| proc{|h| khs[a] = h[:key_hash][m]}}
115
- EagerAlbum.many_to_one :sband, :clone=>:band, :eager_loader=>pr.call(:sband, :band_id), :key=>:band_id, :key_column=>:b_id
116
- EagerAlbum.one_to_many :stracks, :clone=>:tracks, :eager_loader=>pr.call(:stracks, :id), :primary_key=>:id, :primary_key_column=>:i
117
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :eager_loader=>pr.call(:sgenres, :id), :left_primary_key=>:id, :left_primary_key_column=>:i
118
- EagerAlbum.eager(:sband, :stracks, :sgenres).all
119
- khs.must_equal(:sband=>{2=>[EagerAlbum.load(:band_id=>2, :id=>1)]}, :stracks=>{1=>[EagerAlbum.load(:band_id=>2, :id=>1)]}, :sgenres=>{1=>[EagerAlbum.load(:band_id=>2, :id=>1)]})
120
- end
121
-
122
- it "should raise an error if called without a symbol or hash" do
123
- proc{EagerAlbum.eager(Object.new)}.must_raise(Sequel::Error)
124
- end
125
-
126
- it "should eagerly load a single many_to_one association" do
127
- a = EagerAlbum.eager(:band).all
128
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (2))']
129
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
130
- a.first.band.must_equal EagerBand.load(:id=>2)
131
- DB.sqls.must_equal []
132
- end
133
-
134
- it "should eagerly load when using to_hash" do
135
- h = EagerAlbum.eager(:band).to_hash
136
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (2))']
137
- h.must_equal(1=>EagerAlbum.load(:id => 1, :band_id => 2))
138
- h[1].band.must_equal EagerBand.load(:id=>2)
139
- DB.sqls.must_equal []
140
- end
141
-
142
- it "should eagerly load when using to_hash_groups" do
143
- h = EagerAlbum.eager(:band).to_hash_groups(:id)
144
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (2))']
145
- h.must_equal(1=>[EagerAlbum.load(:id => 1, :band_id => 2)])
146
- h[1].first.band.must_equal EagerBand.load(:id=>2)
147
- DB.sqls.must_equal []
148
- end
149
-
150
- it "should skip eager loading for a many_to_one association with no matching keys" do
151
- EagerAlbum.dataset = EagerAlbum.dataset.with_fetch([{:id=>1, :band_id=>nil}])
152
- a = EagerAlbum.eager(:band).all
153
- DB.sqls.must_equal ['SELECT * FROM albums']
154
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => nil)]
155
- a.first.associations.fetch(:band).must_be_nil
156
- a.first.band.must_be_nil
157
- DB.sqls.must_equal []
158
- end
159
-
160
- it "should eagerly load a single many_to_one association with the same name as the column" do
161
- EagerAlbum.def_column_alias(:band_id_id, :band_id)
162
- EagerAlbum.many_to_one :band_id, :key_column=>:band_id, :class=>EagerBand
163
- a = EagerAlbum.eager(:band_id).all
164
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (2))']
165
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
166
- a.first.band_id.must_equal EagerBand.load(:id=>2)
167
- DB.sqls.must_equal []
168
- end
169
-
170
- it "should eagerly load a single one_to_one association" do
171
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id
172
- a = EagerAlbum.eager(:track).all
173
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
174
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
175
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
176
- DB.sqls.must_equal []
177
- end
178
-
179
- it "should not break if the dataset does not have a row proc" do
180
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id
181
- a = EagerAlbum.eager(:track).naked.all
182
- a.must_equal [{:id => 1, :band_id => 2}]
183
- DB.sqls.must_equal ['SELECT * FROM albums']
184
- end
185
-
186
- it "should eagerly load a single one_to_one association without an order" do
187
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id
188
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:id => 3, :album_id=>1}, {:id => 4, :album_id=>1}])
189
- a = EagerAlbum.eager(:track).all
190
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
191
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
192
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
193
- DB.sqls.must_equal []
194
- end
195
-
196
- it "should eagerly load a single one_to_one association with an order" do
197
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:a
198
- a = EagerAlbum.eager(:track).all
199
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
200
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY a LIMIT 1) AS t1']
201
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
202
- DB.sqls.must_equal []
203
- end
204
-
205
- it "should eagerly load a single one_to_one association using the :distinct_on strategy" do
206
- EagerTrack.dataset = EagerTrack.dataset.with_extend{def supports_distinct_on?; true end}
207
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:a, :eager_limit_strategy=>:distinct_on
208
- a = EagerAlbum.eager(:track).all
209
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
210
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT DISTINCT ON (tracks.album_id) * FROM tracks WHERE (tracks.album_id IN (1)) ORDER BY tracks.album_id, a']
211
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
212
- DB.sqls.must_equal []
213
- end
214
-
215
- it "should eagerly load a single one_to_one association using the :window_function strategy" do
216
- EagerTrack.dataset = EagerTrack.dataset.with_extend{def supports_window_functions?; true end}
217
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :eager_limit_strategy=>:window_function
218
- a = EagerAlbum.eager(:track).all
219
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
220
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x = 1)']
221
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
222
- DB.sqls.must_equal []
223
- end
224
-
225
- it "should eagerly load a single one_to_one association using the :window_function strategy on MySQL" do
226
- odb = DB
227
- db = Class.new do
228
- def database_type; :mysql; end
229
- define_method(:method_missing) do |*args, &block|
230
- odb.send(*args, &block)
231
- end
232
- end.new
233
-
234
- begin
235
- EagerTrack.dataset = EagerTrack.dataset.with_extend do
236
- def supports_window_functions?; true end
237
- define_method(:db){db}
238
- end
239
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :eager_limit_strategy=>:window_function
240
- a = EagerAlbum.eager(:track).all
241
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
242
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x = 1) ORDER BY x_sequel_row_number_x']
243
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
244
- DB.sqls.must_equal []
245
- ensure
246
- db = DB
247
- end
248
- end
249
-
250
- it "should automatically use an eager limit stategy if the association has an offset" do
251
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1]
252
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:id => 4, :album_id=>1}])
253
- a = EagerAlbum.eager(:track).all
254
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
255
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1']
256
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
257
- DB.sqls.must_equal []
258
- end
259
-
260
- it "should handle offsets when using the :ruby eager limit stategy" do
261
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1], :eager_limit_strategy=>:ruby
262
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:id => 3, :album_id=>1}, {:id => 4, :album_id=>1}])
263
- a = EagerAlbum.eager(:track).all
264
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
265
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
266
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
267
- DB.sqls.must_equal []
268
- end
269
-
270
- it "should support a :subqueries_per_union option for the number of subqueries in a union" do
271
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1], :subqueries_per_union=>1
272
- EagerAlbum.dataset = EagerAlbum.dataset.with_fetch([{:id => 1, :band_id => 2}, {:id => 2, :band_id => 3}, {:id => 3, :band_id => 4}])
273
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([[{:id => 4, :album_id=>1}], [{:id=>5, :album_id=>2}], [{:id=>6, :album_id=>3}]])
274
- a = EagerAlbum.eager(:track).all
275
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2), EagerAlbum.load(:id => 2, :band_id => 3), EagerAlbum.load(:id => 3, :band_id => 4)]
276
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1', 'SELECT * FROM (SELECT * FROM tracks WHERE (2 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1', 'SELECT * FROM (SELECT * FROM tracks WHERE (3 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1']
277
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
278
- DB.sqls.must_equal []
279
-
280
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1], :subqueries_per_union=>2
281
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([[{:id => 4, :album_id=>1}, {:id=>5, :album_id=>2}], [{:id=>6, :album_id=>3}]])
282
- a = EagerAlbum.eager(:track).all
283
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2), EagerAlbum.load(:id => 2, :band_id => 3), EagerAlbum.load(:id => 3, :band_id => 4)]
284
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1 UNION ALL SELECT * FROM (SELECT * FROM tracks WHERE (2 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1', 'SELECT * FROM (SELECT * FROM tracks WHERE (3 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1']
285
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
286
- DB.sqls.must_equal []
287
-
288
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1], :subqueries_per_union=>3
289
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([[{:id => 4, :album_id=>1}, {:id=>5, :album_id=>2}, {:id=>6, :album_id=>3}]])
290
- a = EagerAlbum.eager(:track).all
291
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2), EagerAlbum.load(:id => 2, :band_id => 3), EagerAlbum.load(:id => 3, :band_id => 4)]
292
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1 UNION ALL SELECT * FROM (SELECT * FROM tracks WHERE (2 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1 UNION ALL SELECT * FROM (SELECT * FROM tracks WHERE (3 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1']
293
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
294
- DB.sqls.must_equal []
295
- end
296
-
297
- it "should eagerly load a single one_to_many association" do
298
- a = EagerAlbum.eager(:tracks).all
299
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
300
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
301
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
302
- DB.sqls.must_equal []
303
- end
304
-
305
- it "should eagerly load a single one_through_one association" do
306
- a = EagerAlbum.eager(:genre).all
307
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
308
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
309
- a.first.genre.must_equal EagerGenre.load(:id=>4)
310
- DB.sqls.must_equal []
311
- end
312
-
313
- it "should use first matching entry when eager loading one_through_one association" do
314
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:id => 3, :x_foreign_key_x=>1}, {:id => 4, :x_foreign_key_x=>1}])
315
- a = EagerAlbum.eager(:genre).all
316
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
317
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
318
- a.first.genre.must_equal EagerGenre.load(:id=>3)
319
- DB.sqls.must_equal []
320
- end
321
-
322
- it "should eagerly load a single one_through_one association" do
323
- EagerAlbum.one_through_one :genre, :clone=>:genre, :order=>:a
324
- a = EagerAlbum.eager(:genre).all
325
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
326
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (1 = ag.album_id) ORDER BY a LIMIT 1) AS t1"]
327
- a.first.genre.must_equal EagerGenre.load(:id=>4)
328
- DB.sqls.must_equal []
329
- end
330
-
331
- it "should eagerly load a single one_through_one association using the :distinct_on strategy" do
332
- EagerGenre.dataset = EagerGenre.dataset.with_extend{def supports_distinct_on?; true end}
333
- EagerAlbum.one_through_one :genre, :clone=>:genre, :order=>:a, :eager_limit_strategy=>:distinct_on
334
- a = EagerAlbum.eager(:genre).all
335
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
336
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT DISTINCT ON (ag.album_id) genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1)) ORDER BY ag.album_id, a"]
337
- a.first.genre.must_equal EagerGenre.load(:id=>4)
338
- DB.sqls.must_equal []
339
- end
340
-
341
- it "should eagerly load a single one_through_one association using the :window_function strategy" do
342
- EagerGenre.dataset = EagerGenre.dataset.with_extend{def supports_window_functions?; true end}
343
- EagerAlbum.one_through_one :genre, :clone=>:genre, :eager_limit_strategy=>:window_function
344
- a = EagerAlbum.eager(:genre).all
345
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
346
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x, row_number() OVER (PARTITION BY ag.album_id) AS x_sequel_row_number_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x = 1)"]
347
- a.first.genre.must_equal EagerGenre.load(:id=>4)
348
- DB.sqls.must_equal []
349
- end
350
-
351
- it "should automatically use an eager limit stategy if the association has an offset" do
352
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:id => 3, :x_foreign_key_x=>1}, {:id => 4, :x_foreign_key_x=>1}])
353
- a = EagerAlbum.eager(:genre).all
354
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
355
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
356
- a.first.genre.must_equal EagerGenre.load(:id=>3)
357
- DB.sqls.must_equal []
358
- end
359
-
360
- it "should eagerly load a single many_to_many association" do
361
- a = EagerAlbum.eager(:genres).all
362
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
363
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
364
- a.first.genres.must_equal [EagerGenre.load(:id=>4)]
365
- DB.sqls.must_equal []
366
- end
367
-
368
- it "should support using a custom :key option when eager loading many_to_one associations" do
369
- EagerAlbum.many_to_one :sband, :clone=>:band, :key=>:band_id3
370
- EagerBand.dataset = EagerBand.dataset.with_fetch(:id=>6)
371
- a = EagerAlbum.eager(:sband).all
372
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (6))']
373
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
374
- a.first.sband.must_equal EagerBand.load(:id=>6)
375
- DB.sqls.must_equal []
376
- end
377
-
378
- it "should support using a custom :primary_key option when eager loading one_to_many associations" do
379
- EagerBand.one_to_many :salbums, :clone=>:albums, :primary_key=>:id3, :eager=>nil, :reciprocal=>nil
380
- EagerBand.dataset = EagerBand.dataset.with_fetch(:id=>6)
381
- a = EagerBand.eager(:salbums).all
382
- DB.sqls.must_equal ['SELECT * FROM bands', 'SELECT * FROM albums WHERE (albums.band_id IN (2))']
383
- a.must_equal [EagerBand.load(:id => 6)]
384
- a.first.salbums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
385
- DB.sqls.must_equal []
386
- end
387
-
388
- it "should support using a custom :left_primary_key option when eager loading many_to_many associations" do
389
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :left_primary_key=>:band_id3
390
- EagerGenre.dataset = EagerGenre.dataset.with_fetch(:id=>4, :x_foreign_key_x=>6)
391
- a = EagerAlbum.eager(:sgenres).all
392
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
393
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (6))"]
394
- a.first.sgenres.must_equal [EagerGenre.load(:id=>4)]
395
- DB.sqls.must_equal []
396
- end
397
-
398
- it "should support using a custom :left_primary_key option when eager loading one_through_one associations" do
399
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :left_primary_key=>:band_id3
400
- EagerGenre.dataset = EagerGenre.dataset.with_fetch(:id=>4, :x_foreign_key_x=>6)
401
- a = EagerAlbum.eager(:sgenre).all
402
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
403
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (6))"]
404
- a.first.sgenre.must_equal EagerGenre.load(:id=>4)
405
- DB.sqls.must_equal []
406
- end
407
-
408
- it "should handle a :predicate_key option to change the SQL used in the lookup, for many_to_one associations" do
409
- EagerAlbum.many_to_one :sband, :clone=>:band, :predicate_key=>(Sequel[:bands][:id] / 3), :primary_key_method=>:id3
410
- EagerBand.dataset = EagerBand.dataset.with_fetch(:id=>6)
411
- a = EagerAlbum.eager(:sband).all
412
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM bands WHERE ((bands.id / 3) IN (2))']
413
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
414
- a.first.sband.must_equal EagerBand.load(:id=>6)
415
- DB.sqls.must_equal []
416
- end
417
-
418
- it "should handle a :predicate_key option to change the SQL used in the lookup, for one_to_many associations" do
419
- EagerBand.one_to_many :salbums, :clone=>:albums, :predicate_key=>(Sequel[:albums][:band_id] * 3), :key_method=>:band_id3, :eager=>nil, :reciprocal=>nil
420
- EagerBand.dataset = EagerBand.dataset.with_fetch(:id=>6)
421
- a = EagerBand.eager(:salbums).all
422
- DB.sqls.must_equal ['SELECT * FROM bands', 'SELECT * FROM albums WHERE ((albums.band_id * 3) IN (6))']
423
- a.must_equal [EagerBand.load(:id => 6)]
424
- a.first.salbums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
425
- DB.sqls.must_equal []
426
- end
427
-
428
- it "should handle a :predicate_key option to change the SQL used in the lookup, for many_to_many associations" do
429
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :predicate_key=>(Sequel[:ag][:album_id] * 1)
430
- a = EagerAlbum.eager(:sgenres).all
431
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
432
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, (ag.album_id * 1) AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE ((ag.album_id * 1) IN (1))"]
433
- a.first.sgenres.must_equal [EagerGenre.load(:id=>4)]
434
- DB.sqls.must_equal []
435
- end
436
-
437
- it "should handle a :predicate_key option to change the SQL used in the lookup, for one_through_one associations" do
438
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :predicate_key=>(Sequel[:ag][:album_id] * 1)
439
- a = EagerAlbum.eager(:sgenre).all
440
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
441
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, (ag.album_id * 1) AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE ((ag.album_id * 1) IN (1))"]
442
- a.first.sgenre.must_equal EagerGenre.load(:id=>4)
443
- DB.sqls.must_equal []
444
- end
445
-
446
- it "should raise an error for an unhandled :eager_loader_key option" do
447
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :eager_loader_key=>1
448
- ds = EagerAlbum.eager(:sgenres)
449
- proc{ds.all}.must_raise(Sequel::Error)
450
- end
451
-
452
- it "should not add entry to key_hash for :eager_loader_key=>nil option" do
453
- eo = nil
454
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :eager_loader_key=>nil, :eager_loader=>proc{|o| eo = o}
455
- ds = EagerAlbum.eager(:sgenres)
456
- ds.all
457
- eo[:key_hash].must_equal({})
458
- eo[:id_map].must_be_nil
459
- end
460
-
461
- it "should correctly handle a :select=>[] option to many_to_many" do
462
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :select=>[]
463
- EagerAlbum.eager(:sgenres).all
464
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT *, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
465
- end
466
-
467
- it "should correctly handle a :select=>[] option to one_through_one" do
468
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :select=>[]
469
- EagerAlbum.eager(:sgenre).all
470
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT *, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
471
- end
472
-
473
- with_symbol_splitting "should correctly handle an aliased join table symbol in many_to_many" do
474
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :join_table=>:ag___ga
475
- EagerAlbum.eager(:sgenres).all
476
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ga.album_id AS x_foreign_key_x FROM genres INNER JOIN ag AS ga ON (ga.genre_id = genres.id) WHERE (ga.album_id IN (1))"]
477
- end
478
-
479
- with_symbol_splitting "should correctly handle an aliased join table symbol in one_through_one" do
480
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :join_table=>:ag___ga
481
- EagerAlbum.eager(:sgenre).all
482
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ga.album_id AS x_foreign_key_x FROM genres INNER JOIN ag AS ga ON (ga.genre_id = genres.id) WHERE (ga.album_id IN (1))"]
483
- end
484
-
485
- it "should correctly handle an aliased join table in many_to_many" do
486
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga)
487
- EagerAlbum.eager(:sgenres).all
488
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ga.album_id AS x_foreign_key_x FROM genres INNER JOIN ag AS ga ON (ga.genre_id = genres.id) WHERE (ga.album_id IN (1))"]
489
- end
490
-
491
- it "should correctly handle an aliased join table in one_through_one" do
492
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :join_table=>Sequel[:ag].as(:ga)
493
- EagerAlbum.eager(:sgenre).all
494
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ga.album_id AS x_foreign_key_x FROM genres INNER JOIN ag AS ga ON (ga.genre_id = genres.id) WHERE (ga.album_id IN (1))"]
495
- end
496
-
497
- it "should eagerly load multiple associations in a single call" do
498
- a = EagerAlbum.eager(:genres, :tracks, :band).all
499
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
500
- sqls = DB.sqls
501
- sqls.shift.must_equal 'SELECT * FROM albums'
502
- sqls.sort.must_equal ['SELECT * FROM bands WHERE (bands.id IN (2))',
503
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))',
504
- 'SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))']
505
- a = a.first
506
- a.band.must_equal EagerBand.load(:id=>2)
507
- a.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
508
- a.genres.must_equal [EagerGenre.load(:id => 4)]
509
- DB.sqls.must_equal []
510
- end
511
-
512
- it "should eagerly load multiple associations in separate calls" do
513
- a = EagerAlbum.eager(:genres).eager(:tracks).eager(:band).all
514
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
515
- sqls = DB.sqls
516
- sqls.shift.must_equal 'SELECT * FROM albums'
517
- sqls.sort.must_equal ['SELECT * FROM bands WHERE (bands.id IN (2))',
518
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))',
519
- 'SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))']
520
- a = a.first
521
- a.band.must_equal EagerBand.load(:id=>2)
522
- a.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
523
- a.genres.must_equal [EagerGenre.load(:id => 4)]
524
- DB.sqls.must_equal []
525
- end
526
-
527
- it "should allow cascading of eager loading for associations of associated models" do
528
- a = EagerTrack.eager(:album=>{:band=>:members}).all
529
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
530
- DB.sqls.must_equal ['SELECT * FROM tracks',
531
- 'SELECT * FROM albums WHERE (albums.id IN (1))',
532
- 'SELECT * FROM bands WHERE (bands.id IN (2))',
533
- "SELECT members.*, bm.band_id AS x_foreign_key_x FROM members INNER JOIN bm ON (bm.member_id = members.id) WHERE (bm.band_id IN (2))"]
534
- a = a.first
535
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
536
- a.album.band.must_equal EagerBand.load(:id => 2)
537
- a.album.band.members.must_equal [EagerBandMember.load(:id => 5)]
538
- DB.sqls.must_equal []
539
- end
540
-
541
- it "should cascade eager loading when using a UNION strategy for eager loading limited associations" do
542
- EagerTrack.many_to_one :album2, :clone=>:album
543
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:a
544
- a = EagerAlbum.eager(:track=>:album2).all
545
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
546
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY a LIMIT 1) AS t1', 'SELECT * FROM albums WHERE (albums.id IN (1))']
547
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
548
- a.first.track.album2.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
549
- DB.sqls.must_equal []
550
-
551
- a = EagerAlbum.eager(:track=>[:album2]).all
552
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
553
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY a LIMIT 1) AS t1', 'SELECT * FROM albums WHERE (albums.id IN (1))']
554
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
555
- a.first.track.album2.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
556
- DB.sqls.must_equal []
557
-
558
- a = EagerAlbum.eager(:track=>{:album2=>:track}).all
559
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
560
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY a LIMIT 1) AS t1', 'SELECT * FROM albums WHERE (albums.id IN (1))', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY a LIMIT 1) AS t1']
561
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
562
- a.first.track.album2.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
563
- a.first.track.album2.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
564
- DB.sqls.must_equal []
565
- end
566
-
567
- it "should call post_load when eager loading limited associations" do
568
- EagerTrack.many_to_one :album2, :clone=>:album
569
- a = []
570
- m = Module.new do
571
- define_method(:post_load) do |objs|
572
- a << 1
573
- super(objs)
574
- end
575
- end
576
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:a, :extend=>m
577
- EagerAlbum.eager(:track).all
578
- a.must_equal [1]
579
- end
580
-
581
- it "should cascade eagerly loading when the :eager association option is used" do
582
- a = EagerBand.eager(:albums).all
583
- a.must_equal [EagerBand.load(:id=>2)]
584
- DB.sqls.must_equal ['SELECT * FROM bands',
585
- 'SELECT * FROM albums WHERE (albums.band_id IN (2))',
586
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
587
- a.first.albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
588
- a.first.albums.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
589
- DB.sqls.must_equal []
590
- end
591
-
592
- it "should respect :eager when lazily loading an association" do
593
- a = EagerBand.all
594
- a.must_equal [EagerBand.load(:id=>2)]
595
- DB.sqls.must_equal ['SELECT * FROM bands']
596
- a = a.first.albums
597
- DB.sqls.must_equal ['SELECT * FROM albums WHERE (albums.band_id = 2)',
598
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
599
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
600
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
601
- DB.sqls.must_equal []
602
- end
603
-
604
- it "should respect :eager with cascaded hash when lazily loading an association" do
605
- EagerBand.one_to_many :albums, :eager=>{:tracks=>:album}, :clone=>:albums
606
- a = EagerBand.all
607
- a.must_equal [EagerBand.load(:id=>2)]
608
- DB.sqls.must_equal ['SELECT * FROM bands']
609
- a = a.first.albums
610
- DB.sqls.must_equal ['SELECT * FROM albums WHERE (albums.band_id = 2)',
611
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))',
612
- 'SELECT * FROM albums WHERE (albums.id IN (1))']
613
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
614
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
615
- a.first.tracks.first.album.must_equal a.first
616
- DB.sqls.must_equal []
617
- end
618
-
619
- it "should cascade eagerly loading when the :eager_graph association option is used" do
620
- EagerAlbum.dataset = EagerAlbum.dataset.with_fetch(:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1)
621
- EagerAlbum.dataset.columns(:id, :band_id)
622
- EagerTrack.dataset.columns(:id, :album_id)
623
- a = EagerBand.eager(:graph_albums).all
624
- a.must_equal [EagerBand.load(:id=>2)]
625
- DB.sqls.must_equal ['SELECT * FROM bands',
626
- 'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) WHERE (albums.band_id IN (2))']
627
- a.first.graph_albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
628
- a.first.graph_albums.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
629
- DB.sqls.must_equal []
630
- end
631
-
632
- it "should raise an Error when eager loading a many_to_many association with the :eager_graph option" do
633
- proc{EagerBand.eager(:graph_members).all}.must_raise(Sequel::Error)
634
- end
635
-
636
- it "should respect :eager_graph when lazily loading an association" do
637
- a = EagerBand.all
638
- a.must_equal [EagerBand.load(:id=>2)]
639
- DB.sqls.must_equal ['SELECT * FROM bands']
640
- a = a.first
641
- EagerAlbum.dataset = EagerAlbum.dataset.with_fetch(:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1)
642
- EagerAlbum.dataset.columns(:id, :band_id)
643
- EagerTrack.dataset.columns(:id, :album_id)
644
- a.graph_albums
645
- DB.sqls.must_equal ['SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) WHERE (albums.band_id = 2)']
646
- a.graph_albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
647
- a.graph_albums.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
648
- DB.sqls.must_equal []
649
- end
650
-
651
- it "should respect :eager_graph when lazily loading a many_to_many association" do
652
- EagerBandMember.dataset = EagerBandMember.dataset.with_fetch([{:id=>5, :bands_id=>2, :p_k=>6}, {:id=>5, :bands_id=>3, :p_k=>6}]).with_extend{def columns; [:id] end}
653
- a = EagerBand.load(:id=>2)
654
- EagerBand.dataset.columns(:id, :p_k)
655
- a.graph_members.must_equal [EagerBandMember.load(:id=>5)]
656
- DB.sqls.must_equal ['SELECT members.id, bands.id AS bands_id, bands.p_k FROM (SELECT members.* FROM members INNER JOIN bm ON (bm.member_id = members.id) WHERE (bm.band_id = 2)) AS members LEFT OUTER JOIN bm AS bm_0 ON (bm_0.member_id = members.id) LEFT OUTER JOIN bands ON (bands.id = bm_0.band_id) ORDER BY bands.id']
657
- a.graph_members.first.bands.must_equal [EagerBand.load(:id=>2, :p_k=>6), EagerBand.load(:id=>3, :p_k=>6)]
658
- DB.sqls.must_equal []
659
- end
660
-
661
- it "should respect :conditions when eagerly loading" do
662
- EagerBandMember.many_to_many :good_bands, :clone=>:bands, :conditions=>{:a=>32}
663
- a = EagerBandMember.eager(:good_bands).all
664
- a.must_equal [EagerBandMember.load(:id => 5)]
665
- DB.sqls.must_equal ['SELECT * FROM members', 'SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON (bm.band_id = bands.id) WHERE ((a = 32) AND (bm.member_id IN (5))) ORDER BY id']
666
- a.first.good_bands.must_equal [EagerBand.load(:id => 2)]
667
- DB.sqls.must_equal []
668
-
669
- EagerBandMember.many_to_many :good_bands, :clone=>:bands, :conditions=>Sequel.lit("x = 1")
670
- a = EagerBandMember.eager(:good_bands).all
671
- DB.sqls.must_equal ['SELECT * FROM members', 'SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON (bm.band_id = bands.id) WHERE ((x = 1) AND (bm.member_id IN (5))) ORDER BY id']
672
- end
673
-
674
- it "should respect :order when eagerly loading" do
675
- a = EagerBandMember.eager(:bands).all
676
- a.must_equal [EagerBandMember.load(:id => 5)]
677
- DB.sqls.must_equal ['SELECT * FROM members', 'SELECT bands.*, bm.member_id AS x_foreign_key_x FROM bands INNER JOIN bm ON (bm.band_id = bands.id) WHERE (bm.member_id IN (5)) ORDER BY id']
678
- a.first.bands.must_equal [EagerBand.load(:id => 2)]
679
- DB.sqls.must_equal []
680
- end
681
-
682
- it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
683
- a = EagerAlbum.eager(:tracks).all
684
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
685
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
686
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
687
- a.first.tracks.first.album.must_equal a.first
688
- DB.sqls.must_equal []
689
- end
690
-
691
- it "should cache the negative lookup when eagerly loading a many_to_one association" do
692
- a = EagerAlbum.eager(:band).filter(:id=>101).all
693
- a.must_equal [EagerAlbum.load(:id => 101, :band_id => 101)]
694
- DB.sqls.must_equal ['SELECT * FROM albums WHERE (id = 101)', 'SELECT * FROM bands WHERE (bands.id IN (101))']
695
- a.first.associations.fetch(:band, 2).must_be_nil
696
- a.first.band.must_be_nil
697
- DB.sqls.must_equal []
698
- end
699
-
700
- it "should cache the negative lookup when eagerly loading a *_to_many associations" do
701
- a = EagerBand.eager(:albums).where{id > 100}.all
702
- a.must_equal [EagerBand.load(:id => 101), EagerBand.load(:id =>102)]
703
- DB.sqls.must_equal ['SELECT * FROM bands WHERE (id > 100)',
704
- 'SELECT * FROM albums WHERE (albums.band_id IN (101, 102))',
705
- "SELECT * FROM tracks WHERE (tracks.album_id IN (101))"]
706
- a.map{|b| b.associations[:albums]}.must_equal [[EagerAlbum.load({:band_id=>101, :id=>101})], []]
707
- DB.sqls.must_equal []
708
- end
709
-
710
- it "should use the association's block when eager loading by default" do
711
- EagerAlbum.eager(:good_tracks).all
712
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE ((name = 'Good') AND (tracks.album_id IN (1)))"]
713
- end
714
-
715
- it "should use the eager_block option when eager loading if given" do
716
- EagerBand.eager(:good_albums).all
717
- DB.sqls.must_equal ['SELECT * FROM bands', "SELECT * FROM albums WHERE ((name = 'good') AND (albums.band_id IN (2)))"]
718
- EagerBand.eager(:good_albums=>:good_tracks).all
719
- DB.sqls.must_equal ['SELECT * FROM bands', "SELECT * FROM albums WHERE ((name = 'good') AND (albums.band_id IN (2)))", "SELECT * FROM tracks WHERE ((name = 'Good') AND (tracks.album_id IN (1)))"]
720
- end
721
-
722
- it "should raise an error when attempting to eagerly load an association with the :allow_eager option set to false" do
723
- proc{EagerBand.eager(:self_titled_albums).all}.must_raise(Sequel::Error)
724
- proc{EagerBand.eager(:albums_by_name).all}.must_raise(Sequel::Error)
725
- end
726
-
727
- it "should respect the association's :select option" do
728
- EagerAlbum.eager(:band_name).all
729
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT id, name FROM bands WHERE (bands.id IN (2))"]
730
- EagerAlbum.eager(:track_names).all
731
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT id, name FROM tracks WHERE (tracks.album_id IN (1))"]
732
- EagerAlbum.eager(:genre_names).all
733
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT id, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
734
- end
735
-
736
- it "should respect many_to_one association's :qualify option" do
737
- EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :qualify=>false, :key=>:band_id
738
- EagerBand.dataset = EagerBand.dataset.with_fetch(:id=>2)
739
- as = EagerAlbum.eager(:special_band).all
740
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM bands WHERE (id IN (2))"]
741
- as.map{|a| a.special_band}.must_equal [EagerBand.load(:id=>2)]
742
- DB.sqls.must_equal []
743
- end
744
-
745
- it "should respect the association's :primary_key option" do
746
- EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :primary_key=>:p_k, :key=>:band_id
747
- EagerBand.dataset = EagerBand.dataset.with_fetch(:p_k=>2, :id=>1)
748
- as = EagerAlbum.eager(:special_band).all
749
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM bands WHERE (bands.p_k IN (2))"]
750
- as.length.must_equal 1
751
- as.first.special_band.must_equal EagerBand.load(:p_k=>2, :id=>1)
752
-
753
- EagerAlbum.one_to_many :special_tracks, :class=>:EagerTrack, :primary_key=>:band_id, :key=>:album_id, :reciprocal=>nil
754
- EagerTrack.dataset = EagerTrack.dataset.with_fetch(:album_id=>2, :id=>1)
755
- as = EagerAlbum.eager(:special_tracks).all
756
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (2))"]
757
- as.length.must_equal 1
758
- as.first.special_tracks.must_equal [EagerTrack.load(:album_id=>2, :id=>1)]
759
- end
760
-
761
- it "should respect the many_to_one association's composite keys" do
762
- EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :primary_key=>[:id, :p_k], :key=>[:band_id, :id]
763
- EagerBand.dataset = EagerBand.dataset.with_fetch(:p_k=>1, :id=>2)
764
- as = EagerAlbum.eager(:special_band).all
765
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM bands WHERE ((bands.id, bands.p_k) IN ((2, 1)))"]
766
- as.length.must_equal 1
767
- as.first.special_band.must_equal EagerBand.load(:p_k=>1, :id=>2)
768
- end
769
-
770
- it "should respect the one_to_many association's composite keys" do
771
- EagerAlbum.one_to_many :special_tracks, :class=>:EagerTrack, :primary_key=>[:band_id, :id], :key=>[:id, :album_id]
772
- EagerTrack.dataset = EagerTrack.dataset.with_fetch(:album_id=>1, :id=>2)
773
- as = EagerAlbum.eager(:special_tracks).all
774
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE ((tracks.id, tracks.album_id) IN ((2, 1)))"]
775
- as.length.must_equal 1
776
- as.first.special_tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>2)]
777
- end
778
-
779
- it "should respect many_to_many association's composite keys" do
780
- EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :left_primary_key=>[:band_id, :id], :left_key=>[:l1, :l2], :right_primary_key=>[:xxx, :id], :right_key=>[:r1, :r2], :join_table=>:ag
781
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_0_x=>2, :x_foreign_key_1_x=>1, :id=>5}, {:x_foreign_key_0_x=>2, :x_foreign_key_1_x=>1, :id=>6}])
782
- as = EagerAlbum.eager(:special_genres).all
783
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.l1 AS x_foreign_key_0_x, ag.l2 AS x_foreign_key_1_x FROM genres INNER JOIN ag ON ((ag.r1 = genres.xxx) AND (ag.r2 = genres.id)) WHERE ((ag.l1, ag.l2) IN ((2, 1)))"]
784
- as.length.must_equal 1
785
- as.first.special_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
786
- end
787
-
788
- it "should respect one_through_one association's composite keys" do
789
- EagerAlbum.one_through_one :special_genre, :class=>:EagerGenre, :left_primary_key=>[:band_id, :id], :left_key=>[:l1, :l2], :right_primary_key=>[:xxx, :id], :right_key=>[:r1, :r2], :join_table=>:ag
790
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_0_x=>2, :x_foreign_key_1_x=>1, :id=>5}])
791
- as = EagerAlbum.eager(:special_genre).all
792
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.l1 AS x_foreign_key_0_x, ag.l2 AS x_foreign_key_1_x FROM genres INNER JOIN ag ON ((ag.r1 = genres.xxx) AND (ag.r2 = genres.id)) WHERE ((ag.l1, ag.l2) IN ((2, 1)))"]
793
- as.length.must_equal 1
794
- as.first.special_genre.must_equal EagerGenre.load(:id=>5)
795
- end
796
-
797
- it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
798
- EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_primary_key=>:xxx, :right_key=>:genre_id, :join_table=>:ag
799
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}])
800
- as = EagerAlbum.eager(:special_genres).all
801
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.xxx) WHERE (ag.album_id IN (2))"]
802
- as.length.must_equal 1
803
- as.first.special_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
804
- end
805
-
806
- it "should respect one_through_one association's :left_primary_key and :right_primary_key options" do
807
- EagerAlbum.one_through_one :special_genre, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_primary_key=>:xxx, :right_key=>:genre_id, :join_table=>:ag
808
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}])
809
- as = EagerAlbum.eager(:special_genre).all
810
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.xxx) WHERE (ag.album_id IN (2))"]
811
- as.length.must_equal 1
812
- as.first.special_genre.must_equal EagerGenre.load(:id=>5)
813
- end
814
-
815
- it "should respect the :limit option on a one_to_many association using the :ruby strategy" do
816
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>2, :eager_limit_strategy=>:ruby
817
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:album_id=>1, :id=>2}, {:album_id=>1, :id=>3}, {:album_id=>1, :id=>4}])
818
- as = EagerAlbum.eager(:first_two_tracks).all
819
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (1))"]
820
- as.length.must_equal 1
821
- as.first.first_two_tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>2), EagerTrack.load(:album_id=>1, :id=>3)]
822
-
823
- DB.reset
824
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>[1,1], :eager_limit_strategy=>:ruby
825
- as = EagerAlbum.eager(:first_two_tracks).all
826
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (1))"]
827
- as.length.must_equal 1
828
- as.first.first_two_tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>3)]
829
-
830
- DB.reset
831
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>[nil,1], :eager_limit_strategy=>:ruby
832
- as = EagerAlbum.eager(:first_two_tracks).all
833
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (1))"]
834
- as.length.must_equal 1
835
- as.first.first_two_tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>3), EagerTrack.load(:album_id=>1, :id=>4)]
836
- end
837
-
838
- it "should respect the :limit option on a one_to_many association" do
839
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>2
840
- a = EagerAlbum.eager(:tracks).all
841
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
842
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY name LIMIT 2) AS t1']
843
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
844
- DB.sqls.must_equal []
845
-
846
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>[2, 1]
847
- a = EagerAlbum.eager(:tracks).all
848
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
849
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY name LIMIT 2 OFFSET 1) AS t1']
850
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
851
- DB.sqls.must_equal []
852
-
853
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>[nil, 1]
854
- a = EagerAlbum.eager(:tracks).all
855
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
856
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY name OFFSET 1) AS t1']
857
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
858
- DB.sqls.must_equal []
859
- end
860
-
861
- it "should respect the :limit option on a one_to_many association with an association block" do
862
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>2 do |ds| ds.where(:a=>1) end
863
- a = EagerAlbum.eager(:tracks).all
864
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
865
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE ((a = 1) AND (1 = tracks.album_id)) ORDER BY name LIMIT 2) AS t1']
866
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
867
- DB.sqls.must_equal []
868
- end
869
-
870
- it "should respect the :limit option on a one_to_many association using the :window_function strategy" do
871
- EagerTrack.dataset = EagerTrack.dataset.with_extend{def supports_window_functions?; true end}
872
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>2, :eager_limit_strategy=>:window_function
873
- a = EagerAlbum.eager(:tracks).all
874
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
875
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x <= 2)']
876
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
877
- DB.sqls.must_equal []
878
-
879
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>[2, 1], :eager_limit_strategy=>:window_function
880
- a = EagerAlbum.eager(:tracks).all
881
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
882
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE ((x_sequel_row_number_x >= 2) AND (x_sequel_row_number_x < 4))']
883
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
884
- DB.sqls.must_equal []
885
-
886
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>[nil, 1], :eager_limit_strategy=>:window_function
887
- a = EagerAlbum.eager(:tracks).all
888
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
889
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x >= 2)']
890
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
891
- DB.sqls.must_equal []
892
- end
893
-
894
- it "should use a ruby strategy for limit if :eager_graph option is used" do
895
- EagerTrack.many_to_one :album2, :clone=>:album
896
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>2, :eager_graph=>:album2
897
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:album_id=>1, :id=>2, :album2_id=>1, :band_id=>5}, {:album_id=>1, :id=>3, :album2_id=>1, :band_id=>5}, {:album_id=>1, :id=>4, :album2_id=>1, :band_id=>5}])
898
- EagerTrack.dataset.columns(:id, :album_id)
899
- as = EagerAlbum.eager(:first_two_tracks).all
900
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT tracks.id, tracks.album_id, album2.id AS album2_id, album2.band_id FROM tracks LEFT OUTER JOIN albums AS album2 ON (album2.id = tracks.album_id) WHERE (tracks.album_id IN (1))"]
901
- as.length.must_equal 1
902
- tracks = as.first.first_two_tracks
903
- tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>2), EagerTrack.load(:album_id=>1, :id=>3)]
904
- tracks.first.album2.must_equal EagerAlbum.load(:id=>1, :band_id=>5)
905
- tracks.last.album2.must_equal EagerAlbum.load(:id=>1, :band_id=>5)
906
- end
907
-
908
- it "should not use a union strategy for limit by default if providing a per-eager load callback" do
909
- EagerTrack.dataset = EagerTrack.dataset.with_extend{def supports_window_functions?; true end}
910
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>2
911
- a = EagerAlbum.eager(:tracks=>proc{|ds| ds.where(:id=>3)}).all
912
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
913
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id ORDER BY name) AS x_sequel_row_number_x FROM tracks WHERE ((tracks.album_id IN (1)) AND (id = 3))) AS t1 WHERE (x_sequel_row_number_x <= 2)']
914
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
915
- DB.sqls.must_equal []
916
- end
917
-
918
- it "should respect the limit option on a many_to_many association using the :ruby strategy" do
919
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>2, :eager_limit_strategy=>:ruby
920
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}, {:x_foreign_key_x=>2, :id=>7}])
921
- as = EagerAlbum.eager(:first_two_genres).all
922
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (2))"]
923
- as.length.must_equal 1
924
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
925
-
926
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}, {:x_foreign_key_x=>2, :id=>7}])
927
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[1, 1], :eager_limit_strategy=>:ruby
928
- as = EagerAlbum.eager(:first_two_genres).all
929
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (2))"]
930
- as.length.must_equal 1
931
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>6)]
932
-
933
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}, {:x_foreign_key_x=>2, :id=>7}])
934
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[nil, 1], :eager_limit_strategy=>:ruby
935
- as = EagerAlbum.eager(:first_two_genres).all
936
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (2))"]
937
- as.length.must_equal 1
938
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>6), EagerGenre.load(:id=>7)]
939
- end
940
-
941
- it "should respect the limit option on a many_to_many association" do
942
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}]).with_extend{def supports_window_functions?; true end}
943
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>2, :order=>:name
944
- as = EagerAlbum.eager(:first_two_genres).all
945
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (2 = ag.album_id) ORDER BY name LIMIT 2) AS t1"]
946
- as.length.must_equal 1
947
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
948
-
949
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}])
950
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[1, 1], :order=>:name
951
- as = EagerAlbum.eager(:first_two_genres).all
952
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (2 = ag.album_id) ORDER BY name LIMIT 1 OFFSET 1) AS t1"]
953
- as.length.must_equal 1
954
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5)]
955
-
956
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}])
957
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[nil, 1], :order=>:name
958
- as = EagerAlbum.eager(:first_two_genres).all
959
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (2 = ag.album_id) ORDER BY name OFFSET 1) AS t1"]
960
- as.length.must_equal 1
961
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
962
- end
963
-
964
- it "should respect the limit option on a many_to_many association using the :window_function strategy" do
965
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}]).with_extend{def supports_window_functions?; true end}
966
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>2, :order=>:name, :eager_limit_strategy=>:window_function
967
- as = EagerAlbum.eager(:first_two_genres).all
968
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x, row_number() OVER (PARTITION BY ag.album_id ORDER BY name) AS x_sequel_row_number_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (2))) AS t1 WHERE (x_sequel_row_number_x <= 2)"]
969
- as.length.must_equal 1
970
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
971
-
972
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}])
973
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[1, 1], :order=>:name, :eager_limit_strategy=>:window_function
974
- as = EagerAlbum.eager(:first_two_genres).all
975
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x, row_number() OVER (PARTITION BY ag.album_id ORDER BY name) AS x_sequel_row_number_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (2))) AS t1 WHERE ((x_sequel_row_number_x >= 2) AND (x_sequel_row_number_x < 3))"]
976
- as.length.must_equal 1
977
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5)]
978
-
979
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}])
980
- EagerAlbum.many_to_many :first_two_genres, :class=>:EagerGenre, :left_primary_key=>:band_id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[nil, 1], :order=>:name, :eager_limit_strategy=>:window_function
981
- as = EagerAlbum.eager(:first_two_genres).all
982
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x, row_number() OVER (PARTITION BY ag.album_id ORDER BY name) AS x_sequel_row_number_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (2))) AS t1 WHERE (x_sequel_row_number_x >= 2)"]
983
- as.length.must_equal 1
984
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
985
- end
986
-
987
- it "should use the :eager_loader association option when eager loading" do
988
- EagerAlbum.many_to_one :special_band, :key=>:band_id, :eager_loader=>(proc do |eo|
989
- item = EagerBand.filter(:album_id=>eo[:rows].collect{|r| [r.pk, r.pk*2]}.flatten).order(:name).first
990
- eo[:rows].each{|r| r.associations[:special_band] = item}
991
- end)
992
- EagerAlbum.one_to_many :special_tracks, :eager_loader=>(proc do |eo|
993
- items = EagerTrack.filter(:album_id=>eo[:rows].collect{|r| [r.pk, r.pk*2]}.flatten).all
994
- eo[:rows].each{|r| r.associations[:special_tracks] = items}
995
- end)
996
- EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :eager_loader=>(proc do |eo|
997
- items = EagerGenre.inner_join(:ag, [:genre_id]).filter(:album_id=>eo[:rows].collect{|r| r.pk}).all
998
- eo[:rows].each{|r| r.associations[:special_genres] = items}
999
- end)
1000
- a = EagerAlbum.eager(:special_genres, :special_tracks, :special_band).all
1001
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1002
- sqls = DB.sqls
1003
- sqls.shift.must_equal 'SELECT * FROM albums'
1004
- sqls.sort.must_equal ['SELECT * FROM bands WHERE (album_id IN (1, 2)) ORDER BY name LIMIT 1',
1005
- 'SELECT * FROM genres INNER JOIN ag USING (genre_id) WHERE (album_id IN (1))',
1006
- 'SELECT * FROM tracks WHERE (album_id IN (1, 2))']
1007
- a = a.first
1008
- a.special_band.must_equal EagerBand.load(:id => 2)
1009
- a.special_tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
1010
- a.special_genres.must_equal [EagerGenre.load(:id => 4)]
1011
- DB.sqls.must_equal []
1012
- end
1013
-
1014
- it "should respect :after_load callbacks on associations when eager loading" do
1015
- EagerAlbum.many_to_one :al_band, :class=>'EagerBand', :key=>:band_id, :after_load=>proc{|o, a| a.id *=2}
1016
- EagerAlbum.one_to_many :al_tracks, :class=>'EagerTrack', :key=>:album_id, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
1017
- EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
1018
- a = EagerAlbum.eager(:al_band, :al_tracks, :al_genres).all.first
1019
- a.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1020
- a.al_band.must_equal EagerBand.load(:id=>4)
1021
- a.al_tracks.must_equal [EagerTrack.load(:id=>6, :album_id=>1)]
1022
- a.al_genres.must_equal [EagerGenre.load(:id=>8)]
1023
- end
1024
-
1025
- it "should respect :uniq option when eagerly loading many_to_many associations" do
1026
- EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :uniq=>true
1027
- EagerGenre.dataset = EagerGenre.dataset.with_fetch([{:x_foreign_key_x=>1, :id=>8}, {:x_foreign_key_x=>1, :id=>8}])
1028
- a = EagerAlbum.eager(:al_genres).all.first
1029
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
1030
- a.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1031
- a.al_genres.must_equal [EagerGenre.load(:id=>8)]
1032
- end
1033
-
1034
- it "should respect :distinct option when eagerly loading many_to_many associations" do
1035
- EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :distinct=>true
1036
- a = EagerAlbum.eager(:al_genres).all.first
1037
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT DISTINCT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
1038
- a.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1039
- a.al_genres.must_equal [EagerGenre.load(:id=>4)]
1040
- end
1041
-
1042
- it "should eagerly load a many_to_one association with custom eager block" do
1043
- a = EagerAlbum.eager(:band => proc {|ds| ds.select(:id, :name)}).all
1044
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1045
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT id, name FROM bands WHERE (bands.id IN (2))']
1046
- a.first.band.must_equal EagerBand.load(:id => 2)
1047
- DB.sqls.must_equal []
1048
- end
1049
-
1050
- it "should eagerly load a one_to_one association with custom eager block" do
1051
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id
1052
- a = EagerAlbum.eager(:track => proc {|ds| ds.select(:id)}).all
1053
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1054
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT id FROM tracks WHERE (tracks.album_id IN (1))']
1055
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
1056
- DB.sqls.must_equal []
1057
- end
1058
-
1059
- it "should eagerly load a one_to_many association with custom eager block" do
1060
- a = EagerAlbum.eager(:tracks => proc {|ds| ds.select(:id)}).all
1061
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1062
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT id FROM tracks WHERE (tracks.album_id IN (1))']
1063
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
1064
- DB.sqls.must_equal []
1065
- end
1066
-
1067
- it "should eagerly load a many_to_many association with custom eager block" do
1068
- a = EagerAlbum.eager(:genres => proc {|ds| ds.select(:name)}).all
1069
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1070
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT name, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
1071
- a.first.genres.must_equal [EagerGenre.load(:id => 4)]
1072
- DB.sqls.must_equal []
1073
- end
1074
-
1075
- it "should eagerly load a one_through_one association with custom eager block" do
1076
- a = EagerAlbum.eager(:genre => proc {|ds| ds.select(:name)}).all
1077
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1078
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT name, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
1079
- a.first.genre.must_equal EagerGenre.load(:id => 4)
1080
- DB.sqls.must_equal []
1081
- end
1082
-
1083
- it "should allow cascading of eager loading within a custom eager block" do
1084
- a = EagerTrack.eager(:album => proc {|ds| ds.eager(:band => :members)}).all
1085
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1086
- DB.sqls.must_equal ['SELECT * FROM tracks',
1087
- 'SELECT * FROM albums WHERE (albums.id IN (1))',
1088
- 'SELECT * FROM bands WHERE (bands.id IN (2))',
1089
- "SELECT members.*, bm.band_id AS x_foreign_key_x FROM members INNER JOIN bm ON (bm.member_id = members.id) WHERE (bm.band_id IN (2))"]
1090
- a = a.first
1091
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1092
- a.album.band.must_equal EagerBand.load(:id => 2)
1093
- a.album.band.members.must_equal [EagerBandMember.load(:id => 5)]
1094
- DB.sqls.must_equal []
1095
- end
1096
-
1097
- it "should allow cascading of eager loading with custom callback with hash value" do
1098
- a = EagerTrack.eager(:album=>{proc{|ds| ds.select(:id, :band_id)}=>{:band => :members}}).all
1099
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1100
- DB.sqls.must_equal ['SELECT * FROM tracks',
1101
- 'SELECT id, band_id FROM albums WHERE (albums.id IN (1))',
1102
- 'SELECT * FROM bands WHERE (bands.id IN (2))',
1103
- "SELECT members.*, bm.band_id AS x_foreign_key_x FROM members INNER JOIN bm ON (bm.member_id = members.id) WHERE (bm.band_id IN (2))"]
1104
- a = a.first
1105
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1106
- a.album.band.must_equal EagerBand.load(:id => 2)
1107
- a.album.band.members.must_equal [EagerBandMember.load(:id => 5)]
1108
- DB.sqls.must_equal []
1109
- end
1110
-
1111
- it "should allow cascading of eager loading with custom callback with symbol value" do
1112
- a = EagerTrack.eager(:album=>{proc{|ds| ds.select(:id, :band_id)}=>:band}).all
1113
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1114
- DB.sqls.must_equal ['SELECT * FROM tracks',
1115
- 'SELECT id, band_id FROM albums WHERE (albums.id IN (1))',
1116
- 'SELECT * FROM bands WHERE (bands.id IN (2))']
1117
- a = a.first
1118
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1119
- a.album.band.must_equal EagerBand.load(:id => 2)
1120
- DB.sqls.must_equal []
1121
- end
1122
-
1123
- it "should allow cascading of eager loading with custom callback with symbol value when association has a limit" do
1124
- EagerAlbum.dataset = EagerAlbum.dataset.with_fetch((1..11).map{|i| {:band_id=>2, :id=>i}})
1125
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:id=>3, :album_id=>1}])
1126
- a = EagerBand.eager(:top_10_albums=>{proc{|ds| ds.select(:id, :name)}=>:tracks}).all
1127
- a.must_equal [EagerBand.load(:id => 2)]
1128
- DB.sqls.must_equal ['SELECT * FROM bands',
1129
- 'SELECT id, name FROM albums WHERE (albums.band_id IN (2))',
1130
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11))']
1131
- a = a.first
1132
- a.top_10_albums.must_equal((1..10).map{|i| EagerAlbum.load(:band_id=>2, :id=>i)})
1133
- a.top_10_albums.map{|x| x.tracks}.must_equal [[EagerTrack.load(:id => 3, :album_id=>1)]] + ([[]] * 9)
1134
- DB.sqls.must_equal []
1135
- end
1136
-
1137
- it "should allow cascading of eager loading with custom callback with symbol value when association has a limit when using window function eager limit strategy" do
1138
- EagerAlbum.dataset = EagerAlbum.dataset.with_fetch(:band_id=>2, :id=>1).with_extend{def supports_window_functions?; true end}
1139
- EagerTrack.dataset = EagerTrack.dataset.with_fetch([{:id=>3, :album_id=>1}])
1140
- a = EagerBand.eager(:top_10_albums=>{proc{|ds| ds.select(:id, :name)}=>:tracks}).all
1141
- a.must_equal [EagerBand.load(:id => 2)]
1142
- DB.sqls.must_equal ['SELECT * FROM bands',
1143
- 'SELECT * FROM (SELECT id, name, row_number() OVER (PARTITION BY albums.band_id) AS x_sequel_row_number_x FROM albums WHERE (albums.band_id IN (2))) AS t1 WHERE (x_sequel_row_number_x <= 10)',
1144
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
1145
- a = a.first
1146
- a.top_10_albums.must_equal [EagerAlbum.load(:band_id=>2, :id=>1)]
1147
- a.top_10_albums.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
1148
- DB.sqls.must_equal []
1149
- end
1150
-
1151
- it "should allow cascading of eager loading with custom callback with array value" do
1152
- a = EagerTrack.eager(:album=>{proc{|ds| ds.select(:id, :band_id)}=>[:band, :band_name]}).all
1153
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1154
- sqls = DB.sqls
1155
- sqls.slice!(0..1).must_equal ['SELECT * FROM tracks',
1156
- 'SELECT id, band_id FROM albums WHERE (albums.id IN (1))']
1157
- sqls.sort.must_equal ['SELECT * FROM bands WHERE (bands.id IN (2))',
1158
- 'SELECT id, name FROM bands WHERE (bands.id IN (2))']
1159
- a = a.first
1160
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1161
- a.album.band.must_equal EagerBand.load(:id => 2)
1162
- a.album.band_name.must_equal EagerBand.load(:id => 2)
1163
- DB.sqls.must_equal []
1164
- end
1165
-
1166
- it "should call both association and custom eager blocks" do
1167
- EagerBand.eager(:good_albums => proc {|ds| ds.select(:name)}).all
1168
- DB.sqls.must_equal ['SELECT * FROM bands', "SELECT name FROM albums WHERE ((name = 'good') AND (albums.band_id IN (2)))"]
1169
- end
1170
-
1171
- it "should respect an :eager_limit option passed in a custom callback" do
1172
- EagerTrack.dataset = EagerTrack.dataset.with_extend{def supports_window_functions?; true end}
1173
- a = EagerAlbum.eager(:tracks=> proc{|ds| ds.clone(:eager_limit=>5)}).all
1174
- a.must_equal [EagerAlbum.load(:id => 1, :band_id=> 2)]
1175
- sqls = DB.sqls
1176
- sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x <= 5)']
1177
- a = a.first
1178
- a.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1179
- DB.sqls.must_equal []
1180
- end
1181
-
1182
- it "should respect an :eager_limit option that includes an offset" do
1183
- EagerTrack.dataset = EagerTrack.dataset.with_extend{def supports_window_functions?; true end}
1184
- EagerAlbum.eager(:tracks=> proc{|ds| ds.clone(:eager_limit=>[5, 5])}).all
1185
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE ((x_sequel_row_number_x >= 6) AND (x_sequel_row_number_x < 11))']
1186
- end
1187
-
1188
- it "should have an :eager_limit option passed in a custom callback override a :limit defined in the association" do
1189
- EagerTrack.dataset = EagerTrack.dataset.with_extend{def supports_window_functions?; true end}
1190
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>2
1191
- EagerAlbum.eager(:first_two_tracks=> proc{|ds| ds.clone(:eager_limit=>5)}).all
1192
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x <= 5)']
1193
- end
1194
-
1195
- it "should respect an :eager_limit_strategy option passed in a custom callback" do
1196
- EagerTrack.dataset = EagerTrack.dataset.with_fetch((1..4).map{|i| {:album_id=>1, :id=>i}}).with_extend{def supports_window_functions?; true end}
1197
- a = EagerAlbum.eager(:tracks=> proc{|ds| ds.clone(:eager_limit=>2, :eager_limit_strategy=>:ruby)}).all
1198
- a.must_equal [EagerAlbum.load(:id => 1, :band_id=> 2)]
1199
- sqls = DB.sqls
1200
- sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
1201
- a = a.first
1202
- a.tracks.must_equal [EagerTrack.load(:id => 1, :album_id => 1), EagerTrack.load(:id => 2, :album_id => 1)]
1203
- DB.sqls.must_equal []
1204
- end
1205
-
1206
- it "should have an :eager_limit_strategy option passed in a custom callback override a :eager_limit_strategy defined in the association" do
1207
- EagerTrack.dataset = EagerTrack.dataset.with_extend{def supports_window_functions?; true end}
1208
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>2, :eager_limit_strategy=>:ruby
1209
- EagerAlbum.eager(:first_two_tracks=> proc{|ds| ds.clone(:eager_limit_strategy=>:window_function)}).all
1210
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks WHERE (tracks.album_id IN (1))) AS t1 WHERE (x_sequel_row_number_x <= 2)']
1211
- end
1212
-
1213
- it "should raise error if using :eager_limit for a singular association" do
1214
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id
1215
- proc{EagerAlbum.eager(:track=> proc{|ds| ds.clone(:eager_limit=>1)}).all}.must_raise Sequel::Error
1216
- DB.sqls.must_equal ['SELECT * FROM albums']
1217
- end
1218
-
1219
- it "should raise error if using :eager_limit for a singular association" do
1220
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:name
1221
- a = EagerAlbum.eager(:track=> proc{|ds| ds.order(:foo)}).all
1222
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1)) ORDER BY foo']
1223
- a = a.first
1224
- a.track.must_equal EagerTrack.load(:id => 3, :album_id => 1)
1225
- DB.sqls.must_equal []
1226
- end
1227
-
1228
- it "should support eager load of many_to_one with eager_graph of many_to_one in custom callback" do
1229
- a = EagerTrack.eager(:album=>proc{|ds| ds.eager_graph(:band).with_fetch(:id=>1, :band_id=>2, :band_id_0=>2)}).all
1230
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1231
- DB.sqls.must_equal ["SELECT * FROM tracks",
1232
- "SELECT albums.id, albums.band_id, band.id AS band_id_0 FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) WHERE (albums.id IN (1))"]
1233
- a = a.first
1234
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1235
- a.album.band.must_equal EagerBand.load(:id => 2)
1236
- DB.sqls.must_equal []
1237
- end
1238
-
1239
- it "should support eager load of many_to_one with eager_graph of one_to_many in custom callback" do
1240
- a = EagerTrack.eager(:album=>proc{|ds| ds.eager_graph(:tracks).with_fetch(:id=>1, :band_id=>2, :tracks_id=>3)}).all
1241
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1242
- DB.sqls.must_equal ["SELECT * FROM tracks",
1243
- "SELECT albums.id, albums.band_id, tracks.id AS tracks_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) WHERE (albums.id IN (1))"]
1244
- a = a.first
1245
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1246
- a.album.tracks.must_equal [EagerTrack.load(:id=>3)]
1247
- DB.sqls.must_equal []
1248
- end
1249
-
1250
- it "should support eager load of many_to_one with eager_graph of many_to_many in custom callback" do
1251
- a = EagerTrack.eager(:album=>proc{|ds| ds.eager_graph(:genres).with_fetch(:id=>1, :band_id=>2, :genres_id=>4)}).all
1252
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1253
- DB.sqls.must_equal ["SELECT * FROM tracks",
1254
- "SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) WHERE (albums.id IN (1))"]
1255
- a = a.first
1256
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1257
- a.album.genres.must_equal [EagerGenre.load(:id=>4)]
1258
- DB.sqls.must_equal []
1259
- end
1260
-
1261
- it "should support eager load of many_to_many with eager_graph of many_to_one in custom callback" do
1262
- a = EagerGenre.eager(:albums=>proc{|ds| ds.columns(:id, :band_id, :x_foreign_key_x).eager_graph(:band).with_fetch(:id=>1, :band_id=>2, :x_foreign_key_x=>4, :band_id_0=>2)}).all
1263
- a.must_equal [EagerGenre.load(:id => 4)]
1264
- DB.sqls.must_equal ["SELECT * FROM genres",
1265
- "SELECT albums.id, albums.band_id, albums.x_foreign_key_x, band.id AS band_id_0 FROM (SELECT albums.*, ag.genre_id AS x_foreign_key_x FROM albums INNER JOIN ag ON (ag.album_id = albums.id) WHERE (ag.genre_id IN (4))) AS albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)"]
1266
- a = a.first
1267
- a.albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1268
- a.albums.first.band.must_equal EagerBand.load(:id=>2)
1269
- DB.sqls.must_equal []
1270
- end
1271
-
1272
- it "should support eager load of many_to_many with eager_graph of one_to_many in custom callback" do
1273
- a = EagerGenre.eager(:albums=>proc{|ds| ds.columns(:id, :band_id, :x_foreign_key_x).eager_graph(:tracks).with_fetch(:id=>1, :band_id=>2, :x_foreign_key_x=>4, :tracks_id=>5)}).all
1274
- a.must_equal [EagerGenre.load(:id => 4)]
1275
- DB.sqls.must_equal ["SELECT * FROM genres",
1276
- "SELECT albums.id, albums.band_id, albums.x_foreign_key_x, tracks.id AS tracks_id FROM (SELECT albums.*, ag.genre_id AS x_foreign_key_x FROM albums INNER JOIN ag ON (ag.album_id = albums.id) WHERE (ag.genre_id IN (4))) AS albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)"]
1277
- a = a.first
1278
- a.albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1279
- a.albums.first.tracks.must_equal [EagerTrack.load(:id=>5)]
1280
- DB.sqls.must_equal []
1281
- end
1282
-
1283
- it "should support eager load of many_to_many with eager_graph of many_to_many in custom callback" do
1284
- a = EagerGenre.eager(:albums=>proc{|ds| ds.columns(:id, :band_id, :x_foreign_key_x).eager_graph(:genres).with_fetch(:id=>1, :band_id=>2, :x_foreign_key_x=>4, :genres_id=>4)}).all
1285
- a.must_equal [EagerGenre.load(:id => 4)]
1286
- DB.sqls.must_equal ["SELECT * FROM genres",
1287
- "SELECT albums.id, albums.band_id, albums.x_foreign_key_x, genres.id AS genres_id FROM (SELECT albums.*, ag.genre_id AS x_foreign_key_x FROM albums INNER JOIN ag ON (ag.album_id = albums.id) WHERE (ag.genre_id IN (4))) AS albums LEFT OUTER JOIN ag AS ag_0 ON (ag_0.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag_0.genre_id)"]
1288
- a = a.first
1289
- a.albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1290
- a.albums.first.genres.must_equal [EagerGenre.load(:id=>4)]
1291
- DB.sqls.must_equal []
1292
- end
1293
-
1294
- it "should support eager_graph usage with cascaded associations in custom callback" do
1295
- a = EagerTrack.eager(:album=>proc{|ds| ds.eager_graph(:band=>:members).with_fetch(:id=>1, :band_id=>2, :band_id_0=>2, :members_id=>5)}).all
1296
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1297
- DB.sqls.must_equal ["SELECT * FROM tracks",
1298
- "SELECT albums.id, albums.band_id, band.id AS band_id_0, members.id AS members_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) WHERE (albums.id IN (1))"]
1299
- a = a.first
1300
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1301
- a.album.band.must_equal EagerBand.load(:id => 2)
1302
- a.album.band.members.must_equal [EagerBandMember.load(:id => 5)]
1303
- DB.sqls.must_equal []
1304
- end
1305
-
1306
- it "should support eager_graph usage in custom callback with dependencies" do
1307
- a = EagerTrack.eager(:album=>{proc{|ds| ds.eager_graph(:band).with_fetch(:id=>1, :band_id=>2, :band_id_0=>2)}=>:genre}).all
1308
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1309
- DB.sqls.must_equal ["SELECT * FROM tracks",
1310
- "SELECT albums.id, albums.band_id, band.id AS band_id_0 FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) WHERE (albums.id IN (1))",
1311
- "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
1312
- a = a.first
1313
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1314
- a.album.band.must_equal EagerBand.load(:id => 2)
1315
- a.album.genre.must_equal EagerGenre.load(:id => 4)
1316
- DB.sqls.must_equal []
1317
- end
1318
- end
1319
-
1320
- describe Sequel::Model, "#eager_graph" do
1321
- before(:all) do
1322
- class ::GraphAlbum < Sequel::Model(:albums)
1323
- columns :id, :band_id
1324
- many_to_one :band, :class=>'GraphBand', :key=>:band_id
1325
- one_to_many :tracks, :class=>'GraphTrack', :key=>:album_id
1326
- one_to_one :track, :class=>'GraphTrack', :key=>:album_id
1327
- many_to_many :genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
1328
- one_through_one :genre, :clone=>:genres
1329
- many_to_one :previous_album, :class=>'GraphAlbum'
1330
- end
1331
-
1332
- class ::GraphBand < Sequel::Model(:bands)
1333
- columns :id, :vocalist_id
1334
- many_to_one :vocalist, :class=>'GraphBandMember', :key=>:vocalist_id
1335
- one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id
1336
- many_to_many :members, :class=>'GraphBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
1337
- many_to_many :genres, :class=>'GraphGenre', :left_key=>:band_id, :right_key=>:genre_id, :join_table=>:bg
1338
- end
1339
-
1340
- class ::GraphTrack < Sequel::Model(:tracks)
1341
- columns :id, :album_id
1342
- many_to_one :album, :class=>'GraphAlbum', :key=>:album_id
1343
- end
1344
-
1345
- class ::GraphGenre < Sequel::Model(:genres)
1346
- columns :id
1347
- many_to_many :albums, :class=>'GraphAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
1348
- end
1349
-
1350
- class ::GraphBandMember < Sequel::Model(:members)
1351
- columns :id
1352
- many_to_many :bands, :class=>'GraphBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm
1353
- end
1354
- end
1355
- before do
1356
- DB.sqls
1357
- end
1358
- after(:all) do
1359
- [:GraphAlbum, :GraphBand, :GraphTrack, :GraphGenre, :GraphBandMember].each{|x| Object.send(:remove_const, x)}
1360
- end
1361
-
1362
- it "should raise an error if called without a symbol or hash" do
1363
- proc{GraphAlbum.eager_graph(Object.new)}.must_raise(Sequel::Error)
1364
- end
1365
-
1366
- it "should work correctly with select_map" do
1367
- ds = GraphAlbum.eager_graph(:band)
1368
- ds.with_fetch([{:id=>1}, {:id=>2}]).select_map(Sequel[:albums][:id]).must_equal [1, 2]
1369
- DB.sqls.must_equal ['SELECT albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)']
1370
- ds.with_fetch([{:id=>1}, {:id=>2}]).select_map([Sequel[:albums][:id], Sequel[:albums][:id]]).must_equal [[1, 1], [2, 2]]
1371
- DB.sqls.must_equal ['SELECT albums.id, albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)']
1372
- end
1373
-
1374
- it "should work correctly with single_value" do
1375
- ds = GraphAlbum.eager_graph(:band).select(Sequel[:albums][:id])
1376
- ds.with_fetch([{:id=>1}]).single_value.must_equal 1
1377
- DB.sqls.must_equal ['SELECT albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) LIMIT 1']
1378
- end
1379
-
1380
- it "should not split results and assign associations if ungraphed is called" do
1381
- ds = GraphAlbum.eager_graph(:band).ungraphed
1382
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
1383
- ds.with_fetch(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3).all.must_equal [GraphAlbum.load(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3)]
1384
- end
1385
-
1386
- it "should not modify existing dataset" do
1387
- ds1 = GraphAlbum.dataset
1388
- ds2 = ds1.eager_graph(:band)
1389
- ds1.eager_graph(:band)
1390
- ds2.eager_graph(:tracks)
1391
- ds2.eager_graph(:tracks)
1392
- end
1393
-
1394
- it "should allow manually selecting the alias base per call via an AliasedExpression" do
1395
- ds = GraphAlbum.eager_graph(Sequel.as(:band, :b))
1396
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, b.id AS b_id, b.vocalist_id FROM albums LEFT OUTER JOIN bands AS b ON (b.id = albums.band_id)'
1397
- a = ds.with_fetch(:id=>1, :band_id=>2, :b_id=>2, :vocalist_id=>3).all
1398
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1399
- a.first.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1400
- end
1401
-
1402
- it "should handle multiple associations using the same alias base" do
1403
- ds = GraphAlbum.eager_graph(Sequel.as(:genres, :b), Sequel.as(:tracks, :b), Sequel.as(:band, :b))
1404
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, b.id AS b_id, b_0.id AS b_0_id, b_0.album_id, b_1.id AS b_1_id, b_1.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS b ON (b.id = ag.genre_id) LEFT OUTER JOIN tracks AS b_0 ON (b_0.album_id = albums.id) LEFT OUTER JOIN bands AS b_1 ON (b_1.id = albums.band_id)'
1405
- a = ds.with_fetch(:id=>1, :band_id=>2, :b_id=>4, :b_0_id=>3, :album_id=>1, :b_1_id=>2, :vocalist_id=>6).all
1406
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1407
- a = a.first
1408
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1409
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1410
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1411
-
1412
- ds = GraphTrack.eager_graph(Sequel.as(:album, :b)=>{Sequel.as(:band, :b)=>Sequel.as(:members, :b)})
1413
- ds.sql.must_equal 'SELECT tracks.id, tracks.album_id, b.id AS b_id, b.band_id, b_0.id AS b_0_id, b_0.vocalist_id, b_1.id AS b_1_id FROM tracks LEFT OUTER JOIN albums AS b ON (b.id = tracks.album_id) LEFT OUTER JOIN bands AS b_0 ON (b_0.id = b.band_id) LEFT OUTER JOIN bm ON (bm.band_id = b_0.id) LEFT OUTER JOIN members AS b_1 ON (b_1.id = bm.member_id)'
1414
- a = ds.with_fetch(:id=>3, :album_id=>1, :b_id=>1, :band_id=>2, :b_1_id=>5, :b_0_id=>2, :vocalist_id=>6).all
1415
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
1416
- a = a.first
1417
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
1418
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1419
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
1420
- end
1421
-
1422
- it "should set up correct inner joins when using association_join" do
1423
- GraphAlbum.association_join(:band).sql.must_equal 'SELECT * FROM albums INNER JOIN bands AS band ON (band.id = albums.band_id)'
1424
- GraphAlbum.association_join(:track).sql.must_equal 'SELECT * FROM albums INNER JOIN tracks AS track ON (track.album_id = albums.id)'
1425
- GraphAlbum.association_join(:tracks).sql.must_equal 'SELECT * FROM albums INNER JOIN tracks ON (tracks.album_id = albums.id)'
1426
- GraphAlbum.association_join(:genres).sql.must_equal 'SELECT * FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres ON (genres.id = ag.genre_id)'
1427
- GraphAlbum.association_join(:genre).sql.must_equal 'SELECT * FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres AS genre ON (genre.id = ag.genre_id)'
1428
- end
1429
-
1430
- it "should handle custom selects when using association_join" do
1431
- GraphAlbum.select{a(b)}.association_join(:band).sql.must_equal 'SELECT a(b) FROM albums INNER JOIN bands AS band ON (band.id = albums.band_id)'
1432
- GraphAlbum.select{a(b)}.association_join(:track).sql.must_equal 'SELECT a(b) FROM albums INNER JOIN tracks AS track ON (track.album_id = albums.id)'
1433
- GraphAlbum.select{a(b)}.association_join(:tracks).sql.must_equal 'SELECT a(b) FROM albums INNER JOIN tracks ON (tracks.album_id = albums.id)'
1434
- GraphAlbum.select{a(b)}.association_join(:genres).sql.must_equal 'SELECT a(b) FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres ON (genres.id = ag.genre_id)'
1435
- GraphAlbum.select{a(b)}.association_join(:genre).sql.must_equal 'SELECT a(b) FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres AS genre ON (genre.id = ag.genre_id)'
1436
- end
1437
-
1438
- it "should set up correct join types when using association_*_join" do
1439
- GraphAlbum.association_inner_join(:band).sql.must_equal 'SELECT * FROM albums INNER JOIN bands AS band ON (band.id = albums.band_id)'
1440
- GraphAlbum.association_left_join(:track).sql.must_equal 'SELECT * FROM albums LEFT JOIN tracks AS track ON (track.album_id = albums.id)'
1441
- GraphAlbum.association_right_join(:tracks).sql.must_equal 'SELECT * FROM albums RIGHT JOIN tracks ON (tracks.album_id = albums.id)'
1442
- GraphAlbum.association_full_join(:genres).sql.must_equal 'SELECT * FROM albums FULL JOIN ag ON (ag.album_id = albums.id) FULL JOIN genres ON (genres.id = ag.genre_id)'
1443
- end
1444
-
1445
- it "should eagerly load a single many_to_one association" do
1446
- ds = GraphAlbum.eager_graph(:band)
1447
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
1448
- a = ds.with_fetch(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3).all
1449
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1450
- a.first.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1451
- end
1452
-
1453
- it "should eagerly load a single many_to_one association with the same name as a column" do
1454
- GraphAlbum.def_column_alias(:band_id_id, :band_id)
1455
- GraphAlbum.many_to_one :band_id, :key_column=>:band_id, :class=>GraphBand
1456
- ds = GraphAlbum.eager_graph(:band_id)
1457
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, band_id.id AS band_id_id, band_id.vocalist_id FROM albums LEFT OUTER JOIN bands AS band_id ON (band_id.id = albums.band_id)'
1458
- a = ds.with_fetch(:id=>1, :band_id=>2, :band_id_id=>2, :vocalist_id=>3).all
1459
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1460
- a.first.band_id.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1461
- end
1462
-
1463
- it "should support :join_type eager_graph option one_to_one association" do
1464
- ds = GraphAlbum.eager_graph_with_options(:track, :join_type=>:inner)
1465
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, track.id AS track_id, track.album_id FROM albums INNER JOIN tracks AS track ON (track.album_id = albums.id)'
1466
- a = ds.with_fetch(:id=>1, :band_id=>2, :track_id=>3, :album_id=>1).all
1467
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1468
- a.first.track.must_equal GraphTrack.load(:id => 3, :album_id=>1)
1469
- end
1470
-
1471
- it "should eagerly load a single one_to_one association" do
1472
- ds = GraphAlbum.eager_graph(:track)
1473
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, track.id AS track_id, track.album_id FROM albums LEFT OUTER JOIN tracks AS track ON (track.album_id = albums.id)'
1474
- a = ds.with_fetch(:id=>1, :band_id=>2, :track_id=>3, :album_id=>1).all
1475
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1476
- a.first.track.must_equal GraphTrack.load(:id => 3, :album_id=>1)
1477
- end
1478
-
1479
- it "should eagerly graph a single one_to_one association using the :distinct_on strategy" do
1480
- sub = Class.new(GraphTrack)
1481
- sub.dataset = sub.dataset.with_extend do
1482
- def supports_distinct_on?; true end
1483
- def columns; [:id, :album_id] end
1484
- end
1485
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1486
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>true)
1487
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, ltrack.id AS ltrack_id, ltrack.album_id FROM albums LEFT OUTER JOIN (SELECT DISTINCT ON (tracks.album_id) * FROM tracks ORDER BY tracks.album_id) AS ltrack ON (ltrack.album_id = albums.id)'
1488
- a = ds.with_fetch(:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1).all
1489
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1490
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1491
- end
1492
-
1493
- it "should eagerly graph a single one_to_one association using the :window_function strategy" do
1494
- sub = Class.new(GraphTrack)
1495
- sub.dataset = sub.dataset.with_extend do
1496
- def supports_window_functions?; true end
1497
- def columns; [:id, :album_id] end
1498
- end
1499
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1500
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>true)
1501
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, ltrack.id AS ltrack_id, ltrack.album_id FROM albums LEFT OUTER JOIN (SELECT id, album_id FROM (SELECT *, 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)) AS ltrack ON (ltrack.album_id = albums.id)'
1502
- a = ds.with_fetch(:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1).all
1503
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1504
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1505
- end
1506
-
1507
- it "should eagerly graph a single one_to_one association using the :correlated_subquery strategy" do
1508
- sub = Class.new(GraphTrack)
1509
- sub.dataset = sub.dataset.with_extend do
1510
- def supports_window_functions?; true end
1511
- def columns; [:id, :album_id] end
1512
- end
1513
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1514
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>:correlated_subquery)
1515
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, ltrack.id AS ltrack_id, ltrack.album_id FROM albums LEFT OUTER JOIN (SELECT * FROM tracks WHERE (tracks.id IN (SELECT t1.id FROM tracks AS t1 WHERE (t1.album_id = tracks.album_id) LIMIT 1))) AS ltrack ON (ltrack.album_id = albums.id)'
1516
- a = ds.with_fetch(:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1).all
1517
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1518
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1519
- end
1520
-
1521
- it "should eagerly load a single one_to_many association" do
1522
- ds = GraphAlbum.eager_graph(:tracks)
1523
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)'
1524
- a = ds.with_fetch(:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1).all
1525
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1526
- a.first.tracks.must_equal [GraphTrack.load(:id => 3, :album_id=>1)]
1527
- end
1528
-
1529
- it "should eagerly graph a single one_to_many association using the :window_function strategy" do
1530
- sub = Class.new(GraphTrack)
1531
- sub.dataset = sub.dataset.with_extend do
1532
- def supports_window_functions?; true end
1533
- def columns; [:id, :album_id] end
1534
- end
1535
- GraphAlbum.one_to_many :ltracks, :clone=>:tracks, :limit=>2, :class=>sub
1536
- ds = GraphAlbum.eager_graph_with_options(:ltracks, :limit_strategy=>true)
1537
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, ltracks.id AS ltracks_id, ltracks.album_id FROM albums LEFT OUTER JOIN (SELECT id, album_id FROM (SELECT *, row_number() OVER (PARTITION BY tracks.album_id) AS x_sequel_row_number_x FROM tracks) AS t1 WHERE (x_sequel_row_number_x <= 2)) AS ltracks ON (ltracks.album_id = albums.id)'
1538
- a = ds.with_fetch(:id=>1, :band_id=>2, :ltracks_id=>3, :album_id=>1).all
1539
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1540
- a.first.ltracks.must_equal [sub.load(:id => 3, :album_id=>1)]
1541
- end
1542
-
1543
- it "should eagerly load a single many_to_many association" do
1544
- ds = GraphAlbum.eager_graph(:genres)
1545
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id)'
1546
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>4).all
1547
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1548
- a.first.genres.must_equal [GraphGenre.load(:id => 4)]
1549
- end
1550
-
1551
- it "should eagerly graph a single many_to_many association using the :window_function strategy" do
1552
- sub = Class.new(GraphGenre)
1553
- sub.dataset = sub.dataset.with_extend do
1554
- def supports_window_functions?; true end
1555
- def columns; literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1556
- end
1557
- GraphAlbum.many_to_many :lgenres, :clone=>:genres, :class=>sub, :limit=>2
1558
- ds = GraphAlbum.eager_graph_with_options(:lgenres, :limit_strategy=>true)
1559
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, lgenres.id AS lgenres_id FROM albums LEFT OUTER JOIN (SELECT id, x_foreign_key_x FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x, row_number() OVER (PARTITION BY ag.album_id) AS x_sequel_row_number_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id)) AS t1 WHERE (x_sequel_row_number_x <= 2)) AS lgenres ON (lgenres.x_foreign_key_x = albums.id)'
1560
- a = ds.with_fetch(:id=>1, :band_id=>2, :lgenres_id=>4).all
1561
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1562
- a.first.lgenres.must_equal [sub.load(:id => 4)]
1563
- end
1564
-
1565
- it "should eagerly load a single one_through_one association" do
1566
- ds = GraphAlbum.eager_graph(:genre)
1567
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genre.id AS genre_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genre ON (genre.id = ag.genre_id)'
1568
- a = ds.with_fetch(:id=>1, :band_id=>2, :genre_id=>4).all
1569
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1570
- a.first.genre.must_equal GraphGenre.load(:id => 4)
1571
- end
1572
-
1573
- it "should eagerly graph a single one_through_one association using the :distinct_on strategy" do
1574
- sub = Class.new(GraphGenre)
1575
- sub.dataset = sub.dataset.with_extend do
1576
- def supports_distinct_on?; true end
1577
- def columns; [:id] end
1578
- end
1579
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>sub
1580
- ds = GraphAlbum.eager_graph_with_options(:lgenre, :limit_strategy=>true)
1581
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, lgenre.id AS lgenre_id FROM albums LEFT OUTER JOIN (SELECT DISTINCT ON (ag.album_id) genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) ORDER BY ag.album_id) AS lgenre ON (lgenre.x_foreign_key_x = albums.id)'
1582
- a = ds.with_fetch(:id=>1, :band_id=>2, :lgenre_id=>4).all
1583
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1584
- a.first.lgenre.must_equal sub.load(:id => 4)
1585
- end
1586
-
1587
- it "should eagerly graph a single one_through_one association using the :window_function strategy" do
1588
- sub = Class.new(GraphGenre)
1589
- sub.dataset = sub.dataset.with_extend do
1590
- def supports_window_functions?; true end
1591
- def columns; literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1592
- end
1593
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>sub
1594
- ds = GraphAlbum.eager_graph_with_options(:lgenre, :limit_strategy=>true)
1595
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, lgenre.id AS lgenre_id FROM albums LEFT OUTER JOIN (SELECT id, x_foreign_key_x FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x, row_number() OVER (PARTITION BY ag.album_id) AS x_sequel_row_number_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id)) AS t1 WHERE (x_sequel_row_number_x = 1)) AS lgenre ON (lgenre.x_foreign_key_x = albums.id)'
1596
- a = ds.with_fetch(:id=>1, :band_id=>2, :lgenre_id=>4).all
1597
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1598
- a.first.lgenre.must_equal sub.load(:id => 4)
1599
- end
1600
-
1601
- it "should correctly handle an aliased join table in many_to_many and one_through_one with graph_conditions or graph_block" do
1602
- c = Class.new(GraphAlbum)
1603
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga), :graph_conditions=>{:a=>:b}
1604
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS ga ON (ga.album_id = albums.id) LEFT OUTER JOIN genres ON ((genres.id = ga.genre_id) AND (genres.a = ga.b))'
1605
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga), :graph_block => proc{true}
1606
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS ga ON (ga.album_id = albums.id) LEFT OUTER JOIN genres ON ((genres.id = ga.genre_id) AND (genres.a = ga.b) AND \'t\')'
1607
- end
1608
-
1609
- with_symbol_splitting "should correctly handle an aliased join table symbol in many_to_many and one_through_one with graph_conditions or graph_block" do
1610
- c = Class.new(GraphAlbum)
1611
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___ga, :graph_conditions=>{:a=>:b}
1612
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS ga ON (ga.album_id = albums.id) LEFT OUTER JOIN genres ON ((genres.id = ga.genre_id) AND (genres.a = ga.b))'
1613
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___ga, :graph_block => proc{true}
1614
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS ga ON (ga.album_id = albums.id) LEFT OUTER JOIN genres ON ((genres.id = ga.genre_id) AND (genres.a = ga.b) AND \'t\')'
1615
- end
1616
-
1617
- it "should raise Error when using eager_graph with :conditions option that isn't a conditions specifier" do
1618
- c = Class.new(GraphAlbum)
1619
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga), :conditions=>'true'
1620
- proc{c.eager_graph(:genres)}.must_raise Sequel::Error
1621
- end
1622
-
1623
- with_symbol_splitting "should correctly handle an aliased join table symbol in many_to_many and one_through_one" do
1624
- c = Class.new(GraphAlbum)
1625
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___ga
1626
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS ga ON (ga.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ga.genre_id)'
1627
-
1628
- c.many_to_many :genre, :clone=>:genre, :join_table=>:ag___ga
1629
- c.eager_graph(:genre).sql.must_equal 'SELECT albums.id, albums.band_id, genre.id AS genre_id FROM albums LEFT OUTER JOIN ag AS ga ON (ga.album_id = albums.id) LEFT OUTER JOIN genres AS genre ON (genre.id = ga.genre_id)'
1630
-
1631
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___albums
1632
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS albums_0 ON (albums_0.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = albums_0.genre_id)'
1633
-
1634
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___genres
1635
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS genres_0 ON (genres_0.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = genres_0.genre_id)'
1636
- end
1637
-
1638
- it "should correctly handle an aliased join table in many_to_many and one_through_one" do
1639
- c = Class.new(GraphAlbum)
1640
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga)
1641
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS ga ON (ga.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ga.genre_id)'
1642
-
1643
- c.many_to_many :genre, :clone=>:genre, :join_table=>Sequel[:ag].as(:ga)
1644
- c.eager_graph(:genre).sql.must_equal 'SELECT albums.id, albums.band_id, genre.id AS genre_id FROM albums LEFT OUTER JOIN ag AS ga ON (ga.album_id = albums.id) LEFT OUTER JOIN genres AS genre ON (genre.id = ga.genre_id)'
1645
-
1646
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:albums)
1647
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS albums_0 ON (albums_0.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = albums_0.genre_id)'
1648
-
1649
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:genres)
1650
- c.eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag AS genres_0 ON (genres_0.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = genres_0.genre_id)'
1651
- end
1652
-
1653
- it "should handle multiple associations in a single call to association_join" do
1654
- GraphAlbum.association_join(:genres, :tracks, :band).sql.must_equal 'SELECT * FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres ON (genres.id = ag.genre_id) INNER JOIN tracks ON (tracks.album_id = albums.id) INNER JOIN bands AS band ON (band.id = albums.band_id)'
1655
- end
1656
-
1657
- it "should eagerly load multiple associations in a single call" do
1658
- ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
1659
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
1660
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>4, :tracks_id=>3, :album_id=>1, :band_id_0=>2, :vocalist_id=>6).all
1661
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1662
- a = a.first
1663
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1664
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1665
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1666
- end
1667
-
1668
- it "should eagerly load multiple associations with different limit strategies in a single call" do
1669
- subg = Class.new(GraphGenre)
1670
- subg.dataset = subg.dataset.with_extend do
1671
- def supports_distinct_on?; true end
1672
- def supports_window_functions?; true end
1673
- def columns; literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1674
- end
1675
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>subg
1676
- GraphAlbum.many_to_many :lgenres, :clone=>:genres, :class=>subg, :limit=>2
1677
-
1678
- ds = GraphAlbum.eager_graph_with_options([:lgenre, :lgenres], :limit_strategy=>{:lgenre=>:distinct_on, :lgenres=>:window_function})
1679
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, lgenre.id AS lgenre_id, lgenres.id AS lgenres_id FROM albums LEFT OUTER JOIN (SELECT DISTINCT ON (ag.album_id) genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) ORDER BY ag.album_id) AS lgenre ON (lgenre.x_foreign_key_x = albums.id) LEFT OUTER JOIN (SELECT id, x_foreign_key_x FROM (SELECT genres.*, ag.album_id AS x_foreign_key_x, row_number() OVER (PARTITION BY ag.album_id) AS x_sequel_row_number_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id)) AS t1 WHERE (x_sequel_row_number_x <= 2)) AS lgenres ON (lgenres.x_foreign_key_x = albums.id)'
1680
- a = ds.with_fetch(:id=>1, :band_id=>2, :lgenres_id=>4, :lgenre_id=>3).all
1681
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1682
- a = a.first
1683
- a.lgenre.must_equal subg.load(:id => 3)
1684
- a.lgenres.must_equal [subg.load(:id => 4)]
1685
- end
1686
-
1687
- it "should handle multiple associations in separate calls to association_join" do
1688
- GraphAlbum.association_join(:genres).association_join(:tracks).association_join(:band).sql.must_equal 'SELECT * FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres ON (genres.id = ag.genre_id) INNER JOIN tracks ON (tracks.album_id = albums.id) INNER JOIN bands AS band ON (band.id = albums.band_id)'
1689
- end
1690
-
1691
- it "should eagerly load multiple associations in separate calls" do
1692
- ds = GraphAlbum.eager_graph(:genres).eager_graph(:tracks).eager_graph(:band)
1693
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
1694
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>4, :tracks_id=>3, :album_id=>1, :band_id_0=>2, :vocalist_id=>6).all
1695
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1696
- a = a.first
1697
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1698
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1699
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1700
- end
1701
-
1702
- it "should handle cascading associations in a single call to association_join" do
1703
- GraphTrack.association_join(:album=>{:band=>:members}).sql.must_equal 'SELECT * FROM tracks INNER JOIN albums AS album ON (album.id = tracks.album_id) INNER JOIN bands AS band ON (band.id = album.band_id) INNER JOIN bm ON (bm.band_id = band.id) INNER JOIN members ON (members.id = bm.member_id)'
1704
- GraphBand.association_join({:albums=>:tracks}, :members).sql.must_equal 'SELECT * FROM bands INNER JOIN albums ON (albums.band_id = bands.id) INNER JOIN tracks ON (tracks.album_id = albums.id) INNER JOIN bm ON (bm.band_id = bands.id) INNER JOIN members ON (members.id = bm.member_id)'
1705
- end
1706
-
1707
- it "should handle matching association names for different models when using association_join" do
1708
- GraphAlbum.association_join(:genres).association_join(:band=>:genres).sql.must_equal 'SELECT * FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres ON (genres.id = ag.genre_id) INNER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN bg ON (bg.band_id = band.id) INNER JOIN genres AS genres_0 ON (genres_0.id = bg.genre_id)'
1709
- end
1710
-
1711
- it "should allow cascading of eager loading for associations of associated models" do
1712
- ds = GraphTrack.eager_graph(:album=>{:band=>:members})
1713
- ds.sql.must_equal 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, members.id AS members_id FROM tracks LEFT OUTER JOIN albums AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
1714
- a = ds.with_fetch(:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :members_id=>5, :band_id_0=>2, :vocalist_id=>6).all
1715
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
1716
- a = a.first
1717
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
1718
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1719
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
1720
- end
1721
-
1722
- it "should allow cascading of eager loading for multiple *_to_many associations, eliminating duplicates caused by cartesian products" do
1723
- ds = GraphBand.eager_graph({:albums=>:tracks}, :members)
1724
- ds.sql.must_equal 'SELECT bands.id, bands.vocalist_id, albums.id AS albums_id, albums.band_id, tracks.id AS tracks_id, tracks.album_id, members.id AS members_id FROM bands LEFT OUTER JOIN albums ON (albums.band_id = bands.id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
1725
- a = ds.with_fetch([{:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>5},
1726
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>6},
1727
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>5},
1728
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>6},
1729
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>5},
1730
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>6},
1731
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>5},
1732
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>6},
1733
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>5},
1734
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>6},
1735
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>5},
1736
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>6},
1737
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>5},
1738
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>6},
1739
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>5},
1740
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>6}]).all
1741
- a.must_equal [GraphBand.load(:id=>1, :vocalist_id=>2), GraphBand.load(:id=>2, :vocalist_id=>2)]
1742
- members = a.map{|x| x.members}
1743
- members.must_equal [[GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)], [GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)]]
1744
- albums = a.map{|x| x.albums}
1745
- albums.must_equal [[GraphAlbum.load(:id=>3, :band_id=>1), GraphAlbum.load(:id=>4, :band_id=>1)], [GraphAlbum.load(:id=>5, :band_id=>2), GraphAlbum.load(:id=>6, :band_id=>2)]]
1746
- tracks = albums.map{|x| x.map{|y| y.tracks}}
1747
- tracks.must_equal [[[GraphTrack.load(:id=>4, :album_id=>3), GraphTrack.load(:id=>5, :album_id=>3)], [GraphTrack.load(:id=>6, :album_id=>4), GraphTrack.load(:id=>7, :album_id=>4)]], [[GraphTrack.load(:id=>8, :album_id=>5), GraphTrack.load(:id=>9, :album_id=>5)], [GraphTrack.load(:id=>1, :album_id=>6), GraphTrack.load(:id=>2, :album_id=>6)]]]
1748
- end
1749
-
1750
- it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
1751
- DB.reset
1752
- ds = GraphAlbum.eager_graph(:tracks)
1753
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)'
1754
- a = ds.with_fetch(:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1).all
1755
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1756
- a = a.first
1757
- a.tracks.must_equal [GraphTrack.load(:id => 3, :album_id=>1)]
1758
- a.tracks.first.album.must_equal a
1759
- DB.sqls.must_equal ['SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)']
1760
- end
1761
-
1762
- it "should eager load multiple associations from the same table" do
1763
- ds = GraphBand.eager_graph(:vocalist, :members)
1764
- ds.sql.must_equal 'SELECT bands.id, bands.vocalist_id, vocalist.id AS vocalist_id_0, members.id AS members_id FROM bands LEFT OUTER JOIN members AS vocalist ON (vocalist.id = bands.vocalist_id) LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
1765
- a = ds.with_fetch(:id=>2, :vocalist_id=>6, :vocalist_id_0=>6, :members_id=>5).all
1766
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1767
- a = a.first
1768
- a.vocalist.must_equal GraphBandMember.load(:id => 6)
1769
- a.members.must_equal [GraphBandMember.load(:id => 5)]
1770
- end
1771
-
1772
- it "should give you a plain hash when called without .all" do
1773
- ds = GraphAlbum.eager_graph(:band)
1774
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
1775
- ds.with_fetch(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3).first.must_equal(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3)
1776
- end
1777
-
1778
- it "should not drop any associated objects if the graph could not be a cartesian product" do
1779
- ds = GraphBand.eager_graph(:members, :vocalist)
1780
- ds.sql.must_equal 'SELECT bands.id, bands.vocalist_id, members.id AS members_id, vocalist.id AS vocalist_id_0 FROM bands LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) LEFT OUTER JOIN members AS vocalist ON (vocalist.id = bands.vocalist_id)'
1781
- a = ds.with_fetch([{:id=>2, :vocalist_id=>6, :members_id=>5, :vocalist_id_0=>6}, {:id=>2, :vocalist_id=>6, :members_id=>5, :vocalist_id_0=>6}]).all
1782
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1783
- a = a.first
1784
- a.vocalist.must_equal GraphBandMember.load(:id => 6)
1785
- a.members.must_equal [GraphBandMember.load(:id => 5), GraphBandMember.load(:id => 5)]
1786
- end
1787
-
1788
- it "should respect the :cartesian_product_number option" do
1789
- GraphBand.many_to_one :other_vocalist, :class=>'GraphBandMember', :key=>:vocalist_id, :cartesian_product_number=>1
1790
- ds = GraphBand.eager_graph(:members, :other_vocalist)
1791
- ds.sql.must_equal 'SELECT bands.id, bands.vocalist_id, members.id AS members_id, other_vocalist.id AS other_vocalist_id FROM bands LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) LEFT OUTER JOIN members AS other_vocalist ON (other_vocalist.id = bands.vocalist_id)'
1792
- a = ds.with_fetch([{:id=>2, :vocalist_id=>6, :members_id=>5, :other_vocalist_id=>6}, {:id=>2, :vocalist_id=>6, :members_id=>5, :other_vocalist_id=>6}]).all
1793
- a.must_equal [GraphBand.load(:id=>2, :vocalist_id => 6)]
1794
- a.first.other_vocalist.must_equal GraphBandMember.load(:id=>6)
1795
- a.first.members.must_equal [GraphBandMember.load(:id=>5)]
1796
- end
1797
-
1798
- it "should drop duplicate items that occur in sequence if the graph could be a cartesian product" do
1799
- ds = GraphBand.eager_graph(:members, :genres)
1800
- ds.sql.must_equal 'SELECT bands.id, bands.vocalist_id, members.id AS members_id, genres.id AS genres_id FROM bands LEFT OUTER JOIN bm ON (bm.band_id = bands.id) LEFT OUTER JOIN members ON (members.id = bm.member_id) LEFT OUTER JOIN bg ON (bg.band_id = bands.id) LEFT OUTER JOIN genres ON (genres.id = bg.genre_id)'
1801
- a = ds.with_fetch([{:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>7},
1802
- {:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>8},
1803
- {:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>7},
1804
- {:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>8}]).all
1805
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1806
- a = a.first
1807
- a.members.must_equal [GraphBandMember.load(:id => 5), GraphBandMember.load(:id => 6)]
1808
- a.genres.must_equal [GraphGenre.load(:id => 7), GraphGenre.load(:id => 8)]
1809
- end
1810
-
1811
- it "should be able to be used in combination with #eager" do
1812
- DB.reset
1813
- ds = GraphAlbum.eager_graph(:tracks).eager(:genres)
1814
- GraphGenre.dataset = GraphGenre.dataset.with_fetch(:id=>6, :x_foreign_key_x=>1)
1815
- a = ds.with_fetch(:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1).all
1816
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1817
- a = a.first
1818
- a.tracks.must_equal [GraphTrack.load(:id=>3, :album_id=>1)]
1819
- a.genres.must_equal [GraphGenre.load(:id => 6)]
1820
- DB.sqls.must_equal ['SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)',
1821
- "SELECT genres.*, ag.album_id AS x_foreign_key_x FROM genres INNER JOIN ag ON (ag.genre_id = genres.id) WHERE (ag.album_id IN (1))"]
1822
- end
1823
-
1824
- it "should handle no associated records for a single many_to_one association" do
1825
- ds = GraphAlbum.eager_graph(:band)
1826
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
1827
- a = ds.with_fetch(:id=>1, :band_id=>2, :band_id_0=>nil, :vocalist_id=>nil).all
1828
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1829
- a.first.band.must_be_nil
1830
- end
1831
-
1832
- it "should handle no associated records for a single one_to_one association" do
1833
- ds = GraphAlbum.eager_graph(:track)
1834
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, track.id AS track_id, track.album_id FROM albums LEFT OUTER JOIN tracks AS track ON (track.album_id = albums.id)'
1835
- a = ds.with_fetch(:id=>1, :band_id=>2, :track_id=>nil, :album_id=>nil).all
1836
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1837
- a.first.track.must_be_nil
1838
- end
1839
-
1840
- it "should handle no associated records for a single one_to_many association" do
1841
- ds = GraphAlbum.eager_graph(:tracks)
1842
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, tracks.id AS tracks_id, tracks.album_id FROM albums LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id)'
1843
- a = ds.with_fetch(:id=>1, :band_id=>2, :tracks_id=>nil, :album_id=>nil).all
1844
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1845
- a.first.tracks.must_equal []
1846
- end
1847
-
1848
- it "should handle no associated records for a single one_through_one association" do
1849
- ds = GraphAlbum.eager_graph(:genre)
1850
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genre.id AS genre_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genre ON (genre.id = ag.genre_id)'
1851
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>nil).all
1852
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1853
- a.first.genre.must_be_nil
1854
- end
1855
-
1856
- it "should handle no associated records for a single many_to_many association" do
1857
- ds = GraphAlbum.eager_graph(:genres)
1858
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id)'
1859
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>nil).all
1860
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1861
- a.first.genres.must_equal []
1862
- end
1863
-
1864
- it "should handle missing associated records when loading multiple associations" do
1865
- ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
1866
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id, tracks.id AS tracks_id, tracks.album_id, band.id AS band_id_0, band.vocalist_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres ON (genres.id = ag.genre_id) LEFT OUTER JOIN tracks ON (tracks.album_id = albums.id) LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)'
1867
- a = ds.with_fetch([{:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>3, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil},
1868
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>4, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil},
1869
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>5, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil},
1870
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>6, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil}]).all
1871
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1872
- a = a.first
1873
- a.tracks.must_equal [GraphTrack.load(:id => 3, :album_id => 1), GraphTrack.load(:id => 4, :album_id => 1), GraphTrack.load(:id => 5, :album_id => 1), GraphTrack.load(:id => 6, :album_id => 1)]
1874
- a.band.must_be_nil
1875
- a.genres.must_equal []
1876
- end
1877
-
1878
- it "should handle missing associated records when cascading eager loading for associations of associated models" do
1879
- ds = GraphTrack.eager_graph(:album=>{:band=>:members})
1880
- ds.sql.must_equal 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, members.id AS members_id FROM tracks LEFT OUTER JOIN albums AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
1881
- a = ds.with_fetch([{:id=>2, :album_id=>2, :album_id_0=>nil, :band_id=>nil, :members_id=>nil, :band_id_0=>nil, :vocalist_id=>nil},
1882
- {:id=>3, :album_id=>3, :album_id_0=>3, :band_id=>3, :members_id=>nil, :band_id_0=>nil, :vocalist_id=>nil},
1883
- {:id=>4, :album_id=>4, :album_id_0=>4, :band_id=>2, :members_id=>nil, :band_id_0=>2, :vocalist_id=>6},
1884
- {:id=>5, :album_id=>1, :album_id_0=>1, :band_id=>4, :members_id=>5, :band_id_0=>4, :vocalist_id=>8},
1885
- {:id=>5, :album_id=>1, :album_id_0=>1, :band_id=>4, :members_id=>6, :band_id_0=>4, :vocalist_id=>8}]).all
1886
- a.must_equal [GraphTrack.load(:id => 2, :album_id => 2), GraphTrack.load(:id => 3, :album_id => 3), GraphTrack.load(:id => 4, :album_id => 4), GraphTrack.load(:id => 5, :album_id => 1)]
1887
- a.map{|x| x.album}.must_equal [nil, GraphAlbum.load(:id => 3, :band_id => 3), GraphAlbum.load(:id => 4, :band_id => 2), GraphAlbum.load(:id => 1, :band_id => 4)]
1888
- a.map{|x| x.album.band if x.album}.must_equal [nil, nil, GraphBand.load(:id => 2, :vocalist_id=>6), GraphBand.load(:id => 4, :vocalist_id=>8)]
1889
- a.map{|x| x.album.band.members if x.album && x.album.band}.must_equal [nil, nil, [], [GraphBandMember.load(:id => 5), GraphBandMember.load(:id => 6)]]
1890
- end
1891
-
1892
- it "should respect the association's :primary_key option" do
1893
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :primary_key=>:vocalist_id
1894
- ds = GraphAlbum.eager_graph(:inner_band)
1895
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, inner_band.id AS inner_band_id, inner_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS inner_band ON (inner_band.vocalist_id = albums.band_id)'
1896
- as = ds.with_fetch(:id=>3, :band_id=>2, :inner_band_id=>5, :vocalist_id=>2).all
1897
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1898
- as.first.inner_band.must_equal GraphBand.load(:id=>5, :vocalist_id=>2)
1899
-
1900
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :primary_key=>:band_id, :reciprocal=>nil
1901
- ds = GraphAlbum.eager_graph(:right_tracks)
1902
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.band_id)'
1903
- as = ds.with_fetch([{:id=>3, :band_id=>2, :right_tracks_id=>5, :album_id=>2}, {:id=>3, :band_id=>2, :right_tracks_id=>6, :album_id=>2}]).all
1904
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1905
- as.first.right_tracks.must_equal [GraphTrack.load(:id=>5, :album_id=>2), GraphTrack.load(:id=>6, :album_id=>2)]
1906
- end
1907
-
1908
- it "should respect many_to_one association's composite keys" do
1909
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>[:band_id, :id], :primary_key=>[:vocalist_id, :id]
1910
- ds = GraphAlbum.eager_graph(:inner_band)
1911
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, inner_band.id AS inner_band_id, inner_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS inner_band ON ((inner_band.vocalist_id = albums.band_id) AND (inner_band.id = albums.id))'
1912
- as = ds.with_fetch(:id=>3, :band_id=>2, :inner_band_id=>3, :vocalist_id=>2).all
1913
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1914
- as.first.inner_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>2)
1915
- end
1916
-
1917
- it "should respect one_to_many association's composite keys" do
1918
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>[:album_id, :id], :primary_key=>[:band_id, :id]
1919
- ds = GraphAlbum.eager_graph(:right_tracks)
1920
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.band_id) AND (right_tracks.id = albums.id))'
1921
- as = ds.with_fetch(:id=>3, :band_id=>2, :right_tracks_id=>3, :album_id=>2).all
1922
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1923
- as.first.right_tracks.must_equal [GraphTrack.load(:id=>3, :album_id=>2)]
1924
- end
1925
-
1926
- it "should respect many_to_many association's composite keys" do
1927
- GraphAlbum.many_to_many :sbands, :class=>'GraphBand', :left_key=>[:l1, :l2], :left_primary_key=>[:band_id, :id], :right_key=>[:r1, :r2], :right_primary_key=>[:vocalist_id, :id], :join_table=>:b
1928
- ds = GraphAlbum.eager_graph(:sbands)
1929
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, sbands.id AS sbands_id, sbands.vocalist_id FROM albums LEFT OUTER JOIN b ON ((b.l1 = albums.band_id) AND (b.l2 = albums.id)) LEFT OUTER JOIN bands AS sbands ON ((sbands.vocalist_id = b.r1) AND (sbands.id = b.r2))'
1930
- as = ds.with_fetch([{:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6}, {:id=>3, :band_id=>2, :sbands_id=>6, :vocalist_id=>22}]).all
1931
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1932
- as.first.sbands.must_equal [GraphBand.load(:id=>5, :vocalist_id=>6), GraphBand.load(:id=>6, :vocalist_id=>22)]
1933
- end
1934
-
1935
- it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
1936
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :left_primary_key=>:band_id, :right_key=>:genre_id, :right_primary_key=>:xxx, :join_table=>:ag
1937
- ds = GraphAlbum.eager_graph(:inner_genres)
1938
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.band_id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.xxx = ag.genre_id)'
1939
- as = ds.with_fetch([{:id=>3, :band_id=>2, :inner_genres_id=>5, :xxx=>12}, {:id=>3, :band_id=>2, :inner_genres_id=>6, :xxx=>22}]).all
1940
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1941
- as.first.inner_genres.must_equal [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
1942
- end
1943
-
1944
- it "should respect composite primary keys for classes when eager loading" do
1945
- c1 = Class.new(GraphAlbum)
1946
- c2 = Class.new(GraphBand)
1947
- c1.set_primary_key [:band_id, :id]
1948
- c2.set_primary_key [:vocalist_id, :id]
1949
- c1.many_to_many :sbands, :class=>c2, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :join_table=>:b
1950
- c2.one_to_many :salbums, :class=>c1, :key=>[:band_id, :id]
1951
- ds = c1.eager_graph(:sbands=>:salbums)
1952
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, sbands.id AS sbands_id, sbands.vocalist_id, salbums.id AS salbums_id, salbums.band_id AS salbums_band_id FROM albums LEFT OUTER JOIN b ON ((b.l1 = albums.band_id) AND (b.l2 = albums.id)) LEFT OUTER JOIN bands AS sbands ON ((sbands.vocalist_id = b.r1) AND (sbands.id = b.r2)) LEFT OUTER JOIN albums AS salbums ON ((salbums.band_id = sbands.vocalist_id) AND (salbums.id = sbands.id))'
1953
- as = ds.with_fetch([{:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6, :salbums_id=>7, :salbums_band_id=>8},
1954
- {:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6, :salbums_id=>9, :salbums_band_id=>10},
1955
- {:id=>3, :band_id=>2, :sbands_id=>6, :vocalist_id=>22, :salbums_id=>nil, :salbums_band_id=>nil},
1956
- {:id=>7, :band_id=>8, :sbands_id=>nil, :vocalist_id=>nil, :salbums_id=>nil, :salbums_band_id=>nil}]).all
1957
- as.must_equal [c1.load(:id=>3, :band_id=>2), c1.load(:id=>7, :band_id=>8)]
1958
- as.map{|x| x.sbands}.must_equal [[c2.load(:id=>5, :vocalist_id=>6), c2.load(:id=>6, :vocalist_id=>22)], []]
1959
- as.map{|x| x.sbands.map{|y| y.salbums}}.must_equal [[[c1.load(:id=>7, :band_id=>8), c1.load(:id=>9, :band_id=>10)], []], []]
1960
- end
1961
-
1962
- it "should respect the association's :graph_select option" do
1963
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_select=>:vocalist_id
1964
- GraphAlbum.eager_graph(:inner_band).sql.must_equal 'SELECT albums.id, albums.band_id, inner_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS inner_band ON (inner_band.id = albums.band_id)'
1965
-
1966
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_select=>[:album_id]
1967
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id)'
1968
-
1969
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_select=>[]
1970
- GraphAlbum.eager_graph(:inner_genres).sql.must_equal 'SELECT albums.id, albums.band_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
1971
- end
1972
-
1973
- it "should respect the association's :graph_alias_base option" do
1974
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_alias_base=>:foo
1975
- ds = GraphAlbum.eager_graph(:inner_band)
1976
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, foo.id AS foo_id, foo.vocalist_id FROM albums LEFT OUTER JOIN bands AS foo ON (foo.id = albums.band_id)'
1977
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_alias_base=>:foo
1978
- ds.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, foo.id AS foo_id, foo.vocalist_id, foo_0.id AS foo_0_id, foo_0.album_id FROM albums LEFT OUTER JOIN bands AS foo ON (foo.id = albums.band_id) LEFT OUTER JOIN tracks AS foo_0 ON (foo_0.album_id = albums.id)'
1979
- end
1980
-
1981
- it "should respect the association's :graph_join_type option" do
1982
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_join_type=>:inner
1983
- GraphAlbum.eager_graph(:inner_band).sql.must_equal 'SELECT albums.id, albums.band_id, inner_band.id AS inner_band_id, inner_band.vocalist_id FROM albums INNER JOIN bands AS inner_band ON (inner_band.id = albums.band_id)'
1984
-
1985
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_join_type=>:right_outer
1986
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums RIGHT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id)'
1987
-
1988
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_type=>:inner
1989
- GraphAlbum.eager_graph(:inner_genres).sql.must_equal 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) INNER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
1990
- end
1991
-
1992
- it "should respect the association's :graph_join_table_join_type option" do
1993
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_join_type=>:inner
1994
- GraphAlbum.eager_graph(:inner_genres).sql.must_equal 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
1995
-
1996
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_join_type=>:inner, :graph_join_type=>:right_outer
1997
- GraphAlbum.eager_graph(:inner_genres).sql.must_equal 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums INNER JOIN ag ON (ag.album_id = albums.id) RIGHT OUTER JOIN genres AS inner_genres ON (inner_genres.id = ag.genre_id)'
1998
- end
1999
-
2000
- it "should respect the association's :conditions option" do
2001
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :conditions=>{:active=>true}
2002
- GraphAlbum.eager_graph(:active_band).sql.must_equal "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND (active_band.active IS TRUE))"
2003
-
2004
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :conditions=>{:id=>(0..100)}, :reciprocal=>nil
2005
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.id) AND (right_tracks.id >= 0) AND (right_tracks.id <= 100))'
2006
-
2007
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :conditions=>{true=>:active}
2008
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
2009
- end
2010
-
2011
- it "should respect the association's :graph_conditions option" do
2012
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_conditions=>{:active=>true}
2013
- GraphAlbum.eager_graph(:active_band).sql.must_equal "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND (active_band.active IS TRUE))"
2014
-
2015
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:id=>(0..100)}
2016
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.id) AND (right_tracks.id >= 0) AND (right_tracks.id <= 100))'
2017
-
2018
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}
2019
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
2020
- end
2021
-
2022
- it "should respect the association's :graph_join_table_conditions option" do
2023
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_conditions=>{:active=>true}
2024
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND (ag.active IS TRUE)) LEFT OUTER JOIN genres AS active_genres ON (active_genres.id = ag.genre_id)"
2025
-
2026
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}, :graph_join_table_conditions=>{true=>:active}
2027
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND ('t' = albums.active)) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
2028
- end
2029
-
2030
- it "should respect the association's :graph_block option" do
2031
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :active)=>true}}
2032
- GraphAlbum.eager_graph(:active_band).sql.must_equal "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON ((active_band.id = albums.band_id) AND (active_band.active IS TRUE))"
2033
-
2034
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :id)=>(0..100)}}
2035
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON ((right_tracks.album_id = albums.id) AND (right_tracks.id >= 0) AND (right_tracks.id <= 100))'
2036
-
2037
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_block=>proc{|ja,lja,js| {true=>Sequel.qualify(lja, :active)}}
2038
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
2039
- end
2040
-
2041
- it "should respect the association's :graph_join_table_block option" do
2042
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :active)=>true}}
2043
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND (ag.active IS TRUE)) LEFT OUTER JOIN genres AS active_genres ON (active_genres.id = ag.genre_id)"
2044
-
2045
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_block=>proc{|ja,lja,js| {true=>Sequel.qualify(lja, :active)}}, :graph_join_table_block=>proc{|ja,lja,js| {true=>Sequel.qualify(lja, :active)}}
2046
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON ((ag.album_id = albums.id) AND ('t' = albums.active)) LEFT OUTER JOIN genres AS active_genres ON ((active_genres.id = ag.genre_id) AND ('t' = ag.active))"
2047
- end
2048
-
2049
- it "should respect the association's :eager_grapher option" do
2050
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :eager_grapher=>proc{|eo| eo[:self].graph(GraphBand.dataset, {:active=>true}, :table_alias=>eo[:table_alias], :join_type=>:inner)}
2051
- GraphAlbum.eager_graph(:active_band).sql.must_equal "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums INNER JOIN bands AS active_band ON (active_band.active IS TRUE)"
2052
-
2053
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :eager_grapher=>proc{|eo| eo[:self].graph(GraphTrack.dataset, nil, :join_type=>:natural, :table_alias=>eo[:table_alias])}
2054
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums NATURAL JOIN tracks AS right_tracks'
2055
-
2056
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :eager_grapher=>proc{|eo| eo[:self].graph(:ag, {:album_id=>:id}, :table_alias=>:a123, :implicit_qualifier=>eo[:implicit_qualifier]).graph(GraphGenre.dataset, [:album_id], :table_alias=>eo[:table_alias])}
2057
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag AS a123 ON (a123.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres USING (album_id)"
2058
- end
2059
-
2060
- it "should respect the association's :graph_only_conditions option" do
2061
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_only_conditions=>{:active=>true}
2062
- GraphAlbum.eager_graph(:active_band).sql.must_equal "SELECT albums.id, albums.band_id, active_band.id AS active_band_id, active_band.vocalist_id FROM albums LEFT OUTER JOIN bands AS active_band ON (active_band.active IS TRUE)"
2063
-
2064
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_only_conditions=>nil, :graph_join_type=>:natural
2065
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums NATURAL JOIN tracks AS right_tracks'
2066
-
2067
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_only_conditions=>[:album_id]
2068
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS active_genres USING (album_id)"
2069
- end
2070
-
2071
- it "should respect the association's :graph_join_table_only_conditions option" do
2072
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_table_only_conditions=>{:active=>true}
2073
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.active IS TRUE) LEFT OUTER JOIN genres AS active_genres ON (active_genres.id = ag.genre_id)"
2074
-
2075
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_only_conditions=>(Sequel.expr(:price) + 2 > 100), :graph_join_table_only_conditions=>Sequel.identifier("active")
2076
- GraphAlbum.eager_graph(:active_genres).sql.must_equal "SELECT albums.id, albums.band_id, active_genres.id AS active_genres_id FROM albums LEFT OUTER JOIN ag ON active LEFT OUTER JOIN genres AS active_genres ON ((price + 2) > 100)"
2077
- end
2078
-
2079
- it "should create unique table aliases for all associations" do
2080
- GraphAlbum.eager_graph(:previous_album=>{:previous_album=>:previous_album}).sql.must_equal "SELECT albums.id, albums.band_id, previous_album.id AS previous_album_id, previous_album.band_id AS previous_album_band_id, previous_album_0.id AS previous_album_0_id, previous_album_0.band_id AS previous_album_0_band_id, previous_album_1.id AS previous_album_1_id, previous_album_1.band_id AS previous_album_1_band_id FROM albums LEFT OUTER JOIN albums AS previous_album ON (previous_album.id = albums.previous_album_id) LEFT OUTER JOIN albums AS previous_album_0 ON (previous_album_0.id = previous_album.previous_album_id) LEFT OUTER JOIN albums AS previous_album_1 ON (previous_album_1.id = previous_album_0.previous_album_id)"
2081
- end
2082
-
2083
- it "should respect the association's :order" do
2084
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
2085
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY right_tracks.id, right_tracks.album_id'
2086
- end
2087
-
2088
- with_symbol_splitting "should not qualify qualified symbols in association's :order" do
2089
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[Sequel.desc(:blah__id), :blah__id]
2090
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY blah.id DESC, blah.id'
2091
- end
2092
-
2093
- it "should only qualify unqualified symbols, identifiers, or ordered versions in association's :order" do
2094
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[Sequel.identifier(:blah__id), Sequel.identifier(:blah__id).desc, Sequel[:blah][:id].desc, Sequel[:blah][:id], :album_id, Sequel.desc(:album_id), 1, Sequel.lit('RANDOM()'), Sequel.qualify(:b, :a)]
2095
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY right_tracks.blah__id, right_tracks.blah__id DESC, blah.id DESC, blah.id, right_tracks.album_id, right_tracks.album_id DESC, 1, RANDOM(), b.a'
2096
- end
2097
-
2098
- it "should not respect the association's :order if :order_eager_graph is false" do
2099
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id], :order_eager_graph=>false
2100
- GraphAlbum.eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id)'
2101
- end
2102
-
2103
- it "should add the association's :order to the existing order" do
2104
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
2105
- GraphAlbum.order(:band_id).eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY band_id, right_tracks.id, right_tracks.album_id'
2106
- end
2107
-
2108
- it "should use the association's :graph_order in preference or order" do
2109
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:tracks__id, :tracks__album_id], :graph_order=>[:id, :album_id]
2110
- GraphAlbum.order(:band_id).eager_graph(:right_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, right_tracks.id AS right_tracks_id, right_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS right_tracks ON (right_tracks.album_id = albums.id) ORDER BY band_id, right_tracks.id, right_tracks.album_id'
2111
- end
2112
-
2113
- it "should add the association's :order for cascading associations" do
2114
- GraphBand.one_to_many :a_albums, :class=>'GraphAlbum', :key=>:band_id, :order=>:name, :reciprocal=>nil
2115
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
2116
- GraphBand.eager_graph(:a_albums=>:b_tracks).sql.must_equal 'SELECT bands.id, bands.vocalist_id, a_albums.id AS a_albums_id, a_albums.band_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM bands LEFT OUTER JOIN albums AS a_albums ON (a_albums.band_id = bands.id) LEFT OUTER JOIN tracks AS b_tracks ON (b_tracks.album_id = a_albums.id) ORDER BY a_albums.name, b_tracks.id, b_tracks.album_id'
2117
- GraphAlbum.one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id, :order=>[:band_id, :id]
2118
- GraphAlbum.eager_graph(:albums=>{:albums=>:albums}).sql.must_equal 'SELECT albums.id, albums.band_id, albums_0.id AS albums_0_id, albums_0.band_id AS albums_0_band_id, albums_1.id AS albums_1_id, albums_1.band_id AS albums_1_band_id, albums_2.id AS albums_2_id, albums_2.band_id AS albums_2_band_id FROM albums LEFT OUTER JOIN albums AS albums_0 ON (albums_0.band_id = albums.id) LEFT OUTER JOIN albums AS albums_1 ON (albums_1.band_id = albums_0.id) LEFT OUTER JOIN albums AS albums_2 ON (albums_2.band_id = albums_1.id) ORDER BY albums_0.band_id, albums_0.id, albums_1.band_id, albums_1.id, albums_2.band_id, albums_2.id'
2119
- end
2120
-
2121
- it "should add the associations :order for multiple associations" do
2122
- GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :order=>:id
2123
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
2124
- GraphAlbum.eager_graph(:a_genres, :b_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, a_genres.id AS a_genres_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS a_genres ON (a_genres.id = ag.genre_id) LEFT OUTER JOIN tracks AS b_tracks ON (b_tracks.album_id = albums.id) ORDER BY a_genres.id, b_tracks.id, b_tracks.album_id'
2125
- end
2126
-
2127
- it "should use the correct qualifier when graphing multiple tables with extra conditions" do
2128
- GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
2129
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:a=>:b}
2130
- GraphAlbum.eager_graph(:a_genres, :b_tracks).sql.must_equal 'SELECT albums.id, albums.band_id, a_genres.id AS a_genres_id, b_tracks.id AS b_tracks_id, b_tracks.album_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS a_genres ON (a_genres.id = ag.genre_id) LEFT OUTER JOIN tracks AS b_tracks ON ((b_tracks.album_id = albums.id) AND (b_tracks.a = albums.b))'
2131
- end
2132
-
2133
- it "should eagerly load associated records for classes that do not have a primary key" do
2134
- GraphAlbum.no_primary_key
2135
- GraphGenre.no_primary_key
2136
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :left_primary_key=>:band_id, :right_key=>:genre_id, :right_primary_key=>:xxx, :join_table=>:ag
2137
- ds = GraphAlbum.eager_graph(:inner_genres)
2138
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, inner_genres.id AS inner_genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.band_id) LEFT OUTER JOIN genres AS inner_genres ON (inner_genres.xxx = ag.genre_id)'
2139
- as = ds.with_fetch([{:id=>3, :band_id=>2, :inner_genres_id=>5, :xxx=>12}, {:id=>3, :band_id=>2, :inner_genres_id=>6, :xxx=>22}]).all
2140
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
2141
- as.first.inner_genres.must_equal [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
2142
- GraphAlbum.set_primary_key :id
2143
- GraphGenre.set_primary_key :id
2144
- end
2145
-
2146
- it "should handle eager loading with schemas and aliases of different types" do
2147
- GraphAlbum.eager_graph(:band).join(Sequel[:s][:genres], [:b_id]).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2148
- GraphAlbum.eager_graph(:band).join(Sequel.qualify(:s, :genres), [:b_id]).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2149
- GraphAlbum.eager_graph(:band).join(Sequel[:s][:b].as('genres'), [:b_id]).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.b AS genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2150
- GraphAlbum.eager_graph(:band).join(Sequel[:s][:b], [:b_id], :table_alias=>Sequel.identifier(:genres)).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.b AS genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2151
- GraphAlbum.eager_graph(:band).join(Sequel.identifier(:genres), [:b_id]).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2152
- GraphAlbum.eager_graph(:band).join('genres', [:b_id]).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2153
- end
2154
-
2155
- with_symbol_splitting "should handle eager loading with splittable symbols" do
2156
- GraphAlbum.eager_graph(:band).join(:s__genres, [:b_id]).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2157
- GraphAlbum.eager_graph(:band).join(Sequel.expr(:s__b).as('genres'), [:b_id]).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.b AS genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2158
- GraphAlbum.eager_graph(:band).join(:s__b, [:b_id], :table_alias=>Sequel.identifier(:genres)).eager_graph(:genres).sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, genres_0.id AS genres_0_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) INNER JOIN s.b AS genres USING (b_id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS genres_0 ON (genres_0.id = ag.genre_id)'
2159
- end
2160
-
2161
- it "should raise errors if invalid aliases or table styles are used" do
2162
- proc{GraphAlbum.from_self(:alias=>Sequel.qualify(:s, :bands)).eager_graph(:band)}.must_raise(Sequel::Error)
2163
- proc{GraphAlbum.from(Sequel.lit('?', :bands)).eager_graph(:band)}.must_raise(Sequel::Error)
2164
- end
2165
-
2166
- it "should eagerly load schema qualified tables correctly with joins" do
2167
- c1 = Class.new(GraphAlbum)
2168
- c2 = Class.new(GraphGenre)
2169
- ds = c1.dataset.from(Sequel[:s][:a]).with_extend{def columns; [:id] end}
2170
- c1.dataset = ds
2171
- ds = c1.dataset
2172
- c2.dataset = c2.dataset.from(Sequel[:s][:g])
2173
- c1.many_to_many :a_genres, :class=>c2, :left_primary_key=>:id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>Sequel[:s][:ag]
2174
- ds = c1.join(Sequel[:s][:t], [:b_id]).eager_graph(:a_genres)
2175
- ds.sql.must_equal 'SELECT a.id, a_genres.id AS a_genres_id FROM (SELECT * FROM s.a INNER JOIN s.t USING (b_id)) AS a LEFT OUTER JOIN s.ag AS ag ON (ag.album_id = a.id) LEFT OUTER JOIN s.g AS a_genres ON (a_genres.id = ag.genre_id)'
2176
- ds = c1.eager_graph(:a_genres)
2177
- ds.sql.must_equal 'SELECT s.a.id, a_genres.id AS a_genres_id FROM s.a LEFT OUTER JOIN s.ag AS ag ON (ag.album_id = s.a.id) LEFT OUTER JOIN s.g AS a_genres ON (a_genres.id = ag.genre_id)'
2178
- end
2179
-
2180
- with_symbol_splitting "should eagerly load schema qualified table symbols correctly with joins" do
2181
- c1 = Class.new(GraphAlbum)
2182
- c2 = Class.new(GraphGenre)
2183
- ds = c1.dataset.from(:s__a).with_extend{def columns; [:id] end}
2184
- c1.dataset = ds
2185
- ds = c1.dataset
2186
- c2.dataset = c2.dataset.from(:s__g)
2187
- c1.many_to_many :a_genres, :class=>c2, :left_primary_key=>:id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:s__ag
2188
- ds = c1.join(:s__t, [:b_id]).eager_graph(:a_genres)
2189
- ds.sql.must_equal 'SELECT a.id, a_genres.id AS a_genres_id FROM (SELECT * FROM s.a INNER JOIN s.t USING (b_id)) AS a LEFT OUTER JOIN s.ag AS ag ON (ag.album_id = a.id) LEFT OUTER JOIN s.g AS a_genres ON (a_genres.id = ag.genre_id)'
2190
- ds = c1.eager_graph(:a_genres)
2191
- ds.sql.must_equal 'SELECT s.a.id, a_genres.id AS a_genres_id FROM s.a LEFT OUTER JOIN s.ag AS ag ON (ag.album_id = s.a.id) LEFT OUTER JOIN s.g AS a_genres ON (a_genres.id = ag.genre_id)'
2192
- end
2193
-
2194
- it "should respect :after_load callbacks on associations when eager graphing" do
2195
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id, :after_load=>proc{|o, a| a.id *=2}
2196
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
2197
- GraphAlbum.many_to_many :al_genres, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
2198
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2199
- ds.sql.must_equal "SELECT albums.id, albums.band_id, al_band.id AS al_band_id, al_band.vocalist_id, al_tracks.id AS al_tracks_id, al_tracks.album_id, al_genres.id AS al_genres_id FROM albums LEFT OUTER JOIN bands AS al_band ON (al_band.id = albums.band_id) LEFT OUTER JOIN tracks AS al_tracks ON (al_tracks.album_id = albums.id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS al_genres ON (al_genres.id = ag.genre_id)"
2200
- a = ds.with_fetch(:id=>1, :band_id=>2, :al_band_id=>3, :vocalist_id=>4, :al_tracks_id=>5, :album_id=>6, :al_genres_id=>7).all.first
2201
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2202
- a.al_band.must_equal GraphBand.load(:id=>6, :vocalist_id=>4)
2203
- a.al_tracks.must_equal [GraphTrack.load(:id=>10, :album_id=>6)]
2204
- a.al_genres.must_equal [GraphGenre.load(:id=>14)]
2205
- end
2206
-
2207
- it "should respect limits on associations when eager graphing" do
2208
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2209
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>2
2210
- GraphAlbum.many_to_many :al_genres, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>2
2211
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2212
- ds.sql.must_equal "SELECT albums.id, albums.band_id, al_band.id AS al_band_id, al_band.vocalist_id, al_tracks.id AS al_tracks_id, al_tracks.album_id, al_genres.id AS al_genres_id FROM albums LEFT OUTER JOIN bands AS al_band ON (al_band.id = albums.band_id) LEFT OUTER JOIN tracks AS al_tracks ON (al_tracks.album_id = albums.id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS al_genres ON (al_genres.id = ag.genre_id)"
2213
- a = ds.with_fetch([{:id=>1, :band_id=>2, :al_band_id=>3, :vocalist_id=>4, :al_tracks_id=>5, :album_id=>6, :al_genres_id=>7},
2214
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_tracks_id=>10, :album_id=>11, :al_genres_id=>12},
2215
- {:id=>1, :band_id=>2, :al_band_id=>13, :vocalist_id=>14, :al_tracks_id=>15, :album_id=>16, :al_genres_id=>17}]).all.first
2216
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2217
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2218
- a.al_tracks.must_equal [GraphTrack.load(:id=>5, :album_id=>6), GraphTrack.load(:id=>10, :album_id=>11)]
2219
- a.al_genres.must_equal [GraphGenre.load(:id=>7), GraphGenre.load(:id=>12)]
2220
- end
2221
-
2222
- it "should handle offsets on associations with no results when eager graphing" do
2223
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>[2, 1]
2224
- ds = GraphAlbum.eager_graph(:al_tracks)
2225
- ds.sql.must_equal "SELECT albums.id, albums.band_id, al_tracks.id AS al_tracks_id, al_tracks.album_id FROM albums LEFT OUTER JOIN tracks AS al_tracks ON (al_tracks.album_id = albums.id)"
2226
- a = ds.with_fetch([{:id=>1, :band_id=>2, :al_tracks_id=>nil, :album_id=>nil}]).all.first
2227
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2228
- a.al_tracks.must_equal []
2229
- end
2230
-
2231
- it "should respect offsets on associations when eager graphing" do
2232
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2233
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>[1, 1]
2234
- GraphAlbum.many_to_many :al_genres, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[1,1]
2235
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2236
- ds.sql.must_equal "SELECT albums.id, albums.band_id, al_band.id AS al_band_id, al_band.vocalist_id, al_tracks.id AS al_tracks_id, al_tracks.album_id, al_genres.id AS al_genres_id FROM albums LEFT OUTER JOIN bands AS al_band ON (al_band.id = albums.band_id) LEFT OUTER JOIN tracks AS al_tracks ON (al_tracks.album_id = albums.id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS al_genres ON (al_genres.id = ag.genre_id)"
2237
- a = ds.with_fetch([{:id=>1, :band_id=>2, :al_band_id=>3, :vocalist_id=>4, :al_tracks_id=>5, :album_id=>6, :al_genres_id=>7},
2238
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_tracks_id=>10, :album_id=>11, :al_genres_id=>12},
2239
- {:id=>1, :band_id=>2, :al_band_id=>13, :vocalist_id=>14, :al_tracks_id=>15, :album_id=>16, :al_genres_id=>17}]).all.first
2240
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2241
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2242
- a.al_tracks.must_equal [GraphTrack.load(:id=>10, :album_id=>11)]
2243
- a.al_genres.must_equal [GraphGenre.load(:id=>12)]
2244
- end
2245
-
2246
- it "should respect offsets on associations when eager graphing one_to_one and one_through_one associations" do
2247
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2248
- GraphAlbum.one_to_one :al_track, :class=>GraphTrack, :key=>:album_id, :limit=>[nil, 1]
2249
- GraphAlbum.one_through_one :al_genre, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[nil,1]
2250
- ds = GraphAlbum.eager_graph(:al_band, :al_track, :al_genre)
2251
- ds.sql.must_equal "SELECT albums.id, albums.band_id, al_band.id AS al_band_id, al_band.vocalist_id, al_track.id AS al_track_id, al_track.album_id, al_genre.id AS al_genre_id FROM albums LEFT OUTER JOIN bands AS al_band ON (al_band.id = albums.band_id) LEFT OUTER JOIN tracks AS al_track ON (al_track.album_id = albums.id) LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN genres AS al_genre ON (al_genre.id = ag.genre_id)"
2252
- a = ds.with_fetch([{:id=>1, :band_id=>2, :al_band_id=>3, :vocalist_id=>4, :al_track_id=>5, :album_id=>6, :al_genre_id=>7},
2253
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_track_id=>10, :album_id=>11, :al_genre_id=>12},
2254
- {:id=>1, :band_id=>2, :al_band_id=>13, :vocalist_id=>14, :al_track_id=>15, :album_id=>16, :al_genre_id=>17}]).all.first
2255
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2256
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2257
- a.al_track.must_equal GraphTrack.load(:id=>10, :album_id=>11)
2258
- a.al_genre.must_equal GraphGenre.load(:id=>12)
2259
- end
2260
-
2261
- it "should not include duplicate objects when eager graphing many_to_one=>one_to_many" do
2262
- ds = GraphAlbum.eager_graph(:band=>:albums)
2263
- ds.sql.must_equal "SELECT albums.id, albums.band_id, band.id AS band_id_0, band.vocalist_id, albums_0.id AS albums_0_id, albums_0.band_id AS albums_0_band_id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.band_id = band.id)"
2264
- a = ds.with_fetch([
2265
- {:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>1, :albums_0_id=>1, :albums_0_band_id=>2},
2266
- {:id=>2, :band_id=>2, :band_id_0=>2, :vocalist_id=>1, :albums_0_id=>1, :albums_0_band_id=>2},
2267
- {:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>1, :albums_0_id=>2, :albums_0_band_id=>2},
2268
- {:id=>2, :band_id=>2, :band_id_0=>2, :vocalist_id=>1, :albums_0_id=>2, :albums_0_band_id=>2}
2269
- ]).all
2270
- albums = [GraphAlbum.load(:id => 1, :band_id => 2), GraphAlbum.load(:id => 2, :band_id => 2)]
2271
- a.must_equal albums
2272
- a.map(&:band).must_equal [GraphBand.load(:id=>2, :vocalist_id=>1), GraphBand.load(:id=>2, :vocalist_id=>1)]
2273
- a.map(&:band).map(&:albums).must_equal [albums, albums]
2274
- end
2275
-
2276
- it "should eagerly load a many_to_one association with a custom callback" do
2277
- ds = GraphAlbum.eager_graph(:band => proc {|ds1| ds1.select(:id).columns(:id)})
2278
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, band.id AS band_id_0 FROM albums LEFT OUTER JOIN (SELECT id FROM bands) AS band ON (band.id = albums.band_id)'
2279
- a = ds.with_fetch(:id=>1, :band_id=>2, :band_id_0=>2).all
2280
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2281
- a.first.band.must_equal GraphBand.load(:id => 2)
2282
- end
2283
-
2284
- it "should eagerly load a one_to_one association with a custom callback" do
2285
- ds = GraphAlbum.eager_graph(:track => proc {|ds1| ds1.select(:album_id).columns(:album_id)})
2286
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, track.album_id FROM albums LEFT OUTER JOIN (SELECT album_id FROM tracks) AS track ON (track.album_id = albums.id)'
2287
- a = ds.with_fetch(:id=>1, :band_id=>2, :album_id=>1).all
2288
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2289
- a.first.track.must_equal GraphTrack.load(:album_id=>1)
2290
- end
2291
-
2292
- it "should eagerly load a one_to_many association with a custom callback" do
2293
- ds = GraphAlbum.eager_graph(:tracks => proc {|ds1| ds1.select(:album_id).columns(:album_id)})
2294
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, tracks.album_id FROM albums LEFT OUTER JOIN (SELECT album_id FROM tracks) AS tracks ON (tracks.album_id = albums.id)'
2295
- a = ds.with_fetch(:id=>1, :band_id=>2, :album_id=>1).all
2296
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2297
- a.first.tracks.must_equal [GraphTrack.load(:album_id=>1)]
2298
- end
2299
-
2300
- it "should eagerly load a one_through_one association with a custom callback" do
2301
- ds = GraphAlbum.eager_graph(:genre => proc {|ds1| ds1.select(:id).columns(:id)})
2302
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genre.id AS genre_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN (SELECT id FROM genres) AS genre ON (genre.id = ag.genre_id)'
2303
- a = ds.with_fetch(:id=>1, :band_id=>2, :genre_id=>4).all
2304
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2305
- a.first.genre.must_equal GraphGenre.load(:id => 4)
2306
- end
2307
-
2308
- it "should eagerly load a many_to_many association with a custom callback" do
2309
- ds = GraphAlbum.eager_graph(:genres => proc {|ds1| ds1.select(:id).columns(:id)})
2310
- ds.sql.must_equal 'SELECT albums.id, albums.band_id, genres.id AS genres_id FROM albums LEFT OUTER JOIN ag ON (ag.album_id = albums.id) LEFT OUTER JOIN (SELECT id FROM genres) AS genres ON (genres.id = ag.genre_id)'
2311
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>4).all
2312
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2313
- a.first.genres.must_equal [GraphGenre.load(:id => 4)]
2314
- end
2315
-
2316
- it "should allow cascading of eager loading with a custom callback with hash value" do
2317
- ds = GraphTrack.eager_graph(:album=>{proc{|ds1| ds1.select(:id, :band_id).columns(:id, :band_id)}=>{:band=>:members}})
2318
- ds.sql.must_equal 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, members.id AS members_id FROM tracks LEFT OUTER JOIN (SELECT id, band_id FROM albums) AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN bm ON (bm.band_id = band.id) LEFT OUTER JOIN members ON (members.id = bm.member_id)'
2319
- a = ds.with_fetch(:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :members_id=>5, :band_id_0=>2, :vocalist_id=>6).all
2320
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2321
- a = a.first
2322
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2323
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
2324
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
2325
- end
2326
-
2327
- it "should allow cascading of eager loading with a custom callback with array value" do
2328
- ds = GraphTrack.eager_graph(:album=>{proc{|ds1| ds1.select(:id, :band_id).columns(:id, :band_id)}=>[:band, :tracks]})
2329
- ds.sql.must_equal 'SELECT tracks.id, tracks.album_id, album.id AS album_id_0, album.band_id, band.id AS band_id_0, band.vocalist_id, tracks_0.id AS tracks_0_id, tracks_0.album_id AS tracks_0_album_id FROM tracks LEFT OUTER JOIN (SELECT id, band_id FROM albums) AS album ON (album.id = tracks.album_id) LEFT OUTER JOIN bands AS band ON (band.id = album.band_id) LEFT OUTER JOIN tracks AS tracks_0 ON (tracks_0.album_id = album.id)'
2330
- a = ds.with_fetch(:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>6, :tracks_0_id=>3, :tracks_0_album_id=>1).all
2331
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2332
- a = a.first
2333
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2334
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
2335
- a.album.tracks.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2336
- end
2337
-
2338
- it "should have frozen internal data structures" do
2339
- ds = GraphAlbum.eager_graph(:band)
2340
- ds.opts[:eager_graph].must_be :frozen?
2341
- ds.opts[:eager_graph].each_value{|v| v.must_be :frozen? if v.is_a?(Hash)}
2342
-
2343
- ds = ds.eager_graph(:tracks)
2344
- ds.opts[:eager_graph].must_be :frozen?
2345
- ds.opts[:eager_graph].each_value{|v| v.must_be :frozen? if v.is_a?(Hash)}
2346
- end
2347
- end
2348
-
2349
- describe "Sequel::Models with double underscores in table names" do
2350
- before do
2351
- @db = Sequel.mock(:fetch=>{:id=>1, :foo_id=>2})
2352
- @Foo = Class.new(Sequel::Model(@db[Sequel.identifier(:fo__os)]))
2353
- @Foo.columns :id, :foo_id
2354
- @Foo.one_to_many :foos, :class=>@Foo
2355
- @db.sqls
2356
- end
2357
-
2358
- it "should have working eager_graph implementations" do
2359
- @db.fetch = {:id=>1, :foo_id=>1, :foos_id=>1, :foos_foo_id=>1}
2360
- foos = @Foo.eager_graph(:foos).all
2361
- @db.sqls.must_equal ["SELECT fo__os.id, fo__os.foo_id, foos.id AS foos_id, foos.foo_id AS foos_foo_id FROM fo__os LEFT OUTER JOIN fo__os AS foos ON (foos._id = fo__os.id)"]
2362
- foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2363
- foos.first.foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2364
- end
2365
-
2366
- it "should have working eager_graph implementations when qualified" do
2367
- @Foo.dataset = Sequel.identifier(:fo__os).qualify(:s)
2368
- @Foo.columns :id, :foo_id
2369
- @db.sqls
2370
- @db.fetch = {:id=>1, :foo_id=>1, :foos_id=>1, :foos_foo_id=>1}
2371
- foos = @Foo.eager_graph(:foos).all
2372
- @db.sqls.must_equal ["SELECT s.fo__os.id, s.fo__os.foo_id, foos.id AS foos_id, foos.foo_id AS foos_foo_id FROM s.fo__os LEFT OUTER JOIN s.fo__os AS foos ON (foos._id = s.fo__os.id)"]
2373
- foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2374
- foos.first.foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2375
- end
2376
- end
2377
-