mongoid 6.4.8 → 7.0.0.beta

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 +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +0 -26
  5. data/lib/config/locales/en.yml +17 -21
  6. data/lib/mongoid.rb +2 -2
  7. data/lib/mongoid/association.rb +150 -0
  8. data/lib/mongoid/association/accessors.rb +339 -0
  9. data/lib/mongoid/{relations/binding.rb → association/bindable.rb} +32 -52
  10. data/lib/mongoid/association/builders.rb +92 -0
  11. data/lib/mongoid/{relations/constraint.rb → association/constrainable.rb} +11 -22
  12. data/lib/mongoid/association/depending.rb +116 -0
  13. data/lib/mongoid/{relations/eager.rb → association/eager_loadable.rb} +11 -11
  14. data/lib/mongoid/association/embedded.rb +4 -0
  15. data/lib/mongoid/{relations → association}/embedded/batchable.rb +27 -53
  16. data/lib/mongoid/association/embedded/cyclic.rb +109 -0
  17. data/lib/mongoid/association/embedded/embedded_in.rb +154 -0
  18. data/lib/mongoid/association/embedded/embedded_in/binding.rb +56 -0
  19. data/lib/mongoid/{relations/builders/embedded/in.rb → association/embedded/embedded_in/buildable.rb} +12 -6
  20. data/lib/mongoid/association/embedded/embedded_in/proxy.rb +121 -0
  21. data/lib/mongoid/association/embedded/embeds_many.rb +210 -0
  22. data/lib/mongoid/{relations/bindings/embedded/many.rb → association/embedded/embeds_many/binding.rb} +11 -9
  23. data/lib/mongoid/{relations/builders/embedded/many.rb → association/embedded/embeds_many/buildable.rb} +13 -7
  24. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +529 -0
  25. data/lib/mongoid/association/embedded/embeds_one.rb +173 -0
  26. data/lib/mongoid/{relations/bindings/embedded/one.rb → association/embedded/embeds_one/binding.rb} +12 -10
  27. data/lib/mongoid/{relations/builders/embedded/one.rb → association/embedded/embeds_one/buildable.rb} +13 -7
  28. data/lib/mongoid/association/embedded/embeds_one/proxy.rb +130 -0
  29. data/lib/mongoid/association/macros.rb +204 -0
  30. data/lib/mongoid/{relations → association}/many.rb +18 -52
  31. data/lib/mongoid/{relations → association}/marshalable.rb +6 -4
  32. data/lib/mongoid/association/nested.rb +15 -0
  33. data/lib/mongoid/association/nested/many.rb +200 -0
  34. data/lib/mongoid/association/nested/nested_buildable.rb +72 -0
  35. data/lib/mongoid/association/nested/one.rb +127 -0
  36. data/lib/mongoid/{relations → association}/one.rb +6 -6
  37. data/lib/mongoid/association/options.rb +152 -0
  38. data/lib/mongoid/{relations → association}/proxy.rb +31 -58
  39. data/lib/mongoid/association/referenced.rb +7 -0
  40. data/lib/mongoid/association/referenced/auto_save.rb +79 -0
  41. data/lib/mongoid/association/referenced/belongs_to.rb +248 -0
  42. data/lib/mongoid/association/referenced/belongs_to/binding.rb +87 -0
  43. data/lib/mongoid/association/referenced/belongs_to/buildable.rb +46 -0
  44. data/lib/mongoid/association/referenced/belongs_to/eager.rb +36 -0
  45. data/lib/mongoid/association/referenced/belongs_to/proxy.rb +136 -0
  46. data/lib/mongoid/association/referenced/counter_cache.rb +163 -0
  47. data/lib/mongoid/association/referenced/eager.rb +159 -0
  48. data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +290 -0
  49. data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +71 -0
  50. data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +40 -0
  51. data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +52 -0
  52. data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +310 -0
  53. data/lib/mongoid/association/referenced/has_many.rb +273 -0
  54. data/lib/mongoid/{relations/bindings/referenced/many.rb → association/referenced/has_many/binding.rb} +6 -5
  55. data/lib/mongoid/association/referenced/has_many/buildable.rb +38 -0
  56. data/lib/mongoid/association/referenced/has_many/eager.rb +43 -0
  57. data/lib/mongoid/association/referenced/has_many/enumerable.rb +479 -0
  58. data/lib/mongoid/association/referenced/has_many/proxy.rb +577 -0
  59. data/lib/mongoid/association/referenced/has_one.rb +204 -0
  60. data/lib/mongoid/{relations/bindings/referenced/one.rb → association/referenced/has_one/binding.rb} +11 -8
  61. data/lib/mongoid/association/referenced/has_one/buildable.rb +60 -0
  62. data/lib/mongoid/association/referenced/has_one/eager.rb +35 -0
  63. data/lib/mongoid/{relations/builders/nested_attributes/one.rb → association/referenced/has_one/nested_builder.rb} +9 -9
  64. data/lib/mongoid/association/referenced/has_one/proxy.rb +113 -0
  65. data/lib/mongoid/association/referenced/syncable.rb +170 -0
  66. data/lib/mongoid/{relations → association}/reflections.rb +21 -17
  67. data/lib/mongoid/association/relatable.rb +415 -0
  68. data/lib/mongoid/association/touchable.rb +97 -0
  69. data/lib/mongoid/atomic.rb +6 -6
  70. data/lib/mongoid/atomic/modifiers.rb +8 -12
  71. data/lib/mongoid/atomic/paths/embedded/many.rb +1 -1
  72. data/lib/mongoid/atomic/paths/embedded/one.rb +1 -1
  73. data/lib/mongoid/attributes.rb +2 -1
  74. data/lib/mongoid/attributes/nested.rb +10 -10
  75. data/lib/mongoid/attributes/processing.rb +2 -2
  76. data/lib/mongoid/attributes/readonly.rb +2 -4
  77. data/lib/mongoid/clients.rb +0 -2
  78. data/lib/mongoid/clients/options.rb +1 -1
  79. data/lib/mongoid/clients/storage_options.rb +0 -1
  80. data/lib/mongoid/composable.rb +3 -4
  81. data/lib/mongoid/config.rb +1 -0
  82. data/lib/mongoid/contextual/aggregable/mongo.rb +1 -1
  83. data/lib/mongoid/contextual/atomic.rb +3 -6
  84. data/lib/mongoid/contextual/map_reduce.rb +3 -7
  85. data/lib/mongoid/contextual/memory.rb +5 -10
  86. data/lib/mongoid/contextual/mongo.rb +10 -27
  87. data/lib/mongoid/copyable.rb +6 -6
  88. data/lib/mongoid/criteria.rb +1 -2
  89. data/lib/mongoid/criteria/includable.rb +14 -14
  90. data/lib/mongoid/criteria/modifiable.rb +8 -14
  91. data/lib/mongoid/criteria/queryable/mergeable.rb +1 -3
  92. data/lib/mongoid/criteria/queryable/pipeline.rb +10 -5
  93. data/lib/mongoid/criteria/queryable/selectable.rb +10 -34
  94. data/lib/mongoid/document.rb +6 -6
  95. data/lib/mongoid/errors.rb +3 -1
  96. data/lib/mongoid/errors/invalid_dependent_strategy.rb +32 -0
  97. data/lib/mongoid/errors/invalid_relation_option.rb +29 -0
  98. data/lib/mongoid/errors/unknown_model.rb +25 -0
  99. data/lib/mongoid/extensions/array.rb +5 -5
  100. data/lib/mongoid/extensions/big_decimal.rb +1 -1
  101. data/lib/mongoid/extensions/object.rb +4 -4
  102. data/lib/mongoid/extensions/range.rb +1 -0
  103. data/lib/mongoid/extensions/regexp.rb +0 -1
  104. data/lib/mongoid/extensions/string.rb +1 -3
  105. data/lib/mongoid/factory.rb +4 -3
  106. data/lib/mongoid/fields.rb +1 -1
  107. data/lib/mongoid/fields/foreign_key.rb +5 -5
  108. data/lib/mongoid/fields/standard.rb +2 -14
  109. data/lib/mongoid/fields/validators/macro.rb +1 -1
  110. data/lib/mongoid/indexable.rb +8 -5
  111. data/lib/mongoid/interceptable.rb +5 -5
  112. data/lib/mongoid/matchable.rb +0 -3
  113. data/lib/mongoid/persistable.rb +4 -5
  114. data/lib/mongoid/persistable/creatable.rb +2 -4
  115. data/lib/mongoid/persistable/deletable.rb +9 -10
  116. data/lib/mongoid/persistable/destroyable.rb +5 -1
  117. data/lib/mongoid/persistable/incrementable.rb +1 -1
  118. data/lib/mongoid/persistable/logical.rb +1 -1
  119. data/lib/mongoid/persistable/settable.rb +5 -5
  120. data/lib/mongoid/persistable/updatable.rb +2 -2
  121. data/lib/mongoid/persistable/upsertable.rb +1 -2
  122. data/lib/mongoid/persistence_context.rb +4 -9
  123. data/lib/mongoid/query_cache.rb +18 -65
  124. data/lib/mongoid/railtie.rb +0 -17
  125. data/lib/mongoid/reloadable.rb +1 -1
  126. data/lib/mongoid/scopable.rb +3 -3
  127. data/lib/mongoid/serializable.rb +3 -3
  128. data/lib/mongoid/tasks/database.rb +2 -3
  129. data/lib/mongoid/threaded.rb +0 -74
  130. data/lib/mongoid/traversable.rb +2 -2
  131. data/lib/mongoid/validatable.rb +8 -8
  132. data/lib/mongoid/validatable/presence.rb +2 -2
  133. data/lib/mongoid/validatable/uniqueness.rb +4 -4
  134. data/lib/mongoid/version.rb +1 -1
  135. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +3 -4
  136. data/spec/app/models/animal.rb +2 -1
  137. data/spec/app/models/band.rb +0 -1
  138. data/spec/app/models/bomb.rb +1 -1
  139. data/spec/app/models/message.rb +1 -1
  140. data/spec/app/models/person.rb +5 -2
  141. data/spec/app/models/vertex.rb +6 -0
  142. data/spec/app/models/wiki_page.rb +1 -1
  143. data/spec/config/mongoid.yml +1 -0
  144. data/spec/mongoid/{relations → association}/accessors_spec.rb +1 -1
  145. data/spec/mongoid/{relations → association}/auto_save_spec.rb +60 -12
  146. data/spec/mongoid/{relations → association}/builders_spec.rb +1 -1
  147. data/spec/mongoid/association/constrainable_spec.rb +115 -0
  148. data/spec/mongoid/{relations → association}/counter_cache_spec.rb +1 -1
  149. data/spec/mongoid/association/depending_spec.rb +613 -0
  150. data/spec/mongoid/{relations → association}/eager_spec.rb +12 -12
  151. data/spec/mongoid/{relations → association/embedded}/cyclic_spec.rb +1 -1
  152. data/spec/mongoid/{relations → association}/embedded/dirty_spec.rb +0 -0
  153. data/spec/mongoid/{relations/bindings/embedded/in_spec.rb → association/embedded/embedded_in/binding_spec.rb} +13 -13
  154. data/spec/mongoid/{relations/builders/embedded/in_spec.rb → association/embedded/embedded_in/buildable_spec.rb} +9 -9
  155. data/spec/mongoid/{relations/embedded/in_spec.rb → association/embedded/embedded_in/proxy_spec.rb} +5 -77
  156. data/spec/mongoid/association/embedded/embedded_in_spec.rb +843 -0
  157. data/spec/mongoid/{relations/bindings/embedded/many_spec.rb → association/embedded/embeds_many/binding_spec.rb} +3 -3
  158. data/spec/mongoid/{relations/builders/embedded/many_spec.rb → association/embedded/embeds_many/buildable_spec.rb} +17 -45
  159. data/spec/mongoid/{relations/embedded/many_spec.rb → association/embedded/embeds_many/proxy_spec.rb} +140 -428
  160. data/spec/mongoid/association/embedded/embeds_many_spec.rb +852 -0
  161. data/spec/mongoid/{relations/bindings/embedded/one_spec.rb → association/embedded/embeds_one/binding_spec.rb} +4 -4
  162. data/spec/mongoid/{relations/builders/embedded/one_spec.rb → association/embedded/embeds_one/buildable_spec.rb} +14 -34
  163. data/spec/mongoid/{relations/embedded/one_spec.rb → association/embedded/embeds_one/proxy_spec.rb} +39 -84
  164. data/spec/mongoid/association/embedded/embeds_one_spec.rb +908 -0
  165. data/spec/mongoid/{relations → association}/macros_spec.rb +148 -93
  166. data/spec/mongoid/{relations/builders/nested_attributes → association/nested}/many_spec.rb +16 -19
  167. data/spec/mongoid/{relations/builders/nested_attributes → association/nested}/one_spec.rb +17 -20
  168. data/spec/mongoid/association/options_spec.rb +1321 -0
  169. data/spec/mongoid/{relations → association}/polymorphic_spec.rb +7 -34
  170. data/spec/mongoid/{relations/bindings/referenced/in_spec.rb → association/referenced/belongs_to/binding_spec.rb} +7 -7
  171. data/spec/mongoid/{relations/builders/referenced/in_spec.rb → association/referenced/belongs_to/buildable_spec.rb} +46 -79
  172. data/spec/mongoid/{relations/eager/belongs_to_spec.rb → association/referenced/belongs_to/eager_spec.rb} +9 -9
  173. data/spec/mongoid/{relations/referenced/in_spec.rb → association/referenced/belongs_to/proxy_spec.rb} +57 -91
  174. data/spec/mongoid/association/referenced/belongs_to_spec.rb +1963 -0
  175. data/spec/mongoid/{relations/bindings/referenced/many_to_many_spec.rb → association/referenced/has_and_belongs_to_many/binding_spec.rb} +5 -5
  176. data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +121 -0
  177. data/spec/mongoid/{relations/eager/has_and_belongs_to_many_spec.rb → association/referenced/has_and_belongs_to_many/eager_spec.rb} +5 -5
  178. data/spec/mongoid/{relations/referenced/many_to_many_spec.rb → association/referenced/has_and_belongs_to_many/proxy_spec.rb} +107 -98
  179. data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +1027 -0
  180. data/spec/mongoid/{relations/bindings/referenced/many_spec.rb → association/referenced/has_many/binding_spec.rb} +5 -5
  181. data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +119 -0
  182. data/spec/mongoid/{relations/eager/has_many_spec.rb → association/referenced/has_many/eager_spec.rb} +11 -11
  183. data/spec/mongoid/{relations/targets → association/referenced/has_many}/enumerable_spec.rb +1 -109
  184. data/spec/mongoid/{relations/referenced/many_spec.rb → association/referenced/has_many/proxy_spec.rb} +28 -93
  185. data/spec/mongoid/association/referenced/has_many_spec.rb +1225 -0
  186. data/spec/mongoid/{relations/bindings/referenced/one_spec.rb → association/referenced/has_one/binding_spec.rb} +4 -4
  187. data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +113 -0
  188. data/spec/mongoid/{relations/eager/has_one_spec.rb → association/referenced/has_one/eager_spec.rb} +10 -10
  189. data/spec/mongoid/{relations/referenced/one_spec.rb → association/referenced/has_one/proxy_spec.rb} +9 -109
  190. data/spec/mongoid/association/referenced/has_one_spec.rb +1244 -0
  191. data/spec/mongoid/{relations → association}/reflections_spec.rb +1 -12
  192. data/spec/mongoid/{relations/synchronization_spec.rb → association/syncable_spec.rb} +4 -2
  193. data/spec/mongoid/{relations → association}/touchable_spec.rb +19 -1
  194. data/spec/mongoid/{relations_spec.rb → association_spec.rb} +1 -1
  195. data/spec/mongoid/atomic/modifiers_spec.rb +17 -17
  196. data/spec/mongoid/atomic_spec.rb +17 -17
  197. data/spec/mongoid/attributes/nested_spec.rb +14 -12
  198. data/spec/mongoid/attributes/readonly_spec.rb +80 -125
  199. data/spec/mongoid/clients/factory_spec.rb +28 -52
  200. data/spec/mongoid/clients/options_spec.rb +65 -69
  201. data/spec/mongoid/config_spec.rb +24 -0
  202. data/spec/mongoid/contextual/geo_near_spec.rb +0 -1
  203. data/spec/mongoid/contextual/mongo_spec.rb +4 -112
  204. data/spec/mongoid/criteria/modifiable_spec.rb +183 -60
  205. data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +3 -3
  206. data/spec/mongoid/criteria/queryable/pipeline_spec.rb +12 -0
  207. data/spec/mongoid/criteria/queryable/selectable_spec.rb +6 -74
  208. data/spec/mongoid/criteria/queryable/selector_spec.rb +2 -2
  209. data/spec/mongoid/criteria/scopable_spec.rb +0 -81
  210. data/spec/mongoid/criteria_spec.rb +16 -19
  211. data/spec/mongoid/document_spec.rb +2 -56
  212. data/spec/mongoid/extensions/array_spec.rb +11 -15
  213. data/spec/mongoid/extensions/big_decimal_spec.rb +9 -9
  214. data/spec/mongoid/extensions/object_spec.rb +7 -11
  215. data/spec/mongoid/extensions/range_spec.rb +7 -0
  216. data/spec/mongoid/extensions/regexp_spec.rb +0 -23
  217. data/spec/mongoid/extensions/string_spec.rb +7 -35
  218. data/spec/mongoid/factory_spec.rb +18 -11
  219. data/spec/mongoid/fields/foreign_key_spec.rb +24 -32
  220. data/spec/mongoid/fields_spec.rb +2 -2
  221. data/spec/mongoid/findable_spec.rb +1 -1
  222. data/spec/mongoid/indexable_spec.rb +18 -8
  223. data/spec/mongoid/interceptable_spec.rb +21 -2
  224. data/spec/mongoid/matchable_spec.rb +1 -26
  225. data/spec/mongoid/persistable/deletable_spec.rb +0 -19
  226. data/spec/mongoid/persistable/destroyable_spec.rb +0 -19
  227. data/spec/mongoid/persistable/incrementable_spec.rb +6 -6
  228. data/spec/mongoid/persistable/savable_spec.rb +3 -3
  229. data/spec/mongoid/persistable/settable_spec.rb +1 -35
  230. data/spec/mongoid/persistable/updatable_spec.rb +2 -2
  231. data/spec/mongoid/persistable_spec.rb +16 -16
  232. data/spec/mongoid/persistence_context_spec.rb +0 -14
  233. data/spec/mongoid/positional_spec.rb +10 -10
  234. data/spec/mongoid/query_cache_spec.rb +18 -87
  235. data/spec/mongoid/relations/proxy_spec.rb +124 -124
  236. data/spec/mongoid/scopable_spec.rb +0 -13
  237. data/spec/mongoid/threaded_spec.rb +0 -68
  238. data/spec/mongoid/validatable/associated_spec.rb +1 -1
  239. data/spec/mongoid/validatable/presence_spec.rb +7 -6
  240. data/spec/mongoid/validatable_spec.rb +1 -1
  241. data/spec/spec_helper.rb +7 -83
  242. metadata +586 -611
  243. metadata.gz.sig +2 -5
  244. data/lib/mongoid/clients/sessions.rb +0 -113
  245. data/lib/mongoid/errors/invalid_session_use.rb +0 -24
  246. data/lib/mongoid/matchable/nor.rb +0 -37
  247. data/lib/mongoid/railties/controller_runtime.rb +0 -86
  248. data/lib/mongoid/relations.rb +0 -148
  249. data/lib/mongoid/relations/accessors.rb +0 -267
  250. data/lib/mongoid/relations/auto_save.rb +0 -94
  251. data/lib/mongoid/relations/bindings.rb +0 -9
  252. data/lib/mongoid/relations/bindings/embedded/in.rb +0 -59
  253. data/lib/mongoid/relations/bindings/referenced/in.rb +0 -65
  254. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +0 -70
  255. data/lib/mongoid/relations/builder.rb +0 -57
  256. data/lib/mongoid/relations/builders.rb +0 -106
  257. data/lib/mongoid/relations/builders/nested_attributes/many.rb +0 -199
  258. data/lib/mongoid/relations/builders/referenced/in.rb +0 -26
  259. data/lib/mongoid/relations/builders/referenced/many.rb +0 -26
  260. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +0 -39
  261. data/lib/mongoid/relations/builders/referenced/one.rb +0 -26
  262. data/lib/mongoid/relations/cascading.rb +0 -56
  263. data/lib/mongoid/relations/cascading/delete.rb +0 -44
  264. data/lib/mongoid/relations/cascading/destroy.rb +0 -43
  265. data/lib/mongoid/relations/cascading/nullify.rb +0 -35
  266. data/lib/mongoid/relations/cascading/restrict.rb +0 -39
  267. data/lib/mongoid/relations/conversions.rb +0 -34
  268. data/lib/mongoid/relations/counter_cache.rb +0 -160
  269. data/lib/mongoid/relations/cyclic.rb +0 -107
  270. data/lib/mongoid/relations/eager/base.rb +0 -153
  271. data/lib/mongoid/relations/eager/belongs_to.rb +0 -31
  272. data/lib/mongoid/relations/eager/has_and_belongs_to_many.rb +0 -47
  273. data/lib/mongoid/relations/eager/has_many.rb +0 -38
  274. data/lib/mongoid/relations/eager/has_one.rb +0 -30
  275. data/lib/mongoid/relations/embedded/in.rb +0 -241
  276. data/lib/mongoid/relations/embedded/many.rb +0 -683
  277. data/lib/mongoid/relations/embedded/one.rb +0 -235
  278. data/lib/mongoid/relations/macros.rb +0 -367
  279. data/lib/mongoid/relations/metadata.rb +0 -1179
  280. data/lib/mongoid/relations/nested_builder.rb +0 -74
  281. data/lib/mongoid/relations/options.rb +0 -49
  282. data/lib/mongoid/relations/polymorphic.rb +0 -39
  283. data/lib/mongoid/relations/referenced/in.rb +0 -304
  284. data/lib/mongoid/relations/referenced/many.rb +0 -812
  285. data/lib/mongoid/relations/referenced/many_to_many.rb +0 -479
  286. data/lib/mongoid/relations/referenced/one.rb +0 -290
  287. data/lib/mongoid/relations/synchronization.rb +0 -169
  288. data/lib/mongoid/relations/targets.rb +0 -2
  289. data/lib/mongoid/relations/targets/enumerable.rb +0 -493
  290. data/lib/mongoid/relations/touchable.rb +0 -97
  291. data/spec/app/models/array_field.rb +0 -7
  292. data/spec/app/models/delegating_patient.rb +0 -16
  293. data/spec/integration/document_spec.rb +0 -22
  294. data/spec/mongoid/clients/sessions_spec.rb +0 -334
  295. data/spec/mongoid/fields/internal/foreign_keys/array_spec.rb +0 -184
  296. data/spec/mongoid/fields/internal/foreign_keys/object_spec.rb +0 -201
  297. data/spec/mongoid/matchable/nor_spec.rb +0 -209
  298. data/spec/mongoid/relations/builders/referenced/many_spec.rb +0 -137
  299. data/spec/mongoid/relations/builders/referenced/many_to_many_spec.rb +0 -178
  300. data/spec/mongoid/relations/builders/referenced/one_spec.rb +0 -111
  301. data/spec/mongoid/relations/cascading/delete_spec.rb +0 -101
  302. data/spec/mongoid/relations/cascading/destroy_spec.rb +0 -47
  303. data/spec/mongoid/relations/cascading/nullify_spec.rb +0 -32
  304. data/spec/mongoid/relations/cascading/restrict_spec.rb +0 -68
  305. data/spec/mongoid/relations/cascading_spec.rb +0 -355
  306. data/spec/mongoid/relations/constraint_spec.rb +0 -75
  307. data/spec/mongoid/relations/conversions_spec.rb +0 -128
  308. data/spec/mongoid/relations/metadata_spec.rb +0 -1985
  309. data/spec/mongoid/relations/options_spec.rb +0 -35
  310. data/spec/rails/controller_extension/controller_runtime_spec.rb +0 -110
  311. data/spec/support/cluster_config.rb +0 -158
  312. data/spec/support/constraints.rb +0 -101
  313. data/spec/support/macros.rb +0 -20
  314. data/spec/support/session_registry.rb +0 -50
  315. data/spec/support/spec_config.rb +0 -42
@@ -1,9 +1,13 @@
1
- # encoding: utf-8
2
1
  module Mongoid
3
- module Relations
4
- module Builders
5
- module Embedded
6
- class In < Builder
2
+ module Association
3
+ module Embedded
4
+ class EmbeddedIn
5
+
6
+ # The Builder behavior for embedded_in associations.
7
+ #
8
+ # @since 7.0
9
+ module Buildable
10
+ include Threaded::Lifecycle
7
11
 
8
12
  # This builder doesn't actually build anything, just returns the
9
13
  # parent since it should already be instantiated.
@@ -11,10 +15,12 @@ module Mongoid
11
15
  # @example Build the document.
12
16
  # Builder.new(meta, attrs).build
13
17
  #
18
+ # @param [ Object ] base The object.
19
+ # @param [ Object ] object The parent hash or document.
14
20
  # @param [ String ] type Not used in this context.
15
21
  #
16
22
  # @return [ Document ] A single document.
17
- def build(type = nil)
23
+ def build(base, object, type = nil)
18
24
  return object unless object.is_a?(Hash)
19
25
  if _loading?
20
26
  Factory.from_db(klass, object)
@@ -0,0 +1,121 @@
1
+ module Mongoid
2
+ module Association
3
+ module Embedded
4
+ class EmbeddedIn
5
+
6
+ class Proxy < Association::One
7
+
8
+ # Instantiate a new embedded_in relation.
9
+ #
10
+ # @example Create the new relation.
11
+ # Association::Embedded::EmbeddedIn.new(person, address, association)
12
+ #
13
+ # @param [ Document ] base The document the relation hangs off of.
14
+ # @param [ Document ] target The target (parent) of the relation.
15
+ # @param [ Association ] association The association metadata.
16
+ #
17
+ # @return [ In ] The proxy.
18
+ def initialize(base, target, association)
19
+ init(base, target, association) do
20
+ characterize_one(_target)
21
+ bind_one
22
+ end
23
+ end
24
+
25
+ # Substitutes the supplied target documents for the existing document
26
+ # in the relation.
27
+ #
28
+ # @example Substitute the new document.
29
+ # person.name.substitute(new_name)
30
+ #
31
+ # @param [ Document ] replacement A document to replace the target.
32
+ #
33
+ # @return [ Document, nil ] The relation or nil.
34
+ #
35
+ # @since 2.0.0.rc.1
36
+ def substitute(replacement)
37
+ unbind_one
38
+ unless replacement
39
+ _base.delete if persistable?
40
+ return nil
41
+ end
42
+ _base.new_record = true
43
+ self._target = replacement
44
+ bind_one
45
+ self
46
+ end
47
+
48
+ private
49
+
50
+ # Instantiate the binding associated with this relation.
51
+ #
52
+ # @example Get the binding.
53
+ # binding([ address ])
54
+ #
55
+ # @return [ Binding ] A binding object.
56
+ #
57
+ # @since 2.0.0.rc.1
58
+ def binding
59
+ Binding.new(_base, _target, _association)
60
+ end
61
+
62
+ # Characterize the document.
63
+ #
64
+ # @example Set the base association.
65
+ # object.characterize_one(document)
66
+ #
67
+ # @param [ Document ] document The document to set the association metadata on.
68
+ #
69
+ # @since 2.1.0
70
+ def characterize_one(document)
71
+ unless _base._association
72
+ _base._association = _association.inverse_association(document)
73
+ end
74
+ end
75
+
76
+ # Are we able to persist this relation?
77
+ #
78
+ # @example Can we persist the relation?
79
+ # relation.persistable?
80
+ #
81
+ # @return [ true, false ] If the relation is persistable.
82
+ #
83
+ # @since 2.1.0
84
+ def persistable?
85
+ _target.persisted? && !_binding? && !_building?
86
+ end
87
+
88
+ class << self
89
+
90
+ # Returns true if the relation is an embedded one. In this case
91
+ # always true.
92
+ #
93
+ # @example Is this relation embedded?
94
+ # Association::Embedded::EmbeddedIn.embedded?
95
+ #
96
+ # @return [ true ] true.
97
+ #
98
+ # @since 2.0.0.rc.1
99
+ def embedded?
100
+ true
101
+ end
102
+
103
+ # Get the path calculator for the supplied document.
104
+ #
105
+ # @example Get the path calculator.
106
+ # Proxy.path(document)
107
+ #
108
+ # @param [ Document ] document The document to calculate on.
109
+ #
110
+ # @return [ Root ] The root atomic path calculator.
111
+ #
112
+ # @since 2.1.0
113
+ def path(document)
114
+ Mongoid::Atomic::Paths::Root.new(document)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,210 @@
1
+ require 'mongoid/association/embedded/embeds_many/binding'
2
+ require 'mongoid/association/embedded/embeds_many/buildable'
3
+ require 'mongoid/association/embedded/embeds_many/proxy'
4
+
5
+ module Mongoid
6
+ module Association
7
+ module Embedded
8
+
9
+ # The EmbedsMany type association.
10
+ #
11
+ # @since 7.0
12
+ class EmbedsMany
13
+ include Relatable
14
+ include Buildable
15
+
16
+ # The options available for this type of association, in addition to the
17
+ # common ones.
18
+ #
19
+ # @return [ Array<Symbol> ] The extra valid options.
20
+ #
21
+ # @since 7.0
22
+ ASSOCIATION_OPTIONS = [
23
+ :as,
24
+ :cascade_callbacks,
25
+ :cyclic,
26
+ :order,
27
+ :store_as,
28
+ :before_add,
29
+ :after_add,
30
+ :before_remove,
31
+ :after_remove
32
+ ]
33
+
34
+ # The complete list of valid options for this association, including
35
+ # the shared ones.
36
+ #
37
+ # @return [ Array<Symbol> ] The valid options.
38
+ #
39
+ # @since 7.0
40
+ VALID_OPTIONS = (ASSOCIATION_OPTIONS + SHARED_OPTIONS).freeze
41
+
42
+ # Setup the instance methods, fields, etc. on the association owning class.
43
+ #
44
+ # @return [ self ]
45
+ #
46
+ # @since 7.0
47
+ def setup!
48
+ setup_instance_methods!
49
+ @owner_class.embedded_relations = @owner_class.embedded_relations.merge(name => self)
50
+ @owner_class.aliased_fields[name.to_s] = store_as if store_as
51
+ self
52
+ end
53
+
54
+ # The field key used to store the list of association objects.
55
+ #
56
+ # @return [ String ] The field name.
57
+ #
58
+ # @since 7.0
59
+ def store_as
60
+ @store_as ||= (@options[:store_as].try(:to_s) || name.to_s)
61
+ end
62
+
63
+ # The key that is used to get the attributes for the associated object.
64
+ #
65
+ # @return [ String ] The name of the field used to store the relation.
66
+ #
67
+ # @since 7.0
68
+ def key
69
+ store_as.to_s
70
+ end
71
+
72
+ # Is this association type embedded?
73
+ #
74
+ # @return [ true ] Always true.
75
+ #
76
+ # @since 7.0
77
+ def embedded?; true; end
78
+
79
+ # Get the default validation setting for the relation. Determines if
80
+ # by default a validates associated will occur.
81
+ #
82
+ # @example Get the validation default.
83
+ # Proxy.validation_default
84
+ #
85
+ # @return [ true ] Always true.
86
+ #
87
+ # @since 2.1.9
88
+ def validation_default; true; end
89
+
90
+ # Does this association type store the foreign key?
91
+ #
92
+ # @return [ false ] Always false.
93
+ #
94
+ # @since 7.0
95
+ def stores_foreign_key?; false; end
96
+
97
+ # The primary key
98
+ #
99
+ # @return [ nil ] Not relevant for this relation
100
+ def primary_key; end
101
+
102
+ # Get the relation proxy class for this association type.
103
+ #
104
+ # @return [ Association::Embedded::EmbedsMany::Proxy ] The proxy class.
105
+ #
106
+ # @since 7.0
107
+ def relation
108
+ Proxy
109
+ end
110
+
111
+ # Is this association polymorphic?
112
+ #
113
+ # @return [ true, false ] Whether this association is polymorphic.
114
+ #
115
+ # @since 7.0
116
+ def polymorphic?
117
+ @polymorphic ||= !!@options[:as]
118
+ end
119
+
120
+ # The field used to store the type of the related object.
121
+ #
122
+ # @note Only relevant if the association is polymorphic.
123
+ #
124
+ # @return [ String, nil ] The field for storing the associated object's type.
125
+ #
126
+ # @since 7.0
127
+ def type
128
+ @type ||= "#{as}_type" if polymorphic?
129
+ end
130
+
131
+ # The nested builder object.
132
+ #
133
+ # @param [ Hash ] attributes The attributes to use to build the association object.
134
+ # @param [ Hash ] options The options for the association.
135
+ #
136
+ # @return [ Association::Nested::Many ] The Nested Builder object.
137
+ #
138
+ # @since 7.0
139
+ def nested_builder(attributes, options)
140
+ Nested::Many.new(self, attributes, options)
141
+ end
142
+
143
+ # Get the path calculator for the supplied document.
144
+ #
145
+ # @example Get the path calculator.
146
+ # Proxy.path(document)
147
+ #
148
+ # @param [ Document ] document The document to calculate on.
149
+ #
150
+ # @return [ Mongoid::Atomic::Paths::Embedded::Many ]
151
+ # The embedded many atomic path calculator.
152
+ #
153
+ # @since 2.1.0
154
+ def path(document)
155
+ Mongoid::Atomic::Paths::Embedded::Many.new(document)
156
+ end
157
+
158
+ # Get a criteria object for searching given a parent and children documents.
159
+ #
160
+ # @param [ Document ] base The base document.
161
+ # @param [ Document ] target The children documents.
162
+ #
163
+ # @since 7.0
164
+ def criteria(base, target)
165
+ criterion = klass.scoped
166
+ criterion.embedded = true
167
+ criterion.documents = target
168
+ criterion.parent_document = base
169
+ criterion.association = self
170
+ apply_ordering(criterion)
171
+ end
172
+
173
+ private
174
+
175
+ def apply_ordering(criteria)
176
+ order ? criteria.order_by(order) : criteria
177
+ end
178
+
179
+ def setup_instance_methods!
180
+ define_getter!
181
+ define_setter!
182
+ define_existence_check!
183
+ define_builder!
184
+ define_creator!
185
+ @owner_class.cyclic = true if cyclic?
186
+ @owner_class.validates_associated(name) if validate?
187
+ end
188
+
189
+ def relation_complements
190
+ @relation_complements ||= [ Embedded::EmbeddedIn ].freeze
191
+ end
192
+
193
+ def polymorphic_inverses(other = nil)
194
+ [ as ]
195
+ end
196
+
197
+ def determine_inverses(other)
198
+ matches = relation_class.relations.values.select do |rel|
199
+ relation_complements.include?(rel.class) &&
200
+ rel.relation_class_name == inverse_class_name
201
+ end
202
+ if matches.size > 1
203
+ raise Errors::AmbiguousRelationship.new(relation_class, @owner_class, name, matches)
204
+ end
205
+ matches.collect { |m| m.name } unless matches.blank?
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
@@ -1,11 +1,13 @@
1
- # encoding: utf-8
2
1
  module Mongoid
3
- module Relations
4
- module Bindings
5
- module Embedded
2
+ module Association
3
+ module Embedded
4
+ class EmbedsMany
6
5
 
7
- # Binding class for embeds_many relations.
8
- class Many < Binding
6
+ # Binding class for all embeds_many relations.
7
+ #
8
+ # @since 7.0
9
+ class Binding
10
+ include Bindable
9
11
 
10
12
  # Binds a single document with the inverse relation. Used
11
13
  # specifically when appending to the proxy.
@@ -17,9 +19,9 @@ module Mongoid
17
19
  #
18
20
  # @since 2.0.0.rc.1
19
21
  def bind_one(doc)
20
- doc.parentize(base)
22
+ doc.parentize(_base)
21
23
  binding do
22
- doc.do_or_do_not(metadata.inverse_setter(target), base)
24
+ doc.do_or_do_not(_association.inverse_setter(_target), _base)
23
25
  end
24
26
  end
25
27
 
@@ -33,7 +35,7 @@ module Mongoid
33
35
  # @since 2.0.0.rc.1
34
36
  def unbind_one(doc)
35
37
  binding do
36
- doc.do_or_do_not(metadata.inverse_setter(target), nil)
38
+ doc.do_or_do_not(_association.inverse_setter(_target), nil)
37
39
  end
38
40
  end
39
41
  end
@@ -1,22 +1,28 @@
1
- # encoding: utf-8
2
1
  module Mongoid
3
- module Relations
4
- module Builders
5
- module Embedded
6
- class Many < Builder
2
+ module Association
3
+ module Embedded
4
+ class EmbedsMany
5
+
6
+ # Builder class for embeds_many associations.
7
+ #
8
+ # @since 7.0
9
+ module Buildable
10
+ include Threaded::Lifecycle
7
11
 
8
12
  # Builds the document out of the attributes using the provided
9
- # metadata on the relation. Instantiates through the factory in order
13
+ # association metadata. Instantiates through the factory in order
10
14
  # to make sure subclasses and allocation are used if fitting. This
11
15
  # case will return many documents.
12
16
  #
13
17
  # @example Build the documents.
14
18
  # Builder.new(meta, attrs).build
15
19
  #
20
+ # @param [ Object ] base The base object.
21
+ # @param [ Object ] object The object to use to build the relation.
16
22
  # @param [ String ] type Not used in this context.
17
23
  #
18
24
  # @return [ Array<Document ] The documents.
19
- def build(type = nil)
25
+ def build(base, object, type = nil)
20
26
  return [] if object.blank?
21
27
  return object if object.first.is_a?(Document)
22
28
  docs = []
@@ -0,0 +1,529 @@
1
+ require 'mongoid/association/embedded/batchable'
2
+
3
+ module Mongoid
4
+ module Association
5
+ module Embedded
6
+ class EmbedsMany
7
+
8
+ class Proxy < Association::Many
9
+ include Batchable
10
+
11
+ # Appends a document or array of documents to the relation. Will set
12
+ # the parent and update the index in the process.
13
+ #
14
+ # @example Append a document.
15
+ # person.addresses << address
16
+ #
17
+ # @example Push a document.
18
+ # person.addresses.push(address)
19
+ #
20
+ # @param [ Document, Array<Document> ] args Any number of documents.
21
+ def <<(*args)
22
+ docs = args.flatten
23
+ return concat(docs) if docs.size > 1
24
+ if doc = docs.first
25
+ append(doc)
26
+ doc.save if persistable? && !_assigning?
27
+ end
28
+ self
29
+ end
30
+
31
+ alias :push :<<
32
+
33
+ # Get this relation as as its representation in the database.
34
+ #
35
+ # @example Convert the relation to an attributes hash.
36
+ # person.addresses.as_document
37
+ #
38
+ # @return [ Array<Hash> ] The relation as stored in the db.
39
+ #
40
+ # @since 2.0.0.rc.1
41
+ def as_document
42
+ as_attributes.collect { |attrs| BSON::Document.new(attrs) }
43
+ end
44
+
45
+ # Appends an array of documents to the relation. Performs a batch
46
+ # insert of the documents instead of persisting one at a time.
47
+ #
48
+ # @example Concat with other documents.
49
+ # person.addresses.concat([ address_one, address_two ])
50
+ #
51
+ # @param [ Array<Document> ] docs The docs to add.
52
+ #
53
+ # @return [ Array<Document> ] The documents.
54
+ #
55
+ # @since 2.4.0
56
+ def concat(docs)
57
+ batch_insert(docs) unless docs.empty?
58
+ self
59
+ end
60
+
61
+ # Builds a new document in the relation and appends it to the target.
62
+ # Takes an optional type if you want to specify a subclass.
63
+ #
64
+ # @example Build a new document on the relation.
65
+ # person.people.build(:name => "Bozo")
66
+ #
67
+ # @param [ Hash ] attributes The attributes to build the document with.
68
+ # @param [ Class ] type Optional class to build the document with.
69
+ #
70
+ # @return [ Document ] The new document.
71
+ def build(attributes = {}, type = nil)
72
+ doc = Factory.build(type || _association.klass, attributes)
73
+ append(doc)
74
+ doc.apply_post_processed_defaults
75
+ yield(doc) if block_given?
76
+ doc.run_callbacks(:build) { doc }
77
+ _base._reset_memoized_children!
78
+ doc
79
+ end
80
+
81
+ alias :new :build
82
+
83
+ # Clear the relation. Will delete the documents from the db if they are
84
+ # already persisted.
85
+ #
86
+ # @example Clear the relation.
87
+ # person.addresses.clear
88
+ #
89
+ # @return [ self ] The empty relation.
90
+ def clear
91
+ batch_clear(_target.dup)
92
+ self
93
+ end
94
+
95
+ # Returns a count of the number of documents in the association that have
96
+ # actually been persisted to the database.
97
+ #
98
+ # Use #size if you want the total number of documents.
99
+ #
100
+ # @example Get the count of persisted documents.
101
+ # person.addresses.count
102
+ #
103
+ # @return [ Integer ] The total number of persisted embedded docs, as
104
+ # flagged by the #persisted? method.
105
+ def count
106
+ _target.select { |doc| doc.persisted? }.size
107
+ end
108
+
109
+ # Delete the supplied document from the target. This method is proxied
110
+ # in order to reindex the array after the operation occurs.
111
+ #
112
+ # @example Delete the document from the relation.
113
+ # person.addresses.delete(address)
114
+ #
115
+ # @param [ Document ] document The document to be deleted.
116
+ #
117
+ # @return [ Document, nil ] The deleted document or nil if nothing deleted.
118
+ #
119
+ # @since 2.0.0.rc.1
120
+ def delete(document)
121
+ execute_callback :before_remove, document
122
+ doc = _target.delete_one(document)
123
+ if doc && !_binding?
124
+ _unscoped.delete_one(doc)
125
+ if _assigning?
126
+ _base.add_atomic_pull(doc)
127
+ else
128
+ doc.delete(suppress: true)
129
+ unbind_one(doc)
130
+ end
131
+ end
132
+ reindex
133
+ execute_callback :after_remove, document
134
+ doc
135
+ end
136
+
137
+ # Delete all the documents in the association without running callbacks.
138
+ #
139
+ # @example Delete all documents from the relation.
140
+ # person.addresses.delete_all
141
+ #
142
+ # @example Conditionally delete documents from the relation.
143
+ # person.addresses.delete_all({ :street => "Bond" })
144
+ #
145
+ # @param [ Hash ] conditions Conditions on which documents to delete.
146
+ #
147
+ # @return [ Integer ] The number of documents deleted.
148
+ def delete_all(conditions = {})
149
+ remove_all(conditions, :delete)
150
+ end
151
+
152
+ # Delete all the documents for which the provided block returns true.
153
+ #
154
+ # @example Delete the matching documents.
155
+ # person.addresses.delete_if do |doc|
156
+ # doc.state == "GA"
157
+ # end
158
+ #
159
+ # @return [ Many, Enumerator ] The relation or an enumerator if no
160
+ # block was provided.
161
+ #
162
+ # @since 3.1.0
163
+ def delete_if
164
+ if block_given?
165
+ dup_target = _target.dup
166
+ dup_target.each do |doc|
167
+ delete(doc) if yield(doc)
168
+ end
169
+ self
170
+ else
171
+ super
172
+ end
173
+ end
174
+
175
+ # Destroy all the documents in the association whilst running callbacks.
176
+ #
177
+ # @example Destroy all documents from the relation.
178
+ # person.addresses.destroy_all
179
+ #
180
+ # @example Conditionally destroy documents from the relation.
181
+ # person.addresses.destroy_all({ :street => "Bond" })
182
+ #
183
+ # @param [ Hash ] conditions Conditions on which documents to destroy.
184
+ #
185
+ # @return [ Integer ] The number of documents destroyed.
186
+ def destroy_all(conditions = {})
187
+ remove_all(conditions, :destroy)
188
+ end
189
+
190
+ # Determine if any documents in this relation exist in the database.
191
+ #
192
+ # @example Are there persisted documents?
193
+ # person.posts.exists?
194
+ #
195
+ # @return [ true, false ] True is persisted documents exist, false if not.
196
+ def exists?
197
+ count > 0
198
+ end
199
+
200
+ # Finds a document in this association through several different
201
+ # methods.
202
+ #
203
+ # @example Find a document by its id.
204
+ # person.addresses.find(BSON::ObjectId.new)
205
+ #
206
+ # @example Find documents for multiple ids.
207
+ # person.addresses.find([ BSON::ObjectId.new, BSON::ObjectId.new ])
208
+ #
209
+ # @param [ Array<Object> ] args Various arguments.
210
+ #
211
+ # @return [ Array<Document>, Document ] A single or multiple documents.
212
+ def find(*args)
213
+ criteria.find(*args)
214
+ end
215
+
216
+ # Instantiate a new embeds_many relation.
217
+ #
218
+ # @example Create the new relation.
219
+ # Many.new(person, addresses, association)
220
+ #
221
+ # @param [ Document ] base The document this relation hangs off of.
222
+ # @param [ Array<Document> ] target The child documents of the relation.
223
+ # @param [ Association ] association The association metadata
224
+ #
225
+ # @return [ Many ] The proxy.
226
+ def initialize(base, target, association)
227
+ init(base, target, association) do
228
+ _target.each_with_index do |doc, index|
229
+ integrate(doc)
230
+ doc._index = index
231
+ end
232
+ @_unscoped = _target.dup
233
+ @_target = scope(_target)
234
+ end
235
+ end
236
+
237
+ # Get all the documents in the relation that are loaded into memory.
238
+ #
239
+ # @example Get the in memory documents.
240
+ # relation.in_memory
241
+ #
242
+ # @return [ Array<Document> ] The documents in memory.
243
+ #
244
+ # @since 2.1.0
245
+ def in_memory
246
+ _target
247
+ end
248
+
249
+ # Pop documents off the relation. This can be a single document or
250
+ # multiples, and will automatically persist the changes.
251
+ #
252
+ # @example Pop a single document.
253
+ # relation.pop
254
+ #
255
+ # @example Pop multiple documents.
256
+ # relation.pop(3)
257
+ #
258
+ # @param [ Integer ] count The number of documents to pop, or 1 if not
259
+ # provided.
260
+ #
261
+ # @return [ Document, Array<Document> ] The popped document(s).
262
+ #
263
+ # @since 3.0.0
264
+ def pop(count = nil)
265
+ if count
266
+ if docs = _target[_target.size - count, _target.size]
267
+ docs.each { |doc| delete(doc) }
268
+ end
269
+ else
270
+ delete(_target[-1])
271
+ end
272
+ end
273
+
274
+ # Substitutes the supplied target documents for the existing documents
275
+ # in the relation.
276
+ #
277
+ # @example Substitute the relation's target.
278
+ # person.addresses.substitute([ address ])
279
+ #
280
+ # @param [ Array<Document> ] docs The replacement docs.
281
+ #
282
+ # @return [ Many ] The proxied relation.
283
+ #
284
+ # @since 2.0.0.rc.1
285
+ def substitute(docs)
286
+ batch_replace(docs)
287
+ self
288
+ end
289
+
290
+ # Return the relation with all previous scoping removed. This is the
291
+ # exact representation of the docs in the database.
292
+ #
293
+ # @example Get the unscoped documents.
294
+ # person.addresses.unscoped
295
+ #
296
+ # @return [ Criteria ] The unscoped relation.
297
+ #
298
+ # @since 2.4.0
299
+ def unscoped
300
+ criterion = klass.unscoped
301
+ criterion.embedded = true
302
+ criterion.documents = _unscoped.delete_if(&:marked_for_destruction?)
303
+ criterion
304
+ end
305
+
306
+ private
307
+
308
+ def object_already_related?(document)
309
+ _target.any? { |existing| existing.id && existing === document }
310
+ end
311
+
312
+ # Appends the document to the target array, updating the index on the
313
+ # document at the same time.
314
+ #
315
+ # @example Append to the document.
316
+ # relation.append(document)
317
+ #
318
+ # @param [ Document ] document The document to append to the target.
319
+ #
320
+ # @since 2.0.0.rc.1
321
+ def append(document)
322
+ execute_callback :before_add, document
323
+ unless object_already_related?(document)
324
+ _target.push(*scope([document]))
325
+ end
326
+ _unscoped.push(document)
327
+ integrate(document)
328
+ document._index = _unscoped.size - 1
329
+ execute_callback :after_add, document
330
+ end
331
+
332
+ # Instantiate the binding associated with this relation.
333
+ #
334
+ # @example Create the binding.
335
+ # relation.binding([ address ])
336
+ #
337
+ # @return [ Binding ] The many binding.
338
+ #
339
+ # @since 2.0.0.rc.1
340
+ def binding
341
+ Binding.new(_base, _target, _association)
342
+ end
343
+
344
+ # Returns the "#{criteria}"# object for the target class with its documents set
345
+ # to target.
346
+ #
347
+ # @example Get a criteria for the relation.
348
+ # relation.criteria
349
+ #
350
+ # @return [ Criteria ] A new criteria.
351
+ def criteria
352
+ @criteria ||= _association.criteria(_base, _target)
353
+ end
354
+
355
+ # Deletes one document from the target and unscoped.
356
+ #
357
+ # @api private
358
+ #
359
+ # @example Delete one document.
360
+ # relation.delete_one(doc)
361
+ #
362
+ # @param [ Document ] document The document to delete.
363
+ #
364
+ # @since 2.4.7
365
+ def delete_one(document)
366
+ _target.delete_one(document)
367
+ _unscoped.delete_one(document)
368
+ reindex
369
+ end
370
+
371
+ # Integrate the document into the relation. will set its metadata and
372
+ # attempt to bind the inverse.
373
+ #
374
+ # @example Integrate the document.
375
+ # relation.integrate(document)
376
+ #
377
+ # @param [ Document ] document The document to integrate.
378
+ #
379
+ # @since 2.1.0
380
+ def integrate(document)
381
+ characterize_one(document)
382
+ bind_one(document)
383
+ end
384
+
385
+ # If the target array does not respond to the supplied method then try to
386
+ # find a named scope or criteria on the class and send the call there.
387
+ #
388
+ # If the method exists on the array, use the default proxy behavior.
389
+ #
390
+ # @param [ Symbol, String ] name The name of the method.
391
+ # @param [ Array ] args The method args
392
+ # @param [ Proc ] block Optional block to pass.
393
+ #
394
+ # @return [ Criteria, Object ] A Criteria or return value from the target.
395
+ def method_missing(name, *args, &block)
396
+ return super if _target.respond_to?(name)
397
+ klass.send(:with_scope, criteria) do
398
+ criteria.public_send(name, *args, &block)
399
+ end
400
+ end
401
+
402
+ # Are we able to persist this relation?
403
+ #
404
+ # @example Can we persist the relation?
405
+ # relation.persistable?
406
+ #
407
+ # @return [ true, false ] If the relation is persistable.
408
+ #
409
+ # @since 2.1.0
410
+ def persistable?
411
+ _base.persisted? && !_binding?
412
+ end
413
+
414
+ # Reindex all the target elements. This is useful when performing
415
+ # operations on the proxied target directly and the indices need to
416
+ # match that on the database side.
417
+ #
418
+ # @example Reindex the relation.
419
+ # person.addresses.reindex
420
+ #
421
+ # @since 2.0.0.rc.1
422
+ def reindex
423
+ _unscoped.each_with_index do |doc, index|
424
+ doc._index = index
425
+ end
426
+ end
427
+
428
+ # Apply the association ordering or the default scoping to the provided
429
+ # documents.
430
+ #
431
+ # @example Apply scoping.
432
+ # person.addresses.scope(target)
433
+ #
434
+ # @param [ Array<Document> ] docs The documents to scope.
435
+ #
436
+ # @return [ Array<Document> ] The scoped docs.
437
+ #
438
+ # @since 2.4.0
439
+ def scope(docs)
440
+ return docs unless _association.order || _association.klass.default_scoping?
441
+ crit = _association.klass.order_by(_association.order)
442
+ crit.embedded = true
443
+ crit.documents = docs
444
+ crit.entries
445
+ end
446
+
447
+ # Remove all documents from the relation, either with a delete or a
448
+ # destroy depending on what this was called through.
449
+ #
450
+ # @example Destroy documents from the relation.
451
+ # relation.remove_all({ :num => 1 }, true)
452
+ #
453
+ # @param [ Hash ] conditions Conditions to filter by.
454
+ # @param [ true, false ] method :delete or :destroy.
455
+ #
456
+ # @return [ Integer ] The number of documents removed.
457
+ def remove_all(conditions = {}, method = :delete)
458
+ criteria = where(conditions || {})
459
+ removed = criteria.size
460
+ batch_remove(criteria, method)
461
+ removed
462
+ end
463
+
464
+ # Get the internal unscoped documents.
465
+ #
466
+ # @example Get the unscoped documents.
467
+ # relation._unscoped
468
+ #
469
+ # @return [ Array<Document> ] The unscoped documents.
470
+ #
471
+ # @since 2.4.0
472
+ def _unscoped
473
+ @_unscoped ||= []
474
+ end
475
+
476
+ # Set the internal unscoped documents.
477
+ #
478
+ # @example Set the unscoped documents.
479
+ # relation._unscoped = docs
480
+ #
481
+ # @param [ Array<Document> ] docs The documents.
482
+ #
483
+ # @return [ Array<Document ] The unscoped docs.
484
+ #
485
+ # @since 2.4.0
486
+ def _unscoped=(docs)
487
+ @_unscoped = docs
488
+ end
489
+
490
+ def as_attributes
491
+ attributes = []
492
+ _unscoped.each do |doc|
493
+ attributes.push(doc.as_document)
494
+ end
495
+ attributes
496
+ end
497
+
498
+ class << self
499
+
500
+ # Returns true if the relation is an embedded one. In this case
501
+ # always true.
502
+ #
503
+ # @example Is the relation embedded?
504
+ # Association::Embedded::EmbedsMany.embedded?
505
+ #
506
+ # @return [ true ] true.
507
+ #
508
+ # @since 2.0.0.rc.1
509
+ def embedded?
510
+ true
511
+ end
512
+
513
+ # Returns the suffix of the foreign key field, either "_id" or "_ids".
514
+ #
515
+ # @example Get the suffix for the foreign key.
516
+ # Association::Embedded::EmbedsMany.foreign_key_suffix
517
+ #
518
+ # @return [ nil ] nil.
519
+ #
520
+ # @since 3.0.0
521
+ def foreign_key_suffix
522
+ nil
523
+ end
524
+ end
525
+ end
526
+ end
527
+ end
528
+ end
529
+ end