mongoid 7.4.0 → 8.0.1

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 (315) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +3 -3
  4. data/lib/config/locales/en.yml +51 -28
  5. data/lib/mongoid/association/accessors.rb +32 -3
  6. data/lib/mongoid/association/bindable.rb +48 -0
  7. data/lib/mongoid/association/builders.rb +4 -2
  8. data/lib/mongoid/association/eager_loadable.rb +29 -7
  9. data/lib/mongoid/association/embedded/batchable.rb +48 -8
  10. data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
  11. data/lib/mongoid/association/embedded/embedded_in.rb +2 -1
  12. data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
  13. data/lib/mongoid/association/embedded/embeds_many/buildable.rb +1 -1
  14. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +40 -18
  15. data/lib/mongoid/association/embedded/embeds_one/buildable.rb +18 -4
  16. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +21 -2
  17. data/lib/mongoid/association/macros.rb +22 -1
  18. data/lib/mongoid/association/many.rb +5 -0
  19. data/lib/mongoid/association/nested/many.rb +2 -1
  20. data/lib/mongoid/association/proxy.rb +12 -0
  21. data/lib/mongoid/association/referenced/auto_save.rb +3 -2
  22. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
  23. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
  24. data/lib/mongoid/association/referenced/belongs_to.rb +1 -1
  25. data/lib/mongoid/association/referenced/counter_cache.rb +8 -8
  26. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +64 -11
  27. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +4 -1
  28. data/lib/mongoid/association/referenced/has_many/enumerable.rb +10 -14
  29. data/lib/mongoid/association/referenced/has_many/proxy.rb +12 -9
  30. data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
  31. data/lib/mongoid/association/referenced/has_one/proxy.rb +8 -11
  32. data/lib/mongoid/association/referenced/syncable.rb +2 -2
  33. data/lib/mongoid/association/relatable.rb +38 -4
  34. data/lib/mongoid/atomic/paths/embedded/many.rb +19 -0
  35. data/lib/mongoid/attributes/processing.rb +9 -2
  36. data/lib/mongoid/attributes.rb +30 -27
  37. data/lib/mongoid/changeable.rb +37 -2
  38. data/lib/mongoid/clients/options.rb +4 -0
  39. data/lib/mongoid/clients/sessions.rb +2 -14
  40. data/lib/mongoid/config/environment.rb +20 -4
  41. data/lib/mongoid/config.rb +25 -10
  42. data/lib/mongoid/contextual/aggregable/memory.rb +23 -15
  43. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  44. data/lib/mongoid/contextual/map_reduce.rb +2 -2
  45. data/lib/mongoid/contextual/memory.rb +176 -17
  46. data/lib/mongoid/contextual/mongo.rb +226 -206
  47. data/lib/mongoid/contextual/none.rb +66 -4
  48. data/lib/mongoid/copyable.rb +32 -8
  49. data/lib/mongoid/criteria/includable.rb +24 -20
  50. data/lib/mongoid/criteria/marshalable.rb +10 -2
  51. data/lib/mongoid/criteria/queryable/extensions/array.rb +2 -13
  52. data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
  53. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  54. data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
  55. data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
  56. data/lib/mongoid/criteria/queryable/extensions/hash.rb +0 -14
  57. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  58. data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
  59. data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
  60. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +1 -1
  61. data/lib/mongoid/criteria/queryable/extensions/symbol.rb +3 -1
  62. data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
  63. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
  64. data/lib/mongoid/criteria/queryable/mergeable.rb +21 -0
  65. data/lib/mongoid/criteria/queryable/optional.rb +3 -9
  66. data/lib/mongoid/criteria/queryable/options.rb +1 -1
  67. data/lib/mongoid/criteria/queryable/selectable.rb +28 -34
  68. data/lib/mongoid/criteria/queryable/selector.rb +89 -4
  69. data/lib/mongoid/criteria/queryable/smash.rb +39 -6
  70. data/lib/mongoid/criteria/queryable.rb +11 -6
  71. data/lib/mongoid/criteria.rb +1 -26
  72. data/lib/mongoid/deprecable.rb +36 -0
  73. data/lib/mongoid/deprecation.rb +25 -0
  74. data/lib/mongoid/document.rb +96 -32
  75. data/lib/mongoid/errors/document_not_found.rb +29 -8
  76. data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
  77. data/lib/mongoid/errors/invalid_field.rb +5 -1
  78. data/lib/mongoid/errors/invalid_field_type.rb +26 -0
  79. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
  80. data/lib/mongoid/errors.rb +2 -2
  81. data/lib/mongoid/extensions/array.rb +8 -6
  82. data/lib/mongoid/extensions/big_decimal.rb +29 -10
  83. data/lib/mongoid/extensions/binary.rb +42 -0
  84. data/lib/mongoid/extensions/boolean.rb +8 -2
  85. data/lib/mongoid/extensions/date.rb +26 -20
  86. data/lib/mongoid/extensions/date_time.rb +1 -1
  87. data/lib/mongoid/extensions/float.rb +4 -5
  88. data/lib/mongoid/extensions/hash.rb +12 -5
  89. data/lib/mongoid/extensions/integer.rb +4 -5
  90. data/lib/mongoid/extensions/object.rb +2 -0
  91. data/lib/mongoid/extensions/range.rb +41 -10
  92. data/lib/mongoid/extensions/regexp.rb +11 -4
  93. data/lib/mongoid/extensions/set.rb +11 -4
  94. data/lib/mongoid/extensions/string.rb +2 -13
  95. data/lib/mongoid/extensions/symbol.rb +3 -14
  96. data/lib/mongoid/extensions/time.rb +27 -16
  97. data/lib/mongoid/extensions/time_with_zone.rb +1 -2
  98. data/lib/mongoid/extensions.rb +1 -0
  99. data/lib/mongoid/factory.rb +42 -7
  100. data/lib/mongoid/fields/foreign_key.rb +7 -0
  101. data/lib/mongoid/fields/validators/macro.rb +3 -9
  102. data/lib/mongoid/fields.rb +194 -28
  103. data/lib/mongoid/findable.rb +27 -7
  104. data/lib/mongoid/indexable/specification.rb +1 -1
  105. data/lib/mongoid/indexable/validators/options.rb +4 -1
  106. data/lib/mongoid/interceptable.rb +69 -9
  107. data/lib/mongoid/persistable/creatable.rb +14 -5
  108. data/lib/mongoid/persistable/updatable.rb +12 -5
  109. data/lib/mongoid/persistable/upsertable.rb +1 -1
  110. data/lib/mongoid/persistence_context.rb +19 -2
  111. data/lib/mongoid/query_cache.rb +6 -258
  112. data/lib/mongoid/railties/controller_runtime.rb +1 -1
  113. data/lib/mongoid/reloadable.rb +7 -3
  114. data/lib/mongoid/selectable.rb +1 -2
  115. data/lib/mongoid/stateful.rb +27 -1
  116. data/lib/mongoid/timestamps/created.rb +1 -1
  117. data/lib/mongoid/timestamps/updated.rb +1 -1
  118. data/lib/mongoid/touchable.rb +2 -3
  119. data/lib/mongoid/traversable.rb +5 -1
  120. data/lib/mongoid/validatable/uniqueness.rb +2 -1
  121. data/lib/mongoid/version.rb +1 -1
  122. data/lib/mongoid/warnings.rb +28 -0
  123. data/lib/mongoid.rb +2 -0
  124. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +11 -5
  125. data/spec/config/mongoid.yml +16 -0
  126. data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
  127. data/spec/integration/app_spec.rb +28 -26
  128. data/spec/integration/associations/belongs_to_spec.rb +18 -0
  129. data/spec/integration/associations/embedded_dirty_spec.rb +28 -0
  130. data/spec/integration/associations/embedded_spec.rb +15 -0
  131. data/spec/integration/associations/embeds_many_spec.rb +15 -2
  132. data/spec/integration/associations/embeds_one_spec.rb +18 -0
  133. data/spec/integration/associations/foreign_key_spec.rb +9 -0
  134. data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
  135. data/spec/integration/associations/has_one_spec.rb +97 -1
  136. data/spec/integration/associations/scope_option_spec.rb +1 -1
  137. data/spec/integration/callbacks_models.rb +95 -1
  138. data/spec/integration/callbacks_spec.rb +226 -4
  139. data/spec/integration/criteria/range_spec.rb +95 -1
  140. data/spec/integration/discriminator_key_spec.rb +115 -76
  141. data/spec/integration/dots_and_dollars_spec.rb +277 -0
  142. data/spec/integration/matcher_examples_spec.rb +20 -13
  143. data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
  144. data/spec/integration/matcher_operator_spec.rb +3 -5
  145. data/spec/integration/persistence/range_field_spec.rb +350 -0
  146. data/spec/lite_spec_helper.rb +1 -1
  147. data/spec/mongoid/association/counter_cache_spec.rb +1 -1
  148. data/spec/mongoid/association/depending_spec.rb +9 -9
  149. data/spec/mongoid/association/eager_spec.rb +2 -1
  150. data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
  151. data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
  152. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +69 -9
  153. data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
  154. data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +219 -8
  155. data/spec/mongoid/association/embedded/embeds_many_models.rb +157 -0
  156. data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
  157. data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
  158. data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
  159. data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
  160. data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
  161. data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
  162. data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
  163. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
  164. data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
  165. data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -2
  166. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +67 -4
  167. data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
  168. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
  169. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
  170. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +8 -8
  171. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +82 -13
  172. data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
  173. data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
  174. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
  175. data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
  176. data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
  177. data/spec/mongoid/association/syncable_spec.rb +14 -0
  178. data/spec/mongoid/atomic/paths_spec.rb +0 -14
  179. data/spec/mongoid/atomic_spec.rb +22 -0
  180. data/spec/mongoid/attributes/nested_spec.rb +80 -11
  181. data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
  182. data/spec/mongoid/attributes/projector_spec.rb +1 -5
  183. data/spec/mongoid/attributes_spec.rb +524 -27
  184. data/spec/mongoid/changeable_spec.rb +130 -13
  185. data/spec/mongoid/clients/factory_spec.rb +34 -42
  186. data/spec/mongoid/clients/options_spec.rb +1 -0
  187. data/spec/mongoid/clients/sessions_spec.rb +0 -38
  188. data/spec/mongoid/clients_spec.rb +32 -2
  189. data/spec/mongoid/config/environment_spec.rb +39 -1
  190. data/spec/mongoid/config_spec.rb +104 -13
  191. data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
  192. data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
  193. data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
  194. data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
  195. data/spec/mongoid/contextual/memory_spec.rb +1337 -69
  196. data/spec/mongoid/contextual/mongo_spec.rb +1105 -172
  197. data/spec/mongoid/contextual/none_spec.rb +38 -0
  198. data/spec/mongoid/copyable_spec.rb +451 -1
  199. data/spec/mongoid/criteria/findable_spec.rb +86 -210
  200. data/spec/mongoid/criteria/includable_spec.rb +1492 -0
  201. data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
  202. data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
  203. data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
  204. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
  205. data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
  206. data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
  207. data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
  208. data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
  209. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
  210. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
  211. data/spec/mongoid/criteria/queryable/optional_spec.rb +0 -484
  212. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +50 -0
  213. data/spec/mongoid/criteria/queryable/selectable_spec.rb +289 -124
  214. data/spec/mongoid/criteria/queryable/selector_spec.rb +14 -2
  215. data/spec/mongoid/criteria_spec.rb +474 -1198
  216. data/spec/mongoid/document_fields_spec.rb +173 -24
  217. data/spec/mongoid/document_spec.rb +32 -41
  218. data/spec/mongoid/errors/document_not_found_spec.rb +76 -0
  219. data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
  220. data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
  221. data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
  222. data/spec/mongoid/errors/no_environment_spec.rb +3 -3
  223. data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
  224. data/spec/mongoid/extensions/array_spec.rb +16 -2
  225. data/spec/mongoid/extensions/big_decimal_spec.rb +697 -212
  226. data/spec/mongoid/extensions/binary_spec.rb +44 -9
  227. data/spec/mongoid/extensions/boolean_spec.rb +68 -82
  228. data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
  229. data/spec/mongoid/extensions/date_spec.rb +71 -1
  230. data/spec/mongoid/extensions/date_time_spec.rb +15 -9
  231. data/spec/mongoid/extensions/float_spec.rb +48 -76
  232. data/spec/mongoid/extensions/hash_spec.rb +30 -0
  233. data/spec/mongoid/extensions/integer_spec.rb +45 -66
  234. data/spec/mongoid/extensions/range_spec.rb +255 -54
  235. data/spec/mongoid/extensions/regexp_spec.rb +58 -33
  236. data/spec/mongoid/extensions/set_spec.rb +106 -0
  237. data/spec/mongoid/extensions/string_spec.rb +53 -25
  238. data/spec/mongoid/extensions/symbol_spec.rb +18 -25
  239. data/spec/mongoid/extensions/time_spec.rb +634 -66
  240. data/spec/mongoid/extensions/time_with_zone_spec.rb +17 -31
  241. data/spec/mongoid/factory_spec.rb +61 -1
  242. data/spec/mongoid/fields_spec.rb +321 -50
  243. data/spec/mongoid/findable_spec.rb +80 -15
  244. data/spec/mongoid/indexable/specification_spec.rb +2 -2
  245. data/spec/mongoid/indexable_spec.rb +16 -19
  246. data/spec/mongoid/interceptable_spec.rb +584 -5
  247. data/spec/mongoid/interceptable_spec_models.rb +235 -4
  248. data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
  249. data/spec/mongoid/mongoizable_spec.rb +285 -0
  250. data/spec/mongoid/persistable/creatable_spec.rb +2 -2
  251. data/spec/mongoid/persistable/deletable_spec.rb +2 -2
  252. data/spec/mongoid/persistable/destroyable_spec.rb +2 -2
  253. data/spec/mongoid/persistable/upsertable_spec.rb +14 -0
  254. data/spec/mongoid/persistence_context_spec.rb +50 -1
  255. data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
  256. data/spec/mongoid/query_cache_spec.rb +0 -154
  257. data/spec/mongoid/reloadable_spec.rb +35 -2
  258. data/spec/mongoid/scopable_spec.rb +21 -1
  259. data/spec/mongoid/shardable_spec.rb +14 -0
  260. data/spec/mongoid/stateful_spec.rb +28 -0
  261. data/spec/mongoid/timestamps_spec.rb +390 -0
  262. data/spec/mongoid/timestamps_spec_models.rb +67 -0
  263. data/spec/mongoid/touchable_spec.rb +116 -0
  264. data/spec/mongoid/touchable_spec_models.rb +12 -8
  265. data/spec/mongoid/traversable_spec.rb +4 -11
  266. data/spec/mongoid/validatable/presence_spec.rb +1 -1
  267. data/spec/mongoid/validatable/uniqueness_spec.rb +60 -31
  268. data/spec/mongoid/warnings_spec.rb +35 -0
  269. data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
  270. data/spec/rails/mongoid_spec.rb +4 -16
  271. data/spec/shared/lib/mrss/constraints.rb +8 -16
  272. data/spec/shared/lib/mrss/docker_runner.rb +23 -3
  273. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  274. data/spec/shared/lib/mrss/lite_constraints.rb +32 -1
  275. data/spec/shared/share/Dockerfile.erb +34 -48
  276. data/spec/shared/shlib/config.sh +27 -0
  277. data/spec/shared/shlib/server.sh +32 -19
  278. data/spec/shared/shlib/set_env.sh +37 -0
  279. data/spec/support/constraints.rb +24 -0
  280. data/spec/support/macros.rb +39 -0
  281. data/spec/support/models/augmentation.rb +12 -0
  282. data/spec/support/models/band.rb +3 -0
  283. data/spec/support/models/catalog.rb +24 -0
  284. data/spec/support/models/circus.rb +3 -0
  285. data/spec/support/models/code.rb +2 -0
  286. data/spec/support/models/fanatic.rb +8 -0
  287. data/spec/support/models/implant.rb +9 -0
  288. data/spec/support/models/label.rb +2 -0
  289. data/spec/support/models/membership.rb +1 -0
  290. data/spec/support/models/passport.rb +9 -0
  291. data/spec/support/models/person.rb +1 -0
  292. data/spec/support/models/player.rb +2 -0
  293. data/spec/support/models/powerup.rb +12 -0
  294. data/spec/support/models/registry.rb +1 -0
  295. data/spec/support/models/school.rb +14 -0
  296. data/spec/support/models/shield.rb +18 -0
  297. data/spec/support/models/student.rb +14 -0
  298. data/spec/support/models/weapon.rb +12 -0
  299. data/spec/support/schema_maps/schema_map_aws.json +17 -0
  300. data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
  301. data/spec/support/schema_maps/schema_map_azure.json +17 -0
  302. data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
  303. data/spec/support/schema_maps/schema_map_gcp.json +17 -0
  304. data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
  305. data/spec/support/schema_maps/schema_map_kmip.json +17 -0
  306. data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
  307. data/spec/support/schema_maps/schema_map_local.json +18 -0
  308. data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
  309. data/spec/support/spec_config.rb +4 -0
  310. data.tar.gz.sig +0 -0
  311. metadata +76 -13
  312. metadata.gz.sig +0 -0
  313. data/lib/mongoid/errors/eager_load.rb +0 -23
  314. data/lib/mongoid/errors/invalid_value.rb +0 -17
  315. data/spec/mongoid/errors/eager_load_spec.rb +0 -31
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "spec_helper"
4
+ require_relative '../embeds_many_models'
4
5
 
5
6
  describe Mongoid::Association::Embedded::EmbeddedIn::Proxy do
6
7
 
@@ -507,7 +508,7 @@ describe Mongoid::Association::Embedded::EmbeddedIn::Proxy do
507
508
  end
508
509
  end
509
510
 
510
- context "when the same class is embedded multiple times" do
511
+ context "when the same class is embedded multiple times; embeds_one" do
511
512
 
512
513
  let(:customer) do
513
514
  Customer.new
@@ -516,7 +517,6 @@ describe Mongoid::Association::Embedded::EmbeddedIn::Proxy do
516
517
  context "assignment after saving" do
517
518
 
518
519
  it "correctly sets the association for the embedded class" do
519
- pending 'MONGOID-5039'
520
520
 
521
521
  customer.home_address = CustomerAddress.new
522
522
  customer.work_address = CustomerAddress.new
@@ -537,22 +537,82 @@ describe Mongoid::Association::Embedded::EmbeddedIn::Proxy do
537
537
 
538
538
  expect(customer.home_address.instance_eval { _association.store_as }).to eq("home_address")
539
539
  expect(customer.work_address.instance_eval { _association.store_as }).to eq("work_address")
540
+
541
+ expect(customer.home_address.addressable).to eq(customer)
542
+ expect(customer.work_address.addressable).to eq(customer)
540
543
  end
541
544
  end
542
545
 
543
546
  context "inverse assignment" do
544
547
 
548
+ it "raises an error when trying to set the association" do
549
+ customer.work_address = CustomerAddress.new
550
+
551
+ expect do
552
+ customer.work_address.addressable = customer
553
+ end.to raise_error(Mongoid::Errors::InvalidSetPolymorphicRelation)
554
+ end
555
+ end
556
+
557
+ context "when there is an explicit inverse_of" do
558
+
559
+ let(:customer) { EmmCustomer.new }
560
+
545
561
  it "correctly sets the association for the embedded class" do
546
- pending 'MONGOID-5039'
562
+ customer.work_address = EmmCustomerAddress.new
547
563
 
548
- customer.work_address = CustomerAddress.new
549
- customer.work_address.addressable = customer
564
+ expect do
565
+ customer.work_address.addressable = customer
566
+ end.to_not raise_error
550
567
 
551
- expect(customer.home_address._association.store_as).to eq("home_address")
552
- expect(customer.work_address._association.store_as).to eq("work_address")
568
+ expect(customer.work_address.addressable).to eq(customer)
569
+ end
570
+ end
571
+ end
553
572
 
554
- expect(customer.home_address.instance_eval { _association.store_as }).to eq("home_address")
555
- expect(customer.work_address.instance_eval { _association.store_as }).to eq("work_address")
573
+ context "when the same class is embedded multiple times; embeds_many" do
574
+
575
+ let(:customer) do
576
+ EmmCustomer.new
577
+ end
578
+
579
+ context "assignment after saving" do
580
+
581
+ it "correctly sets the association for the embedded class" do
582
+
583
+ customer.close_friends = [EmmFriend.new]
584
+ customer.acquaintances = [EmmFriend.new]
585
+
586
+ expect(customer.close_friends._association.store_as).to eq("close_friends")
587
+ expect(customer.acquaintances._association.store_as).to eq("acquaintances")
588
+
589
+ expect(customer.close_friends[0].instance_eval { _association.store_as }).to eq("close_friends")
590
+ expect(customer.acquaintances[0].instance_eval { _association.store_as }).to eq("acquaintances")
591
+
592
+ customer.save!
593
+
594
+ customer.close_friends = [EmmFriend.new]
595
+ customer.acquaintances = [EmmFriend.new]
596
+
597
+ expect(customer.close_friends._association.store_as).to eq("close_friends")
598
+ expect(customer.acquaintances._association.store_as).to eq("acquaintances")
599
+
600
+ expect(customer.close_friends[0].instance_eval { _association.store_as }).to eq("close_friends")
601
+ expect(customer.acquaintances[0].instance_eval { _association.store_as }).to eq("acquaintances")
602
+
603
+ expect(customer.close_friends[0].befriendable).to eq(customer)
604
+ expect(customer.acquaintances[0].befriendable).to eq(customer)
605
+ end
606
+ end
607
+
608
+ context "inverse assignment" do
609
+
610
+ it "raises an error when trying to set the association" do
611
+ customer.acquaintances = [EmmFriend.new]
612
+
613
+ expect do
614
+ customer.acquaintances[0].befriendable = customer
615
+ end.to raise_error(Mongoid::Errors::InvalidSetPolymorphicRelation)
556
616
  end
557
617
  end
558
618
  end
@@ -103,4 +103,116 @@ describe Mongoid::Association::Embedded::EmbedsMany::Buildable do
103
103
  end
104
104
  end
105
105
  end
106
+
107
+ context 'when the object is already associated with another object' do
108
+
109
+ context "when using <<" do
110
+
111
+ let(:person1) do
112
+ Person.new
113
+ end
114
+
115
+ let(:person2) do
116
+ Person.new
117
+ end
118
+
119
+ let(:appointment) do
120
+ Appointment.new
121
+ end
122
+
123
+ before do
124
+ person1.appointments << appointment
125
+ person2.appointments << appointment
126
+ end
127
+
128
+ it 'clears the object of its previous association' do
129
+ expect(person1.appointments).to eq([])
130
+ expect(person2.appointments).to eq([appointment])
131
+ end
132
+ end
133
+
134
+ context "when using concat" do
135
+
136
+ let(:person1) do
137
+ Person.new
138
+ end
139
+
140
+ let(:person2) do
141
+ Person.new
142
+ end
143
+
144
+ let(:appointment) do
145
+ Appointment.new
146
+ end
147
+
148
+ before do
149
+ person1.appointments.concat([appointment])
150
+ person2.appointments.concat([appointment])
151
+ end
152
+
153
+ it 'clears the object of its previous association' do
154
+ expect(person1.appointments).to eq([])
155
+ expect(person2.appointments).to eq([appointment])
156
+ end
157
+ end
158
+
159
+ context "when using =" do
160
+
161
+ let(:person1) do
162
+ Person.new
163
+ end
164
+
165
+ let(:person2) do
166
+ Person.new
167
+ end
168
+
169
+ let(:appointment) do
170
+ Appointment.new
171
+ end
172
+
173
+ let(:apts) { [ appointment ] }
174
+
175
+ before do
176
+ person1.appointments = apts
177
+ person2.appointments = apts
178
+ expect(apts).to eq([ appointment ])
179
+ end
180
+
181
+ it 'clears the object of its previous association' do
182
+ expect(person1.appointments).to eq([])
183
+ expect(person2.appointments).to eq([appointment])
184
+ end
185
+ end
186
+
187
+ context "when using = on the same document twice" do
188
+
189
+ let(:person1) do
190
+ Person.new
191
+ end
192
+
193
+ let(:person2) do
194
+ Person.new
195
+ end
196
+
197
+ let(:appointment1) do
198
+ Appointment.new
199
+ end
200
+
201
+ let(:appointment2) do
202
+ Appointment.new
203
+ end
204
+
205
+ let(:apts) { [ appointment1, appointment2 ] }
206
+
207
+ before do
208
+ person1.appointments = apts
209
+ person1.appointments = person1.appointments.reverse
210
+ expect(apts).to eq([ appointment1, appointment2 ])
211
+ end
212
+
213
+ it 'clears the object of its previous association' do
214
+ expect(person1.appointments).to eq([ appointment2, appointment1 ])
215
+ end
216
+ end
217
+ end
106
218
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "spec_helper"
4
+ require_relative '../embeds_many_models.rb'
4
5
 
5
6
  describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
6
7
 
@@ -2209,6 +2210,79 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
2209
2210
  end
2210
2211
  end
2211
2212
  end
2213
+
2214
+ context "when modifying the document beforehand" do
2215
+ let(:parent) { EmmParent.new }
2216
+
2217
+ before do
2218
+
2219
+ parent.blocks << EmmBlock.new(name: 'test', children: [size: 1, order: 1])
2220
+ parent.save!
2221
+
2222
+ parent.blocks[0].children[0].assign_attributes(size: 2)
2223
+
2224
+ parent.blocks.destroy_all(:name => 'test')
2225
+ end
2226
+
2227
+ it "deletes the correct document in the database" do
2228
+ expect(parent.reload.blocks.length).to eq(0)
2229
+ end
2230
+ end
2231
+
2232
+ context "when nil _id" do
2233
+ let(:parent) { EmmParent.new }
2234
+
2235
+ before do
2236
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2237
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test2', children: [size: 1, order: 1])
2238
+ parent.save!
2239
+
2240
+ parent.blocks.destroy_all(:name => 'test')
2241
+ end
2242
+
2243
+ it "deletes only the matching documents in the database" do
2244
+ expect(parent.reload.blocks.length).to eq(1)
2245
+ end
2246
+ end
2247
+
2248
+ # Since without an _id field we must us a $pullAll with the attributes of
2249
+ # the embedded document, if you modify it beforehand, the query will not
2250
+ # be able to find the correct document to pull.
2251
+ context "when modifying the document with nil _id" do
2252
+ let(:parent) { EmmParent.new }
2253
+
2254
+ before do
2255
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2256
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test2', children: [size: 1, order: 1])
2257
+ parent.save!
2258
+
2259
+ parent.blocks[0].children[0].assign_attributes(size: 2)
2260
+
2261
+ parent.blocks.destroy_all(:name => 'test')
2262
+ end
2263
+
2264
+ it "does not delete the correct documents" do
2265
+ expect(parent.reload.blocks.length).to eq(2)
2266
+ end
2267
+ end
2268
+
2269
+ context "when documents with and without _id" do
2270
+ let(:parent) { EmmParent.new }
2271
+
2272
+ before do
2273
+ parent.blocks << EmmBlock.new(_id: nil, name: 'test', children: [size: 1, order: 1])
2274
+ parent.blocks << EmmBlock.new(name: 'test', children: [size: 1, order: 1])
2275
+ parent.save!
2276
+
2277
+ parent.blocks[1].children[0].assign_attributes(size: 2)
2278
+
2279
+ parent.blocks.destroy_all(:name => 'test')
2280
+ end
2281
+
2282
+ it "does not delete the correct documents" do
2283
+ expect(parent.reload.blocks.length).to eq(0)
2284
+ end
2285
+ end
2212
2286
  end
2213
2287
  end
2214
2288
 
@@ -2286,7 +2360,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
2286
2360
  it "raises an error" do
2287
2361
  expect {
2288
2362
  person.addresses.find(BSON::ObjectId.new)
2289
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2363
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Address with id\(s\)/)
2290
2364
  end
2291
2365
  end
2292
2366
 
@@ -2335,7 +2409,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
2335
2409
  it "raises an error" do
2336
2410
  expect {
2337
2411
  person.addresses.find([ BSON::ObjectId.new ])
2338
- }.to raise_error(Mongoid::Errors::DocumentNotFound)
2412
+ }.to raise_error(Mongoid::Errors::DocumentNotFound, /Document\(s\) not found for class Address with id\(s\)/)
2339
2413
  end
2340
2414
  end
2341
2415
 
@@ -3460,7 +3534,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3460
3534
 
3461
3535
  describe "replacing the entire embedded list" do
3462
3536
 
3463
- context "when an embeds many relationship contains a nil as the first item" do
3537
+ context "when an embeds many relationship contains nil as the first item" do
3464
3538
 
3465
3539
  let(:person) do
3466
3540
  Person.create!
@@ -3481,7 +3555,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3481
3555
  end
3482
3556
  end
3483
3557
 
3484
- context "when an embeds many relationship contains a nil in the middle of the list" do
3558
+ context "when an embeds many relationship contains nil in the middle of the list" do
3485
3559
 
3486
3560
  let(:person) do
3487
3561
  Person.create!
@@ -3502,7 +3576,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3502
3576
  end
3503
3577
  end
3504
3578
 
3505
- context "when an embeds many relationship contains a nil at the end of the list" do
3579
+ context "when an embeds many relationship contains nil at the end of the list" do
3506
3580
 
3507
3581
  let(:person) do
3508
3582
  Person.create!
@@ -3526,7 +3600,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3526
3600
 
3527
3601
  describe "appending to the embedded list" do
3528
3602
 
3529
- context "when appending a nil to the first position in an embedded list" do
3603
+ context "when appending nil to the first position in an embedded list" do
3530
3604
 
3531
3605
  let(:person) do
3532
3606
  Person.create! phone_numbers: []
@@ -3545,7 +3619,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3545
3619
  end
3546
3620
  end
3547
3621
 
3548
- context "when appending a nil into the middle of an embedded list" do
3622
+ context "when appending nil into the middle of an embedded list" do
3549
3623
 
3550
3624
  let(:person) do
3551
3625
  Person.create! phone_numbers: []
@@ -3564,7 +3638,7 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3564
3638
  end
3565
3639
  end
3566
3640
 
3567
- context "when appending a nil to the end of an embedded list" do
3641
+ context "when appending nil to the end of an embedded list" do
3568
3642
 
3569
3643
  let(:person) do
3570
3644
  Person.create! phone_numbers: []
@@ -3959,6 +4033,28 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
3959
4033
  end
3960
4034
  end
3961
4035
 
4036
+ context "when destroying a document with multiple nil _ids" do
4037
+ let(:congress) { EmmCongress.create! }
4038
+
4039
+ before do
4040
+ congress.legislators << EmmLegislator.new(_id: nil, a: 1)
4041
+ congress.legislators << EmmLegislator.new(_id: nil, a: 2)
4042
+
4043
+ congress.legislators[0].destroy
4044
+ end
4045
+
4046
+ it "deletes the correct document locally" do
4047
+ pending "MONGOID-5394"
4048
+ expect(congress.legislators.length).to eq(1)
4049
+ expect(congress.legislators.first.a).to eq(1)
4050
+ end
4051
+
4052
+ it "only deletes the one document" do
4053
+ pending "MONGOID-5394"
4054
+ expect(congress.reload.legislators.length).to eq(1)
4055
+ end
4056
+ end
4057
+
3962
4058
  context "when adding a document" do
3963
4059
 
3964
4060
  let(:person) do
@@ -4649,4 +4745,119 @@ describe Mongoid::Association::Embedded::EmbedsMany::Proxy do
4649
4745
  end
4650
4746
  end
4651
4747
  end
4748
+
4749
+ context "when trying to persist the empty list" do
4750
+
4751
+ context "in an embeds_many relation" do
4752
+
4753
+ let(:band) { Band.create! }
4754
+
4755
+ before do
4756
+ band.labels = []
4757
+ band.save!
4758
+ end
4759
+
4760
+ let(:reloaded_band) { Band.collection.find(_id: band._id).first }
4761
+
4762
+ it "persists the empty list" do
4763
+ expect(reloaded_band).to have_key(:labels)
4764
+ expect(reloaded_band[:labels]).to eq []
4765
+ end
4766
+ end
4767
+
4768
+ context "in a nested embeds_many relation" do
4769
+
4770
+ let(:survey) { Survey.create!(questions: [Question.new]) }
4771
+
4772
+ before do
4773
+ survey.questions.first.answers = []
4774
+ survey.save!
4775
+ end
4776
+
4777
+ let(:reloaded_survey) { Survey.collection.find(_id: survey._id).first }
4778
+
4779
+ it "persists the empty list" do
4780
+ expect(reloaded_survey).to have_key(:questions)
4781
+ expect(reloaded_survey[:questions][0]).to have_key(:answers)
4782
+ expect(reloaded_survey[:questions][0][:answers]).to eq []
4783
+ end
4784
+ end
4785
+
4786
+ context "when not setting the embeds_many field" do
4787
+
4788
+ let(:band) { Band.create! }
4789
+
4790
+ let(:reloaded_band) { Band.collection.find(_id: band._id).first }
4791
+
4792
+ it "does not persist the empty list" do
4793
+ expect(reloaded_band).to_not have_key(:labels)
4794
+ end
4795
+ end
4796
+ end
4797
+
4798
+ context "when using assign_attributes with an already populated array" do
4799
+ let(:post) { EmmPost.create! }
4800
+
4801
+ before do
4802
+ post.assign_attributes(company_tags: [{id: BSON::ObjectId.new, title: 'a'}],
4803
+ user_tags: [{id: BSON::ObjectId.new, title: 'b'}])
4804
+ post.save!
4805
+ post.reload
4806
+ post.assign_attributes(company_tags: [{id: BSON::ObjectId.new, title: 'c'}],
4807
+ user_tags: [])
4808
+ post.save!
4809
+ post.reload
4810
+ end
4811
+
4812
+ it "has the correct embedded documents" do
4813
+ expect(post.company_tags.length).to eq(1)
4814
+ expect(post.company_tags.first.title).to eq("c")
4815
+ end
4816
+ end
4817
+
4818
+ context "when the parent fails validation" do
4819
+ let(:school) { EmmSchool.new }
4820
+ let(:student) { school.students.new }
4821
+
4822
+ before do
4823
+ student.save
4824
+ end
4825
+
4826
+ it "does not mark the parent as persisted" do
4827
+ expect(school.persisted?).to be false
4828
+ end
4829
+
4830
+ it "does not mark the child as persisted" do
4831
+ expect(student.persisted?).to be false
4832
+ end
4833
+
4834
+ it "does not persist the parent" do
4835
+ expect(School.count).to eq(0)
4836
+ end
4837
+ end
4838
+
4839
+ context "when doing assign_attributes then assignment" do
4840
+
4841
+ let(:post) do
4842
+ EmmPost.create!(
4843
+ company_tags: [ EmmCompanyTag.new(title: "1"), EmmCompanyTag.new(title: "1") ],
4844
+ user_tags: [ EmmUserTag.new(title: "1"), EmmUserTag.new(title: "1") ]
4845
+ )
4846
+ end
4847
+
4848
+ let(:from_db) { EmmPost.find(post.id) }
4849
+
4850
+ before do
4851
+ post.assign_attributes(
4852
+ company_tags: [ EmmCompanyTag.new(title: '3'), EmmCompanyTag.new(title: '4') ]
4853
+ )
4854
+ post.user_tags = [ EmmUserTag.new(title: '3'), EmmUserTag.new(title: '4') ]
4855
+ post.save!
4856
+ end
4857
+
4858
+ it "persists the associations correctly" do
4859
+ expect(from_db.user_tags.size).to eq(2)
4860
+ expect(from_db.company_tags.size).to eq(2)
4861
+ end
4862
+ end
4652
4863
  end
@@ -67,3 +67,160 @@ class EmmOuter
67
67
 
68
68
  field :level, :type => Integer
69
69
  end
70
+
71
+ class EmmCustomerAddress
72
+ include Mongoid::Document
73
+
74
+ embedded_in :addressable, polymorphic: true, inverse_of: :work_address
75
+ end
76
+
77
+ class EmmFriend
78
+ include Mongoid::Document
79
+
80
+ embedded_in :befriendable, polymorphic: true
81
+ end
82
+
83
+ class EmmCustomer
84
+ include Mongoid::Document
85
+
86
+ embeds_one :home_address, class_name: 'EmmCustomerAddress', as: :addressable
87
+ embeds_one :work_address, class_name: 'EmmCustomerAddress', as: :addressable
88
+
89
+ embeds_many :close_friends, class_name: 'EmmFriend', as: :befriendable
90
+ embeds_many :acquaintances, class_name: 'EmmFriend', as: :befriendable
91
+ end
92
+
93
+ class EmmUser
94
+ include Mongoid::Document
95
+ include Mongoid::Timestamps
96
+
97
+ embeds_many :orders, class_name: 'EmmOrder'
98
+ end
99
+
100
+ class EmmOrder
101
+ include Mongoid::Document
102
+
103
+ field :amount, type: Integer
104
+
105
+ embedded_in :user, class_name: 'EmmUser'
106
+ end
107
+
108
+ module EmmSpec
109
+ # There is also a top-level Car class defined.
110
+ class Car
111
+ include Mongoid::Document
112
+
113
+ embeds_many :doors
114
+ end
115
+
116
+ class Door
117
+ include Mongoid::Document
118
+
119
+ embedded_in :car
120
+ end
121
+
122
+ class Tank
123
+ include Mongoid::Document
124
+
125
+ embeds_many :guns
126
+ embeds_many :emm_turrets
127
+ # This association references a model that is not in our module,
128
+ # and it does not define class_name hence Mongoid will not be able to
129
+ # figure out the inverse for this association.
130
+ embeds_many :emm_hatches
131
+
132
+ # class_name is intentionally unqualified, references a class in the
133
+ # same module. Rails permits class_name to be unqualified like this.
134
+ embeds_many :launchers, class_name: 'Launcher'
135
+ end
136
+
137
+ class Gun
138
+ include Mongoid::Document
139
+
140
+ embedded_in :tank
141
+ end
142
+
143
+ class Launcher
144
+ include Mongoid::Document
145
+
146
+ # class_name is intentionally unqualified.
147
+ embedded_in :tank, class_name: 'Tank'
148
+ end
149
+ end
150
+
151
+ # This is intentionally on top level.
152
+ class EmmTurret
153
+ include Mongoid::Document
154
+
155
+ embedded_in :tank, class_name: 'EmmSpec::Tank'
156
+ end
157
+
158
+ # This is intentionally on top level.
159
+ class EmmHatch
160
+ include Mongoid::Document
161
+
162
+ # No :class_name option on this association intentionally.
163
+ embedded_in :tank
164
+ end
165
+
166
+ class EmmPost
167
+ include Mongoid::Document
168
+
169
+ embeds_many :company_tags, class_name: "EmmCompanyTag"
170
+ embeds_many :user_tags, class_name: "EmmUserTag"
171
+ end
172
+
173
+
174
+ class EmmCompanyTag
175
+ include Mongoid::Document
176
+
177
+ field :title, type: String
178
+
179
+ embedded_in :post, class_name: "EmmPost"
180
+ end
181
+
182
+
183
+ class EmmUserTag
184
+ include Mongoid::Document
185
+
186
+ field :title, type: String
187
+
188
+ embedded_in :post, class_name: "EmmPost"
189
+ end
190
+
191
+ class EmmSchool
192
+ include Mongoid::Document
193
+
194
+ embeds_many :students, class_name: "EmmStudent"
195
+
196
+ field :name, type: :string
197
+
198
+ validates :name, presence: true
199
+ end
200
+
201
+ class EmmStudent
202
+ include Mongoid::Document
203
+
204
+ embedded_in :school, class_name: "EmmSchool"
205
+ end
206
+
207
+ class EmmParent
208
+ include Mongoid::Document
209
+ embeds_many :blocks, class_name: "EmmBlock"
210
+ end
211
+
212
+ class EmmBlock
213
+ include Mongoid::Document
214
+ field :name, type: String
215
+ embeds_many :children, class_name: "EmmChild"
216
+ end
217
+
218
+ class EmmChild
219
+ include Mongoid::Document
220
+ embedded_in :block, class_name: "EmmBlock"
221
+
222
+ field :size, type: Integer
223
+ field :order, type: Integer
224
+ field :t
225
+ end
226
+
@@ -47,5 +47,17 @@ describe Mongoid::Association::Embedded::EmbedsMany do
47
47
  expect(patient.addresses.first.number).to eq(123)
48
48
  end
49
49
  end
50
+
51
+ context "when excluding the relation" do
52
+ let(:congress) do
53
+ EmmCongress.where(name: 'foo').only(:_id).first
54
+ end
55
+
56
+ it 'raises a MissingAttributeError' do
57
+ expect do
58
+ congress.legislators
59
+ end.to raise_error(ActiveModel::MissingAttributeError)
60
+ end
61
+ end
50
62
  end
51
63
  end