sequel 5.8.0 → 5.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (510) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +409 -1795
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/bin/sequel +4 -0
  6. data/doc/advanced_associations.rdoc +136 -18
  7. data/doc/association_basics.rdoc +10 -5
  8. data/doc/cheat_sheet.rdoc +1 -0
  9. data/doc/code_order.rdoc +12 -2
  10. data/doc/dataset_filtering.rdoc +17 -2
  11. data/doc/mass_assignment.rdoc +3 -3
  12. data/doc/model_dataset_method_design.rdoc +1 -1
  13. data/doc/model_plugins.rdoc +1 -1
  14. data/doc/opening_databases.rdoc +30 -8
  15. data/doc/postgresql.rdoc +107 -2
  16. data/doc/release_notes/5.10.0.txt +84 -0
  17. data/doc/release_notes/5.11.0.txt +83 -0
  18. data/doc/release_notes/5.12.0.txt +141 -0
  19. data/doc/release_notes/5.13.0.txt +27 -0
  20. data/doc/release_notes/5.14.0.txt +63 -0
  21. data/doc/release_notes/5.15.0.txt +39 -0
  22. data/doc/release_notes/5.16.0.txt +110 -0
  23. data/doc/release_notes/5.17.0.txt +31 -0
  24. data/doc/release_notes/5.18.0.txt +69 -0
  25. data/doc/release_notes/5.19.0.txt +28 -0
  26. data/doc/release_notes/5.20.0.txt +89 -0
  27. data/doc/release_notes/5.21.0.txt +87 -0
  28. data/doc/release_notes/5.22.0.txt +48 -0
  29. data/doc/release_notes/5.23.0.txt +56 -0
  30. data/doc/release_notes/5.24.0.txt +56 -0
  31. data/doc/release_notes/5.25.0.txt +32 -0
  32. data/doc/release_notes/5.26.0.txt +35 -0
  33. data/doc/release_notes/5.27.0.txt +21 -0
  34. data/doc/release_notes/5.28.0.txt +16 -0
  35. data/doc/release_notes/5.29.0.txt +22 -0
  36. data/doc/release_notes/5.30.0.txt +20 -0
  37. data/doc/release_notes/5.31.0.txt +148 -0
  38. data/doc/release_notes/5.32.0.txt +46 -0
  39. data/doc/release_notes/5.33.0.txt +24 -0
  40. data/doc/release_notes/5.34.0.txt +40 -0
  41. data/doc/release_notes/5.35.0.txt +56 -0
  42. data/doc/release_notes/5.36.0.txt +60 -0
  43. data/doc/release_notes/5.37.0.txt +30 -0
  44. data/doc/release_notes/5.38.0.txt +28 -0
  45. data/doc/release_notes/5.9.0.txt +99 -0
  46. data/doc/security.rdoc +10 -0
  47. data/doc/sharding.rdoc +42 -28
  48. data/doc/sql.rdoc +12 -0
  49. data/doc/testing.rdoc +24 -17
  50. data/doc/transactions.rdoc +78 -0
  51. data/doc/validations.rdoc +2 -2
  52. data/lib/sequel/adapters/ado.rb +26 -18
  53. data/lib/sequel/adapters/ado/access.rb +2 -2
  54. data/lib/sequel/adapters/ado/mssql.rb +5 -8
  55. data/lib/sequel/adapters/amalgalite.rb +1 -1
  56. data/lib/sequel/adapters/jdbc.rb +71 -27
  57. data/lib/sequel/adapters/jdbc/mysql.rb +6 -6
  58. data/lib/sequel/adapters/jdbc/oracle.rb +7 -6
  59. data/lib/sequel/adapters/jdbc/postgresql.rb +17 -28
  60. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +5 -6
  61. data/lib/sequel/adapters/jdbc/sqlite.rb +33 -2
  62. data/lib/sequel/adapters/jdbc/sqlserver.rb +4 -3
  63. data/lib/sequel/adapters/jdbc/transactions.rb +14 -28
  64. data/lib/sequel/adapters/mysql.rb +14 -15
  65. data/lib/sequel/adapters/mysql2.rb +5 -3
  66. data/lib/sequel/adapters/odbc.rb +4 -6
  67. data/lib/sequel/adapters/oracle.rb +7 -7
  68. data/lib/sequel/adapters/postgres.rb +52 -16
  69. data/lib/sequel/adapters/shared/access.rb +16 -12
  70. data/lib/sequel/adapters/shared/db2.rb +5 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +41 -18
  72. data/lib/sequel/adapters/shared/mysql.rb +66 -19
  73. data/lib/sequel/adapters/shared/oracle.rb +29 -23
  74. data/lib/sequel/adapters/shared/postgres.rb +341 -95
  75. data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
  76. data/lib/sequel/adapters/shared/sqlite.rb +174 -21
  77. data/lib/sequel/adapters/sqlanywhere.rb +33 -17
  78. data/lib/sequel/adapters/sqlite.rb +78 -68
  79. data/lib/sequel/adapters/tinytds.rb +14 -6
  80. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +2 -5
  81. data/lib/sequel/adapters/utils/mysql_mysql2.rb +5 -1
  82. data/lib/sequel/connection_pool.rb +2 -6
  83. data/lib/sequel/connection_pool/sharded_single.rb +7 -4
  84. data/lib/sequel/connection_pool/sharded_threaded.rb +32 -21
  85. data/lib/sequel/connection_pool/single.rb +1 -1
  86. data/lib/sequel/connection_pool/threaded.rb +26 -11
  87. data/lib/sequel/core.rb +327 -319
  88. data/lib/sequel/database/connecting.rb +7 -8
  89. data/lib/sequel/database/logging.rb +7 -1
  90. data/lib/sequel/database/misc.rb +68 -34
  91. data/lib/sequel/database/query.rb +6 -4
  92. data/lib/sequel/database/schema_generator.rb +31 -11
  93. data/lib/sequel/database/schema_methods.rb +32 -22
  94. data/lib/sequel/database/transactions.rb +129 -25
  95. data/lib/sequel/dataset.rb +4 -2
  96. data/lib/sequel/dataset/actions.rb +34 -23
  97. data/lib/sequel/dataset/features.rb +34 -0
  98. data/lib/sequel/dataset/graph.rb +27 -11
  99. data/lib/sequel/dataset/misc.rb +17 -3
  100. data/lib/sequel/dataset/placeholder_literalizer.rb +50 -21
  101. data/lib/sequel/dataset/prepared_statements.rb +96 -26
  102. data/lib/sequel/dataset/query.rb +43 -8
  103. data/lib/sequel/dataset/sql.rb +189 -41
  104. data/lib/sequel/deprecated.rb +3 -1
  105. data/lib/sequel/exceptions.rb +2 -0
  106. data/lib/sequel/extensions/_pretty_table.rb +1 -2
  107. data/lib/sequel/extensions/any_not_empty.rb +45 -0
  108. data/lib/sequel/extensions/caller_logging.rb +79 -0
  109. data/lib/sequel/extensions/columns_introspection.rb +1 -2
  110. data/lib/sequel/extensions/connection_expiration.rb +6 -6
  111. data/lib/sequel/extensions/connection_validator.rb +7 -6
  112. data/lib/sequel/extensions/constant_sql_override.rb +65 -0
  113. data/lib/sequel/extensions/constraint_validations.rb +53 -28
  114. data/lib/sequel/extensions/core_refinements.rb +2 -0
  115. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -0
  116. data/lib/sequel/extensions/escaped_like.rb +100 -0
  117. data/lib/sequel/extensions/eval_inspect.rb +3 -1
  118. data/lib/sequel/extensions/exclude_or_null.rb +68 -0
  119. data/lib/sequel/extensions/fiber_concurrency.rb +24 -0
  120. data/lib/sequel/extensions/index_caching.rb +9 -7
  121. data/lib/sequel/extensions/integer64.rb +3 -1
  122. data/lib/sequel/extensions/looser_typecasting.rb +3 -3
  123. data/lib/sequel/extensions/migration.rb +13 -6
  124. data/lib/sequel/extensions/named_timezones.rb +84 -23
  125. data/lib/sequel/extensions/pg_array.rb +87 -79
  126. data/lib/sequel/extensions/pg_array_ops.rb +14 -6
  127. data/lib/sequel/extensions/pg_enum.rb +34 -18
  128. data/lib/sequel/extensions/pg_extended_date_support.rb +34 -14
  129. data/lib/sequel/extensions/pg_hstore.rb +6 -0
  130. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  131. data/lib/sequel/extensions/pg_inet.rb +15 -5
  132. data/lib/sequel/extensions/pg_interval.rb +2 -0
  133. data/lib/sequel/extensions/pg_json.rb +387 -123
  134. data/lib/sequel/extensions/pg_json_ops.rb +168 -0
  135. data/lib/sequel/extensions/pg_range.rb +20 -10
  136. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  137. data/lib/sequel/extensions/pg_row.rb +3 -2
  138. data/lib/sequel/extensions/pg_row_ops.rb +24 -0
  139. data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -2
  140. data/lib/sequel/extensions/pg_timestamptz.rb +2 -0
  141. data/lib/sequel/extensions/query.rb +1 -0
  142. data/lib/sequel/extensions/run_transaction_hooks.rb +72 -0
  143. data/lib/sequel/extensions/s.rb +2 -0
  144. data/lib/sequel/extensions/schema_dumper.rb +13 -7
  145. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +4 -2
  146. data/lib/sequel/extensions/server_block.rb +18 -7
  147. data/lib/sequel/extensions/sql_comments.rb +2 -2
  148. data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
  149. data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
  150. data/lib/sequel/extensions/to_dot.rb +9 -3
  151. data/lib/sequel/model.rb +3 -1
  152. data/lib/sequel/model/associations.rb +403 -69
  153. data/lib/sequel/model/base.rb +170 -90
  154. data/lib/sequel/model/plugins.rb +105 -0
  155. data/lib/sequel/plugins/after_initialize.rb +1 -1
  156. data/lib/sequel/plugins/association_dependencies.rb +3 -3
  157. data/lib/sequel/plugins/association_lazy_eager_option.rb +66 -0
  158. data/lib/sequel/plugins/association_multi_add_remove.rb +85 -0
  159. data/lib/sequel/plugins/association_pks.rb +74 -22
  160. data/lib/sequel/plugins/association_proxies.rb +6 -2
  161. data/lib/sequel/plugins/auto_validations.rb +36 -17
  162. data/lib/sequel/plugins/blacklist_security.rb +1 -2
  163. data/lib/sequel/plugins/boolean_subsets.rb +4 -1
  164. data/lib/sequel/plugins/caching.rb +3 -0
  165. data/lib/sequel/plugins/class_table_inheritance.rb +62 -34
  166. data/lib/sequel/plugins/composition.rb +13 -9
  167. data/lib/sequel/plugins/csv_serializer.rb +28 -9
  168. data/lib/sequel/plugins/defaults_setter.rb +2 -2
  169. data/lib/sequel/plugins/dirty.rb +60 -22
  170. data/lib/sequel/plugins/eager_graph_eager.rb +139 -0
  171. data/lib/sequel/plugins/empty_failure_backtraces.rb +38 -0
  172. data/lib/sequel/plugins/finder.rb +2 -2
  173. data/lib/sequel/plugins/forbid_lazy_load.rb +216 -0
  174. data/lib/sequel/plugins/hook_class_methods.rb +17 -5
  175. data/lib/sequel/plugins/insert_conflict.rb +72 -0
  176. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  177. data/lib/sequel/plugins/inverted_subsets.rb +2 -2
  178. data/lib/sequel/plugins/json_serializer.rb +21 -14
  179. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  180. data/lib/sequel/plugins/list.rb +22 -10
  181. data/lib/sequel/plugins/many_through_many.rb +1 -1
  182. data/lib/sequel/plugins/nested_attributes.rb +27 -5
  183. data/lib/sequel/plugins/pg_array_associations.rb +12 -9
  184. data/lib/sequel/plugins/pg_auto_constraint_validations.rb +149 -61
  185. data/lib/sequel/plugins/prepared_statements.rb +6 -12
  186. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
  187. data/lib/sequel/plugins/rcte_tree.rb +20 -22
  188. data/lib/sequel/plugins/sharding.rb +13 -7
  189. data/lib/sequel/plugins/single_table_inheritance.rb +20 -15
  190. data/lib/sequel/plugins/skip_saving_columns.rb +108 -0
  191. data/lib/sequel/plugins/static_cache.rb +36 -17
  192. data/lib/sequel/plugins/static_cache_cache.rb +53 -0
  193. data/lib/sequel/plugins/string_stripper.rb +1 -1
  194. data/lib/sequel/plugins/subclasses.rb +2 -0
  195. data/lib/sequel/plugins/subset_conditions.rb +2 -2
  196. data/lib/sequel/plugins/tactical_eager_loading.rb +73 -2
  197. data/lib/sequel/plugins/throw_failures.rb +110 -0
  198. data/lib/sequel/plugins/tree.rb +49 -31
  199. data/lib/sequel/plugins/typecast_on_load.rb +3 -2
  200. data/lib/sequel/plugins/validation_class_methods.rb +11 -5
  201. data/lib/sequel/plugins/validation_helpers.rb +2 -2
  202. data/lib/sequel/sql.rb +120 -30
  203. data/lib/sequel/timezones.rb +55 -14
  204. data/lib/sequel/version.rb +6 -1
  205. metadata +101 -361
  206. data/Rakefile +0 -151
  207. data/doc/release_notes/4.0.0.txt +0 -262
  208. data/doc/release_notes/4.1.0.txt +0 -85
  209. data/doc/release_notes/4.10.0.txt +0 -226
  210. data/doc/release_notes/4.11.0.txt +0 -147
  211. data/doc/release_notes/4.12.0.txt +0 -105
  212. data/doc/release_notes/4.13.0.txt +0 -169
  213. data/doc/release_notes/4.14.0.txt +0 -68
  214. data/doc/release_notes/4.15.0.txt +0 -56
  215. data/doc/release_notes/4.16.0.txt +0 -36
  216. data/doc/release_notes/4.17.0.txt +0 -38
  217. data/doc/release_notes/4.18.0.txt +0 -36
  218. data/doc/release_notes/4.19.0.txt +0 -45
  219. data/doc/release_notes/4.2.0.txt +0 -129
  220. data/doc/release_notes/4.20.0.txt +0 -79
  221. data/doc/release_notes/4.21.0.txt +0 -94
  222. data/doc/release_notes/4.22.0.txt +0 -72
  223. data/doc/release_notes/4.23.0.txt +0 -65
  224. data/doc/release_notes/4.24.0.txt +0 -99
  225. data/doc/release_notes/4.25.0.txt +0 -181
  226. data/doc/release_notes/4.26.0.txt +0 -44
  227. data/doc/release_notes/4.27.0.txt +0 -78
  228. data/doc/release_notes/4.28.0.txt +0 -57
  229. data/doc/release_notes/4.29.0.txt +0 -41
  230. data/doc/release_notes/4.3.0.txt +0 -40
  231. data/doc/release_notes/4.30.0.txt +0 -37
  232. data/doc/release_notes/4.31.0.txt +0 -57
  233. data/doc/release_notes/4.32.0.txt +0 -132
  234. data/doc/release_notes/4.33.0.txt +0 -88
  235. data/doc/release_notes/4.34.0.txt +0 -86
  236. data/doc/release_notes/4.35.0.txt +0 -130
  237. data/doc/release_notes/4.36.0.txt +0 -116
  238. data/doc/release_notes/4.37.0.txt +0 -50
  239. data/doc/release_notes/4.38.0.txt +0 -67
  240. data/doc/release_notes/4.39.0.txt +0 -127
  241. data/doc/release_notes/4.4.0.txt +0 -92
  242. data/doc/release_notes/4.40.0.txt +0 -179
  243. data/doc/release_notes/4.41.0.txt +0 -77
  244. data/doc/release_notes/4.42.0.txt +0 -221
  245. data/doc/release_notes/4.43.0.txt +0 -87
  246. data/doc/release_notes/4.44.0.txt +0 -125
  247. data/doc/release_notes/4.45.0.txt +0 -370
  248. data/doc/release_notes/4.46.0.txt +0 -404
  249. data/doc/release_notes/4.47.0.txt +0 -56
  250. data/doc/release_notes/4.48.0.txt +0 -293
  251. data/doc/release_notes/4.49.0.txt +0 -222
  252. data/doc/release_notes/4.5.0.txt +0 -34
  253. data/doc/release_notes/4.6.0.txt +0 -30
  254. data/doc/release_notes/4.7.0.txt +0 -103
  255. data/doc/release_notes/4.8.0.txt +0 -175
  256. data/doc/release_notes/4.9.0.txt +0 -190
  257. data/spec/adapter_spec.rb +0 -4
  258. data/spec/adapters/db2_spec.rb +0 -170
  259. data/spec/adapters/mssql_spec.rb +0 -804
  260. data/spec/adapters/mysql_spec.rb +0 -1041
  261. data/spec/adapters/oracle_spec.rb +0 -327
  262. data/spec/adapters/postgres_spec.rb +0 -4000
  263. data/spec/adapters/spec_helper.rb +0 -43
  264. data/spec/adapters/sqlanywhere_spec.rb +0 -97
  265. data/spec/adapters/sqlite_spec.rb +0 -600
  266. data/spec/bin_spec.rb +0 -269
  267. data/spec/core/connection_pool_spec.rb +0 -1228
  268. data/spec/core/database_spec.rb +0 -2673
  269. data/spec/core/dataset_spec.rb +0 -5419
  270. data/spec/core/deprecated_spec.rb +0 -70
  271. data/spec/core/expression_filters_spec.rb +0 -1344
  272. data/spec/core/mock_adapter_spec.rb +0 -722
  273. data/spec/core/object_graph_spec.rb +0 -306
  274. data/spec/core/placeholder_literalizer_spec.rb +0 -166
  275. data/spec/core/schema_generator_spec.rb +0 -214
  276. data/spec/core/schema_spec.rb +0 -1820
  277. data/spec/core/spec_helper.rb +0 -23
  278. data/spec/core/version_spec.rb +0 -7
  279. data/spec/core_extensions_spec.rb +0 -762
  280. data/spec/core_model_spec.rb +0 -2
  281. data/spec/core_spec.rb +0 -1
  282. data/spec/deprecation_helper.rb +0 -30
  283. data/spec/extensions/accessed_columns_spec.rb +0 -51
  284. data/spec/extensions/active_model_spec.rb +0 -99
  285. data/spec/extensions/after_initialize_spec.rb +0 -24
  286. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  287. data/spec/extensions/association_dependencies_spec.rb +0 -125
  288. data/spec/extensions/association_pks_spec.rb +0 -423
  289. data/spec/extensions/association_proxies_spec.rb +0 -100
  290. data/spec/extensions/auto_literal_strings_spec.rb +0 -205
  291. data/spec/extensions/auto_validations_spec.rb +0 -202
  292. data/spec/extensions/blacklist_security_spec.rb +0 -95
  293. data/spec/extensions/blank_spec.rb +0 -69
  294. data/spec/extensions/boolean_readers_spec.rb +0 -93
  295. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  296. data/spec/extensions/caching_spec.rb +0 -273
  297. data/spec/extensions/class_table_inheritance_spec.rb +0 -568
  298. data/spec/extensions/column_conflicts_spec.rb +0 -75
  299. data/spec/extensions/column_select_spec.rb +0 -129
  300. data/spec/extensions/columns_introspection_spec.rb +0 -90
  301. data/spec/extensions/columns_updated_spec.rb +0 -35
  302. data/spec/extensions/composition_spec.rb +0 -248
  303. data/spec/extensions/connection_expiration_spec.rb +0 -133
  304. data/spec/extensions/connection_validator_spec.rb +0 -127
  305. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -300
  306. data/spec/extensions/constraint_validations_spec.rb +0 -395
  307. data/spec/extensions/core_refinements_spec.rb +0 -528
  308. data/spec/extensions/csv_serializer_spec.rb +0 -183
  309. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  310. data/spec/extensions/dataset_associations_spec.rb +0 -365
  311. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  312. data/spec/extensions/date_arithmetic_spec.rb +0 -181
  313. data/spec/extensions/datetime_parse_to_time_spec.rb +0 -169
  314. data/spec/extensions/def_dataset_method_spec.rb +0 -100
  315. data/spec/extensions/defaults_setter_spec.rb +0 -141
  316. data/spec/extensions/delay_add_association_spec.rb +0 -73
  317. data/spec/extensions/dirty_spec.rb +0 -189
  318. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -104
  319. data/spec/extensions/eager_each_spec.rb +0 -62
  320. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  321. data/spec/extensions/error_splitter_spec.rb +0 -18
  322. data/spec/extensions/error_sql_spec.rb +0 -20
  323. data/spec/extensions/eval_inspect_spec.rb +0 -74
  324. data/spec/extensions/finder_spec.rb +0 -260
  325. data/spec/extensions/force_encoding_spec.rb +0 -126
  326. data/spec/extensions/freeze_datasets_spec.rb +0 -31
  327. data/spec/extensions/graph_each_spec.rb +0 -113
  328. data/spec/extensions/hook_class_methods_spec.rb +0 -380
  329. data/spec/extensions/identifier_mangling_spec.rb +0 -201
  330. data/spec/extensions/implicit_subquery_spec.rb +0 -58
  331. data/spec/extensions/index_caching_spec.rb +0 -66
  332. data/spec/extensions/inflector_spec.rb +0 -183
  333. data/spec/extensions/input_transformer_spec.rb +0 -69
  334. data/spec/extensions/insert_returning_select_spec.rb +0 -72
  335. data/spec/extensions/instance_filters_spec.rb +0 -79
  336. data/spec/extensions/instance_hooks_spec.rb +0 -246
  337. data/spec/extensions/integer64_spec.rb +0 -22
  338. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  339. data/spec/extensions/json_serializer_spec.rb +0 -336
  340. data/spec/extensions/lazy_attributes_spec.rb +0 -183
  341. data/spec/extensions/list_spec.rb +0 -275
  342. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  343. data/spec/extensions/many_through_many_spec.rb +0 -2177
  344. data/spec/extensions/migration_spec.rb +0 -840
  345. data/spec/extensions/modification_detection_spec.rb +0 -93
  346. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -92
  347. data/spec/extensions/named_timezones_spec.rb +0 -109
  348. data/spec/extensions/nested_attributes_spec.rb +0 -703
  349. data/spec/extensions/null_dataset_spec.rb +0 -85
  350. data/spec/extensions/optimistic_locking_spec.rb +0 -127
  351. data/spec/extensions/pagination_spec.rb +0 -116
  352. data/spec/extensions/pg_array_associations_spec.rb +0 -802
  353. data/spec/extensions/pg_array_ops_spec.rb +0 -144
  354. data/spec/extensions/pg_array_spec.rb +0 -398
  355. data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -165
  356. data/spec/extensions/pg_enum_spec.rb +0 -113
  357. data/spec/extensions/pg_extended_date_support_spec.rb +0 -126
  358. data/spec/extensions/pg_hstore_ops_spec.rb +0 -238
  359. data/spec/extensions/pg_hstore_spec.rb +0 -219
  360. data/spec/extensions/pg_inet_ops_spec.rb +0 -102
  361. data/spec/extensions/pg_inet_spec.rb +0 -72
  362. data/spec/extensions/pg_interval_spec.rb +0 -103
  363. data/spec/extensions/pg_json_ops_spec.rb +0 -289
  364. data/spec/extensions/pg_json_spec.rb +0 -262
  365. data/spec/extensions/pg_loose_count_spec.rb +0 -23
  366. data/spec/extensions/pg_range_ops_spec.rb +0 -60
  367. data/spec/extensions/pg_range_spec.rb +0 -487
  368. data/spec/extensions/pg_row_ops_spec.rb +0 -61
  369. data/spec/extensions/pg_row_plugin_spec.rb +0 -60
  370. data/spec/extensions/pg_row_spec.rb +0 -363
  371. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -93
  372. data/spec/extensions/pg_timestamptz_spec.rb +0 -17
  373. data/spec/extensions/prepared_statements_safe_spec.rb +0 -66
  374. data/spec/extensions/prepared_statements_spec.rb +0 -182
  375. data/spec/extensions/pretty_table_spec.rb +0 -123
  376. data/spec/extensions/query_spec.rb +0 -94
  377. data/spec/extensions/rcte_tree_spec.rb +0 -381
  378. data/spec/extensions/round_timestamps_spec.rb +0 -39
  379. data/spec/extensions/s_spec.rb +0 -60
  380. data/spec/extensions/schema_caching_spec.rb +0 -64
  381. data/spec/extensions/schema_dumper_spec.rb +0 -868
  382. data/spec/extensions/select_remove_spec.rb +0 -38
  383. data/spec/extensions/sequel_4_dataset_methods_spec.rb +0 -121
  384. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  385. data/spec/extensions/serialization_spec.rb +0 -365
  386. data/spec/extensions/server_block_spec.rb +0 -97
  387. data/spec/extensions/server_logging_spec.rb +0 -45
  388. data/spec/extensions/sharding_spec.rb +0 -189
  389. data/spec/extensions/shared_caching_spec.rb +0 -151
  390. data/spec/extensions/single_table_inheritance_spec.rb +0 -347
  391. data/spec/extensions/singular_table_names_spec.rb +0 -22
  392. data/spec/extensions/skip_create_refresh_spec.rb +0 -18
  393. data/spec/extensions/spec_helper.rb +0 -61
  394. data/spec/extensions/split_array_nil_spec.rb +0 -24
  395. data/spec/extensions/split_values_spec.rb +0 -57
  396. data/spec/extensions/sql_comments_spec.rb +0 -33
  397. data/spec/extensions/sql_expr_spec.rb +0 -59
  398. data/spec/extensions/static_cache_spec.rb +0 -410
  399. data/spec/extensions/string_agg_spec.rb +0 -90
  400. data/spec/extensions/string_date_time_spec.rb +0 -95
  401. data/spec/extensions/string_stripper_spec.rb +0 -68
  402. data/spec/extensions/subclasses_spec.rb +0 -79
  403. data/spec/extensions/subset_conditions_spec.rb +0 -38
  404. data/spec/extensions/symbol_aref_refinement_spec.rb +0 -28
  405. data/spec/extensions/symbol_as_refinement_spec.rb +0 -21
  406. data/spec/extensions/synchronize_sql_spec.rb +0 -124
  407. data/spec/extensions/table_select_spec.rb +0 -83
  408. data/spec/extensions/tactical_eager_loading_spec.rb +0 -141
  409. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  410. data/spec/extensions/timestamps_spec.rb +0 -209
  411. data/spec/extensions/to_dot_spec.rb +0 -153
  412. data/spec/extensions/touch_spec.rb +0 -226
  413. data/spec/extensions/tree_spec.rb +0 -284
  414. data/spec/extensions/typecast_on_load_spec.rb +0 -86
  415. data/spec/extensions/unlimited_update_spec.rb +0 -21
  416. data/spec/extensions/update_or_create_spec.rb +0 -83
  417. data/spec/extensions/update_primary_key_spec.rb +0 -105
  418. data/spec/extensions/update_refresh_spec.rb +0 -59
  419. data/spec/extensions/uuid_spec.rb +0 -101
  420. data/spec/extensions/validate_associated_spec.rb +0 -52
  421. data/spec/extensions/validation_class_methods_spec.rb +0 -1040
  422. data/spec/extensions/validation_contexts_spec.rb +0 -31
  423. data/spec/extensions/validation_helpers_spec.rb +0 -525
  424. data/spec/extensions/whitelist_security_spec.rb +0 -157
  425. data/spec/extensions/xml_serializer_spec.rb +0 -213
  426. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  427. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  428. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  429. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  430. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  431. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  432. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  433. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  434. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  435. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  436. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  437. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  438. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  439. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  440. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  441. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  442. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  443. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  444. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  445. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  446. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  447. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  448. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  449. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  450. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  451. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  452. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  453. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  454. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  455. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  456. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  457. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  458. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  459. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  460. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  461. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  462. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  463. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  464. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  465. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  466. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  467. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  468. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  469. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  470. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  471. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  472. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  473. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  474. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  475. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  476. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  477. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  478. data/spec/guards_helper.rb +0 -58
  479. data/spec/integration/associations_test.rb +0 -2513
  480. data/spec/integration/database_test.rb +0 -113
  481. data/spec/integration/dataset_test.rb +0 -1880
  482. data/spec/integration/eager_loader_test.rb +0 -687
  483. data/spec/integration/migrator_test.rb +0 -262
  484. data/spec/integration/model_test.rb +0 -203
  485. data/spec/integration/plugin_test.rb +0 -2302
  486. data/spec/integration/prepared_statement_test.rb +0 -398
  487. data/spec/integration/schema_test.rb +0 -869
  488. data/spec/integration/spec_helper.rb +0 -64
  489. data/spec/integration/timezone_test.rb +0 -86
  490. data/spec/integration/transaction_test.rb +0 -354
  491. data/spec/integration/type_test.rb +0 -127
  492. data/spec/model/association_reflection_spec.rb +0 -803
  493. data/spec/model/associations_spec.rb +0 -4538
  494. data/spec/model/base_spec.rb +0 -817
  495. data/spec/model/class_dataset_methods_spec.rb +0 -146
  496. data/spec/model/dataset_methods_spec.rb +0 -198
  497. data/spec/model/eager_loading_spec.rb +0 -2262
  498. data/spec/model/hooks_spec.rb +0 -370
  499. data/spec/model/inflector_spec.rb +0 -26
  500. data/spec/model/model_spec.rb +0 -953
  501. data/spec/model/plugins_spec.rb +0 -318
  502. data/spec/model/record_spec.rb +0 -2107
  503. data/spec/model/spec_helper.rb +0 -45
  504. data/spec/model/validations_spec.rb +0 -193
  505. data/spec/model_no_assoc_spec.rb +0 -1
  506. data/spec/model_spec.rb +0 -1
  507. data/spec/plugin_spec.rb +0 -1
  508. data/spec/sequel_coverage.rb +0 -15
  509. data/spec/sequel_warning.rb +0 -4
  510. data/spec/spec_config.rb +0 -12
@@ -1,85 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "null_dataset extension" do
4
- before do
5
- @db = Sequel::mock(:fetch=>{:id=>1}, :autoid=>1, :numrows=>1, :columns=>[:id]).extension(:null_dataset)
6
- @ds = @db[:table].nullify
7
- @i = 0
8
- @pr = proc{|*a| @i += 1}
9
- end
10
- after do
11
- @db.sqls.must_equal [] unless @skip_check
12
- end
13
-
14
- it "should make each be a noop" do
15
- @ds.each(&@pr).must_be_same_as(@ds)
16
- @i.must_equal 0
17
- end
18
-
19
- it "should make fetch_rows be a noop" do
20
- @ds.fetch_rows("SELECT 1", &@pr).must_be_nil
21
- @i.must_equal 0
22
- end
23
-
24
- it "nullify should be a cached dataset" do
25
- ds = @db[:table]
26
- ds.nullify.object_id.must_equal(ds.nullify.object_id)
27
- end
28
-
29
- it "should make insert be a noop" do
30
- @ds.insert(1).must_be_nil
31
- end
32
-
33
- it "should make update be a noop" do
34
- @ds.update(:a=>1).must_equal 0
35
- end
36
-
37
- it "should make delete be a noop" do
38
- @ds.delete.must_equal 0
39
- end
40
-
41
- it "should make truncate be a noop" do
42
- @ds.truncate.must_be_nil
43
- end
44
-
45
- it "should make execute_* be a noop" do
46
- @ds.send(:execute_ddl,'FOO').must_be_nil
47
- @ds.send(:execute_insert,'FOO').must_be_nil
48
- @ds.send(:execute_dui,'FOO').must_be_nil
49
- @ds.send(:execute,'FOO').must_be_nil
50
- end
51
-
52
- it "should have working columns" do
53
- @skip_check = true
54
- 2.times do
55
- @ds.columns.must_equal [:id]
56
- end
57
- @db.sqls.must_equal ['SELECT * FROM table LIMIT 1']
58
- end
59
-
60
- it "should have count return 0" do
61
- @ds.count.must_equal 0
62
- end
63
-
64
- it "should have empty return true" do
65
- @ds.empty?.must_equal true
66
- end
67
-
68
- it "should make import a noop" do
69
- @ds.import([:id], [[1], [2], [3]]).must_be_nil
70
- end
71
-
72
- it "should have nullify method returned modified receiver" do
73
- @skip_check = true
74
- ds = @db[:table]
75
- ds.nullify.wont_be_same_as(ds)
76
- ds.each(&@pr)
77
- @db.sqls.must_equal ['SELECT * FROM table']
78
- @i.must_equal 1
79
- end
80
-
81
- it "should work with method chaining" do
82
- @ds.where(:a=>1).select(:b).each(&@pr)
83
- @i.must_equal 0
84
- end
85
- end
@@ -1,127 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "optimistic_locking plugin" do
4
- before do
5
- @c = Class.new(Sequel::Model(:people)) do
6
- end
7
- h = {1=>{:id=>1, :name=>'John', :lock_version=>2}}
8
- lv = @lv = "lock_version".dup
9
- @c.dataset = @c.dataset.with_numrows(proc do |sql|
10
- case sql
11
- when /UPDATE people SET (name|#{lv}) = ('Jim'|'Bob'|\d+), (?:name|#{lv}) = ('Jim'|'Bob'|\d+) WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
12
- name, nlv = $1 == 'name' ? [$2, $3] : [$3, $2]
13
- m = h[$4.to_i]
14
- if m && m[:lock_version] == $5.to_i
15
- m.merge!(:name=>name.gsub("'", ''), :lock_version=>nlv.to_i)
16
- 1
17
- else
18
- 0
19
- end
20
- when /UPDATE people SET #{lv} = (\d+) WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
21
- m = h[$2.to_i]
22
- if m && m[:lock_version] == $3.to_i
23
- m.merge!(:lock_version=>$1.to_i)
24
- 1
25
- else
26
- 0
27
- end
28
- when /DELETE FROM people WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
29
- m = h[$1.to_i]
30
- if m && m[lv.to_sym] == $2.to_i
31
- h.delete[$1.to_i]
32
- 1
33
- else
34
- 0
35
- end
36
- else
37
- puts sql
38
- end
39
- end).with_fetch(proc do |sql|
40
- m = h[1].dup
41
- v = m.delete(:lock_version)
42
- m[lv.to_sym] = v
43
- m
44
- end)
45
- @c.columns :id, :name, :lock_version
46
- @c.plugin :optimistic_locking
47
- end
48
-
49
- it "should raise an error when updating a stale record" do
50
- p1 = @c[1]
51
- p2 = @c[1]
52
- p1.update(:name=>'Jim')
53
- proc{p2.update(:name=>'Bob')}.must_raise(Sequel::Plugins::OptimisticLocking::Error)
54
- end
55
-
56
- it "should raise an error when destroying a stale record" do
57
- p1 = @c[1]
58
- p2 = @c[1]
59
- p1.update(:name=>'Jim')
60
- proc{p2.destroy}.must_raise(Sequel::Plugins::OptimisticLocking::Error)
61
- end
62
-
63
- it "should not raise an error when updating the same record twice" do
64
- p1 = @c[1]
65
- p1.update(:name=>'Jim')
66
- p1.update(:name=>'Bob')
67
- end
68
-
69
- it "should allow changing the lock column via model.lock_column=" do
70
- @lv.replace('lv')
71
- @c.columns :id, :name, :lv
72
- @c.lock_column = :lv
73
- p1 = @c[1]
74
- p2 = @c[1]
75
- p1.update(:name=>'Jim')
76
- proc{p2.update(:name=>'Bob')}.must_raise(Sequel::Plugins::OptimisticLocking::Error)
77
- end
78
-
79
- it "should allow changing the lock column via plugin option" do
80
- @lv.replace('lv')
81
- @c.columns :id, :name, :lv
82
- @c.plugin :optimistic_locking, :lock_column=>:lv
83
- p1 = @c[1]
84
- p2 = @c[1]
85
- p1.update(:name=>'Jim')
86
- proc{p2.destroy}.must_raise(Sequel::Plugins::OptimisticLocking::Error)
87
- end
88
-
89
- it "should work when subclassing" do
90
- c = Class.new(@c)
91
- p1 = c[1]
92
- p2 = c[1]
93
- p1.update(:name=>'Jim')
94
- proc{p2.update(:name=>'Bob')}.must_raise(Sequel::Plugins::OptimisticLocking::Error)
95
- end
96
-
97
- it "should work correctly if attempting to refresh and save again after a failed save" do
98
- p1 = @c[1]
99
- p2 = @c[1]
100
- p1.update(:name=>'Jim')
101
- begin
102
- p2.update(:name=>'Bob')
103
- rescue Sequel::Plugins::OptimisticLocking::Error
104
- p2.refresh
105
- @c.db.sqls
106
- p2.update(:name=>'Bob')
107
- end
108
- @c.db.sqls.must_equal ["UPDATE people SET name = 'Bob', lock_version = 4 WHERE ((id = 1) AND (lock_version = 3))"]
109
- end
110
-
111
- it "should increment the lock column when #modified! even if no columns are changed" do
112
- p1 = @c[1]
113
- p1.modified!
114
- lv = p1.lock_version
115
- p1.save_changes
116
- p1.lock_version.must_equal lv + 1
117
- end
118
-
119
- it "should not increment the lock column when the update fails" do
120
- @c.dataset = @c.dataset.with_extend{def update(_) raise end}
121
- p1 = @c[1]
122
- p1.modified!
123
- lv = p1.lock_version
124
- proc{p1.save_changes}.must_raise(RuntimeError)
125
- p1.lock_version.must_equal lv
126
- end
127
- end
@@ -1,116 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "A paginated dataset" do
4
- before do
5
- count = @count = [153]
6
- @d = Sequel.mock.dataset.extension(:pagination).with_extend{define_method(:count){count.first}}
7
- @paginated = @d.paginate(1, 20)
8
- end
9
-
10
- it "should raise an error if the dataset already has a limit" do
11
- proc{@d.limit(10).paginate(1,10)}.must_raise(Sequel::Error)
12
- proc{@paginated.paginate(2,20)}.must_raise(Sequel::Error)
13
- proc{@d.limit(10).each_page(10){|ds|}}.must_raise(Sequel::Error)
14
- proc{@d.limit(10).each_page(10)}.must_raise(Sequel::Error)
15
- end
16
-
17
- it "should set the limit and offset options correctly" do
18
- @paginated.opts[:limit].must_equal 20
19
- @paginated.opts[:offset].must_equal 0
20
- end
21
-
22
- it "should set the page count correctly" do
23
- @paginated.page_count.must_equal 8
24
- @d.paginate(1, 50).page_count.must_equal 4
25
-
26
- @count[0] = 0
27
- @d.paginate(1, 50).page_count.must_equal 1
28
- end
29
-
30
- it "should set the current page number correctly" do
31
- @paginated.current_page.must_equal 1
32
- @d.paginate(3, 50).current_page.must_equal 3
33
- end
34
-
35
- it "should return the next page number or nil if we're on the last" do
36
- @paginated.next_page.must_equal 2
37
- @d.paginate(4, 50).next_page.must_be_nil
38
- end
39
-
40
- it "should return the previous page number or nil if we're on the first" do
41
- @paginated.prev_page.must_be_nil
42
- @d.paginate(4, 50).prev_page.must_equal 3
43
- end
44
-
45
- it "should return the page range" do
46
- @paginated.page_range.must_equal(1..8)
47
- @d.paginate(4, 50).page_range.must_equal(1..4)
48
- end
49
-
50
- it "should return the record range for the current page" do
51
- @paginated.current_page_record_range.must_equal(1..20)
52
- @d.paginate(4, 50).current_page_record_range.must_equal(151..153)
53
- @d.paginate(5, 50).current_page_record_range.must_equal(0..0)
54
- end
55
-
56
- it "should return the record count for the current page" do
57
- @paginated.current_page_record_count.must_equal 20
58
- @d.paginate(3, 50).current_page_record_count.must_equal 50
59
- @d.paginate(4, 50).current_page_record_count.must_equal 3
60
- @d.paginate(5, 50).current_page_record_count.must_equal 0
61
- end
62
-
63
- it "should know if current page is last page" do
64
- @paginated.last_page?.must_equal false
65
- @d.paginate(2, 20).last_page?.must_equal false
66
- @d.paginate(5, 30).last_page?.must_equal false
67
- @d.paginate(6, 30).last_page?.must_equal true
68
-
69
- @count[0] = 0
70
- @d.paginate(1, 30).last_page?.must_equal true
71
- @d.paginate(2, 30).last_page?.must_equal false
72
- end
73
-
74
- it "should know if current page is first page" do
75
- @paginated.first_page?.must_equal true
76
- @d.paginate(1, 20).first_page?.must_equal true
77
- @d.paginate(2, 20).first_page?.must_equal false
78
- end
79
-
80
- it "should work with fixed sql" do
81
- ds = @d.clone(:sql => 'select * from blah')
82
- @count[0] = 150
83
- ds.paginate(2, 50).sql.must_equal 'SELECT * FROM (select * from blah) AS t1 LIMIT 50 OFFSET 50'
84
- end
85
- end
86
-
87
- describe "Dataset#each_page" do
88
- before do
89
- @d = Sequel.mock[:items].extension(:pagination).with_extend{def count; 153 end}
90
- end
91
-
92
- it "should raise an error if the dataset already has a limit" do
93
- proc{@d.limit(10).each_page(10){}}.must_raise(Sequel::Error)
94
- end
95
-
96
- it "should iterate over each page in the resultset as a paginated dataset" do
97
- a = []
98
- @d.each_page(50) {|p| a << p}
99
- a.map {|p| p.sql}.must_equal [
100
- 'SELECT * FROM items LIMIT 50 OFFSET 0',
101
- 'SELECT * FROM items LIMIT 50 OFFSET 50',
102
- 'SELECT * FROM items LIMIT 50 OFFSET 100',
103
- 'SELECT * FROM items LIMIT 50 OFFSET 150',
104
- ]
105
- end
106
-
107
- it "should return an enumerator if no block is given" do
108
- enum = @d.each_page(50)
109
- enum.map {|p| p.sql}.must_equal [
110
- 'SELECT * FROM items LIMIT 50 OFFSET 0',
111
- 'SELECT * FROM items LIMIT 50 OFFSET 50',
112
- 'SELECT * FROM items LIMIT 50 OFFSET 100',
113
- 'SELECT * FROM items LIMIT 50 OFFSET 150',
114
- ]
115
- end
116
- end
@@ -1,802 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe Sequel::Model, "pg_array_associations" do
4
- before do
5
- @db = Sequel.mock(:host=>'postgres', :numrows=>1)
6
- @db.extend_datasets{def quote_identifiers?; false end}
7
- class ::Artist < Sequel::Model(@db)
8
- attr_accessor :yyy
9
- columns :id, :tag_ids
10
- plugin :pg_array_associations
11
- pg_array_to_many :tags
12
- pg_array_to_many :a_tags, :clone=>:tags, :conditions=>{:name=>'A'}, :key=>:tag_ids
13
- end
14
- class ::Tag < Sequel::Model(@db)
15
- columns :id
16
- plugin :pg_array_associations
17
- many_to_pg_array :artists
18
- many_to_pg_array :a_artists, :clone=>:artists, :conditions=>{:name=>'A'}
19
- def id3
20
- id*3
21
- end
22
- end
23
- @c1 = Artist
24
- @c2 = Tag
25
- @c1.dataset = @c1.dataset.with_fetch(:id=>1, :tag_ids=>Sequel.pg_array([1,2,3]))
26
- @c2.dataset = @c2.dataset.with_fetch(:id=>2)
27
- @o1 = @c1.first
28
- @o2 = @c2.first
29
- @n1 = @c1.new
30
- @n2 = @c2.new
31
- @db.sqls
32
- end
33
- after do
34
- Object.send(:remove_const, :Artist)
35
- Object.send(:remove_const, :Tag)
36
- end
37
-
38
- it "should populate :key_hash and :id_map option correctly for custom eager loaders" do
39
- khs = []
40
- pr = proc{|h| khs << [h[:key_hash], h[:id_map]]}
41
- @c1.pg_array_to_many :tags, :clone=>:tags, :eager_loader=>pr
42
- @c2.many_to_pg_array :artists, :clone=>:artists, :eager_loader=>pr
43
- @c1.eager(:tags).all
44
- @c2.eager(:artists).all
45
- khs.must_equal [[{}, nil], [{:id=>{2=>[Tag.load(:id=>2)]}}, {2=>[Tag.load(:id=>2)]}]]
46
- end
47
-
48
- it "should not issue queries if the object cannot have associated objects" do
49
- @n1.tags.must_equal []
50
- @c1.load(:tag_ids=>[]).tags.must_equal []
51
- @n2.artists.must_equal []
52
- @db.sqls.must_equal []
53
- end
54
-
55
- it "should use correct SQL when loading associations lazily" do
56
- @o1.tags.must_equal [@o2]
57
- @o2.artists.must_equal [@o1]
58
- @db.sqls.must_equal ["SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))", "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2]::integer[])"]
59
- end
60
-
61
- it "should accept :primary_key option for primary keys to use in current and associated table" do
62
- @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>Sequel./(:id, 3)
63
- @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>:id3
64
- @o1.tags_dataset.sql.must_equal "SELECT * FROM tags WHERE ((tags.id / 3) IN (1, 2, 3))"
65
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[6]::integer[])"
66
- end
67
-
68
- it "should allowing filtering by associations" do
69
- @c1.filter(:tags=>@o2).sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2]::integer[])"
70
- @c2.filter(:artists=>@o1).sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))"
71
- end
72
-
73
- it "should allowing filtering by associations with :conditions" do
74
- @c1.filter(:a_tags=>@o2).sql.must_equal "SELECT * FROM artists WHERE coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE ((name = 'A') AND (tags.id IS NOT NULL) AND (tags.id = 2)))), false)"
75
- @c2.filter(:a_artists=>@o1).sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (SELECT unnest(artists.tag_ids) FROM artists WHERE ((name = 'A') AND (artists.tag_ids IS NOT NULL) AND (artists.id = 1))))"
76
- end
77
-
78
- it "should allowing excluding by associations" do
79
- @c1.exclude(:tags=>@o2).sql.must_equal "SELECT * FROM artists WHERE (NOT (artists.tag_ids @> ARRAY[2]::integer[]) OR (artists.tag_ids IS NULL))"
80
- @c2.exclude(:artists=>@o1).sql.must_equal "SELECT * FROM tags WHERE ((tags.id NOT IN (1, 2, 3)) OR (tags.id IS NULL))"
81
- end
82
-
83
- it "should allowing excluding by associations with :conditions" do
84
- @c1.exclude(:a_tags=>@o2).sql.must_equal "SELECT * FROM artists WHERE (NOT coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE ((name = 'A') AND (tags.id IS NOT NULL) AND (tags.id = 2)))), false) OR (artists.tag_ids IS NULL))"
85
- @c2.exclude(:a_artists=>@o1).sql.must_equal "SELECT * FROM tags WHERE ((tags.id NOT IN (SELECT unnest(artists.tag_ids) FROM artists WHERE ((name = 'A') AND (artists.tag_ids IS NOT NULL) AND (artists.id = 1)))) OR (tags.id IS NULL))"
86
- end
87
-
88
- it "should allowing filtering by multiple associations" do
89
- @c1.filter(:tags=>[@c2.load(:id=>1), @c2.load(:id=>2)]).sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[1,2]::integer[])"
90
- @c2.filter(:artists=>[@c1.load(:tag_ids=>Sequel.pg_array([3, 4])), @c1.load(:tag_ids=>Sequel.pg_array([4, 5]))]).sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (3, 4, 5))"
91
- end
92
-
93
- it "should allowing filtering by multiple associations with :conditions" do
94
- @c1.filter(:a_tags=>[@c2.load(:id=>1), @c2.load(:id=>2)]).sql.must_equal "SELECT * FROM artists WHERE coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE ((name = 'A') AND (tags.id IS NOT NULL) AND (tags.id IN (1, 2))))), false)"
95
- @c2.filter(:a_artists=>[@c1.load(:id=>7, :tag_ids=>Sequel.pg_array([3, 4])), @c1.load(:id=>8, :tag_ids=>Sequel.pg_array([4, 5]))]).sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (SELECT unnest(artists.tag_ids) FROM artists WHERE ((name = 'A') AND (artists.tag_ids IS NOT NULL) AND (artists.id IN (7, 8)))))"
96
- end
97
-
98
- it "should allowing excluding by multiple associations" do
99
- @c1.exclude(:tags=>[@c2.load(:id=>1), @c2.load(:id=>2)]).sql.must_equal "SELECT * FROM artists WHERE (NOT (artists.tag_ids && ARRAY[1,2]::integer[]) OR (artists.tag_ids IS NULL))"
100
- @c2.exclude(:artists=>[@c1.load(:tag_ids=>Sequel.pg_array([3, 4])), @c1.load(:tag_ids=>Sequel.pg_array([4, 5]))]).sql.must_equal "SELECT * FROM tags WHERE ((tags.id NOT IN (3, 4, 5)) OR (tags.id IS NULL))"
101
- end
102
-
103
- it "should allowing excluding by multiple associations with :conditions" do
104
- @c1.exclude(:a_tags=>[@c2.load(:id=>1), @c2.load(:id=>2)]).sql.must_equal "SELECT * FROM artists WHERE (NOT coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE ((name = 'A') AND (tags.id IS NOT NULL) AND (tags.id IN (1, 2))))), false) OR (artists.tag_ids IS NULL))"
105
- @c2.exclude(:a_artists=>[@c1.load(:id=>7, :tag_ids=>Sequel.pg_array([3, 4])), @c1.load(:id=>8, :tag_ids=>Sequel.pg_array([4, 5]))]).sql.must_equal "SELECT * FROM tags WHERE ((tags.id NOT IN (SELECT unnest(artists.tag_ids) FROM artists WHERE ((name = 'A') AND (artists.tag_ids IS NOT NULL) AND (artists.id IN (7, 8))))) OR (tags.id IS NULL))"
106
- end
107
-
108
- it "should allowing filtering/excluding associations with NULL or empty values" do
109
- @c1.filter(:tags=>@c2.new).sql.must_equal 'SELECT * FROM artists WHERE false'
110
- @c1.exclude(:tags=>@c2.new).sql.must_equal 'SELECT * FROM artists WHERE true'
111
- @c2.filter(:artists=>@c1.new).sql.must_equal 'SELECT * FROM tags WHERE false'
112
- @c2.exclude(:artists=>@c1.new).sql.must_equal 'SELECT * FROM tags WHERE true'
113
-
114
- @c2.filter(:artists=>@c1.load(:tag_ids=>[])).sql.must_equal 'SELECT * FROM tags WHERE false'
115
- @c2.exclude(:artists=>@c1.load(:tag_ids=>[])).sql.must_equal 'SELECT * FROM tags WHERE true'
116
-
117
- @c1.filter(:tags=>[@c2.new, @c2.load(:id=>2)]).sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2]::integer[])"
118
- @c2.filter(:artists=>[@c1.load(:tag_ids=>Sequel.pg_array([3, 4])), @c1.new]).sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (3, 4))"
119
- end
120
-
121
- it "should allowing filtering by association datasets" do
122
- @c1.filter(:tags=>@c2.where(:id=>1)).sql.must_equal "SELECT * FROM artists WHERE coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE (id = 1))), false)"
123
- @c2.filter(:artists=>@c1.where(:id=>1)).sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (SELECT unnest(artists.tag_ids) FROM artists WHERE (id = 1)))"
124
- end
125
-
126
- it "should allowing filtering by association datasets with :conditions" do
127
- @c1.filter(:a_tags=>@c2.where(:id=>1)).sql.must_equal "SELECT * FROM artists WHERE coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE ((name = 'A') AND (tags.id IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (id = 1)))))), false)"
128
- @c2.filter(:a_artists=>@c1.where(:id=>1)).sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (SELECT unnest(artists.tag_ids) FROM artists WHERE ((name = 'A') AND (artists.tag_ids IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (id = 1))))))"
129
- end
130
-
131
- it "should allowing excluding by association datasets" do
132
- @c1.exclude(:tags=>@c2.where(:id=>1)).sql.must_equal "SELECT * FROM artists WHERE (NOT coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE (id = 1))), false) OR (artists.tag_ids IS NULL))"
133
- @c2.exclude(:artists=>@c1.where(:id=>1)).sql.must_equal "SELECT * FROM tags WHERE ((tags.id NOT IN (SELECT unnest(artists.tag_ids) FROM artists WHERE (id = 1))) OR (tags.id IS NULL))"
134
- end
135
-
136
- it "should allowing excluding by association datasets with :conditions" do
137
- @c1.exclude(:a_tags=>@c2.where(:id=>1)).sql.must_equal "SELECT * FROM artists WHERE (NOT coalesce((artists.tag_ids && (SELECT array_agg(tags.id) FROM tags WHERE ((name = 'A') AND (tags.id IS NOT NULL) AND (tags.id IN (SELECT tags.id FROM tags WHERE (id = 1)))))), false) OR (artists.tag_ids IS NULL))"
138
- @c2.exclude(:a_artists=>@c1.where(:id=>1)).sql.must_equal "SELECT * FROM tags WHERE ((tags.id NOT IN (SELECT unnest(artists.tag_ids) FROM artists WHERE ((name = 'A') AND (artists.tag_ids IS NOT NULL) AND (artists.id IN (SELECT artists.id FROM artists WHERE (id = 1)))))) OR (tags.id IS NULL))"
139
- end
140
-
141
- it "filter by associations should respect key options" do
142
- @c1.class_eval{def tag3_ids; tag_ids.map{|x| x*3} end}
143
- @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>Sequel.*(:id, 3), :primary_key_method=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
144
- @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>Sequel.*(:id, 3), :primary_key_method=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
145
-
146
- @c1.filter(:tags=>@o2).sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids[1:2] @> ARRAY[6]::integer[])"
147
- @c2.filter(:artists=>@o1).sql.must_equal "SELECT * FROM tags WHERE ((tags.id * 3) IN (3, 6, 9))"
148
- @c1.filter(:tags=>@c2.where(:id=>1)).sql.must_equal "SELECT * FROM artists WHERE coalesce((artists.tag_ids[1:2] && (SELECT array_agg((tags.id * 3)) FROM tags WHERE (id = 1))), false)"
149
- @c2.filter(:artists=>@c1.where(:id=>1)).sql.must_equal "SELECT * FROM tags WHERE ((tags.id * 3) IN (SELECT unnest(artists.tag_ids[1:2]) FROM artists WHERE (id = 1)))"
150
- end
151
-
152
- it "should raise an error if associated model does not have a primary key, and :primary_key is not specified" do
153
- @c1.no_primary_key
154
- @c2.no_primary_key
155
- @c1.pg_array_to_many :tags, :clone=>:tags
156
- proc{@o1.tags}.must_raise(Sequel::Error)
157
- proc{@c2.many_to_pg_array :artists, :clone=>:artists}.must_raise(Sequel::Error)
158
- @db.sqls.must_equal []
159
- end
160
-
161
- it "should support a :key option" do
162
- @c1.pg_array_to_many :tags, :clone=>:tags, :key=>:tag2_ids
163
- @c2.many_to_pg_array :artists, :clone=>:artists, :key=>:tag2_ids
164
- @c1.class_eval{def tag2_ids; tag_ids.map{|x| x * 2} end}
165
- @o1.tags_dataset.sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (2, 4, 6))"
166
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE (artists.tag2_ids @> ARRAY[2]::integer[])"
167
- end
168
-
169
- it "should support a :key_column option" do
170
- @c2.many_to_pg_array :artists, :clone=>:artists, :key_column=>Sequel.pg_array(:tag_ids)[1..2], :key=>:tag2_ids
171
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids[1:2] @> ARRAY[2]::integer[])"
172
- end
173
-
174
- it "should support a :primary_key option" do
175
- @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>:id2
176
- @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>:id2
177
- @o1.tags_dataset.sql.must_equal "SELECT * FROM tags WHERE (tags.id2 IN (1, 2, 3))"
178
- @c2.class_eval{def id2; id*2 end}
179
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[4]::integer[])"
180
- end
181
-
182
- it "should support a :conditions option" do
183
- @c1.pg_array_to_many :tags, :clone=>:tags, :conditions=>{:a=>1}
184
- @c2.many_to_pg_array :artists, :clone=>:artists, :conditions=>{:a=>1}
185
- @o1.tags_dataset.sql.must_equal "SELECT * FROM tags WHERE ((a = 1) AND (tags.id IN (1, 2, 3)))"
186
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE ((a = 1) AND (artists.tag_ids @> ARRAY[2]::integer[]))"
187
- end
188
-
189
- it "should support an :order option" do
190
- @c1.pg_array_to_many :tags, :clone=>:tags, :order=>[:a, :b]
191
- @c2.many_to_pg_array :artists, :clone=>:artists, :order=>[:a, :b]
192
- @o1.tags_dataset.sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (1, 2, 3)) ORDER BY a, b"
193
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2]::integer[]) ORDER BY a, b"
194
- end
195
-
196
- it "should support a select option" do
197
- @c1.pg_array_to_many :tags, :clone=>:tags, :select=>[:a, :b]
198
- @c2.many_to_pg_array :artists, :clone=>:artists, :select=>[:a, :b]
199
- @c1.load(:tag_ids=>Sequel.pg_array([1,2,3])).tags_dataset.sql.must_equal "SELECT a, b FROM tags WHERE (tags.id IN (1, 2, 3))"
200
- @c2.load(:id=>1).artists_dataset.sql.must_equal "SELECT a, b FROM artists WHERE (artists.tag_ids @> ARRAY[1]::integer[])"
201
- end
202
-
203
- it "should accept a block" do
204
- @c1.pg_array_to_many :tags, :clone=>:tags do |ds| ds.filter(:yyy=>@yyy) end
205
- @c2.many_to_pg_array :artists, :clone=>:artists do |ds| ds.filter(:a=>1) end
206
- @c1.new(:yyy=>6, :tag_ids=>Sequel.pg_array([1,2,3])).tags_dataset.sql.must_equal "SELECT * FROM tags WHERE ((tags.id IN (1, 2, 3)) AND (yyy = 6))"
207
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE ((artists.tag_ids @> ARRAY[2]::integer[]) AND (a = 1))"
208
- end
209
-
210
- it "should support a :dataset option that is used instead of the default" do
211
- @c1.pg_array_to_many :tags, :clone=>:tags, :dataset=>proc{Tag.where(:id=>tag_ids.map{|x| x*2})}
212
- @c2.many_to_pg_array :artists, :clone=>:artists, :dataset=>proc{Artist.where(Sequel.pg_array(Sequel.pg_array(:tag_ids)[1..2]).contains([id]))}
213
- @o1.tags_dataset.sql.must_equal "SELECT * FROM tags WHERE (id IN (2, 4, 6))"
214
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE (tag_ids[1:2] @> ARRAY[2])"
215
- end
216
-
217
- it "should support a :limit option" do
218
- @c1.pg_array_to_many :tags, :clone=>:tags, :limit=>[2, 3]
219
- @c2.many_to_pg_array :artists, :clone=>:artists, :limit=>[3, 2]
220
- @o1.tags_dataset.sql.must_equal "SELECT * FROM tags WHERE (tags.id IN (1, 2, 3)) LIMIT 2 OFFSET 3"
221
- @o2.artists_dataset.sql.must_equal "SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2]::integer[]) LIMIT 3 OFFSET 2"
222
- end
223
-
224
- it "should support a :uniq option that removes duplicates from the association" do
225
- @c1.pg_array_to_many :tags, :clone=>:tags, :uniq=>true
226
- @c2.many_to_pg_array :artists, :clone=>:artists, :uniq=>true
227
- @c1.dataset = @c1.dataset.with_fetch([{:id=>20}, {:id=>30}, {:id=>20}, {:id=>30}])
228
- @c2.dataset = @c1.dataset.with_fetch([{:id=>20}, {:id=>30}, {:id=>20}, {:id=>30}])
229
- @o1.tags.must_equal [@c2.load(:id=>20), @c2.load(:id=>30)]
230
- @o2.artists.must_equal [@c1.load(:id=>20), @c1.load(:id=>30)]
231
- end
232
-
233
- it "reflection associated_object_keys should return correct values" do
234
- @c1.association_reflection(:tags).associated_object_keys.must_equal [:id]
235
- @c2.association_reflection(:artists).associated_object_keys.must_equal [:tag_ids]
236
- end
237
-
238
- it "reflection remove_before_destroy? should return correct values" do
239
- @c1.association_reflection(:tags).remove_before_destroy?.must_equal true
240
- @c2.association_reflection(:artists).remove_before_destroy?.must_equal false
241
- end
242
-
243
- it "reflection reciprocal should be correct" do
244
- @c1.association_reflection(:tags).reciprocal.must_equal :artists
245
- @c2.association_reflection(:artists).reciprocal.must_equal :tags
246
- end
247
-
248
- it "should eagerly load correctly" do
249
- a = @c1.eager(:tags).all
250
- a.must_equal [@o1]
251
- @db.sqls.must_equal ["SELECT * FROM artists",
252
- 'SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))']
253
- a.first.tags.must_equal [@o2]
254
- @db.sqls.must_equal []
255
-
256
- a = @c2.eager(:artists).all
257
- a.must_equal [@o2]
258
- @db.sqls.must_equal ['SELECT * FROM tags', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2]::integer[])"]
259
- a.first.artists.must_equal [@o1]
260
- @db.sqls.must_equal []
261
- end
262
-
263
- it "should support using custom key options when eager loading associations" do
264
- @c1.class_eval{def tag3_ids; tag_ids.map{|x| x*3} end}
265
- @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>Sequel.*(:id, 3), :primary_key_method=>:id3, :key=>:tag3_ids
266
- @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
267
-
268
- a = @c1.eager(:tags).all
269
- a.must_equal [@o1]
270
- @db.sqls.must_equal ["SELECT * FROM artists",
271
- 'SELECT * FROM tags WHERE ((tags.id * 3) IN (3, 6, 9))']
272
- a.first.tags.must_equal [@o2]
273
- @db.sqls.must_equal []
274
-
275
- a = @c2.eager(:artists).all
276
- a.must_equal [@o2]
277
- @db.sqls.must_equal ["SELECT * FROM tags", "SELECT * FROM artists WHERE (artists.tag_ids[1:2] && ARRAY[6]::integer[])"]
278
- a.first.artists.must_equal [@o1]
279
- @db.sqls.must_equal []
280
- end
281
-
282
- it "should allow cascading of eager loading for associations of associated models" do
283
- a = @c1.eager(:tags=>:artists).all
284
- a.must_equal [@o1]
285
- @db.sqls.must_equal ["SELECT * FROM artists",
286
- 'SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))',
287
- "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2]::integer[])"]
288
- a.first.tags.must_equal [@o2]
289
- a.first.tags.first.artists.must_equal [@o1]
290
- @db.sqls.must_equal []
291
- end
292
-
293
- it "should respect :eager when lazily loading an association" do
294
- @c1.pg_array_to_many :tags2, :clone=>:tags, :eager=>:artists, :key=>:tag_ids
295
- @c2.many_to_pg_array :artists2, :clone=>:artists, :eager=>:tags
296
-
297
- @o1.tags2.must_equal [@o2]
298
- @db.sqls.must_equal ["SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))", "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2]::integer[])"]
299
- @o1.tags2.first.artists.must_equal [@o1]
300
- @db.sqls.must_equal []
301
-
302
- @o2.artists2.must_equal [@o1]
303
- @db.sqls.must_equal ["SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[2]::integer[])",
304
- 'SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))']
305
- @o2.artists2.first.tags.must_equal [@o2]
306
- @db.sqls.must_equal []
307
- end
308
-
309
- it "should cascade eagerly loading when the :eager_graph association option is used" do
310
- @c1.pg_array_to_many :tags2, :clone=>:tags, :eager_graph=>:artists, :key=>:tag_ids
311
- @c2.many_to_pg_array :artists2, :clone=>:artists, :eager_graph=>:tags
312
-
313
- @c2.dataset = @c2.dataset.with_fetch(:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3]))
314
- @c1.dataset = @c1.dataset.with_fetch(:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3]))
315
- @db.sqls
316
-
317
- @o1.tags2.must_equal [@o2]
318
- @db.sqls.must_equal ['SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id]) WHERE (tags.id IN (1, 2, 3))']
319
- @o1.tags2.first.artists.must_equal [@o1]
320
- @db.sqls.must_equal []
321
-
322
- @o2.artists2.must_equal [@o1]
323
- @db.sqls.must_equal ["SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id]) WHERE (artists.tag_ids @> ARRAY[2]::integer[])"]
324
- @o2.artists2.first.tags.must_equal [@o2]
325
- @db.sqls.must_equal []
326
-
327
- @c2.dataset = @c2.dataset.with_fetch(:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3]))
328
- @c1.dataset = @c1.dataset.with_fetch(:id=>1, :tag_ids=>Sequel.pg_array([1,2,3]))
329
- @db.sqls
330
-
331
- a = @c1.eager(:tags2).all
332
- @db.sqls.must_equal ["SELECT * FROM artists",
333
- 'SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id]) WHERE (tags.id IN (1, 2, 3))']
334
- a.must_equal [@o1]
335
- a.first.tags2.must_equal [@o2]
336
- a.first.tags2.first.artists.must_equal [@o1]
337
- @db.sqls.must_equal []
338
-
339
- @c2.dataset = @c2.dataset.with_fetch(:id=>2)
340
- @c1.dataset = @c1.dataset.with_fetch(:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3]))
341
- @db.sqls
342
-
343
- a = @c2.eager(:artists2).all
344
- @db.sqls.must_equal ["SELECT * FROM tags", "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id]) WHERE (artists.tag_ids && ARRAY[2]::integer[])"]
345
- a.must_equal [@o2]
346
- a.first.artists2.must_equal [@o1]
347
- a.first.artists2.first.tags.must_equal [@o2]
348
- @db.sqls.must_equal []
349
- end
350
-
351
- it "should respect the :limit option when eager loading" do
352
- @c2.dataset = @c2.dataset.with_fetch([{:id=>1},{:id=>2}, {:id=>3}])
353
- @db.sqls
354
-
355
- @c1.pg_array_to_many :tags, :clone=>:tags, :limit=>2
356
- a = @c1.eager(:tags).all
357
- a.must_equal [@o1]
358
- @db.sqls.must_equal ["SELECT * FROM artists",
359
- 'SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))']
360
- a.first.tags.must_equal [@c2.load(:id=>1), @c2.load(:id=>2)]
361
- @db.sqls.must_equal []
362
-
363
- @c1.pg_array_to_many :tags, :clone=>:tags, :limit=>[1, 1]
364
- a = @c1.eager(:tags).all
365
- a.must_equal [@o1]
366
- @db.sqls.must_equal ["SELECT * FROM artists",
367
- 'SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))']
368
- a.first.tags.must_equal [@c2.load(:id=>2)]
369
- @db.sqls.must_equal []
370
-
371
- @c1.pg_array_to_many :tags, :clone=>:tags, :limit=>[nil, 1]
372
- a = @c1.eager(:tags).all
373
- a.must_equal [@o1]
374
- @db.sqls.must_equal ["SELECT * FROM artists",
375
- 'SELECT * FROM tags WHERE (tags.id IN (1, 2, 3))']
376
- a.first.tags.must_equal [@c2.load(:id=>2), @c2.load(:id=>3)]
377
- @db.sqls.length.must_equal 0
378
-
379
- @c2.dataset = @c2.dataset.with_fetch(:id=>2)
380
- @c1.dataset = @c1.dataset.with_fetch([{:id=>5, :tag_ids=>Sequel.pg_array([1,2,3])},{:id=>6, :tag_ids=>Sequel.pg_array([2,3])}, {:id=>7, :tag_ids=>Sequel.pg_array([1,2])}])
381
- @db.sqls
382
-
383
- @c2.many_to_pg_array :artists, :clone=>:artists, :limit=>2
384
- a = @c2.eager(:artists).all
385
- a.must_equal [@o2]
386
- @db.sqls.must_equal ['SELECT * FROM tags', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2]::integer[])"]
387
- a.first.artists.must_equal [@c1.load(:id=>5, :tag_ids=>Sequel.pg_array([1,2,3])), @c1.load(:id=>6, :tag_ids=>Sequel.pg_array([2,3]))]
388
- @db.sqls.must_equal []
389
-
390
- @c2.many_to_pg_array :artists, :clone=>:artists, :limit=>[1, 1]
391
- a = @c2.eager(:artists).all
392
- a.must_equal [@o2]
393
- @db.sqls.must_equal ['SELECT * FROM tags', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2]::integer[])"]
394
- a.first.artists.must_equal [@c1.load(:id=>6, :tag_ids=>Sequel.pg_array([2,3]))]
395
- @db.sqls.must_equal []
396
-
397
- @c2.many_to_pg_array :artists, :clone=>:artists, :limit=>[nil, 1]
398
- a = @c2.eager(:artists).all
399
- a.must_equal [@o2]
400
- @db.sqls.must_equal ['SELECT * FROM tags', "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2]::integer[])"]
401
- a.first.artists.must_equal [@c1.load(:id=>6, :tag_ids=>Sequel.pg_array([2,3])), @c1.load(:id=>7, :tag_ids=>Sequel.pg_array([1,2]))]
402
- @db.sqls.must_equal []
403
- end
404
-
405
- it "should support association_join" do
406
- @c1.association_join(:tags).sql.must_equal "SELECT * FROM artists INNER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id])"
407
- @c2.association_join(:artists).sql.must_equal "SELECT * FROM tags INNER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id])"
408
- end
409
-
410
- it "should support custom selects when using association_join" do
411
- @c1.select{a(b)}.association_join(:tags).sql.must_equal "SELECT a(b) FROM artists INNER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id])"
412
- @c2.select{a(b)}.association_join(:artists).sql.must_equal "SELECT a(b) FROM tags INNER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id])"
413
- end
414
-
415
- it "should eagerly graph associations" do
416
- @c2.dataset = @c2.dataset.with_fetch(:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3]))
417
- @c1.dataset = @c1.dataset.with_fetch(:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3]))
418
- @db.sqls
419
-
420
- a = @c1.eager_graph(:tags).all
421
- @db.sqls.must_equal ["SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id])"]
422
- a.must_equal [@o1]
423
- a.first.tags.must_equal [@o2]
424
- @db.sqls.must_equal []
425
-
426
- a = @c2.eager_graph(:artists).all
427
- @db.sqls.must_equal ["SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id])"]
428
- a.must_equal [@o2]
429
- a.first.artists.must_equal [@o1]
430
- @db.sqls.must_equal []
431
- end
432
-
433
- it "should allow cascading of eager graphing for associations of associated models" do
434
- @c2.dataset = @c2.dataset.with_fetch(:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3]), :tags_0_id=>2)
435
- @c1.dataset = @c1.dataset.with_fetch(:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3]), :artists_0_id=>1, :artists_0_tag_ids=>Sequel.pg_array([1,2,3]))
436
- @db.sqls
437
-
438
- a = @c1.eager_graph(:tags=>:artists).all
439
- @db.sqls.must_equal ["SELECT artists.id, artists.tag_ids, tags.id AS tags_id, artists_0.id AS artists_0_id, artists_0.tag_ids AS artists_0_tag_ids FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id]) LEFT OUTER JOIN artists AS artists_0 ON (artists_0.tag_ids @> ARRAY[tags.id])"]
440
- a.must_equal [@o1]
441
- a.first.tags.must_equal [@o2]
442
- a.first.tags.first.artists.must_equal [@o1]
443
- @db.sqls.must_equal []
444
-
445
- a = @c2.eager_graph(:artists=>:tags).all
446
- @db.sqls.must_equal ["SELECT tags.id, artists.id AS artists_id, artists.tag_ids, tags_0.id AS tags_0_id FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id]) LEFT OUTER JOIN tags AS tags_0 ON (artists.tag_ids @> ARRAY[tags_0.id])"]
447
- a.must_equal [@o2]
448
- a.first.artists.must_equal [@o1]
449
- a.first.artists.first.tags.must_equal [@o2]
450
- @db.sqls.must_equal []
451
- end
452
-
453
- it "eager graphing should respect key options" do
454
- @c1.class_eval{def tag3_ids; tag_ids.map{|x| x*3} end}
455
- @c1.pg_array_to_many :tags, :clone=>:tags, :primary_key=>Sequel.*(:id, 3), :primary_key_method=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
456
- @c2.many_to_pg_array :artists, :clone=>:artists, :primary_key=>:id3, :key=>:tag3_ids, :key_column=>Sequel.pg_array(:tag_ids)[1..2]
457
-
458
- @c2.dataset = @c2.dataset.with_fetch(:id=>2, :artists_id=>1, :tag_ids=>Sequel.pg_array([1,2,3]), :tags_0_id=>2)
459
- @c1.dataset = @c1.dataset.with_fetch(:id=>1, :tags_id=>2, :tag_ids=>Sequel.pg_array([1,2,3]), :artists_0_id=>1, :artists_0_tag_ids=>Sequel.pg_array([1,2,3]))
460
- @db.sqls
461
-
462
- a = @c1.eager_graph(:tags).all
463
- a.must_equal [@o1]
464
- @db.sqls.must_equal ["SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids[1:2] @> ARRAY[(tags.id * 3)])"]
465
- a.first.tags.must_equal [@o2]
466
- @db.sqls.must_equal []
467
-
468
- a = @c2.eager_graph(:artists).all
469
- a.must_equal [@o2]
470
- @db.sqls.must_equal ["SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids[1:2] @> ARRAY[tags.id3])"]
471
- a.first.artists.must_equal [@o1]
472
- @db.sqls.must_equal []
473
- end
474
-
475
- it "should respect the association's :graph_select option" do
476
- @c1.pg_array_to_many :tags, :clone=>:tags, :graph_select=>:id2
477
- @c2.many_to_pg_array :artists, :clone=>:artists, :graph_select=>:id
478
-
479
- @c2.dataset = @c2.dataset.with_fetch(:id=>2, :artists_id=>1)
480
- @c1.dataset = @c1.dataset.with_fetch(:id=>1, :id2=>2, :tag_ids=>Sequel.pg_array([1,2,3]))
481
- @db.sqls
482
-
483
- a = @c1.eager_graph(:tags).all
484
- @db.sqls.must_equal ["SELECT artists.id, artists.tag_ids, tags.id2 FROM artists LEFT OUTER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id])"]
485
- a.must_equal [@o1]
486
- a.first.tags.must_equal [@c2.load(:id2=>2)]
487
- @db.sqls.must_equal []
488
-
489
- a = @c2.eager_graph(:artists).all
490
- @db.sqls.must_equal ["SELECT tags.id, artists.id AS artists_id FROM tags LEFT OUTER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id])"]
491
- a.must_equal [@o2]
492
- a.first.artists.must_equal [@c1.load(:id=>1)]
493
- @db.sqls.must_equal []
494
- end
495
-
496
- it "should respect the association's :graph_join_type option" do
497
- @c1.pg_array_to_many :tags, :clone=>:tags, :graph_join_type=>:inner
498
- @c2.many_to_pg_array :artists, :clone=>:artists, :graph_join_type=>:inner
499
- @c1.eager_graph(:tags).sql.must_equal "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists INNER JOIN tags ON (artists.tag_ids @> ARRAY[tags.id])"
500
- @c2.eager_graph(:artists).sql.must_equal "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags INNER JOIN artists ON (artists.tag_ids @> ARRAY[tags.id])"
501
- end
502
-
503
- it "should respect the association's :conditions option" do
504
- @c1.pg_array_to_many :tags, :clone=>:tags, :conditions=>{:a=>1}
505
- @c2.many_to_pg_array :artists, :clone=>:artists, :conditions=>{:a=>1}
506
- @c1.eager_graph(:tags).sql.must_equal "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON ((tags.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
507
- @c2.eager_graph(:artists).sql.must_equal "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON ((artists.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
508
- end
509
-
510
- it "should respect the association's :graph_conditions option" do
511
- @c1.pg_array_to_many :tags, :clone=>:tags, :graph_conditions=>{:a=>1}
512
- @c2.many_to_pg_array :artists, :clone=>:artists, :graph_conditions=>{:a=>1}
513
- @c1.eager_graph(:tags).sql.must_equal "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON ((tags.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
514
- @c2.eager_graph(:artists).sql.must_equal "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON ((artists.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
515
- end
516
-
517
- it "should respect the association's :graph_block option" do
518
- @c1.pg_array_to_many :tags, :clone=>:tags, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :a)=>1}}
519
- @c2.many_to_pg_array :artists, :clone=>:artists, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(ja, :a)=>1}}
520
- @c1.eager_graph(:tags).sql.must_equal "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON ((tags.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
521
- @c2.eager_graph(:artists).sql.must_equal "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON ((artists.a = 1) AND (artists.tag_ids @> ARRAY[tags.id]))"
522
- end
523
-
524
- it "should respect the association's :graph_only_conditions option" do
525
- @c1.pg_array_to_many :tags, :clone=>:tags, :graph_only_conditions=>{:a=>1}
526
- @c2.many_to_pg_array :artists, :clone=>:artists, :graph_only_conditions=>{:a=>1}
527
- @c1.eager_graph(:tags).sql.must_equal "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON (tags.a = 1)"
528
- @c2.eager_graph(:artists).sql.must_equal "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON (artists.a = 1)"
529
- end
530
-
531
- it "should respect the association's :graph_only_conditions with :graph_block option" do
532
- @c1.pg_array_to_many :tags, :clone=>:tags, :graph_only_conditions=>{:a=>1}, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(lja, :b)=>1}}
533
- @c2.many_to_pg_array :artists, :clone=>:artists, :graph_only_conditions=>{:a=>1}, :graph_block=>proc{|ja,lja,js| {Sequel.qualify(lja, :b)=>1}}
534
- @c1.eager_graph(:tags).sql.must_equal "SELECT artists.id, artists.tag_ids, tags.id AS tags_id FROM artists LEFT OUTER JOIN tags ON ((tags.a = 1) AND (artists.b = 1))"
535
- @c2.eager_graph(:artists).sql.must_equal "SELECT tags.id, artists.id AS artists_id, artists.tag_ids FROM tags LEFT OUTER JOIN artists ON ((artists.a = 1) AND (tags.b = 1))"
536
- end
537
-
538
- it "should define an add_ method for adding associated objects" do
539
- @o1.add_tag(@c2.load(:id=>4))
540
- @o1.tag_ids.must_equal [1,2,3,4]
541
- @db.sqls.must_equal []
542
- @o1.save_changes
543
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[1,2,3,4] WHERE (id = 1)"]
544
-
545
- @o2.add_artist(@c1.load(:id=>1, :tag_ids=>Sequel.pg_array([4])))
546
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[4,2] WHERE (id = 1)"]
547
- end
548
-
549
- it "should define a remove_ method for removing associated objects" do
550
- @o1.remove_tag(@o2)
551
- @o1.tag_ids.must_equal [1,3]
552
- @db.sqls.must_equal []
553
- @o1.save_changes
554
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[1,3] WHERE (id = 1)"]
555
-
556
- @o2.remove_artist(@c1.load(:id=>1, :tag_ids=>Sequel.pg_array([1,2,3,4])))
557
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[1,3,4] WHERE (id = 1)"]
558
- end
559
-
560
- it "should define a remove_all_ method for removing all associated objects" do
561
- @o1.remove_all_tags
562
- @o1.tag_ids.must_equal []
563
- @db.sqls.must_equal []
564
- @o1.save_changes
565
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[] WHERE (id = 1)"]
566
-
567
- @o2.remove_all_artists
568
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = array_remove(tag_ids, CAST(2 AS integer)) WHERE (tag_ids @> ARRAY[2]::integer[])"]
569
- end
570
-
571
- it "should define a remove_all_ method for removing all associated objects respecting database type" do
572
- @c2.many_to_pg_array :artists, :clone=>:artists, :array_type=>:bigint
573
- @o1.remove_all_tags
574
- @o1.tag_ids.must_equal []
575
- @db.sqls.must_equal []
576
- @o1.save_changes
577
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[] WHERE (id = 1)"]
578
-
579
- @o2.remove_all_artists
580
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = array_remove(tag_ids, CAST(2 AS bigint)) WHERE (tag_ids @> ARRAY[2]::bigint[])"]
581
- end
582
-
583
- it "should allow calling add_ and remove_ methods on new objects for pg_array_to_many associations" do
584
- a = Artist.new
585
- a.add_tag(@c2.load(:id=>4))
586
- a.tag_ids.must_equal [4]
587
- a.remove_tag(@c2.load(:id=>4))
588
- a.tag_ids.must_equal []
589
- a.add_tag(@c2.load(:id=>4))
590
- a.tag_ids.must_equal [4]
591
- a.remove_all_tags
592
- a.tag_ids.must_equal []
593
- end
594
-
595
- it "should have pg_array_to_many association modification methods save if :save_after_modify option is used" do
596
- @c1.pg_array_to_many :tags, :clone=>:tags, :save_after_modify=>true
597
-
598
- @o1.add_tag(@c2.load(:id=>4))
599
- @o1.tag_ids.must_equal [1,2,3,4]
600
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[1,2,3,4] WHERE (id = 1)"]
601
-
602
- @o1.remove_tag(@o2)
603
- @o1.tag_ids.must_equal [1,3,4]
604
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[1,3,4] WHERE (id = 1)"]
605
-
606
- @o1.remove_all_tags
607
- @o1.tag_ids.must_equal []
608
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[] WHERE (id = 1)"]
609
- end
610
-
611
- it "should have association modification methods deal with nil values" do
612
- v = @c1.load(:id=>1)
613
- v.add_tag(@c2.load(:id=>4))
614
- v.tag_ids.must_equal [4]
615
- @db.sqls.must_equal []
616
- v.save_changes
617
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[4]::integer[] WHERE (id = 1)"]
618
-
619
- @o2.add_artist(@c1.load(:id=>1))
620
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[2]::integer[] WHERE (id = 1)"]
621
-
622
- v = @c1.load(:id=>1)
623
- v.remove_tag(@c2.load(:id=>4))
624
- v.tag_ids.must_be_nil
625
- @db.sqls.must_equal []
626
- v.save_changes
627
- @db.sqls.must_equal []
628
-
629
- @o2.remove_artist(@c1.load(:id=>1))
630
- @db.sqls.must_equal []
631
-
632
- v = @c1.load(:id=>1)
633
- v.remove_all_tags
634
- v.tag_ids.must_be_nil
635
- @db.sqls.must_equal []
636
- v.save_changes
637
- @db.sqls.must_equal []
638
- end
639
-
640
- it "should have association modification methods deal with empty arrays values" do
641
- v = @c1.load(:id=>1, :tag_ids=>Sequel.pg_array([]))
642
- v.add_tag(@c2.load(:id=>4))
643
- v.tag_ids.must_equal [4]
644
- @db.sqls.must_equal []
645
- v.save_changes
646
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[4] WHERE (id = 1)"]
647
-
648
- @o2.add_artist(@c1.load(:id=>1, :tag_ids=>Sequel.pg_array([])))
649
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[2] WHERE (id = 1)"]
650
-
651
- v = @c1.load(:id=>1, :tag_ids=>Sequel.pg_array([]))
652
- v.remove_tag(@c2.load(:id=>4))
653
- v.tag_ids.must_equal []
654
- @db.sqls.must_equal []
655
- v.save_changes
656
- @db.sqls.must_equal []
657
-
658
- @o2.remove_artist(@c1.load(:id=>1, :tag_ids=>Sequel.pg_array([])))
659
- @db.sqls.must_equal []
660
-
661
- v = @c1.load(:id=>1, :tag_ids=>Sequel.pg_array([]))
662
- v.remove_all_tags
663
- v.tag_ids.must_equal []
664
- @db.sqls.must_equal []
665
- v.save_changes
666
- @db.sqls.must_equal []
667
- end
668
-
669
- it "should respect the :array_type option when manually creating arrays" do
670
- @c1.pg_array_to_many :tags, :clone=>:tags, :array_type=>:int8
671
- @c2.many_to_pg_array :artists, :clone=>:artists, :array_type=>:int8
672
- v = @c1.load(:id=>1)
673
- v.add_tag(@c2.load(:id=>4))
674
- v.tag_ids.must_equal [4]
675
- @db.sqls.must_equal []
676
- v.save_changes
677
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[4]::int8[] WHERE (id = 1)"]
678
-
679
- @o2.add_artist(@c1.load(:id=>1))
680
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[2]::int8[] WHERE (id = 1)"]
681
- end
682
-
683
- it "should respect the :array_type option in the associations dataset" do
684
- @c2.many_to_pg_array :artists, :clone=>:artists, :array_type=>:int8
685
- @c2.load(:id=>1).artists_dataset.sql.must_equal 'SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[1]::int8[])'
686
- end
687
-
688
- it "should respect the :array_type option when eager loading" do
689
- @c2.many_to_pg_array :artists, :clone=>:artists, :array_type=>:int8
690
- @c2.eager(:artists).all
691
- @db.sqls.must_equal ["SELECT * FROM tags", "SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[2]::int8[])"]
692
- end
693
-
694
- it "should respect the :array_type option when filtering by associations" do
695
- @c1.pg_array_to_many :tags, :clone=>:tags, :array_type=>:int8
696
- @c1.where(:tags=>@c2.load(:id=>1)).sql.must_equal 'SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[1]::int8[])'
697
- @c1.where(:tags=>[@c2.load(:id=>1), @c2.load(:id=>2)]).sql.must_equal 'SELECT * FROM artists WHERE (artists.tag_ids && ARRAY[1,2]::int8[])'
698
- end
699
-
700
- it "should automatically determine the array type by looking at the schema" do
701
- @c1.db_schema[:tag_ids][:db_type] = 'int8[]'
702
- @c2.many_to_pg_array :artists, :clone=>:artists
703
- @c1.pg_array_to_many :tags, :clone=>:tags, :save_after_modify=>true
704
- @c2.load(:id=>1).artists_dataset.sql.must_equal 'SELECT * FROM artists WHERE (artists.tag_ids @> ARRAY[1]::int8[])'
705
- @c1.load(:id=>1).add_tag(@c2.load(:id=>1))
706
- @db.sqls.must_equal ["UPDATE artists SET tag_ids = ARRAY[1]::int8[] WHERE (id = 1)"]
707
- end
708
-
709
- it "should automatically determine the array type by looking at the schema" do
710
- end
711
-
712
- it "should not validate the current/associated object in add_ and remove_ if the :validate=>false option is used" do
713
- @c1.pg_array_to_many :tags, :clone=>:tags, :validate=>false, :save_after_modify=>true
714
- @c2.many_to_pg_array :artists, :clone=>:artists, :validate=>false
715
- a = @c1.load(:id=>1)
716
- t = @c2.load(:id=>2)
717
- def a.validate() errors.add(:id, 'foo') end
718
- a.associations[:tags] = []
719
- a.add_tag(t).must_equal t
720
- a.tags.must_equal [t]
721
- a.remove_tag(t).must_equal t
722
- a.tags.must_equal []
723
-
724
- t.associations[:artists] = []
725
- t.add_artist(a).must_equal a
726
- t.artists.must_equal [a]
727
- t.remove_artist(a).must_equal a
728
- t.artists.must_equal []
729
- end
730
-
731
- it "should not raise exception in add_ and remove_ if the :raise_on_save_failure=>false option is used" do
732
- @c1.pg_array_to_many :tags, :clone=>:tags, :raise_on_save_failure=>false, :save_after_modify=>true
733
- @c2.many_to_pg_array :artists, :clone=>:artists, :raise_on_save_failure=>false
734
- a = @c1.load(:id=>1)
735
- t = @c2.load(:id=>2)
736
- def a.validate() errors.add(:id, 'foo') end
737
- a.associations[:tags] = []
738
- a.add_tag(t).must_be_nil
739
- a.tags.must_equal []
740
- a.associations[:tags] = [t]
741
- a.remove_tag(t).must_be_nil
742
- a.tags.must_equal [t]
743
-
744
- t.associations[:artists] = []
745
- t.add_artist(a).must_be_nil
746
- t.artists.must_equal []
747
- t.associations[:artists] = [a]
748
- t.remove_artist(a).must_be_nil
749
- t.artists.must_equal [a]
750
- end
751
- end
752
-
753
- describe "Sequel::Model.finalize_associations" do
754
- before do
755
- @db = Sequel.mock(:host=>'postgres', :numrows=>1)
756
- @db.extend_datasets do
757
- def quote_identifiers?; false end
758
- end
759
- class ::Foo < Sequel::Model(@db)
760
- plugin :pg_array_associations
761
- many_to_pg_array :items
762
- end
763
- class ::Item < Sequel::Model(@db)
764
- plugin :pg_array_associations
765
- pg_array_to_many :foos
766
- end
767
- [Foo, Item].each(&:finalize_associations)
768
- @db.sqls
769
- end
770
- after do
771
- Object.send(:remove_const, :Item)
772
- Object.send(:remove_const, :Foo)
773
- end
774
-
775
- it "should finalize pg_array_to_many associations" do
776
- r = Item.association_reflection(:foos)
777
- r[:class].must_equal Foo
778
- r[:_dataset].sql.must_equal "SELECT * FROM foos"
779
- r[:associated_eager_dataset].sql.must_equal "SELECT * FROM foos"
780
- r.fetch(:_eager_limit_strategy).must_be_nil
781
- r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT array_agg(foos.id) FROM foos WHERE (foos.id IS NOT NULL)"
782
- r[:predicate_key].must_equal Sequel.qualify(:foos, :id)
783
- r[:predicate_keys].must_equal [Sequel.qualify(:foos, :id)]
784
- r[:reciprocal].must_equal :items
785
- r[:array_type].must_equal :integer
786
- r[:primary_key].must_equal :id
787
- r[:primary_key_method].must_equal :id
788
- end
789
-
790
- it "should finalize many_to_pg_array associations" do
791
- r = Foo.association_reflection(:items)
792
- r[:class].must_equal Item
793
- r[:_dataset].sql.must_equal "SELECT * FROM items"
794
- r[:associated_eager_dataset].sql.must_equal "SELECT * FROM items"
795
- r.fetch(:_eager_limit_strategy).must_be_nil
796
- r[:filter_by_associations_conditions_dataset].sql.must_equal "SELECT unnest(items.foo_ids) FROM items WHERE (items.foo_ids IS NOT NULL)"
797
- r[:predicate_key].must_equal Sequel.qualify(:items, :foo_ids)
798
- r[:predicate_keys].must_equal [Sequel.qualify(:items, :foo_ids)]
799
- r[:reciprocal].must_equal :foos
800
- r[:array_type].must_equal :integer
801
- end
802
- end