sequel 5.8.0 → 5.38.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 (510) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +409 -1795
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/bin/sequel +4 -0
  6. data/doc/advanced_associations.rdoc +136 -18
  7. data/doc/association_basics.rdoc +10 -5
  8. data/doc/cheat_sheet.rdoc +1 -0
  9. data/doc/code_order.rdoc +12 -2
  10. data/doc/dataset_filtering.rdoc +17 -2
  11. data/doc/mass_assignment.rdoc +3 -3
  12. data/doc/model_dataset_method_design.rdoc +1 -1
  13. data/doc/model_plugins.rdoc +1 -1
  14. data/doc/opening_databases.rdoc +30 -8
  15. data/doc/postgresql.rdoc +107 -2
  16. data/doc/release_notes/5.10.0.txt +84 -0
  17. data/doc/release_notes/5.11.0.txt +83 -0
  18. data/doc/release_notes/5.12.0.txt +141 -0
  19. data/doc/release_notes/5.13.0.txt +27 -0
  20. data/doc/release_notes/5.14.0.txt +63 -0
  21. data/doc/release_notes/5.15.0.txt +39 -0
  22. data/doc/release_notes/5.16.0.txt +110 -0
  23. data/doc/release_notes/5.17.0.txt +31 -0
  24. data/doc/release_notes/5.18.0.txt +69 -0
  25. data/doc/release_notes/5.19.0.txt +28 -0
  26. data/doc/release_notes/5.20.0.txt +89 -0
  27. data/doc/release_notes/5.21.0.txt +87 -0
  28. data/doc/release_notes/5.22.0.txt +48 -0
  29. data/doc/release_notes/5.23.0.txt +56 -0
  30. data/doc/release_notes/5.24.0.txt +56 -0
  31. data/doc/release_notes/5.25.0.txt +32 -0
  32. data/doc/release_notes/5.26.0.txt +35 -0
  33. data/doc/release_notes/5.27.0.txt +21 -0
  34. data/doc/release_notes/5.28.0.txt +16 -0
  35. data/doc/release_notes/5.29.0.txt +22 -0
  36. data/doc/release_notes/5.30.0.txt +20 -0
  37. data/doc/release_notes/5.31.0.txt +148 -0
  38. data/doc/release_notes/5.32.0.txt +46 -0
  39. data/doc/release_notes/5.33.0.txt +24 -0
  40. data/doc/release_notes/5.34.0.txt +40 -0
  41. data/doc/release_notes/5.35.0.txt +56 -0
  42. data/doc/release_notes/5.36.0.txt +60 -0
  43. data/doc/release_notes/5.37.0.txt +30 -0
  44. data/doc/release_notes/5.38.0.txt +28 -0
  45. data/doc/release_notes/5.9.0.txt +99 -0
  46. data/doc/security.rdoc +10 -0
  47. data/doc/sharding.rdoc +42 -28
  48. data/doc/sql.rdoc +12 -0
  49. data/doc/testing.rdoc +24 -17
  50. data/doc/transactions.rdoc +78 -0
  51. data/doc/validations.rdoc +2 -2
  52. data/lib/sequel/adapters/ado.rb +26 -18
  53. data/lib/sequel/adapters/ado/access.rb +2 -2
  54. data/lib/sequel/adapters/ado/mssql.rb +5 -8
  55. data/lib/sequel/adapters/amalgalite.rb +1 -1
  56. data/lib/sequel/adapters/jdbc.rb +71 -27
  57. data/lib/sequel/adapters/jdbc/mysql.rb +6 -6
  58. data/lib/sequel/adapters/jdbc/oracle.rb +7 -6
  59. data/lib/sequel/adapters/jdbc/postgresql.rb +17 -28
  60. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +5 -6
  61. data/lib/sequel/adapters/jdbc/sqlite.rb +33 -2
  62. data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -3
  63. data/lib/sequel/adapters/jdbc/transactions.rb +14 -28
  64. data/lib/sequel/adapters/mysql.rb +14 -15
  65. data/lib/sequel/adapters/mysql2.rb +5 -3
  66. data/lib/sequel/adapters/odbc.rb +4 -6
  67. data/lib/sequel/adapters/oracle.rb +7 -7
  68. data/lib/sequel/adapters/postgres.rb +52 -16
  69. data/lib/sequel/adapters/shared/access.rb +16 -12
  70. data/lib/sequel/adapters/shared/db2.rb +5 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +41 -18
  72. data/lib/sequel/adapters/shared/mysql.rb +66 -19
  73. data/lib/sequel/adapters/shared/oracle.rb +29 -23
  74. data/lib/sequel/adapters/shared/postgres.rb +341 -95
  75. data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
  76. data/lib/sequel/adapters/shared/sqlite.rb +174 -21
  77. data/lib/sequel/adapters/sqlanywhere.rb +33 -17
  78. data/lib/sequel/adapters/sqlite.rb +78 -68
  79. data/lib/sequel/adapters/tinytds.rb +14 -6
  80. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +2 -5
  81. data/lib/sequel/adapters/utils/mysql_mysql2.rb +5 -1
  82. data/lib/sequel/connection_pool.rb +2 -6
  83. data/lib/sequel/connection_pool/sharded_single.rb +7 -4
  84. data/lib/sequel/connection_pool/sharded_threaded.rb +32 -21
  85. data/lib/sequel/connection_pool/single.rb +1 -1
  86. data/lib/sequel/connection_pool/threaded.rb +26 -11
  87. data/lib/sequel/core.rb +327 -319
  88. data/lib/sequel/database/connecting.rb +7 -8
  89. data/lib/sequel/database/logging.rb +7 -1
  90. data/lib/sequel/database/misc.rb +68 -34
  91. data/lib/sequel/database/query.rb +6 -4
  92. data/lib/sequel/database/schema_generator.rb +31 -11
  93. data/lib/sequel/database/schema_methods.rb +32 -22
  94. data/lib/sequel/database/transactions.rb +129 -25
  95. data/lib/sequel/dataset.rb +4 -2
  96. data/lib/sequel/dataset/actions.rb +34 -23
  97. data/lib/sequel/dataset/features.rb +34 -0
  98. data/lib/sequel/dataset/graph.rb +27 -11
  99. data/lib/sequel/dataset/misc.rb +17 -3
  100. data/lib/sequel/dataset/placeholder_literalizer.rb +50 -21
  101. data/lib/sequel/dataset/prepared_statements.rb +96 -26
  102. data/lib/sequel/dataset/query.rb +43 -8
  103. data/lib/sequel/dataset/sql.rb +189 -41
  104. data/lib/sequel/deprecated.rb +3 -1
  105. data/lib/sequel/exceptions.rb +2 -0
  106. data/lib/sequel/extensions/_pretty_table.rb +1 -2
  107. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  108. data/lib/sequel/extensions/caller_logging.rb +79 -0
  109. data/lib/sequel/extensions/columns_introspection.rb +1 -2
  110. data/lib/sequel/extensions/connection_expiration.rb +6 -6
  111. data/lib/sequel/extensions/connection_validator.rb +7 -6
  112. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  113. data/lib/sequel/extensions/constraint_validations.rb +53 -28
  114. data/lib/sequel/extensions/core_refinements.rb +2 -0
  115. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -0
  116. data/lib/sequel/extensions/escaped_like.rb +100 -0
  117. data/lib/sequel/extensions/eval_inspect.rb +3 -1
  118. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  119. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  120. data/lib/sequel/extensions/index_caching.rb +9 -7
  121. data/lib/sequel/extensions/integer64.rb +3 -1
  122. data/lib/sequel/extensions/looser_typecasting.rb +3 -3
  123. data/lib/sequel/extensions/migration.rb +13 -6
  124. data/lib/sequel/extensions/named_timezones.rb +84 -23
  125. data/lib/sequel/extensions/pg_array.rb +87 -79
  126. data/lib/sequel/extensions/pg_array_ops.rb +14 -6
  127. data/lib/sequel/extensions/pg_enum.rb +34 -18
  128. data/lib/sequel/extensions/pg_extended_date_support.rb +34 -14
  129. data/lib/sequel/extensions/pg_hstore.rb +6 -0
  130. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  131. data/lib/sequel/extensions/pg_inet.rb +15 -5
  132. data/lib/sequel/extensions/pg_interval.rb +2 -0
  133. data/lib/sequel/extensions/pg_json.rb +387 -123
  134. data/lib/sequel/extensions/pg_json_ops.rb +168 -0
  135. data/lib/sequel/extensions/pg_range.rb +20 -10
  136. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  137. data/lib/sequel/extensions/pg_row.rb +3 -2
  138. data/lib/sequel/extensions/pg_row_ops.rb +24 -0
  139. data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
  140. data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
  141. data/lib/sequel/extensions/query.rb +1 -0
  142. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  143. data/lib/sequel/extensions/s.rb +2 -0
  144. data/lib/sequel/extensions/schema_dumper.rb +13 -7
  145. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +4 -2
  146. data/lib/sequel/extensions/server_block.rb +18 -7
  147. data/lib/sequel/extensions/sql_comments.rb +2 -2
  148. data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
  149. data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
  150. data/lib/sequel/extensions/to_dot.rb +9 -3
  151. data/lib/sequel/model.rb +3 -1
  152. data/lib/sequel/model/associations.rb +403 -69
  153. data/lib/sequel/model/base.rb +170 -90
  154. data/lib/sequel/model/plugins.rb +105 -0
  155. data/lib/sequel/plugins/after_initialize.rb +1 -1
  156. data/lib/sequel/plugins/association_dependencies.rb +3 -3
  157. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  158. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  159. data/lib/sequel/plugins/association_pks.rb +74 -22
  160. data/lib/sequel/plugins/association_proxies.rb +6 -2
  161. data/lib/sequel/plugins/auto_validations.rb +36 -17
  162. data/lib/sequel/plugins/blacklist_security.rb +1 -2
  163. data/lib/sequel/plugins/boolean_subsets.rb +4 -1
  164. data/lib/sequel/plugins/caching.rb +3 -0
  165. data/lib/sequel/plugins/class_table_inheritance.rb +62 -34
  166. data/lib/sequel/plugins/composition.rb +13 -9
  167. data/lib/sequel/plugins/csv_serializer.rb +28 -9
  168. data/lib/sequel/plugins/defaults_setter.rb +2 -2
  169. data/lib/sequel/plugins/dirty.rb +60 -22
  170. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  171. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  172. data/lib/sequel/plugins/finder.rb +2 -2
  173. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  174. data/lib/sequel/plugins/hook_class_methods.rb +17 -5
  175. data/lib/sequel/plugins/insert_conflict.rb +72 -0
  176. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  177. data/lib/sequel/plugins/inverted_subsets.rb +2 -2
  178. data/lib/sequel/plugins/json_serializer.rb +21 -14
  179. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  180. data/lib/sequel/plugins/list.rb +22 -10
  181. data/lib/sequel/plugins/many_through_many.rb +1 -1
  182. data/lib/sequel/plugins/nested_attributes.rb +27 -5
  183. data/lib/sequel/plugins/pg_array_associations.rb +12 -9
  184. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +149 -61
  185. data/lib/sequel/plugins/prepared_statements.rb +6 -12
  186. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
  187. data/lib/sequel/plugins/rcte_tree.rb +20 -22
  188. data/lib/sequel/plugins/sharding.rb +13 -7
  189. data/lib/sequel/plugins/single_table_inheritance.rb +20 -15
  190. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  191. data/lib/sequel/plugins/static_cache.rb +36 -17
  192. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  193. data/lib/sequel/plugins/string_stripper.rb +1 -1
  194. data/lib/sequel/plugins/subclasses.rb +2 -0
  195. data/lib/sequel/plugins/subset_conditions.rb +2 -2
  196. data/lib/sequel/plugins/tactical_eager_loading.rb +73 -2
  197. data/lib/sequel/plugins/throw_failures.rb +110 -0
  198. data/lib/sequel/plugins/tree.rb +49 -31
  199. data/lib/sequel/plugins/typecast_on_load.rb +3 -2
  200. data/lib/sequel/plugins/validation_class_methods.rb +11 -5
  201. data/lib/sequel/plugins/validation_helpers.rb +2 -2
  202. data/lib/sequel/sql.rb +120 -30
  203. data/lib/sequel/timezones.rb +55 -14
  204. data/lib/sequel/version.rb +6 -1
  205. metadata +101 -361
  206. data/Rakefile +0 -151
  207. data/doc/release_notes/4.0.0.txt +0 -262
  208. data/doc/release_notes/4.1.0.txt +0 -85
  209. data/doc/release_notes/4.10.0.txt +0 -226
  210. data/doc/release_notes/4.11.0.txt +0 -147
  211. data/doc/release_notes/4.12.0.txt +0 -105
  212. data/doc/release_notes/4.13.0.txt +0 -169
  213. data/doc/release_notes/4.14.0.txt +0 -68
  214. data/doc/release_notes/4.15.0.txt +0 -56
  215. data/doc/release_notes/4.16.0.txt +0 -36
  216. data/doc/release_notes/4.17.0.txt +0 -38
  217. data/doc/release_notes/4.18.0.txt +0 -36
  218. data/doc/release_notes/4.19.0.txt +0 -45
  219. data/doc/release_notes/4.2.0.txt +0 -129
  220. data/doc/release_notes/4.20.0.txt +0 -79
  221. data/doc/release_notes/4.21.0.txt +0 -94
  222. data/doc/release_notes/4.22.0.txt +0 -72
  223. data/doc/release_notes/4.23.0.txt +0 -65
  224. data/doc/release_notes/4.24.0.txt +0 -99
  225. data/doc/release_notes/4.25.0.txt +0 -181
  226. data/doc/release_notes/4.26.0.txt +0 -44
  227. data/doc/release_notes/4.27.0.txt +0 -78
  228. data/doc/release_notes/4.28.0.txt +0 -57
  229. data/doc/release_notes/4.29.0.txt +0 -41
  230. data/doc/release_notes/4.3.0.txt +0 -40
  231. data/doc/release_notes/4.30.0.txt +0 -37
  232. data/doc/release_notes/4.31.0.txt +0 -57
  233. data/doc/release_notes/4.32.0.txt +0 -132
  234. data/doc/release_notes/4.33.0.txt +0 -88
  235. data/doc/release_notes/4.34.0.txt +0 -86
  236. data/doc/release_notes/4.35.0.txt +0 -130
  237. data/doc/release_notes/4.36.0.txt +0 -116
  238. data/doc/release_notes/4.37.0.txt +0 -50
  239. data/doc/release_notes/4.38.0.txt +0 -67
  240. data/doc/release_notes/4.39.0.txt +0 -127
  241. data/doc/release_notes/4.4.0.txt +0 -92
  242. data/doc/release_notes/4.40.0.txt +0 -179
  243. data/doc/release_notes/4.41.0.txt +0 -77
  244. data/doc/release_notes/4.42.0.txt +0 -221
  245. data/doc/release_notes/4.43.0.txt +0 -87
  246. data/doc/release_notes/4.44.0.txt +0 -125
  247. data/doc/release_notes/4.45.0.txt +0 -370
  248. data/doc/release_notes/4.46.0.txt +0 -404
  249. data/doc/release_notes/4.47.0.txt +0 -56
  250. data/doc/release_notes/4.48.0.txt +0 -293
  251. data/doc/release_notes/4.49.0.txt +0 -222
  252. data/doc/release_notes/4.5.0.txt +0 -34
  253. data/doc/release_notes/4.6.0.txt +0 -30
  254. data/doc/release_notes/4.7.0.txt +0 -103
  255. data/doc/release_notes/4.8.0.txt +0 -175
  256. data/doc/release_notes/4.9.0.txt +0 -190
  257. data/spec/adapter_spec.rb +0 -4
  258. data/spec/adapters/db2_spec.rb +0 -170
  259. data/spec/adapters/mssql_spec.rb +0 -804
  260. data/spec/adapters/mysql_spec.rb +0 -1041
  261. data/spec/adapters/oracle_spec.rb +0 -327
  262. data/spec/adapters/postgres_spec.rb +0 -4000
  263. data/spec/adapters/spec_helper.rb +0 -43
  264. data/spec/adapters/sqlanywhere_spec.rb +0 -97
  265. data/spec/adapters/sqlite_spec.rb +0 -600
  266. data/spec/bin_spec.rb +0 -269
  267. data/spec/core/connection_pool_spec.rb +0 -1228
  268. data/spec/core/database_spec.rb +0 -2673
  269. data/spec/core/dataset_spec.rb +0 -5419
  270. data/spec/core/deprecated_spec.rb +0 -70
  271. data/spec/core/expression_filters_spec.rb +0 -1344
  272. data/spec/core/mock_adapter_spec.rb +0 -722
  273. data/spec/core/object_graph_spec.rb +0 -306
  274. data/spec/core/placeholder_literalizer_spec.rb +0 -166
  275. data/spec/core/schema_generator_spec.rb +0 -214
  276. data/spec/core/schema_spec.rb +0 -1820
  277. data/spec/core/spec_helper.rb +0 -23
  278. data/spec/core/version_spec.rb +0 -7
  279. data/spec/core_extensions_spec.rb +0 -762
  280. data/spec/core_model_spec.rb +0 -2
  281. data/spec/core_spec.rb +0 -1
  282. data/spec/deprecation_helper.rb +0 -30
  283. data/spec/extensions/accessed_columns_spec.rb +0 -51
  284. data/spec/extensions/active_model_spec.rb +0 -99
  285. data/spec/extensions/after_initialize_spec.rb +0 -24
  286. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  287. data/spec/extensions/association_dependencies_spec.rb +0 -125
  288. data/spec/extensions/association_pks_spec.rb +0 -423
  289. data/spec/extensions/association_proxies_spec.rb +0 -100
  290. data/spec/extensions/auto_literal_strings_spec.rb +0 -205
  291. data/spec/extensions/auto_validations_spec.rb +0 -202
  292. data/spec/extensions/blacklist_security_spec.rb +0 -95
  293. data/spec/extensions/blank_spec.rb +0 -69
  294. data/spec/extensions/boolean_readers_spec.rb +0 -93
  295. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  296. data/spec/extensions/caching_spec.rb +0 -273
  297. data/spec/extensions/class_table_inheritance_spec.rb +0 -568
  298. data/spec/extensions/column_conflicts_spec.rb +0 -75
  299. data/spec/extensions/column_select_spec.rb +0 -129
  300. data/spec/extensions/columns_introspection_spec.rb +0 -90
  301. data/spec/extensions/columns_updated_spec.rb +0 -35
  302. data/spec/extensions/composition_spec.rb +0 -248
  303. data/spec/extensions/connection_expiration_spec.rb +0 -133
  304. data/spec/extensions/connection_validator_spec.rb +0 -127
  305. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -300
  306. data/spec/extensions/constraint_validations_spec.rb +0 -395
  307. data/spec/extensions/core_refinements_spec.rb +0 -528
  308. data/spec/extensions/csv_serializer_spec.rb +0 -183
  309. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  310. data/spec/extensions/dataset_associations_spec.rb +0 -365
  311. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  312. data/spec/extensions/date_arithmetic_spec.rb +0 -181
  313. data/spec/extensions/datetime_parse_to_time_spec.rb +0 -169
  314. data/spec/extensions/def_dataset_method_spec.rb +0 -100
  315. data/spec/extensions/defaults_setter_spec.rb +0 -141
  316. data/spec/extensions/delay_add_association_spec.rb +0 -73
  317. data/spec/extensions/dirty_spec.rb +0 -189
  318. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -104
  319. data/spec/extensions/eager_each_spec.rb +0 -62
  320. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  321. data/spec/extensions/error_splitter_spec.rb +0 -18
  322. data/spec/extensions/error_sql_spec.rb +0 -20
  323. data/spec/extensions/eval_inspect_spec.rb +0 -74
  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 -380
  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 -275
  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 -840
  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 -109
  348. data/spec/extensions/nested_attributes_spec.rb +0 -703
  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 -165
  356. data/spec/extensions/pg_enum_spec.rb +0 -113
  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 -487
  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 -182
  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 -868
  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 -61
  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 -410
  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 -141
  409. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  410. data/spec/extensions/timestamps_spec.rb +0 -209
  411. data/spec/extensions/to_dot_spec.rb +0 -153
  412. data/spec/extensions/touch_spec.rb +0 -226
  413. data/spec/extensions/tree_spec.rb +0 -284
  414. data/spec/extensions/typecast_on_load_spec.rb +0 -86
  415. data/spec/extensions/unlimited_update_spec.rb +0 -21
  416. data/spec/extensions/update_or_create_spec.rb +0 -83
  417. data/spec/extensions/update_primary_key_spec.rb +0 -105
  418. data/spec/extensions/update_refresh_spec.rb +0 -59
  419. data/spec/extensions/uuid_spec.rb +0 -101
  420. data/spec/extensions/validate_associated_spec.rb +0 -52
  421. data/spec/extensions/validation_class_methods_spec.rb +0 -1040
  422. data/spec/extensions/validation_contexts_spec.rb +0 -31
  423. data/spec/extensions/validation_helpers_spec.rb +0 -525
  424. data/spec/extensions/whitelist_security_spec.rb +0 -157
  425. data/spec/extensions/xml_serializer_spec.rb +0 -213
  426. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  427. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  428. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  429. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  430. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  431. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  432. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  433. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  434. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  435. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  436. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  437. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  438. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  439. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  440. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  441. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  442. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  443. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  444. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  445. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  446. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  447. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  448. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  449. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  450. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  451. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  452. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  453. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  454. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  455. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  456. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  457. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  458. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  459. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  460. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  461. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  462. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  463. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  464. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  465. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  466. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  467. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  468. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  469. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  470. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  471. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  472. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  473. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  474. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  475. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  476. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  477. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  478. data/spec/guards_helper.rb +0 -58
  479. data/spec/integration/associations_test.rb +0 -2513
  480. data/spec/integration/database_test.rb +0 -113
  481. data/spec/integration/dataset_test.rb +0 -1880
  482. data/spec/integration/eager_loader_test.rb +0 -687
  483. data/spec/integration/migrator_test.rb +0 -262
  484. data/spec/integration/model_test.rb +0 -203
  485. data/spec/integration/plugin_test.rb +0 -2302
  486. data/spec/integration/prepared_statement_test.rb +0 -398
  487. data/spec/integration/schema_test.rb +0 -869
  488. data/spec/integration/spec_helper.rb +0 -64
  489. data/spec/integration/timezone_test.rb +0 -86
  490. data/spec/integration/transaction_test.rb +0 -354
  491. data/spec/integration/type_test.rb +0 -127
  492. data/spec/model/association_reflection_spec.rb +0 -803
  493. data/spec/model/associations_spec.rb +0 -4538
  494. data/spec/model/base_spec.rb +0 -817
  495. data/spec/model/class_dataset_methods_spec.rb +0 -146
  496. data/spec/model/dataset_methods_spec.rb +0 -198
  497. data/spec/model/eager_loading_spec.rb +0 -2262
  498. data/spec/model/hooks_spec.rb +0 -370
  499. data/spec/model/inflector_spec.rb +0 -26
  500. data/spec/model/model_spec.rb +0 -953
  501. data/spec/model/plugins_spec.rb +0 -318
  502. data/spec/model/record_spec.rb +0 -2107
  503. data/spec/model/spec_helper.rb +0 -45
  504. data/spec/model/validations_spec.rb +0 -193
  505. data/spec/model_no_assoc_spec.rb +0 -1
  506. data/spec/model_spec.rb +0 -1
  507. data/spec/plugin_spec.rb +0 -1
  508. data/spec/sequel_coverage.rb +0 -15
  509. data/spec/sequel_warning.rb +0 -4
  510. data/spec/spec_config.rb +0 -12
@@ -1,146 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe Sequel::Model, "class dataset methods" do
4
- before do
5
- @db = Sequel.mock
6
- @c = Class.new(Sequel::Model(@db[:items].with_extend{def supports_cte?(*) true end}.with_fetch(:id=>1).with_autoid(1).with_numrows(0)))
7
- @d = @c.dataset
8
- @db.sqls
9
- end
10
-
11
- it "should call the dataset method of the same name with the same args" do
12
- @c.all.must_equal [@c.load(:id=>1)]
13
- @db.sqls.must_equal ["SELECT * FROM items"]
14
- @c.avg(:id).must_equal 1
15
- @db.sqls.must_equal ["SELECT avg(id) AS avg FROM items LIMIT 1"]
16
- @c.count.must_equal 1
17
- @db.sqls.must_equal ["SELECT count(*) AS count FROM items LIMIT 1"]
18
- @c.cross_join(@c.table_name).sql.must_equal "SELECT * FROM items CROSS JOIN items"
19
- @c.distinct.sql.must_equal "SELECT DISTINCT * FROM items"
20
- @c.each{|r| r.must_equal @c.load(:id=>1)}.must_equal @d
21
- @db.sqls.must_equal ["SELECT * FROM items"]
22
- @c.each_server{|r| r.opts[:server].must_equal :default}
23
- @c.empty?.must_equal false
24
- @db.sqls.must_equal ["SELECT 1 AS one FROM items LIMIT 1"]
25
- @c.except(@d, :from_self=>false).sql.must_equal "SELECT * FROM items EXCEPT SELECT * FROM items"
26
- @c.exclude(:a).sql.must_equal "SELECT * FROM items WHERE NOT a"
27
- @c.exclude_having(:a).sql.must_equal "SELECT * FROM items HAVING NOT a"
28
- @c.fetch_rows("S"){|r| r.must_equal(:id=>1)}
29
- @db.sqls.must_equal ["S"]
30
- @c.filter(:a).sql.must_equal "SELECT * FROM items WHERE a"
31
- @c.first.must_equal @c.load(:id=>1)
32
- @db.sqls.must_equal ["SELECT * FROM items LIMIT 1"]
33
- @c.first!.must_equal @c.load(:id=>1)
34
- @db.sqls.must_equal ["SELECT * FROM items LIMIT 1"]
35
- @c.for_update.sql.must_equal "SELECT * FROM items FOR UPDATE"
36
- @c.from.sql.must_equal "SELECT *"
37
- @c.from_self.sql.must_equal "SELECT * FROM (SELECT * FROM items) AS t1"
38
- @c.full_join(@c.table_name).sql.must_equal "SELECT * FROM items FULL JOIN items"
39
- @c.full_outer_join(@c.table_name).sql.must_equal "SELECT * FROM items FULL OUTER JOIN items"
40
- @c.get(:a).must_equal 1
41
- @db.sqls.must_equal ["SELECT a FROM items LIMIT 1"]
42
- @c.graph(@c.table_name, nil, :table_alias=>:a).sql.must_equal "SELECT * FROM items LEFT OUTER JOIN items AS a"
43
- @db.sqls
44
- @c.grep(:id, 'a%').sql.must_equal "SELECT * FROM items WHERE ((id LIKE 'a%' ESCAPE '\\'))"
45
- @c.group(:a).sql.must_equal "SELECT * FROM items GROUP BY a"
46
- @c.group_append(:a).sql.must_equal "SELECT * FROM items GROUP BY a"
47
- @c.group_and_count(:a).sql.must_equal "SELECT a, count(*) AS count FROM items GROUP BY a"
48
- @c.group_by(:a).sql.must_equal "SELECT * FROM items GROUP BY a"
49
- @c.having(:a).sql.must_equal "SELECT * FROM items HAVING a"
50
- @c.import([:id], [[1]])
51
- @db.sqls.must_equal ["BEGIN", "INSERT INTO items (id) VALUES (1)", "COMMIT"]
52
- @c.inner_join(@c.table_name).sql.must_equal "SELECT * FROM items INNER JOIN items"
53
- @c.insert.must_equal 1
54
- @db.sqls.must_equal ["INSERT INTO items DEFAULT VALUES"]
55
- @c.intersect(@d, :from_self=>false).sql.must_equal "SELECT * FROM items INTERSECT SELECT * FROM items"
56
- @c.join(@c.table_name).sql.must_equal "SELECT * FROM items INNER JOIN items"
57
- @c.join_table(:inner, @c.table_name).sql.must_equal "SELECT * FROM items INNER JOIN items"
58
- @c.last.must_equal @c.load(:id=>1)
59
- @db.sqls.must_equal ["SELECT * FROM items ORDER BY id DESC LIMIT 1"]
60
- @c.left_join(@c.table_name).sql.must_equal "SELECT * FROM items LEFT JOIN items"
61
- @c.left_outer_join(@c.table_name).sql.must_equal "SELECT * FROM items LEFT OUTER JOIN items"
62
- @c.limit(2).sql.must_equal "SELECT * FROM items LIMIT 2"
63
- @c.lock_style(:update).sql.must_equal "SELECT * FROM items FOR UPDATE"
64
- @c.map(:id).must_equal [1]
65
- @db.sqls.must_equal ["SELECT * FROM items"]
66
- @c.max(:id).must_equal 1
67
- @db.sqls.must_equal ["SELECT max(id) AS max FROM items LIMIT 1"]
68
- @c.min(:id).must_equal 1
69
- @db.sqls.must_equal ["SELECT min(id) AS min FROM items LIMIT 1"]
70
- @c.multi_insert([{:id=>1}])
71
- @db.sqls.must_equal ["BEGIN", "INSERT INTO items (id) VALUES (1)", "COMMIT"]
72
- @c.naked.row_proc.must_be_nil
73
- @c.natural_full_join(@c.table_name).sql.must_equal "SELECT * FROM items NATURAL FULL JOIN items"
74
- @c.natural_join(@c.table_name).sql.must_equal "SELECT * FROM items NATURAL JOIN items"
75
- @c.natural_left_join(@c.table_name).sql.must_equal "SELECT * FROM items NATURAL LEFT JOIN items"
76
- @c.natural_right_join(@c.table_name).sql.must_equal "SELECT * FROM items NATURAL RIGHT JOIN items"
77
- @c.offset(2).sql.must_equal "SELECT * FROM items OFFSET 2"
78
- @c.order(:a).sql.must_equal "SELECT * FROM items ORDER BY a"
79
- @c.order_append(:a).sql.must_equal "SELECT * FROM items ORDER BY a"
80
- @c.order_by(:a).sql.must_equal "SELECT * FROM items ORDER BY a"
81
- @c.order_more(:a).sql.must_equal "SELECT * FROM items ORDER BY a"
82
- @c.order_prepend(:a).sql.must_equal "SELECT * FROM items ORDER BY a"
83
- @c.paged_each{|r| r.must_equal @c.load(:id=>1)}
84
- @db.sqls.must_equal ["BEGIN", "SELECT * FROM items ORDER BY id LIMIT 1000 OFFSET 0", "COMMIT"]
85
- @c.qualify.sql.must_equal 'SELECT items.* FROM items'
86
- @c.right_join(@c.table_name).sql.must_equal "SELECT * FROM items RIGHT JOIN items"
87
- @c.right_outer_join(@c.table_name).sql.must_equal "SELECT * FROM items RIGHT OUTER JOIN items"
88
- @c.select(:a).sql.must_equal "SELECT a FROM items"
89
- @c.select_all(:items).sql.must_equal "SELECT items.* FROM items"
90
- @c.select_append(:a).sql.must_equal "SELECT *, a FROM items"
91
- @c.select_group(:a).sql.must_equal "SELECT a FROM items GROUP BY a"
92
- @c.select_hash(:id, :id).must_equal(1=>1)
93
- @db.sqls.must_equal ["SELECT id, id FROM items"]
94
- @c.select_hash_groups(:id, :id).must_equal(1=>[1])
95
- @db.sqls.must_equal ["SELECT id, id FROM items"]
96
- @c.select_map(:id).must_equal [1]
97
- @db.sqls.must_equal ["SELECT id FROM items"]
98
- @c.select_order_map(:id).must_equal [1]
99
- @db.sqls.must_equal ["SELECT id FROM items ORDER BY id"]
100
- @c.server(:a).opts[:server].must_equal :a
101
- @c.single_record.must_equal @c.load(:id=>1)
102
- @db.sqls.must_equal ["SELECT * FROM items LIMIT 1"]
103
- @c.single_record!.must_equal @c.load(:id=>1)
104
- @db.sqls.must_equal ["SELECT * FROM items"]
105
- @c.single_value.must_equal 1
106
- @db.sqls.must_equal ["SELECT * FROM items LIMIT 1"]
107
- @c.single_value!.must_equal 1
108
- @db.sqls.must_equal ["SELECT * FROM items"]
109
- @c.sum(:id).must_equal 1
110
- @db.sqls.must_equal ["SELECT sum(id) AS sum FROM items LIMIT 1"]
111
- @c.as_hash(:id, :id).must_equal(1=>1)
112
- @db.sqls.must_equal ["SELECT * FROM items"]
113
- @c.to_hash(:id, :id).must_equal(1=>1)
114
- @db.sqls.must_equal ["SELECT * FROM items"]
115
- @c.to_hash_groups(:id, :id).must_equal(1=>[1])
116
- @db.sqls.must_equal ["SELECT * FROM items"]
117
- @c.truncate
118
- @db.sqls.must_equal ["TRUNCATE TABLE items"]
119
- @c.union(@d, :from_self=>false).sql.must_equal "SELECT * FROM items UNION SELECT * FROM items"
120
- @c.where(:a).sql.must_equal "SELECT * FROM items WHERE a"
121
- @c.with(:a, @d).sql.must_equal "WITH a AS (SELECT * FROM items) SELECT * FROM items"
122
- @c.with_recursive(:a, @d, @d).sql.must_equal "WITH a AS (SELECT * FROM items UNION ALL SELECT * FROM items) SELECT * FROM items"
123
- @c.with_sql('S').sql.must_equal "S"
124
- @c.where_all(:id=>1){|r|}.must_equal [@c.load(:id=>1)]
125
- @db.sqls.must_equal ["SELECT * FROM items WHERE (id = 1)"]
126
- @c.where_each(:id=>1){|r|}
127
- @db.sqls.must_equal ["SELECT * FROM items WHERE (id = 1)"]
128
- @c.where_single_value(:id=>1).must_equal 1
129
- @db.sqls.must_equal ["SELECT * FROM items WHERE (id = 1) LIMIT 1"]
130
-
131
- sc = Class.new(@c)
132
- sc.set_dataset(@d.where(:a).order(:a).select(:a).group(:a).limit(2))
133
- @db.sqls
134
- sc.invert.sql.must_equal 'SELECT a FROM items WHERE NOT a GROUP BY a ORDER BY a LIMIT 2'
135
- sc.dataset = sc.dataset.with_fetch(:v1=>1, :v2=>2)
136
- @db.sqls
137
- sc.reverse.sql.must_equal 'SELECT a FROM items WHERE a GROUP BY a ORDER BY a DESC LIMIT 2'
138
- sc.reverse_order.sql.must_equal 'SELECT a FROM items WHERE a GROUP BY a ORDER BY a DESC LIMIT 2'
139
- sc.select_more(:a).sql.must_equal 'SELECT a, a FROM items WHERE a GROUP BY a ORDER BY a LIMIT 2'
140
- sc.unfiltered.sql.must_equal 'SELECT a FROM items GROUP BY a ORDER BY a LIMIT 2'
141
- sc.ungrouped.sql.must_equal 'SELECT a FROM items WHERE a ORDER BY a LIMIT 2'
142
- sc.unordered.sql.must_equal 'SELECT a FROM items WHERE a GROUP BY a LIMIT 2'
143
- sc.unlimited.sql.must_equal 'SELECT a FROM items WHERE a GROUP BY a ORDER BY a'
144
- sc.dataset.graph(:a).ungraphed.opts[:graph].must_be_nil
145
- end
146
- end
@@ -1,198 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe Sequel::Model::DatasetMethods, "#destroy" do
4
- before do
5
- @c = Class.new(Sequel::Model(:items)) do
6
- self::Destroyed = []
7
- def destroy
8
- model::Destroyed << self
9
- end
10
- end
11
- @d = @c.dataset
12
- @d = @d.with_fetch([{:id=>1}, {:id=>2}])
13
- DB.reset
14
- end
15
-
16
- it "should instantiate objects in the dataset and call destroy on each" do
17
- @d.destroy
18
- @c::Destroyed.collect{|x| x.values}.must_equal [{:id=>1}, {:id=>2}]
19
- end
20
-
21
- it "should return the number of records destroyed" do
22
- @d.destroy.must_equal 2
23
- @d = @d.with_fetch([[{:id=>1}], []])
24
- @d.destroy.must_equal 1
25
- @d.destroy.must_equal 0
26
- end
27
-
28
- it "should use a transaction if use_transactions is true for the model" do
29
- @c.use_transactions = true
30
- @d.destroy
31
- DB.sqls.must_equal ["BEGIN", "SELECT * FROM items", "COMMIT"]
32
- end
33
-
34
- it "should not use a transaction if use_transactions is false for the model" do
35
- @c.use_transactions = false
36
- @d.destroy
37
- DB.sqls.must_equal ["SELECT * FROM items"]
38
- end
39
- end
40
-
41
- describe Sequel::Model::DatasetMethods, "#as_hash" do
42
- before do
43
- @c = Class.new(Sequel::Model(:items)) do
44
- set_primary_key :name
45
- end
46
- @d = @c.dataset
47
- end
48
-
49
- it "should result in a hash with primary key value keys and model object values" do
50
- @d = @d.with_fetch([{:name=>1}, {:name=>2}])
51
- h = @d.as_hash
52
- h.must_be_kind_of(Hash)
53
- a = h.to_a
54
- a.collect{|x| x[1].class}.must_equal [@c, @c]
55
- a.sort_by{|x| x[0]}.collect{|x| [x[0], x[1].values]}.must_equal [[1, {:name=>1}], [2, {:name=>2}]]
56
- end
57
-
58
- it "should be aliased as to_hash" do
59
- @d = @d.with_fetch([{:name=>1}, {:name=>2}])
60
- h = @d.to_hash
61
- h.must_be_kind_of(Hash)
62
- a = h.to_a
63
- a.collect{|x| x[1].class}.must_equal [@c, @c]
64
- a.sort_by{|x| x[0]}.collect{|x| [x[0], x[1].values]}.must_equal [[1, {:name=>1}], [2, {:name=>2}]]
65
- end
66
-
67
- it "should result in a hash with given value keys and model object values" do
68
- @d = @d.with_fetch([{:name=>1, :number=>3}, {:name=>2, :number=>4}])
69
- h = @d.as_hash(:number)
70
- h.must_be_kind_of(Hash)
71
- a = h.to_a
72
- a.collect{|x| x[1].class}.must_equal [@c, @c]
73
- a.sort_by{|x| x[0]}.collect{|x| [x[0], x[1].values]}.must_equal [[3, {:name=>1, :number=>3}], [4, {:name=>2, :number=>4}]]
74
- end
75
-
76
- it "should raise an error if the class doesn't have a primary key" do
77
- @c.no_primary_key
78
- proc{@d.as_hash}.must_raise(Sequel::Error)
79
- end
80
- end
81
-
82
- describe Sequel::Model::DatasetMethods do
83
- before do
84
- @c = Class.new(Sequel::Model(:items))
85
- @c.columns :id
86
- @c.db.reset
87
- end
88
-
89
- it "#first should handle no primary key" do
90
- @c.no_primary_key
91
- @c.first.must_be_kind_of(@c)
92
- @c.db.sqls.must_equal ['SELECT * FROM items LIMIT 1']
93
- end
94
-
95
- it "#last should reverse order by primary key if not already ordered" do
96
- @c.last.must_be_kind_of(@c)
97
- @c.db.sqls.must_equal ['SELECT * FROM items ORDER BY id DESC LIMIT 1']
98
- @c.where(:id=>2).last(:foo=>2){{bar=>3}}.must_be_kind_of(@c)
99
- @c.db.sqls.must_equal ['SELECT * FROM items WHERE ((id = 2) AND (foo = 2) AND (bar = 3)) ORDER BY id DESC LIMIT 1']
100
- end
101
-
102
- it "#last should use existing order if there is one" do
103
- @c.order(:foo).last.must_be_kind_of(@c)
104
- @c.db.sqls.must_equal ['SELECT * FROM items ORDER BY foo DESC LIMIT 1']
105
- end
106
-
107
- it "#last should handle a composite primary key" do
108
- @c.set_primary_key [:id1, :id2]
109
- @c.last.must_be_kind_of(@c)
110
- @c.db.sqls.must_equal ['SELECT * FROM items ORDER BY id1 DESC, id2 DESC LIMIT 1']
111
- end
112
-
113
- it "#last should raise an error if no primary key" do
114
- @c.no_primary_key
115
- proc{@c.last}.must_raise(Sequel::Error)
116
- end
117
-
118
- it "#paged_each should order by primary key if not already ordered" do
119
- @c.paged_each{|r| r.must_be_kind_of(@c)}
120
- @c.db.sqls.must_equal ['BEGIN', 'SELECT * FROM items ORDER BY id LIMIT 1000 OFFSET 0', 'COMMIT']
121
- @c.paged_each(:rows_per_fetch=>5){|r|}
122
- @c.db.sqls.must_equal ['BEGIN', 'SELECT * FROM items ORDER BY id LIMIT 5 OFFSET 0', 'COMMIT']
123
- end
124
-
125
- it "#paged_each should use existing order if there is one" do
126
- @c.order(:foo).paged_each{|r| r.must_be_kind_of(@c)}
127
- @c.db.sqls.must_equal ['BEGIN', 'SELECT * FROM items ORDER BY foo LIMIT 1000 OFFSET 0', 'COMMIT']
128
- end
129
-
130
- it "#paged_each should handle a composite primary key" do
131
- @c.set_primary_key [:id1, :id2]
132
- @c.paged_each{|r| r.must_be_kind_of(@c)}
133
- @c.db.sqls.must_equal ['BEGIN', 'SELECT * FROM items ORDER BY id1, id2 LIMIT 1000 OFFSET 0', 'COMMIT']
134
- end
135
-
136
- it "#paged_each should raise an error if no primary key" do
137
- @c.no_primary_key
138
- proc{@c.paged_each{|r| }}.must_raise(Sequel::Error)
139
- end
140
- end
141
-
142
- describe Sequel::Model::DatasetMethods, "#where_all" do
143
- before do
144
- @c = Class.new(Sequel::Model(DB[:items].freeze))
145
- DB.reset
146
- end
147
-
148
- it "should filter dataset with condition, and return related rows" do
149
- 5.times do
150
- @c.where_all(:id=>1).must_equal [@c.load(:id=>1, :x=>1)]
151
- @c.db.sqls.must_equal ['SELECT * FROM items WHERE (id = 1)']
152
- end
153
- end
154
-
155
- it "should yield each row to the given block" do
156
- 5.times do
157
- a = []
158
- @c.where_all(:id=>1){|r| a << r}.must_equal [@c.load(:id=>1, :x=>1)]
159
- a.must_equal [@c.load(:id=>1, :x=>1)]
160
- @c.db.sqls.must_equal ['SELECT * FROM items WHERE (id = 1)']
161
- end
162
- end
163
- end
164
-
165
- describe Sequel::Model::DatasetMethods, "#where_each" do
166
- before do
167
- @c = Class.new(Sequel::Model(DB[:items].freeze))
168
- DB.reset
169
- end
170
-
171
- it "should yield each row to the given block" do
172
- 5.times do
173
- a = []
174
- @c.where_each(:id=>1){|r| a << r}
175
- a.must_equal [@c.load(:id=>1, :x=>1)]
176
- @c.db.sqls.must_equal ['SELECT * FROM items WHERE (id = 1)']
177
- end
178
- end
179
- end
180
-
181
- describe Sequel::Model::DatasetMethods, "#where_single_value" do
182
- before do
183
- @c = Class.new(Sequel::Model(DB[:items].freeze))
184
- @c.class_eval do
185
- dataset_module do
186
- select :only_id, :id
187
- end
188
- end
189
- DB.reset
190
- end
191
-
192
- it "should return single value" do
193
- 5.times do
194
- @c.only_id.where_single_value(:id=>1).must_equal 1
195
- @c.db.sqls.must_equal ['SELECT id FROM items WHERE (id = 1) LIMIT 1']
196
- end
197
- end
198
- end
@@ -1,2262 +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
- end
1229
-
1230
- describe Sequel::Model, "#eager_graph" do
1231
- before(:all) do
1232
- class ::GraphAlbum < Sequel::Model(:albums)
1233
- columns :id, :band_id
1234
- many_to_one :band, :class=>'GraphBand', :key=>:band_id
1235
- one_to_many :tracks, :class=>'GraphTrack', :key=>:album_id
1236
- one_to_one :track, :class=>'GraphTrack', :key=>:album_id
1237
- many_to_many :genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
1238
- one_through_one :genre, :clone=>:genres
1239
- many_to_one :previous_album, :class=>'GraphAlbum'
1240
- end
1241
-
1242
- class ::GraphBand < Sequel::Model(:bands)
1243
- columns :id, :vocalist_id
1244
- many_to_one :vocalist, :class=>'GraphBandMember', :key=>:vocalist_id
1245
- one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id
1246
- many_to_many :members, :class=>'GraphBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
1247
- many_to_many :genres, :class=>'GraphGenre', :left_key=>:band_id, :right_key=>:genre_id, :join_table=>:bg
1248
- end
1249
-
1250
- class ::GraphTrack < Sequel::Model(:tracks)
1251
- columns :id, :album_id
1252
- many_to_one :album, :class=>'GraphAlbum', :key=>:album_id
1253
- end
1254
-
1255
- class ::GraphGenre < Sequel::Model(:genres)
1256
- columns :id
1257
- many_to_many :albums, :class=>'GraphAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
1258
- end
1259
-
1260
- class ::GraphBandMember < Sequel::Model(:members)
1261
- columns :id
1262
- many_to_many :bands, :class=>'GraphBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm
1263
- end
1264
- end
1265
- before do
1266
- DB.sqls
1267
- end
1268
- after(:all) do
1269
- [:GraphAlbum, :GraphBand, :GraphTrack, :GraphGenre, :GraphBandMember].each{|x| Object.send(:remove_const, x)}
1270
- end
1271
-
1272
- it "should raise an error if called without a symbol or hash" do
1273
- proc{GraphAlbum.eager_graph(Object.new)}.must_raise(Sequel::Error)
1274
- end
1275
-
1276
- it "should work correctly with select_map" do
1277
- ds = GraphAlbum.eager_graph(:band)
1278
- ds.with_fetch([{:id=>1}, {:id=>2}]).select_map(Sequel[:albums][:id]).must_equal [1, 2]
1279
- DB.sqls.must_equal ['SELECT albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)']
1280
- ds.with_fetch([{:id=>1}, {:id=>2}]).select_map([Sequel[:albums][:id], Sequel[:albums][:id]]).must_equal [[1, 1], [2, 2]]
1281
- DB.sqls.must_equal ['SELECT albums.id, albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)']
1282
- end
1283
-
1284
- it "should work correctly with single_value" do
1285
- ds = GraphAlbum.eager_graph(:band).select(Sequel[:albums][:id])
1286
- ds.with_fetch([{:id=>1}]).single_value.must_equal 1
1287
- DB.sqls.must_equal ['SELECT albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) LIMIT 1']
1288
- end
1289
-
1290
- it "should not split results and assign associations if ungraphed is called" do
1291
- ds = GraphAlbum.eager_graph(:band).ungraphed
1292
- 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)'
1293
- 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)]
1294
- end
1295
-
1296
- it "should not modify existing dataset" do
1297
- ds1 = GraphAlbum.dataset
1298
- ds2 = ds1.eager_graph(:band)
1299
- ds1.eager_graph(:band)
1300
- ds2.eager_graph(:tracks)
1301
- ds2.eager_graph(:tracks)
1302
- end
1303
-
1304
- it "should allow manually selecting the alias base per call via an AliasedExpression" do
1305
- ds = GraphAlbum.eager_graph(Sequel.as(:band, :b))
1306
- 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)'
1307
- a = ds.with_fetch(:id=>1, :band_id=>2, :b_id=>2, :vocalist_id=>3).all
1308
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1309
- a.first.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1310
- end
1311
-
1312
- it "should handle multiple associations using the same alias base" do
1313
- ds = GraphAlbum.eager_graph(Sequel.as(:genres, :b), Sequel.as(:tracks, :b), Sequel.as(:band, :b))
1314
- 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)'
1315
- 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
1316
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1317
- a = a.first
1318
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1319
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1320
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1321
-
1322
- ds = GraphTrack.eager_graph(Sequel.as(:album, :b)=>{Sequel.as(:band, :b)=>Sequel.as(:members, :b)})
1323
- 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)'
1324
- 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
1325
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
1326
- a = a.first
1327
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
1328
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1329
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
1330
- end
1331
-
1332
- it "should set up correct inner joins when using association_join" do
1333
- GraphAlbum.association_join(:band).sql.must_equal 'SELECT * FROM albums INNER JOIN bands AS band ON (band.id = albums.band_id)'
1334
- GraphAlbum.association_join(:track).sql.must_equal 'SELECT * FROM albums INNER JOIN tracks AS track ON (track.album_id = albums.id)'
1335
- GraphAlbum.association_join(:tracks).sql.must_equal 'SELECT * FROM albums INNER JOIN tracks ON (tracks.album_id = albums.id)'
1336
- 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)'
1337
- 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)'
1338
- end
1339
-
1340
- it "should handle custom selects when using association_join" do
1341
- 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)'
1342
- 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)'
1343
- GraphAlbum.select{a(b)}.association_join(:tracks).sql.must_equal 'SELECT a(b) FROM albums INNER JOIN tracks ON (tracks.album_id = albums.id)'
1344
- 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)'
1345
- 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)'
1346
- end
1347
-
1348
- it "should set up correct join types when using association_*_join" do
1349
- GraphAlbum.association_inner_join(:band).sql.must_equal 'SELECT * FROM albums INNER JOIN bands AS band ON (band.id = albums.band_id)'
1350
- GraphAlbum.association_left_join(:track).sql.must_equal 'SELECT * FROM albums LEFT JOIN tracks AS track ON (track.album_id = albums.id)'
1351
- GraphAlbum.association_right_join(:tracks).sql.must_equal 'SELECT * FROM albums RIGHT JOIN tracks ON (tracks.album_id = albums.id)'
1352
- 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)'
1353
- end
1354
-
1355
- it "should eagerly load a single many_to_one association" do
1356
- ds = GraphAlbum.eager_graph(:band)
1357
- 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)'
1358
- a = ds.with_fetch(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3).all
1359
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1360
- a.first.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1361
- end
1362
-
1363
- it "should eagerly load a single many_to_one association with the same name as a column" do
1364
- GraphAlbum.def_column_alias(:band_id_id, :band_id)
1365
- GraphAlbum.many_to_one :band_id, :key_column=>:band_id, :class=>GraphBand
1366
- ds = GraphAlbum.eager_graph(:band_id)
1367
- 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)'
1368
- a = ds.with_fetch(:id=>1, :band_id=>2, :band_id_id=>2, :vocalist_id=>3).all
1369
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1370
- a.first.band_id.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1371
- end
1372
-
1373
- it "should support :join_type eager_graph option one_to_one association" do
1374
- ds = GraphAlbum.eager_graph_with_options(:track, :join_type=>:inner)
1375
- 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)'
1376
- a = ds.with_fetch(:id=>1, :band_id=>2, :track_id=>3, :album_id=>1).all
1377
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1378
- a.first.track.must_equal GraphTrack.load(:id => 3, :album_id=>1)
1379
- end
1380
-
1381
- it "should eagerly load a single one_to_one association" do
1382
- ds = GraphAlbum.eager_graph(:track)
1383
- 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)'
1384
- a = ds.with_fetch(:id=>1, :band_id=>2, :track_id=>3, :album_id=>1).all
1385
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1386
- a.first.track.must_equal GraphTrack.load(:id => 3, :album_id=>1)
1387
- end
1388
-
1389
- it "should eagerly graph a single one_to_one association using the :distinct_on strategy" do
1390
- sub = Class.new(GraphTrack)
1391
- sub.dataset = sub.dataset.with_extend do
1392
- def supports_distinct_on?; true end
1393
- def columns; [:id, :album_id] end
1394
- end
1395
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1396
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>true)
1397
- 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)'
1398
- a = ds.with_fetch(:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1).all
1399
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1400
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1401
- end
1402
-
1403
- it "should eagerly graph a single one_to_one association using the :window_function strategy" do
1404
- sub = Class.new(GraphTrack)
1405
- sub.dataset = sub.dataset.with_extend do
1406
- def supports_window_functions?; true end
1407
- def columns; [:id, :album_id] end
1408
- end
1409
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1410
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>true)
1411
- 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)'
1412
- a = ds.with_fetch(:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1).all
1413
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1414
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1415
- end
1416
-
1417
- it "should eagerly graph a single one_to_one association using the :correlated_subquery strategy" do
1418
- sub = Class.new(GraphTrack)
1419
- sub.dataset = sub.dataset.with_extend do
1420
- def supports_window_functions?; true end
1421
- def columns; [:id, :album_id] end
1422
- end
1423
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1424
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>:correlated_subquery)
1425
- 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)'
1426
- a = ds.with_fetch(:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1).all
1427
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1428
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1429
- end
1430
-
1431
- it "should eagerly load a single one_to_many association" do
1432
- ds = GraphAlbum.eager_graph(:tracks)
1433
- 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)'
1434
- a = ds.with_fetch(:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1).all
1435
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1436
- a.first.tracks.must_equal [GraphTrack.load(:id => 3, :album_id=>1)]
1437
- end
1438
-
1439
- it "should eagerly graph a single one_to_many association using the :window_function strategy" do
1440
- sub = Class.new(GraphTrack)
1441
- sub.dataset = sub.dataset.with_extend do
1442
- def supports_window_functions?; true end
1443
- def columns; [:id, :album_id] end
1444
- end
1445
- GraphAlbum.one_to_many :ltracks, :clone=>:tracks, :limit=>2, :class=>sub
1446
- ds = GraphAlbum.eager_graph_with_options(:ltracks, :limit_strategy=>true)
1447
- 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)'
1448
- a = ds.with_fetch(:id=>1, :band_id=>2, :ltracks_id=>3, :album_id=>1).all
1449
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1450
- a.first.ltracks.must_equal [sub.load(:id => 3, :album_id=>1)]
1451
- end
1452
-
1453
- it "should eagerly load a single many_to_many association" do
1454
- ds = GraphAlbum.eager_graph(:genres)
1455
- 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)'
1456
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>4).all
1457
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1458
- a.first.genres.must_equal [GraphGenre.load(:id => 4)]
1459
- end
1460
-
1461
- it "should eagerly graph a single many_to_many association using the :window_function strategy" do
1462
- sub = Class.new(GraphGenre)
1463
- sub.dataset = sub.dataset.with_extend do
1464
- def supports_window_functions?; true end
1465
- def columns; literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1466
- end
1467
- GraphAlbum.many_to_many :lgenres, :clone=>:genres, :class=>sub, :limit=>2
1468
- ds = GraphAlbum.eager_graph_with_options(:lgenres, :limit_strategy=>true)
1469
- 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)'
1470
- a = ds.with_fetch(:id=>1, :band_id=>2, :lgenres_id=>4).all
1471
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1472
- a.first.lgenres.must_equal [sub.load(:id => 4)]
1473
- end
1474
-
1475
- it "should eagerly load a single one_through_one association" do
1476
- ds = GraphAlbum.eager_graph(:genre)
1477
- 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)'
1478
- a = ds.with_fetch(:id=>1, :band_id=>2, :genre_id=>4).all
1479
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1480
- a.first.genre.must_equal GraphGenre.load(:id => 4)
1481
- end
1482
-
1483
- it "should eagerly graph a single one_through_one association using the :distinct_on strategy" do
1484
- sub = Class.new(GraphGenre)
1485
- sub.dataset = sub.dataset.with_extend do
1486
- def supports_distinct_on?; true end
1487
- def columns; [:id] end
1488
- end
1489
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>sub
1490
- ds = GraphAlbum.eager_graph_with_options(:lgenre, :limit_strategy=>true)
1491
- 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)'
1492
- a = ds.with_fetch(:id=>1, :band_id=>2, :lgenre_id=>4).all
1493
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1494
- a.first.lgenre.must_equal sub.load(:id => 4)
1495
- end
1496
-
1497
- it "should eagerly graph a single one_through_one association using the :window_function strategy" do
1498
- sub = Class.new(GraphGenre)
1499
- sub.dataset = sub.dataset.with_extend do
1500
- def supports_window_functions?; true end
1501
- def columns; literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1502
- end
1503
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>sub
1504
- ds = GraphAlbum.eager_graph_with_options(:lgenre, :limit_strategy=>true)
1505
- 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)'
1506
- a = ds.with_fetch(:id=>1, :band_id=>2, :lgenre_id=>4).all
1507
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1508
- a.first.lgenre.must_equal sub.load(:id => 4)
1509
- end
1510
-
1511
- it "should correctly handle an aliased join table in many_to_many and one_through_one with graph_conditions or graph_block" do
1512
- c = Class.new(GraphAlbum)
1513
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga), :graph_conditions=>{:a=>:b}
1514
- 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))'
1515
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga), :graph_block => proc{true}
1516
- 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\')'
1517
- end
1518
-
1519
- 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
1520
- c = Class.new(GraphAlbum)
1521
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___ga, :graph_conditions=>{:a=>:b}
1522
- 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))'
1523
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___ga, :graph_block => proc{true}
1524
- 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\')'
1525
- end
1526
-
1527
- it "should raise Error when using eager_graph with :conditions option that isn't a conditions specifier" do
1528
- c = Class.new(GraphAlbum)
1529
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga), :conditions=>'true'
1530
- proc{c.eager_graph(:genres)}.must_raise Sequel::Error
1531
- end
1532
-
1533
- with_symbol_splitting "should correctly handle an aliased join table symbol in many_to_many and one_through_one" do
1534
- c = Class.new(GraphAlbum)
1535
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___ga
1536
- 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)'
1537
-
1538
- c.many_to_many :genre, :clone=>:genre, :join_table=>:ag___ga
1539
- 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)'
1540
-
1541
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___albums
1542
- 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)'
1543
-
1544
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___genres
1545
- 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)'
1546
- end
1547
-
1548
- it "should correctly handle an aliased join table in many_to_many and one_through_one" do
1549
- c = Class.new(GraphAlbum)
1550
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:ga)
1551
- 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)'
1552
-
1553
- c.many_to_many :genre, :clone=>:genre, :join_table=>Sequel[:ag].as(:ga)
1554
- 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)'
1555
-
1556
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:albums)
1557
- 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)'
1558
-
1559
- c.many_to_many :genres, :clone=>:genres, :join_table=>Sequel[:ag].as(:genres)
1560
- 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)'
1561
- end
1562
-
1563
- it "should handle multiple associations in a single call to association_join" do
1564
- 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)'
1565
- end
1566
-
1567
- it "should eagerly load multiple associations in a single call" do
1568
- ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
1569
- 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)'
1570
- 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
1571
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1572
- a = a.first
1573
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1574
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1575
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1576
- end
1577
-
1578
- it "should eagerly load multiple associations with different limit strategies in a single call" do
1579
- subg = Class.new(GraphGenre)
1580
- subg.dataset = subg.dataset.with_extend do
1581
- def supports_distinct_on?; true end
1582
- def supports_window_functions?; true end
1583
- def columns; literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1584
- end
1585
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>subg
1586
- GraphAlbum.many_to_many :lgenres, :clone=>:genres, :class=>subg, :limit=>2
1587
-
1588
- ds = GraphAlbum.eager_graph_with_options([:lgenre, :lgenres], :limit_strategy=>{:lgenre=>:distinct_on, :lgenres=>:window_function})
1589
- 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)'
1590
- a = ds.with_fetch(:id=>1, :band_id=>2, :lgenres_id=>4, :lgenre_id=>3).all
1591
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1592
- a = a.first
1593
- a.lgenre.must_equal subg.load(:id => 3)
1594
- a.lgenres.must_equal [subg.load(:id => 4)]
1595
- end
1596
-
1597
- it "should handle multiple associations in separate calls to association_join" do
1598
- 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)'
1599
- end
1600
-
1601
- it "should eagerly load multiple associations in separate calls" do
1602
- ds = GraphAlbum.eager_graph(:genres).eager_graph(:tracks).eager_graph(:band)
1603
- 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)'
1604
- 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
1605
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1606
- a = a.first
1607
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1608
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1609
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1610
- end
1611
-
1612
- it "should handle cascading associations in a single call to association_join" do
1613
- 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)'
1614
- 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)'
1615
- end
1616
-
1617
- it "should handle matching association names for different models when using association_join" do
1618
- 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)'
1619
- end
1620
-
1621
- it "should allow cascading of eager loading for associations of associated models" do
1622
- ds = GraphTrack.eager_graph(:album=>{:band=>:members})
1623
- 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)'
1624
- 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
1625
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
1626
- a = a.first
1627
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
1628
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1629
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
1630
- end
1631
-
1632
- it "should allow cascading of eager loading for multiple *_to_many associations, eliminating duplicates caused by cartesian products" do
1633
- ds = GraphBand.eager_graph({:albums=>:tracks}, :members)
1634
- 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)'
1635
- a = ds.with_fetch([{:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>5},
1636
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>6},
1637
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>5},
1638
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>6},
1639
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>5},
1640
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>6},
1641
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>5},
1642
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>6},
1643
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>5},
1644
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>6},
1645
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>5},
1646
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>6},
1647
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>5},
1648
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>6},
1649
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>5},
1650
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>6}]).all
1651
- a.must_equal [GraphBand.load(:id=>1, :vocalist_id=>2), GraphBand.load(:id=>2, :vocalist_id=>2)]
1652
- members = a.map{|x| x.members}
1653
- members.must_equal [[GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)], [GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)]]
1654
- albums = a.map{|x| x.albums}
1655
- 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)]]
1656
- tracks = albums.map{|x| x.map{|y| y.tracks}}
1657
- 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)]]]
1658
- end
1659
-
1660
- it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
1661
- DB.reset
1662
- ds = GraphAlbum.eager_graph(:tracks)
1663
- 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)'
1664
- a = ds.with_fetch(:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1).all
1665
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1666
- a = a.first
1667
- a.tracks.must_equal [GraphTrack.load(:id => 3, :album_id=>1)]
1668
- a.tracks.first.album.must_equal a
1669
- 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)']
1670
- end
1671
-
1672
- it "should eager load multiple associations from the same table" do
1673
- ds = GraphBand.eager_graph(:vocalist, :members)
1674
- 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)'
1675
- a = ds.with_fetch(:id=>2, :vocalist_id=>6, :vocalist_id_0=>6, :members_id=>5).all
1676
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1677
- a = a.first
1678
- a.vocalist.must_equal GraphBandMember.load(:id => 6)
1679
- a.members.must_equal [GraphBandMember.load(:id => 5)]
1680
- end
1681
-
1682
- it "should give you a plain hash when called without .all" do
1683
- ds = GraphAlbum.eager_graph(:band)
1684
- 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)'
1685
- 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)
1686
- end
1687
-
1688
- it "should not drop any associated objects if the graph could not be a cartesian product" do
1689
- ds = GraphBand.eager_graph(:members, :vocalist)
1690
- 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)'
1691
- 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
1692
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1693
- a = a.first
1694
- a.vocalist.must_equal GraphBandMember.load(:id => 6)
1695
- a.members.must_equal [GraphBandMember.load(:id => 5), GraphBandMember.load(:id => 5)]
1696
- end
1697
-
1698
- it "should respect the :cartesian_product_number option" do
1699
- GraphBand.many_to_one :other_vocalist, :class=>'GraphBandMember', :key=>:vocalist_id, :cartesian_product_number=>1
1700
- ds = GraphBand.eager_graph(:members, :other_vocalist)
1701
- 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)'
1702
- 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
1703
- a.must_equal [GraphBand.load(:id=>2, :vocalist_id => 6)]
1704
- a.first.other_vocalist.must_equal GraphBandMember.load(:id=>6)
1705
- a.first.members.must_equal [GraphBandMember.load(:id=>5)]
1706
- end
1707
-
1708
- it "should drop duplicate items that occur in sequence if the graph could be a cartesian product" do
1709
- ds = GraphBand.eager_graph(:members, :genres)
1710
- 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)'
1711
- a = ds.with_fetch([{:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>7},
1712
- {:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>8},
1713
- {:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>7},
1714
- {:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>8}]).all
1715
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1716
- a = a.first
1717
- a.members.must_equal [GraphBandMember.load(:id => 5), GraphBandMember.load(:id => 6)]
1718
- a.genres.must_equal [GraphGenre.load(:id => 7), GraphGenre.load(:id => 8)]
1719
- end
1720
-
1721
- it "should be able to be used in combination with #eager" do
1722
- DB.reset
1723
- ds = GraphAlbum.eager_graph(:tracks).eager(:genres)
1724
- GraphGenre.dataset = GraphGenre.dataset.with_fetch(:id=>6, :x_foreign_key_x=>1)
1725
- a = ds.with_fetch(:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1).all
1726
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1727
- a = a.first
1728
- a.tracks.must_equal [GraphTrack.load(:id=>3, :album_id=>1)]
1729
- a.genres.must_equal [GraphGenre.load(:id => 6)]
1730
- 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)',
1731
- "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))"]
1732
- end
1733
-
1734
- it "should handle no associated records for a single many_to_one association" do
1735
- ds = GraphAlbum.eager_graph(:band)
1736
- 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)'
1737
- a = ds.with_fetch(:id=>1, :band_id=>2, :band_id_0=>nil, :vocalist_id=>nil).all
1738
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1739
- a.first.band.must_be_nil
1740
- end
1741
-
1742
- it "should handle no associated records for a single one_to_one association" do
1743
- ds = GraphAlbum.eager_graph(:track)
1744
- 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)'
1745
- a = ds.with_fetch(:id=>1, :band_id=>2, :track_id=>nil, :album_id=>nil).all
1746
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1747
- a.first.track.must_be_nil
1748
- end
1749
-
1750
- it "should handle no associated records for a single one_to_many association" do
1751
- ds = GraphAlbum.eager_graph(:tracks)
1752
- 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)'
1753
- a = ds.with_fetch(:id=>1, :band_id=>2, :tracks_id=>nil, :album_id=>nil).all
1754
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1755
- a.first.tracks.must_equal []
1756
- end
1757
-
1758
- it "should handle no associated records for a single one_through_one association" do
1759
- ds = GraphAlbum.eager_graph(:genre)
1760
- 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)'
1761
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>nil).all
1762
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1763
- a.first.genre.must_be_nil
1764
- end
1765
-
1766
- it "should handle no associated records for a single many_to_many association" do
1767
- ds = GraphAlbum.eager_graph(:genres)
1768
- 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)'
1769
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>nil).all
1770
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1771
- a.first.genres.must_equal []
1772
- end
1773
-
1774
- it "should handle missing associated records when loading multiple associations" do
1775
- ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
1776
- 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)'
1777
- 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},
1778
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>4, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil},
1779
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>5, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil},
1780
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>6, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil}]).all
1781
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1782
- a = a.first
1783
- 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)]
1784
- a.band.must_be_nil
1785
- a.genres.must_equal []
1786
- end
1787
-
1788
- it "should handle missing associated records when cascading eager loading for associations of associated models" do
1789
- ds = GraphTrack.eager_graph(:album=>{:band=>:members})
1790
- 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)'
1791
- 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},
1792
- {:id=>3, :album_id=>3, :album_id_0=>3, :band_id=>3, :members_id=>nil, :band_id_0=>nil, :vocalist_id=>nil},
1793
- {:id=>4, :album_id=>4, :album_id_0=>4, :band_id=>2, :members_id=>nil, :band_id_0=>2, :vocalist_id=>6},
1794
- {:id=>5, :album_id=>1, :album_id_0=>1, :band_id=>4, :members_id=>5, :band_id_0=>4, :vocalist_id=>8},
1795
- {:id=>5, :album_id=>1, :album_id_0=>1, :band_id=>4, :members_id=>6, :band_id_0=>4, :vocalist_id=>8}]).all
1796
- 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)]
1797
- 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)]
1798
- 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)]
1799
- 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)]]
1800
- end
1801
-
1802
- it "should respect the association's :primary_key option" do
1803
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :primary_key=>:vocalist_id
1804
- ds = GraphAlbum.eager_graph(:inner_band)
1805
- 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)'
1806
- as = ds.with_fetch(:id=>3, :band_id=>2, :inner_band_id=>5, :vocalist_id=>2).all
1807
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1808
- as.first.inner_band.must_equal GraphBand.load(:id=>5, :vocalist_id=>2)
1809
-
1810
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :primary_key=>:band_id, :reciprocal=>nil
1811
- ds = GraphAlbum.eager_graph(:right_tracks)
1812
- 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)'
1813
- 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
1814
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1815
- as.first.right_tracks.must_equal [GraphTrack.load(:id=>5, :album_id=>2), GraphTrack.load(:id=>6, :album_id=>2)]
1816
- end
1817
-
1818
- it "should respect many_to_one association's composite keys" do
1819
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>[:band_id, :id], :primary_key=>[:vocalist_id, :id]
1820
- ds = GraphAlbum.eager_graph(:inner_band)
1821
- 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))'
1822
- as = ds.with_fetch(:id=>3, :band_id=>2, :inner_band_id=>3, :vocalist_id=>2).all
1823
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1824
- as.first.inner_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>2)
1825
- end
1826
-
1827
- it "should respect one_to_many association's composite keys" do
1828
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>[:album_id, :id], :primary_key=>[:band_id, :id]
1829
- ds = GraphAlbum.eager_graph(:right_tracks)
1830
- 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))'
1831
- as = ds.with_fetch(:id=>3, :band_id=>2, :right_tracks_id=>3, :album_id=>2).all
1832
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1833
- as.first.right_tracks.must_equal [GraphTrack.load(:id=>3, :album_id=>2)]
1834
- end
1835
-
1836
- it "should respect many_to_many association's composite keys" do
1837
- 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
1838
- ds = GraphAlbum.eager_graph(:sbands)
1839
- 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))'
1840
- 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
1841
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1842
- as.first.sbands.must_equal [GraphBand.load(:id=>5, :vocalist_id=>6), GraphBand.load(:id=>6, :vocalist_id=>22)]
1843
- end
1844
-
1845
- it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
1846
- 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
1847
- ds = GraphAlbum.eager_graph(:inner_genres)
1848
- 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)'
1849
- 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
1850
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1851
- as.first.inner_genres.must_equal [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
1852
- end
1853
-
1854
- it "should respect composite primary keys for classes when eager loading" do
1855
- c1 = Class.new(GraphAlbum)
1856
- c2 = Class.new(GraphBand)
1857
- c1.set_primary_key [:band_id, :id]
1858
- c2.set_primary_key [:vocalist_id, :id]
1859
- c1.many_to_many :sbands, :class=>c2, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :join_table=>:b
1860
- c2.one_to_many :salbums, :class=>c1, :key=>[:band_id, :id]
1861
- ds = c1.eager_graph(:sbands=>:salbums)
1862
- 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))'
1863
- as = ds.with_fetch([{:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6, :salbums_id=>7, :salbums_band_id=>8},
1864
- {:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6, :salbums_id=>9, :salbums_band_id=>10},
1865
- {:id=>3, :band_id=>2, :sbands_id=>6, :vocalist_id=>22, :salbums_id=>nil, :salbums_band_id=>nil},
1866
- {:id=>7, :band_id=>8, :sbands_id=>nil, :vocalist_id=>nil, :salbums_id=>nil, :salbums_band_id=>nil}]).all
1867
- as.must_equal [c1.load(:id=>3, :band_id=>2), c1.load(:id=>7, :band_id=>8)]
1868
- as.map{|x| x.sbands}.must_equal [[c2.load(:id=>5, :vocalist_id=>6), c2.load(:id=>6, :vocalist_id=>22)], []]
1869
- 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)], []], []]
1870
- end
1871
-
1872
- it "should respect the association's :graph_select option" do
1873
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_select=>:vocalist_id
1874
- 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)'
1875
-
1876
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_select=>[:album_id]
1877
- 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)'
1878
-
1879
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_select=>[]
1880
- 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)'
1881
- end
1882
-
1883
- it "should respect the association's :graph_alias_base option" do
1884
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_alias_base=>:foo
1885
- ds = GraphAlbum.eager_graph(:inner_band)
1886
- 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)'
1887
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_alias_base=>:foo
1888
- 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)'
1889
- end
1890
-
1891
- it "should respect the association's :graph_join_type option" do
1892
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_join_type=>:inner
1893
- 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)'
1894
-
1895
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_join_type=>:right_outer
1896
- 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)'
1897
-
1898
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_type=>:inner
1899
- 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)'
1900
- end
1901
-
1902
- it "should respect the association's :graph_join_table_join_type option" do
1903
- 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
1904
- 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)'
1905
-
1906
- 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
1907
- 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)'
1908
- end
1909
-
1910
- it "should respect the association's :conditions option" do
1911
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :conditions=>{:active=>true}
1912
- 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))"
1913
-
1914
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :conditions=>{:id=>(0..100)}, :reciprocal=>nil
1915
- 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))'
1916
-
1917
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :conditions=>{true=>:active}
1918
- 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))"
1919
- end
1920
-
1921
- it "should respect the association's :graph_conditions option" do
1922
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_conditions=>{:active=>true}
1923
- 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))"
1924
-
1925
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:id=>(0..100)}
1926
- 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))'
1927
-
1928
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}
1929
- 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))"
1930
- end
1931
-
1932
- it "should respect the association's :graph_join_table_conditions option" do
1933
- 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}
1934
- 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)"
1935
-
1936
- 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}
1937
- 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))"
1938
- end
1939
-
1940
- it "should respect the association's :graph_block option" do
1941
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :active)=>true}}
1942
- 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))"
1943
-
1944
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :id)=>(0..100)}}
1945
- 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))'
1946
-
1947
- 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)}}
1948
- 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))"
1949
- end
1950
-
1951
- it "should respect the association's :graph_join_table_block option" do
1952
- 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}}
1953
- 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)"
1954
-
1955
- 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)}}
1956
- 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))"
1957
- end
1958
-
1959
- it "should respect the association's :eager_grapher option" do
1960
- 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)}
1961
- 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)"
1962
-
1963
- 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])}
1964
- 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'
1965
-
1966
- 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])}
1967
- 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)"
1968
- end
1969
-
1970
- it "should respect the association's :graph_only_conditions option" do
1971
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_only_conditions=>{:active=>true}
1972
- 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)"
1973
-
1974
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_only_conditions=>nil, :graph_join_type=>:natural
1975
- 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'
1976
-
1977
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_only_conditions=>[:album_id]
1978
- 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)"
1979
- end
1980
-
1981
- it "should respect the association's :graph_join_table_only_conditions option" do
1982
- 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}
1983
- 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)"
1984
-
1985
- 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")
1986
- 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)"
1987
- end
1988
-
1989
- it "should create unique table aliases for all associations" do
1990
- 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)"
1991
- end
1992
-
1993
- it "should respect the association's :order" do
1994
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
1995
- 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'
1996
- end
1997
-
1998
- with_symbol_splitting "should not qualify qualified symbols in association's :order" do
1999
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[Sequel.desc(:blah__id), :blah__id]
2000
- 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'
2001
- end
2002
-
2003
- it "should only qualify unqualified symbols, identifiers, or ordered versions in association's :order" do
2004
- 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)]
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) 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'
2006
- end
2007
-
2008
- it "should not respect the association's :order if :order_eager_graph is false" do
2009
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id], :order_eager_graph=>false
2010
- 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)'
2011
- end
2012
-
2013
- it "should add the association's :order to the existing order" do
2014
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
2015
- 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'
2016
- end
2017
-
2018
- it "should use the association's :graph_order in preference or order" do
2019
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:tracks__id, :tracks__album_id], :graph_order=>[:id, :album_id]
2020
- 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'
2021
- end
2022
-
2023
- it "should add the association's :order for cascading associations" do
2024
- GraphBand.one_to_many :a_albums, :class=>'GraphAlbum', :key=>:band_id, :order=>:name, :reciprocal=>nil
2025
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
2026
- 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'
2027
- GraphAlbum.one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id, :order=>[:band_id, :id]
2028
- 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'
2029
- end
2030
-
2031
- it "should add the associations :order for multiple associations" do
2032
- GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :order=>:id
2033
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
2034
- 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'
2035
- end
2036
-
2037
- it "should use the correct qualifier when graphing multiple tables with extra conditions" do
2038
- GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
2039
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:a=>:b}
2040
- 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))'
2041
- end
2042
-
2043
- it "should eagerly load associated records for classes that do not have a primary key" do
2044
- GraphAlbum.no_primary_key
2045
- GraphGenre.no_primary_key
2046
- 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
2047
- ds = GraphAlbum.eager_graph(:inner_genres)
2048
- 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)'
2049
- 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
2050
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
2051
- as.first.inner_genres.must_equal [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
2052
- GraphAlbum.set_primary_key :id
2053
- GraphGenre.set_primary_key :id
2054
- end
2055
-
2056
- it "should handle eager loading with schemas and aliases of different types" do
2057
- 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)'
2058
- 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)'
2059
- 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)'
2060
- 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)'
2061
- 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)'
2062
- 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)'
2063
- end
2064
-
2065
- with_symbol_splitting "should handle eager loading with splittable symbols" do
2066
- 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)'
2067
- 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)'
2068
- 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)'
2069
- end
2070
-
2071
- it "should raise errors if invalid aliases or table styles are used" do
2072
- proc{GraphAlbum.from_self(:alias=>Sequel.qualify(:s, :bands)).eager_graph(:band)}.must_raise(Sequel::Error)
2073
- proc{GraphAlbum.from(Sequel.lit('?', :bands)).eager_graph(:band)}.must_raise(Sequel::Error)
2074
- end
2075
-
2076
- it "should eagerly load schema qualified tables correctly with joins" do
2077
- c1 = Class.new(GraphAlbum)
2078
- c2 = Class.new(GraphGenre)
2079
- ds = c1.dataset.from(Sequel[:s][:a]).with_extend{def columns; [:id] end}
2080
- c1.dataset = ds
2081
- ds = c1.dataset
2082
- c2.dataset = c2.dataset.from(Sequel[:s][:g])
2083
- 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]
2084
- ds = c1.join(Sequel[:s][:t], [:b_id]).eager_graph(:a_genres)
2085
- 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)'
2086
- ds = c1.eager_graph(:a_genres)
2087
- 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)'
2088
- end
2089
-
2090
- with_symbol_splitting "should eagerly load schema qualified table symbols correctly with joins" do
2091
- c1 = Class.new(GraphAlbum)
2092
- c2 = Class.new(GraphGenre)
2093
- ds = c1.dataset.from(:s__a).with_extend{def columns; [:id] end}
2094
- c1.dataset = ds
2095
- ds = c1.dataset
2096
- c2.dataset = c2.dataset.from(:s__g)
2097
- c1.many_to_many :a_genres, :class=>c2, :left_primary_key=>:id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:s__ag
2098
- ds = c1.join(:s__t, [:b_id]).eager_graph(:a_genres)
2099
- 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)'
2100
- ds = c1.eager_graph(:a_genres)
2101
- 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)'
2102
- end
2103
-
2104
- it "should respect :after_load callbacks on associations when eager graphing" do
2105
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id, :after_load=>proc{|o, a| a.id *=2}
2106
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
2107
- 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}}
2108
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2109
- 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)"
2110
- 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
2111
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2112
- a.al_band.must_equal GraphBand.load(:id=>6, :vocalist_id=>4)
2113
- a.al_tracks.must_equal [GraphTrack.load(:id=>10, :album_id=>6)]
2114
- a.al_genres.must_equal [GraphGenre.load(:id=>14)]
2115
- end
2116
-
2117
- it "should respect limits on associations when eager graphing" do
2118
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2119
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>2
2120
- GraphAlbum.many_to_many :al_genres, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>2
2121
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2122
- 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)"
2123
- 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},
2124
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_tracks_id=>10, :album_id=>11, :al_genres_id=>12},
2125
- {: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
2126
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2127
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2128
- a.al_tracks.must_equal [GraphTrack.load(:id=>5, :album_id=>6), GraphTrack.load(:id=>10, :album_id=>11)]
2129
- a.al_genres.must_equal [GraphGenre.load(:id=>7), GraphGenre.load(:id=>12)]
2130
- end
2131
-
2132
- it "should handle offsets on associations with no results when eager graphing" do
2133
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>[2, 1]
2134
- ds = GraphAlbum.eager_graph(:al_tracks)
2135
- 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)"
2136
- a = ds.with_fetch([{:id=>1, :band_id=>2, :al_tracks_id=>nil, :album_id=>nil}]).all.first
2137
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2138
- a.al_tracks.must_equal []
2139
- end
2140
-
2141
- it "should respect offsets on associations when eager graphing" do
2142
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2143
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>[1, 1]
2144
- GraphAlbum.many_to_many :al_genres, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[1,1]
2145
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2146
- 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)"
2147
- 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},
2148
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_tracks_id=>10, :album_id=>11, :al_genres_id=>12},
2149
- {: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
2150
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2151
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2152
- a.al_tracks.must_equal [GraphTrack.load(:id=>10, :album_id=>11)]
2153
- a.al_genres.must_equal [GraphGenre.load(:id=>12)]
2154
- end
2155
-
2156
- it "should respect offsets on associations when eager graphing one_to_one and one_through_one associations" do
2157
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2158
- GraphAlbum.one_to_one :al_track, :class=>GraphTrack, :key=>:album_id, :limit=>[nil, 1]
2159
- GraphAlbum.one_through_one :al_genre, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[nil,1]
2160
- ds = GraphAlbum.eager_graph(:al_band, :al_track, :al_genre)
2161
- 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)"
2162
- 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},
2163
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_track_id=>10, :album_id=>11, :al_genre_id=>12},
2164
- {: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
2165
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2166
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2167
- a.al_track.must_equal GraphTrack.load(:id=>10, :album_id=>11)
2168
- a.al_genre.must_equal GraphGenre.load(:id=>12)
2169
- end
2170
-
2171
- it "should eagerly load a many_to_one association with a custom callback" do
2172
- ds = GraphAlbum.eager_graph(:band => proc {|ds1| ds1.select(:id).columns(:id)})
2173
- 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)'
2174
- a = ds.with_fetch(:id=>1, :band_id=>2, :band_id_0=>2).all
2175
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2176
- a.first.band.must_equal GraphBand.load(:id => 2)
2177
- end
2178
-
2179
- it "should eagerly load a one_to_one association with a custom callback" do
2180
- ds = GraphAlbum.eager_graph(:track => proc {|ds1| ds1.select(:album_id).columns(:album_id)})
2181
- 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)'
2182
- a = ds.with_fetch(:id=>1, :band_id=>2, :album_id=>1).all
2183
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2184
- a.first.track.must_equal GraphTrack.load(:album_id=>1)
2185
- end
2186
-
2187
- it "should eagerly load a one_to_many association with a custom callback" do
2188
- ds = GraphAlbum.eager_graph(:tracks => proc {|ds1| ds1.select(:album_id).columns(:album_id)})
2189
- 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)'
2190
- a = ds.with_fetch(:id=>1, :band_id=>2, :album_id=>1).all
2191
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2192
- a.first.tracks.must_equal [GraphTrack.load(:album_id=>1)]
2193
- end
2194
-
2195
- it "should eagerly load a one_through_one association with a custom callback" do
2196
- ds = GraphAlbum.eager_graph(:genre => proc {|ds1| ds1.select(:id).columns(:id)})
2197
- 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)'
2198
- a = ds.with_fetch(:id=>1, :band_id=>2, :genre_id=>4).all
2199
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2200
- a.first.genre.must_equal GraphGenre.load(:id => 4)
2201
- end
2202
-
2203
- it "should eagerly load a many_to_many association with a custom callback" do
2204
- ds = GraphAlbum.eager_graph(:genres => proc {|ds1| ds1.select(:id).columns(:id)})
2205
- 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)'
2206
- a = ds.with_fetch(:id=>1, :band_id=>2, :genres_id=>4).all
2207
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2208
- a.first.genres.must_equal [GraphGenre.load(:id => 4)]
2209
- end
2210
-
2211
- it "should allow cascading of eager loading with a custom callback with hash value" do
2212
- ds = GraphTrack.eager_graph(:album=>{proc{|ds1| ds1.select(:id, :band_id).columns(:id, :band_id)}=>{:band=>:members}})
2213
- 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)'
2214
- 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
2215
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2216
- a = a.first
2217
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2218
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
2219
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
2220
- end
2221
-
2222
- it "should allow cascading of eager loading with a custom callback with array value" do
2223
- ds = GraphTrack.eager_graph(:album=>{proc{|ds1| ds1.select(:id, :band_id).columns(:id, :band_id)}=>[:band, :tracks]})
2224
- 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)'
2225
- 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
2226
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2227
- a = a.first
2228
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2229
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
2230
- a.album.tracks.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2231
- end
2232
- end
2233
-
2234
- describe "Sequel::Models with double underscores in table names" do
2235
- before do
2236
- @db = Sequel.mock(:fetch=>{:id=>1, :foo_id=>2})
2237
- @Foo = Class.new(Sequel::Model(@db[Sequel.identifier(:fo__os)]))
2238
- @Foo.columns :id, :foo_id
2239
- @Foo.one_to_many :foos, :class=>@Foo
2240
- @db.sqls
2241
- end
2242
-
2243
- it "should have working eager_graph implementations" do
2244
- @db.fetch = {:id=>1, :foo_id=>1, :foos_id=>1, :foos_foo_id=>1}
2245
- foos = @Foo.eager_graph(:foos).all
2246
- @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)"]
2247
- foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2248
- foos.first.foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2249
- end
2250
-
2251
- it "should have working eager_graph implementations when qualified" do
2252
- @Foo.dataset = Sequel.identifier(:fo__os).qualify(:s)
2253
- @Foo.columns :id, :foo_id
2254
- @db.sqls
2255
- @db.fetch = {:id=>1, :foo_id=>1, :foos_id=>1, :foos_foo_id=>1}
2256
- foos = @Foo.eager_graph(:foos).all
2257
- @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)"]
2258
- foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2259
- foos.first.foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2260
- end
2261
- end
2262
-