mongoid-braxton 2.0.2

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 (226) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +50 -0
  3. data/Rakefile +51 -0
  4. data/lib/config/locales/bg.yml +41 -0
  5. data/lib/config/locales/de.yml +41 -0
  6. data/lib/config/locales/en.yml +45 -0
  7. data/lib/config/locales/es.yml +41 -0
  8. data/lib/config/locales/fr.yml +42 -0
  9. data/lib/config/locales/hu.yml +44 -0
  10. data/lib/config/locales/id.yml +46 -0
  11. data/lib/config/locales/it.yml +39 -0
  12. data/lib/config/locales/ja.yml +40 -0
  13. data/lib/config/locales/kr.yml +65 -0
  14. data/lib/config/locales/nl.yml +39 -0
  15. data/lib/config/locales/pl.yml +39 -0
  16. data/lib/config/locales/pt-BR.yml +40 -0
  17. data/lib/config/locales/pt.yml +40 -0
  18. data/lib/config/locales/ro.yml +46 -0
  19. data/lib/config/locales/ru.yml +41 -0
  20. data/lib/config/locales/sv.yml +40 -0
  21. data/lib/config/locales/vi.yml +45 -0
  22. data/lib/config/locales/zh-CN.yml +33 -0
  23. data/lib/mongoid.rb +140 -0
  24. data/lib/mongoid/atomicity.rb +111 -0
  25. data/lib/mongoid/attributes.rb +185 -0
  26. data/lib/mongoid/attributes/processing.rb +145 -0
  27. data/lib/mongoid/callbacks.rb +23 -0
  28. data/lib/mongoid/collection.rb +137 -0
  29. data/lib/mongoid/collections.rb +71 -0
  30. data/lib/mongoid/collections/master.rb +37 -0
  31. data/lib/mongoid/collections/operations.rb +42 -0
  32. data/lib/mongoid/collections/retry.rb +39 -0
  33. data/lib/mongoid/components.rb +45 -0
  34. data/lib/mongoid/config.rb +349 -0
  35. data/lib/mongoid/config/database.rb +167 -0
  36. data/lib/mongoid/config/replset_database.rb +78 -0
  37. data/lib/mongoid/contexts.rb +19 -0
  38. data/lib/mongoid/contexts/enumerable.rb +275 -0
  39. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  40. data/lib/mongoid/contexts/mongo.rb +345 -0
  41. data/lib/mongoid/copyable.rb +46 -0
  42. data/lib/mongoid/criteria.rb +357 -0
  43. data/lib/mongoid/criterion/builder.rb +34 -0
  44. data/lib/mongoid/criterion/complex.rb +34 -0
  45. data/lib/mongoid/criterion/creational.rb +34 -0
  46. data/lib/mongoid/criterion/exclusion.rb +108 -0
  47. data/lib/mongoid/criterion/inclusion.rb +198 -0
  48. data/lib/mongoid/criterion/inspection.rb +22 -0
  49. data/lib/mongoid/criterion/optional.rb +193 -0
  50. data/lib/mongoid/criterion/selector.rb +143 -0
  51. data/lib/mongoid/criterion/unconvertable.rb +20 -0
  52. data/lib/mongoid/cursor.rb +86 -0
  53. data/lib/mongoid/default_scope.rb +36 -0
  54. data/lib/mongoid/dirty.rb +253 -0
  55. data/lib/mongoid/document.rb +284 -0
  56. data/lib/mongoid/errors.rb +13 -0
  57. data/lib/mongoid/errors/document_not_found.rb +29 -0
  58. data/lib/mongoid/errors/invalid_collection.rb +19 -0
  59. data/lib/mongoid/errors/invalid_database.rb +20 -0
  60. data/lib/mongoid/errors/invalid_field.rb +19 -0
  61. data/lib/mongoid/errors/invalid_options.rb +16 -0
  62. data/lib/mongoid/errors/invalid_type.rb +26 -0
  63. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  64. data/lib/mongoid/errors/mongoid_error.rb +27 -0
  65. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
  66. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  67. data/lib/mongoid/errors/unsupported_version.rb +21 -0
  68. data/lib/mongoid/errors/validations.rb +24 -0
  69. data/lib/mongoid/extensions.rb +123 -0
  70. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  71. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  72. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  73. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  74. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  75. data/lib/mongoid/extensions/date/conversions.rb +25 -0
  76. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  77. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  78. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  79. data/lib/mongoid/extensions/hash/conversions.rb +19 -0
  80. data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
  81. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  82. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  83. data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
  84. data/lib/mongoid/extensions/object/checks.rb +32 -0
  85. data/lib/mongoid/extensions/object/conversions.rb +25 -0
  86. data/lib/mongoid/extensions/object/reflections.rb +17 -0
  87. data/lib/mongoid/extensions/object/yoda.rb +27 -0
  88. data/lib/mongoid/extensions/object_id/conversions.rb +96 -0
  89. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  90. data/lib/mongoid/extensions/range/conversions.rb +25 -0
  91. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  92. data/lib/mongoid/extensions/string/conversions.rb +34 -0
  93. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  94. data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
  95. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  96. data/lib/mongoid/extensions/time_conversions.rb +38 -0
  97. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  98. data/lib/mongoid/extras.rb +42 -0
  99. data/lib/mongoid/factory.rb +37 -0
  100. data/lib/mongoid/field.rb +162 -0
  101. data/lib/mongoid/fields.rb +183 -0
  102. data/lib/mongoid/finders.rb +127 -0
  103. data/lib/mongoid/hierarchy.rb +85 -0
  104. data/lib/mongoid/identity.rb +92 -0
  105. data/lib/mongoid/indexes.rb +38 -0
  106. data/lib/mongoid/inspection.rb +54 -0
  107. data/lib/mongoid/javascript.rb +21 -0
  108. data/lib/mongoid/javascript/functions.yml +37 -0
  109. data/lib/mongoid/json.rb +16 -0
  110. data/lib/mongoid/keys.rb +131 -0
  111. data/lib/mongoid/logger.rb +18 -0
  112. data/lib/mongoid/matchers.rb +32 -0
  113. data/lib/mongoid/matchers/all.rb +11 -0
  114. data/lib/mongoid/matchers/default.rb +70 -0
  115. data/lib/mongoid/matchers/exists.rb +13 -0
  116. data/lib/mongoid/matchers/gt.rb +11 -0
  117. data/lib/mongoid/matchers/gte.rb +11 -0
  118. data/lib/mongoid/matchers/in.rb +11 -0
  119. data/lib/mongoid/matchers/lt.rb +11 -0
  120. data/lib/mongoid/matchers/lte.rb +11 -0
  121. data/lib/mongoid/matchers/ne.rb +11 -0
  122. data/lib/mongoid/matchers/nin.rb +11 -0
  123. data/lib/mongoid/matchers/or.rb +30 -0
  124. data/lib/mongoid/matchers/size.rb +11 -0
  125. data/lib/mongoid/matchers/strategies.rb +63 -0
  126. data/lib/mongoid/multi_database.rb +11 -0
  127. data/lib/mongoid/multi_parameter_attributes.rb +82 -0
  128. data/lib/mongoid/named_scope.rb +137 -0
  129. data/lib/mongoid/nested_attributes.rb +51 -0
  130. data/lib/mongoid/observer.rb +67 -0
  131. data/lib/mongoid/paranoia.rb +103 -0
  132. data/lib/mongoid/paths.rb +61 -0
  133. data/lib/mongoid/persistence.rb +240 -0
  134. data/lib/mongoid/persistence/atomic.rb +88 -0
  135. data/lib/mongoid/persistence/atomic/add_to_set.rb +32 -0
  136. data/lib/mongoid/persistence/atomic/inc.rb +28 -0
  137. data/lib/mongoid/persistence/atomic/operation.rb +44 -0
  138. data/lib/mongoid/persistence/atomic/pull_all.rb +33 -0
  139. data/lib/mongoid/persistence/atomic/push.rb +28 -0
  140. data/lib/mongoid/persistence/command.rb +71 -0
  141. data/lib/mongoid/persistence/insert.rb +53 -0
  142. data/lib/mongoid/persistence/insert_embedded.rb +43 -0
  143. data/lib/mongoid/persistence/remove.rb +44 -0
  144. data/lib/mongoid/persistence/remove_all.rb +40 -0
  145. data/lib/mongoid/persistence/remove_embedded.rb +48 -0
  146. data/lib/mongoid/persistence/update.rb +77 -0
  147. data/lib/mongoid/railtie.rb +139 -0
  148. data/lib/mongoid/railties/database.rake +171 -0
  149. data/lib/mongoid/railties/document.rb +12 -0
  150. data/lib/mongoid/relations.rb +107 -0
  151. data/lib/mongoid/relations/accessors.rb +175 -0
  152. data/lib/mongoid/relations/auto_save.rb +34 -0
  153. data/lib/mongoid/relations/binding.rb +26 -0
  154. data/lib/mongoid/relations/bindings.rb +9 -0
  155. data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
  156. data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
  157. data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
  158. data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
  159. data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
  160. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +103 -0
  161. data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
  162. data/lib/mongoid/relations/builder.rb +42 -0
  163. data/lib/mongoid/relations/builders.rb +79 -0
  164. data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
  165. data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
  166. data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
  167. data/lib/mongoid/relations/builders/nested_attributes/many.rb +126 -0
  168. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  169. data/lib/mongoid/relations/builders/referenced/in.rb +29 -0
  170. data/lib/mongoid/relations/builders/referenced/many.rb +47 -0
  171. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
  172. data/lib/mongoid/relations/builders/referenced/one.rb +27 -0
  173. data/lib/mongoid/relations/cascading.rb +55 -0
  174. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  175. data/lib/mongoid/relations/cascading/destroy.rb +19 -0
  176. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  177. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  178. data/lib/mongoid/relations/constraint.rb +42 -0
  179. data/lib/mongoid/relations/cyclic.rb +103 -0
  180. data/lib/mongoid/relations/embedded/atomic.rb +86 -0
  181. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  182. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  183. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  184. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  185. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  186. data/lib/mongoid/relations/embedded/in.rb +173 -0
  187. data/lib/mongoid/relations/embedded/many.rb +499 -0
  188. data/lib/mongoid/relations/embedded/one.rb +170 -0
  189. data/lib/mongoid/relations/macros.rb +310 -0
  190. data/lib/mongoid/relations/many.rb +215 -0
  191. data/lib/mongoid/relations/metadata.rb +539 -0
  192. data/lib/mongoid/relations/nested_builder.rb +68 -0
  193. data/lib/mongoid/relations/one.rb +47 -0
  194. data/lib/mongoid/relations/polymorphic.rb +54 -0
  195. data/lib/mongoid/relations/proxy.rb +143 -0
  196. data/lib/mongoid/relations/referenced/batch.rb +71 -0
  197. data/lib/mongoid/relations/referenced/batch/insert.rb +57 -0
  198. data/lib/mongoid/relations/referenced/in.rb +216 -0
  199. data/lib/mongoid/relations/referenced/many.rb +516 -0
  200. data/lib/mongoid/relations/referenced/many_to_many.rb +396 -0
  201. data/lib/mongoid/relations/referenced/one.rb +222 -0
  202. data/lib/mongoid/relations/reflections.rb +45 -0
  203. data/lib/mongoid/safe.rb +23 -0
  204. data/lib/mongoid/safety.rb +207 -0
  205. data/lib/mongoid/scope.rb +31 -0
  206. data/lib/mongoid/serialization.rb +99 -0
  207. data/lib/mongoid/sharding.rb +51 -0
  208. data/lib/mongoid/state.rb +67 -0
  209. data/lib/mongoid/timestamps.rb +14 -0
  210. data/lib/mongoid/timestamps/created.rb +31 -0
  211. data/lib/mongoid/timestamps/updated.rb +33 -0
  212. data/lib/mongoid/validations.rb +124 -0
  213. data/lib/mongoid/validations/associated.rb +44 -0
  214. data/lib/mongoid/validations/referenced.rb +58 -0
  215. data/lib/mongoid/validations/uniqueness.rb +85 -0
  216. data/lib/mongoid/version.rb +4 -0
  217. data/lib/mongoid/versioning.rb +113 -0
  218. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  219. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +20 -0
  220. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  221. data/lib/rails/generators/mongoid/model/templates/model.rb +19 -0
  222. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  223. data/lib/rails/generators/mongoid/observer/templates/observer.rb +4 -0
  224. data/lib/rails/generators/mongoid_generator.rb +70 -0
  225. data/lib/rails/mongoid.rb +58 -0
  226. metadata +406 -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 < Referenced::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.addresses << address
15
+ #
16
+ # @example Push a document.
17
+ # person.addresses.push(address)
18
+ #
19
+ # @example Concat with other documents.
20
+ # person.addresses.concat([ address_one, address_two ])
21
+ #
22
+ # @param [ Document, Array<Document> ] *args Any number of documents.
23
+ def <<(*args)
24
+ options = default_options(args)
25
+ args.flatten.each do |doc|
26
+ return doc unless doc
27
+ append(doc, options)
28
+ base.add_to_set(metadata.foreign_key, doc.id)
29
+ doc.save if base.persisted? && !options[:binding]
30
+ end
31
+ end
32
+ alias :concat :<<
33
+ alias :push :<<
34
+
35
+ # Builds a new document in the relation and appends it to the target.
36
+ # Takes an optional type if you want to specify a subclass.
37
+ #
38
+ # @example Build a new document on the relation.
39
+ # person.people.build(:name => "Bozo")
40
+ #
41
+ # @param [ Hash ] attributes The attributes to build the document with.
42
+ # @param [ Class ] type Optional class to build the document with.
43
+ #
44
+ # @return [ Document ] The new document.
45
+ def build(attributes = {}, type = nil, &block)
46
+ super.tap do |doc|
47
+ base.send(metadata.foreign_key).push(doc.id)
48
+ end
49
+ end
50
+ alias :new :build
51
+
52
+ # Creates a new document on the references many relation. This will
53
+ # save the document if the parent has been persisted.
54
+ #
55
+ # @example Create and save the new document.
56
+ # person.preferences.create(:text => "Testing")
57
+ #
58
+ # @param [ Hash ] attributes The attributes to create with.
59
+ # @param [ Class ] type The optional type of document to create.
60
+ #
61
+ # @return [ Document ] The newly created document.
62
+ def create(attributes = nil, type = nil, &block)
63
+ build(attributes, type, &block).tap do |doc|
64
+ base.add_to_set(metadata.foreign_key, doc.id)
65
+ doc.save if base.persisted?
66
+ end
67
+ end
68
+
69
+ # Creates a new document on the references many relation. This will
70
+ # save the document if the parent has been persisted and will raise an
71
+ # error if validation fails.
72
+ #
73
+ # @example Create and save the new document.
74
+ # person.preferences.create!(:text => "Testing")
75
+ #
76
+ # @param [ Hash ] attributes The attributes to create with.
77
+ # @param [ Class ] type The optional type of document to create.
78
+ #
79
+ # @raise [ Errors::Validations ] If validation failed.
80
+ #
81
+ # @return [ Document ] The newly created document.
82
+ def create!(attributes = nil, type = nil, &block)
83
+ build(attributes, type, &block).tap do |doc|
84
+ base.add_to_set(metadata.foreign_key, doc.id)
85
+ doc.save! if base.persisted?
86
+ end
87
+ end
88
+
89
+ # Delete a single document from the relation.
90
+ #
91
+ # @example Delete a document.
92
+ # person.preferences.delete(preference)
93
+ #
94
+ # @param [ Document ] document The document to delete.
95
+ #
96
+ # @since 2.0.0.rc.1
97
+ def delete(document, options = {})
98
+ target.delete(document).tap do |doc|
99
+ if doc
100
+ binding.unbind_one(doc, default_options.merge!(options))
101
+ end
102
+ end
103
+ end
104
+
105
+ # Deletes all related documents from the database given the supplied
106
+ # conditions.
107
+ #
108
+ # @example Delete all documents in the relation.
109
+ # person.preferences.delete_all
110
+ #
111
+ # @example Conditonally delete all documents in the relation.
112
+ # person.preferences.delete_all(:conditions => { :title => "Testing" })
113
+ #
114
+ # @param [ Hash ] conditions Optional conditions to delete with.
115
+ #
116
+ # @return [ Integer ] The number of documents deleted.
117
+ def delete_all(conditions = nil)
118
+ remove_all(conditions, :delete_all)
119
+ end
120
+
121
+ # Destroys all related documents from the database given the supplied
122
+ # conditions.
123
+ #
124
+ # @example Destroy all documents in the relation.
125
+ # person.preferences.destroy_all
126
+ #
127
+ # @example Conditonally destroy all documents in the relation.
128
+ # person.preferences.destroy_all(:conditions => { :title => "Testing" })
129
+ #
130
+ # @param [ Hash ] conditions Optional conditions to destroy with.
131
+ #
132
+ # @return [ Integer ] The number of documents destroyd.
133
+ def destroy_all(conditions = nil)
134
+ remove_all(conditions, :destroy_all)
135
+ end
136
+
137
+ # Instantiate a new references_many relation. Will set the foreign key
138
+ # and the base on the inverse object.
139
+ #
140
+ # @example Create the new relation.
141
+ # Referenced::ManyToMany.new(base, target, metadata)
142
+ #
143
+ # @param [ Document ] base The document this relation hangs off of.
144
+ # @param [ Array<Document> ] target The target of the relation.
145
+ # @param [ Metadata ] metadata The relation's metadata.
146
+ def initialize(base, target, metadata)
147
+ init(base, target, metadata) do
148
+ unless base.frozen?
149
+ base.send(metadata.foreign_key_setter, target.map(&:id))
150
+ end
151
+ end
152
+ end
153
+
154
+ # Removes all associations between the base document and the target
155
+ # documents by deleting the foreign keys and the references, orphaning
156
+ # the target documents in the process.
157
+ #
158
+ # @example Nullify the relation.
159
+ # person.preferences.nullify
160
+ #
161
+ # @since 2.0.0.rc.1
162
+ def nullify
163
+ load! and target.each do |doc|
164
+ base.send(metadata.foreign_key).delete(doc.id)
165
+ dereference(doc)
166
+ end
167
+ target.clear
168
+ end
169
+ alias :nullify_all :nullify
170
+
171
+ # Substitutes the supplied target documents for the existing documents
172
+ # in the relation. If the new target is nil, perform the necessary
173
+ # deletion.
174
+ #
175
+ # @example Replace the relation.
176
+ # person.posts.substitute(new_name)
177
+ #
178
+ # @param [ Array<Document> ] target The replacement target.
179
+ # @param [ Hash ] options The options to bind with.
180
+ #
181
+ # @option options [ true, false ] :binding Are we in build mode?
182
+ # @option options [ true, false ] :continue Continue binding the
183
+ # inverse?
184
+ #
185
+ # @return [ Many ] The relation.
186
+ #
187
+ # @since 2.0.0.rc.1
188
+ def substitute(new_target, options = {})
189
+ tap do |relation|
190
+ if new_target
191
+ binding.unbind(options)
192
+ relation.target = new_target.to_a
193
+ base.send(metadata.foreign_key_setter, new_target.map(&:id))
194
+ bind(options)
195
+ else
196
+ relation.target = unbind(options)
197
+ end
198
+ base.save if base.persisted? && !options[:binding]
199
+ end
200
+ end
201
+
202
+ # Unbinds the base object to the inverse of the relation. This occurs
203
+ # when setting a side of the relation to nil.
204
+ #
205
+ # Will delete the object if necessary.
206
+ #
207
+ # @example Unbind the target.
208
+ # person.posts.unbind
209
+ #
210
+ # @param [ Hash ] options The options to bind with.
211
+ #
212
+ # @option options [ true, false ] :binding Are we in build mode?
213
+ # @option options [ true, false ] :continue Continue binding the
214
+ # inverse?
215
+ #
216
+ # @since 2.0.0.rc.1
217
+ def unbind(options = {})
218
+ target.each(&:delete) if base.persisted?
219
+ binding.unbind(options)
220
+ []
221
+ end
222
+
223
+ private
224
+
225
+ # Instantiate the binding associated with this relation.
226
+ #
227
+ # @example Get the binding.
228
+ # relation.binding([ address ])
229
+ #
230
+ # @param [ Array<Document> ] new_target The new documents to bind with.
231
+ #
232
+ # @return [ Binding ] The binding.
233
+ #
234
+ # @since 2.0.0.rc.1
235
+ def binding(new_target = nil)
236
+ Bindings::Referenced::ManyToMany.new(base, new_target || target, metadata)
237
+ end
238
+
239
+ # Returns the criteria object for the target class with its documents set
240
+ # to target.
241
+ #
242
+ # @example Get a criteria for the relation.
243
+ # relation.criteria
244
+ #
245
+ # @return [ Criteria ] A new criteria.
246
+ def criteria
247
+ if metadata.inverse
248
+ metadata.klass.any_in(metadata.inverse_foreign_key => [ base.id ])
249
+ else
250
+ metadata.klass.where(:_id => { "$in" => base.send(metadata.foreign_key) })
251
+ end
252
+ end
253
+
254
+ # Dereferences the supplied document from the base of the relation.
255
+ #
256
+ # @example Dereference the document.
257
+ # person.preferences.dereference(preference)
258
+ #
259
+ # @param [ Document ] document The document to dereference.
260
+ def dereference(document)
261
+ document.send(metadata.inverse_foreign_key).delete(base.id)
262
+ document.send(metadata.inverse(document)).target.delete(base)
263
+ document.save
264
+ end
265
+
266
+ # Remove all documents from the relation, either with a delete or a
267
+ # destroy depending on what this was called through.
268
+ #
269
+ # @example Destroy documents from the relation.
270
+ # relation.remove_all(:conditions => { :num => 1 }, true)
271
+ #
272
+ # @param [ Hash ] conditions Conditions to filter by.
273
+ # @param [ true, false ] destroy If true then destroy, else delete.
274
+ #
275
+ # @return [ Integer ] The number of documents removed.
276
+ def remove_all(conditions = {}, method = :destroy)
277
+ cond = conditions || {}
278
+ target.delete_if do |doc|
279
+ doc.matches?(cond[:conditions] || {})
280
+ end
281
+ ids = criteria.merge(cond).only(:_id).map(&:_id)
282
+ criteria.merge(cond).send(method).tap do
283
+ base.pull_all(metadata.foreign_key, ids)
284
+ end
285
+ end
286
+
287
+ class << self
288
+
289
+ # Return the builder that is responsible for generating the documents
290
+ # that will be used by this relation.
291
+ #
292
+ # @example Get the builder.
293
+ # Referenced::ManyToMany.builder(meta, object)
294
+ #
295
+ # @param [ Metadata ] meta The metadata of the relation.
296
+ # @param [ Document, Hash ] object A document or attributes to build
297
+ # with.
298
+ #
299
+ # @return [ Builder ] A new builder object.
300
+ #
301
+ # @since 2.0.0.rc.1
302
+ def builder(meta, object)
303
+ Builders::Referenced::ManyToMany.new(meta, object)
304
+ end
305
+
306
+ # Returns true if the relation is an embedded one. In this case
307
+ # always false.
308
+ #
309
+ # @example Is this relation embedded?
310
+ # Referenced::ManyToMany.embedded?
311
+ #
312
+ # @return [ false ] Always false.
313
+ #
314
+ # @since 2.0.0.rc.1
315
+ def embedded?
316
+ false
317
+ end
318
+
319
+ # Get the default value for the foreign key.
320
+ #
321
+ # @example Get the default.
322
+ # Referenced::ManyToMany.foreign_key_default
323
+ #
324
+ # @return [ Array ] Always an empty array.
325
+ #
326
+ # @since 2.0.0.rc.1
327
+ def foreign_key_default
328
+ []
329
+ end
330
+
331
+ # Returns the suffix of the foreign key field, either "_id" or "_ids".
332
+ #
333
+ # @example Get the suffix for the foreign key.
334
+ # Referenced::ManyToMany.foreign_key_suffix
335
+ #
336
+ # @return [ String ] "_ids"
337
+ #
338
+ # @since 2.0.0.rc.1
339
+ def foreign_key_suffix
340
+ "_ids"
341
+ end
342
+
343
+ # Returns the macro for this relation. Used mostly as a helper in
344
+ # reflection.
345
+ #
346
+ # @example Get the macro.
347
+ # Referenced::ManyToMany.macro
348
+ #
349
+ # @return [ Symbol ] :references_and_referenced_in_many
350
+ def macro
351
+ :references_and_referenced_in_many
352
+ end
353
+
354
+ # Return the nested builder that is responsible for generating the documents
355
+ # that will be used by this relation.
356
+ #
357
+ # @example Get the nested builder.
358
+ # Referenced::ManyToMany.builder(attributes, options)
359
+ #
360
+ # @param [ Metadata ] metadata The relation metadata.
361
+ # @param [ Hash ] attributes The attributes to build with.
362
+ # @param [ Hash ] options The options for the builder.
363
+ #
364
+ # @option options [ true, false ] :allow_destroy Can documents be
365
+ # deleted?
366
+ # @option options [ Integer ] :limit Max number of documents to
367
+ # create at once.
368
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
369
+ # option then they are ignored.
370
+ # @option options [ true, false ] :update_only Only existing documents
371
+ # can be modified.
372
+ #
373
+ # @return [ NestedBuilder ] A newly instantiated nested builder object.
374
+ #
375
+ # @since 2.0.0.rc.1
376
+ def nested_builder(metadata, attributes, options)
377
+ Builders::NestedAttributes::Many.new(metadata, attributes, options)
378
+ end
379
+
380
+ # Tells the caller if this relation is one that stores the foreign
381
+ # key on its own objects.
382
+ #
383
+ # @example Does this relation store a foreign key?
384
+ # Referenced::Many.stores_foreign_key?
385
+ #
386
+ # @return [ true ] Always true.
387
+ #
388
+ # @since 2.0.0.rc.1
389
+ def stores_foreign_key?
390
+ true
391
+ end
392
+ end
393
+ end
394
+ end
395
+ end
396
+ end
@@ -0,0 +1,222 @@
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
+ # Binds the base object to the inverse of the relation. This is so we
11
+ # are referenced to the actual objects themselves and dont hit the
12
+ # database twice when setting the relations up.
13
+ #
14
+ # This is called after first creating the relation, or if a new object
15
+ # is set on the relation.
16
+ #
17
+ # @example Bind the relation.
18
+ # person.game.bind(:continue => false)
19
+ #
20
+ # @param [ Hash ] options The options to bind with.
21
+ #
22
+ # @option options [ true, false ] :binding Are we in build mode?
23
+ # @option options [ true, false ] :continue Continue binding the
24
+ # inverse?
25
+ #
26
+ # @since 2.0.0.rc.1
27
+ def bind(options = {})
28
+ binding.bind(options)
29
+ target.save if base.persisted? && !options[:binding]
30
+ end
31
+
32
+ # Instantiate a new references_one relation. Will set the foreign key
33
+ # and the base on the inverse object.
34
+ #
35
+ # @example Create the new relation.
36
+ # Referenced::One.new(base, target, metadata)
37
+ #
38
+ # @param [ Document ] base The document this relation hangs off of.
39
+ # @param [ Document ] target The target (child) of the relation.
40
+ # @param [ Metadata ] metadata The relation's metadata.
41
+ def initialize(base, target, metadata)
42
+ init(base, target, metadata) do
43
+ characterize_one(target)
44
+ end
45
+ end
46
+
47
+ # Will load the target into an array if the target had not already been
48
+ # loaded.
49
+ #
50
+ # @example Load the relation into memory.
51
+ # relation.load!
52
+ #
53
+ # @return [ One ] The relation.
54
+ #
55
+ # @since 2.0.0.rc.5
56
+ def load!(options = {})
57
+ raise_mixed if klass.embedded?
58
+ super(options)
59
+ end
60
+
61
+ # Removes the association between the base document and the target
62
+ # document by deleting the foreign key and the reference, orphaning
63
+ # the target document in the process.
64
+ #
65
+ # @example Nullify the relation.
66
+ # person.game.nullify
67
+ #
68
+ # @since 2.0.0.rc.1
69
+ def nullify
70
+ target.send(metadata.foreign_key_setter, nil)
71
+ target.send(:remove_instance_variable, "@#{metadata.inverse(target)}")
72
+ base.send(:remove_instance_variable, "@#{metadata.name}")
73
+ target.save
74
+ end
75
+
76
+ # Unbinds the base object to the inverse of the relation. This occurs
77
+ # when setting a side of the relation to nil.
78
+ #
79
+ # Will delete the object if necessary.
80
+ #
81
+ # @example Unbind the relation.
82
+ # person.game.unbind(name, :continue => true)
83
+ #
84
+ # @param [ Document ] old_target The previous target of the relation.
85
+ # @param [ Hash ] options The options to bind with.
86
+ #
87
+ # @option options [ true, false ] :binding Are we in build mode?
88
+ # @option options [ true, false ] :continue Continue binding the
89
+ # inverse?
90
+ #
91
+ # @since 2.0.0.rc.1
92
+ def unbind(old_target, options = {})
93
+ binding(old_target).unbind(options)
94
+ if base.persisted? && !old_target.destroyed? && !options[:binding]
95
+ old_target.delete
96
+ end
97
+ end
98
+
99
+ private
100
+
101
+ # Instantiate the binding associated with this relation.
102
+ #
103
+ # @example Get the binding.
104
+ # relation.binding([ address ])
105
+ #
106
+ # @param [ Document ] new_target The new target of the relation.
107
+ #
108
+ # @return [ Binding ] The binding object.
109
+ def binding(new_target = nil)
110
+ Bindings::Referenced::One.new(base, new_target || target, metadata)
111
+ end
112
+
113
+ class << self
114
+
115
+ # Return the builder that is responsible for generating the documents
116
+ # that will be used by this relation.
117
+ #
118
+ # @example Get the builder.
119
+ # Referenced::One.builder(meta, object)
120
+ #
121
+ # @param [ Metadata ] meta The metadata of the relation.
122
+ # @param [ Document, Hash ] object A document or attributes to build
123
+ # with.
124
+ #
125
+ # @return [ Builder ] A new builder object.
126
+ #
127
+ # @since 2.0.0.rc.1
128
+ def builder(meta, object)
129
+ Builders::Referenced::One.new(meta, object)
130
+ end
131
+
132
+ # Returns true if the relation is an embedded one. In this case
133
+ # always false.
134
+ #
135
+ # @example Is this relation embedded?
136
+ # Referenced::One.embedded?
137
+ #
138
+ # @return [ false ] Always false.
139
+ #
140
+ # @since 2.0.0.rc.1
141
+ def embedded?
142
+ false
143
+ end
144
+
145
+ # Get the default value for the foreign key.
146
+ #
147
+ # @example Get the default.
148
+ # Referenced::One.foreign_key_default
149
+ #
150
+ # @return [ nil ] Always nil.
151
+ #
152
+ # @since 2.0.0.rc.1
153
+ def foreign_key_default
154
+ nil
155
+ end
156
+
157
+ # Returns the suffix of the foreign key field, either "_id" or "_ids".
158
+ #
159
+ # @example Get the suffix for the foreign key.
160
+ # Referenced::One.foreign_key_suffix
161
+ #
162
+ # @return [ String ] "_id"
163
+ #
164
+ # @since 2.0.0.rc.1
165
+ def foreign_key_suffix
166
+ "_id"
167
+ end
168
+
169
+ # Returns the macro for this relation. Used mostly as a helper in
170
+ # reflection.
171
+ #
172
+ # @example Get the macro.
173
+ # Referenced::One.macro
174
+ #
175
+ # @return [ Symbol ] :references_one.
176
+ def macro
177
+ :references_one
178
+ end
179
+
180
+ # Return the nested builder that is responsible for generating the documents
181
+ # that will be used by this relation.
182
+ #
183
+ # @example Get the nested builder.
184
+ # Referenced::One.builder(attributes, options)
185
+ #
186
+ # @param [ Metadata ] metadata The relation metadata.
187
+ # @param [ Hash ] attributes The attributes to build with.
188
+ # @param [ Hash ] options The options for the builder.
189
+ #
190
+ # @option options [ true, false ] :allow_destroy Can documents be
191
+ # deleted?
192
+ # @option options [ Integer ] :limit Max number of documents to
193
+ # create at once.
194
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
195
+ # option then they are ignored.
196
+ # @option options [ true, false ] :update_only Only existing documents
197
+ # can be modified.
198
+ #
199
+ # @return [ NestedBuilder ] A newly instantiated nested builder object.
200
+ #
201
+ # @since 2.0.0.rc.1
202
+ def nested_builder(metadata, attributes, options)
203
+ Builders::NestedAttributes::One.new(metadata, attributes, options)
204
+ end
205
+
206
+ # Tells the caller if this relation is one that stores the foreign
207
+ # key on its own objects.
208
+ #
209
+ # @example Does this relation store a foreign key?
210
+ # Referenced::One.stores_foreign_key?
211
+ #
212
+ # @return [ false ] Always false.
213
+ #
214
+ # @since 2.0.0.rc.1
215
+ def stores_foreign_key?
216
+ false
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end