stonegao-mongoid 2.0.0.rc.6

Sign up to get free protection for your applications and to get access to all the features.
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