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,483 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Embedded #:nodoc:
5
+
6
+ # This class handles the behaviour for a document that embeds many other
7
+ # documents within in it as an array.
8
+ class Many < Relations::Many
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.addresses.bind(:continue => true)
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.each(&:save) if base.persisted? && !options[:binding]
30
+ end
31
+
32
+ # Bind the inverse relation between a single document in this proxy
33
+ # instead of the entire target.
34
+ #
35
+ # Used when appending to the target instead of setting the entire
36
+ # thing.
37
+ #
38
+ # @example Bind a single document.
39
+ # person.addressses.bind_one(address)
40
+ #
41
+ # @param [ Document ] document The document to bind.
42
+ #
43
+ # @since 2.0.0.rc.1
44
+ def bind_one(document, options = {})
45
+ binding.bind_one(document, options)
46
+ end
47
+
48
+ # Clear the relation. Will delete the documents from the db if they are
49
+ # already persisted.
50
+ #
51
+ # @example Clear the relation.
52
+ # person.addresses.clear
53
+ #
54
+ # @return [ Many ] The empty relation.
55
+ def clear
56
+ load! and substitute(nil)
57
+ end
58
+
59
+ # Returns a count of the number of documents in the association that have
60
+ # actually been persisted to the database.
61
+ #
62
+ # Use #size if you want the total number of documents.
63
+ #
64
+ # @example Get the count of persisted documents.
65
+ # person.addresses.count
66
+ #
67
+ # @return [ Integer ] The total number of persisted embedded docs, as
68
+ # flagged by the #persisted? method.
69
+ def count
70
+ target.select(&:persisted?).size
71
+ end
72
+
73
+ # Create a new document in the relation. This is essentially the same
74
+ # as doing a #build then #save on the new document.
75
+ #
76
+ # @example Create a new document in the relation.
77
+ # person.movies.create(:name => "Bozo")
78
+ #
79
+ # @param [ Hash ] attributes The attributes to build the document with.
80
+ # @param [ Class ] type Optional class to create the document with.
81
+ #
82
+ # @return [ Document ] The newly created document.
83
+ def create(attributes = {}, type = nil)
84
+ build(attributes, type).tap(&:save)
85
+ end
86
+
87
+ # Create a new document in the relation. This is essentially the same
88
+ # as doing a #build then #save on the new document. If validation
89
+ # failed on the document an error will get raised.
90
+ #
91
+ # @example Create the document.
92
+ # person.addresses.create!(:street => "Unter der Linden")</tt>
93
+ #
94
+ # @param [ Hash ] attributes The attributes to build the document with.
95
+ # @param [ Class ] type Optional class to create the document with.
96
+ #
97
+ # @raise [ Errors::Validations ] If a validation error occured.
98
+ #
99
+ # @return [ Document ] The newly created document.
100
+ def create!(attributes = {}, type = nil)
101
+ build(attributes, type).tap(&:save!)
102
+ end
103
+
104
+ # Delete the supplied document from the target. This method is proxied
105
+ # in order to reindex the array after the operation occurs.
106
+ #
107
+ # @example Delete the document from the relation.
108
+ # perosn.addresses.delete(address)
109
+ #
110
+ # @param [ Document ] document The document to be deleted.
111
+ #
112
+ # @return [ Document, nil ] The deleted document or nil if nothing deleted.
113
+ #
114
+ # @since 2.0.0.rc.1
115
+ def delete(document)
116
+ target.delete(document).tap { reindex }
117
+ end
118
+
119
+ # Delete all the documents in the association without running callbacks.
120
+ #
121
+ # @example Delete all documents from the relation.
122
+ # person.addresses.delete_all
123
+ #
124
+ # @example Conditionally delete documents from the relation.
125
+ # person.addresses.delete_all(:conditions => { :street => "Bond" })
126
+ #
127
+ # @param [ Hash ] conditions Conditions on which documents to delete.
128
+ #
129
+ # @return [ Integer ] The number of documents deleted.
130
+ def delete_all(conditions = {})
131
+ remove_all(conditions, false)
132
+ end
133
+
134
+ # Destroy all the documents in the association whilst running callbacks.
135
+ #
136
+ # @example Destroy all documents from the relation.
137
+ # person.addresses.destroy_all
138
+ #
139
+ # @example Conditionally destroy documents from the relation.
140
+ # person.addresses.destroy_all(:conditions => { :street => "Bond" })
141
+ #
142
+ # @param [ Hash ] conditions Conditions on which documents to destroy.
143
+ #
144
+ # @return [ Integer ] The number of documents destroyed.
145
+ def destroy_all(conditions = {})
146
+ remove_all(conditions, true)
147
+ end
148
+
149
+ # Finds a document in this association through several different
150
+ # methods.
151
+ #
152
+ # @example Find a document by its id.
153
+ # person.addresses.find(BSON::ObjectId.new)
154
+ #
155
+ # @example Find documents for multiple ids.
156
+ # person.addresses.find([ BSON::ObjectId.new, BSON::ObjectId.new ])
157
+ #
158
+ # @example Find documents based on conditions.
159
+ # person.addresses.find(:all, :conditions => { :number => 10 })
160
+ # person.addresses.find(:first, :conditions => { :number => 10 })
161
+ # person.addresses.find(:last, :conditions => { :number => 10 })
162
+ #
163
+ # @param [ Array<Object> ] args Various arguments.
164
+ #
165
+ # @return [ Array<Document>, Document ] A single or multiple documents.
166
+ def find(*args)
167
+ type, criteria = Criteria.parse!(self, true, *args)
168
+ case type
169
+ when :first then return criteria.one
170
+ when :last then return criteria.last
171
+ else
172
+ criteria.tap do |crit|
173
+ crit.documents = target if crit.is_a?(Criteria)
174
+ end
175
+ end
176
+ end
177
+
178
+ # Instantiate a new embeds_many relation.
179
+ #
180
+ # @example Create the new relation.
181
+ # Many.new(person, addresses, metadata)
182
+ #
183
+ # @param [ Document ] base The document this relation hangs off of.
184
+ # @param [ Array<Document> ] target The child documents of the relation.
185
+ # @param [ Metadata ] metadata The relation's metadata
186
+ #
187
+ # @return [ Many ] The proxy.
188
+ def initialize(base, target, metadata)
189
+ init(base, target, metadata) do
190
+ target.each_with_index do |doc, index|
191
+ characterize_one(doc)
192
+ doc.parentize(base)
193
+ doc._index = index
194
+ end
195
+ end
196
+ end
197
+
198
+ # Will load the target into an array if the target had not already been
199
+ # loaded.
200
+ #
201
+ # @example Load the relation into memory.
202
+ # relation.load!
203
+ #
204
+ # @return [ Many ] The relation.
205
+ #
206
+ # @since 2.0.0.rc.5
207
+ def load!(options = {})
208
+ tap do |relation|
209
+ unless relation.loaded?
210
+ relation.bind(options)
211
+ relation.loaded = true
212
+ end
213
+ end
214
+ end
215
+
216
+ # Paginate the association. Will create a new criteria, set the documents
217
+ # on it and execute in an enumerable context.
218
+ #
219
+ # @example Paginate the relation.
220
+ # person.addresses.paginate(:page => 1, :per_page => 20)
221
+ #
222
+ # @param [ Hash ] options The pagination options.
223
+ #
224
+ # @option options [ Integer ] :page The page number.
225
+ # @option options [ Integer ] :per_page The number on each page.
226
+ #
227
+ # @return [ WillPaginate::Collection ] The paginated documents.
228
+ def paginate(options)
229
+ criteria = Mongoid::Criteria.translate(metadata.klass, true, options)
230
+ criteria.documents = target
231
+ criteria.paginate(options)
232
+ end
233
+
234
+ # Substitutes the supplied target documents for the existing documents
235
+ # in the relation.
236
+ #
237
+ # @example Substitute the relation's target.
238
+ # person.addresses.substitute([ address ])
239
+ #
240
+ # @param [ Array<Document> ] new_target The replacement array.
241
+ # @param [ true, false ] building Are we in build mode?
242
+ #
243
+ # @return [ Many ] The proxied relation.
244
+ #
245
+ # @since 2.0.0.rc.1
246
+ def substitute(new_target, options = {})
247
+ old_target = target
248
+ tap do |relation|
249
+ relation.target = new_target || []
250
+ if !new_target.blank?
251
+ unbind(old_target, options)
252
+ bind(options)
253
+ else
254
+ unbind(old_target, options)
255
+ end
256
+ end
257
+ end
258
+
259
+ # Get this relation as as its representation in the database.
260
+ #
261
+ # @example Convert the relation to an attributes hash.
262
+ # person.addresses.to_hash
263
+ #
264
+ # @return [ Array<Hash> ] The relation as stored in the db.
265
+ #
266
+ # @since 2.0.0.rc.1
267
+ def to_hash
268
+ target.inject([]) do |attributes, doc|
269
+ attributes.tap do |attr|
270
+ attr << doc.to_hash
271
+ end
272
+ end
273
+ end
274
+
275
+ # Unbind the inverse relation from this set of documents. Used when the
276
+ # entire proxy has been cleared, set to nil or empty, or replaced.
277
+ #
278
+ # @example Unbind the relation.
279
+ # person.addresses.unbind(target, :continue => false)
280
+ #
281
+ # @param [ Array<Document> ] old_target The relations previous target.
282
+ # @param [ Hash ] options The options to bind with.
283
+ #
284
+ # @option options [ true, false ] :binding Are we in build mode?
285
+ # @option options [ true, false ] :continue Continue binding the
286
+ # inverse?
287
+ #
288
+ # @since 2.0.0.rc.1
289
+ def unbind(old_target, options = {})
290
+ binding(old_target).unbind(options)
291
+ if base.persisted?
292
+ old_target.each do |doc|
293
+ doc.delete unless doc.destroyed?
294
+ end
295
+ end
296
+ end
297
+
298
+ private
299
+
300
+ # Appends the document to the target array, updating the index on the
301
+ # document at the same time.
302
+ #
303
+ # @example Append to the document.
304
+ # relation.append(document)
305
+ #
306
+ # @param [ Document ] document The document to append to the target.
307
+ #
308
+ # @since 2.0.0.rc.1
309
+ def append(document, options = {})
310
+ load! and target.push(document)
311
+ characterize_one(document)
312
+ bind_one(document, options)
313
+ document._index = target.size - 1
314
+ end
315
+
316
+ # Instantiate the binding associated with this relation.
317
+ #
318
+ # @example Create the binding.
319
+ # relation.binding([ address ])
320
+ #
321
+ # @param [ Array<Document> ] new_target The new documents to bind with.
322
+ #
323
+ # @return [ Binding ] The many binding.
324
+ #
325
+ # @since 2.0.0.rc.1
326
+ def binding(new_target = nil)
327
+ Bindings::Embedded::Many.new(base, new_target || target, metadata)
328
+ end
329
+
330
+ # Returns the criteria object for the target class with its documents set
331
+ # to target.
332
+ #
333
+ # @example Get a criteria for the relation.
334
+ # relation.criteria
335
+ #
336
+ # @return [ Criteria ] A new criteria.
337
+ def criteria
338
+ metadata.klass.criteria(true).tap do |criterion|
339
+ criterion.documents = target
340
+ end
341
+ end
342
+
343
+ # If the target array does not respond to the supplied method then try to
344
+ # find a named scope or criteria on the class and send the call there.
345
+ #
346
+ # If the method exists on the array, use the default proxy behavior.
347
+ #
348
+ # @param [ Symbol, String ] name The name of the method.
349
+ # @param [ Array ] args The method args
350
+ # @param [ Proc ] block Optional block to pass.
351
+ #
352
+ # @return [ Criteria, Object ] A Criteria or return value from the target.
353
+ def method_missing(name, *args, &block)
354
+ load!(:binding => true) and return super if target.respond_to?(name)
355
+ klass = metadata.klass
356
+ klass.send(:with_scope, criteria) do
357
+ criteria.send(name, *args)
358
+ end
359
+ end
360
+
361
+ # Reindex all the target elements. This is useful when performing
362
+ # operations on the proxied target directly and the indices need to
363
+ # match that on the database side.
364
+ #
365
+ # @example Reindex the relation.
366
+ # person.addresses.reindex
367
+ #
368
+ # @since 2.0.0.rc.1
369
+ def reindex
370
+ target.each_with_index do |doc, index|
371
+ doc._index = index
372
+ end
373
+ end
374
+
375
+ # Remove all documents from the relation, either with a delete or a
376
+ # destroy depending on what this was called through.
377
+ #
378
+ # @example Destroy documents from the relation.
379
+ # relation.remove_all(:conditions => { :num => 1 }, true)
380
+ #
381
+ # @param [ Hash ] conditions Conditions to filter by.
382
+ # @param [ true, false ] destroy If true then destroy, else delete.
383
+ #
384
+ # @return [ Integer ] The number of documents removed.
385
+ def remove_all(conditions = {}, destroy = false)
386
+ criteria = find(conditions || {})
387
+ criteria.size.tap do
388
+ criteria.each do |doc|
389
+ target.delete(doc)
390
+ destroy ? doc.destroy : doc.delete
391
+ end
392
+ reindex
393
+ end
394
+ end
395
+
396
+ class << self
397
+
398
+ # Return the builder that is responsible for generating the documents
399
+ # that will be used by this relation.
400
+ #
401
+ # @example Get the builder.
402
+ # Embedded::Many.builder(meta, object)
403
+ #
404
+ # @param [ Metadata ] meta The metadata of the relation.
405
+ # @param [ Document, Hash ] object A document or attributes to build
406
+ # with.
407
+ #
408
+ # @return [ Builder ] A newly instantiated builder object.
409
+ #
410
+ # @since 2.0.0.rc.1
411
+ def builder(meta, object)
412
+ Builders::Embedded::Many.new(meta, object)
413
+ end
414
+
415
+ # Returns true if the relation is an embedded one. In this case
416
+ # always true.
417
+ #
418
+ # @example Is the relation embedded?
419
+ # Embedded::Many.embedded?
420
+ #
421
+ # @return [ true ] true.
422
+ #
423
+ # @since 2.0.0.rc.1
424
+ def embedded?
425
+ true
426
+ end
427
+
428
+ # Returns the macro for this relation. Used mostly as a helper in
429
+ # reflection.
430
+ #
431
+ # @example Get the relation macro.
432
+ # Mongoid::Relations::Embedded::Many.macro
433
+ #
434
+ # @return [ Symbol ] :embeds_many
435
+ #
436
+ # @since 2.0.0.rc.1
437
+ def macro
438
+ :embeds_many
439
+ end
440
+
441
+ # Return the nested builder that is responsible for generating the
442
+ # documents that will be used by this relation.
443
+ #
444
+ # @example Get the nested builder.
445
+ # NestedAttributes::Many.builder(attributes, options)
446
+ #
447
+ # @param [ Metadata ] metadata The relation metadata.
448
+ # @param [ Hash ] attributes The attributes to build with.
449
+ # @param [ Hash ] options The builder options.
450
+ #
451
+ # @option options [ true, false ] :allow_destroy Can documents be
452
+ # deleted?
453
+ # @option options [ Integer ] :limit Max number of documents to
454
+ # create at once.
455
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
456
+ # option then they are ignored.
457
+ # @option options [ true, false ] :update_only Only existing documents
458
+ # can be modified.
459
+ #
460
+ # @return [ NestedBuilder ] The nested attributes builder.
461
+ #
462
+ # @since 2.0.0.rc.1
463
+ def nested_builder(metadata, attributes, options)
464
+ Builders::NestedAttributes::Many.new(metadata, attributes, options)
465
+ end
466
+
467
+ # Tells the caller if this relation is one that stores the foreign
468
+ # key on its own objects.
469
+ #
470
+ # @example Does this relation store a foreign key?
471
+ # Embedded::Many.stores_foreign_key?
472
+ #
473
+ # @return [ false ] false.
474
+ #
475
+ # @since 2.0.0.rc.1
476
+ def stores_foreign_key?
477
+ false
478
+ end
479
+ end
480
+ end
481
+ end
482
+ end
483
+ end
@@ -0,0 +1,170 @@
1
+ # encoding: utf-8
2
+ module Mongoid # :nodoc:
3
+ module Relations #:nodoc:
4
+ module Embedded #:nodoc:
5
+
6
+ # This class defines the behaviour needed for embedded one to one
7
+ # relations.
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.name.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 embeds_one relation.
33
+ #
34
+ # @example Create the new proxy.
35
+ # One.new(person, name, metadata)
36
+ #
37
+ # @param [ Document ] base The document this relation hangs off of.
38
+ # @param [ Document ] target The child document in the relation.
39
+ # @param [ Metadata ] metadata The relation's metadata
40
+ def initialize(base, target, metadata)
41
+ init(base, target, metadata) do
42
+ characterize_one(target)
43
+ target.parentize(base)
44
+ end
45
+ end
46
+
47
+ # Unbinds the base object to the inverse of the relation. This occurs
48
+ # when setting a side of the relation to nil.
49
+ #
50
+ # Will delete the object if necessary.
51
+ #
52
+ # @example Unbind the relation.
53
+ # person.name.unbind(name, :continue => true)
54
+ #
55
+ # @param [ Document ] old_target The previous target of the relation.
56
+ # @param [ Hash ] options The options to bind with.
57
+ #
58
+ # @option options [ true, false ] :binding Are we in build mode?
59
+ # @option options [ true, false ] :continue Continue binding the
60
+ # inverse?
61
+ #
62
+ # @since 2.0.0.rc.1
63
+ def unbind(old_target, options = {})
64
+ binding(old_target).unbind(options)
65
+ old_target.delete if base.persisted? && !old_target.destroyed?
66
+ end
67
+
68
+ private
69
+
70
+ # Instantiate the binding associated with this relation.
71
+ #
72
+ # @example Get the binding.
73
+ # relation.binding([ address ])
74
+ #
75
+ # @param [ Document ] new_target The new document to bind with.
76
+ #
77
+ # @return [ Binding ] The relation's binding.
78
+ #
79
+ # @since 2.0.0.rc.1
80
+ def binding(new_target = nil)
81
+ Bindings::Embedded::One.new(base, new_target || target, metadata)
82
+ end
83
+
84
+ class << self
85
+
86
+ # Return the builder that is responsible for generating the documents
87
+ # that will be used by this relation.
88
+ #
89
+ # @example Get the builder.
90
+ # Embedded::One.builder(meta, object, person)
91
+ #
92
+ # @param [ Metadata ] meta The metadata of the relation.
93
+ # @param [ Document, Hash ] object A document or attributes to build with.
94
+ #
95
+ # @return [ Builder ] A newly instantiated builder object.
96
+ #
97
+ # @since 2.0.0.rc.1
98
+ def builder(meta, object)
99
+ Builders::Embedded::One.new(meta, object)
100
+ end
101
+
102
+ # Returns true if the relation is an embedded one. In this case
103
+ # always true.
104
+ #
105
+ # @example Is this relation embedded?
106
+ # Embedded::One.embedded?
107
+ #
108
+ # @return [ true ] true.
109
+ #
110
+ # @since 2.0.0.rc.1
111
+ def embedded?
112
+ true
113
+ end
114
+
115
+ # Returns the macro for this relation. Used mostly as a helper in
116
+ # reflection.
117
+ #
118
+ # @example Get the macro.
119
+ # Mongoid::Relations::Embedded::One.macro
120
+ #
121
+ # @return [ Symbol ] :embeds_one.
122
+ #
123
+ # @since 2.0.0.rc.1
124
+ def macro
125
+ :embeds_one
126
+ end
127
+
128
+ # Return the nested builder that is responsible for generating
129
+ # the documents that will be used by this relation.
130
+ #
131
+ # @example Get the builder.
132
+ # NestedAttributes::One.builder(attributes, options)
133
+ #
134
+ # @param [ Metadata ] metadata The relation metadata.
135
+ # @param [ Hash ] attributes The attributes to build with.
136
+ # @param [ Hash ] options The options for the builder.
137
+ #
138
+ # @option options [ true, false ] :allow_destroy Can documents be
139
+ # deleted?
140
+ # @option options [ Integer ] :limit Max number of documents to
141
+ # create at once.
142
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
143
+ # option then they are ignored.
144
+ # @option options [ true, false ] :update_only Only existing documents
145
+ # can be modified.
146
+ #
147
+ # @return [ Builder ] A newly instantiated nested builder object.
148
+ #
149
+ # @since 2.0.0.rc.1
150
+ def nested_builder(metadata, attributes, options)
151
+ Builders::NestedAttributes::One.new(metadata, attributes, options)
152
+ end
153
+
154
+ # Tells the caller if this relation is one that stores the foreign
155
+ # key on its own objects.
156
+ #
157
+ # @example Does this relation store a foreign key?
158
+ # Embedded::One.stores_foreign_key?
159
+ #
160
+ # @return [ false ] false.
161
+ #
162
+ # @since 2.0.0.rc.1
163
+ def stores_foreign_key?
164
+ false
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end