mongoid-multi-db 3.0.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 (276) hide show
  1. data/CHANGELOG.md +615 -0
  2. data/LICENSE +20 -0
  3. data/README.md +62 -0
  4. data/Rakefile +49 -0
  5. data/lib/config/locales/bg.yml +54 -0
  6. data/lib/config/locales/de.yml +54 -0
  7. data/lib/config/locales/en-GB.yml +55 -0
  8. data/lib/config/locales/en.yml +55 -0
  9. data/lib/config/locales/es.yml +52 -0
  10. data/lib/config/locales/fr.yml +55 -0
  11. data/lib/config/locales/hi.yml +46 -0
  12. data/lib/config/locales/hu.yml +57 -0
  13. data/lib/config/locales/id.yml +55 -0
  14. data/lib/config/locales/it.yml +52 -0
  15. data/lib/config/locales/ja.yml +50 -0
  16. data/lib/config/locales/kr.yml +47 -0
  17. data/lib/config/locales/nl.yml +52 -0
  18. data/lib/config/locales/pl.yml +52 -0
  19. data/lib/config/locales/pt-BR.yml +53 -0
  20. data/lib/config/locales/pt.yml +53 -0
  21. data/lib/config/locales/ro.yml +59 -0
  22. data/lib/config/locales/ru.yml +54 -0
  23. data/lib/config/locales/sv.yml +53 -0
  24. data/lib/config/locales/vi.yml +55 -0
  25. data/lib/config/locales/zh-CN.yml +46 -0
  26. data/lib/mongoid.rb +148 -0
  27. data/lib/mongoid/atomic.rb +230 -0
  28. data/lib/mongoid/atomic/modifiers.rb +243 -0
  29. data/lib/mongoid/atomic/paths.rb +3 -0
  30. data/lib/mongoid/atomic/paths/embedded.rb +43 -0
  31. data/lib/mongoid/atomic/paths/embedded/many.rb +44 -0
  32. data/lib/mongoid/atomic/paths/embedded/one.rb +43 -0
  33. data/lib/mongoid/atomic/paths/root.rb +40 -0
  34. data/lib/mongoid/attributes.rb +234 -0
  35. data/lib/mongoid/attributes/processing.rb +146 -0
  36. data/lib/mongoid/callbacks.rb +135 -0
  37. data/lib/mongoid/collection.rb +153 -0
  38. data/lib/mongoid/collection_proxy.rb +59 -0
  39. data/lib/mongoid/collections.rb +120 -0
  40. data/lib/mongoid/collections/master.rb +45 -0
  41. data/lib/mongoid/collections/operations.rb +44 -0
  42. data/lib/mongoid/collections/retry.rb +46 -0
  43. data/lib/mongoid/components.rb +96 -0
  44. data/lib/mongoid/config.rb +347 -0
  45. data/lib/mongoid/config/database.rb +186 -0
  46. data/lib/mongoid/config/replset_database.rb +82 -0
  47. data/lib/mongoid/connection_proxy.rb +30 -0
  48. data/lib/mongoid/contexts.rb +25 -0
  49. data/lib/mongoid/contexts/enumerable.rb +288 -0
  50. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  51. data/lib/mongoid/contexts/mongo.rb +409 -0
  52. data/lib/mongoid/copyable.rb +48 -0
  53. data/lib/mongoid/criteria.rb +418 -0
  54. data/lib/mongoid/criterion/builder.rb +34 -0
  55. data/lib/mongoid/criterion/complex.rb +84 -0
  56. data/lib/mongoid/criterion/creational.rb +34 -0
  57. data/lib/mongoid/criterion/exclusion.rb +108 -0
  58. data/lib/mongoid/criterion/inclusion.rb +305 -0
  59. data/lib/mongoid/criterion/inspection.rb +22 -0
  60. data/lib/mongoid/criterion/optional.rb +232 -0
  61. data/lib/mongoid/criterion/selector.rb +153 -0
  62. data/lib/mongoid/cursor.rb +86 -0
  63. data/lib/mongoid/database_proxy.rb +97 -0
  64. data/lib/mongoid/default_scope.rb +36 -0
  65. data/lib/mongoid/dirty.rb +110 -0
  66. data/lib/mongoid/document.rb +280 -0
  67. data/lib/mongoid/errors.rb +17 -0
  68. data/lib/mongoid/errors/callback.rb +26 -0
  69. data/lib/mongoid/errors/document_not_found.rb +28 -0
  70. data/lib/mongoid/errors/eager_load.rb +25 -0
  71. data/lib/mongoid/errors/invalid_collection.rb +18 -0
  72. data/lib/mongoid/errors/invalid_database.rb +19 -0
  73. data/lib/mongoid/errors/invalid_field.rb +18 -0
  74. data/lib/mongoid/errors/invalid_find.rb +19 -0
  75. data/lib/mongoid/errors/invalid_options.rb +28 -0
  76. data/lib/mongoid/errors/invalid_time.rb +25 -0
  77. data/lib/mongoid/errors/invalid_type.rb +25 -0
  78. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  79. data/lib/mongoid/errors/mongoid_error.rb +26 -0
  80. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +20 -0
  81. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  82. data/lib/mongoid/errors/unsupported_version.rb +20 -0
  83. data/lib/mongoid/errors/validations.rb +23 -0
  84. data/lib/mongoid/extensions.rb +82 -0
  85. data/lib/mongoid/extensions/array/deletion.rb +29 -0
  86. data/lib/mongoid/extensions/false_class/equality.rb +26 -0
  87. data/lib/mongoid/extensions/hash/criteria_helpers.rb +45 -0
  88. data/lib/mongoid/extensions/hash/scoping.rb +25 -0
  89. data/lib/mongoid/extensions/integer/checks.rb +23 -0
  90. data/lib/mongoid/extensions/nil/collectionization.rb +23 -0
  91. data/lib/mongoid/extensions/object/checks.rb +29 -0
  92. data/lib/mongoid/extensions/object/reflections.rb +48 -0
  93. data/lib/mongoid/extensions/object/substitutable.rb +15 -0
  94. data/lib/mongoid/extensions/object/yoda.rb +44 -0
  95. data/lib/mongoid/extensions/object_id/conversions.rb +60 -0
  96. data/lib/mongoid/extensions/proc/scoping.rb +25 -0
  97. data/lib/mongoid/extensions/string/checks.rb +36 -0
  98. data/lib/mongoid/extensions/string/conversions.rb +22 -0
  99. data/lib/mongoid/extensions/string/inflections.rb +118 -0
  100. data/lib/mongoid/extensions/symbol/checks.rb +23 -0
  101. data/lib/mongoid/extensions/symbol/inflections.rb +66 -0
  102. data/lib/mongoid/extensions/true_class/equality.rb +26 -0
  103. data/lib/mongoid/extras.rb +31 -0
  104. data/lib/mongoid/factory.rb +46 -0
  105. data/lib/mongoid/fields.rb +332 -0
  106. data/lib/mongoid/fields/mappings.rb +41 -0
  107. data/lib/mongoid/fields/serializable.rb +201 -0
  108. data/lib/mongoid/fields/serializable/array.rb +49 -0
  109. data/lib/mongoid/fields/serializable/big_decimal.rb +42 -0
  110. data/lib/mongoid/fields/serializable/bignum.rb +10 -0
  111. data/lib/mongoid/fields/serializable/binary.rb +11 -0
  112. data/lib/mongoid/fields/serializable/boolean.rb +43 -0
  113. data/lib/mongoid/fields/serializable/date.rb +51 -0
  114. data/lib/mongoid/fields/serializable/date_time.rb +28 -0
  115. data/lib/mongoid/fields/serializable/fixnum.rb +10 -0
  116. data/lib/mongoid/fields/serializable/float.rb +32 -0
  117. data/lib/mongoid/fields/serializable/foreign_keys/array.rb +42 -0
  118. data/lib/mongoid/fields/serializable/foreign_keys/object.rb +47 -0
  119. data/lib/mongoid/fields/serializable/hash.rb +11 -0
  120. data/lib/mongoid/fields/serializable/integer.rb +44 -0
  121. data/lib/mongoid/fields/serializable/localized.rb +41 -0
  122. data/lib/mongoid/fields/serializable/nil_class.rb +38 -0
  123. data/lib/mongoid/fields/serializable/object.rb +11 -0
  124. data/lib/mongoid/fields/serializable/object_id.rb +31 -0
  125. data/lib/mongoid/fields/serializable/range.rb +42 -0
  126. data/lib/mongoid/fields/serializable/set.rb +42 -0
  127. data/lib/mongoid/fields/serializable/string.rb +27 -0
  128. data/lib/mongoid/fields/serializable/symbol.rb +27 -0
  129. data/lib/mongoid/fields/serializable/time.rb +23 -0
  130. data/lib/mongoid/fields/serializable/time_with_zone.rb +23 -0
  131. data/lib/mongoid/fields/serializable/timekeeping.rb +106 -0
  132. data/lib/mongoid/finders.rb +152 -0
  133. data/lib/mongoid/hierarchy.rb +120 -0
  134. data/lib/mongoid/identity.rb +92 -0
  135. data/lib/mongoid/identity_map.rb +119 -0
  136. data/lib/mongoid/indexes.rb +54 -0
  137. data/lib/mongoid/inspection.rb +54 -0
  138. data/lib/mongoid/javascript.rb +20 -0
  139. data/lib/mongoid/javascript/functions.yml +63 -0
  140. data/lib/mongoid/json.rb +16 -0
  141. data/lib/mongoid/keys.rb +144 -0
  142. data/lib/mongoid/logger.rb +39 -0
  143. data/lib/mongoid/matchers.rb +32 -0
  144. data/lib/mongoid/matchers/all.rb +21 -0
  145. data/lib/mongoid/matchers/and.rb +30 -0
  146. data/lib/mongoid/matchers/default.rb +70 -0
  147. data/lib/mongoid/matchers/exists.rb +23 -0
  148. data/lib/mongoid/matchers/gt.rb +21 -0
  149. data/lib/mongoid/matchers/gte.rb +21 -0
  150. data/lib/mongoid/matchers/in.rb +21 -0
  151. data/lib/mongoid/matchers/lt.rb +21 -0
  152. data/lib/mongoid/matchers/lte.rb +21 -0
  153. data/lib/mongoid/matchers/ne.rb +21 -0
  154. data/lib/mongoid/matchers/nin.rb +21 -0
  155. data/lib/mongoid/matchers/or.rb +33 -0
  156. data/lib/mongoid/matchers/size.rb +21 -0
  157. data/lib/mongoid/matchers/strategies.rb +93 -0
  158. data/lib/mongoid/multi_database.rb +31 -0
  159. data/lib/mongoid/multi_parameter_attributes.rb +106 -0
  160. data/lib/mongoid/named_scope.rb +146 -0
  161. data/lib/mongoid/nested_attributes.rb +54 -0
  162. data/lib/mongoid/observer.rb +170 -0
  163. data/lib/mongoid/paranoia.rb +158 -0
  164. data/lib/mongoid/persistence.rb +264 -0
  165. data/lib/mongoid/persistence/atomic.rb +223 -0
  166. data/lib/mongoid/persistence/atomic/add_to_set.rb +35 -0
  167. data/lib/mongoid/persistence/atomic/bit.rb +37 -0
  168. data/lib/mongoid/persistence/atomic/inc.rb +31 -0
  169. data/lib/mongoid/persistence/atomic/operation.rb +85 -0
  170. data/lib/mongoid/persistence/atomic/pop.rb +34 -0
  171. data/lib/mongoid/persistence/atomic/pull.rb +34 -0
  172. data/lib/mongoid/persistence/atomic/pull_all.rb +34 -0
  173. data/lib/mongoid/persistence/atomic/push.rb +31 -0
  174. data/lib/mongoid/persistence/atomic/push_all.rb +31 -0
  175. data/lib/mongoid/persistence/atomic/rename.rb +31 -0
  176. data/lib/mongoid/persistence/atomic/sets.rb +30 -0
  177. data/lib/mongoid/persistence/atomic/unset.rb +28 -0
  178. data/lib/mongoid/persistence/deletion.rb +32 -0
  179. data/lib/mongoid/persistence/insertion.rb +41 -0
  180. data/lib/mongoid/persistence/modification.rb +37 -0
  181. data/lib/mongoid/persistence/operations.rb +211 -0
  182. data/lib/mongoid/persistence/operations/embedded/insert.rb +42 -0
  183. data/lib/mongoid/persistence/operations/embedded/remove.rb +40 -0
  184. data/lib/mongoid/persistence/operations/insert.rb +34 -0
  185. data/lib/mongoid/persistence/operations/remove.rb +33 -0
  186. data/lib/mongoid/persistence/operations/update.rb +64 -0
  187. data/lib/mongoid/railtie.rb +126 -0
  188. data/lib/mongoid/railties/database.rake +182 -0
  189. data/lib/mongoid/railties/document.rb +12 -0
  190. data/lib/mongoid/relations.rb +144 -0
  191. data/lib/mongoid/relations/accessors.rb +138 -0
  192. data/lib/mongoid/relations/auto_save.rb +38 -0
  193. data/lib/mongoid/relations/binding.rb +26 -0
  194. data/lib/mongoid/relations/bindings.rb +9 -0
  195. data/lib/mongoid/relations/bindings/embedded/in.rb +69 -0
  196. data/lib/mongoid/relations/bindings/embedded/many.rb +93 -0
  197. data/lib/mongoid/relations/bindings/embedded/one.rb +61 -0
  198. data/lib/mongoid/relations/bindings/referenced/in.rb +76 -0
  199. data/lib/mongoid/relations/bindings/referenced/many.rb +54 -0
  200. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +51 -0
  201. data/lib/mongoid/relations/bindings/referenced/one.rb +58 -0
  202. data/lib/mongoid/relations/builder.rb +57 -0
  203. data/lib/mongoid/relations/builders.rb +83 -0
  204. data/lib/mongoid/relations/builders/embedded/in.rb +29 -0
  205. data/lib/mongoid/relations/builders/embedded/many.rb +40 -0
  206. data/lib/mongoid/relations/builders/embedded/one.rb +30 -0
  207. data/lib/mongoid/relations/builders/nested_attributes/many.rb +110 -0
  208. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  209. data/lib/mongoid/relations/builders/referenced/in.rb +26 -0
  210. data/lib/mongoid/relations/builders/referenced/many.rb +27 -0
  211. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +38 -0
  212. data/lib/mongoid/relations/builders/referenced/one.rb +26 -0
  213. data/lib/mongoid/relations/cascading.rb +56 -0
  214. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  215. data/lib/mongoid/relations/cascading/destroy.rb +26 -0
  216. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  217. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  218. data/lib/mongoid/relations/constraint.rb +42 -0
  219. data/lib/mongoid/relations/conversions.rb +35 -0
  220. data/lib/mongoid/relations/cyclic.rb +103 -0
  221. data/lib/mongoid/relations/embedded/atomic.rb +89 -0
  222. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  223. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  224. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  225. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  226. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  227. data/lib/mongoid/relations/embedded/in.rb +220 -0
  228. data/lib/mongoid/relations/embedded/many.rb +560 -0
  229. data/lib/mongoid/relations/embedded/one.rb +206 -0
  230. data/lib/mongoid/relations/embedded/sort.rb +31 -0
  231. data/lib/mongoid/relations/macros.rb +310 -0
  232. data/lib/mongoid/relations/many.rb +135 -0
  233. data/lib/mongoid/relations/metadata.rb +919 -0
  234. data/lib/mongoid/relations/nested_builder.rb +75 -0
  235. data/lib/mongoid/relations/one.rb +36 -0
  236. data/lib/mongoid/relations/options.rb +47 -0
  237. data/lib/mongoid/relations/polymorphic.rb +40 -0
  238. data/lib/mongoid/relations/proxy.rb +145 -0
  239. data/lib/mongoid/relations/referenced/batch.rb +72 -0
  240. data/lib/mongoid/relations/referenced/batch/insert.rb +57 -0
  241. data/lib/mongoid/relations/referenced/in.rb +262 -0
  242. data/lib/mongoid/relations/referenced/many.rb +623 -0
  243. data/lib/mongoid/relations/referenced/many_to_many.rb +396 -0
  244. data/lib/mongoid/relations/referenced/one.rb +272 -0
  245. data/lib/mongoid/relations/reflections.rb +62 -0
  246. data/lib/mongoid/relations/synchronization.rb +153 -0
  247. data/lib/mongoid/relations/targets.rb +2 -0
  248. data/lib/mongoid/relations/targets/enumerable.rb +372 -0
  249. data/lib/mongoid/reloading.rb +91 -0
  250. data/lib/mongoid/safety.rb +105 -0
  251. data/lib/mongoid/scope.rb +31 -0
  252. data/lib/mongoid/serialization.rb +134 -0
  253. data/lib/mongoid/sharding.rb +61 -0
  254. data/lib/mongoid/state.rb +97 -0
  255. data/lib/mongoid/threaded.rb +530 -0
  256. data/lib/mongoid/threaded/lifecycle.rb +192 -0
  257. data/lib/mongoid/timestamps.rb +15 -0
  258. data/lib/mongoid/timestamps/created.rb +24 -0
  259. data/lib/mongoid/timestamps/timeless.rb +50 -0
  260. data/lib/mongoid/timestamps/updated.rb +26 -0
  261. data/lib/mongoid/validations.rb +140 -0
  262. data/lib/mongoid/validations/associated.rb +46 -0
  263. data/lib/mongoid/validations/uniqueness.rb +145 -0
  264. data/lib/mongoid/version.rb +4 -0
  265. data/lib/mongoid/versioning.rb +185 -0
  266. data/lib/rack/mongoid.rb +2 -0
  267. data/lib/rack/mongoid/middleware/identity_map.rb +38 -0
  268. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  269. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +20 -0
  270. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  271. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +19 -0
  272. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  273. data/lib/rails/generators/mongoid/observer/templates/observer.rb.tt +4 -0
  274. data/lib/rails/generators/mongoid_generator.rb +70 -0
  275. data/lib/rails/mongoid.rb +91 -0
  276. metadata +465 -0
@@ -0,0 +1,396 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Referenced #:nodoc:
5
+
6
+ # This class defines the behaviour for all relations that are a
7
+ # many-to-many between documents in different collections.
8
+ class ManyToMany < Many
9
+
10
+ # Appends a document or array of documents to the relation. Will set
11
+ # the parent and update the index in the process.
12
+ #
13
+ # @example Append a document.
14
+ # person.posts << post
15
+ #
16
+ # @example Push a document.
17
+ # person.posts.push(post)
18
+ #
19
+ # @example Concat with other documents.
20
+ # person.posts.concat([ post_one, post_two ])
21
+ #
22
+ # @param [ Document, Array<Document> ] *args Any number of documents.
23
+ #
24
+ # @return [ Array<Document> ] The loaded docs.
25
+ #
26
+ # @since 2.0.0.beta.1
27
+ def <<(*args)
28
+ batched do
29
+ [].tap do |ids|
30
+ args.flatten.each do |doc|
31
+ next unless doc
32
+ append(doc)
33
+ if persistable? || _creating?
34
+ ids.push(doc.id)
35
+ doc.save
36
+ else
37
+ base.send(metadata.foreign_key).push(doc.id)
38
+ base.synced[metadata.foreign_key] = false
39
+ end
40
+ end
41
+ if persistable? || _creating?
42
+ base.push_all(metadata.foreign_key, ids)
43
+ base.synced[metadata.foreign_key] = false
44
+ end
45
+ end
46
+ end
47
+ end
48
+ alias :concat :<<
49
+ alias :push :<<
50
+
51
+ # Build a new document from the attributes and append it to this
52
+ # relation without saving.
53
+ #
54
+ # @example Build a new document on the relation.
55
+ # person.posts.build(:title => "A new post")
56
+ #
57
+ # @overload build(attributes = {}, options = {}, type = nil)
58
+ # @param [ Hash ] attributes The attributes of the new document.
59
+ # @param [ Hash ] options The scoped assignment options.
60
+ # @param [ Class ] type The optional subclass to build.
61
+ #
62
+ # @overload build(attributes = {}, type = nil)
63
+ # @param [ Hash ] attributes The attributes of the new document.
64
+ # @param [ Hash ] options The scoped assignment options.
65
+ # @param [ Class ] type The optional subclass to build.
66
+ #
67
+ # @return [ Document ] The new document.
68
+ #
69
+ # @since 2.0.0.beta.1
70
+ def build(attributes = {}, options = {}, type = nil)
71
+ if options.is_a? Class
72
+ options, type = {}, options
73
+ end
74
+
75
+ Factory.build(type || klass, attributes, options).tap do |doc|
76
+ base.send(metadata.foreign_key).push(doc.id)
77
+ append(doc)
78
+ doc.synced[metadata.inverse_foreign_key] = false
79
+ yield(doc) if block_given?
80
+ end
81
+ end
82
+ alias :new :build
83
+
84
+ # Creates a new document on the references many relation. This will
85
+ # save the document if the parent has been persisted.
86
+ #
87
+ # @example Create and save the new document.
88
+ # person.posts.create(:text => "Testing")
89
+ #
90
+ # @param [ Hash ] attributes The attributes to create with.
91
+ # @param [ Class ] type The optional type of document to create.
92
+ #
93
+ # @return [ Document ] The newly created document.
94
+ #
95
+ # @since 2.0.0.beta.1
96
+ def create(attributes = nil, type = nil, &block)
97
+ super.tap do |doc|
98
+ base.send(metadata.foreign_key).delete_one(doc.id)
99
+ base.push(metadata.foreign_key, doc.id)
100
+ base.synced[metadata.foreign_key] = false
101
+ end
102
+ end
103
+
104
+ # Creates a new document on the references many relation. This will
105
+ # save the document if the parent has been persisted and will raise an
106
+ # error if validation fails.
107
+ #
108
+ # @example Create and save the new document.
109
+ # person.posts.create!(:text => "Testing")
110
+ #
111
+ # @param [ Hash ] attributes The attributes to create with.
112
+ # @param [ Class ] type The optional type of document to create.
113
+ #
114
+ # @raise [ Errors::Validations ] If validation failed.
115
+ #
116
+ # @return [ Document ] The newly created document.
117
+ #
118
+ # @since 2.0.0.beta.1
119
+ def create!(attributes = nil, type = nil, &block)
120
+ super.tap do |doc|
121
+ base.send(metadata.foreign_key).delete_one(doc.id)
122
+ base.push(metadata.foreign_key, doc.id)
123
+ base.synced[metadata.foreign_key] = false
124
+ end
125
+ end
126
+
127
+ # Delete the document from the relation. This will set the foreign key
128
+ # on the document to nil. If the dependent options on the relation are
129
+ # :delete or :destroy the appropriate removal will occur.
130
+ #
131
+ # @example Delete the document.
132
+ # person.posts.delete(post)
133
+ #
134
+ # @param [ Document ] document The document to remove.
135
+ #
136
+ # @return [ Document ] The matching document.
137
+ #
138
+ # @since 2.1.0
139
+ def delete(document)
140
+ super.tap do |doc|
141
+ if doc && persistable?
142
+ base.pull(metadata.foreign_key, doc.id)
143
+ base.synced[metadata.foreign_key] = false
144
+ end
145
+ end
146
+ end
147
+
148
+ # Removes all associations between the base document and the target
149
+ # documents by deleting the foreign keys and the references, orphaning
150
+ # the target documents in the process.
151
+ #
152
+ # @example Nullify the relation.
153
+ # person.preferences.nullify
154
+ #
155
+ # @since 2.0.0.rc.1
156
+ def nullify
157
+ unless metadata.forced_nil_inverse?
158
+ criteria.pull(metadata.inverse_foreign_key, base.id)
159
+ end
160
+ if persistable?
161
+ base.set(
162
+ metadata.foreign_key,
163
+ base.send(metadata.foreign_key).clear
164
+ )
165
+ end
166
+ target.clear do |doc|
167
+ unbind_one(doc)
168
+ end
169
+ end
170
+ alias :nullify_all :nullify
171
+ alias :clear :nullify
172
+ alias :purge :nullify
173
+
174
+ private
175
+
176
+ # Appends the document to the target array, updating the index on the
177
+ # document at the same time.
178
+ #
179
+ # @example Append the document to the relation.
180
+ # relation.append(document)
181
+ #
182
+ # @param [ Document ] document The document to append to the target.
183
+ #
184
+ # @since 2.0.0.rc.1
185
+ def append(document)
186
+ target.push(document)
187
+ characterize_one(document)
188
+ bind_one(document)
189
+ end
190
+
191
+ # Instantiate the binding associated with this relation.
192
+ #
193
+ # @example Get the binding.
194
+ # relation.binding([ address ])
195
+ #
196
+ # @return [ Binding ] The binding.
197
+ #
198
+ # @since 2.0.0.rc.1
199
+ def binding
200
+ Bindings::Referenced::ManyToMany.new(base, target, metadata)
201
+ end
202
+
203
+ # Returns the criteria object for the target class with its documents set
204
+ # to target.
205
+ #
206
+ # @example Get a criteria for the relation.
207
+ # relation.criteria
208
+ #
209
+ # @return [ Criteria ] A new criteria.
210
+ def criteria
211
+ ManyToMany.criteria(metadata, base.send(metadata.foreign_key))
212
+ end
213
+
214
+ class << self
215
+
216
+ # Return the builder that is responsible for generating the documents
217
+ # that will be used by this relation.
218
+ #
219
+ # @example Get the builder.
220
+ # Referenced::ManyToMany.builder(meta, object)
221
+ #
222
+ # @param [ Document ] base The base document.
223
+ # @param [ Metadata ] meta The metadata of the relation.
224
+ # @param [ Document, Hash ] object A document or attributes to build
225
+ # with.
226
+ #
227
+ # @return [ Builder ] A new builder object.
228
+ #
229
+ # @since 2.0.0.rc.1
230
+ def builder(base, meta, object)
231
+ Builders::Referenced::ManyToMany.new(base, meta, object)
232
+ end
233
+
234
+ # Create the standard criteria for this relation given the supplied
235
+ # metadata and object.
236
+ #
237
+ # @example Get the criteria.
238
+ # Proxy.criteria(meta, object)
239
+ #
240
+ # @param [ Metadata ] metadata The relation metadata.
241
+ # @param [ Object ] object The object for the criteria.
242
+ # @param [ Class ] type The criteria class.
243
+ #
244
+ # @return [ Criteria ] The criteria.
245
+ #
246
+ # @since 2.1.0
247
+ def criteria(metadata, object, type = nil)
248
+ metadata.klass.any_in(:_id => object)
249
+ end
250
+
251
+ # Get the criteria that is used to eager load a relation of this
252
+ # type.
253
+ #
254
+ # @example Get the eager load criteria.
255
+ # Proxy.eager_load(metadata, criteria)
256
+ #
257
+ # @param [ Metadata ] metadata The relation metadata.
258
+ # @param [ Criteria ] criteria The criteria being used.
259
+ #
260
+ # @return [ Criteria ] The criteria to eager load the relation.
261
+ #
262
+ # @since 2.2.0
263
+ def eager_load(metadata, criteria)
264
+ raise Errors::EagerLoad.new(metadata.name)
265
+ end
266
+
267
+ # Returns true if the relation is an embedded one. In this case
268
+ # always false.
269
+ #
270
+ # @example Is this relation embedded?
271
+ # Referenced::ManyToMany.embedded?
272
+ #
273
+ # @return [ false ] Always false.
274
+ #
275
+ # @since 2.0.0.rc.1
276
+ def embedded?
277
+ false
278
+ end
279
+
280
+ # Get the default value for the foreign key.
281
+ #
282
+ # @example Get the default.
283
+ # Referenced::ManyToMany.foreign_key_default
284
+ #
285
+ # @return [ Array ] Always an empty array.
286
+ #
287
+ # @since 2.0.0.rc.1
288
+ def foreign_key_default
289
+ []
290
+ end
291
+
292
+ # Returns the suffix of the foreign key field, either "_id" or "_ids".
293
+ #
294
+ # @example Get the suffix for the foreign key.
295
+ # Referenced::ManyToMany.foreign_key_suffix
296
+ #
297
+ # @return [ String ] "_ids"
298
+ #
299
+ # @since 2.0.0.rc.1
300
+ def foreign_key_suffix
301
+ "_ids"
302
+ end
303
+
304
+ # Returns the macro for this relation. Used mostly as a helper in
305
+ # reflection.
306
+ #
307
+ # @example Get the macro.
308
+ # Referenced::ManyToMany.macro
309
+ #
310
+ # @return [ Symbol ] :references_and_referenced_in_many
311
+ def macro
312
+ :references_and_referenced_in_many
313
+ end
314
+
315
+ # Return the nested builder that is responsible for generating the documents
316
+ # that will be used by this relation.
317
+ #
318
+ # @example Get the nested builder.
319
+ # Referenced::ManyToMany.builder(attributes, options)
320
+ #
321
+ # @param [ Metadata ] metadata The relation metadata.
322
+ # @param [ Hash ] attributes The attributes to build with.
323
+ # @param [ Hash ] options The options for the builder.
324
+ #
325
+ # @option options [ true, false ] :allow_destroy Can documents be
326
+ # deleted?
327
+ # @option options [ Integer ] :limit Max number of documents to
328
+ # create at once.
329
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
330
+ # option then they are ignored.
331
+ # @option options [ true, false ] :update_only Only existing documents
332
+ # can be modified.
333
+ #
334
+ # @return [ NestedBuilder ] A newly instantiated nested builder object.
335
+ #
336
+ # @since 2.0.0.rc.1
337
+ def nested_builder(metadata, attributes, options)
338
+ Builders::NestedAttributes::Many.new(metadata, attributes, options)
339
+ end
340
+
341
+ # Get the path calculator for the supplied document.
342
+ #
343
+ # @example Get the path calculator.
344
+ # Proxy.path(document)
345
+ #
346
+ # @param [ Document ] document The document to calculate on.
347
+ #
348
+ # @return [ Root ] The root atomic path calculator.
349
+ #
350
+ # @since 2.1.0
351
+ def path(document)
352
+ Mongoid::Atomic::Paths::Root.new(document)
353
+ end
354
+
355
+ # Tells the caller if this relation is one that stores the foreign
356
+ # key on its own objects.
357
+ #
358
+ # @example Does this relation store a foreign key?
359
+ # Referenced::Many.stores_foreign_key?
360
+ #
361
+ # @return [ true ] Always true.
362
+ #
363
+ # @since 2.0.0.rc.1
364
+ def stores_foreign_key?
365
+ true
366
+ end
367
+
368
+ # Get the valid options allowed with this relation.
369
+ #
370
+ # @example Get the valid options.
371
+ # Relation.valid_options
372
+ #
373
+ # @return [ Array<Symbol> ] The valid options.
374
+ #
375
+ # @since 2.1.0
376
+ def valid_options
377
+ [ :autosave, :dependent, :foreign_key, :index, :order ]
378
+ end
379
+
380
+ # Get the default validation setting for the relation. Determines if
381
+ # by default a validates associated will occur.
382
+ #
383
+ # @example Get the validation default.
384
+ # Proxy.validation_default
385
+ #
386
+ # @return [ true, false ] The validation default.
387
+ #
388
+ # @since 2.1.9
389
+ def validation_default
390
+ true
391
+ end
392
+ end
393
+ end
394
+ end
395
+ end
396
+ end
@@ -0,0 +1,272 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Referenced #:nodoc:
5
+
6
+ # This class defines the behaviour for all relations that are a
7
+ # one-to-one between documents in different collections.
8
+ class One < Relations::One
9
+
10
+ # Instantiate a new references_one relation. Will set the foreign key
11
+ # and the base on the inverse object.
12
+ #
13
+ # @example Create the new relation.
14
+ # Referenced::One.new(base, target, metadata)
15
+ #
16
+ # @param [ Document ] base The document this relation hangs off of.
17
+ # @param [ Document ] target The target (child) of the relation.
18
+ # @param [ Metadata ] metadata The relation's metadata.
19
+ def initialize(base, target, metadata)
20
+ init(base, target, metadata) do
21
+ raise_mixed if klass.embedded?
22
+ characterize_one(target)
23
+ bind_one
24
+ target.save if persistable?
25
+ end
26
+ end
27
+
28
+ # Removes the association between the base document and the target
29
+ # document by deleting the foreign key and the reference, orphaning
30
+ # the target document in the process.
31
+ #
32
+ # @example Nullify the relation.
33
+ # person.game.nullify
34
+ #
35
+ # @since 2.0.0.rc.1
36
+ def nullify
37
+ unbind_one
38
+ target.save
39
+ end
40
+
41
+ # Substitutes the supplied target document for the existing document
42
+ # in the relation. If the new target is nil, perform the necessary
43
+ # deletion.
44
+ #
45
+ # @example Replace the relation.
46
+ # person.game.substitute(new_game)
47
+ #
48
+ # @param [ Array<Document> ] replacement The replacement target.
49
+ #
50
+ # @return [ One ] The relation.
51
+ #
52
+ # @since 2.0.0.rc.1
53
+ def substitute(replacement)
54
+ unbind_one
55
+ if persistable?
56
+ metadata.destructive? ? send(metadata.dependent) : save
57
+ end
58
+ return nil unless replacement
59
+ One.new(base, replacement, metadata)
60
+ end
61
+
62
+ private
63
+
64
+ # Instantiate the binding associated with this relation.
65
+ #
66
+ # @example Get the binding.
67
+ # relation.binding([ address ])
68
+ #
69
+ # @param [ Document ] new_target The new target of the relation.
70
+ #
71
+ # @return [ Binding ] The binding object.
72
+ def binding
73
+ Bindings::Referenced::One.new(base, target, metadata)
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
+ base.persisted? && !_binding? && !_building?
86
+ end
87
+
88
+ class << self
89
+
90
+ # Return the builder that is responsible for generating the documents
91
+ # that will be used by this relation.
92
+ #
93
+ # @example Get the builder.
94
+ # Referenced::One.builder(meta, object)
95
+ #
96
+ # @param [ Document ] base The base document.
97
+ # @param [ Metadata ] meta The metadata of the relation.
98
+ # @param [ Document, Hash ] object A document or attributes to build
99
+ # with.
100
+ #
101
+ # @return [ Builder ] A new builder object.
102
+ #
103
+ # @since 2.0.0.rc.1
104
+ def builder(base, meta, object)
105
+ Builders::Referenced::One.new(base, meta, object)
106
+ end
107
+
108
+ # Get the standard criteria used for querying this relation.
109
+ #
110
+ # @example Get the criteria.
111
+ # Proxy.criteria(meta, id, Model)
112
+ #
113
+ # @param [ Metadata ] metadata The metadata.
114
+ # @param [ Object ] object The value of the foreign key.
115
+ # @param [ Class ] type The optional type.
116
+ #
117
+ # @return [ Criteria ] The criteria.
118
+ #
119
+ # @since 2.1.0
120
+ def criteria(metadata, object, type = nil)
121
+ metadata.klass.where(metadata.foreign_key => object)
122
+ end
123
+
124
+ # Get the criteria that is used to eager load a relation of this
125
+ # type.
126
+ #
127
+ # @example Get the eager load criteria.
128
+ # Proxy.eager_load(metadata, criteria)
129
+ #
130
+ # @param [ Metadata ] metadata The relation metadata.
131
+ # @param [ Criteria ] criteria The criteria being used.
132
+ #
133
+ # @return [ Criteria ] The criteria to eager load the relation.
134
+ #
135
+ # @since 2.2.0
136
+ def eager_load(metadata, criteria)
137
+ klass, foreign_key = metadata.klass, metadata.foreign_key
138
+ klass.any_in(foreign_key => criteria.load_ids("_id").uniq).each do |doc|
139
+ IdentityMap.set_one(doc, foreign_key => doc.send(foreign_key))
140
+ end
141
+ end
142
+
143
+ # Returns true if the relation is an embedded one. In this case
144
+ # always false.
145
+ #
146
+ # @example Is this relation embedded?
147
+ # Referenced::One.embedded?
148
+ #
149
+ # @return [ false ] Always false.
150
+ #
151
+ # @since 2.0.0.rc.1
152
+ def embedded?
153
+ false
154
+ end
155
+
156
+ # Get the default value for the foreign key.
157
+ #
158
+ # @example Get the default.
159
+ # Referenced::One.foreign_key_default
160
+ #
161
+ # @return [ nil ] Always nil.
162
+ #
163
+ # @since 2.0.0.rc.1
164
+ def foreign_key_default
165
+ nil
166
+ end
167
+
168
+ # Returns the suffix of the foreign key field, either "_id" or "_ids".
169
+ #
170
+ # @example Get the suffix for the foreign key.
171
+ # Referenced::One.foreign_key_suffix
172
+ #
173
+ # @return [ String ] "_id"
174
+ #
175
+ # @since 2.0.0.rc.1
176
+ def foreign_key_suffix
177
+ "_id"
178
+ end
179
+
180
+ # Returns the macro for this relation. Used mostly as a helper in
181
+ # reflection.
182
+ #
183
+ # @example Get the macro.
184
+ # Referenced::One.macro
185
+ #
186
+ # @return [ Symbol ] :references_one.
187
+ def macro
188
+ :references_one
189
+ end
190
+
191
+ # Return the nested builder that is responsible for generating the documents
192
+ # that will be used by this relation.
193
+ #
194
+ # @example Get the nested builder.
195
+ # Referenced::One.builder(attributes, options)
196
+ #
197
+ # @param [ Metadata ] metadata The relation metadata.
198
+ # @param [ Hash ] attributes The attributes to build with.
199
+ # @param [ Hash ] options The options for the builder.
200
+ #
201
+ # @option options [ true, false ] :allow_destroy Can documents be
202
+ # deleted?
203
+ # @option options [ Integer ] :limit Max number of documents to
204
+ # create at once.
205
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
206
+ # option then they are ignored.
207
+ # @option options [ true, false ] :update_only Only existing documents
208
+ # can be modified.
209
+ #
210
+ # @return [ NestedBuilder ] A newly instantiated nested builder object.
211
+ #
212
+ # @since 2.0.0.rc.1
213
+ def nested_builder(metadata, attributes, options)
214
+ Builders::NestedAttributes::One.new(metadata, attributes, options)
215
+ end
216
+
217
+ # Get the path calculator for the supplied document.
218
+ #
219
+ # @example Get the path calculator.
220
+ # Proxy.path(document)
221
+ #
222
+ # @param [ Document ] document The document to calculate on.
223
+ #
224
+ # @return [ Root ] The root atomic path calculator.
225
+ #
226
+ # @since 2.1.0
227
+ def path(document)
228
+ Mongoid::Atomic::Paths::Root.new(document)
229
+ end
230
+
231
+ # Tells the caller if this relation is one that stores the foreign
232
+ # key on its own objects.
233
+ #
234
+ # @example Does this relation store a foreign key?
235
+ # Referenced::One.stores_foreign_key?
236
+ #
237
+ # @return [ false ] Always false.
238
+ #
239
+ # @since 2.0.0.rc.1
240
+ def stores_foreign_key?
241
+ false
242
+ end
243
+
244
+ # Get the valid options allowed with this relation.
245
+ #
246
+ # @example Get the valid options.
247
+ # Relation.valid_options
248
+ #
249
+ # @return [ Array<Symbol> ] The valid options.
250
+ #
251
+ # @since 2.1.0
252
+ def valid_options
253
+ [ :as, :autosave, :dependent, :foreign_key ]
254
+ end
255
+
256
+ # Get the default validation setting for the relation. Determines if
257
+ # by default a validates associated will occur.
258
+ #
259
+ # @example Get the validation default.
260
+ # Proxy.validation_default
261
+ #
262
+ # @return [ true, false ] The validation default.
263
+ #
264
+ # @since 2.1.9
265
+ def validation_default
266
+ true
267
+ end
268
+ end
269
+ end
270
+ end
271
+ end
272
+ end