mongoid-braxton 2.0.2

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