stonegao-mongoid 2.0.0.rc.6

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 (199) 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 +44 -0
  5. data/lib/config/locales/de.yml +44 -0
  6. data/lib/config/locales/en.yml +45 -0
  7. data/lib/config/locales/es.yml +44 -0
  8. data/lib/config/locales/fr.yml +45 -0
  9. data/lib/config/locales/hu.yml +47 -0
  10. data/lib/config/locales/it.yml +42 -0
  11. data/lib/config/locales/kr.yml +68 -0
  12. data/lib/config/locales/nl.yml +42 -0
  13. data/lib/config/locales/pl.yml +42 -0
  14. data/lib/config/locales/pt-br.yml +43 -0
  15. data/lib/config/locales/pt.yml +43 -0
  16. data/lib/config/locales/ro.yml +49 -0
  17. data/lib/config/locales/sv.yml +43 -0
  18. data/lib/config/locales/zh-CN.yml +34 -0
  19. data/lib/mongoid/atomicity.rb +111 -0
  20. data/lib/mongoid/attributes.rb +251 -0
  21. data/lib/mongoid/callbacks.rb +13 -0
  22. data/lib/mongoid/collection.rb +137 -0
  23. data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
  24. data/lib/mongoid/collections/master.rb +29 -0
  25. data/lib/mongoid/collections/operations.rb +42 -0
  26. data/lib/mongoid/collections/slaves.rb +45 -0
  27. data/lib/mongoid/collections.rb +70 -0
  28. data/lib/mongoid/components.rb +45 -0
  29. data/lib/mongoid/config/database.rb +167 -0
  30. data/lib/mongoid/config/replset_database.rb +48 -0
  31. data/lib/mongoid/config.rb +343 -0
  32. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  33. data/lib/mongoid/contexts/enumerable.rb +226 -0
  34. data/lib/mongoid/contexts/ids.rb +25 -0
  35. data/lib/mongoid/contexts/mongo.rb +345 -0
  36. data/lib/mongoid/contexts/paging.rb +50 -0
  37. data/lib/mongoid/contexts.rb +21 -0
  38. data/lib/mongoid/copyable.rb +44 -0
  39. data/lib/mongoid/criteria.rb +325 -0
  40. data/lib/mongoid/criterion/complex.rb +34 -0
  41. data/lib/mongoid/criterion/creational.rb +34 -0
  42. data/lib/mongoid/criterion/exclusion.rb +67 -0
  43. data/lib/mongoid/criterion/inclusion.rb +134 -0
  44. data/lib/mongoid/criterion/inspection.rb +20 -0
  45. data/lib/mongoid/criterion/optional.rb +213 -0
  46. data/lib/mongoid/criterion/selector.rb +74 -0
  47. data/lib/mongoid/cursor.rb +81 -0
  48. data/lib/mongoid/default_scope.rb +28 -0
  49. data/lib/mongoid/dirty.rb +251 -0
  50. data/lib/mongoid/document.rb +256 -0
  51. data/lib/mongoid/errors/document_not_found.rb +29 -0
  52. data/lib/mongoid/errors/invalid_collection.rb +19 -0
  53. data/lib/mongoid/errors/invalid_database.rb +20 -0
  54. data/lib/mongoid/errors/invalid_field.rb +19 -0
  55. data/lib/mongoid/errors/invalid_options.rb +16 -0
  56. data/lib/mongoid/errors/invalid_type.rb +26 -0
  57. data/lib/mongoid/errors/mongoid_error.rb +27 -0
  58. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
  59. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  60. data/lib/mongoid/errors/unsupported_version.rb +21 -0
  61. data/lib/mongoid/errors/validations.rb +24 -0
  62. data/lib/mongoid/errors.rb +12 -0
  63. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  64. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  65. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  66. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  67. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  68. data/lib/mongoid/extensions/date/conversions.rb +25 -0
  69. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  70. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  71. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  72. data/lib/mongoid/extensions/hash/conversions.rb +19 -0
  73. data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
  74. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  75. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  76. data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
  77. data/lib/mongoid/extensions/object/conversions.rb +25 -0
  78. data/lib/mongoid/extensions/object/reflections.rb +17 -0
  79. data/lib/mongoid/extensions/object/yoda.rb +27 -0
  80. data/lib/mongoid/extensions/object_id/conversions.rb +57 -0
  81. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  82. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  83. data/lib/mongoid/extensions/string/conversions.rb +34 -0
  84. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  85. data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
  86. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  87. data/lib/mongoid/extensions/time_conversions.rb +38 -0
  88. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  89. data/lib/mongoid/extensions.rb +116 -0
  90. data/lib/mongoid/extras.rb +61 -0
  91. data/lib/mongoid/factory.rb +20 -0
  92. data/lib/mongoid/field.rb +95 -0
  93. data/lib/mongoid/fields.rb +138 -0
  94. data/lib/mongoid/finders.rb +173 -0
  95. data/lib/mongoid/hierarchy.rb +85 -0
  96. data/lib/mongoid/identity.rb +89 -0
  97. data/lib/mongoid/indexes.rb +38 -0
  98. data/lib/mongoid/inspection.rb +58 -0
  99. data/lib/mongoid/javascript/functions.yml +37 -0
  100. data/lib/mongoid/javascript.rb +21 -0
  101. data/lib/mongoid/json.rb +16 -0
  102. data/lib/mongoid/keys.rb +77 -0
  103. data/lib/mongoid/logger.rb +18 -0
  104. data/lib/mongoid/matchers/all.rb +11 -0
  105. data/lib/mongoid/matchers/default.rb +27 -0
  106. data/lib/mongoid/matchers/exists.rb +13 -0
  107. data/lib/mongoid/matchers/gt.rb +11 -0
  108. data/lib/mongoid/matchers/gte.rb +11 -0
  109. data/lib/mongoid/matchers/in.rb +11 -0
  110. data/lib/mongoid/matchers/lt.rb +11 -0
  111. data/lib/mongoid/matchers/lte.rb +11 -0
  112. data/lib/mongoid/matchers/ne.rb +11 -0
  113. data/lib/mongoid/matchers/nin.rb +11 -0
  114. data/lib/mongoid/matchers/size.rb +11 -0
  115. data/lib/mongoid/matchers.rb +55 -0
  116. data/lib/mongoid/modifiers/command.rb +18 -0
  117. data/lib/mongoid/modifiers/inc.rb +24 -0
  118. data/lib/mongoid/modifiers.rb +24 -0
  119. data/lib/mongoid/multi_database.rb +11 -0
  120. data/lib/mongoid/multi_parameter_attributes.rb +80 -0
  121. data/lib/mongoid/named_scope.rb +36 -0
  122. data/lib/mongoid/nested_attributes.rb +43 -0
  123. data/lib/mongoid/paranoia.rb +103 -0
  124. data/lib/mongoid/paths.rb +61 -0
  125. data/lib/mongoid/persistence/command.rb +59 -0
  126. data/lib/mongoid/persistence/insert.rb +53 -0
  127. data/lib/mongoid/persistence/insert_embedded.rb +42 -0
  128. data/lib/mongoid/persistence/remove.rb +44 -0
  129. data/lib/mongoid/persistence/remove_all.rb +40 -0
  130. data/lib/mongoid/persistence/remove_embedded.rb +48 -0
  131. data/lib/mongoid/persistence/update.rb +76 -0
  132. data/lib/mongoid/persistence.rb +237 -0
  133. data/lib/mongoid/railtie.rb +129 -0
  134. data/lib/mongoid/railties/database.rake +171 -0
  135. data/lib/mongoid/railties/document.rb +12 -0
  136. data/lib/mongoid/relations/accessors.rb +157 -0
  137. data/lib/mongoid/relations/auto_save.rb +34 -0
  138. data/lib/mongoid/relations/binding.rb +26 -0
  139. data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
  140. data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
  141. data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
  142. data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
  143. data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
  144. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +99 -0
  145. data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
  146. data/lib/mongoid/relations/bindings.rb +9 -0
  147. data/lib/mongoid/relations/builder.rb +42 -0
  148. data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
  149. data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
  150. data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
  151. data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
  152. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  153. data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
  154. data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
  155. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
  156. data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
  157. data/lib/mongoid/relations/builders.rb +79 -0
  158. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  159. data/lib/mongoid/relations/cascading/destroy.rb +19 -0
  160. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  161. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  162. data/lib/mongoid/relations/cascading.rb +55 -0
  163. data/lib/mongoid/relations/constraint.rb +45 -0
  164. data/lib/mongoid/relations/cyclic.rb +97 -0
  165. data/lib/mongoid/relations/embedded/in.rb +173 -0
  166. data/lib/mongoid/relations/embedded/many.rb +483 -0
  167. data/lib/mongoid/relations/embedded/one.rb +170 -0
  168. data/lib/mongoid/relations/macros.rb +306 -0
  169. data/lib/mongoid/relations/many.rb +171 -0
  170. data/lib/mongoid/relations/metadata.rb +533 -0
  171. data/lib/mongoid/relations/nested_builder.rb +68 -0
  172. data/lib/mongoid/relations/one.rb +47 -0
  173. data/lib/mongoid/relations/polymorphic.rb +54 -0
  174. data/lib/mongoid/relations/proxy.rb +128 -0
  175. data/lib/mongoid/relations/referenced/in.rb +216 -0
  176. data/lib/mongoid/relations/referenced/many.rb +443 -0
  177. data/lib/mongoid/relations/referenced/many_to_many.rb +344 -0
  178. data/lib/mongoid/relations/referenced/one.rb +206 -0
  179. data/lib/mongoid/relations/reflections.rb +45 -0
  180. data/lib/mongoid/relations.rb +105 -0
  181. data/lib/mongoid/safe.rb +23 -0
  182. data/lib/mongoid/safety.rb +207 -0
  183. data/lib/mongoid/scope.rb +31 -0
  184. data/lib/mongoid/serialization.rb +99 -0
  185. data/lib/mongoid/state.rb +66 -0
  186. data/lib/mongoid/timestamps.rb +38 -0
  187. data/lib/mongoid/validations/associated.rb +42 -0
  188. data/lib/mongoid/validations/uniqueness.rb +85 -0
  189. data/lib/mongoid/validations.rb +117 -0
  190. data/lib/mongoid/version.rb +4 -0
  191. data/lib/mongoid/versioning.rb +51 -0
  192. data/lib/mongoid.rb +139 -0
  193. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  194. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +23 -0
  195. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  196. data/lib/rails/generators/mongoid/model/templates/model.rb +17 -0
  197. data/lib/rails/generators/mongoid_generator.rb +61 -0
  198. data/lib/rails/mongoid.rb +57 -0
  199. metadata +380 -0
@@ -0,0 +1,344 @@
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
+ # Creates a new document on the references many relation. This will
11
+ # save the document if the parent has been persisted.
12
+ #
13
+ # @example Create and save the new document.
14
+ # person.preferences.create(:text => "Testing")
15
+ #
16
+ # @param [ Hash ] attributes The attributes to create with.
17
+ # @param [ Class ] type The optional type of document to create.
18
+ #
19
+ # @return [ Document ] The newly created document.
20
+ def create(attributes = nil, type = nil)
21
+ build(attributes, type).tap do |doc|
22
+ doc.save and base.save if base.persisted?
23
+ end
24
+ end
25
+
26
+ # Creates a new document on the references many relation. This will
27
+ # save the document if the parent has been persisted and will raise an
28
+ # error if validation fails.
29
+ #
30
+ # @example Create and save the new document.
31
+ # person.preferences.create!(:text => "Testing")
32
+ #
33
+ # @param [ Hash ] attributes The attributes to create with.
34
+ # @param [ Class ] type The optional type of document to create.
35
+ #
36
+ # @raise [ Errors::Validations ] If validation failed.
37
+ #
38
+ # @return [ Document ] The newly created document.
39
+ def create!(attributes = nil, type = nil)
40
+ build(attributes, type).tap do |doc|
41
+ doc.save! and base.save! if base.persisted?
42
+ end
43
+ end
44
+
45
+ # Delete a single document from the relation.
46
+ #
47
+ # @example Delete a document.
48
+ # person.preferences.delete(preference)
49
+ #
50
+ # @param [ Document ] document The document to delete.
51
+ #
52
+ # @since 2.0.0.rc.1
53
+ def delete(document, options = {})
54
+ target.delete(document).tap do |doc|
55
+ binding.unbind_one(doc, default_options.merge!(options)) if doc
56
+ end
57
+ end
58
+
59
+ # Deletes all related documents from the database given the supplied
60
+ # conditions.
61
+ #
62
+ # @example Delete all documents in the relation.
63
+ # person.preferences.delete_all
64
+ #
65
+ # @example Conditonally delete all documents in the relation.
66
+ # person.preferences.delete_all(:conditions => { :title => "Testing" })
67
+ #
68
+ # @param [ Hash ] conditions Optional conditions to delete with.
69
+ #
70
+ # @return [ Integer ] The number of documents deleted.
71
+ def delete_all(conditions = nil)
72
+ selector = (conditions || {})[:conditions] || {}
73
+ target.delete_if { |doc| doc.matches?(selector) }
74
+ scoping = { :_id => { "$in" => base.send(metadata.foreign_key) } }
75
+ metadata.klass.delete_all(:conditions => selector.merge(scoping))
76
+ end
77
+
78
+ # Destroys all related documents from the database given the supplied
79
+ # conditions.
80
+ #
81
+ # @example Destroy all documents in the relation.
82
+ # person.preferences.destroy_all
83
+ #
84
+ # @example Conditonally destroy all documents in the relation.
85
+ # person.preferences.destroy_all(:conditions => { :title => "Testing" })
86
+ #
87
+ # @param [ Hash ] conditions Optional conditions to destroy with.
88
+ #
89
+ # @return [ Integer ] The number of documents destroyd.
90
+ def destroy_all(conditions = nil)
91
+ selector = (conditions || {})[:conditions] || {}
92
+ target.delete_if { |doc| doc.matches?(selector) }
93
+ scoping = { :_id => { "$in" => base.send(metadata.foreign_key) } }
94
+ metadata.klass.destroy_all(:conditions => selector.merge(scoping))
95
+ end
96
+
97
+ # Find the matchind document on the association, either based on id or
98
+ # conditions.
99
+ #
100
+ # @example Find by an id.
101
+ # person.preferences.find(BSON::ObjectId.new)
102
+ #
103
+ # @example Find by multiple ids.
104
+ # person.preferences.find([ BSON::ObjectId.new, BSON::ObjectId.new ])
105
+ #
106
+ # @example Conditionally find all matching documents.
107
+ # person.preferences.find(:all, :conditions => { :title => "Sir" })
108
+ #
109
+ # @example Conditionally find the first document.
110
+ # person.preferences.find(:first, :conditions => { :title => "Sir" })
111
+ #
112
+ # @example Conditionally find the last document.
113
+ # person.preferences.find(:last, :conditions => { :title => "Sir" })
114
+ #
115
+ # @param [ Symbol, BSON::ObjectId, Array<BSON::ObjectId> ] arg The
116
+ # argument to search with.
117
+ # @param [ Hash ] options The options to search with.
118
+ #
119
+ # @return [ Document, Criteria ] The matching document(s).
120
+ def find(arg, options = {})
121
+ klass = metadata.klass
122
+ return klass.criteria.id_criteria(arg) unless arg.is_a?(Symbol)
123
+ selector = (options[:conditions] || {}).merge(
124
+ "_id" => { "$in" => base.send(metadata.foreign_key) }
125
+ )
126
+ klass.find(arg, :conditions => selector)
127
+ end
128
+
129
+ # Removes all associations between the base document and the target
130
+ # documents by deleting the foreign keys and the references, orphaning
131
+ # the target documents in the process.
132
+ #
133
+ # @example Nullify the relation.
134
+ # person.preferences.nullify
135
+ #
136
+ # @since 2.0.0.rc.1
137
+ def nullify
138
+ load! and target.each do |doc|
139
+ base.send(metadata.foreign_key).delete(doc.id)
140
+ dereference(doc)
141
+ end
142
+ target.clear
143
+ end
144
+ alias :nullify_all :nullify
145
+
146
+ # Substitutes the supplied target documents for the existing documents
147
+ # in the relation. If the new target is nil, perform the necessary
148
+ # deletion.
149
+ #
150
+ # @example Replace the relation.
151
+ # person.posts.substitute(new_name)
152
+ #
153
+ # @param [ Array<Document> ] target The replacement target.
154
+ # @param [ Hash ] options The options to bind with.
155
+ #
156
+ # @option options [ true, false ] :binding Are we in build mode?
157
+ # @option options [ true, false ] :continue Continue binding the
158
+ # inverse?
159
+ #
160
+ # @return [ Many ] The relation.
161
+ #
162
+ # @since 2.0.0.rc.1
163
+ def substitute(new_target, options = {})
164
+ tap do |relation|
165
+ if new_target
166
+ binding.unbind(options)
167
+ relation.target = new_target.to_a
168
+ bind(options)
169
+ else
170
+ relation.target = unbind(options)
171
+ end
172
+ end
173
+ end
174
+
175
+ # Unbinds the base object to the inverse of the relation. This occurs
176
+ # when setting a side of the relation to nil.
177
+ #
178
+ # Will delete the object if necessary.
179
+ #
180
+ # @example Unbind the target.
181
+ # person.posts.unbind
182
+ #
183
+ # @param [ Hash ] options The options to bind with.
184
+ #
185
+ # @option options [ true, false ] :binding Are we in build mode?
186
+ # @option options [ true, false ] :continue Continue binding the
187
+ # inverse?
188
+ #
189
+ # @since 2.0.0.rc.1
190
+ def unbind(options = {})
191
+ target.each(&:delete) if base.persisted?
192
+ binding.unbind(options)
193
+ []
194
+ end
195
+
196
+ private
197
+
198
+ # Instantiate the binding associated with this relation.
199
+ #
200
+ # @example Get the binding.
201
+ # relation.binding([ address ])
202
+ #
203
+ # @param [ Array<Document> ] new_target The new documents to bind with.
204
+ #
205
+ # @return [ Binding ] The binding.
206
+ #
207
+ # @since 2.0.0.rc.1
208
+ def binding(new_target = nil)
209
+ Bindings::Referenced::ManyToMany.new(base, new_target || target, metadata)
210
+ end
211
+
212
+ # Returns the criteria object for the target class with its documents set
213
+ # to target.
214
+ #
215
+ # @example Get a criteria for the relation.
216
+ # relation.criteria
217
+ #
218
+ # @return [ Criteria ] A new criteria.
219
+ def criteria
220
+ metadata.klass.any_in(metadata.inverse_foreign_key => [ base.id ])
221
+ end
222
+
223
+ # Dereferences the supplied document from the base of the relation.
224
+ #
225
+ # @example Dereference the document.
226
+ # person.preferences.dereference(preference)
227
+ #
228
+ # @param [ Document ] document The document to dereference.
229
+ def dereference(document)
230
+ document.send(metadata.inverse_foreign_key).delete(base.id)
231
+ document.send(metadata.inverse(document)).target.delete(base)
232
+ document.save
233
+ end
234
+
235
+ class << self
236
+
237
+ # Return the builder that is responsible for generating the documents
238
+ # that will be used by this relation.
239
+ #
240
+ # @example Get the builder.
241
+ # Referenced::ManyToMany.builder(meta, object)
242
+ #
243
+ # @param [ Metadata ] meta The metadata of the relation.
244
+ # @param [ Document, Hash ] object A document or attributes to build
245
+ # with.
246
+ #
247
+ # @return [ Builder ] A new builder object.
248
+ #
249
+ # @since 2.0.0.rc.1
250
+ def builder(meta, object)
251
+ Builders::Referenced::ManyToMany.new(meta, object)
252
+ end
253
+
254
+ # Returns true if the relation is an embedded one. In this case
255
+ # always false.
256
+ #
257
+ # @example Is this relation embedded?
258
+ # Referenced::ManyToMany.embedded?
259
+ #
260
+ # @return [ false ] Always false.
261
+ #
262
+ # @since 2.0.0.rc.1
263
+ def embedded?
264
+ false
265
+ end
266
+
267
+ # Get the default value for the foreign key.
268
+ #
269
+ # @example Get the default.
270
+ # Referenced::ManyToMany.foreign_key_default
271
+ #
272
+ # @return [ Array ] Always an empty array.
273
+ #
274
+ # @since 2.0.0.rc.1
275
+ def foreign_key_default
276
+ []
277
+ end
278
+
279
+ # Returns the suffix of the foreign key field, either "_id" or "_ids".
280
+ #
281
+ # @example Get the suffix for the foreign key.
282
+ # Referenced::ManyToMany.foreign_key_suffix
283
+ #
284
+ # @return [ String ] "_ids"
285
+ #
286
+ # @since 2.0.0.rc.1
287
+ def foreign_key_suffix
288
+ "_ids"
289
+ end
290
+
291
+ # Returns the macro for this relation. Used mostly as a helper in
292
+ # reflection.
293
+ #
294
+ # @example Get the macro.
295
+ # Referenced::ManyToMany.macro
296
+ #
297
+ # @return [ Symbol ] :references_and_referenced_in_many
298
+ def macro
299
+ :references_and_referenced_in_many
300
+ end
301
+
302
+ # Return the nested builder that is responsible for generating the documents
303
+ # that will be used by this relation.
304
+ #
305
+ # @example Get the nested builder.
306
+ # Referenced::ManyToMany.builder(attributes, options)
307
+ #
308
+ # @param [ Metadata ] metadata The relation metadata.
309
+ # @param [ Hash ] attributes The attributes to build with.
310
+ # @param [ Hash ] options The options for the builder.
311
+ #
312
+ # @option options [ true, false ] :allow_destroy Can documents be
313
+ # deleted?
314
+ # @option options [ Integer ] :limit Max number of documents to
315
+ # create at once.
316
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
317
+ # option then they are ignored.
318
+ # @option options [ true, false ] :update_only Only existing documents
319
+ # can be modified.
320
+ #
321
+ # @return [ NestedBuilder ] A newly instantiated nested builder object.
322
+ #
323
+ # @since 2.0.0.rc.1
324
+ def nested_builder(metadata, attributes, options)
325
+ Builders::NestedAttributes::Many.new(metadata, attributes, options)
326
+ end
327
+
328
+ # Tells the caller if this relation is one that stores the foreign
329
+ # key on its own objects.
330
+ #
331
+ # @example Does this relation store a foreign key?
332
+ # Referenced::Many.stores_foreign_key?
333
+ #
334
+ # @return [ true ] Always true.
335
+ #
336
+ # @since 2.0.0.rc.1
337
+ def stores_foreign_key?
338
+ true
339
+ end
340
+ end
341
+ end
342
+ end
343
+ end
344
+ end
@@ -0,0 +1,206 @@
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
+ # Removes the association between the base document and the target
48
+ # document by deleting the foreign key and the reference, orphaning
49
+ # the target document in the process.
50
+ #
51
+ # @example Nullify the relation.
52
+ # person.game.nullify
53
+ #
54
+ # @since 2.0.0.rc.1
55
+ def nullify
56
+ target.send(metadata.foreign_key_setter, nil)
57
+ target.send(:remove_instance_variable, "@#{metadata.inverse(target)}")
58
+ base.send(:remove_instance_variable, "@#{metadata.name}")
59
+ target.save
60
+ end
61
+
62
+ # Unbinds the base object to the inverse of the relation. This occurs
63
+ # when setting a side of the relation to nil.
64
+ #
65
+ # Will delete the object if necessary.
66
+ #
67
+ # @example Unbind the relation.
68
+ # person.game.unbind(name, :continue => true)
69
+ #
70
+ # @param [ Document ] old_target The previous target of the relation.
71
+ # @param [ Hash ] options The options to bind with.
72
+ #
73
+ # @option options [ true, false ] :binding Are we in build mode?
74
+ # @option options [ true, false ] :continue Continue binding the
75
+ # inverse?
76
+ #
77
+ # @since 2.0.0.rc.1
78
+ def unbind(old_target, options = {})
79
+ binding(old_target).unbind(options)
80
+ old_target.delete if base.persisted? && !old_target.destroyed?
81
+ end
82
+
83
+ private
84
+
85
+ # Instantiate the binding associated with this relation.
86
+ #
87
+ # @example Get the binding.
88
+ # relation.binding([ address ])
89
+ #
90
+ # @param [ Document ] new_target The new target of the relation.
91
+ #
92
+ # @return [ Binding ] The binding object.
93
+ def binding(new_target = nil)
94
+ Bindings::Referenced::One.new(base, new_target || target, metadata)
95
+ end
96
+
97
+ class << self
98
+
99
+ # Return the builder that is responsible for generating the documents
100
+ # that will be used by this relation.
101
+ #
102
+ # @example Get the builder.
103
+ # Referenced::One.builder(meta, object)
104
+ #
105
+ # @param [ Metadata ] meta The metadata of the relation.
106
+ # @param [ Document, Hash ] object A document or attributes to build
107
+ # with.
108
+ #
109
+ # @return [ Builder ] A new builder object.
110
+ #
111
+ # @since 2.0.0.rc.1
112
+ def builder(meta, object)
113
+ Builders::Referenced::One.new(meta, object)
114
+ end
115
+
116
+ # Returns true if the relation is an embedded one. In this case
117
+ # always false.
118
+ #
119
+ # @example Is this relation embedded?
120
+ # Referenced::One.embedded?
121
+ #
122
+ # @return [ false ] Always false.
123
+ #
124
+ # @since 2.0.0.rc.1
125
+ def embedded?
126
+ false
127
+ end
128
+
129
+ # Get the default value for the foreign key.
130
+ #
131
+ # @example Get the default.
132
+ # Referenced::One.foreign_key_default
133
+ #
134
+ # @return [ nil ] Always nil.
135
+ #
136
+ # @since 2.0.0.rc.1
137
+ def foreign_key_default
138
+ nil
139
+ end
140
+
141
+ # Returns the suffix of the foreign key field, either "_id" or "_ids".
142
+ #
143
+ # @example Get the suffix for the foreign key.
144
+ # Referenced::One.foreign_key_suffix
145
+ #
146
+ # @return [ String ] "_id"
147
+ #
148
+ # @since 2.0.0.rc.1
149
+ def foreign_key_suffix
150
+ "_id"
151
+ end
152
+
153
+ # Returns the macro for this relation. Used mostly as a helper in
154
+ # reflection.
155
+ #
156
+ # @example Get the macro.
157
+ # Referenced::One.macro
158
+ #
159
+ # @return [ Symbol ] :references_one.
160
+ def macro
161
+ :references_one
162
+ end
163
+
164
+ # Return the nested builder that is responsible for generating the documents
165
+ # that will be used by this relation.
166
+ #
167
+ # @example Get the nested builder.
168
+ # Referenced::One.builder(attributes, options)
169
+ #
170
+ # @param [ Metadata ] metadata The relation metadata.
171
+ # @param [ Hash ] attributes The attributes to build with.
172
+ # @param [ Hash ] options The options for the builder.
173
+ #
174
+ # @option options [ true, false ] :allow_destroy Can documents be
175
+ # deleted?
176
+ # @option options [ Integer ] :limit Max number of documents to
177
+ # create at once.
178
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
179
+ # option then they are ignored.
180
+ # @option options [ true, false ] :update_only Only existing documents
181
+ # can be modified.
182
+ #
183
+ # @return [ NestedBuilder ] A newly instantiated nested builder object.
184
+ #
185
+ # @since 2.0.0.rc.1
186
+ def nested_builder(metadata, attributes, options)
187
+ Builders::NestedAttributes::One.new(metadata, attributes, options)
188
+ end
189
+
190
+ # Tells the caller if this relation is one that stores the foreign
191
+ # key on its own objects.
192
+ #
193
+ # @example Does this relation store a foreign key?
194
+ # Referenced::One.stores_foreign_key?
195
+ #
196
+ # @return [ false ] Always false.
197
+ #
198
+ # @since 2.0.0.rc.1
199
+ def stores_foreign_key?
200
+ false
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+
5
+ # The reflections module provides convenience methods that can retrieve
6
+ # useful information about associations.
7
+ module Reflections
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+
12
+ delegate \
13
+ :reflect_on_association,
14
+ :reflect_on_all_associations, :to => "self.class"
15
+ end
16
+
17
+ module ClassMethods #:nodoc
18
+
19
+ # Returns the relation metadata for the supplied name.
20
+ #
21
+ # @example Find relation metadata by name.
22
+ # Person.reflect_on_association(:addresses)
23
+ #
24
+ # @param [ String, Symbol ] name The name of the relation to find.
25
+ #
26
+ # @return [ Metadata ] The matching relation metadata.
27
+ def reflect_on_association(name)
28
+ relations[name.to_s]
29
+ end
30
+
31
+ # Returns all relation metadata for the supplied macros.
32
+ #
33
+ # @example Find multiple relation metadata by macro.
34
+ # Person.reflect_on_all_associations(:embeds_many)
35
+ #
36
+ # @param [ Array<String, Symbol> ] *macros The relation macros.
37
+ #
38
+ # @return [ Array<Metadata> ] The matching relation metadata.
39
+ def reflect_on_all_associations(*macros)
40
+ relations.values.select { |meta| macros.include?(meta.macro) }
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,105 @@
1
+ # encoding: utf-8
2
+ require "mongoid/relations/accessors"
3
+ require "mongoid/relations/auto_save"
4
+ require "mongoid/relations/cascading"
5
+ require "mongoid/relations/constraint"
6
+ require "mongoid/relations/cyclic"
7
+ require "mongoid/relations/proxy"
8
+ require "mongoid/relations/bindings"
9
+ require "mongoid/relations/builders"
10
+ require "mongoid/relations/many"
11
+ require "mongoid/relations/one"
12
+ require "mongoid/relations/polymorphic"
13
+ require "mongoid/relations/embedded/in"
14
+ require "mongoid/relations/embedded/many"
15
+ require "mongoid/relations/embedded/one"
16
+ require "mongoid/relations/referenced/in"
17
+ require "mongoid/relations/referenced/many"
18
+ require "mongoid/relations/referenced/many_to_many"
19
+ require "mongoid/relations/referenced/one"
20
+ require "mongoid/relations/reflections"
21
+ require "mongoid/relations/metadata"
22
+ require "mongoid/relations/macros"
23
+
24
+ module Mongoid # :nodoc:
25
+
26
+ # All classes and modules under the relations namespace handle the
27
+ # functionality that has to do with embedded and referenced (relational)
28
+ # associations.
29
+ module Relations
30
+ extend ActiveSupport::Concern
31
+ include Accessors
32
+ include AutoSave
33
+ include Cascading
34
+ include Cyclic
35
+ include Builders
36
+ include Macros
37
+ include Polymorphic
38
+ include Reflections
39
+
40
+ included do
41
+ attr_accessor :metadata
42
+ end
43
+
44
+ # Determine if the document itself is embedded in another document via the
45
+ # proper channels. (If it has a parent document.)
46
+ #
47
+ # @example Is the document embedded?
48
+ # address.embedded?
49
+ #
50
+ # @return [ true, false ] True if the document has a parent document.
51
+ #
52
+ # @since 2.0.0.rc.1
53
+ def embedded?
54
+ _parent.present?
55
+ end
56
+
57
+ # Determine if the document is part of an embeds_many relation.
58
+ #
59
+ # @example Is the document in an embeds many?
60
+ # address.embedded_many?
61
+ #
62
+ # @return [ true, false ] True if in an embeds many.
63
+ #
64
+ # @since 2.0.0.rc.1
65
+ def embedded_many?
66
+ metadata && metadata.macro == :embeds_many
67
+ end
68
+
69
+ # Determine if the document is part of an embeds_one relation.
70
+ #
71
+ # @example Is the document in an embeds one?
72
+ # address.embedded_one?
73
+ #
74
+ # @return [ true, false ] True if in an embeds one.
75
+ #
76
+ # @since 2.0.0.rc.1
77
+ def embedded_one?
78
+ metadata && metadata.macro == :embeds_one
79
+ end
80
+
81
+ # Determine if the document is part of an references_many relation.
82
+ #
83
+ # @example Is the document in a references many?
84
+ # post.referenced_many?
85
+ #
86
+ # @return [ true, false ] True if in a references many.
87
+ #
88
+ # @since 2.0.0.rc.1
89
+ def referenced_many?
90
+ metadata && metadata.macro == :references_many
91
+ end
92
+
93
+ # Determine if the document is part of an references_one relation.
94
+ #
95
+ # @example Is the document in a references one?
96
+ # address.referenced_one?
97
+ #
98
+ # @return [ true, false ] True if in a references one.
99
+ #
100
+ # @since 2.0.0.rc.1
101
+ def referenced_one?
102
+ metadata && metadata.macro == :references_one
103
+ end
104
+ end
105
+ end