sequel 4.36.0 → 5.61.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 (760) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +548 -5749
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +265 -159
  5. data/bin/sequel +34 -12
  6. data/doc/advanced_associations.rdoc +228 -187
  7. data/doc/association_basics.rdoc +281 -291
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +86 -51
  10. data/doc/code_order.rdoc +25 -19
  11. data/doc/core_extensions.rdoc +104 -63
  12. data/doc/dataset_basics.rdoc +12 -21
  13. data/doc/dataset_filtering.rdoc +99 -86
  14. data/doc/extensions.rdoc +3 -10
  15. data/doc/fork_safety.rdoc +84 -0
  16. data/doc/mass_assignment.rdoc +74 -31
  17. data/doc/migration.rdoc +59 -51
  18. data/doc/model_dataset_method_design.rdoc +129 -0
  19. data/doc/model_hooks.rdoc +15 -25
  20. data/doc/model_plugins.rdoc +12 -12
  21. data/doc/mssql_stored_procedures.rdoc +3 -3
  22. data/doc/object_model.rdoc +58 -68
  23. data/doc/opening_databases.rdoc +85 -95
  24. data/doc/postgresql.rdoc +263 -38
  25. data/doc/prepared_statements.rdoc +29 -24
  26. data/doc/querying.rdoc +189 -167
  27. data/doc/reflection.rdoc +5 -6
  28. data/doc/release_notes/5.0.0.txt +159 -0
  29. data/doc/release_notes/5.1.0.txt +31 -0
  30. data/doc/release_notes/5.10.0.txt +84 -0
  31. data/doc/release_notes/5.11.0.txt +83 -0
  32. data/doc/release_notes/5.12.0.txt +141 -0
  33. data/doc/release_notes/5.13.0.txt +27 -0
  34. data/doc/release_notes/5.14.0.txt +63 -0
  35. data/doc/release_notes/5.15.0.txt +39 -0
  36. data/doc/release_notes/5.16.0.txt +110 -0
  37. data/doc/release_notes/5.17.0.txt +31 -0
  38. data/doc/release_notes/5.18.0.txt +69 -0
  39. data/doc/release_notes/5.19.0.txt +28 -0
  40. data/doc/release_notes/5.2.0.txt +33 -0
  41. data/doc/release_notes/5.20.0.txt +89 -0
  42. data/doc/release_notes/5.21.0.txt +87 -0
  43. data/doc/release_notes/5.22.0.txt +48 -0
  44. data/doc/release_notes/5.23.0.txt +56 -0
  45. data/doc/release_notes/5.24.0.txt +56 -0
  46. data/doc/release_notes/5.25.0.txt +32 -0
  47. data/doc/release_notes/5.26.0.txt +35 -0
  48. data/doc/release_notes/5.27.0.txt +21 -0
  49. data/doc/release_notes/5.28.0.txt +16 -0
  50. data/doc/release_notes/5.29.0.txt +22 -0
  51. data/doc/release_notes/5.3.0.txt +121 -0
  52. data/doc/release_notes/5.30.0.txt +20 -0
  53. data/doc/release_notes/5.31.0.txt +148 -0
  54. data/doc/release_notes/5.32.0.txt +46 -0
  55. data/doc/release_notes/5.33.0.txt +24 -0
  56. data/doc/release_notes/5.34.0.txt +40 -0
  57. data/doc/release_notes/5.35.0.txt +56 -0
  58. data/doc/release_notes/5.36.0.txt +60 -0
  59. data/doc/release_notes/5.37.0.txt +30 -0
  60. data/doc/release_notes/5.38.0.txt +28 -0
  61. data/doc/release_notes/5.39.0.txt +19 -0
  62. data/doc/release_notes/5.4.0.txt +80 -0
  63. data/doc/release_notes/5.40.0.txt +40 -0
  64. data/doc/release_notes/5.41.0.txt +25 -0
  65. data/doc/release_notes/5.42.0.txt +136 -0
  66. data/doc/release_notes/5.43.0.txt +98 -0
  67. data/doc/release_notes/5.44.0.txt +32 -0
  68. data/doc/release_notes/5.45.0.txt +34 -0
  69. data/doc/release_notes/5.46.0.txt +87 -0
  70. data/doc/release_notes/5.47.0.txt +59 -0
  71. data/doc/release_notes/5.48.0.txt +14 -0
  72. data/doc/release_notes/5.49.0.txt +59 -0
  73. data/doc/release_notes/5.5.0.txt +61 -0
  74. data/doc/release_notes/5.50.0.txt +78 -0
  75. data/doc/release_notes/5.51.0.txt +47 -0
  76. data/doc/release_notes/5.52.0.txt +87 -0
  77. data/doc/release_notes/5.53.0.txt +23 -0
  78. data/doc/release_notes/5.54.0.txt +27 -0
  79. data/doc/release_notes/5.55.0.txt +21 -0
  80. data/doc/release_notes/5.56.0.txt +51 -0
  81. data/doc/release_notes/5.57.0.txt +23 -0
  82. data/doc/release_notes/5.58.0.txt +31 -0
  83. data/doc/release_notes/5.59.0.txt +73 -0
  84. data/doc/release_notes/5.6.0.txt +31 -0
  85. data/doc/release_notes/5.60.0.txt +22 -0
  86. data/doc/release_notes/5.61.0.txt +43 -0
  87. data/doc/release_notes/5.7.0.txt +108 -0
  88. data/doc/release_notes/5.8.0.txt +170 -0
  89. data/doc/release_notes/5.9.0.txt +99 -0
  90. data/doc/schema_modification.rdoc +95 -75
  91. data/doc/security.rdoc +109 -80
  92. data/doc/sharding.rdoc +74 -47
  93. data/doc/sql.rdoc +147 -122
  94. data/doc/testing.rdoc +43 -20
  95. data/doc/thread_safety.rdoc +2 -4
  96. data/doc/transactions.rdoc +97 -18
  97. data/doc/validations.rdoc +52 -50
  98. data/doc/virtual_rows.rdoc +90 -109
  99. data/lib/sequel/adapters/ado/access.rb +15 -17
  100. data/lib/sequel/adapters/ado/mssql.rb +6 -15
  101. data/lib/sequel/adapters/ado.rb +150 -20
  102. data/lib/sequel/adapters/amalgalite.rb +11 -23
  103. data/lib/sequel/adapters/ibmdb.rb +47 -55
  104. data/lib/sequel/adapters/jdbc/db2.rb +29 -39
  105. data/lib/sequel/adapters/jdbc/derby.rb +58 -54
  106. data/lib/sequel/adapters/jdbc/h2.rb +93 -35
  107. data/lib/sequel/adapters/jdbc/hsqldb.rb +24 -31
  108. data/lib/sequel/adapters/jdbc/jtds.rb +2 -10
  109. data/lib/sequel/adapters/jdbc/mssql.rb +3 -11
  110. data/lib/sequel/adapters/jdbc/mysql.rb +17 -20
  111. data/lib/sequel/adapters/jdbc/oracle.rb +22 -18
  112. data/lib/sequel/adapters/jdbc/postgresql.rb +69 -71
  113. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +11 -23
  114. data/lib/sequel/adapters/jdbc/sqlite.rb +47 -11
  115. data/lib/sequel/adapters/jdbc/sqlserver.rb +34 -9
  116. data/lib/sequel/adapters/jdbc/transactions.rb +22 -38
  117. data/lib/sequel/adapters/jdbc.rb +145 -130
  118. data/lib/sequel/adapters/mock.rb +100 -111
  119. data/lib/sequel/adapters/mysql.rb +114 -122
  120. data/lib/sequel/adapters/mysql2.rb +147 -63
  121. data/lib/sequel/adapters/odbc/db2.rb +1 -1
  122. data/lib/sequel/adapters/odbc/mssql.rb +8 -14
  123. data/lib/sequel/adapters/odbc/oracle.rb +11 -0
  124. data/lib/sequel/adapters/odbc.rb +20 -25
  125. data/lib/sequel/adapters/oracle.rb +50 -56
  126. data/lib/sequel/adapters/postgres.rb +305 -327
  127. data/lib/sequel/adapters/postgresql.rb +1 -1
  128. data/lib/sequel/adapters/shared/access.rb +74 -78
  129. data/lib/sequel/adapters/shared/db2.rb +118 -71
  130. data/lib/sequel/adapters/shared/mssql.rb +301 -220
  131. data/lib/sequel/adapters/shared/mysql.rb +299 -217
  132. data/lib/sequel/adapters/shared/oracle.rb +226 -65
  133. data/lib/sequel/adapters/shared/postgres.rb +935 -395
  134. data/lib/sequel/adapters/shared/sqlanywhere.rb +105 -126
  135. data/lib/sequel/adapters/shared/sqlite.rb +447 -173
  136. data/lib/sequel/adapters/sqlanywhere.rb +48 -35
  137. data/lib/sequel/adapters/sqlite.rb +156 -111
  138. data/lib/sequel/adapters/tinytds.rb +30 -38
  139. data/lib/sequel/adapters/utils/columns_limit_1.rb +22 -0
  140. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +3 -6
  141. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +2 -2
  142. data/lib/sequel/adapters/utils/mysql_mysql2.rb +87 -0
  143. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +56 -0
  144. data/lib/sequel/adapters/utils/replace.rb +1 -4
  145. data/lib/sequel/adapters/utils/stored_procedures.rb +7 -22
  146. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +28 -0
  147. data/lib/sequel/ast_transformer.rb +17 -89
  148. data/lib/sequel/connection_pool/sharded_single.rb +18 -15
  149. data/lib/sequel/connection_pool/sharded_threaded.rb +130 -111
  150. data/lib/sequel/connection_pool/single.rb +18 -13
  151. data/lib/sequel/connection_pool/threaded.rb +121 -120
  152. data/lib/sequel/connection_pool.rb +48 -29
  153. data/lib/sequel/core.rb +351 -301
  154. data/lib/sequel/database/connecting.rb +69 -57
  155. data/lib/sequel/database/dataset.rb +13 -5
  156. data/lib/sequel/database/dataset_defaults.rb +18 -102
  157. data/lib/sequel/database/features.rb +18 -4
  158. data/lib/sequel/database/logging.rb +12 -11
  159. data/lib/sequel/database/misc.rb +180 -122
  160. data/lib/sequel/database/query.rb +47 -27
  161. data/lib/sequel/database/schema_generator.rb +178 -84
  162. data/lib/sequel/database/schema_methods.rb +172 -97
  163. data/lib/sequel/database/transactions.rb +205 -44
  164. data/lib/sequel/database.rb +17 -2
  165. data/lib/sequel/dataset/actions.rb +339 -155
  166. data/lib/sequel/dataset/dataset_module.rb +46 -0
  167. data/lib/sequel/dataset/features.rb +90 -35
  168. data/lib/sequel/dataset/graph.rb +80 -58
  169. data/lib/sequel/dataset/misc.rb +137 -47
  170. data/lib/sequel/dataset/placeholder_literalizer.rb +63 -25
  171. data/lib/sequel/dataset/prepared_statements.rb +188 -85
  172. data/lib/sequel/dataset/query.rb +530 -222
  173. data/lib/sequel/dataset/sql.rb +590 -368
  174. data/lib/sequel/dataset.rb +26 -16
  175. data/lib/sequel/deprecated.rb +12 -2
  176. data/lib/sequel/exceptions.rb +46 -16
  177. data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
  178. data/lib/sequel/extensions/_model_pg_row.rb +43 -0
  179. data/lib/sequel/extensions/_pretty_table.rb +2 -5
  180. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  181. data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
  182. data/lib/sequel/extensions/async_thread_pool.rb +438 -0
  183. data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
  184. data/lib/sequel/extensions/blank.rb +8 -0
  185. data/lib/sequel/extensions/caller_logging.rb +79 -0
  186. data/lib/sequel/extensions/columns_introspection.rb +4 -3
  187. data/lib/sequel/extensions/connection_expiration.rb +20 -10
  188. data/lib/sequel/extensions/connection_validator.rb +11 -10
  189. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  190. data/lib/sequel/extensions/constraint_validations.rb +62 -39
  191. data/lib/sequel/extensions/core_extensions.rb +42 -48
  192. data/lib/sequel/extensions/core_refinements.rb +80 -59
  193. data/lib/sequel/extensions/current_datetime_timestamp.rb +1 -4
  194. data/lib/sequel/extensions/date_arithmetic.rb +98 -39
  195. data/lib/sequel/extensions/date_parse_input_handler.rb +67 -0
  196. data/lib/sequel/extensions/datetime_parse_to_time.rb +41 -0
  197. data/lib/sequel/extensions/duplicate_columns_handler.rb +21 -14
  198. data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
  199. data/lib/sequel/extensions/escaped_like.rb +100 -0
  200. data/lib/sequel/extensions/eval_inspect.rb +12 -15
  201. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  202. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  203. data/lib/sequel/extensions/freeze_datasets.rb +3 -0
  204. data/lib/sequel/extensions/from_block.rb +1 -34
  205. data/lib/sequel/extensions/graph_each.rb +4 -4
  206. data/lib/sequel/extensions/identifier_mangling.rb +180 -0
  207. data/lib/sequel/extensions/implicit_subquery.rb +48 -0
  208. data/lib/sequel/extensions/index_caching.rb +109 -0
  209. data/lib/sequel/extensions/inflector.rb +13 -5
  210. data/lib/sequel/extensions/integer64.rb +32 -0
  211. data/lib/sequel/extensions/is_distinct_from.rb +141 -0
  212. data/lib/sequel/extensions/looser_typecasting.rb +17 -8
  213. data/lib/sequel/extensions/migration.rb +119 -78
  214. data/lib/sequel/extensions/named_timezones.rb +88 -23
  215. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -82
  216. data/lib/sequel/extensions/null_dataset.rb +8 -8
  217. data/lib/sequel/extensions/pagination.rb +32 -29
  218. data/lib/sequel/extensions/pg_array.rb +221 -287
  219. data/lib/sequel/extensions/pg_array_ops.rb +17 -9
  220. data/lib/sequel/extensions/pg_enum.rb +63 -23
  221. data/lib/sequel/extensions/pg_extended_date_support.rb +241 -0
  222. data/lib/sequel/extensions/pg_hstore.rb +45 -54
  223. data/lib/sequel/extensions/pg_hstore_ops.rb +58 -6
  224. data/lib/sequel/extensions/pg_inet.rb +31 -12
  225. data/lib/sequel/extensions/pg_inet_ops.rb +2 -2
  226. data/lib/sequel/extensions/pg_interval.rb +56 -29
  227. data/lib/sequel/extensions/pg_json.rb +417 -140
  228. data/lib/sequel/extensions/pg_json_ops.rb +270 -18
  229. data/lib/sequel/extensions/pg_loose_count.rb +4 -2
  230. data/lib/sequel/extensions/pg_multirange.rb +372 -0
  231. data/lib/sequel/extensions/pg_range.rb +131 -191
  232. data/lib/sequel/extensions/pg_range_ops.rb +42 -13
  233. data/lib/sequel/extensions/pg_row.rb +48 -81
  234. data/lib/sequel/extensions/pg_row_ops.rb +33 -14
  235. data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
  236. data/lib/sequel/extensions/pg_timestamptz.rb +28 -0
  237. data/lib/sequel/extensions/query.rb +9 -7
  238. data/lib/sequel/extensions/round_timestamps.rb +0 -6
  239. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  240. data/lib/sequel/extensions/s.rb +60 -0
  241. data/lib/sequel/extensions/schema_caching.rb +10 -1
  242. data/lib/sequel/extensions/schema_dumper.rb +71 -48
  243. data/lib/sequel/extensions/select_remove.rb +4 -4
  244. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +85 -0
  245. data/lib/sequel/extensions/server_block.rb +51 -27
  246. data/lib/sequel/extensions/split_array_nil.rb +4 -4
  247. data/lib/sequel/extensions/sql_comments.rb +119 -7
  248. data/lib/sequel/extensions/sql_expr.rb +2 -1
  249. data/lib/sequel/extensions/sql_log_normalizer.rb +108 -0
  250. data/lib/sequel/extensions/sqlite_json_ops.rb +255 -0
  251. data/lib/sequel/extensions/string_agg.rb +11 -8
  252. data/lib/sequel/extensions/string_date_time.rb +19 -23
  253. data/lib/sequel/extensions/symbol_aref.rb +55 -0
  254. data/lib/sequel/extensions/symbol_aref_refinement.rb +43 -0
  255. data/lib/sequel/extensions/symbol_as.rb +23 -0
  256. data/lib/sequel/extensions/symbol_as_refinement.rb +37 -0
  257. data/lib/sequel/extensions/synchronize_sql.rb +45 -0
  258. data/lib/sequel/extensions/to_dot.rb +10 -4
  259. data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
  260. data/lib/sequel/model/associations.rb +1006 -284
  261. data/lib/sequel/model/base.rb +560 -805
  262. data/lib/sequel/model/dataset_module.rb +11 -10
  263. data/lib/sequel/model/default_inflections.rb +1 -1
  264. data/lib/sequel/model/errors.rb +10 -3
  265. data/lib/sequel/model/exceptions.rb +8 -10
  266. data/lib/sequel/model/inflections.rb +7 -20
  267. data/lib/sequel/model/plugins.rb +114 -0
  268. data/lib/sequel/model.rb +32 -82
  269. data/lib/sequel/plugins/active_model.rb +30 -14
  270. data/lib/sequel/plugins/after_initialize.rb +1 -1
  271. data/lib/sequel/plugins/association_dependencies.rb +25 -18
  272. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  273. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  274. data/lib/sequel/plugins/association_pks.rb +147 -70
  275. data/lib/sequel/plugins/association_proxies.rb +33 -9
  276. data/lib/sequel/plugins/async_thread_pool.rb +39 -0
  277. data/lib/sequel/plugins/auto_restrict_eager_graph.rb +62 -0
  278. data/lib/sequel/plugins/auto_validations.rb +95 -28
  279. data/lib/sequel/plugins/auto_validations_constraint_validations_presence_message.rb +68 -0
  280. data/lib/sequel/plugins/before_after_save.rb +0 -42
  281. data/lib/sequel/plugins/blacklist_security.rb +21 -12
  282. data/lib/sequel/plugins/boolean_readers.rb +5 -5
  283. data/lib/sequel/plugins/boolean_subsets.rb +13 -8
  284. data/lib/sequel/plugins/caching.rb +25 -16
  285. data/lib/sequel/plugins/class_table_inheritance.rb +179 -100
  286. data/lib/sequel/plugins/column_conflicts.rb +16 -3
  287. data/lib/sequel/plugins/column_encryption.rb +728 -0
  288. data/lib/sequel/plugins/column_select.rb +7 -5
  289. data/lib/sequel/plugins/columns_updated.rb +42 -0
  290. data/lib/sequel/plugins/composition.rb +42 -26
  291. data/lib/sequel/plugins/concurrent_eager_loading.rb +174 -0
  292. data/lib/sequel/plugins/constraint_validations.rb +20 -14
  293. data/lib/sequel/plugins/csv_serializer.rb +56 -35
  294. data/lib/sequel/plugins/dataset_associations.rb +40 -17
  295. data/lib/sequel/plugins/def_dataset_method.rb +90 -0
  296. data/lib/sequel/plugins/defaults_setter.rb +65 -10
  297. data/lib/sequel/plugins/delay_add_association.rb +1 -1
  298. data/lib/sequel/plugins/dirty.rb +62 -24
  299. data/lib/sequel/plugins/eager_each.rb +3 -3
  300. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  301. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  302. data/lib/sequel/plugins/enum.rb +124 -0
  303. data/lib/sequel/plugins/error_splitter.rb +17 -12
  304. data/lib/sequel/plugins/finder.rb +246 -0
  305. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  306. data/lib/sequel/plugins/force_encoding.rb +7 -12
  307. data/lib/sequel/plugins/hook_class_methods.rb +37 -54
  308. data/lib/sequel/plugins/input_transformer.rb +18 -10
  309. data/lib/sequel/plugins/insert_conflict.rb +76 -0
  310. data/lib/sequel/plugins/insert_returning_select.rb +2 -2
  311. data/lib/sequel/plugins/instance_filters.rb +10 -8
  312. data/lib/sequel/plugins/instance_hooks.rb +34 -17
  313. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  314. data/lib/sequel/plugins/inverted_subsets.rb +22 -13
  315. data/lib/sequel/plugins/json_serializer.rb +124 -64
  316. data/lib/sequel/plugins/lazy_attributes.rb +21 -14
  317. data/lib/sequel/plugins/list.rb +35 -21
  318. data/lib/sequel/plugins/many_through_many.rb +134 -21
  319. data/lib/sequel/plugins/modification_detection.rb +15 -5
  320. data/lib/sequel/plugins/mssql_optimistic_locking.rb +6 -5
  321. data/lib/sequel/plugins/nested_attributes.rb +61 -31
  322. data/lib/sequel/plugins/optimistic_locking.rb +3 -3
  323. data/lib/sequel/plugins/pg_array_associations.rb +103 -53
  324. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +350 -0
  325. data/lib/sequel/plugins/pg_row.rb +5 -51
  326. data/lib/sequel/plugins/prepared_statements.rb +60 -72
  327. data/lib/sequel/plugins/prepared_statements_safe.rb +9 -4
  328. data/lib/sequel/plugins/rcte_tree.rb +68 -82
  329. data/lib/sequel/plugins/require_valid_schema.rb +67 -0
  330. data/lib/sequel/plugins/serialization.rb +43 -46
  331. data/lib/sequel/plugins/serialization_modification_detection.rb +3 -2
  332. data/lib/sequel/plugins/sharding.rb +15 -10
  333. data/lib/sequel/plugins/single_table_inheritance.rb +67 -28
  334. data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
  335. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  336. data/lib/sequel/plugins/split_values.rb +11 -6
  337. data/lib/sequel/plugins/sql_comments.rb +189 -0
  338. data/lib/sequel/plugins/static_cache.rb +77 -53
  339. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  340. data/lib/sequel/plugins/string_stripper.rb +3 -3
  341. data/lib/sequel/plugins/subclasses.rb +43 -10
  342. data/lib/sequel/plugins/subset_conditions.rb +15 -5
  343. data/lib/sequel/plugins/table_select.rb +2 -2
  344. data/lib/sequel/plugins/tactical_eager_loading.rb +96 -12
  345. data/lib/sequel/plugins/throw_failures.rb +110 -0
  346. data/lib/sequel/plugins/timestamps.rb +20 -8
  347. data/lib/sequel/plugins/touch.rb +19 -8
  348. data/lib/sequel/plugins/tree.rb +62 -32
  349. data/lib/sequel/plugins/typecast_on_load.rb +12 -4
  350. data/lib/sequel/plugins/unlimited_update.rb +1 -7
  351. data/lib/sequel/plugins/unused_associations.rb +521 -0
  352. data/lib/sequel/plugins/update_or_create.rb +4 -4
  353. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  354. data/lib/sequel/plugins/update_refresh.rb +26 -15
  355. data/lib/sequel/plugins/uuid.rb +7 -11
  356. data/lib/sequel/plugins/validate_associated.rb +18 -0
  357. data/lib/sequel/plugins/validation_class_methods.rb +38 -19
  358. data/lib/sequel/plugins/validation_contexts.rb +49 -0
  359. data/lib/sequel/plugins/validation_helpers.rb +57 -41
  360. data/lib/sequel/plugins/whitelist_security.rb +122 -0
  361. data/lib/sequel/plugins/xml_serializer.rb +30 -31
  362. data/lib/sequel/sql.rb +471 -331
  363. data/lib/sequel/timezones.rb +78 -47
  364. data/lib/sequel/version.rb +7 -2
  365. data/lib/sequel.rb +1 -1
  366. metadata +217 -521
  367. data/Rakefile +0 -164
  368. data/doc/active_record.rdoc +0 -928
  369. data/doc/release_notes/1.0.txt +0 -38
  370. data/doc/release_notes/1.1.txt +0 -143
  371. data/doc/release_notes/1.3.txt +0 -101
  372. data/doc/release_notes/1.4.0.txt +0 -53
  373. data/doc/release_notes/1.5.0.txt +0 -155
  374. data/doc/release_notes/2.0.0.txt +0 -298
  375. data/doc/release_notes/2.1.0.txt +0 -271
  376. data/doc/release_notes/2.10.0.txt +0 -328
  377. data/doc/release_notes/2.11.0.txt +0 -215
  378. data/doc/release_notes/2.12.0.txt +0 -534
  379. data/doc/release_notes/2.2.0.txt +0 -253
  380. data/doc/release_notes/2.3.0.txt +0 -88
  381. data/doc/release_notes/2.4.0.txt +0 -106
  382. data/doc/release_notes/2.5.0.txt +0 -137
  383. data/doc/release_notes/2.6.0.txt +0 -157
  384. data/doc/release_notes/2.7.0.txt +0 -166
  385. data/doc/release_notes/2.8.0.txt +0 -171
  386. data/doc/release_notes/2.9.0.txt +0 -97
  387. data/doc/release_notes/3.0.0.txt +0 -221
  388. data/doc/release_notes/3.1.0.txt +0 -406
  389. data/doc/release_notes/3.10.0.txt +0 -286
  390. data/doc/release_notes/3.11.0.txt +0 -254
  391. data/doc/release_notes/3.12.0.txt +0 -304
  392. data/doc/release_notes/3.13.0.txt +0 -210
  393. data/doc/release_notes/3.14.0.txt +0 -118
  394. data/doc/release_notes/3.15.0.txt +0 -78
  395. data/doc/release_notes/3.16.0.txt +0 -45
  396. data/doc/release_notes/3.17.0.txt +0 -58
  397. data/doc/release_notes/3.18.0.txt +0 -120
  398. data/doc/release_notes/3.19.0.txt +0 -67
  399. data/doc/release_notes/3.2.0.txt +0 -268
  400. data/doc/release_notes/3.20.0.txt +0 -41
  401. data/doc/release_notes/3.21.0.txt +0 -87
  402. data/doc/release_notes/3.22.0.txt +0 -39
  403. data/doc/release_notes/3.23.0.txt +0 -172
  404. data/doc/release_notes/3.24.0.txt +0 -420
  405. data/doc/release_notes/3.25.0.txt +0 -88
  406. data/doc/release_notes/3.26.0.txt +0 -88
  407. data/doc/release_notes/3.27.0.txt +0 -82
  408. data/doc/release_notes/3.28.0.txt +0 -304
  409. data/doc/release_notes/3.29.0.txt +0 -459
  410. data/doc/release_notes/3.3.0.txt +0 -192
  411. data/doc/release_notes/3.30.0.txt +0 -135
  412. data/doc/release_notes/3.31.0.txt +0 -146
  413. data/doc/release_notes/3.32.0.txt +0 -202
  414. data/doc/release_notes/3.33.0.txt +0 -157
  415. data/doc/release_notes/3.34.0.txt +0 -671
  416. data/doc/release_notes/3.35.0.txt +0 -144
  417. data/doc/release_notes/3.36.0.txt +0 -245
  418. data/doc/release_notes/3.37.0.txt +0 -338
  419. data/doc/release_notes/3.38.0.txt +0 -234
  420. data/doc/release_notes/3.39.0.txt +0 -237
  421. data/doc/release_notes/3.4.0.txt +0 -325
  422. data/doc/release_notes/3.40.0.txt +0 -73
  423. data/doc/release_notes/3.41.0.txt +0 -155
  424. data/doc/release_notes/3.42.0.txt +0 -74
  425. data/doc/release_notes/3.43.0.txt +0 -105
  426. data/doc/release_notes/3.44.0.txt +0 -152
  427. data/doc/release_notes/3.45.0.txt +0 -179
  428. data/doc/release_notes/3.46.0.txt +0 -122
  429. data/doc/release_notes/3.47.0.txt +0 -270
  430. data/doc/release_notes/3.48.0.txt +0 -477
  431. data/doc/release_notes/3.5.0.txt +0 -510
  432. data/doc/release_notes/3.6.0.txt +0 -366
  433. data/doc/release_notes/3.7.0.txt +0 -179
  434. data/doc/release_notes/3.8.0.txt +0 -151
  435. data/doc/release_notes/3.9.0.txt +0 -233
  436. data/doc/release_notes/4.0.0.txt +0 -262
  437. data/doc/release_notes/4.1.0.txt +0 -85
  438. data/doc/release_notes/4.10.0.txt +0 -226
  439. data/doc/release_notes/4.11.0.txt +0 -147
  440. data/doc/release_notes/4.12.0.txt +0 -105
  441. data/doc/release_notes/4.13.0.txt +0 -169
  442. data/doc/release_notes/4.14.0.txt +0 -68
  443. data/doc/release_notes/4.15.0.txt +0 -56
  444. data/doc/release_notes/4.16.0.txt +0 -36
  445. data/doc/release_notes/4.17.0.txt +0 -38
  446. data/doc/release_notes/4.18.0.txt +0 -36
  447. data/doc/release_notes/4.19.0.txt +0 -45
  448. data/doc/release_notes/4.2.0.txt +0 -129
  449. data/doc/release_notes/4.20.0.txt +0 -79
  450. data/doc/release_notes/4.21.0.txt +0 -94
  451. data/doc/release_notes/4.22.0.txt +0 -72
  452. data/doc/release_notes/4.23.0.txt +0 -65
  453. data/doc/release_notes/4.24.0.txt +0 -99
  454. data/doc/release_notes/4.25.0.txt +0 -181
  455. data/doc/release_notes/4.26.0.txt +0 -44
  456. data/doc/release_notes/4.27.0.txt +0 -78
  457. data/doc/release_notes/4.28.0.txt +0 -57
  458. data/doc/release_notes/4.29.0.txt +0 -41
  459. data/doc/release_notes/4.3.0.txt +0 -40
  460. data/doc/release_notes/4.30.0.txt +0 -37
  461. data/doc/release_notes/4.31.0.txt +0 -57
  462. data/doc/release_notes/4.32.0.txt +0 -132
  463. data/doc/release_notes/4.33.0.txt +0 -88
  464. data/doc/release_notes/4.34.0.txt +0 -86
  465. data/doc/release_notes/4.35.0.txt +0 -130
  466. data/doc/release_notes/4.36.0.txt +0 -116
  467. data/doc/release_notes/4.4.0.txt +0 -92
  468. data/doc/release_notes/4.5.0.txt +0 -34
  469. data/doc/release_notes/4.6.0.txt +0 -30
  470. data/doc/release_notes/4.7.0.txt +0 -103
  471. data/doc/release_notes/4.8.0.txt +0 -175
  472. data/doc/release_notes/4.9.0.txt +0 -190
  473. data/lib/sequel/adapters/cubrid.rb +0 -144
  474. data/lib/sequel/adapters/do/mysql.rb +0 -66
  475. data/lib/sequel/adapters/do/postgres.rb +0 -44
  476. data/lib/sequel/adapters/do/sqlite3.rb +0 -42
  477. data/lib/sequel/adapters/do.rb +0 -158
  478. data/lib/sequel/adapters/jdbc/as400.rb +0 -84
  479. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -64
  480. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -36
  481. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -33
  482. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -33
  483. data/lib/sequel/adapters/odbc/progress.rb +0 -10
  484. data/lib/sequel/adapters/shared/cubrid.rb +0 -245
  485. data/lib/sequel/adapters/shared/firebird.rb +0 -247
  486. data/lib/sequel/adapters/shared/informix.rb +0 -54
  487. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +0 -152
  488. data/lib/sequel/adapters/shared/progress.rb +0 -40
  489. data/lib/sequel/adapters/swift/mysql.rb +0 -49
  490. data/lib/sequel/adapters/swift/postgres.rb +0 -47
  491. data/lib/sequel/adapters/swift/sqlite.rb +0 -49
  492. data/lib/sequel/adapters/swift.rb +0 -160
  493. data/lib/sequel/adapters/utils/pg_types.rb +0 -70
  494. data/lib/sequel/dataset/mutation.rb +0 -111
  495. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -5
  496. data/lib/sequel/extensions/filter_having.rb +0 -63
  497. data/lib/sequel/extensions/hash_aliases.rb +0 -49
  498. data/lib/sequel/extensions/meta_def.rb +0 -35
  499. data/lib/sequel/extensions/query_literals.rb +0 -84
  500. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -24
  501. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -122
  502. data/lib/sequel/extensions/set_overrides.rb +0 -76
  503. data/lib/sequel/no_core_ext.rb +0 -3
  504. data/lib/sequel/plugins/association_autoreloading.rb +0 -9
  505. data/lib/sequel/plugins/identifier_columns.rb +0 -47
  506. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -9
  507. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -81
  508. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -119
  509. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -61
  510. data/lib/sequel/plugins/schema.rb +0 -82
  511. data/lib/sequel/plugins/scissors.rb +0 -35
  512. data/spec/adapter_spec.rb +0 -4
  513. data/spec/adapters/db2_spec.rb +0 -160
  514. data/spec/adapters/firebird_spec.rb +0 -411
  515. data/spec/adapters/informix_spec.rb +0 -100
  516. data/spec/adapters/mssql_spec.rb +0 -733
  517. data/spec/adapters/mysql_spec.rb +0 -1319
  518. data/spec/adapters/oracle_spec.rb +0 -313
  519. data/spec/adapters/postgres_spec.rb +0 -3790
  520. data/spec/adapters/spec_helper.rb +0 -49
  521. data/spec/adapters/sqlanywhere_spec.rb +0 -170
  522. data/spec/adapters/sqlite_spec.rb +0 -688
  523. data/spec/bin_spec.rb +0 -258
  524. data/spec/core/connection_pool_spec.rb +0 -1045
  525. data/spec/core/database_spec.rb +0 -2636
  526. data/spec/core/dataset_spec.rb +0 -5175
  527. data/spec/core/deprecated_spec.rb +0 -70
  528. data/spec/core/expression_filters_spec.rb +0 -1247
  529. data/spec/core/mock_adapter_spec.rb +0 -464
  530. data/spec/core/object_graph_spec.rb +0 -303
  531. data/spec/core/placeholder_literalizer_spec.rb +0 -163
  532. data/spec/core/schema_generator_spec.rb +0 -203
  533. data/spec/core/schema_spec.rb +0 -1676
  534. data/spec/core/spec_helper.rb +0 -34
  535. data/spec/core/version_spec.rb +0 -7
  536. data/spec/core_extensions_spec.rb +0 -699
  537. data/spec/core_model_spec.rb +0 -2
  538. data/spec/core_spec.rb +0 -1
  539. data/spec/extensions/accessed_columns_spec.rb +0 -51
  540. data/spec/extensions/active_model_spec.rb +0 -85
  541. data/spec/extensions/after_initialize_spec.rb +0 -24
  542. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  543. data/spec/extensions/association_dependencies_spec.rb +0 -117
  544. data/spec/extensions/association_pks_spec.rb +0 -405
  545. data/spec/extensions/association_proxies_spec.rb +0 -86
  546. data/spec/extensions/auto_validations_spec.rb +0 -192
  547. data/spec/extensions/before_after_save_spec.rb +0 -40
  548. data/spec/extensions/blacklist_security_spec.rb +0 -88
  549. data/spec/extensions/blank_spec.rb +0 -69
  550. data/spec/extensions/boolean_readers_spec.rb +0 -93
  551. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  552. data/spec/extensions/caching_spec.rb +0 -270
  553. data/spec/extensions/class_table_inheritance_spec.rb +0 -444
  554. data/spec/extensions/column_conflicts_spec.rb +0 -60
  555. data/spec/extensions/column_select_spec.rb +0 -108
  556. data/spec/extensions/columns_introspection_spec.rb +0 -91
  557. data/spec/extensions/composition_spec.rb +0 -242
  558. data/spec/extensions/connection_expiration_spec.rb +0 -121
  559. data/spec/extensions/connection_validator_spec.rb +0 -127
  560. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -288
  561. data/spec/extensions/constraint_validations_spec.rb +0 -389
  562. data/spec/extensions/core_refinements_spec.rb +0 -519
  563. data/spec/extensions/csv_serializer_spec.rb +0 -180
  564. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  565. data/spec/extensions/dataset_associations_spec.rb +0 -343
  566. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  567. data/spec/extensions/date_arithmetic_spec.rb +0 -167
  568. data/spec/extensions/defaults_setter_spec.rb +0 -102
  569. data/spec/extensions/delay_add_association_spec.rb +0 -74
  570. data/spec/extensions/dirty_spec.rb +0 -180
  571. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -110
  572. data/spec/extensions/eager_each_spec.rb +0 -66
  573. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  574. data/spec/extensions/error_splitter_spec.rb +0 -18
  575. data/spec/extensions/error_sql_spec.rb +0 -20
  576. data/spec/extensions/eval_inspect_spec.rb +0 -73
  577. data/spec/extensions/filter_having_spec.rb +0 -40
  578. data/spec/extensions/force_encoding_spec.rb +0 -114
  579. data/spec/extensions/from_block_spec.rb +0 -21
  580. data/spec/extensions/graph_each_spec.rb +0 -119
  581. data/spec/extensions/hash_aliases_spec.rb +0 -24
  582. data/spec/extensions/hook_class_methods_spec.rb +0 -429
  583. data/spec/extensions/identifier_columns_spec.rb +0 -17
  584. data/spec/extensions/inflector_spec.rb +0 -183
  585. data/spec/extensions/input_transformer_spec.rb +0 -54
  586. data/spec/extensions/insert_returning_select_spec.rb +0 -46
  587. data/spec/extensions/instance_filters_spec.rb +0 -79
  588. data/spec/extensions/instance_hooks_spec.rb +0 -276
  589. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  590. data/spec/extensions/json_serializer_spec.rb +0 -304
  591. data/spec/extensions/lazy_attributes_spec.rb +0 -170
  592. data/spec/extensions/list_spec.rb +0 -278
  593. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  594. data/spec/extensions/many_through_many_spec.rb +0 -2172
  595. data/spec/extensions/meta_def_spec.rb +0 -21
  596. data/spec/extensions/migration_spec.rb +0 -728
  597. data/spec/extensions/modification_detection_spec.rb +0 -80
  598. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -91
  599. data/spec/extensions/named_timezones_spec.rb +0 -108
  600. data/spec/extensions/nested_attributes_spec.rb +0 -697
  601. data/spec/extensions/no_auto_literal_strings_spec.rb +0 -65
  602. data/spec/extensions/null_dataset_spec.rb +0 -85
  603. data/spec/extensions/optimistic_locking_spec.rb +0 -128
  604. data/spec/extensions/pagination_spec.rb +0 -118
  605. data/spec/extensions/pg_array_associations_spec.rb +0 -736
  606. data/spec/extensions/pg_array_ops_spec.rb +0 -143
  607. data/spec/extensions/pg_array_spec.rb +0 -390
  608. data/spec/extensions/pg_enum_spec.rb +0 -92
  609. data/spec/extensions/pg_hstore_ops_spec.rb +0 -236
  610. data/spec/extensions/pg_hstore_spec.rb +0 -206
  611. data/spec/extensions/pg_inet_ops_spec.rb +0 -101
  612. data/spec/extensions/pg_inet_spec.rb +0 -52
  613. data/spec/extensions/pg_interval_spec.rb +0 -76
  614. data/spec/extensions/pg_json_ops_spec.rb +0 -275
  615. data/spec/extensions/pg_json_spec.rb +0 -218
  616. data/spec/extensions/pg_loose_count_spec.rb +0 -17
  617. data/spec/extensions/pg_range_ops_spec.rb +0 -58
  618. data/spec/extensions/pg_range_spec.rb +0 -473
  619. data/spec/extensions/pg_row_ops_spec.rb +0 -60
  620. data/spec/extensions/pg_row_plugin_spec.rb +0 -62
  621. data/spec/extensions/pg_row_spec.rb +0 -360
  622. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -92
  623. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -63
  624. data/spec/extensions/prepared_statements_associations_spec.rb +0 -159
  625. data/spec/extensions/prepared_statements_safe_spec.rb +0 -61
  626. data/spec/extensions/prepared_statements_spec.rb +0 -103
  627. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -31
  628. data/spec/extensions/pretty_table_spec.rb +0 -92
  629. data/spec/extensions/query_literals_spec.rb +0 -183
  630. data/spec/extensions/query_spec.rb +0 -102
  631. data/spec/extensions/rcte_tree_spec.rb +0 -392
  632. data/spec/extensions/round_timestamps_spec.rb +0 -43
  633. data/spec/extensions/schema_caching_spec.rb +0 -41
  634. data/spec/extensions/schema_dumper_spec.rb +0 -814
  635. data/spec/extensions/schema_spec.rb +0 -117
  636. data/spec/extensions/scissors_spec.rb +0 -26
  637. data/spec/extensions/select_remove_spec.rb +0 -38
  638. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -101
  639. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  640. data/spec/extensions/serialization_spec.rb +0 -362
  641. data/spec/extensions/server_block_spec.rb +0 -90
  642. data/spec/extensions/server_logging_spec.rb +0 -45
  643. data/spec/extensions/set_overrides_spec.rb +0 -61
  644. data/spec/extensions/sharding_spec.rb +0 -198
  645. data/spec/extensions/shared_caching_spec.rb +0 -175
  646. data/spec/extensions/single_table_inheritance_spec.rb +0 -297
  647. data/spec/extensions/singular_table_names_spec.rb +0 -22
  648. data/spec/extensions/skip_create_refresh_spec.rb +0 -17
  649. data/spec/extensions/spec_helper.rb +0 -71
  650. data/spec/extensions/split_array_nil_spec.rb +0 -24
  651. data/spec/extensions/split_values_spec.rb +0 -22
  652. data/spec/extensions/sql_comments_spec.rb +0 -27
  653. data/spec/extensions/sql_expr_spec.rb +0 -60
  654. data/spec/extensions/static_cache_spec.rb +0 -361
  655. data/spec/extensions/string_agg_spec.rb +0 -85
  656. data/spec/extensions/string_date_time_spec.rb +0 -95
  657. data/spec/extensions/string_stripper_spec.rb +0 -68
  658. data/spec/extensions/subclasses_spec.rb +0 -66
  659. data/spec/extensions/subset_conditions_spec.rb +0 -38
  660. data/spec/extensions/table_select_spec.rb +0 -71
  661. data/spec/extensions/tactical_eager_loading_spec.rb +0 -136
  662. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  663. data/spec/extensions/timestamps_spec.rb +0 -175
  664. data/spec/extensions/to_dot_spec.rb +0 -154
  665. data/spec/extensions/touch_spec.rb +0 -203
  666. data/spec/extensions/tree_spec.rb +0 -274
  667. data/spec/extensions/typecast_on_load_spec.rb +0 -80
  668. data/spec/extensions/unlimited_update_spec.rb +0 -20
  669. data/spec/extensions/update_or_create_spec.rb +0 -87
  670. data/spec/extensions/update_primary_key_spec.rb +0 -100
  671. data/spec/extensions/update_refresh_spec.rb +0 -53
  672. data/spec/extensions/uuid_spec.rb +0 -106
  673. data/spec/extensions/validate_associated_spec.rb +0 -52
  674. data/spec/extensions/validation_class_methods_spec.rb +0 -1027
  675. data/spec/extensions/validation_helpers_spec.rb +0 -554
  676. data/spec/extensions/xml_serializer_spec.rb +0 -207
  677. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  678. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  679. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  680. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  681. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  682. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  683. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  684. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  685. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  686. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  687. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  688. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  689. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  690. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  691. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  692. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  693. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  694. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  695. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  696. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  697. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  698. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  699. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  700. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  701. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  702. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  703. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  704. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  705. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  706. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  707. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  708. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  709. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  710. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  711. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  712. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  713. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  714. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  715. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  716. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  717. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  718. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  719. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  720. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  721. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  722. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  723. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  724. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  725. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  726. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  727. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  728. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  729. data/spec/guards_helper.rb +0 -55
  730. data/spec/integration/associations_test.rb +0 -2506
  731. data/spec/integration/database_test.rb +0 -113
  732. data/spec/integration/dataset_test.rb +0 -1858
  733. data/spec/integration/eager_loader_test.rb +0 -687
  734. data/spec/integration/migrator_test.rb +0 -262
  735. data/spec/integration/model_test.rb +0 -230
  736. data/spec/integration/plugin_test.rb +0 -2297
  737. data/spec/integration/prepared_statement_test.rb +0 -467
  738. data/spec/integration/schema_test.rb +0 -815
  739. data/spec/integration/spec_helper.rb +0 -56
  740. data/spec/integration/timezone_test.rb +0 -86
  741. data/spec/integration/transaction_test.rb +0 -406
  742. data/spec/integration/type_test.rb +0 -133
  743. data/spec/model/association_reflection_spec.rb +0 -565
  744. data/spec/model/associations_spec.rb +0 -4589
  745. data/spec/model/base_spec.rb +0 -759
  746. data/spec/model/class_dataset_methods_spec.rb +0 -150
  747. data/spec/model/dataset_methods_spec.rb +0 -149
  748. data/spec/model/eager_loading_spec.rb +0 -2197
  749. data/spec/model/hooks_spec.rb +0 -604
  750. data/spec/model/inflector_spec.rb +0 -26
  751. data/spec/model/model_spec.rb +0 -1097
  752. data/spec/model/plugins_spec.rb +0 -299
  753. data/spec/model/record_spec.rb +0 -2162
  754. data/spec/model/spec_helper.rb +0 -46
  755. data/spec/model/validations_spec.rb +0 -193
  756. data/spec/model_no_assoc_spec.rb +0 -1
  757. data/spec/model_spec.rb +0 -1
  758. data/spec/plugin_spec.rb +0 -1
  759. data/spec/sequel_coverage.rb +0 -15
  760. data/spec/spec_config.rb +0 -10
@@ -1,2197 +0,0 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), "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.columns(:id, :band_id)
59
- EagerAlbum.dataset._fetch = proc do |sql|
60
- h = if sql =~ /101/
61
- {:id => 101, :band_id=> 101}
62
- else
63
- {:id => 1, :band_id=> 2}
64
- end
65
- h[:x_foreign_key_x] = 4 if sql =~ /ag\.genre_id/
66
- h
67
- end
68
-
69
- EagerBand.dataset._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._fetch = {:id => 3, :album_id => 1}
83
-
84
- EagerGenre.dataset._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._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._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_equal nil
156
- a.first.band.must_equal 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._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
- def (EagerTrack.dataset).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
- def (EagerTrack.dataset).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 automatically use an eager limit stategy if the association has an offset" do
226
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1]
227
- EagerTrack.dataset._fetch = [{:id => 4, :album_id=>1}]
228
- a = EagerAlbum.eager(:track).all
229
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
230
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) LIMIT 1 OFFSET 1) AS t1']
231
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
232
- DB.sqls.must_equal []
233
- end
234
-
235
- it "should handle offsets when using the :ruby eager limit stategy" do
236
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1], :eager_limit_strategy=>:ruby
237
- EagerTrack.dataset._fetch = [{:id => 3, :album_id=>1}, {:id => 4, :album_id=>1}]
238
- a = EagerAlbum.eager(:track).all
239
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
240
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
241
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
242
- DB.sqls.must_equal []
243
- end
244
-
245
- it "should support a :subqueries_per_union option for the number of subqueries in a union" do
246
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1], :subqueries_per_union=>1
247
- EagerAlbum.dataset._fetch = [{:id => 1, :band_id => 2}, {:id => 2, :band_id => 3}, {:id => 3, :band_id => 4}]
248
- EagerTrack.dataset._fetch = [[{:id => 4, :album_id=>1}], [{:id=>5, :album_id=>2}], [{:id=>6, :album_id=>3}]]
249
- a = EagerAlbum.eager(:track).all
250
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2), EagerAlbum.load(:id => 2, :band_id => 3), EagerAlbum.load(:id => 3, :band_id => 4)]
251
- 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']
252
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
253
- DB.sqls.must_equal []
254
-
255
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1], :subqueries_per_union=>2
256
- EagerTrack.dataset._fetch = [[{:id => 4, :album_id=>1}, {:id=>5, :album_id=>2}], [{:id=>6, :album_id=>3}]]
257
- a = EagerAlbum.eager(:track).all
258
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2), EagerAlbum.load(:id => 2, :band_id => 3), EagerAlbum.load(:id => 3, :band_id => 4)]
259
- 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']
260
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
261
- DB.sqls.must_equal []
262
-
263
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :limit=>[1,1], :subqueries_per_union=>3
264
- EagerTrack.dataset._fetch = [[{:id => 4, :album_id=>1}, {:id=>5, :album_id=>2}, {:id=>6, :album_id=>3}]]
265
- a = EagerAlbum.eager(:track).all
266
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2), EagerAlbum.load(:id => 2, :band_id => 3), EagerAlbum.load(:id => 3, :band_id => 4)]
267
- 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']
268
- a.first.track.must_equal EagerTrack.load(:id => 4, :album_id=>1)
269
- DB.sqls.must_equal []
270
- end
271
-
272
- it "should eagerly load a single one_to_many association" do
273
- a = EagerAlbum.eager(:tracks).all
274
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
275
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
276
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
277
- DB.sqls.must_equal []
278
- end
279
-
280
- it "should eagerly load a single one_through_one association" do
281
- a = EagerAlbum.eager(:genre).all
282
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
283
- 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))"]
284
- a.first.genre.must_equal EagerGenre.load(:id=>4)
285
- DB.sqls.must_equal []
286
- end
287
-
288
- it "should use first matching entry when eager loading one_through_one association" do
289
- EagerGenre.dataset._fetch = [{:id => 3, :x_foreign_key_x=>1}, {:id => 4, :x_foreign_key_x=>1}]
290
- a = EagerAlbum.eager(:genre).all
291
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
292
- 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))"]
293
- a.first.genre.must_equal EagerGenre.load(:id=>3)
294
- DB.sqls.must_equal []
295
- end
296
-
297
- it "should eagerly load a single one_through_one association" do
298
- EagerAlbum.one_through_one :genre, :clone=>:genre, :order=>:a
299
- a = EagerAlbum.eager(:genre).all
300
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
301
- 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"]
302
- a.first.genre.must_equal EagerGenre.load(:id=>4)
303
- DB.sqls.must_equal []
304
- end
305
-
306
- it "should eagerly load a single one_through_one association using the :distinct_on strategy" do
307
- def (EagerGenre.dataset).supports_distinct_on?() true end
308
- EagerAlbum.one_through_one :genre, :clone=>:genre, :order=>:a, :eager_limit_strategy=>:distinct_on
309
- a = EagerAlbum.eager(:genre).all
310
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
311
- 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"]
312
- a.first.genre.must_equal EagerGenre.load(:id=>4)
313
- DB.sqls.must_equal []
314
- end
315
-
316
- it "should eagerly load a single one_through_one association using the :window_function strategy" do
317
- def (EagerGenre.dataset).supports_window_functions?() true end
318
- EagerAlbum.one_through_one :genre, :clone=>:genre, :eager_limit_strategy=>:window_function
319
- a = EagerAlbum.eager(:genre).all
320
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
321
- 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)"]
322
- a.first.genre.must_equal EagerGenre.load(:id=>4)
323
- DB.sqls.must_equal []
324
- end
325
-
326
- it "should automatically use an eager limit stategy if the association has an offset" do
327
- EagerGenre.dataset._fetch = [{:id => 3, :x_foreign_key_x=>1}, {:id => 4, :x_foreign_key_x=>1}]
328
- a = EagerAlbum.eager(:genre).all
329
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
330
- 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))"]
331
- a.first.genre.must_equal EagerGenre.load(:id=>3)
332
- DB.sqls.must_equal []
333
- end
334
-
335
- it "should eagerly load a single many_to_many association" do
336
- a = EagerAlbum.eager(:genres).all
337
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
338
- 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))"]
339
- a.first.genres.must_equal [EagerGenre.load(:id=>4)]
340
- DB.sqls.must_equal []
341
- end
342
-
343
- it "should support using a custom :key option when eager loading many_to_one associations" do
344
- EagerAlbum.many_to_one :sband, :clone=>:band, :key=>:band_id3
345
- EagerBand.dataset._fetch = {:id=>6}
346
- a = EagerAlbum.eager(:sband).all
347
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM bands WHERE (bands.id IN (6))']
348
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
349
- a.first.sband.must_equal EagerBand.load(:id=>6)
350
- DB.sqls.must_equal []
351
- end
352
-
353
- it "should support using a custom :primary_key option when eager loading one_to_many associations" do
354
- EagerBand.one_to_many :salbums, :clone=>:albums, :primary_key=>:id3, :eager=>nil, :reciprocal=>nil
355
- EagerBand.dataset._fetch = {:id=>6}
356
- a = EagerBand.eager(:salbums).all
357
- DB.sqls.must_equal ['SELECT * FROM bands', 'SELECT * FROM albums WHERE (albums.band_id IN (2))']
358
- a.must_equal [EagerBand.load(:id => 6)]
359
- a.first.salbums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
360
- DB.sqls.must_equal []
361
- end
362
-
363
- it "should support using a custom :left_primary_key option when eager loading many_to_many associations" do
364
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :left_primary_key=>:band_id3
365
- EagerGenre.dataset._fetch = {:id=>4, :x_foreign_key_x=>6}
366
- a = EagerAlbum.eager(:sgenres).all
367
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
368
- 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))"]
369
- a.first.sgenres.must_equal [EagerGenre.load(:id=>4)]
370
- DB.sqls.must_equal []
371
- end
372
-
373
- it "should support using a custom :left_primary_key option when eager loading one_through_one associations" do
374
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :left_primary_key=>:band_id3
375
- EagerGenre.dataset._fetch = {:id=>4, :x_foreign_key_x=>6}
376
- a = EagerAlbum.eager(:sgenre).all
377
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
378
- 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))"]
379
- a.first.sgenre.must_equal EagerGenre.load(:id=>4)
380
- DB.sqls.must_equal []
381
- end
382
-
383
- it "should handle a :eager_loading_predicate_key option to change the SQL used in the lookup, for many_to_one associations" do
384
- EagerAlbum.many_to_one :sband, :clone=>:band, :eager_loading_predicate_key=>Sequel./(:bands__id, 3), :primary_key_method=>:id3
385
- EagerBand.dataset._fetch = {:id=>6}
386
- a = EagerAlbum.eager(:sband).all
387
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM bands WHERE ((bands.id / 3) IN (2))']
388
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
389
- a.first.sband.must_equal EagerBand.load(:id=>6)
390
- DB.sqls.must_equal []
391
- end
392
-
393
- it "should handle a :eager_loading_predicate_key option to change the SQL used in the lookup, for one_to_many associations" do
394
- EagerBand.one_to_many :salbums, :clone=>:albums, :eager_loading_predicate_key=>Sequel.*(:albums__band_id, 3), :key_method=>:band_id3, :eager=>nil, :reciprocal=>nil
395
- EagerBand.dataset._fetch = {:id=>6}
396
- a = EagerBand.eager(:salbums).all
397
- DB.sqls.must_equal ['SELECT * FROM bands', 'SELECT * FROM albums WHERE ((albums.band_id * 3) IN (6))']
398
- a.must_equal [EagerBand.load(:id => 6)]
399
- a.first.salbums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
400
- DB.sqls.must_equal []
401
- end
402
-
403
- it "should handle a :eager_loading_predicate_key option to change the SQL used in the lookup, for many_to_many associations" do
404
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :eager_loading_predicate_key=>Sequel.*(:ag__album_id, 1)
405
- a = EagerAlbum.eager(:sgenres).all
406
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
407
- 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))"]
408
- a.first.sgenres.must_equal [EagerGenre.load(:id=>4)]
409
- DB.sqls.must_equal []
410
- end
411
-
412
- it "should handle a :eager_loading_predicate_key option to change the SQL used in the lookup, for one_through_one associations" do
413
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :eager_loading_predicate_key=>Sequel.*(:ag__album_id, 1)
414
- a = EagerAlbum.eager(:sgenre).all
415
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
416
- 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))"]
417
- a.first.sgenre.must_equal EagerGenre.load(:id=>4)
418
- DB.sqls.must_equal []
419
- end
420
-
421
- it "should raise an error for an unhandled :eager_loader_key option" do
422
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :eager_loader_key=>1
423
- ds = EagerAlbum.eager(:sgenres)
424
- proc{ds.all}.must_raise(Sequel::Error)
425
- end
426
-
427
- it "should not add entry to key_hash for :eager_loader_key=>nil option" do
428
- eo = nil
429
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :eager_loader_key=>nil, :eager_loader=>proc{|o| eo = o}
430
- ds = EagerAlbum.eager(:sgenres)
431
- ds.all
432
- eo[:key_hash].must_equal({})
433
- eo[:id_map].must_equal nil
434
- end
435
-
436
- it "should correctly handle a :select=>[] option to many_to_many" do
437
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :select=>[]
438
- EagerAlbum.eager(:sgenres).all
439
- 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))"]
440
- end
441
-
442
- it "should correctly handle a :select=>[] option to one_through_one" do
443
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :select=>[]
444
- EagerAlbum.eager(:sgenre).all
445
- 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))"]
446
- end
447
-
448
- it "should correctly handle an aliased join table in many_to_many" do
449
- EagerAlbum.many_to_many :sgenres, :clone=>:genres, :join_table=>:ag___ga
450
- EagerAlbum.eager(:sgenres).all
451
- 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))"]
452
- end
453
-
454
- it "should correctly handle an aliased join table in one_through_one" do
455
- EagerAlbum.one_through_one :sgenre, :clone=>:genre, :join_table=>:ag___ga
456
- EagerAlbum.eager(:sgenre).all
457
- 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))"]
458
- end
459
-
460
- it "should eagerly load multiple associations in a single call" do
461
- a = EagerAlbum.eager(:genres, :tracks, :band).all
462
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
463
- sqls = DB.sqls
464
- sqls.shift.must_equal 'SELECT * FROM albums'
465
- sqls.sort.must_equal ['SELECT * FROM bands WHERE (bands.id IN (2))',
466
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))',
467
- '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))']
468
- a = a.first
469
- a.band.must_equal EagerBand.load(:id=>2)
470
- a.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
471
- a.genres.must_equal [EagerGenre.load(:id => 4)]
472
- DB.sqls.must_equal []
473
- end
474
-
475
- it "should eagerly load multiple associations in separate calls" do
476
- a = EagerAlbum.eager(:genres).eager(:tracks).eager(:band).all
477
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
478
- sqls = DB.sqls
479
- sqls.shift.must_equal 'SELECT * FROM albums'
480
- sqls.sort.must_equal ['SELECT * FROM bands WHERE (bands.id IN (2))',
481
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))',
482
- '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))']
483
- a = a.first
484
- a.band.must_equal EagerBand.load(:id=>2)
485
- a.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
486
- a.genres.must_equal [EagerGenre.load(:id => 4)]
487
- DB.sqls.must_equal []
488
- end
489
-
490
- it "should allow cascading of eager loading for associations of associated models" do
491
- a = EagerTrack.eager(:album=>{:band=>:members}).all
492
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
493
- DB.sqls.must_equal ['SELECT * FROM tracks',
494
- 'SELECT * FROM albums WHERE (albums.id IN (1))',
495
- 'SELECT * FROM bands WHERE (bands.id IN (2))',
496
- "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))"]
497
- a = a.first
498
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
499
- a.album.band.must_equal EagerBand.load(:id => 2)
500
- a.album.band.members.must_equal [EagerBandMember.load(:id => 5)]
501
- DB.sqls.must_equal []
502
- end
503
-
504
- it "should cascade eager loading when using a UNION strategy for eager loading limited associations" do
505
- EagerTrack.many_to_one :album2, :clone=>:album
506
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:a
507
- a = EagerAlbum.eager(:track=>:album2).all
508
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
509
- 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))']
510
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
511
- a.first.track.album2.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
512
- DB.sqls.must_equal []
513
-
514
- a = EagerAlbum.eager(:track=>[:album2]).all
515
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
516
- 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))']
517
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
518
- a.first.track.album2.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
519
- DB.sqls.must_equal []
520
-
521
- a = EagerAlbum.eager(:track=>{:album2=>:track}).all
522
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
523
- 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']
524
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
525
- a.first.track.album2.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
526
- a.first.track.album2.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
527
- DB.sqls.must_equal []
528
- end
529
-
530
- it "should call post_load when eager loading limited associations" do
531
- EagerTrack.many_to_one :album2, :clone=>:album
532
- a = []
533
- m = Module.new do
534
- define_method(:post_load) do |objs|
535
- a << 1
536
- super(objs)
537
- end
538
- end
539
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id, :order=>:a, :extend=>m
540
- EagerAlbum.eager(:track).all
541
- a.must_equal [1]
542
- end
543
-
544
- it "should cascade eagerly loading when the :eager association option is used" do
545
- a = EagerBand.eager(:albums).all
546
- a.must_equal [EagerBand.load(:id=>2)]
547
- DB.sqls.must_equal ['SELECT * FROM bands',
548
- 'SELECT * FROM albums WHERE (albums.band_id IN (2))',
549
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
550
- a.first.albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
551
- a.first.albums.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
552
- DB.sqls.must_equal []
553
- end
554
-
555
- it "should respect :eager when lazily loading an association" do
556
- a = EagerBand.all
557
- a.must_equal [EagerBand.load(:id=>2)]
558
- DB.sqls.must_equal ['SELECT * FROM bands']
559
- a = a.first.albums
560
- DB.sqls.must_equal ['SELECT * FROM albums WHERE (albums.band_id = 2)',
561
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
562
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
563
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
564
- DB.sqls.must_equal []
565
- end
566
-
567
- it "should respect :eager with cascaded hash when lazily loading an association" do
568
- EagerBand.one_to_many :albums, :eager=>{:tracks=>:album}, :clone=>:albums
569
- a = EagerBand.all
570
- a.must_equal [EagerBand.load(:id=>2)]
571
- DB.sqls.must_equal ['SELECT * FROM bands']
572
- a = a.first.albums
573
- DB.sqls.must_equal ['SELECT * FROM albums WHERE (albums.band_id = 2)',
574
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))',
575
- 'SELECT * FROM albums WHERE (albums.id IN (1))']
576
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
577
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
578
- a.first.tracks.first.album.must_equal a.first
579
- DB.sqls.must_equal []
580
- end
581
-
582
- it "should cascade eagerly loading when the :eager_graph association option is used" do
583
- EagerAlbum.dataset._fetch = {:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1}
584
- a = EagerBand.eager(:graph_albums).all
585
- a.must_equal [EagerBand.load(:id=>2)]
586
- DB.sqls.must_equal ['SELECT * FROM bands',
587
- '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))']
588
- a.first.graph_albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
589
- a.first.graph_albums.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
590
- DB.sqls.must_equal []
591
- end
592
-
593
- it "should raise an Error when eager loading a many_to_many association with the :eager_graph option" do
594
- proc{EagerBand.eager(:graph_members).all}.must_raise(Sequel::Error)
595
- end
596
-
597
- it "should respect :eager_graph when lazily loading an association" do
598
- a = EagerBand.all
599
- a.must_equal [EagerBand.load(:id=>2)]
600
- DB.sqls.must_equal ['SELECT * FROM bands']
601
- a = a.first
602
- EagerAlbum.dataset._fetch = {:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1}
603
- a.graph_albums
604
- 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)']
605
- a.graph_albums.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
606
- a.graph_albums.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
607
- DB.sqls.must_equal []
608
- end
609
-
610
- it "should respect :eager_graph when lazily loading a many_to_many association" do
611
- ds = EagerBandMember.dataset
612
- def ds.columns() [:id] end
613
- ds._fetch = [{:id=>5, :bands_id=>2, :p_k=>6}, {:id=>5, :bands_id=>3, :p_k=>6}]
614
- a = EagerBand.load(:id=>2)
615
- a.graph_members.must_equal [EagerBandMember.load(:id=>5)]
616
- 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']
617
- a.graph_members.first.bands.must_equal [EagerBand.load(:id=>2, :p_k=>6), EagerBand.load(:id=>3, :p_k=>6)]
618
- DB.sqls.must_equal []
619
- end
620
-
621
- it "should respect :conditions when eagerly loading" do
622
- EagerBandMember.many_to_many :good_bands, :clone=>:bands, :conditions=>{:a=>32}
623
- a = EagerBandMember.eager(:good_bands).all
624
- a.must_equal [EagerBandMember.load(:id => 5)]
625
- 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']
626
- a.first.good_bands.must_equal [EagerBand.load(:id => 2)]
627
- DB.sqls.must_equal []
628
-
629
- EagerBandMember.many_to_many :good_bands, :clone=>:bands, :conditions=>"x = 1"
630
- a = EagerBandMember.eager(:good_bands).all
631
- 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']
632
- end
633
-
634
- it "should respect :order when eagerly loading" do
635
- a = EagerBandMember.eager(:bands).all
636
- a.must_equal [EagerBandMember.load(:id => 5)]
637
- 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']
638
- a.first.bands.must_equal [EagerBand.load(:id => 2)]
639
- DB.sqls.must_equal []
640
- end
641
-
642
- it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
643
- a = EagerAlbum.eager(:tracks).all
644
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
645
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
646
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
647
- a.first.tracks.first.album.must_equal a.first
648
- DB.sqls.must_equal []
649
- end
650
-
651
- it "should cache the negative lookup when eagerly loading a many_to_one association" do
652
- a = EagerAlbum.eager(:band).filter(:id=>101).all
653
- a.must_equal [EagerAlbum.load(:id => 101, :band_id => 101)]
654
- DB.sqls.must_equal ['SELECT * FROM albums WHERE (id = 101)', 'SELECT * FROM bands WHERE (bands.id IN (101))']
655
- a.first.associations.fetch(:band, 2).must_equal nil
656
- a.first.band.must_equal nil
657
- DB.sqls.must_equal []
658
- end
659
-
660
- it "should cache the negative lookup when eagerly loading a *_to_many associations" do
661
- a = EagerBand.eager(:albums).filter('id > 100').all
662
- a.must_equal [EagerBand.load(:id => 101), EagerBand.load(:id =>102)]
663
- sqls = DB.sqls
664
- ['SELECT * FROM albums WHERE (albums.band_id IN (101, 102))', 'SELECT * FROM albums WHERE (albums.band_id IN (102, 101))'].must_include(sqls.delete_at(1))
665
- sqls.must_equal ['SELECT * FROM bands WHERE (id > 100)', "SELECT * FROM tracks WHERE (tracks.album_id IN (101))"]
666
- a.map{|b| b.associations[:albums]}.must_equal [[EagerAlbum.load({:band_id=>101, :id=>101})], []]
667
- DB.sqls.must_equal []
668
- end
669
-
670
- it "should use the association's block when eager loading by default" do
671
- EagerAlbum.eager(:good_tracks).all
672
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE ((name = 'Good') AND (tracks.album_id IN (1)))"]
673
- end
674
-
675
- it "should use the eager_block option when eager loading if given" do
676
- EagerBand.eager(:good_albums).all
677
- DB.sqls.must_equal ['SELECT * FROM bands', "SELECT * FROM albums WHERE ((name = 'good') AND (albums.band_id IN (2)))"]
678
- EagerBand.eager(:good_albums=>:good_tracks).all
679
- 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)))"]
680
- end
681
-
682
- it "should raise an error when attempting to eagerly load an association with the :allow_eager option set to false" do
683
- proc{EagerBand.eager(:self_titled_albums).all}.must_raise(Sequel::Error)
684
- proc{EagerBand.eager(:albums_by_name).all}.must_raise(Sequel::Error)
685
- end
686
-
687
- it "should respect the association's :select option" do
688
- EagerAlbum.eager(:band_name).all
689
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT id, name FROM bands WHERE (bands.id IN (2))"]
690
- EagerAlbum.eager(:track_names).all
691
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT id, name FROM tracks WHERE (tracks.album_id IN (1))"]
692
- EagerAlbum.eager(:genre_names).all
693
- 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))"]
694
- end
695
-
696
- it "should respect many_to_one association's :qualify option" do
697
- EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :qualify=>false, :key=>:band_id
698
- EagerBand.dataset._fetch = {:id=>2}
699
- as = EagerAlbum.eager(:special_band).all
700
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM bands WHERE (id IN (2))"]
701
- as.map{|a| a.special_band}.must_equal [EagerBand.load(:id=>2)]
702
- DB.sqls.must_equal []
703
- end
704
-
705
- it "should respect the association's :primary_key option" do
706
- EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :primary_key=>:p_k, :key=>:band_id
707
- EagerBand.dataset._fetch = {:p_k=>2, :id=>1}
708
- as = EagerAlbum.eager(:special_band).all
709
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM bands WHERE (bands.p_k IN (2))"]
710
- as.length.must_equal 1
711
- as.first.special_band.must_equal EagerBand.load(:p_k=>2, :id=>1)
712
-
713
- EagerAlbum.one_to_many :special_tracks, :class=>:EagerTrack, :primary_key=>:band_id, :key=>:album_id, :reciprocal=>nil
714
- EagerTrack.dataset._fetch = {:album_id=>2, :id=>1}
715
- as = EagerAlbum.eager(:special_tracks).all
716
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (2))"]
717
- as.length.must_equal 1
718
- as.first.special_tracks.must_equal [EagerTrack.load(:album_id=>2, :id=>1)]
719
- end
720
-
721
- it "should respect the many_to_one association's composite keys" do
722
- EagerAlbum.many_to_one :special_band, :class=>:EagerBand, :primary_key=>[:id, :p_k], :key=>[:band_id, :id]
723
- EagerBand.dataset._fetch = {:p_k=>1, :id=>2}
724
- as = EagerAlbum.eager(:special_band).all
725
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM bands WHERE ((bands.id, bands.p_k) IN ((2, 1)))"]
726
- as.length.must_equal 1
727
- as.first.special_band.must_equal EagerBand.load(:p_k=>1, :id=>2)
728
- end
729
-
730
- it "should respect the one_to_many association's composite keys" do
731
- EagerAlbum.one_to_many :special_tracks, :class=>:EagerTrack, :primary_key=>[:band_id, :id], :key=>[:id, :album_id]
732
- EagerTrack.dataset._fetch = {:album_id=>1, :id=>2}
733
- as = EagerAlbum.eager(:special_tracks).all
734
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE ((tracks.id, tracks.album_id) IN ((2, 1)))"]
735
- as.length.must_equal 1
736
- as.first.special_tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>2)]
737
- end
738
-
739
- it "should respect many_to_many association's composite keys" do
740
- 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
741
- EagerGenre.dataset._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}]
742
- as = EagerAlbum.eager(:special_genres).all
743
- 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)))"]
744
- as.length.must_equal 1
745
- as.first.special_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
746
- end
747
-
748
- it "should respect one_through_one association's composite keys" do
749
- 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
750
- EagerGenre.dataset._fetch = [{:x_foreign_key_0_x=>2, :x_foreign_key_1_x=>1, :id=>5}]
751
- as = EagerAlbum.eager(:special_genre).all
752
- 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)))"]
753
- as.length.must_equal 1
754
- as.first.special_genre.must_equal EagerGenre.load(:id=>5)
755
- end
756
-
757
- it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
758
- 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
759
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}]
760
- as = EagerAlbum.eager(:special_genres).all
761
- 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))"]
762
- as.length.must_equal 1
763
- as.first.special_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
764
- end
765
-
766
- it "should respect one_through_one association's :left_primary_key and :right_primary_key options" do
767
- 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
768
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}]
769
- as = EagerAlbum.eager(:special_genre).all
770
- 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))"]
771
- as.length.must_equal 1
772
- as.first.special_genre.must_equal EagerGenre.load(:id=>5)
773
- end
774
-
775
- it "should respect the :limit option on a one_to_many association using the :ruby strategy" do
776
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>2, :eager_limit_strategy=>:ruby
777
- EagerTrack.dataset._fetch = [{:album_id=>1, :id=>2}, {:album_id=>1, :id=>3}, {:album_id=>1, :id=>4}]
778
- as = EagerAlbum.eager(:first_two_tracks).all
779
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (1))"]
780
- as.length.must_equal 1
781
- as.first.first_two_tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>2), EagerTrack.load(:album_id=>1, :id=>3)]
782
-
783
- DB.reset
784
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>[1,1], :eager_limit_strategy=>:ruby
785
- as = EagerAlbum.eager(:first_two_tracks).all
786
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (1))"]
787
- as.length.must_equal 1
788
- as.first.first_two_tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>3)]
789
-
790
- DB.reset
791
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>[nil,1], :eager_limit_strategy=>:ruby
792
- as = EagerAlbum.eager(:first_two_tracks).all
793
- DB.sqls.must_equal ['SELECT * FROM albums', "SELECT * FROM tracks WHERE (tracks.album_id IN (1))"]
794
- as.length.must_equal 1
795
- as.first.first_two_tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>3), EagerTrack.load(:album_id=>1, :id=>4)]
796
- end
797
-
798
- it "should respect the :limit option on a one_to_many association" do
799
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>2
800
- a = EagerAlbum.eager(:tracks).all
801
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
802
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY name LIMIT 2) AS t1']
803
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
804
- DB.sqls.must_equal []
805
-
806
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>[2, 1]
807
- a = EagerAlbum.eager(:tracks).all
808
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
809
- 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']
810
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
811
- DB.sqls.must_equal []
812
-
813
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>[nil, 1]
814
- a = EagerAlbum.eager(:tracks).all
815
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
816
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM (SELECT * FROM tracks WHERE (1 = tracks.album_id) ORDER BY name OFFSET 1) AS t1']
817
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
818
- DB.sqls.must_equal []
819
- end
820
-
821
- it "should respect the :limit option on a one_to_many association with an association block" do
822
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>2 do |ds| ds.where(:a=>1) end
823
- a = EagerAlbum.eager(:tracks).all
824
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
825
- 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']
826
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
827
- DB.sqls.must_equal []
828
- end
829
-
830
- it "should respect the :limit option on a one_to_many association using the :window_function strategy" do
831
- def (EagerTrack.dataset).supports_window_functions?() true end
832
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>2, :eager_limit_strategy=>:window_function
833
- a = EagerAlbum.eager(:tracks).all
834
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
835
- 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)']
836
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
837
- DB.sqls.must_equal []
838
-
839
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>[2, 1], :eager_limit_strategy=>:window_function
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 *, 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))']
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=>[nil, 1], :eager_limit_strategy=>:window_function
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 *, 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)']
850
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
851
- DB.sqls.must_equal []
852
- end
853
-
854
- it "should use a ruby strategy for limit if :eager_graph option is used" do
855
- EagerTrack.many_to_one :album2, :clone=>:album
856
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>2, :eager_graph=>:album2
857
- EagerTrack.dataset._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}]
858
- as = EagerAlbum.eager(:first_two_tracks).all
859
- 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))"]
860
- as.length.must_equal 1
861
- tracks = as.first.first_two_tracks
862
- tracks.must_equal [EagerTrack.load(:album_id=>1, :id=>2), EagerTrack.load(:album_id=>1, :id=>3)]
863
- tracks.first.album2.must_equal EagerAlbum.load(:id=>1, :band_id=>5)
864
- tracks.last.album2.must_equal EagerAlbum.load(:id=>1, :band_id=>5)
865
- end
866
-
867
- it "should not use a union strategy for limit by default if providing a per-eager load callback" do
868
- def (EagerTrack.dataset).supports_window_functions?() true end
869
- EagerAlbum.one_to_many :tracks, :class=>'EagerTrack', :key=>:album_id, :order=>:name, :limit=>2
870
- a = EagerAlbum.eager(:tracks=>proc{|ds| ds.where(:id=>3)}).all
871
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
872
- 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)']
873
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
874
- DB.sqls.must_equal []
875
- end
876
-
877
- it "should respect the limit option on a many_to_many association using the :ruby strategy" do
878
- 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
879
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}, {:x_foreign_key_x=>2, :id=>7}]
880
- as = EagerAlbum.eager(:first_two_genres).all
881
- 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))"]
882
- as.length.must_equal 1
883
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
884
-
885
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}, {:x_foreign_key_x=>2, :id=>7}]
886
- 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
887
- as = EagerAlbum.eager(:first_two_genres).all
888
- 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))"]
889
- as.length.must_equal 1
890
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>6)]
891
-
892
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}, {:x_foreign_key_x=>2, :id=>7}]
893
- 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
894
- as = EagerAlbum.eager(:first_two_genres).all
895
- 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))"]
896
- as.length.must_equal 1
897
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>6), EagerGenre.load(:id=>7)]
898
- end
899
-
900
- it "should respect the limit option on a many_to_many association" do
901
- def (EagerGenre.dataset).supports_window_functions?() true end
902
- 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
903
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}]
904
- as = EagerAlbum.eager(:first_two_genres).all
905
- 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"]
906
- as.length.must_equal 1
907
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
908
-
909
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}]
910
- 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
911
- as = EagerAlbum.eager(:first_two_genres).all
912
- 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"]
913
- as.length.must_equal 1
914
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5)]
915
-
916
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}]
917
- 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
918
- as = EagerAlbum.eager(:first_two_genres).all
919
- 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"]
920
- as.length.must_equal 1
921
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
922
- end
923
-
924
- it "should respect the limit option on a many_to_many association using the :window_function strategy" do
925
- def (EagerGenre.dataset).supports_window_functions?() true end
926
- 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
927
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}]
928
- as = EagerAlbum.eager(:first_two_genres).all
929
- 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)"]
930
- as.length.must_equal 1
931
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
932
-
933
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}]
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=>[1, 1], :order=>:name, :eager_limit_strategy=>:window_function
935
- as = EagerAlbum.eager(:first_two_genres).all
936
- 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))"]
937
- as.length.must_equal 1
938
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5)]
939
-
940
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>2, :id=>5}, {:x_foreign_key_x=>2, :id=>6}]
941
- 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
942
- as = EagerAlbum.eager(:first_two_genres).all
943
- 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)"]
944
- as.length.must_equal 1
945
- as.first.first_two_genres.must_equal [EagerGenre.load(:id=>5), EagerGenre.load(:id=>6)]
946
- end
947
-
948
- it "should use the :eager_loader association option when eager loading" do
949
- EagerAlbum.many_to_one :special_band, :key=>:band_id, :eager_loader=>(proc do |eo|
950
- item = EagerBand.filter(:album_id=>eo[:rows].collect{|r| [r.pk, r.pk*2]}.flatten).order(:name).first
951
- eo[:rows].each{|r| r.associations[:special_band] = item}
952
- end)
953
- EagerAlbum.one_to_many :special_tracks, :eager_loader=>(proc do |eo|
954
- items = EagerTrack.filter(:album_id=>eo[:rows].collect{|r| [r.pk, r.pk*2]}.flatten).all
955
- eo[:rows].each{|r| r.associations[:special_tracks] = items}
956
- end)
957
- EagerAlbum.many_to_many :special_genres, :class=>:EagerGenre, :eager_loader=>(proc do |eo|
958
- items = EagerGenre.inner_join(:ag, [:genre_id]).filter(:album_id=>eo[:rows].collect{|r| r.pk}).all
959
- eo[:rows].each{|r| r.associations[:special_genres] = items}
960
- end)
961
- a = EagerAlbum.eager(:special_genres, :special_tracks, :special_band).all
962
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
963
- sqls = DB.sqls
964
- sqls.shift.must_equal 'SELECT * FROM albums'
965
- sqls.sort.must_equal ['SELECT * FROM bands WHERE (album_id IN (1, 2)) ORDER BY name LIMIT 1',
966
- 'SELECT * FROM genres INNER JOIN ag USING (genre_id) WHERE (album_id IN (1))',
967
- 'SELECT * FROM tracks WHERE (album_id IN (1, 2))']
968
- a = a.first
969
- a.special_band.must_equal EagerBand.load(:id => 2)
970
- a.special_tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
971
- a.special_genres.must_equal [EagerGenre.load(:id => 4)]
972
- DB.sqls.must_equal []
973
- end
974
-
975
- it "should respect :after_load callbacks on associations when eager loading" do
976
- EagerAlbum.many_to_one :al_band, :class=>'EagerBand', :key=>:band_id, :after_load=>proc{|o, a| a.id *=2}
977
- EagerAlbum.one_to_many :al_tracks, :class=>'EagerTrack', :key=>:album_id, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
978
- 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}}
979
- a = EagerAlbum.eager(:al_band, :al_tracks, :al_genres).all.first
980
- a.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
981
- a.al_band.must_equal EagerBand.load(:id=>4)
982
- a.al_tracks.must_equal [EagerTrack.load(:id=>6, :album_id=>1)]
983
- a.al_genres.must_equal [EagerGenre.load(:id=>8)]
984
- end
985
-
986
- it "should respect :uniq option when eagerly loading many_to_many associations" do
987
- EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :uniq=>true
988
- EagerGenre.dataset._fetch = [{:x_foreign_key_x=>1, :id=>8}, {:x_foreign_key_x=>1, :id=>8}]
989
- a = EagerAlbum.eager(:al_genres).all.first
990
- 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))"]
991
- a.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
992
- a.al_genres.must_equal [EagerGenre.load(:id=>8)]
993
- end
994
-
995
- it "should respect :distinct option when eagerly loading many_to_many associations" do
996
- EagerAlbum.many_to_many :al_genres, :class=>'EagerGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :distinct=>true
997
- a = EagerAlbum.eager(:al_genres).all.first
998
- 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))"]
999
- a.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1000
- a.al_genres.must_equal [EagerGenre.load(:id=>4)]
1001
- end
1002
-
1003
- it "should eagerly load a many_to_one association with custom eager block" do
1004
- a = EagerAlbum.eager(:band => proc {|ds| ds.select(:id, :name)}).all
1005
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1006
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT id, name FROM bands WHERE (bands.id IN (2))']
1007
- a.first.band.must_equal EagerBand.load(:id => 2)
1008
- DB.sqls.must_equal []
1009
- end
1010
-
1011
- it "should eagerly load a one_to_one association with custom eager block" do
1012
- EagerAlbum.one_to_one :track, :class=>'EagerTrack', :key=>:album_id
1013
- a = EagerAlbum.eager(:track => proc {|ds| ds.select(:id)}).all
1014
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1015
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT id FROM tracks WHERE (tracks.album_id IN (1))']
1016
- a.first.track.must_equal EagerTrack.load(:id => 3, :album_id=>1)
1017
- DB.sqls.must_equal []
1018
- end
1019
-
1020
- it "should eagerly load a one_to_many association with custom eager block" do
1021
- a = EagerAlbum.eager(:tracks => proc {|ds| ds.select(:id)}).all
1022
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1023
- DB.sqls.must_equal ['SELECT * FROM albums', 'SELECT id FROM tracks WHERE (tracks.album_id IN (1))']
1024
- a.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
1025
- DB.sqls.must_equal []
1026
- end
1027
-
1028
- it "should eagerly load a many_to_many association with custom eager block" do
1029
- a = EagerAlbum.eager(:genres => proc {|ds| ds.select(:name)}).all
1030
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1031
- 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))"]
1032
- a.first.genres.must_equal [EagerGenre.load(:id => 4)]
1033
- DB.sqls.must_equal []
1034
- end
1035
-
1036
- it "should eagerly load a one_through_one association with custom eager block" do
1037
- a = EagerAlbum.eager(:genre => proc {|ds| ds.select(:name)}).all
1038
- a.must_equal [EagerAlbum.load(:id => 1, :band_id => 2)]
1039
- 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))"]
1040
- a.first.genre.must_equal EagerGenre.load(:id => 4)
1041
- DB.sqls.must_equal []
1042
- end
1043
-
1044
- it "should allow cascading of eager loading within a custom eager block" do
1045
- a = EagerTrack.eager(:album => proc {|ds| ds.eager(:band => :members)}).all
1046
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1047
- DB.sqls.must_equal ['SELECT * FROM tracks',
1048
- 'SELECT * FROM albums WHERE (albums.id IN (1))',
1049
- 'SELECT * FROM bands WHERE (bands.id IN (2))',
1050
- "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))"]
1051
- a = a.first
1052
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1053
- a.album.band.must_equal EagerBand.load(:id => 2)
1054
- a.album.band.members.must_equal [EagerBandMember.load(:id => 5)]
1055
- DB.sqls.must_equal []
1056
- end
1057
-
1058
- it "should allow cascading of eager loading with custom callback with hash value" do
1059
- a = EagerTrack.eager(:album=>{proc{|ds| ds.select(:id, :band_id)}=>{:band => :members}}).all
1060
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1061
- DB.sqls.must_equal ['SELECT * FROM tracks',
1062
- 'SELECT id, band_id FROM albums WHERE (albums.id IN (1))',
1063
- 'SELECT * FROM bands WHERE (bands.id IN (2))',
1064
- "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))"]
1065
- a = a.first
1066
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1067
- a.album.band.must_equal EagerBand.load(:id => 2)
1068
- a.album.band.members.must_equal [EagerBandMember.load(:id => 5)]
1069
- DB.sqls.must_equal []
1070
- end
1071
-
1072
- it "should allow cascading of eager loading with custom callback with symbol value" do
1073
- a = EagerTrack.eager(:album=>{proc{|ds| ds.select(:id, :band_id)}=>:band}).all
1074
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1075
- DB.sqls.must_equal ['SELECT * FROM tracks',
1076
- 'SELECT id, band_id FROM albums WHERE (albums.id IN (1))',
1077
- 'SELECT * FROM bands WHERE (bands.id IN (2))']
1078
- a = a.first
1079
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1080
- a.album.band.must_equal EagerBand.load(:id => 2)
1081
- DB.sqls.must_equal []
1082
- end
1083
-
1084
- it "should allow cascading of eager loading with custom callback with symbol value when association has a limit" do
1085
- EagerAlbum.dataset._fetch = (1..11).map{|i| {:band_id=>2, :id=>i}}
1086
- EagerTrack.dataset._fetch = [{:id=>3, :album_id=>1}]
1087
- a = EagerBand.eager(:top_10_albums=>{proc{|ds| ds.select(:id, :name)}=>:tracks}).all
1088
- a.must_equal [EagerBand.load(:id => 2)]
1089
- sqls = DB.sqls
1090
- sqls.pop.must_match(/SELECT \* FROM tracks WHERE \(tracks.album_id IN \((\d+, ){10}\d+\)\)/)
1091
- sqls.must_equal ['SELECT * FROM bands', 'SELECT id, name FROM albums WHERE (albums.band_id IN (2))']
1092
- a = a.first
1093
- a.top_10_albums.must_equal((1..10).map{|i| EagerAlbum.load(:band_id=>2, :id=>i)})
1094
- a.top_10_albums.map{|x| x.tracks}.must_equal [[EagerTrack.load(:id => 3, :album_id=>1)]] + ([[]] * 9)
1095
- DB.sqls.must_equal []
1096
- end
1097
-
1098
- 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
1099
- def (EagerAlbum.dataset).supports_window_functions?() true end
1100
- EagerAlbum.dataset._fetch = {:band_id=>2, :id=>1}
1101
- EagerTrack.dataset._fetch = [{:id=>3, :album_id=>1}]
1102
- a = EagerBand.eager(:top_10_albums=>{proc{|ds| ds.select(:id, :name)}=>:tracks}).all
1103
- a.must_equal [EagerBand.load(:id => 2)]
1104
- DB.sqls.must_equal ['SELECT * FROM bands',
1105
- '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)',
1106
- 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
1107
- a = a.first
1108
- a.top_10_albums.must_equal [EagerAlbum.load(:band_id=>2, :id=>1)]
1109
- a.top_10_albums.first.tracks.must_equal [EagerTrack.load(:id => 3, :album_id=>1)]
1110
- DB.sqls.must_equal []
1111
- end
1112
-
1113
- it "should allow cascading of eager loading with custom callback with array value" do
1114
- a = EagerTrack.eager(:album=>{proc{|ds| ds.select(:id, :band_id)}=>[:band, :band_name]}).all
1115
- a.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1116
- sqls = DB.sqls
1117
- sqls.slice!(0..1).must_equal ['SELECT * FROM tracks',
1118
- 'SELECT id, band_id FROM albums WHERE (albums.id IN (1))']
1119
- sqls.sort.must_equal ['SELECT * FROM bands WHERE (bands.id IN (2))',
1120
- 'SELECT id, name FROM bands WHERE (bands.id IN (2))']
1121
- a = a.first
1122
- a.album.must_equal EagerAlbum.load(:id => 1, :band_id => 2)
1123
- a.album.band.must_equal EagerBand.load(:id => 2)
1124
- a.album.band_name.must_equal EagerBand.load(:id => 2)
1125
- DB.sqls.must_equal []
1126
- end
1127
-
1128
- it "should call both association and custom eager blocks" do
1129
- EagerBand.eager(:good_albums => proc {|ds| ds.select(:name)}).all
1130
- DB.sqls.must_equal ['SELECT * FROM bands', "SELECT name FROM albums WHERE ((name = 'good') AND (albums.band_id IN (2)))"]
1131
- end
1132
-
1133
- it "should respect an :eager_limit option passed in a custom callback" do
1134
- # Should default to a window function on its own.
1135
- def (EagerTrack.dataset).supports_window_functions?() true end
1136
- a = EagerAlbum.eager(:tracks=> proc{|ds| ds.clone(:eager_limit=>5)}).all
1137
- a.must_equal [EagerAlbum.load(:id => 1, :band_id=> 2)]
1138
- sqls = DB.sqls
1139
- 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)']
1140
- a = a.first
1141
- a.tracks.must_equal [EagerTrack.load(:id => 3, :album_id => 1)]
1142
- DB.sqls.must_equal []
1143
- end
1144
-
1145
- it "should respect an :eager_limit option that includes an offset" do
1146
- def (EagerTrack.dataset).supports_window_functions?() true end
1147
- EagerAlbum.eager(:tracks=> proc{|ds| ds.clone(:eager_limit=>[5, 5])}).all
1148
- 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))']
1149
- end
1150
-
1151
- it "should have an :eager_limit option passed in a custom callback override a :limit defined in the association" do
1152
- def (EagerTrack.dataset).supports_window_functions?() true end
1153
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>2
1154
- EagerAlbum.eager(:first_two_tracks=> proc{|ds| ds.clone(:eager_limit=>5)}).all
1155
- 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)']
1156
- end
1157
-
1158
- it "should respect an :eager_limit_strategy option passed in a custom callback" do
1159
- def (EagerTrack.dataset).supports_window_functions?() true end
1160
- EagerTrack.dataset._fetch = (1..4).map{|i| {:album_id=>1, :id=>i}}
1161
- a = EagerAlbum.eager(:tracks=> proc{|ds| ds.clone(:eager_limit=>2, :eager_limit_strategy=>:ruby)}).all
1162
- a.must_equal [EagerAlbum.load(:id => 1, :band_id=> 2)]
1163
- sqls = DB.sqls
1164
- sqls.must_equal ['SELECT * FROM albums', 'SELECT * FROM tracks WHERE (tracks.album_id IN (1))']
1165
- a = a.first
1166
- a.tracks.must_equal [EagerTrack.load(:id => 1, :album_id => 1), EagerTrack.load(:id => 2, :album_id => 1)]
1167
- DB.sqls.must_equal []
1168
- end
1169
-
1170
- it "should have an :eager_limit_strategy option passed in a custom callback override a :eager_limit_strategy defined in the association" do
1171
- def (EagerTrack.dataset).supports_window_functions?() true end
1172
- EagerAlbum.one_to_many :first_two_tracks, :class=>:EagerTrack, :key=>:album_id, :limit=>2, :eager_limit_strategy=>:ruby
1173
- EagerAlbum.eager(:first_two_tracks=> proc{|ds| ds.clone(:eager_limit_strategy=>:window_function)}).all
1174
- 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)']
1175
- end
1176
- end
1177
-
1178
- describe Sequel::Model, "#eager_graph" do
1179
- before(:all) do
1180
- class ::GraphAlbum < Sequel::Model(:albums)
1181
- dataset.opts[:from] = [:albums]
1182
- columns :id, :band_id
1183
- many_to_one :band, :class=>'GraphBand', :key=>:band_id
1184
- one_to_many :tracks, :class=>'GraphTrack', :key=>:album_id
1185
- one_to_one :track, :class=>'GraphTrack', :key=>:album_id
1186
- many_to_many :genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
1187
- one_through_one :genre, :clone=>:genres
1188
- many_to_one :previous_album, :class=>'GraphAlbum'
1189
- end
1190
-
1191
- class ::GraphBand < Sequel::Model(:bands)
1192
- dataset.opts[:from] = [:bands]
1193
- columns :id, :vocalist_id
1194
- many_to_one :vocalist, :class=>'GraphBandMember', :key=>:vocalist_id
1195
- one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id
1196
- many_to_many :members, :class=>'GraphBandMember', :left_key=>:band_id, :right_key=>:member_id, :join_table=>:bm
1197
- many_to_many :genres, :class=>'GraphGenre', :left_key=>:band_id, :right_key=>:genre_id, :join_table=>:bg
1198
- end
1199
-
1200
- class ::GraphTrack < Sequel::Model(:tracks)
1201
- dataset.opts[:from] = [:tracks]
1202
- columns :id, :album_id
1203
- many_to_one :album, :class=>'GraphAlbum', :key=>:album_id
1204
- end
1205
-
1206
- class ::GraphGenre < Sequel::Model(:genres)
1207
- dataset.opts[:from] = [:genres]
1208
- columns :id
1209
- many_to_many :albums, :class=>'GraphAlbum', :left_key=>:genre_id, :right_key=>:album_id, :join_table=>:ag
1210
- end
1211
-
1212
- class ::GraphBandMember < Sequel::Model(:members)
1213
- dataset.opts[:from] = [:members]
1214
- columns :id
1215
- many_to_many :bands, :class=>'GraphBand', :left_key=>:member_id, :right_key=>:band_id, :join_table=>:bm
1216
- end
1217
- end
1218
- before do
1219
- DB.sqls
1220
- end
1221
- after(:all) do
1222
- [:GraphAlbum, :GraphBand, :GraphTrack, :GraphGenre, :GraphBandMember].each{|x| Object.send(:remove_const, x)}
1223
- end
1224
-
1225
- it "should raise an error if called without a symbol or hash" do
1226
- proc{GraphAlbum.eager_graph(Object.new)}.must_raise(Sequel::Error)
1227
- end
1228
-
1229
- it "should work correctly with select_map" do
1230
- ds = GraphAlbum.eager_graph(:band)
1231
- ds._fetch = [{:id=>1}, {:id=>2}]
1232
- ds.select_map(:albums__id).must_equal [1, 2]
1233
- DB.sqls.must_equal ['SELECT albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)']
1234
- ds._fetch = [{:id=>1}, {:id=>2}]
1235
- ds.select_map([:albums__id, :albums__id]).must_equal [[1, 1], [2, 2]]
1236
- DB.sqls.must_equal ['SELECT albums.id, albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id)']
1237
- end
1238
-
1239
- it "should work correctly with single_value" do
1240
- ds = GraphAlbum.eager_graph(:band).select(:albums__id)
1241
- ds._fetch = [{:id=>1}]
1242
- ds.single_value.must_equal 1
1243
- DB.sqls.must_equal ['SELECT albums.id FROM albums LEFT OUTER JOIN bands AS band ON (band.id = albums.band_id) LIMIT 1']
1244
- end
1245
-
1246
- it "should not split results and assign associations if ungraphed is called" do
1247
- ds = GraphAlbum.eager_graph(:band).ungraphed
1248
- 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)'
1249
- ds._fetch = {:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3}
1250
- ds.all.must_equal [GraphAlbum.load(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3)]
1251
- end
1252
-
1253
- it "should not modify existing dataset" do
1254
- ds1 = GraphAlbum.dataset
1255
- ds2 = ds1.eager_graph(:band)
1256
- ds1.eager_graph(:band)
1257
- ds2.eager_graph(:tracks)
1258
- ds2.eager_graph(:tracks)
1259
- end
1260
-
1261
- it "should allow manually selecting the alias base per call via an AliasedExpression" do
1262
- ds = GraphAlbum.eager_graph(Sequel.as(:band, :b))
1263
- 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)'
1264
- ds._fetch = {:id=>1, :band_id=>2, :b_id=>2, :vocalist_id=>3}
1265
- a = ds.all
1266
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1267
- a.first.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1268
- end
1269
-
1270
- it "should handle multiple associations using the same alias base" do
1271
- ds = GraphAlbum.eager_graph(Sequel.as(:genres, :b), Sequel.as(:tracks, :b), Sequel.as(:band, :b))
1272
- 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)'
1273
- ds._fetch = {:id=>1, :band_id=>2, :b_id=>4, :b_0_id=>3, :album_id=>1, :b_1_id=>2, :vocalist_id=>6}
1274
- a = ds.all
1275
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1276
- a = a.first
1277
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1278
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1279
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1280
-
1281
- ds = GraphTrack.eager_graph(Sequel.as(:album, :b)=>{Sequel.as(:band, :b)=>Sequel.as(:members, :b)})
1282
- 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)'
1283
- ds._fetch = {:id=>3, :album_id=>1, :b_id=>1, :band_id=>2, :b_1_id=>5, :b_0_id=>2, :vocalist_id=>6}
1284
- a = ds.all
1285
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
1286
- a = a.first
1287
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
1288
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1289
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
1290
- end
1291
-
1292
- it "should set up correct inner joins when using association_join" do
1293
- GraphAlbum.association_join(:band).sql.must_equal 'SELECT * FROM albums INNER JOIN bands AS band ON (band.id = albums.band_id)'
1294
- GraphAlbum.association_join(:track).sql.must_equal 'SELECT * FROM albums INNER JOIN tracks AS track ON (track.album_id = albums.id)'
1295
- GraphAlbum.association_join(:tracks).sql.must_equal 'SELECT * FROM albums INNER JOIN tracks ON (tracks.album_id = albums.id)'
1296
- 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)'
1297
- 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)'
1298
- end
1299
-
1300
- it "should handle custom selects when using association_join" do
1301
- 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)'
1302
- 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)'
1303
- GraphAlbum.select{a(b)}.association_join(:tracks).sql.must_equal 'SELECT a(b) FROM albums INNER JOIN tracks ON (tracks.album_id = albums.id)'
1304
- 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)'
1305
- 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)'
1306
- end
1307
-
1308
- it "should set up correct join types when using association_*_join" do
1309
- GraphAlbum.association_inner_join(:band).sql.must_equal 'SELECT * FROM albums INNER JOIN bands AS band ON (band.id = albums.band_id)'
1310
- GraphAlbum.association_left_join(:track).sql.must_equal 'SELECT * FROM albums LEFT JOIN tracks AS track ON (track.album_id = albums.id)'
1311
- GraphAlbum.association_right_join(:tracks).sql.must_equal 'SELECT * FROM albums RIGHT JOIN tracks ON (tracks.album_id = albums.id)'
1312
- 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)'
1313
- end
1314
-
1315
- it "should eagerly load a single many_to_one association" do
1316
- ds = GraphAlbum.eager_graph(:band)
1317
- 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)'
1318
- ds._fetch = {:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3}
1319
- a = ds.all
1320
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1321
- a.first.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1322
- end
1323
-
1324
- it "should eagerly load a single many_to_one association with the same name as a column" do
1325
- GraphAlbum.def_column_alias(:band_id_id, :band_id)
1326
- GraphAlbum.many_to_one :band_id, :key_column=>:band_id, :class=>GraphBand
1327
- ds = GraphAlbum.eager_graph(:band_id)
1328
- 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)'
1329
- ds._fetch = {:id=>1, :band_id=>2, :band_id_id=>2, :vocalist_id=>3}
1330
- a = ds.all
1331
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1332
- a.first.band_id.must_equal GraphBand.load(:id => 2, :vocalist_id=>3)
1333
- end
1334
-
1335
- it "should support :join_type eager_graph option one_to_one association" do
1336
- ds = GraphAlbum.eager_graph_with_options(:track, :join_type=>:inner)
1337
- 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)'
1338
- ds._fetch = {:id=>1, :band_id=>2, :track_id=>3, :album_id=>1}
1339
- a = ds.all
1340
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1341
- a.first.track.must_equal GraphTrack.load(:id => 3, :album_id=>1)
1342
- end
1343
-
1344
- it "should eagerly load a single one_to_one association" do
1345
- ds = GraphAlbum.eager_graph(:track)
1346
- 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)'
1347
- ds._fetch = {:id=>1, :band_id=>2, :track_id=>3, :album_id=>1}
1348
- a = ds.all
1349
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1350
- a.first.track.must_equal GraphTrack.load(:id => 3, :album_id=>1)
1351
- end
1352
-
1353
- it "should eagerly graph a single one_to_one association using the :distinct_on strategy" do
1354
- sub = Class.new(GraphTrack)
1355
- def (sub.dataset).supports_distinct_on?() true end
1356
- def (sub.dataset).columns() [:id, :album_id] end
1357
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1358
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>true)
1359
- 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)'
1360
- ds._fetch = {:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1}
1361
- a = ds.all
1362
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1363
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1364
- end
1365
-
1366
- it "should eagerly graph a single one_to_one association using the :window_function strategy" do
1367
- sub = Class.new(GraphTrack)
1368
- def (sub.dataset).supports_window_functions?() true end
1369
- def (sub.dataset).columns() [:id, :album_id] end
1370
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1371
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>true)
1372
- 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)'
1373
- ds._fetch = {:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1}
1374
- a = ds.all
1375
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1376
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1377
- end
1378
-
1379
- it "should eagerly graph a single one_to_one association using the :correlated_subquery strategy" do
1380
- sub = Class.new(GraphTrack)
1381
- def (sub.dataset).supports_window_functions?() true end
1382
- def (sub.dataset).columns() [:id, :album_id] end
1383
- GraphAlbum.one_to_one :ltrack, :clone=>:track, :class=>sub
1384
- ds = GraphAlbum.eager_graph_with_options(:ltrack, :limit_strategy=>:correlated_subquery)
1385
- 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)'
1386
- ds._fetch = {:id=>1, :band_id=>2, :ltrack_id=>3, :album_id=>1}
1387
- a = ds.all
1388
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1389
- a.first.ltrack.must_equal sub.load(:id => 3, :album_id=>1)
1390
- end
1391
-
1392
- it "should eagerly load a single one_to_many association" do
1393
- ds = GraphAlbum.eager_graph(:tracks)
1394
- 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)'
1395
- ds._fetch = {:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1}
1396
- a = ds.all
1397
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1398
- a.first.tracks.must_equal [GraphTrack.load(:id => 3, :album_id=>1)]
1399
- end
1400
-
1401
- it "should eagerly graph a single one_to_many association using the :window_function strategy" do
1402
- sub = Class.new(GraphTrack)
1403
- def (sub.dataset).supports_window_functions?() true end
1404
- def (sub.dataset).columns() [:id, :album_id] end
1405
- GraphAlbum.one_to_many :ltracks, :clone=>:tracks, :limit=>2, :class=>sub
1406
- ds = GraphAlbum.eager_graph_with_options(:ltracks, :limit_strategy=>true)
1407
- 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)'
1408
- ds._fetch = {:id=>1, :band_id=>2, :ltracks_id=>3, :album_id=>1}
1409
- a = ds.all
1410
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1411
- a.first.ltracks.must_equal [sub.load(:id => 3, :album_id=>1)]
1412
- end
1413
-
1414
- it "should eagerly load a single many_to_many association" do
1415
- ds = GraphAlbum.eager_graph(:genres)
1416
- 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)'
1417
- ds._fetch = {:id=>1, :band_id=>2, :genres_id=>4}
1418
- a = ds.all
1419
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1420
- a.first.genres.must_equal [GraphGenre.load(:id => 4)]
1421
- end
1422
-
1423
- it "should eagerly graph a single many_to_many association using the :window_function strategy" do
1424
- sub = Class.new(GraphGenre)
1425
- def (sub.dataset).supports_window_functions?() true end
1426
- def (sub.dataset).columns() literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1427
- GraphAlbum.many_to_many :lgenres, :clone=>:genres, :class=>sub, :limit=>2
1428
- ds = GraphAlbum.eager_graph_with_options(:lgenres, :limit_strategy=>true)
1429
- 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)'
1430
- ds._fetch = {:id=>1, :band_id=>2, :lgenres_id=>4}
1431
- a = ds.all
1432
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1433
- a.first.lgenres.must_equal [sub.load(:id => 4)]
1434
- end
1435
-
1436
- it "should eagerly load a single one_through_one association" do
1437
- ds = GraphAlbum.eager_graph(:genre)
1438
- 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)'
1439
- ds._fetch = {:id=>1, :band_id=>2, :genre_id=>4}
1440
- a = ds.all
1441
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1442
- a.first.genre.must_equal GraphGenre.load(:id => 4)
1443
- end
1444
-
1445
- it "should eagerly graph a single one_through_one association using the :distinct_on strategy" do
1446
- sub = Class.new(GraphGenre)
1447
- def (sub.dataset).supports_distinct_on?() true end
1448
- def (sub.dataset).columns() [:id] end
1449
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>sub
1450
- ds = GraphAlbum.eager_graph_with_options(:lgenre, :limit_strategy=>true)
1451
- 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)'
1452
- ds._fetch = {:id=>1, :band_id=>2, :lgenre_id=>4}
1453
- a = ds.all
1454
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1455
- a.first.lgenre.must_equal sub.load(:id => 4)
1456
- end
1457
-
1458
- it "should eagerly graph a single one_through_one association using the :window_function strategy" do
1459
- sub = Class.new(GraphGenre)
1460
- def (sub.dataset).supports_window_functions?() true end
1461
- def (sub.dataset).columns() literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1462
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>sub
1463
- ds = GraphAlbum.eager_graph_with_options(:lgenre, :limit_strategy=>true)
1464
- 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)'
1465
- ds._fetch = {:id=>1, :band_id=>2, :lgenre_id=>4}
1466
- a = ds.all
1467
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1468
- a.first.lgenre.must_equal sub.load(:id => 4)
1469
- end
1470
-
1471
- it "should correctly handle an aliased join table in many_to_many and one_through_one" do
1472
- c = Class.new(GraphAlbum)
1473
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___ga
1474
- 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)'
1475
-
1476
- c.many_to_many :genre, :clone=>:genre, :join_table=>:ag___ga
1477
- 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)'
1478
-
1479
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___albums
1480
- 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)'
1481
-
1482
- c.many_to_many :genres, :clone=>:genres, :join_table=>:ag___genres
1483
- 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)'
1484
- end
1485
-
1486
- it "should handle multiple associations in a single call to association_join" do
1487
- 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)'
1488
- end
1489
-
1490
- it "should eagerly load multiple associations in a single call" do
1491
- ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
1492
- 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)'
1493
- ds._fetch = {:id=>1, :band_id=>2, :genres_id=>4, :tracks_id=>3, :album_id=>1, :band_id_0=>2, :vocalist_id=>6}
1494
- a = ds.all
1495
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1496
- a = a.first
1497
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1498
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1499
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1500
- end
1501
-
1502
- it "should eagerly load multiple associations with different limit strategies in a single call" do
1503
- subg = Class.new(GraphGenre)
1504
- def (subg.dataset).supports_distinct_on?() true end
1505
- def (subg.dataset).supports_window_functions?() true end
1506
- def (subg.dataset).columns() literal(opts[:select]) =~ /x_foreign_key_x/ ? [:id, :x_foreign_key_x] : [:id] end
1507
- GraphAlbum.one_through_one :lgenre, :clone=>:genre, :class=>subg
1508
- GraphAlbum.many_to_many :lgenres, :clone=>:genres, :class=>subg, :limit=>2
1509
-
1510
- ds = GraphAlbum.eager_graph_with_options([:lgenre, :lgenres], :limit_strategy=>{:lgenre=>:distinct_on, :lgenres=>:window_function})
1511
- 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)'
1512
- ds._fetch = {:id=>1, :band_id=>2, :lgenres_id=>4, :lgenre_id=>3}
1513
- a = ds.all
1514
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1515
- a = a.first
1516
- a.lgenre.must_equal subg.load(:id => 3)
1517
- a.lgenres.must_equal [subg.load(:id => 4)]
1518
- end
1519
-
1520
- it "should handle multiple associations in separate calls to association_join" do
1521
- 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)'
1522
- end
1523
-
1524
- it "should eagerly load multiple associations in separate calls" do
1525
- ds = GraphAlbum.eager_graph(:genres).eager_graph(:tracks).eager_graph(:band)
1526
- 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)'
1527
- ds._fetch = {:id=>1, :band_id=>2, :genres_id=>4, :tracks_id=>3, :album_id=>1, :band_id_0=>2, :vocalist_id=>6}
1528
- a = ds.all
1529
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1530
- a = a.first
1531
- a.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1532
- a.tracks.must_equal [GraphTrack.load({:id => 3, :album_id=>1})]
1533
- a.genres.must_equal [GraphGenre.load(:id => 4)]
1534
- end
1535
-
1536
- it "should handle cascading associations in a single call to association_join" do
1537
- 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)'
1538
- 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)'
1539
- end
1540
-
1541
- it "should handle matching association names for different models when using association_join" do
1542
- 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)'
1543
- end
1544
-
1545
- it "should allow cascading of eager loading for associations of associated models" do
1546
- ds = GraphTrack.eager_graph(:album=>{:band=>:members})
1547
- 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)'
1548
- ds._fetch = {:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :members_id=>5, :band_id_0=>2, :vocalist_id=>6}
1549
- a = ds.all
1550
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
1551
- a = a.first
1552
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
1553
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
1554
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
1555
- end
1556
-
1557
- it "should allow cascading of eager loading for multiple *_to_many associations, eliminating duplicates caused by cartesian products" do
1558
- ds = GraphBand.eager_graph({:albums=>:tracks}, :members)
1559
- 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)'
1560
- ds._fetch = [{:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>5},
1561
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>4, :album_id=>3, :members_id=>6},
1562
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>5},
1563
- {:id=>1, :vocalist_id=>2, :albums_id=>3, :band_id=>1, :tracks_id=>5, :album_id=>3, :members_id=>6},
1564
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>5},
1565
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>6, :album_id=>4, :members_id=>6},
1566
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>5},
1567
- {:id=>1, :vocalist_id=>2, :albums_id=>4, :band_id=>1, :tracks_id=>7, :album_id=>4, :members_id=>6},
1568
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>5},
1569
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>8, :album_id=>5, :members_id=>6},
1570
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>5},
1571
- {:id=>2, :vocalist_id=>2, :albums_id=>5, :band_id=>2, :tracks_id=>9, :album_id=>5, :members_id=>6},
1572
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>5},
1573
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>1, :album_id=>6, :members_id=>6},
1574
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>5},
1575
- {:id=>2, :vocalist_id=>2, :albums_id=>6, :band_id=>2, :tracks_id=>2, :album_id=>6, :members_id=>6}]
1576
- a = ds.all
1577
- a.must_equal [GraphBand.load(:id=>1, :vocalist_id=>2), GraphBand.load(:id=>2, :vocalist_id=>2)]
1578
- members = a.map{|x| x.members}
1579
- members.must_equal [[GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)], [GraphBandMember.load(:id=>5), GraphBandMember.load(:id=>6)]]
1580
- albums = a.map{|x| x.albums}
1581
- 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)]]
1582
- tracks = albums.map{|x| x.map{|y| y.tracks}}
1583
- 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)]]]
1584
- end
1585
-
1586
- it "should populate the reciprocal many_to_one association when eagerly loading the one_to_many association" do
1587
- DB.reset
1588
- ds = GraphAlbum.eager_graph(:tracks)
1589
- 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)'
1590
- ds._fetch = {:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1}
1591
- a = ds.all
1592
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1593
- a = a.first
1594
- a.tracks.must_equal [GraphTrack.load(:id => 3, :album_id=>1)]
1595
- a.tracks.first.album.must_equal a
1596
- 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)']
1597
- end
1598
-
1599
- it "should eager load multiple associations from the same table" do
1600
- ds = GraphBand.eager_graph(:vocalist, :members)
1601
- 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)'
1602
- ds._fetch = {:id=>2, :vocalist_id=>6, :vocalist_id_0=>6, :members_id=>5}
1603
- a = ds.all
1604
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1605
- a = a.first
1606
- a.vocalist.must_equal GraphBandMember.load(:id => 6)
1607
- a.members.must_equal [GraphBandMember.load(:id => 5)]
1608
- end
1609
-
1610
- it "should give you a plain hash when called without .all" do
1611
- ds = GraphAlbum.eager_graph(:band)
1612
- 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)'
1613
- ds._fetch = {:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3}
1614
- ds.first.must_equal(:id=>1, :band_id=>2, :band_id_0=>2, :vocalist_id=>3)
1615
- end
1616
-
1617
- it "should not drop any associated objects if the graph could not be a cartesian product" do
1618
- ds = GraphBand.eager_graph(:members, :vocalist)
1619
- 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)'
1620
- ds._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}]
1621
- a = ds.all
1622
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1623
- a = a.first
1624
- a.vocalist.must_equal GraphBandMember.load(:id => 6)
1625
- a.members.must_equal [GraphBandMember.load(:id => 5), GraphBandMember.load(:id => 5)]
1626
- end
1627
-
1628
- it "should respect the :cartesian_product_number option" do
1629
- GraphBand.many_to_one :other_vocalist, :class=>'GraphBandMember', :key=>:vocalist_id, :cartesian_product_number=>1
1630
- ds = GraphBand.eager_graph(:members, :other_vocalist)
1631
- 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)'
1632
- ds._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}]
1633
- a = ds.all
1634
- a.must_equal [GraphBand.load(:id=>2, :vocalist_id => 6)]
1635
- a.first.other_vocalist.must_equal GraphBandMember.load(:id=>6)
1636
- a.first.members.must_equal [GraphBandMember.load(:id=>5)]
1637
- end
1638
-
1639
- it "should drop duplicate items that occur in sequence if the graph could be a cartesian product" do
1640
- ds = GraphBand.eager_graph(:members, :genres)
1641
- 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)'
1642
- ds._fetch = [{:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>7},
1643
- {:id=>2, :vocalist_id=>6, :members_id=>5, :genres_id=>8},
1644
- {:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>7},
1645
- {:id=>2, :vocalist_id=>6, :members_id=>6, :genres_id=>8}]
1646
- a = ds.all
1647
- a.must_equal [GraphBand.load(:id => 2, :vocalist_id => 6)]
1648
- a = a.first
1649
- a.members.must_equal [GraphBandMember.load(:id => 5), GraphBandMember.load(:id => 6)]
1650
- a.genres.must_equal [GraphGenre.load(:id => 7), GraphGenre.load(:id => 8)]
1651
- end
1652
-
1653
- it "should be able to be used in combination with #eager" do
1654
- DB.reset
1655
- ds = GraphAlbum.eager_graph(:tracks).eager(:genres)
1656
- ds._fetch = {:id=>1, :band_id=>2, :tracks_id=>3, :album_id=>1}
1657
- ds2 = GraphGenre.dataset
1658
- ds2._fetch = {:id=>6, :x_foreign_key_x=>1}
1659
- a = ds.all
1660
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1661
- a = a.first
1662
- a.tracks.must_equal [GraphTrack.load(:id=>3, :album_id=>1)]
1663
- a.genres.must_equal [GraphGenre.load(:id => 6)]
1664
- 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)',
1665
- "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))"]
1666
- end
1667
-
1668
- it "should handle no associated records for a single many_to_one association" do
1669
- ds = GraphAlbum.eager_graph(:band)
1670
- 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)'
1671
- ds._fetch = {:id=>1, :band_id=>2, :band_id_0=>nil, :vocalist_id=>nil}
1672
- a = ds.all
1673
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1674
- a.first.band.must_equal nil
1675
- end
1676
-
1677
- it "should handle no associated records for a single one_to_one association" do
1678
- ds = GraphAlbum.eager_graph(:track)
1679
- 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)'
1680
- ds._fetch = {:id=>1, :band_id=>2, :track_id=>nil, :album_id=>nil}
1681
- a = ds.all
1682
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1683
- a.first.track.must_equal nil
1684
- end
1685
-
1686
- it "should handle no associated records for a single one_to_many association" do
1687
- ds = GraphAlbum.eager_graph(:tracks)
1688
- 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)'
1689
- ds._fetch = {:id=>1, :band_id=>2, :tracks_id=>nil, :album_id=>nil}
1690
- a = ds.all
1691
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1692
- a.first.tracks.must_equal []
1693
- end
1694
-
1695
- it "should handle no associated records for a single one_through_one association" do
1696
- ds = GraphAlbum.eager_graph(:genre)
1697
- 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)'
1698
- ds._fetch = {:id=>1, :band_id=>2, :genres_id=>nil}
1699
- a = ds.all
1700
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1701
- a.first.genre.must_equal nil
1702
- end
1703
-
1704
- it "should handle no associated records for a single many_to_many association" do
1705
- ds = GraphAlbum.eager_graph(:genres)
1706
- 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)'
1707
- ds._fetch = {:id=>1, :band_id=>2, :genres_id=>nil}
1708
- a = ds.all
1709
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1710
- a.first.genres.must_equal []
1711
- end
1712
-
1713
- it "should handle missing associated records when loading multiple associations" do
1714
- ds = GraphAlbum.eager_graph(:genres, :tracks, :band)
1715
- 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)'
1716
- ds._fetch = [{:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>3, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil},
1717
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>4, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil},
1718
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>5, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil},
1719
- {:id=>1, :band_id=>2, :genres_id=>nil, :tracks_id=>6, :album_id=>1, :band_id_0=>nil, :vocalist_id=>nil}]
1720
- a = ds.all
1721
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
1722
- a = a.first
1723
- 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)]
1724
- a.band.must_equal nil
1725
- a.genres.must_equal []
1726
- end
1727
-
1728
- it "should handle missing associated records when cascading eager loading for associations of associated models" do
1729
- ds = GraphTrack.eager_graph(:album=>{:band=>:members})
1730
- 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)'
1731
- ds._fetch = [{:id=>2, :album_id=>2, :album_id_0=>nil, :band_id=>nil, :members_id=>nil, :band_id_0=>nil, :vocalist_id=>nil},
1732
- {:id=>3, :album_id=>3, :album_id_0=>3, :band_id=>3, :members_id=>nil, :band_id_0=>nil, :vocalist_id=>nil},
1733
- {:id=>4, :album_id=>4, :album_id_0=>4, :band_id=>2, :members_id=>nil, :band_id_0=>2, :vocalist_id=>6},
1734
- {:id=>5, :album_id=>1, :album_id_0=>1, :band_id=>4, :members_id=>5, :band_id_0=>4, :vocalist_id=>8},
1735
- {:id=>5, :album_id=>1, :album_id_0=>1, :band_id=>4, :members_id=>6, :band_id_0=>4, :vocalist_id=>8}]
1736
- a = ds.all
1737
- 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)]
1738
- 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)]
1739
- 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)]
1740
- 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)]]
1741
- end
1742
-
1743
- it "should respect the association's :primary_key option" do
1744
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :primary_key=>:vocalist_id
1745
- ds = GraphAlbum.eager_graph(:inner_band)
1746
- 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)'
1747
- ds._fetch = {:id=>3, :band_id=>2, :inner_band_id=>5, :vocalist_id=>2}
1748
- as = ds.all
1749
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1750
- as.first.inner_band.must_equal GraphBand.load(:id=>5, :vocalist_id=>2)
1751
-
1752
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :primary_key=>:band_id, :reciprocal=>nil
1753
- ds = GraphAlbum.eager_graph(:right_tracks)
1754
- 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)'
1755
- ds._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}]
1756
- as = ds.all
1757
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1758
- as.first.right_tracks.must_equal [GraphTrack.load(:id=>5, :album_id=>2), GraphTrack.load(:id=>6, :album_id=>2)]
1759
- end
1760
-
1761
- it "should respect many_to_one association's composite keys" do
1762
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>[:band_id, :id], :primary_key=>[:vocalist_id, :id]
1763
- ds = GraphAlbum.eager_graph(:inner_band)
1764
- 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))'
1765
- ds._fetch = {:id=>3, :band_id=>2, :inner_band_id=>3, :vocalist_id=>2}
1766
- as = ds.all
1767
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1768
- as.first.inner_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>2)
1769
- end
1770
-
1771
- it "should respect one_to_many association's composite keys" do
1772
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>[:album_id, :id], :primary_key=>[:band_id, :id]
1773
- ds = GraphAlbum.eager_graph(:right_tracks)
1774
- 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))'
1775
- ds._fetch = {:id=>3, :band_id=>2, :right_tracks_id=>3, :album_id=>2}
1776
- as = ds.all
1777
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1778
- as.first.right_tracks.must_equal [GraphTrack.load(:id=>3, :album_id=>2)]
1779
- end
1780
-
1781
- it "should respect many_to_many association's composite keys" do
1782
- 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
1783
- ds = GraphAlbum.eager_graph(:sbands)
1784
- 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))'
1785
- ds._fetch = [{:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6}, {:id=>3, :band_id=>2, :sbands_id=>6, :vocalist_id=>22}]
1786
- as = ds.all
1787
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1788
- as.first.sbands.must_equal [GraphBand.load(:id=>5, :vocalist_id=>6), GraphBand.load(:id=>6, :vocalist_id=>22)]
1789
- end
1790
-
1791
- it "should respect many_to_many association's :left_primary_key and :right_primary_key options" do
1792
- 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
1793
- ds = GraphAlbum.eager_graph(:inner_genres)
1794
- 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)'
1795
- ds._fetch = [{:id=>3, :band_id=>2, :inner_genres_id=>5, :xxx=>12}, {:id=>3, :band_id=>2, :inner_genres_id=>6, :xxx=>22}]
1796
- as = ds.all
1797
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1798
- as.first.inner_genres.must_equal [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
1799
- end
1800
-
1801
- it "should respect composite primary keys for classes when eager loading" do
1802
- c1 = Class.new(GraphAlbum)
1803
- c2 = Class.new(GraphBand)
1804
- c1.set_primary_key [:band_id, :id]
1805
- c2.set_primary_key [:vocalist_id, :id]
1806
- c1.many_to_many :sbands, :class=>c2, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :join_table=>:b
1807
- c2.one_to_many :salbums, :class=>c1, :key=>[:band_id, :id]
1808
- ds = c1.eager_graph(:sbands=>:salbums)
1809
- 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))'
1810
- ds._fetch = [{:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6, :salbums_id=>7, :salbums_band_id=>8},
1811
- {:id=>3, :band_id=>2, :sbands_id=>5, :vocalist_id=>6, :salbums_id=>9, :salbums_band_id=>10},
1812
- {:id=>3, :band_id=>2, :sbands_id=>6, :vocalist_id=>22, :salbums_id=>nil, :salbums_band_id=>nil},
1813
- {:id=>7, :band_id=>8, :sbands_id=>nil, :vocalist_id=>nil, :salbums_id=>nil, :salbums_band_id=>nil}]
1814
- as = ds.all
1815
- as.must_equal [c1.load(:id=>3, :band_id=>2), c1.load(:id=>7, :band_id=>8)]
1816
- as.map{|x| x.sbands}.must_equal [[c2.load(:id=>5, :vocalist_id=>6), c2.load(:id=>6, :vocalist_id=>22)], []]
1817
- 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)], []], []]
1818
- end
1819
-
1820
- it "should respect the association's :graph_select option" do
1821
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_select=>:vocalist_id
1822
- 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)'
1823
-
1824
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_select=>[:album_id]
1825
- 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)'
1826
-
1827
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_select=>[]
1828
- 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)'
1829
- end
1830
-
1831
- it "should respect the association's :graph_alias_base option" do
1832
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_alias_base=>:foo
1833
- ds = GraphAlbum.eager_graph(:inner_band)
1834
- 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)'
1835
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_alias_base=>:foo
1836
- 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)'
1837
- end
1838
-
1839
- it "should respect the association's :graph_join_type option" do
1840
- GraphAlbum.many_to_one :inner_band, :class=>'GraphBand', :key=>:band_id, :graph_join_type=>:inner
1841
- 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)'
1842
-
1843
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_join_type=>:right_outer
1844
- 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)'
1845
-
1846
- GraphAlbum.many_to_many :inner_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_join_type=>:inner
1847
- 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)'
1848
- end
1849
-
1850
- it "should respect the association's :graph_join_table_join_type option" do
1851
- 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
1852
- 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)'
1853
-
1854
- 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
1855
- 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)'
1856
- end
1857
-
1858
- it "should respect the association's :conditions option" do
1859
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :conditions=>{:active=>true}
1860
- 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))"
1861
-
1862
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :conditions=>{:id=>(0..100)}, :reciprocal=>nil
1863
- 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))'
1864
-
1865
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :conditions=>{true=>:active}
1866
- 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))"
1867
- end
1868
-
1869
- it "should respect the association's :graph_conditions option" do
1870
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_conditions=>{:active=>true}
1871
- 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))"
1872
-
1873
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:id=>(0..100)}
1874
- 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))'
1875
-
1876
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_conditions=>{true=>:active}
1877
- 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))"
1878
- end
1879
-
1880
- it "should respect the association's :graph_join_table_conditions option" do
1881
- 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}
1882
- 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)"
1883
-
1884
- 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}
1885
- 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))"
1886
- end
1887
-
1888
- it "should respect the association's :graph_block option" do
1889
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :active)=>true}}
1890
- 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))"
1891
-
1892
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :id)=>(0..100)}}
1893
- 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))'
1894
-
1895
- 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)}}
1896
- 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))"
1897
- end
1898
-
1899
- it "should respect the association's :graph_join_table_block option" do
1900
- 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}}
1901
- 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)"
1902
-
1903
- 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)}}
1904
- 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))"
1905
- end
1906
-
1907
- it "should respect the association's :eager_grapher option" do
1908
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :eager_grapher=>proc{|eo| eo[:self].graph(GraphBand, {:active=>true}, :table_alias=>eo[:table_alias], :join_type=>:inner)}
1909
- 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)"
1910
-
1911
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :eager_grapher=>proc{|eo| eo[:self].graph(GraphTrack, nil, :join_type=>:natural, :table_alias=>eo[:table_alias])}
1912
- 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'
1913
-
1914
- 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, [:album_id], :table_alias=>eo[:table_alias])}
1915
- 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)"
1916
- end
1917
-
1918
- it "should respect the association's :graph_only_conditions option" do
1919
- GraphAlbum.many_to_one :active_band, :class=>'GraphBand', :key=>:band_id, :graph_only_conditions=>{:active=>true}
1920
- 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)"
1921
-
1922
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_only_conditions=>nil, :graph_join_type=>:natural
1923
- 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'
1924
-
1925
- GraphAlbum.many_to_many :active_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :graph_only_conditions=>[:album_id]
1926
- 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)"
1927
- end
1928
-
1929
- it "should respect the association's :graph_join_table_only_conditions option" do
1930
- 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}
1931
- 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)"
1932
-
1933
- 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=>"active"
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 (active) LEFT OUTER JOIN genres AS active_genres ON ((price + 2) > 100)"
1935
- end
1936
-
1937
- it "should create unique table aliases for all associations" do
1938
- 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)"
1939
- end
1940
-
1941
- it "should respect the association's :order" do
1942
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
1943
- 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'
1944
- end
1945
-
1946
- it "should only qualify unqualified symbols, identifiers, or ordered versions in association's :order" do
1947
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[Sequel.identifier(:blah__id), Sequel.identifier(:blah__id).desc, Sequel.desc(:blah__id), :blah__id, :album_id, Sequel.desc(:album_id), 1, Sequel.lit('RANDOM()'), Sequel.qualify(:b, :a)]
1948
- 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'
1949
- end
1950
-
1951
- it "should not respect the association's :order if :order_eager_graph is false" do
1952
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id], :order_eager_graph=>false
1953
- 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)'
1954
- end
1955
-
1956
- it "should add the association's :order to the existing order" do
1957
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
1958
- 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'
1959
- end
1960
-
1961
- it "should use the association's :graph_order in preference or order" do
1962
- GraphAlbum.one_to_many :right_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:tracks__id, :tracks__album_id], :graph_order=>[:id, :album_id]
1963
- 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'
1964
- end
1965
-
1966
- it "should add the association's :order for cascading associations" do
1967
- GraphBand.one_to_many :a_albums, :class=>'GraphAlbum', :key=>:band_id, :order=>:name, :reciprocal=>nil
1968
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
1969
- 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'
1970
- GraphAlbum.one_to_many :albums, :class=>'GraphAlbum', :key=>:band_id, :order=>[:band_id, :id]
1971
- 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'
1972
- end
1973
-
1974
- it "should add the associations :order for multiple associations" do
1975
- GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :order=>:id
1976
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :order=>[:id, :album_id]
1977
- 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'
1978
- end
1979
-
1980
- it "should use the correct qualifier when graphing multiple tables with extra conditions" do
1981
- GraphAlbum.many_to_many :a_genres, :class=>'GraphGenre', :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag
1982
- GraphAlbum.one_to_many :b_tracks, :class=>'GraphTrack', :key=>:album_id, :graph_conditions=>{:a=>:b}
1983
- 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))'
1984
- end
1985
-
1986
- it "should eagerly load associated records for classes that do not have a primary key" do
1987
- GraphAlbum.no_primary_key
1988
- GraphGenre.no_primary_key
1989
- 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
1990
- ds = GraphAlbum.eager_graph(:inner_genres)
1991
- 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)'
1992
- ds._fetch = [{:id=>3, :band_id=>2, :inner_genres_id=>5, :xxx=>12}, {:id=>3, :band_id=>2, :inner_genres_id=>6, :xxx=>22}]
1993
- as = ds.all
1994
- as.must_equal [GraphAlbum.load(:id=>3, :band_id=>2)]
1995
- as.first.inner_genres.must_equal [GraphGenre.load(:id=>5), GraphGenre.load(:id=>6)]
1996
- GraphAlbum.set_primary_key :id
1997
- GraphGenre.set_primary_key :id
1998
- end
1999
-
2000
- it "should handle eager loading with schemas and aliases of different types" do
2001
- 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)'
2002
- 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)'
2003
- 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)'
2004
- 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)'
2005
- 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)'
2006
- 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)'
2007
- end
2008
-
2009
- it "should raise errors if invalid aliases or table styles are used" do
2010
- proc{GraphAlbum.from_self(:alias=>Sequel.qualify(:s, :bands)).eager_graph(:band)}.must_raise(Sequel::Error)
2011
- proc{GraphAlbum.from(Sequel.lit('?', :bands)).eager_graph(:band)}.must_raise(Sequel::Error)
2012
- end
2013
-
2014
- it "should eagerly load schema qualified tables correctly with joins" do
2015
- c1 = Class.new(GraphAlbum)
2016
- c2 = Class.new(GraphGenre)
2017
- ds = c1.dataset = c1.dataset.from(:s__a)
2018
- def ds.columns() [:id] end
2019
- c2.dataset = c2.dataset.from(:s__g)
2020
- c1.many_to_many :a_genres, :class=>c2, :left_primary_key=>:id, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:s__ag
2021
- ds = c1.join(:s__t, [:b_id]).eager_graph(:a_genres)
2022
- 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)'
2023
- ds = c1.eager_graph(:a_genres)
2024
- 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)'
2025
- end
2026
-
2027
- it "should respect :after_load callbacks on associations when eager graphing" do
2028
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id, :after_load=>proc{|o, a| a.id *=2}
2029
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :after_load=>proc{|o, os| os.each{|a| a.id *=2}}
2030
- 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}}
2031
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2032
- 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)"
2033
- ds._fetch = {:id=>1, :band_id=>2, :al_band_id=>3, :vocalist_id=>4, :al_tracks_id=>5, :album_id=>6, :al_genres_id=>7}
2034
- a = ds.all.first
2035
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2036
- a.al_band.must_equal GraphBand.load(:id=>6, :vocalist_id=>4)
2037
- a.al_tracks.must_equal [GraphTrack.load(:id=>10, :album_id=>6)]
2038
- a.al_genres.must_equal [GraphGenre.load(:id=>14)]
2039
- end
2040
-
2041
- it "should respect limits on associations when eager graphing" do
2042
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2043
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>2
2044
- GraphAlbum.many_to_many :al_genres, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>2
2045
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2046
- 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)"
2047
- ds._fetch = [{:id=>1, :band_id=>2, :al_band_id=>3, :vocalist_id=>4, :al_tracks_id=>5, :album_id=>6, :al_genres_id=>7},
2048
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_tracks_id=>10, :album_id=>11, :al_genres_id=>12},
2049
- {:id=>1, :band_id=>2, :al_band_id=>13, :vocalist_id=>14, :al_tracks_id=>15, :album_id=>16, :al_genres_id=>17}]
2050
- a = ds.all.first
2051
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2052
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2053
- a.al_tracks.must_equal [GraphTrack.load(:id=>5, :album_id=>6), GraphTrack.load(:id=>10, :album_id=>11)]
2054
- a.al_genres.must_equal [GraphGenre.load(:id=>7), GraphGenre.load(:id=>12)]
2055
- end
2056
-
2057
- it "should handle offsets on associations with no results when eager graphing" do
2058
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>[2, 1]
2059
- ds = GraphAlbum.eager_graph(:al_tracks)
2060
- 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)"
2061
- ds._fetch = [{:id=>1, :band_id=>2, :al_tracks_id=>nil, :album_id=>nil}]
2062
- a = ds.all.first
2063
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2064
- a.al_tracks.must_equal []
2065
- end
2066
-
2067
- it "should respect offsets on associations when eager graphing" do
2068
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2069
- GraphAlbum.one_to_many :al_tracks, :class=>GraphTrack, :key=>:album_id, :limit=>[1, 1]
2070
- GraphAlbum.many_to_many :al_genres, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[1,1]
2071
- ds = GraphAlbum.eager_graph(:al_band, :al_tracks, :al_genres)
2072
- 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)"
2073
- ds._fetch = [{:id=>1, :band_id=>2, :al_band_id=>3, :vocalist_id=>4, :al_tracks_id=>5, :album_id=>6, :al_genres_id=>7},
2074
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_tracks_id=>10, :album_id=>11, :al_genres_id=>12},
2075
- {:id=>1, :band_id=>2, :al_band_id=>13, :vocalist_id=>14, :al_tracks_id=>15, :album_id=>16, :al_genres_id=>17}]
2076
- a = ds.all.first
2077
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2078
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2079
- a.al_tracks.must_equal [GraphTrack.load(:id=>10, :album_id=>11)]
2080
- a.al_genres.must_equal [GraphGenre.load(:id=>12)]
2081
- end
2082
-
2083
- it "should respect offsets on associations when eager graphing one_to_one and one_through_one associations" do
2084
- GraphAlbum.many_to_one :al_band, :class=>GraphBand, :key=>:band_id
2085
- GraphAlbum.one_to_one :al_track, :class=>GraphTrack, :key=>:album_id, :limit=>[nil, 1]
2086
- GraphAlbum.one_through_one :al_genre, :class=>GraphGenre, :left_key=>:album_id, :right_key=>:genre_id, :join_table=>:ag, :limit=>[nil,1]
2087
- ds = GraphAlbum.eager_graph(:al_band, :al_track, :al_genre)
2088
- 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)"
2089
- ds._fetch = [{:id=>1, :band_id=>2, :al_band_id=>3, :vocalist_id=>4, :al_track_id=>5, :album_id=>6, :al_genre_id=>7},
2090
- {:id=>1, :band_id=>2, :al_band_id=>8, :vocalist_id=>9, :al_track_id=>10, :album_id=>11, :al_genre_id=>12},
2091
- {:id=>1, :band_id=>2, :al_band_id=>13, :vocalist_id=>14, :al_track_id=>15, :album_id=>16, :al_genre_id=>17}]
2092
- a = ds.all.first
2093
- a.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2094
- a.al_band.must_equal GraphBand.load(:id=>3, :vocalist_id=>4)
2095
- a.al_track.must_equal GraphTrack.load(:id=>10, :album_id=>11)
2096
- a.al_genre.must_equal GraphGenre.load(:id=>12)
2097
- end
2098
-
2099
- it "should eagerly load a many_to_one association with a custom callback" do
2100
- ds = GraphAlbum.eager_graph(:band => proc {|ds1| ds1.select(:id).columns(:id)})
2101
- 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)'
2102
- ds._fetch = {:id=>1, :band_id=>2, :band_id_0=>2}
2103
- a = ds.all
2104
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2105
- a.first.band.must_equal GraphBand.load(:id => 2)
2106
- end
2107
-
2108
- it "should eagerly load a one_to_one association with a custom callback" do
2109
- ds = GraphAlbum.eager_graph(:track => proc {|ds1| ds1.select(:album_id).columns(:album_id)})
2110
- 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)'
2111
- ds._fetch = {:id=>1, :band_id=>2, :album_id=>1}
2112
- a = ds.all
2113
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2114
- a.first.track.must_equal GraphTrack.load(:album_id=>1)
2115
- end
2116
-
2117
- it "should eagerly load a one_to_many association with a custom callback" do
2118
- ds = GraphAlbum.eager_graph(:tracks => proc {|ds1| ds1.select(:album_id).columns(:album_id)})
2119
- 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)'
2120
- ds._fetch = {:id=>1, :band_id=>2, :album_id=>1}
2121
- a = ds.all
2122
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2123
- a.first.tracks.must_equal [GraphTrack.load(:album_id=>1)]
2124
- end
2125
-
2126
- it "should eagerly load a one_through_one association with a custom callback" do
2127
- ds = GraphAlbum.eager_graph(:genre => proc {|ds1| ds1.select(:id).columns(:id)})
2128
- 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)'
2129
- ds._fetch = {:id=>1, :band_id=>2, :genre_id=>4}
2130
- a = ds.all
2131
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2132
- a.first.genre.must_equal GraphGenre.load(:id => 4)
2133
- end
2134
-
2135
- it "should eagerly load a many_to_many association with a custom callback" do
2136
- ds = GraphAlbum.eager_graph(:genres => proc {|ds1| ds1.select(:id).columns(:id)})
2137
- 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)'
2138
- ds._fetch = {:id=>1, :band_id=>2, :genres_id=>4}
2139
- a = ds.all
2140
- a.must_equal [GraphAlbum.load(:id => 1, :band_id => 2)]
2141
- a.first.genres.must_equal [GraphGenre.load(:id => 4)]
2142
- end
2143
-
2144
- it "should allow cascading of eager loading with a custom callback with hash value" do
2145
- ds = GraphTrack.eager_graph(:album=>{proc{|ds1| ds1.select(:id, :band_id).columns(:id, :band_id)}=>{:band=>:members}})
2146
- 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)'
2147
- ds._fetch = {:id=>3, :album_id=>1, :album_id_0=>1, :band_id=>2, :members_id=>5, :band_id_0=>2, :vocalist_id=>6}
2148
- a = ds.all
2149
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2150
- a = a.first
2151
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2152
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
2153
- a.album.band.members.must_equal [GraphBandMember.load(:id => 5)]
2154
- end
2155
-
2156
- it "should allow cascading of eager loading with a custom callback with array value" do
2157
- ds = GraphTrack.eager_graph(:album=>{proc{|ds1| ds1.select(:id, :band_id).columns(:id, :band_id)}=>[:band, :tracks]})
2158
- 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)'
2159
- ds._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}
2160
- a = ds.all
2161
- a.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2162
- a = a.first
2163
- a.album.must_equal GraphAlbum.load(:id => 1, :band_id => 2)
2164
- a.album.band.must_equal GraphBand.load(:id => 2, :vocalist_id=>6)
2165
- a.album.tracks.must_equal [GraphTrack.load(:id => 3, :album_id => 1)]
2166
- end
2167
- end
2168
-
2169
- describe "Sequel::Models with double underscores in table names" do
2170
- before do
2171
- @db = Sequel.mock(:fetch=>{:id=>1, :foo_id=>2})
2172
- @Foo = Class.new(Sequel::Model(@db[Sequel.identifier(:fo__os)]))
2173
- @Foo.columns :id, :foo_id
2174
- @Foo.one_to_many :foos, :class=>@Foo
2175
- @db.sqls
2176
- end
2177
-
2178
- it "should have working eager_graph implementations" do
2179
- @db.fetch = {:id=>1, :foo_id=>1, :foos_id=>1, :foos_foo_id=>1}
2180
- foos = @Foo.eager_graph(:foos).all
2181
- @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 (SELECT * FROM fo__os) AS foos ON (foos._id = fo__os.id)"]
2182
- foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2183
- foos.first.foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2184
- end
2185
-
2186
- it "should have working eager_graph implementations when qualified" do
2187
- @Foo.dataset = Sequel.identifier(:fo__os).qualify(:s)
2188
- @Foo.columns :id, :foo_id
2189
- @db.sqls
2190
- @db.fetch = {:id=>1, :foo_id=>1, :foos_id=>1, :foos_foo_id=>1}
2191
- foos = @Foo.eager_graph(:foos).all
2192
- @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 (SELECT * FROM s.fo__os) AS foos ON (foos._id = s.fo__os.id)"]
2193
- foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2194
- foos.first.foos.must_equal [@Foo.load(:id=>1, :foo_id=>1)]
2195
- end
2196
- end
2197
-