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,93 +0,0 @@
1
- require_relative "spec_helper"
2
- require 'yaml'
3
-
4
- describe "serialization_modification_detection plugin" do
5
- before do
6
- @ds = Sequel.mock(:fetch=>{:id=>1, :a=>'a'.dup, :b=>1, :c=>['a'.dup], :d=>{'b'=>'c'.dup}}, :numrows=>1, :autoid=>1)[:items]
7
- @c = Class.new(Sequel::Model(@ds))
8
- @c.plugin :modification_detection
9
- @c.columns :a, :b, :c, :d
10
- @o = @c.first
11
- @ds.db.sqls
12
- end
13
-
14
- it "should detect setting new column values on new objects" do
15
- @o = @c.new
16
- @o.changed_columns.must_equal []
17
- @o.a = 'c'
18
- @o.changed_columns.must_equal [:a]
19
- end
20
-
21
- it "should only detect columns that have been changed" do
22
- @o.changed_columns.must_equal []
23
- @o.a << 'b'
24
- @o.changed_columns.must_equal [:a]
25
- @o.a.replace('a')
26
- @o.changed_columns.must_equal []
27
-
28
- @o.values[:b] = 2
29
- @o.changed_columns.must_equal [:b]
30
- @o.values[:b] = 1
31
- @o.changed_columns.must_equal []
32
-
33
- @o.c[0] << 'b'
34
- @o.d['b'] << 'b'
35
- @o.changed_columns.sort_by{|c| c.to_s}.must_equal [:c, :d]
36
- @o.c[0] = 'a'
37
- @o.changed_columns.must_equal [:d]
38
- @o.d['b'] = 'c'
39
- @o.changed_columns.must_equal []
40
- end
41
-
42
- it "should detect columns that have been changed on frozen objects" do
43
- @o.freeze
44
- @o.a << 'b'
45
- @o.changed_columns.must_equal [:a]
46
- end
47
-
48
- it "should not list a column twice" do
49
- @o.a = 'b'.dup
50
- @o.a << 'a'
51
- @o.changed_columns.must_equal [:a]
52
- end
53
-
54
- it "should report correct changed_columns after updating" do
55
- @o.a << 'a'
56
- @o.save_changes
57
- @o.changed_columns.must_equal []
58
-
59
- @o.values[:b] = 2
60
- @o.save_changes
61
- @o.changed_columns.must_equal []
62
-
63
- @o.c[0] << 'b'
64
- @o.save_changes
65
- @o.changed_columns.must_equal []
66
-
67
- @o.d['b'] << 'a'
68
- @o.save_changes
69
- @o.changed_columns.must_equal []
70
-
71
- @ds.db.sqls.must_equal ["UPDATE items SET a = 'aa' WHERE (id = 1)",
72
- "UPDATE items SET b = 2 WHERE (id = 1)",
73
- "UPDATE items SET c = ('ab') WHERE (id = 1)",
74
- "UPDATE items SET d = ('b' = 'ca') WHERE (id = 1)"]
75
- end
76
-
77
- it "should report correct changed_columns after creating new object" do
78
- o = @c.create
79
- o.changed_columns.must_equal []
80
- o.a << 'a'
81
- o.changed_columns.must_equal [:a]
82
- @ds.db.sqls.must_equal ["INSERT INTO items DEFAULT VALUES", "SELECT * FROM items WHERE (id = 1) LIMIT 1"]
83
- end
84
-
85
- it "should report correct changed_columns after refreshing existing object" do
86
- @o.a << 'a'
87
- @o.changed_columns.must_equal [:a]
88
- @o.refresh
89
- @o.changed_columns.must_equal []
90
- @o.a << 'a'
91
- @o.changed_columns.must_equal [:a]
92
- end
93
- end
@@ -1,92 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "MSSSQL optimistic locking plugin" do
4
- before do
5
- @db = Sequel.mock(:host=>'mssql')
6
- @ds = @db[:items].with_quote_identifiers(false).with_extend{def input_identifier(v); v.to_s end}
7
- @c = Class.new(Sequel::Model(@ds))
8
- @c.columns :id, :name, :timestamp
9
- @c.plugin :mssql_optimistic_locking
10
- @o = @c.load(:id=>1, :name=>'a', :timestamp=>'1234')
11
- @db.sqls
12
- end
13
-
14
- it "should not include the lock column when updating" do
15
- @db.fetch = [[{:timestamp=>'2345'}]]
16
- @o.save
17
- @db.sqls.must_equal ["UPDATE TOP (1) items SET name = 'a' OUTPUT inserted.timestamp WHERE ((id = 1) AND (timestamp = 0x31323334))"]
18
- end
19
-
20
- it "should automatically update lock column using new value from database" do
21
- @db.fetch = [[{:timestamp=>'2345'}]]
22
- @o.save
23
- @o.timestamp.must_equal '2345'
24
- end
25
-
26
- it "should raise error when updating stale object" do
27
- @db.fetch = []
28
- @o.timestamp = '2345'
29
- proc{@o.save}.must_raise(Sequel::NoExistingObject)
30
- @o.timestamp.must_equal '2345'
31
- @db.sqls.must_equal ["UPDATE TOP (1) items SET name = 'a' OUTPUT inserted.timestamp WHERE ((id = 1) AND (timestamp = 0x32333435))"]
32
- end
33
-
34
- it "should raise error when destroying stale object" do
35
- @db.numrows = 0
36
- @o.timestamp = '2345'
37
- proc{@o.destroy}.must_raise(Sequel::NoExistingObject)
38
- @db.sqls.must_equal ["DELETE TOP (1) FROM items WHERE ((id = 1) AND (timestamp = 0x32333435))"]
39
- end
40
-
41
- it "should allow refresh after failed save" do
42
- @db.fetch = []
43
- @o.timestamp = '2345'
44
- proc{@o.save}.must_raise(Sequel::NoExistingObject)
45
- @db.fetch = {:id=>1, :name=>'a', :timestamp=>'2345'}
46
- @o.refresh
47
- @db.sqls
48
- @o.save
49
- @db.sqls.must_equal ["UPDATE TOP (1) items SET name = 'a' OUTPUT inserted.timestamp WHERE ((id = 1) AND (timestamp = 0x32333435))"]
50
- end
51
-
52
- it "should allow changing the lock column via model.lock_column=" do
53
- @c = Class.new(Sequel::Model(@ds))
54
- @c.columns :id, :name, :lv
55
- @c.plugin :mssql_optimistic_locking
56
- @c.lock_column = :lv
57
- @o = @c.load(:id=>1, :name=>'a', :lv=>'1234')
58
- @db.sqls
59
- @db.fetch = []
60
- proc{@o.save}.must_raise(Sequel::NoExistingObject)
61
- @o.lv.must_equal '1234'
62
- @db.sqls.must_equal ["UPDATE TOP (1) items SET name = 'a' OUTPUT inserted.lv WHERE ((id = 1) AND (lv = 0x31323334))"]
63
- @o = @c.load(:id=>1, :name=>'a', :lv=>'1234')
64
- @db.fetch = {:lv=>'2345'}
65
- @o.save
66
- @o.lv.must_equal '2345'
67
- end
68
-
69
- it "should allow changing the lock column via plugin option" do
70
- @c = Class.new(Sequel::Model(@ds))
71
- @c.columns :id, :name, :lv
72
- @c.plugin :mssql_optimistic_locking, :lock_column=>:lv
73
- @o = @c.load(:id=>1, :name=>'a', :lv=>'1234')
74
- @db.sqls
75
- @db.fetch = []
76
- proc{@o.save}.must_raise(Sequel::NoExistingObject)
77
- @o.lv.must_equal '1234'
78
- @db.sqls.must_equal ["UPDATE TOP (1) items SET name = 'a' OUTPUT inserted.lv WHERE ((id = 1) AND (lv = 0x31323334))"]
79
- @o = @c.load(:id=>1, :name=>'a', :lv=>'1234')
80
- @db.fetch = {:lv=>'2345'}
81
- @o.save
82
- @o.lv.must_equal '2345'
83
- end
84
-
85
- it "should work when subclassing" do
86
- c = Class.new(@c)
87
- o = c.load(:id=>1, :name=>'a', :timestamp=>'1234')
88
- @db.fetch = [[{:timestamp=>'2345'}]]
89
- o.save
90
- @db.sqls.must_equal ["UPDATE TOP (1) items SET name = 'a' OUTPUT inserted.timestamp WHERE ((id = 1) AND (timestamp = 0x31323334))"]
91
- end
92
- end
@@ -1,109 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- begin
4
- require 'tzinfo'
5
- rescue LoadError
6
- warn "Skipping test of named_timezones extension: can't load tzinfo"
7
- else
8
- Sequel.extension :thread_local_timezones
9
- Sequel.extension :named_timezones
10
- Sequel.datetime_class = Time
11
-
12
- describe "Sequel named_timezones extension" do
13
- before do
14
- @tz_in = TZInfo::Timezone.get('America/Los_Angeles')
15
- @tz_out = TZInfo::Timezone.get('America/New_York')
16
- @db = Sequel.mock
17
- @dt = DateTime.civil(2009,6,1,10,20,30,0)
18
- Sequel.application_timezone = 'America/Los_Angeles'
19
- Sequel.database_timezone = 'America/New_York'
20
- Sequel.datetime_class = DateTime
21
- end
22
- after do
23
- Sequel.tzinfo_disambiguator = nil
24
- Sequel.default_timezone = nil
25
- Sequel.datetime_class = Time
26
- end
27
-
28
- it "should convert string arguments to *_timezone= to TZInfo::Timezone instances" do
29
- Sequel.application_timezone.must_equal @tz_in
30
- Sequel.database_timezone.must_equal @tz_out
31
- end
32
-
33
- it "should convert string arguments for Database#timezone= to TZInfo::Timezone instances for database-specific timezones" do
34
- @db.extension :named_timezones
35
- @db.timezone = 'America/Los_Angeles'
36
- @db.timezone.must_equal @tz_in
37
- end
38
-
39
- it "should accept TZInfo::Timezone instances in *_timezone=" do
40
- Sequel.application_timezone = @tz_in
41
- Sequel.database_timezone = @tz_out
42
- Sequel.application_timezone.must_equal @tz_in
43
- Sequel.database_timezone.must_equal @tz_out
44
- end
45
-
46
- it "should convert datetimes going into the database to named database_timezone" do
47
- ds = @db[:a].with_extend do
48
- def supports_timestamp_timezones?; true; end
49
- def supports_timestamp_usecs?; false; end
50
- end
51
- ds.insert([@dt, DateTime.civil(2009,6,1,3,20,30,-7/24.0), DateTime.civil(2009,6,1,6,20,30,-1/6.0)])
52
- @db.sqls.must_equal ["INSERT INTO a VALUES ('2009-06-01 06:20:30-0400', '2009-06-01 06:20:30-0400', '2009-06-01 06:20:30-0400')"]
53
- end
54
-
55
- it "should convert datetimes coming out of the database from database_timezone to application_timezone" do
56
- dt = Sequel.database_to_application_timestamp('2009-06-01 06:20:30-0400')
57
- dt.must_equal @dt
58
- dt.offset.must_equal(-7/24.0)
59
-
60
- dt = Sequel.database_to_application_timestamp('2009-06-01 10:20:30+0000')
61
- dt.must_equal @dt
62
- dt.offset.must_equal(-7/24.0)
63
- end
64
-
65
- it "should raise an error for ambiguous timezones by default" do
66
- proc{Sequel.database_to_application_timestamp('2004-10-31T01:30:00')}.must_raise(Sequel::InvalidValue)
67
- end
68
-
69
- it "should support tzinfo_disambiguator= to handle ambiguous timezones automatically" do
70
- Sequel.tzinfo_disambiguator = proc{|datetime, periods| periods.first}
71
- Sequel.database_to_application_timestamp('2004-10-31T01:30:00').must_equal DateTime.parse('2004-10-30T22:30:00-07:00')
72
- end
73
-
74
- it "should assume datetimes coming out of the database that don't have an offset as coming from database_timezone" do
75
- dt = Sequel.database_to_application_timestamp('2009-06-01 06:20:30')
76
- dt.must_equal @dt
77
- dt.offset.must_equal(-7/24.0)
78
-
79
- dt = Sequel.database_to_application_timestamp('2009-06-01 10:20:30')
80
- dt.must_equal @dt + 1/6.0
81
- dt.offset.must_equal(-7/24.0)
82
- end
83
-
84
- it "should work with the thread_local_timezones extension" do
85
- q, q1, q2 = Queue.new, Queue.new, Queue.new
86
- tz1, tz2 = nil, nil
87
- t1 = Thread.new do
88
- Sequel.thread_application_timezone = 'America/New_York'
89
- q2.push nil
90
- q.pop
91
- tz1 = Sequel.application_timezone
92
- end
93
- t2 = Thread.new do
94
- Sequel.thread_application_timezone = 'America/Los_Angeles'
95
- q2.push nil
96
- q1.pop
97
- tz2 = Sequel.application_timezone
98
- end
99
- q2.pop
100
- q2.pop
101
- q.push nil
102
- q1.push nil
103
- t1.join
104
- t2.join
105
- tz1.must_equal @tz_out
106
- tz2.must_equal @tz_in
107
- end
108
- end
109
- end
@@ -1,703 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "NestedAttributes plugin" do
4
- def check_sqls(should, is)
5
- if should.is_a?(Array)
6
- should.must_include(is)
7
- else
8
- is.must_equal should
9
- end
10
- end
11
-
12
- def check_sql_array(*shoulds)
13
- sqls = @db.sqls
14
- sqls.length.must_equal shoulds.length
15
- shoulds.zip(sqls){|s, i| check_sqls(s, i)}
16
- end
17
-
18
- before do
19
- @db = Sequel.mock(:autoid=>1, :numrows=>1)
20
- @c = Class.new(Sequel::Model(@db))
21
- @c.plugin :nested_attributes
22
- @Artist = Class.new(@c).set_dataset(:artists)
23
- @Album = Class.new(@c).set_dataset(:albums)
24
- @Tag = Class.new(@c).set_dataset(:tags)
25
- @Concert = Class.new(@c).set_dataset(:concerts)
26
- @Artist.plugin :skip_create_refresh
27
- @Album.plugin :skip_create_refresh
28
- @Tag.plugin :skip_create_refresh
29
- @Concert.plugin :skip_create_refresh
30
- @Artist.columns :id, :name
31
- @Album.columns :id, :name, :artist_id
32
- @Tag.columns :id, :name
33
- @Concert.columns :tour, :date, :artist_id, :playlist
34
- @Concert.set_primary_key([:tour, :date])
35
- @Concert.unrestrict_primary_key
36
- @Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id
37
- @Artist.one_to_many :concerts, :class=>@Concert, :key=>:artist_id
38
- @Artist.one_to_one :first_album, :class=>@Album, :key=>:artist_id
39
- @Artist.one_to_one :first_concert, :class=>@Concert, :key=>:artist_id
40
- @Concert.one_to_many :albums, :class=>@Album, :key=>:artist_id, :primary_key=>:artist_id
41
- @Album.many_to_one :artist, :class=>@Artist, :reciprocal=>:albums
42
- @Album.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at
43
- @Tag.many_to_many :albums, :class=>@Album, :left_key=>:tag_id, :right_key=>:album_id, :join_table=>:at
44
- @Artist.nested_attributes :albums, :first_album, :destroy=>true, :remove=>true
45
- @Artist.nested_attributes :concerts, :destroy=>true, :remove=>true
46
- @Album.nested_attributes :artist, :tags, :destroy=>true, :remove=>true
47
- @Artist.nested_attributes :first_concert
48
- @Concert.nested_attributes :albums
49
- @db.sqls
50
- end
51
-
52
- it "should support creating new many_to_one objects" do
53
- a = @Album.new({:name=>'Al', :artist_attributes=>{:name=>'Ar'}})
54
- @db.sqls.must_equal []
55
- a.save
56
- check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
57
- ["INSERT INTO albums (name, artist_id) VALUES ('Al', 1)", "INSERT INTO albums (artist_id, name) VALUES (1, 'Al')"])
58
- end
59
-
60
- it "should support creating new one_to_one objects" do
61
- a = @Artist.new(:name=>'Ar')
62
- a.id = 1
63
- a.first_album_attributes = {:name=>'Al'}
64
- @db.sqls.must_equal []
65
- a.save
66
- check_sql_array(["INSERT INTO artists (name, id) VALUES ('Ar', 1)", "INSERT INTO artists (id, name) VALUES (1, 'Ar')"],
67
- "UPDATE albums SET artist_id = NULL WHERE (artist_id = 1)",
68
- ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
69
- end
70
-
71
- it "should support creating new one_to_many objects" do
72
- a = @Artist.new({:name=>'Ar', :albums_attributes=>[{:name=>'Al'}]})
73
- @db.sqls.must_equal []
74
- a.save
75
- check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
76
- ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
77
- end
78
-
79
- it "should support creating new one_to_many and one_to_one objects with presence validations on the foreign key" do
80
- @Album.class_eval do
81
- plugin :validation_helpers
82
- def validate
83
- validates_integer :artist_id
84
- super
85
- end
86
- end
87
- a = @Artist.new({:name=>'Ar', :albums_attributes=>[{:name=>'Al'}]})
88
- @db.sqls.must_equal []
89
- a.save
90
- check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
91
- ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
92
-
93
- a = @Artist.new(:name=>'Ar')
94
- a.id = 1
95
- a.first_album_attributes = {:name=>'Al'}
96
- @db.sqls.must_equal []
97
- a.save
98
- check_sql_array(["INSERT INTO artists (name, id) VALUES ('Ar', 1)", "INSERT INTO artists (id, name) VALUES (1, 'Ar')"],
99
- "UPDATE albums SET artist_id = NULL WHERE (artist_id = 1)",
100
- ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
101
- end
102
-
103
- it "should support creating new one_to_many and one_to_one objects with composite keys with presence validations on the foreign key" do
104
- insert = nil
105
- @Album.class_eval do
106
- plugin :validation_helpers
107
- def validate
108
- validates_integer :artist_id
109
- super
110
- end
111
- end
112
- @Concert.class_eval do
113
- define_method :_insert do
114
- insert = values.dup
115
- end
116
- def before_create # Have to define the CPK somehow.
117
- self.tour = 'To'
118
- self.date = '2004-04-05'
119
- super
120
- end
121
- def after_create
122
- super
123
- self.artist_id = 3
124
- end
125
- end
126
-
127
- c = @Concert.new(:playlist=>'Pl')
128
- @db.sqls.must_equal []
129
- c.albums_attributes = [{:name=>'Al'}]
130
- c.save
131
- insert.must_equal(:tour=>'To', :date=>'2004-04-05', :playlist=>'Pl')
132
- check_sql_array(["INSERT INTO albums (name, artist_id) VALUES ('Al', 3)", "INSERT INTO albums (artist_id, name) VALUES (3, 'Al')"])
133
-
134
- @Concert.class_eval do
135
- plugin :validation_helpers
136
- def validate
137
- validates_integer :artist_id
138
- super
139
- end
140
- end
141
-
142
- a = @Artist.new(:name=>'Ar')
143
- a.id = 1
144
- a.first_concert_attributes = {:playlist=>'Pl'}
145
- @db.sqls.must_equal []
146
- a.save
147
- check_sql_array(["INSERT INTO artists (name, id) VALUES ('Ar', 1)", "INSERT INTO artists (id, name) VALUES (1, 'Ar')"],
148
- "UPDATE concerts SET artist_id = NULL WHERE (artist_id = 1)")
149
- insert.must_equal(:tour=>'To', :date=>'2004-04-05', :artist_id=>1, :playlist=>'Pl')
150
- end
151
-
152
- it "should should not remove existing values from object when validating" do
153
- @Artist.one_to_one :first_album, :class=>@Album, :key=>:id
154
- @Artist.nested_attributes :first_album
155
- @db.fetch = {:id=>1}
156
- a = @Artist.load(:id=>1)
157
- a.set(:first_album_attributes=>{:id=>1, :name=>'Ar'})
158
- a.first_album.values.must_equal(:id=>1, :name=>'Ar')
159
- @db.sqls.must_equal ["SELECT * FROM albums WHERE (albums.id = 1) LIMIT 1"]
160
- a.save_changes
161
- check_sql_array("UPDATE albums SET name = 'Ar' WHERE (id = 1)")
162
- end
163
-
164
- it "should support creating new many_to_many objects" do
165
- a = @Album.new({:name=>'Al', :tags_attributes=>[{:name=>'T'}]})
166
- @db.sqls.must_equal []
167
- a.save
168
- check_sql_array("INSERT INTO albums (name) VALUES ('Al')",
169
- "INSERT INTO tags (name) VALUES ('T')",
170
- ["INSERT INTO at (album_id, tag_id) VALUES (1, 2)", "INSERT INTO at (tag_id, album_id) VALUES (2, 1)"])
171
- end
172
-
173
- it "should add new objects to the cached association array as soon as the *_attributes= method is called" do
174
- a = @Artist.new({:name=>'Ar', :first_album_attributes=>{:name=>'B'}, :albums_attributes=>[{:name=>'Al', :tags_attributes=>[{:name=>'T'}]}]})
175
- a.albums.must_equal [@Album.new(:name=>'Al')]
176
- a.albums.first.artist.must_equal a
177
- a.albums.first.tags.must_equal [@Tag.new(:name=>'T')]
178
- a.first_album.must_equal @Album.new(:name=>'B')
179
- a.first_album.artist.must_equal a
180
- end
181
-
182
- it "should support creating new objects with composite primary keys" do
183
- insert = nil
184
- @Concert.class_eval do
185
- define_method :_insert do
186
- insert = values.dup
187
- end
188
- def before_create # Have to define the CPK somehow.
189
- self.tour = 'To'
190
- self.date = '2004-04-05'
191
- super
192
- end
193
- end
194
- a = @Artist.new({:name=>'Ar', :concerts_attributes=>[{:playlist=>'Pl'}]})
195
- @db.sqls.must_equal []
196
- a.save
197
- @db.sqls.must_equal ["INSERT INTO artists (name) VALUES ('Ar')"]
198
- insert.must_equal(:tour=>'To', :date=>'2004-04-05', :artist_id=>1, :playlist=>'Pl')
199
- end
200
-
201
- it "should support creating new objects with specific primary keys if :unmatched_pk => :create is set" do
202
- @Artist.nested_attributes :albums, :unmatched_pk=>:create
203
- insert = nil
204
- @Album.class_eval do
205
- unrestrict_primary_key
206
- define_method :_insert do
207
- insert = values.dup
208
- end
209
- end
210
- a = @Artist.new({:name=>'Ar', :albums_attributes=>[{:id=>7, :name=>'Al'}]})
211
- @db.sqls.must_equal []
212
- a.save
213
- @db.sqls.must_equal ["INSERT INTO artists (name) VALUES ('Ar')"]
214
- insert.must_equal(:artist_id=>1, :name=>'Al', :id=>7)
215
- end
216
-
217
- it "should support creating new objects with specific composite primary keys if :unmatched_pk => :create is set" do
218
- insert = nil
219
- @Artist.nested_attributes :concerts, :unmatched_pk=>:create
220
- @Concert.class_eval do
221
- define_method :_insert do
222
- insert = values.dup
223
- end
224
- end
225
- a = @Artist.new({:name=>'Ar', :concerts_attributes=>[{:tour=>'To', :date=>'2004-04-05', :playlist=>'Pl'}]})
226
- @db.sqls.must_equal []
227
- a.save
228
- @db.sqls.must_equal ["INSERT INTO artists (name) VALUES ('Ar')"]
229
- insert.must_equal(:tour=>'To', :date=>'2004-04-05', :artist_id=>1, :playlist=>'Pl')
230
- end
231
-
232
- it "should support updating many_to_one objects" do
233
- al = @Album.load(:id=>10, :name=>'Al')
234
- ar = @Artist.load(:id=>20, :name=>'Ar')
235
- al.associations[:artist] = ar
236
- al.set(:artist_attributes=>{:id=>'20', :name=>'Ar2'})
237
- @db.sqls.must_equal []
238
- al.save
239
- @db.sqls.must_equal ["UPDATE albums SET name = 'Al' WHERE (id = 10)", "UPDATE artists SET name = 'Ar2' WHERE (id = 20)"]
240
- end
241
-
242
- it "should support updating one_to_one objects" do
243
- al = @Album.load(:id=>10, :name=>'Al')
244
- ar = @Artist.load(:id=>20, :name=>'Ar')
245
- ar.associations[:first_album] = al
246
- ar.set(:first_album_attributes=>{:id=>10, :name=>'Al2'})
247
- @db.sqls.must_equal []
248
- ar.save
249
- @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'Al2' WHERE (id = 10)"]
250
- end
251
-
252
- it "should support updating one_to_many objects" do
253
- al = @Album.load(:id=>10, :name=>'Al')
254
- ar = @Artist.load(:id=>20, :name=>'Ar')
255
- ar.associations[:albums] = [al]
256
- ar.set(:albums_attributes=>[{:id=>10, :name=>'Al2'}])
257
- @db.sqls.must_equal []
258
- ar.save
259
- @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'Al2' WHERE (id = 10)"]
260
- end
261
-
262
- it "should support updating one_to_many objects with _delete/_remove flags set to false" do
263
- al = @Album.load(:id=>10, :name=>'Al')
264
- ar = @Artist.load(:id=>20, :name=>'Ar')
265
- ar.associations[:albums] = [al]
266
- ar.set(:albums_attributes=>[{:id=>10, :name=>'Al2', :_delete => 'f', :_remove => '0'}])
267
- @db.sqls.must_equal []
268
- ar.save
269
- @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "UPDATE albums SET name = 'Al2' WHERE (id = 10)"]
270
- end
271
-
272
- it "should support updating many_to_many objects" do
273
- a = @Album.load(:id=>10, :name=>'Al')
274
- t = @Tag.load(:id=>20, :name=>'T')
275
- a.associations[:tags] = [t]
276
- a.set(:tags_attributes=>[{:id=>20, :name=>'T2'}])
277
- @db.sqls.must_equal []
278
- a.save
279
- @db.sqls.must_equal ["UPDATE albums SET name = 'Al' WHERE (id = 10)", "UPDATE tags SET name = 'T2' WHERE (id = 20)"]
280
- end
281
-
282
- it "should support updating many_to_many objects with _delete/_remove flags set to false" do
283
- a = @Album.load(:id=>10, :name=>'Al')
284
- t = @Tag.load(:id=>20, :name=>'T')
285
- a.associations[:tags] = [t]
286
- a.set(:tags_attributes=>[{:id=>20, :name=>'T2', '_delete' => false, '_remove' => 'F'}])
287
- @db.sqls.must_equal []
288
- a.save
289
- @db.sqls.must_equal ["UPDATE albums SET name = 'Al' WHERE (id = 10)", "UPDATE tags SET name = 'T2' WHERE (id = 20)"]
290
- end
291
-
292
- it "should support updating objects with composite primary keys" do
293
- ar = @Artist.load(:id=>10, :name=>'Ar')
294
- co = @Concert.load(:tour=>'To', :date=>'2004-04-05', :playlist=>'Pl')
295
- ar.associations[:concerts] = [co]
296
- ar.set(:concerts_attributes=>[{:tour=>'To', :date=>'2004-04-05', :playlist=>'Pl2'}])
297
- @db.sqls.must_equal []
298
- ar.save
299
- check_sql_array("UPDATE artists SET name = 'Ar' WHERE (id = 10)", ["UPDATE concerts SET playlist = 'Pl2' WHERE ((tour = 'To') AND (date = '2004-04-05'))", "UPDATE concerts SET playlist = 'Pl2' WHERE ((date = '2004-04-05') AND (tour = 'To'))"])
300
- end
301
-
302
- it "should support removing many_to_one objects" do
303
- al = @Album.load(:id=>10, :name=>'Al')
304
- ar = @Artist.load(:id=>20, :name=>'Ar')
305
- al.associations[:artist] = ar
306
- al.set(:artist_attributes=>{:id=>'20', :_remove=>'1'})
307
- @db.sqls.must_equal []
308
- al.save
309
- check_sql_array(["UPDATE albums SET artist_id = NULL, name = 'Al' WHERE (id = 10)", "UPDATE albums SET name = 'Al', artist_id = NULL WHERE (id = 10)"])
310
- end
311
-
312
- it "should support removing one_to_one objects" do
313
- al = @Album.load(:id=>10, :name=>'Al')
314
- ar = @Artist.load(:id=>20, :name=>'Ar')
315
- ar.associations[:first_album] = al
316
- ar.set(:first_album_attributes=>{:id=>10, :_remove=>'t'})
317
- @db.sqls.must_equal []
318
- ar.save
319
- @db.sqls.must_equal ["UPDATE albums SET artist_id = NULL WHERE (artist_id = 20)", "UPDATE artists SET name = 'Ar' WHERE (id = 20)"]
320
- end
321
-
322
- it "should support removing one_to_many objects" do
323
- al = @Album.load(:id=>10, :name=>'Al')
324
- ar = @Artist.load(:id=>20, :name=>'Ar')
325
- ar.associations[:albums] = [al]
326
- ar.set(:albums_attributes=>[{:id=>10, :_remove=>'t'}])
327
- ar.associations[:albums].must_equal []
328
- @db.sqls.must_equal []
329
- @Album.dataset = @Album.dataset.with_fetch(:id=>1)
330
- ar.save
331
- check_sql_array("SELECT 1 AS one FROM albums WHERE ((albums.artist_id = 20) AND (id = 10)) LIMIT 1",
332
- ["UPDATE albums SET artist_id = NULL, name = 'Al' WHERE (id = 10)", "UPDATE albums SET name = 'Al', artist_id = NULL WHERE (id = 10)"],
333
- "UPDATE artists SET name = 'Ar' WHERE (id = 20)")
334
- end
335
-
336
- it "should support removing many_to_many objects" do
337
- a = @Album.load(:id=>10, :name=>'Al')
338
- t = @Tag.load(:id=>20, :name=>'T')
339
- a.associations[:tags] = [t]
340
- a.set(:tags_attributes=>[{:id=>20, :_remove=>true}])
341
- a.associations[:tags].must_equal []
342
- @db.sqls.must_equal []
343
- a.save
344
- @db.sqls.must_equal ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)"]
345
- end
346
-
347
- it "should support removing objects with composite primary keys" do
348
- ar = @Artist.load(:id=>10, :name=>'Ar')
349
- co = @Concert.load(:tour=>'To', :date=>'2004-04-05', :playlist=>'Pl')
350
- ar.associations[:concerts] = [co]
351
- ar.set(:concerts_attributes=>[{:tour=>'To', :date=>'2004-04-05', :_remove=>'t'}])
352
- @db.sqls.must_equal []
353
- @Concert.dataset = @Concert.dataset.with_fetch(:id=>1)
354
- ar.save
355
- check_sql_array(["SELECT 1 AS one FROM concerts WHERE ((concerts.artist_id = 10) AND (tour = 'To') AND (date = '2004-04-05')) LIMIT 1", "SELECT 1 AS one FROM concerts WHERE ((concerts.artist_id = 10) AND (date = '2004-04-05') AND (tour = 'To')) LIMIT 1"],
356
- ["UPDATE concerts SET artist_id = NULL, playlist = 'Pl' WHERE ((tour = 'To') AND (date = '2004-04-05'))", "UPDATE concerts SET playlist = 'Pl', artist_id = NULL WHERE ((tour = 'To') AND (date = '2004-04-05'))", "UPDATE concerts SET artist_id = NULL, playlist = 'Pl' WHERE ((date = '2004-04-05') AND (tour = 'To'))", "UPDATE concerts SET playlist = 'Pl', artist_id = NULL WHERE ((date = '2004-04-05') AND (tour = 'To'))"],
357
- "UPDATE artists SET name = 'Ar' WHERE (id = 10)")
358
- end
359
-
360
- it "should support destroying many_to_one objects" do
361
- al = @Album.load(:id=>10, :name=>'Al')
362
- ar = @Artist.load(:id=>20, :name=>'Ar')
363
- al.associations[:artist] = ar
364
- al.set(:artist_attributes=>{:id=>'20', :_delete=>'1'})
365
- @db.sqls.must_equal []
366
- al.save
367
- check_sql_array(["UPDATE albums SET artist_id = NULL, name = 'Al' WHERE (id = 10)", "UPDATE albums SET name = 'Al', artist_id = NULL WHERE (id = 10)"],
368
- "DELETE FROM artists WHERE (id = 20)")
369
- end
370
-
371
- it "should support destroying one_to_one objects" do
372
- al = @Album.load(:id=>10, :name=>'Al')
373
- ar = @Artist.load(:id=>20, :name=>'Ar')
374
- ar.associations[:first_album] = al
375
- ar.set(:first_album_attributes=>{:id=>10, :_delete=>'t'})
376
- @db.sqls.must_equal []
377
- ar.save
378
- @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "DELETE FROM albums WHERE (id = 10)"]
379
- end
380
-
381
- it "should support destroying one_to_many objects" do
382
- al = @Album.load(:id=>10, :name=>'Al')
383
- ar = @Artist.load(:id=>20, :name=>'Ar')
384
- ar.associations[:albums] = [al]
385
- ar.set(:albums_attributes=>[{:id=>10, :_delete=>'t'}])
386
- @db.sqls.must_equal []
387
- ar.save
388
- @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)", "DELETE FROM albums WHERE (id = 10)"]
389
- end
390
-
391
- it "should support destroying many_to_many objects" do
392
- a = @Album.load(:id=>10, :name=>'Al')
393
- t = @Tag.load(:id=>20, :name=>'T')
394
- a.associations[:tags] = [t]
395
- a.set(:tags_attributes=>[{:id=>20, :_delete=>true}])
396
- @db.sqls.must_equal []
397
- a.save
398
- @db.sqls.must_equal ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)", "DELETE FROM tags WHERE (id = 20)"]
399
- end
400
-
401
- it "should support destroying objects with composite primary keys" do
402
- ar = @Artist.load(:id=>10, :name=>'Ar')
403
- co = @Concert.load(:tour=>'To', :date=>'2004-04-05', :playlist=>'Pl')
404
- ar.associations[:concerts] = [co]
405
- ar.set(:concerts_attributes=>[{:tour=>'To', :date=>'2004-04-05', :_delete=>'t'}])
406
- @db.sqls.must_equal []
407
- ar.save
408
- check_sql_array("UPDATE artists SET name = 'Ar' WHERE (id = 10)", ["DELETE FROM concerts WHERE ((tour = 'To') AND (date = '2004-04-05'))", "DELETE FROM concerts WHERE ((date = '2004-04-05') AND (tour = 'To'))"])
409
- end
410
-
411
- it "should support both string and symbol keys in nested attribute hashes" do
412
- a = @Album.load(:id=>10, :name=>'Al')
413
- t = @Tag.load(:id=>20, :name=>'T')
414
- a.associations[:tags] = [t]
415
- a.set('tags_attributes'=>[{'id'=>20, '_delete'=>true}])
416
- @db.sqls.must_equal []
417
- a.save
418
- @db.sqls.must_equal ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)", "DELETE FROM tags WHERE (id = 20)"]
419
- end
420
-
421
- it "should support using a hash instead of an array for to_many nested attributes" do
422
- a = @Album.load(:id=>10, :name=>'Al')
423
- t = @Tag.load(:id=>20, :name=>'T')
424
- a.associations[:tags] = [t]
425
- a.set('tags_attributes'=>{'1'=>{'id'=>20, '_delete'=>true}})
426
- @db.sqls.must_equal []
427
- a.save
428
- @db.sqls.must_equal ["DELETE FROM at WHERE ((album_id = 10) AND (tag_id = 20))", "UPDATE albums SET name = 'Al' WHERE (id = 10)", "DELETE FROM tags WHERE (id = 20)"]
429
- end
430
-
431
- it "should only allow destroying associated objects if :destroy option is used in the nested_attributes call" do
432
- a = @Album.load(:id=>10, :name=>'Al')
433
- ar = @Artist.load(:id=>20, :name=>'Ar')
434
- a.associations[:artist] = ar
435
- @Album.nested_attributes :artist
436
- proc{a.set(:artist_attributes=>{:id=>'20', :_delete=>'1'})}.must_raise(Sequel::MassAssignmentRestriction)
437
- @Album.nested_attributes :artist, :destroy=>true
438
- a.set(:artist_attributes=>{:id=>'20', :_delete=>'1'})
439
- end
440
-
441
- it "should only allow removing associated objects if :remove option is used in the nested_attributes call" do
442
- a = @Album.load(:id=>10, :name=>'Al')
443
- ar = @Artist.load(:id=>20, :name=>'Ar')
444
- a.associations[:artist] = ar
445
- @Album.nested_attributes :artist
446
- proc{a.set(:artist_attributes=>{:id=>'20', :_remove=>'1'})}.must_raise(Sequel::MassAssignmentRestriction)
447
- @Album.nested_attributes :artist, :remove=>true
448
- a.set(:artist_attributes=>{:id=>'20', :_remove=>'1'})
449
- end
450
-
451
- it "should raise an Error if a primary key is given in a nested attribute hash, but no matching associated object exists" do
452
- al = @Album.load(:id=>10, :name=>'Al')
453
- ar = @Artist.load(:id=>20, :name=>'Ar')
454
- ar.associations[:albums] = [al]
455
- proc{ar.set(:albums_attributes=>[{:id=>30, :_delete=>'t'}])}.must_raise(Sequel::Error)
456
- ar.set(:albums_attributes=>[{:id=>10, :_delete=>'t'}])
457
- end
458
-
459
- it "should not raise an Error if an unmatched primary key is given, if the :unmatched_pk=>:ignore option is used" do
460
- @Artist.nested_attributes :albums, :unmatched_pk=>:ignore
461
- al = @Album.load(:id=>10, :name=>'Al')
462
- ar = @Artist.load(:id=>20, :name=>'Ar')
463
- ar.associations[:albums] = [al]
464
- ar.set(:albums_attributes=>[{:id=>30, :_delete=>'t'}])
465
- @db.sqls.must_equal []
466
- ar.save
467
- @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 20)"]
468
- end
469
-
470
- it "should raise an Error if a composite primary key is given in a nested attribute hash, but no matching associated object exists" do
471
- ar = @Artist.load(:id=>10, :name=>'Ar')
472
- co = @Concert.load(:tour=>'To', :date=>'2004-04-05', :playlist=>'Pl')
473
- ar.associations[:concerts] = [co]
474
- proc{ar.set(:concerts_attributes=>[{:tour=>'To', :date=>'2004-04-04', :_delete=>'t'}])}.must_raise(Sequel::Error)
475
- ar.set(:concerts_attributes=>[{:tour=>'To', :date=>'2004-04-05', :_delete=>'t'}])
476
- end
477
-
478
- it "should not raise an Error if an unmatched composite primary key is given, if the :unmatched_pk=>:ignore option is used" do
479
- @Artist.nested_attributes :concerts, :unmatched_pk=>:ignore
480
- ar = @Artist.load(:id=>10, :name=>'Ar')
481
- co = @Concert.load(:tour=>'To', :date=>'2004-04-05', :playlist=>'Pl')
482
- ar.associations[:concerts] = [co]
483
- ar.set(:concerts_attributes=>[{:tour=>'To', :date=>'2004-04-06', :_delete=>'t'}])
484
- @db.sqls.must_equal []
485
- ar.save
486
- @db.sqls.must_equal ["UPDATE artists SET name = 'Ar' WHERE (id = 10)"]
487
- end
488
-
489
- it "should not save if nested attribute is not valid and should include nested attribute validation errors in the main object's validation errors" do
490
- @Artist.class_eval do
491
- def validate
492
- super
493
- errors.add(:name, 'cannot be Ar') if name == 'Ar'
494
- end
495
- end
496
- a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
497
- @db.sqls.must_equal []
498
- proc{a.save}.must_raise(Sequel::ValidationFailed)
499
- a.errors.full_messages.must_equal ['artist name cannot be Ar']
500
- @db.sqls.must_equal []
501
- # Should preserve attributes
502
- a.artist.name.must_equal 'Ar'
503
- end
504
-
505
- it "should not attempt to validate nested attributes if the :validate=>false association option is used" do
506
- @Album.many_to_one :artist, :class=>@Artist, :validate=>false, :reciprocal=>nil
507
- @Album.nested_attributes :artist, :tags, :destroy=>true, :remove=>true
508
- @Artist.class_eval do
509
- def validate
510
- super
511
- errors.add(:name, 'cannot be Ar') if name == 'Ar'
512
- end
513
- end
514
- a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
515
- @db.sqls.must_equal []
516
- a.save
517
- check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
518
- ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
519
- end
520
-
521
- it "should not attempt to validate nested attributes if the :validate=>false option is passed to save" do
522
- @Artist.class_eval do
523
- def validate
524
- super
525
- errors.add(:name, 'cannot be Ar') if name == 'Ar'
526
- end
527
- end
528
- a = @Album.new(:name=>'Al', :artist_attributes=>{:name=>'Ar'})
529
- @db.sqls.must_equal []
530
- a.save(:validate=>false)
531
- check_sql_array("INSERT INTO artists (name) VALUES ('Ar')",
532
- ["INSERT INTO albums (artist_id, name) VALUES (1, 'Al')", "INSERT INTO albums (name, artist_id) VALUES ('Al', 1)"])
533
- end
534
-
535
- it "should not accept nested attributes unless explicitly specified" do
536
- @Artist.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at
537
- proc{@Artist.create({:name=>'Ar', :tags_attributes=>[{:name=>'T'}]})}.must_raise(Sequel::MassAssignmentRestriction)
538
- @db.sqls.must_equal []
539
- end
540
-
541
- it "should save when save_changes or update is called if nested attribute associated objects changed but there are no changes to the main object" do
542
- al = @Album.load(:id=>10, :name=>'Al')
543
- ar = @Artist.load(:id=>20, :name=>'Ar')
544
- al.associations[:artist] = ar
545
- @db.sqls.must_equal []
546
- al.update(:artist_attributes=>{:id=>'20', :name=>'Ar2'})
547
- @db.sqls.must_equal ["UPDATE artists SET name = 'Ar2' WHERE (id = 20)"]
548
- end
549
-
550
- it "should have a :limit option limiting the amount of entries" do
551
- @Album.nested_attributes :tags, :limit=>2
552
- arr = [{:name=>'T'}]
553
- proc{@Album.new({:name=>'Al', :tags_attributes=>arr*3})}.must_raise(Sequel::Error)
554
- a = @Album.new({:name=>'Al', :tags_attributes=>arr*2})
555
- @db.sqls.must_equal []
556
- a.save
557
- check_sql_array("INSERT INTO albums (name) VALUES ('Al')",
558
- "INSERT INTO tags (name) VALUES ('T')",
559
- ["INSERT INTO at (album_id, tag_id) VALUES (1, 2)", "INSERT INTO at (tag_id, album_id) VALUES (2, 1)"],
560
- "INSERT INTO tags (name) VALUES ('T')",
561
- ["INSERT INTO at (album_id, tag_id) VALUES (1, 4)", "INSERT INTO at (tag_id, album_id) VALUES (4, 1)"])
562
- end
563
-
564
- it "should accept a block that each hash gets passed to determine if it should be processed" do
565
- @Album.nested_attributes(:tags){|h| h[:name].empty?}
566
- a = @Album.new({:name=>'Al', :tags_attributes=>[{:name=>'T'}, {:name=>''}, {:name=>'T2'}]})
567
- @db.sqls.must_equal []
568
- a.save
569
- check_sql_array("INSERT INTO albums (name) VALUES ('Al')",
570
- "INSERT INTO tags (name) VALUES ('T')",
571
- ["INSERT INTO at (album_id, tag_id) VALUES (1, 2)", "INSERT INTO at (tag_id, album_id) VALUES (2, 1)"],
572
- "INSERT INTO tags (name) VALUES ('T2')",
573
- ["INSERT INTO at (album_id, tag_id) VALUES (1, 4)", "INSERT INTO at (tag_id, album_id) VALUES (4, 1)"])
574
- end
575
-
576
- it "should accept a :transform block that returns a changed attributes hash" do
577
- @Album.nested_attributes :tags, :transform=>proc{|parent, hash| hash[:name] << parent.name; hash }
578
- a = @Album.new(:name => 'Al')
579
- a.set(:tags_attributes=>[{:name=>'T'.dup}, {:name=>'T2'.dup}])
580
- @db.sqls.must_equal []
581
- a.save
582
- check_sql_array("INSERT INTO albums (name) VALUES ('Al')",
583
- "INSERT INTO tags (name) VALUES ('TAl')",
584
- ["INSERT INTO at (album_id, tag_id) VALUES (1, 2)", "INSERT INTO at (tag_id, album_id) VALUES (2, 1)"],
585
- "INSERT INTO tags (name) VALUES ('T2Al')",
586
- ["INSERT INTO at (album_id, tag_id) VALUES (1, 4)", "INSERT INTO at (tag_id, album_id) VALUES (4, 1)"])
587
- end
588
-
589
- it "should return objects created/modified in the internal methods" do
590
- @Album.nested_attributes :tags, :remove=>true, :unmatched_pk=>:ignore
591
- objs = []
592
- @Album.class_eval do
593
- define_method(:nested_attributes_create){|*a| objs << [super(*a), :create]}
594
- define_method(:nested_attributes_remove){|*a| objs << [super(*a), :remove]}
595
- define_method(:nested_attributes_update){|*a| objs << [super(*a), :update]}
596
- end
597
- a = @Album.new(:name=>'Al')
598
- a.associations[:tags] = [@Tag.load(:id=>6, :name=>'A'), @Tag.load(:id=>7, :name=>'A2')]
599
- a.tags_attributes = [{:id=>6, :name=>'T'}, {:id=>7, :name=>'T2', :_remove=>true}, {:name=>'T3'}, {:id=>8, :name=>'T4'}, {:id=>9, :name=>'T5', :_remove=>true}]
600
- objs.must_equal [[@Tag.load(:id=>6, :name=>'T'), :update], [@Tag.load(:id=>7, :name=>'A2'), :remove], [@Tag.new(:name=>'T3'), :create]]
601
- end
602
-
603
- it "should raise an error if updating modifies the associated objects keys" do
604
- @Artist.columns :id, :name, :artist_id
605
- @Album.columns :id, :name, :artist_id
606
- @Tag.columns :id, :name, :tag_id
607
- @Artist.one_to_many :albums, :class=>@Album, :key=>:artist_id, :primary_key=>:artist_id
608
- @Album.many_to_one :artist, :class=>@Artist, :primary_key=>:artist_id
609
- @Album.many_to_many :tags, :class=>@Tag, :left_key=>:album_id, :right_key=>:tag_id, :join_table=>:at, :right_primary_key=>:tag_id
610
- @Artist.nested_attributes :albums, :destroy=>true, :remove=>true
611
- @Album.nested_attributes :artist, :tags, :destroy=>true, :remove=>true
612
-
613
- al = @Album.load(:id=>10, :name=>'Al', :artist_id=>25)
614
- ar = @Artist.load(:id=>20, :name=>'Ar', :artist_id=>25)
615
- t = @Tag.load(:id=>30, :name=>'T', :tag_id=>15)
616
- al.associations[:artist] = ar
617
- al.associations[:tags] = [t]
618
- ar.associations[:albums] = [al]
619
- proc{ar.set(:albums_attributes=>[{:id=>10, :name=>'Al2', :artist_id=>'3'}])}.must_raise(Sequel::Error)
620
- proc{al.set(:artist_attributes=>{:id=>20, :name=>'Ar2', :artist_id=>'3'})}.must_raise(Sequel::Error)
621
- proc{al.set(:tags_attributes=>[{:id=>30, :name=>'T2', :tag_id=>'3'}])}.must_raise(Sequel::Error)
622
- end
623
-
624
- it "should accept a :fields option and only allow modification of those fields" do
625
- @Tag.columns :id, :name, :number
626
- @Album.nested_attributes :tags, :destroy=>true, :remove=>true, :fields=>[:name]
627
-
628
- al = @Album.load(:id=>10, :name=>'Al')
629
- t = @Tag.load(:id=>30, :name=>'T', :number=>10)
630
- al.associations[:tags] = [t]
631
- al.set(:tags_attributes=>[{:id=>30, :name=>'T2'}, {:name=>'T3'}])
632
- @db.sqls.must_equal []
633
- al.save
634
- check_sql_array("UPDATE albums SET name = 'Al' WHERE (id = 10)",
635
- "UPDATE tags SET name = 'T2' WHERE (id = 30)",
636
- "INSERT INTO tags (name) VALUES ('T3')",
637
- ["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
638
- al.set(:tags_attributes=>[{:id=>30, :name=>'T3', :number=>3}])
639
- al.tags.first.name.must_equal 'T3'
640
- al.tags.first.number.must_equal 10
641
- al.set(:tags_attributes=>[{:name=>'T4', :number=>3}])
642
- al.tags.last.name.must_equal 'T4'
643
- al.tags.last.number.must_be_nil
644
- end
645
-
646
- it "should accept a proc for the :fields option that accepts the associated object and returns an array of fields" do
647
- @Tag.columns :id, :name, :number
648
- @Album.nested_attributes :tags, :destroy=>true, :remove=>true, :fields=>proc{|object| object.is_a?(@Tag) ? [:name] : []}
649
-
650
- al = @Album.load(:id=>10, :name=>'Al')
651
- t = @Tag.load(:id=>30, :name=>'T', :number=>10)
652
- al.associations[:tags] = [t]
653
- al.set(:tags_attributes=>[{:id=>30, :name=>'T2'}, {:name=>'T3'}])
654
- @db.sqls.must_equal []
655
- al.save
656
- check_sql_array("UPDATE albums SET name = 'Al' WHERE (id = 10)",
657
- "UPDATE tags SET name = 'T2' WHERE (id = 30)",
658
- "INSERT INTO tags (name) VALUES ('T3')",
659
- ["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
660
- al.set_nested_attributes(:tags, [{:id=>30, :name=>'T3', :number=>3}], :fields=>[:name])
661
- al.tags.first.name.must_equal 'T3'
662
- al.tags.first.number.must_equal 10
663
- al.set_nested_attributes(:tags, [{:name=>'T4', :number=>3}], :fields=>[:name])
664
- al.tags.last.name.must_equal 'T4'
665
- al.tags.last.number.must_be_nil
666
- end
667
-
668
- it "should allow per-call options via the set_nested_attributes method" do
669
- @Tag.columns :id, :name, :number
670
- @Album.nested_attributes :tags
671
-
672
- al = @Album.load(:id=>10, :name=>'Al')
673
- t = @Tag.load(:id=>30, :name=>'T', :number=>10)
674
- al.associations[:tags] = [t]
675
- al.set_nested_attributes(:tags, [{:id=>30, :name=>'T2'}, {:name=>'T3'}], :fields=>[:name])
676
- @db.sqls.must_equal []
677
- al.save
678
- check_sql_array("UPDATE albums SET name = 'Al' WHERE (id = 10)",
679
- "UPDATE tags SET name = 'T2' WHERE (id = 30)",
680
- "INSERT INTO tags (name) VALUES ('T3')",
681
- ["INSERT INTO at (album_id, tag_id) VALUES (10, 1)", "INSERT INTO at (tag_id, album_id) VALUES (1, 10)"])
682
- al.set_nested_attributes(:tags, [{:id=>30, :name=>'T3', :number=>3}], :fields=>[:name])
683
- al.tags.first.name.must_equal 'T3'
684
- al.tags.first.number.must_equal 10
685
- al.set_nested_attributes(:tags, [{:name=>'T4', :number=>3}], :fields=>[:name])
686
- al.tags.last.name.must_equal 'T4'
687
- al.tags.last.number.must_be_nil
688
- end
689
-
690
- it "should have set_nested_attributes method raise error if called with a bad association" do
691
- proc{@Album.load(:id=>10, :name=>'Al').set_nested_attributes(:tags2, [{:id=>30, :name=>'T2', :number=>3}], :fields=>[:name])}.must_raise(Sequel::Error)
692
- end
693
-
694
- it "should have set_nested_attributes method raise error if called with an association that doesn't support nested attributes" do
695
- @Tag.columns :id, :name, :number
696
- proc{@Album.load(:id=>10, :name=>'Al').set_nested_attributes(:tags, [{:id=>30, :name=>'T2', :number=>3}], :fields=>[:name])}.must_raise(Sequel::Error)
697
- end
698
-
699
- it "should not allow modifying ensted attributes after freezing" do
700
- @Artist.freeze
701
- proc{@Artist.nested_attributes :albums}.must_raise RuntimeError, TypeError
702
- end
703
- end