sequel 4.26.0 → 5.37.0

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