mongoid 2.0.0.beta.20 → 2.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/README.rdoc +8 -0
  2. data/Rakefile +51 -0
  3. data/lib/config/locales/nl.yml +39 -0
  4. data/lib/config/locales/ro.yml +1 -1
  5. data/lib/mongoid.rb +17 -17
  6. data/lib/mongoid/atomicity.rb +54 -22
  7. data/lib/mongoid/attributes.rb +145 -125
  8. data/lib/mongoid/callbacks.rb +7 -2
  9. data/lib/mongoid/collection.rb +49 -32
  10. data/lib/mongoid/collections.rb +0 -1
  11. data/lib/mongoid/components.rb +34 -29
  12. data/lib/mongoid/config.rb +207 -193
  13. data/lib/mongoid/config/database.rb +167 -0
  14. data/lib/mongoid/contexts.rb +2 -5
  15. data/lib/mongoid/contexts/enumerable.rb +30 -4
  16. data/lib/mongoid/contexts/ids.rb +2 -2
  17. data/lib/mongoid/contexts/mongo.rb +30 -5
  18. data/lib/mongoid/copyable.rb +44 -0
  19. data/lib/mongoid/criteria.rb +110 -56
  20. data/lib/mongoid/criterion/creational.rb +34 -0
  21. data/lib/mongoid/criterion/destructive.rb +37 -0
  22. data/lib/mongoid/criterion/exclusion.rb +3 -1
  23. data/lib/mongoid/criterion/inclusion.rb +59 -64
  24. data/lib/mongoid/criterion/inspection.rb +22 -0
  25. data/lib/mongoid/criterion/optional.rb +42 -54
  26. data/lib/mongoid/criterion/selector.rb +9 -0
  27. data/lib/mongoid/default_scope.rb +28 -0
  28. data/lib/mongoid/deprecation.rb +5 -5
  29. data/lib/mongoid/dirty.rb +4 -5
  30. data/lib/mongoid/document.rb +161 -114
  31. data/lib/mongoid/extensions.rb +7 -11
  32. data/lib/mongoid/extensions/array/parentization.rb +2 -2
  33. data/lib/mongoid/extensions/date/conversions.rb +1 -1
  34. data/lib/mongoid/extensions/hash/conversions.rb +0 -23
  35. data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
  36. data/lib/mongoid/extensions/object/reflections.rb +17 -0
  37. data/lib/mongoid/extensions/object/yoda.rb +27 -0
  38. data/lib/mongoid/extensions/string/conversions.rb +23 -4
  39. data/lib/mongoid/extensions/time_conversions.rb +4 -4
  40. data/lib/mongoid/field.rb +30 -19
  41. data/lib/mongoid/fields.rb +15 -5
  42. data/lib/mongoid/finders.rb +19 -11
  43. data/lib/mongoid/hierarchy.rb +34 -28
  44. data/lib/mongoid/identity.rb +62 -20
  45. data/lib/mongoid/inspection.rb +58 -0
  46. data/lib/mongoid/matchers.rb +20 -0
  47. data/lib/mongoid/multi_database.rb +11 -0
  48. data/lib/mongoid/nested_attributes.rb +41 -0
  49. data/lib/mongoid/paranoia.rb +3 -4
  50. data/lib/mongoid/paths.rb +1 -1
  51. data/lib/mongoid/persistence.rb +89 -90
  52. data/lib/mongoid/persistence/command.rb +20 -4
  53. data/lib/mongoid/persistence/insert.rb +13 -11
  54. data/lib/mongoid/persistence/insert_embedded.rb +8 -6
  55. data/lib/mongoid/persistence/remove.rb +6 -4
  56. data/lib/mongoid/persistence/remove_all.rb +6 -4
  57. data/lib/mongoid/persistence/remove_embedded.rb +8 -6
  58. data/lib/mongoid/persistence/update.rb +12 -10
  59. data/lib/mongoid/railtie.rb +2 -2
  60. data/lib/mongoid/railties/database.rake +10 -9
  61. data/lib/mongoid/relations.rb +104 -0
  62. data/lib/mongoid/relations/accessors.rb +154 -0
  63. data/lib/mongoid/relations/auto_save.rb +34 -0
  64. data/lib/mongoid/relations/binding.rb +24 -0
  65. data/lib/mongoid/relations/bindings.rb +9 -0
  66. data/lib/mongoid/relations/bindings/embedded/in.rb +77 -0
  67. data/lib/mongoid/relations/bindings/embedded/many.rb +93 -0
  68. data/lib/mongoid/relations/bindings/embedded/one.rb +65 -0
  69. data/lib/mongoid/relations/bindings/referenced/in.rb +78 -0
  70. data/lib/mongoid/relations/bindings/referenced/many.rb +93 -0
  71. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +94 -0
  72. data/lib/mongoid/relations/bindings/referenced/one.rb +63 -0
  73. data/lib/mongoid/relations/builder.rb +41 -0
  74. data/lib/mongoid/relations/builders.rb +79 -0
  75. data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
  76. data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
  77. data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
  78. data/lib/mongoid/relations/builders/nested_attributes/many.rb +116 -0
  79. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  80. data/lib/mongoid/relations/builders/referenced/in.rb +32 -0
  81. data/lib/mongoid/relations/builders/referenced/many.rb +26 -0
  82. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
  83. data/lib/mongoid/relations/builders/referenced/one.rb +30 -0
  84. data/lib/mongoid/relations/cascading.rb +55 -0
  85. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  86. data/lib/mongoid/relations/cascading/destroy.rb +19 -0
  87. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  88. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  89. data/lib/mongoid/relations/cyclic.rb +97 -0
  90. data/lib/mongoid/relations/embedded/in.rb +172 -0
  91. data/lib/mongoid/relations/embedded/many.rb +450 -0
  92. data/lib/mongoid/relations/embedded/one.rb +169 -0
  93. data/lib/mongoid/relations/macros.rb +302 -0
  94. data/lib/mongoid/relations/many.rb +185 -0
  95. data/lib/mongoid/relations/metadata.rb +529 -0
  96. data/lib/mongoid/relations/nested_builder.rb +52 -0
  97. data/lib/mongoid/relations/one.rb +29 -0
  98. data/lib/mongoid/relations/polymorphic.rb +54 -0
  99. data/lib/mongoid/relations/proxy.rb +122 -0
  100. data/lib/mongoid/relations/referenced/in.rb +214 -0
  101. data/lib/mongoid/relations/referenced/many.rb +358 -0
  102. data/lib/mongoid/relations/referenced/many_to_many.rb +379 -0
  103. data/lib/mongoid/relations/referenced/one.rb +204 -0
  104. data/lib/mongoid/relations/reflections.rb +45 -0
  105. data/lib/mongoid/safe.rb +11 -1
  106. data/lib/mongoid/safety.rb +122 -97
  107. data/lib/mongoid/scope.rb +14 -9
  108. data/lib/mongoid/state.rb +37 -3
  109. data/lib/mongoid/timestamps.rb +11 -0
  110. data/lib/mongoid/validations.rb +42 -3
  111. data/lib/mongoid/validations/associated.rb +8 -5
  112. data/lib/mongoid/validations/uniqueness.rb +23 -2
  113. data/lib/mongoid/version.rb +1 -1
  114. data/lib/mongoid/versioning.rb +25 -16
  115. data/lib/rails/generators/mongoid/model/templates/model.rb +3 -1
  116. metadata +95 -80
  117. data/lib/mongoid/associations.rb +0 -364
  118. data/lib/mongoid/associations/embedded_in.rb +0 -74
  119. data/lib/mongoid/associations/embeds_many.rb +0 -299
  120. data/lib/mongoid/associations/embeds_one.rb +0 -111
  121. data/lib/mongoid/associations/foreign_key.rb +0 -35
  122. data/lib/mongoid/associations/meta_data.rb +0 -38
  123. data/lib/mongoid/associations/options.rb +0 -78
  124. data/lib/mongoid/associations/proxy.rb +0 -60
  125. data/lib/mongoid/associations/referenced_in.rb +0 -70
  126. data/lib/mongoid/associations/references_many.rb +0 -254
  127. data/lib/mongoid/associations/references_many_as_array.rb +0 -128
  128. data/lib/mongoid/associations/references_one.rb +0 -104
  129. data/lib/mongoid/extensions/array/accessors.rb +0 -17
  130. data/lib/mongoid/extensions/array/assimilation.rb +0 -26
  131. data/lib/mongoid/extensions/hash/accessors.rb +0 -42
  132. data/lib/mongoid/extensions/hash/assimilation.rb +0 -40
  133. data/lib/mongoid/extensions/nil/assimilation.rb +0 -17
  134. data/lib/mongoid/memoization.rb +0 -33
@@ -0,0 +1,204 @@
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 ] :building 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[:building]
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)
43
+ end
44
+
45
+ # Removes the association between the base document and the target
46
+ # document by deleting the foreign key and the reference, orphaning
47
+ # the target document in the process.
48
+ #
49
+ # @example Nullify the relation.
50
+ # person.game.nullify
51
+ #
52
+ # @since 2.0.0.rc.1
53
+ def nullify
54
+ target.send(metadata.foreign_key_setter, nil)
55
+ target.send(:remove_instance_variable, "@#{metadata.inverse(target)}")
56
+ base.send(:remove_instance_variable, "@#{metadata.name}")
57
+ target.save
58
+ end
59
+
60
+ # Unbinds the base object to the inverse of the relation. This occurs
61
+ # when setting a side of the relation to nil.
62
+ #
63
+ # Will delete the object if necessary.
64
+ #
65
+ # @example Unbind the relation.
66
+ # person.game.unbind(name, :continue => true)
67
+ #
68
+ # @param [ Document ] old_target The previous target of the relation.
69
+ # @param [ Hash ] options The options to bind with.
70
+ #
71
+ # @option options [ true, false ] :building Are we in build mode?
72
+ # @option options [ true, false ] :continue Continue binding the
73
+ # inverse?
74
+ #
75
+ # @since 2.0.0.rc.1
76
+ def unbind(old_target, options = {})
77
+ binding(old_target).unbind(options)
78
+ old_target.delete if base.persisted? && !old_target.destroyed?
79
+ end
80
+
81
+ private
82
+
83
+ # Instantiate the binding associated with this relation.
84
+ #
85
+ # @example Get the binding.
86
+ # relation.binding([ address ])
87
+ #
88
+ # @param [ Document ] new_target The new target of the relation.
89
+ #
90
+ # @return [ Binding ] The binding object.
91
+ def binding(new_target = nil)
92
+ Bindings::Referenced::One.new(base, new_target || target, metadata)
93
+ end
94
+
95
+ class << self
96
+
97
+ # Return the builder that is responsible for generating the documents
98
+ # that will be used by this relation.
99
+ #
100
+ # @example Get the builder.
101
+ # Referenced::One.builder(meta, object)
102
+ #
103
+ # @param [ Metadata ] meta The metadata of the relation.
104
+ # @param [ Document, Hash ] object A document or attributes to build
105
+ # with.
106
+ #
107
+ # @return [ Builder ] A new builder object.
108
+ #
109
+ # @since 2.0.0.rc.1
110
+ def builder(meta, object)
111
+ Builders::Referenced::One.new(meta, object)
112
+ end
113
+
114
+ # Returns true if the relation is an embedded one. In this case
115
+ # always false.
116
+ #
117
+ # @example Is this relation embedded?
118
+ # Referenced::One.embedded?
119
+ #
120
+ # @return [ false ] Always false.
121
+ #
122
+ # @since 2.0.0.rc.1
123
+ def embedded?
124
+ false
125
+ end
126
+
127
+ # Get the default value for the foreign key.
128
+ #
129
+ # @example Get the default.
130
+ # Referenced::One.foreign_key_default
131
+ #
132
+ # @return [ nil ] Always nil.
133
+ #
134
+ # @since 2.0.0.rc.1
135
+ def foreign_key_default
136
+ nil
137
+ end
138
+
139
+ # Returns the suffix of the foreign key field, either "_id" or "_ids".
140
+ #
141
+ # @example Get the suffix for the foreign key.
142
+ # Referenced::One.foreign_key_suffix
143
+ #
144
+ # @return [ String ] "_id"
145
+ #
146
+ # @since 2.0.0.rc.1
147
+ def foreign_key_suffix
148
+ "_id"
149
+ end
150
+
151
+ # Returns the macro for this relation. Used mostly as a helper in
152
+ # reflection.
153
+ #
154
+ # @example Get the macro.
155
+ # Referenced::One.macro
156
+ #
157
+ # @return [ Symbol ] :references_one.
158
+ def macro
159
+ :references_one
160
+ end
161
+
162
+ # Return the nested builder that is responsible for generating the documents
163
+ # that will be used by this relation.
164
+ #
165
+ # @example Get the nested builder.
166
+ # Referenced::One.builder(attributes, options)
167
+ #
168
+ # @param [ Metadata ] metadata The relation metadata.
169
+ # @param [ Hash ] attributes The attributes to build with.
170
+ # @param [ Hash ] options The options for the builder.
171
+ #
172
+ # @option options [ true, false ] :allow_destroy Can documents be
173
+ # deleted?
174
+ # @option options [ Integer ] :limit Max number of documents to
175
+ # create at once.
176
+ # @option options [ Proc, Symbol ] :reject_if If documents match this
177
+ # option then they are ignored.
178
+ # @option options [ true, false ] :update_only Only existing documents
179
+ # can be modified.
180
+ #
181
+ # @return [ NestedBuilder ] A newly instantiated nested builder object.
182
+ #
183
+ # @since 2.0.0.rc.1
184
+ def nested_builder(metadata, attributes, options)
185
+ Builders::NestedAttributes::One.new(metadata, attributes, options)
186
+ end
187
+
188
+ # Tells the caller if this relation is one that stores the foreign
189
+ # key on its own objects.
190
+ #
191
+ # @example Does this relation store a foreign key?
192
+ # Referenced::One.stores_foreign_key?
193
+ #
194
+ # @return [ false ] Always false.
195
+ #
196
+ # @since 2.0.0.rc.1
197
+ def stores_foreign_key?
198
+ false
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
204
+ 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
@@ -1,10 +1,20 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
- module Safe #:nodoc:
3
+
4
+ # Contains behaviour for determining if Mongoid is in safe mode.
5
+ module Safe
6
+
4
7
  # Determine based on configuration if we are persisting in safe mode or
5
8
  # not.
6
9
  #
7
10
  # The query option will always override the global configuration.
11
+ #
12
+ # @example Are we in safe mode?
13
+ # document.safe_mode?(:safe => true)
14
+ #
15
+ # @param [ Hash ] options Persistence options.
16
+ #
17
+ # @return [ true, false ] True if in safe mode, false if not.
8
18
  def safe_mode?(options)
9
19
  safe = options[:safe]
10
20
  safe.nil? ? Mongoid.persist_in_safe_mode : safe
@@ -9,14 +9,20 @@ module Mongoid #:nodoc:
9
9
 
10
10
  # Execute the following class-level persistence operation in safe mode.
11
11
  #
12
- # Example:
12
+ # @example Upsert in safe mode.
13
+ # person.safely.upsert
13
14
  #
14
- # <tt>person.safely.upsert</tt>
15
- # <tt>person.safely(:w => 2, :fsync => true).destroy</tt>
15
+ # @example Destroy in safe mode with w and fsync options.
16
+ # person.safely(:w => 2, :fsync => true).destroy
16
17
  #
17
- # Returns:
18
+ # @param [ Hash ] options The safe mode options.
18
19
  #
19
- # A +Proxy+ to the +Document+.
20
+ # @option options [ Integer ] :w The number of nodes to write to.
21
+ # @option options [ Integer ] :wtimeout Time to wait for return from all
22
+ # nodes.
23
+ # @option options [ true, false ] :fsync Should a fsync occur.
24
+ #
25
+ # @return [ Proxy ] The safety proxy.
20
26
  def safely(safety = true)
21
27
  Proxy.new(self, safety)
22
28
  end
@@ -25,14 +31,20 @@ module Mongoid #:nodoc:
25
31
 
26
32
  # Execute the following class-level persistence operation in safe mode.
27
33
  #
28
- # Example:
34
+ # @example Create in safe mode.
35
+ # Person.safely.create(:name => "John")
36
+ #
37
+ # @example Delete all in safe mode with options.
38
+ # Person.safely(:w => 2, :fsync => true).delete_all
29
39
  #
30
- # <tt>Person.safely.create(:name => "John")</tt>
31
- # <tt>Person.safely(:w => 2, :fsync => true).delete_all</tt>
40
+ # @param [ Hash ] options The safe mode options.
32
41
  #
33
- # Returns:
42
+ # @option options [ Integer ] :w The number of nodes to write to.
43
+ # @option options [ Integer ] :wtimeout Time to wait for return from all
44
+ # nodes.
45
+ # @option options [ true, false ] :fsync Should a fsync occur.
34
46
  #
35
- # A +Proxy+ to the +Document+ class.
47
+ # @return [ Proxy ] The safety proxy.
36
48
  def safely(safety = true)
37
49
  Proxy.new(self, safety)
38
50
  end
@@ -50,132 +62,145 @@ module Mongoid #:nodoc:
50
62
 
51
63
  attr_reader :target, :safety_options
52
64
 
53
- # Create the new +Proxy+.
65
+ # Create a new +Document+. This will instantiate a new document and
66
+ # insert it in a single call. Will always return the document
67
+ # whether save passed or not.
54
68
  #
55
- # Options:
69
+ # @example Safely create a document.
70
+ # Person.safely.create(:title => "Mr")
56
71
  #
57
- # target: Either the class or the instance.
58
- # safety_options: true or a hash of options
59
- def initialize(target, safety_options)
60
- @target = target
61
- @safety_options = safety_options
72
+ # @param [ Hash ] attributes The attributes to create with.
73
+ #
74
+ # @return [ Document ] The new document.
75
+ def create(attributes = {})
76
+ target.new(attributes).tap { |doc| doc.insert(:safe => safety_options) }
62
77
  end
63
78
 
64
- # We will use method missing to proxy calls to the target.
79
+ # Create a new +Document+. This will instantiate a new document and
80
+ # insert it in a single call. Will always return the document
81
+ # whether save passed or not, and if validation fails an error will be
82
+ # raise.
65
83
  #
66
- # Example:
84
+ # @example Safely create a document.
85
+ # Person.safely.create!(:title => "Mr")
67
86
  #
68
- # <tt>person.safely.save</tt>
69
- def method_missing(*args)
70
- name = args[0]
71
- attributes = args[1] || {}
72
- @target.send(name, attributes.merge(:safe => safety_options))
73
- end
74
-
75
- # Increment the field by the provided value, else if it doesn't exists set
76
- # it to that value.
87
+ # @param [ Hash ] attributes The attributes to create with.
77
88
  #
78
- # Options:
89
+ # @raise [ Errors::Validations ] If validation failed.
79
90
  #
80
- # field: The field to increment.
81
- # value: The value to increment by.
82
- # options: Options to pass through to the driver.
83
- def inc(field, value, options = {})
84
- @target.inc(field, value, :safe => safety_options)
91
+ # @return [ Document ] If validation passed.
92
+ def create!(attributes = {})
93
+ target.new(attributes).tap do |document|
94
+ fail_validate!(document) if document.insert(:safe => safety_options).errors.any?
95
+ end
85
96
  end
86
97
 
87
- # Update the +Document+ attributes in the datbase.
98
+ # Delete all documents given the supplied conditions. If no conditions
99
+ # are passed, the entire collection will be dropped for performance
100
+ # benefits. Does not fire any callbacks.
88
101
  #
89
- # Example:
102
+ # @example Delete all documents.
103
+ # Person.safely.delete_all
90
104
  #
91
- # <tt>document.update_attributes(:title => "Sir")</tt>
105
+ # @example Conditionally delete all documents.
106
+ # Person.safely.delete_all(:conditions => { :title => "Sir" })
92
107
  #
93
- # Returns:
108
+ # @param [ Hash ] conditions The conditions to delete with.
94
109
  #
95
- # +true+ if validation passed, +false+ if not.
96
- def update_attributes(attributes = {})
97
- @target.write_attributes(attributes)
98
- @target.update(:safe => safety_options)
110
+ # @return [ Integer ] The number of documents deleted.
111
+ def delete_all(conditions = {})
112
+ Mongoid::Persistence::RemoveAll.new(
113
+ target,
114
+ { :validate => false, :safe => safety_options },
115
+ conditions[:conditions] || {}
116
+ ).persist
99
117
  end
100
118
 
101
- # Update the +Document+ attributes in the datbase.
119
+ # destroy all documents given the supplied conditions. If no conditions
120
+ # are passed, the entire collection will be dropped for performance
121
+ # benefits. Fires the destroy callbacks if conditions were passed.
102
122
  #
103
- # Example:
123
+ # @example destroy all documents.
124
+ # Person.safely.destroy_all
104
125
  #
105
- # <tt>document.update_attributes(:title => "Sir")</tt>
126
+ # @example Conditionally destroy all documents.
127
+ # Person.safely.destroy_all(:conditions => { :title => "Sir" })
106
128
  #
107
- # Returns:
129
+ # @param [ Hash ] conditions The conditions to destroy with.
108
130
  #
109
- # +true+ if validation passed, raises an error if not
110
- def update_attributes!(attributes = {})
111
- @target.write_attributes(attributes)
112
- result = update(:safe => safety_options)
113
- @target.class.fail_validate!(self) unless result
114
- result
131
+ # @return [ Integer ] The number of documents destroyd.
132
+ def destroy_all(conditions = {})
133
+ documents = target.all(conditions)
134
+ documents.count.tap do |count|
135
+ documents.each { |doc| doc.destroy(:safe => safety_options) }
136
+ end
115
137
  end
116
138
 
117
- # Create a new +Document+. This will instantiate a new document and
118
- # insert it in a single call. Will always return the document
119
- # whether save passed or not.
120
- #
121
- # Example:
139
+ # Increment the field by the provided value, else if it doesn't exists set
140
+ # it to that value.
122
141
  #
123
- # <tt>Person.create(:title => "Mr")</tt>
142
+ # @example Safely increment a field.
143
+ # person.safely.inc(:age, 1)
124
144
  #
125
- # Returns: the +Document+.
126
- def create(attributes = {})
127
- @target.new(attributes).tap { |doc| doc.insert(:safe => safety_options) }
145
+ # @param [ Symbol, String ] field The field to increment.
146
+ # @param [ Integer ] value The value to increment by.
147
+ # @param [ Hash ] options Options to pass through to the driver.
148
+ def inc(field, value, options = {})
149
+ target.inc(field, value, :safe => safety_options)
128
150
  end
129
151
 
130
- # Create a new +Document+. This will instantiate a new document and
131
- # insert it in a single call. Will always return the document
132
- # whether save passed or not, and if validation fails an error will be
133
- # raise.
152
+ # Create the new +Proxy+.
153
+ #
154
+ # @example Create the proxy.
155
+ # Proxy.new(document, :w => 3)
134
156
  #
135
- # Example:
157
+ # @param [ Document, Class ] target Either the class or the instance.
158
+ # @param [ true, Hash ] safety_options The options.
159
+ def initialize(target, safety_options)
160
+ @target = target
161
+ @safety_options = safety_options
162
+ end
163
+
164
+ # We will use method missing to proxy calls to the target.
136
165
  #
137
- # <tt>Person.create!(:title => "Mr")</tt>
166
+ # @example Save safely.
167
+ # person.safely.save
138
168
  #
139
- # Returns: the +Document+.
140
- def create!(attributes = {})
141
- document = @target.new(attributes)
142
- fail_validate!(document) if document.insert(:safe => safety_options).errors.any?
143
- document
169
+ # @param [ Array ] *args The arguments to pass on.
170
+ def method_missing(*args)
171
+ name = args[0]
172
+ attributes = args[1] || {}
173
+ target.send(name, attributes.merge(:safe => safety_options))
144
174
  end
145
175
 
146
- # Delete all documents given the supplied conditions. If no conditions
147
- # are passed, the entire collection will be dropped for performance
148
- # benefits. Does not fire any callbacks.
176
+ # Update the +Document+ attributes in the datbase.
149
177
  #
150
- # Example:
178
+ # @example Safely update attributes.
179
+ # person.safely.update_attributes(:title => "Sir")
151
180
  #
152
- # <tt>Person.delete_all(:conditions => { :title => "Sir" })</tt>
153
- # <tt>Person.delete_all</tt>
181
+ # @param [ Hash ] attributes The attributes to update.
154
182
  #
155
- # Returns: true or raises an error.
156
- def delete_all(conditions = {})
157
- Mongoid::Persistence::RemoveAll.new(
158
- @target,
159
- { :validate => false, :safe => safety_options },
160
- conditions[:conditions] || {}
161
- ).persist
183
+ # @return [ true, false ] Whether the document was saved.
184
+ def update_attributes(attributes = {})
185
+ target.write_attributes(attributes)
186
+ target.update(:safe => safety_options)
162
187
  end
163
188
 
164
- # Delete all documents given the supplied conditions. If no conditions
165
- # are passed, the entire collection will be dropped for performance
166
- # benefits. Fires the destroy callbacks if conditions were passed.
189
+ # Update the +Document+ attributes in the datbase.
167
190
  #
168
- # Example:
191
+ # @example Safely update attributes.
192
+ # person.safely.update_attributes(:title => "Sir")
169
193
  #
170
- # <tt>Person.destroy_all(:conditions => { :title => "Sir" })</tt>
171
- # <tt>Person.destroy_all</tt>
194
+ # @param [ Hash ] attributes The attributes to update.
172
195
  #
173
- # Returns: true or raises an error.
174
- def destroy_all(conditions = {})
175
- documents = @target.all(conditions)
176
- count = documents.count
177
- documents.each { |doc| doc.destroy(:safe => safety_options) }
178
- count
196
+ # @raise [ Errors::Validations ] If validation failed.
197
+ #
198
+ # @return [ true ] If the document was saved.
199
+ def update_attributes!(attributes = {})
200
+ target.write_attributes(attributes)
201
+ update(:safe => safety_options).tap do |result|
202
+ target.class.fail_validate!(self) unless result
203
+ end
179
204
  end
180
205
  end
181
206
  end