mongoid 2.0.0.alpha → 2.0.0.beta.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. data/lib/mongoid.rb +11 -5
  2. data/lib/mongoid/associations.rb +112 -107
  3. data/lib/mongoid/associations/belongs_to_related.rb +2 -3
  4. data/lib/mongoid/associations/embedded_in.rb +12 -4
  5. data/lib/mongoid/associations/{embed_many.rb → embeds_many.rb} +101 -32
  6. data/lib/mongoid/associations/{embed_one.rb → embeds_one.rb} +10 -10
  7. data/lib/mongoid/associations/has_many_related.rb +51 -5
  8. data/lib/mongoid/associations/has_one_related.rb +9 -5
  9. data/lib/mongoid/associations/meta_data.rb +2 -1
  10. data/lib/mongoid/associations/options.rb +15 -6
  11. data/lib/mongoid/associations/proxy.rb +14 -21
  12. data/lib/mongoid/attributes.rb +34 -13
  13. data/lib/mongoid/callbacks.rb +1 -2
  14. data/lib/mongoid/collection.rb +4 -3
  15. data/lib/mongoid/collections.rb +41 -0
  16. data/lib/mongoid/collections/master.rb +3 -2
  17. data/lib/mongoid/collections/slaves.rb +3 -2
  18. data/lib/mongoid/components.rb +4 -1
  19. data/lib/mongoid/config.rb +163 -13
  20. data/lib/mongoid/contexts.rb +1 -2
  21. data/lib/mongoid/contexts/enumerable.rb +1 -1
  22. data/lib/mongoid/contexts/mongo.rb +1 -1
  23. data/lib/mongoid/contexts/paging.rb +10 -2
  24. data/lib/mongoid/criteria.rb +13 -22
  25. data/lib/mongoid/criterion/exclusion.rb +3 -3
  26. data/lib/mongoid/criterion/inclusion.rb +17 -0
  27. data/lib/mongoid/criterion/optional.rb +1 -1
  28. data/lib/mongoid/dirty.rb +253 -0
  29. data/lib/mongoid/document.rb +40 -85
  30. data/lib/mongoid/errors.rb +48 -1
  31. data/lib/mongoid/extensions.rb +11 -9
  32. data/lib/mongoid/extensions/big_decimal/conversions.rb +2 -2
  33. data/lib/mongoid/extensions/boolean/conversions.rb +8 -2
  34. data/lib/mongoid/extensions/date/conversions.rb +13 -4
  35. data/lib/mongoid/extensions/datetime/conversions.rb +1 -6
  36. data/lib/mongoid/extensions/float/conversions.rb +5 -1
  37. data/lib/mongoid/extensions/hash/assimilation.rb +12 -3
  38. data/lib/mongoid/extensions/hash/conversions.rb +34 -4
  39. data/lib/mongoid/extensions/integer/conversions.rb +5 -1
  40. data/lib/mongoid/extensions/nil/assimilation.rb +4 -0
  41. data/lib/mongoid/extensions/object/conversions.rb +3 -3
  42. data/lib/mongoid/extensions/string/conversions.rb +1 -1
  43. data/lib/mongoid/extensions/symbol/inflections.rb +5 -2
  44. data/lib/mongoid/extensions/time_conversions.rb +35 -0
  45. data/lib/mongoid/factory.rb +2 -1
  46. data/lib/mongoid/field.rb +15 -2
  47. data/lib/mongoid/fields.rb +1 -1
  48. data/lib/mongoid/identity.rb +3 -3
  49. data/lib/mongoid/indexes.rb +3 -3
  50. data/lib/mongoid/matchers.rb +1 -2
  51. data/lib/mongoid/memoization.rb +8 -2
  52. data/lib/mongoid/named_scope.rb +0 -5
  53. data/lib/mongoid/observable.rb +1 -1
  54. data/lib/mongoid/paths.rb +30 -22
  55. data/lib/mongoid/persistence.rb +218 -0
  56. data/lib/mongoid/persistence/command.rb +39 -0
  57. data/lib/mongoid/persistence/insert.rb +47 -0
  58. data/lib/mongoid/persistence/insert_embedded.rb +38 -0
  59. data/lib/mongoid/persistence/remove.rb +39 -0
  60. data/lib/mongoid/persistence/remove_all.rb +37 -0
  61. data/lib/mongoid/persistence/remove_embedded.rb +50 -0
  62. data/lib/mongoid/persistence/update.rb +63 -0
  63. data/lib/mongoid/railtie.rb +53 -0
  64. data/lib/mongoid/railties/database.rake +37 -0
  65. data/lib/mongoid/timestamps.rb +2 -2
  66. data/lib/mongoid/validations.rb +2 -2
  67. data/lib/mongoid/validations/associated.rb +2 -2
  68. data/lib/mongoid/validations/uniqueness.rb +13 -2
  69. data/lib/mongoid/version.rb +4 -0
  70. data/lib/mongoid/versioning.rb +3 -2
  71. data/lib/rails/generators/mongoid/config/config_generator.rb +41 -0
  72. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
  73. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  74. data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
  75. data/lib/rails/generators/mongoid_generator.rb +61 -0
  76. metadata +76 -301
  77. data/.gitignore +0 -6
  78. data/.watchr +0 -29
  79. data/Rakefile +0 -52
  80. data/VERSION +0 -1
  81. data/caliper.yml +0 -4
  82. data/lib/mongoid/collections/mimic.rb +0 -46
  83. data/lib/mongoid/commands.rb +0 -161
  84. data/lib/mongoid/commands/create.rb +0 -19
  85. data/lib/mongoid/commands/delete.rb +0 -16
  86. data/lib/mongoid/commands/delete_all.rb +0 -23
  87. data/lib/mongoid/commands/deletion.rb +0 -18
  88. data/lib/mongoid/commands/destroy.rb +0 -17
  89. data/lib/mongoid/commands/destroy_all.rb +0 -23
  90. data/lib/mongoid/commands/save.rb +0 -29
  91. data/lib/mongoid/extensions/time/conversions.rb +0 -18
  92. data/mongoid.gemspec +0 -408
  93. data/perf/benchmark.rb +0 -77
  94. data/spec/integration/mongoid/associations_spec.rb +0 -340
  95. data/spec/integration/mongoid/attributes_spec.rb +0 -22
  96. data/spec/integration/mongoid/commands_spec.rb +0 -227
  97. data/spec/integration/mongoid/contexts/enumerable_spec.rb +0 -33
  98. data/spec/integration/mongoid/criteria_spec.rb +0 -272
  99. data/spec/integration/mongoid/document_spec.rb +0 -650
  100. data/spec/integration/mongoid/extensions_spec.rb +0 -22
  101. data/spec/integration/mongoid/finders_spec.rb +0 -119
  102. data/spec/integration/mongoid/inheritance_spec.rb +0 -137
  103. data/spec/integration/mongoid/named_scope_spec.rb +0 -46
  104. data/spec/models/address.rb +0 -39
  105. data/spec/models/animal.rb +0 -6
  106. data/spec/models/callbacks.rb +0 -18
  107. data/spec/models/comment.rb +0 -8
  108. data/spec/models/country_code.rb +0 -6
  109. data/spec/models/employer.rb +0 -5
  110. data/spec/models/game.rb +0 -7
  111. data/spec/models/inheritance.rb +0 -56
  112. data/spec/models/location.rb +0 -5
  113. data/spec/models/mixed_drink.rb +0 -4
  114. data/spec/models/name.rb +0 -13
  115. data/spec/models/namespacing.rb +0 -11
  116. data/spec/models/patient.rb +0 -4
  117. data/spec/models/person.rb +0 -99
  118. data/spec/models/pet.rb +0 -7
  119. data/spec/models/pet_owner.rb +0 -6
  120. data/spec/models/phone.rb +0 -7
  121. data/spec/models/post.rb +0 -15
  122. data/spec/models/translation.rb +0 -5
  123. data/spec/models/vet_visit.rb +0 -5
  124. data/spec/spec.opts +0 -3
  125. data/spec/spec_helper.rb +0 -31
  126. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +0 -145
  127. data/spec/unit/mongoid/associations/embed_many_spec.rb +0 -516
  128. data/spec/unit/mongoid/associations/embed_one_spec.rb +0 -282
  129. data/spec/unit/mongoid/associations/embedded_in_spec.rb +0 -193
  130. data/spec/unit/mongoid/associations/has_many_related_spec.rb +0 -418
  131. data/spec/unit/mongoid/associations/has_one_related_spec.rb +0 -179
  132. data/spec/unit/mongoid/associations/meta_data_spec.rb +0 -88
  133. data/spec/unit/mongoid/associations/options_spec.rb +0 -192
  134. data/spec/unit/mongoid/associations_spec.rb +0 -595
  135. data/spec/unit/mongoid/attributes_spec.rb +0 -507
  136. data/spec/unit/mongoid/callbacks_spec.rb +0 -55
  137. data/spec/unit/mongoid/collection_spec.rb +0 -187
  138. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +0 -75
  139. data/spec/unit/mongoid/collections/master_spec.rb +0 -41
  140. data/spec/unit/mongoid/collections/mimic_spec.rb +0 -43
  141. data/spec/unit/mongoid/collections/slaves_spec.rb +0 -81
  142. data/spec/unit/mongoid/commands/create_spec.rb +0 -31
  143. data/spec/unit/mongoid/commands/delete_all_spec.rb +0 -58
  144. data/spec/unit/mongoid/commands/delete_spec.rb +0 -38
  145. data/spec/unit/mongoid/commands/destroy_all_spec.rb +0 -21
  146. data/spec/unit/mongoid/commands/destroy_spec.rb +0 -51
  147. data/spec/unit/mongoid/commands/save_spec.rb +0 -107
  148. data/spec/unit/mongoid/commands_spec.rb +0 -270
  149. data/spec/unit/mongoid/config_spec.rb +0 -172
  150. data/spec/unit/mongoid/contexts/enumerable_spec.rb +0 -421
  151. data/spec/unit/mongoid/contexts/mongo_spec.rb +0 -682
  152. data/spec/unit/mongoid/contexts_spec.rb +0 -25
  153. data/spec/unit/mongoid/criteria_spec.rb +0 -824
  154. data/spec/unit/mongoid/criterion/complex_spec.rb +0 -19
  155. data/spec/unit/mongoid/criterion/exclusion_spec.rb +0 -91
  156. data/spec/unit/mongoid/criterion/inclusion_spec.rb +0 -219
  157. data/spec/unit/mongoid/criterion/optional_spec.rb +0 -319
  158. data/spec/unit/mongoid/cursor_spec.rb +0 -74
  159. data/spec/unit/mongoid/deprecation_spec.rb +0 -24
  160. data/spec/unit/mongoid/document_spec.rb +0 -818
  161. data/spec/unit/mongoid/errors_spec.rb +0 -103
  162. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +0 -50
  163. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +0 -24
  164. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +0 -35
  165. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +0 -20
  166. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +0 -22
  167. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +0 -22
  168. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +0 -49
  169. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +0 -102
  170. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +0 -67
  171. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +0 -61
  172. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +0 -184
  173. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +0 -46
  174. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +0 -21
  175. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +0 -17
  176. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +0 -14
  177. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +0 -61
  178. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +0 -24
  179. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +0 -57
  180. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +0 -34
  181. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +0 -17
  182. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +0 -208
  183. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +0 -91
  184. data/spec/unit/mongoid/extensions/time/conversions_spec.rb +0 -70
  185. data/spec/unit/mongoid/extras_spec.rb +0 -102
  186. data/spec/unit/mongoid/factory_spec.rb +0 -31
  187. data/spec/unit/mongoid/field_spec.rb +0 -143
  188. data/spec/unit/mongoid/fields_spec.rb +0 -181
  189. data/spec/unit/mongoid/finders_spec.rb +0 -404
  190. data/spec/unit/mongoid/identity_spec.rb +0 -109
  191. data/spec/unit/mongoid/indexes_spec.rb +0 -93
  192. data/spec/unit/mongoid/javascript_spec.rb +0 -48
  193. data/spec/unit/mongoid/matchers/all_spec.rb +0 -27
  194. data/spec/unit/mongoid/matchers/default_spec.rb +0 -27
  195. data/spec/unit/mongoid/matchers/exists_spec.rb +0 -56
  196. data/spec/unit/mongoid/matchers/gt_spec.rb +0 -39
  197. data/spec/unit/mongoid/matchers/gte_spec.rb +0 -49
  198. data/spec/unit/mongoid/matchers/in_spec.rb +0 -27
  199. data/spec/unit/mongoid/matchers/lt_spec.rb +0 -39
  200. data/spec/unit/mongoid/matchers/lte_spec.rb +0 -49
  201. data/spec/unit/mongoid/matchers/ne_spec.rb +0 -27
  202. data/spec/unit/mongoid/matchers/nin_spec.rb +0 -27
  203. data/spec/unit/mongoid/matchers/size_spec.rb +0 -27
  204. data/spec/unit/mongoid/matchers_spec.rb +0 -329
  205. data/spec/unit/mongoid/memoization_spec.rb +0 -75
  206. data/spec/unit/mongoid/named_scope_spec.rb +0 -123
  207. data/spec/unit/mongoid/observable_spec.rb +0 -46
  208. data/spec/unit/mongoid/paths_spec.rb +0 -124
  209. data/spec/unit/mongoid/scope_spec.rb +0 -240
  210. data/spec/unit/mongoid/state_spec.rb +0 -83
  211. data/spec/unit/mongoid/timestamps_spec.rb +0 -25
  212. data/spec/unit/mongoid/validations/associated_spec.rb +0 -103
  213. data/spec/unit/mongoid/validations/uniqueness_spec.rb +0 -47
  214. data/spec/unit/mongoid/validations_spec.rb +0 -190
  215. data/spec/unit/mongoid/versioning_spec.rb +0 -41
  216. data/spec/unit/mongoid_spec.rb +0 -46
@@ -15,19 +15,19 @@ module Mongoid #:nodoc:
15
15
  protected
16
16
  # Return the proper id for the document.
17
17
  def generate_id
18
- id = Mongo::ObjectID.new
18
+ id = BSON::ObjectID.new
19
19
  Mongoid.use_object_ids ? id : id.to_s
20
20
  end
21
21
 
22
22
  # Set the id for the document.
23
23
  def identify(doc)
24
24
  doc.id = compose(doc).join(" ").identify if doc.primary_key
25
- doc.id = generate_id unless doc.id
25
+ doc.id = generate_id if doc.id.blank?
26
26
  end
27
27
 
28
28
  # Set the _type field on the document.
29
29
  def type(doc)
30
- doc._type = doc.class.name if Mongoid.persist_types
30
+ doc._type = doc.class.name if doc.hereditary?
31
31
  end
32
32
 
33
33
  # Generates the composite key for a document.
@@ -11,8 +11,8 @@ module Mongoid #:nodoc
11
11
  # Add the default indexes to the root document if they do not already
12
12
  # exist. Currently this is only _type.
13
13
  def add_indexes
14
- unless indexed
15
- self._collection.create_index(:_type, false)
14
+ if hereditary && !indexed
15
+ self._collection.create_index(:_type, :unique => false, :background => true)
16
16
  self.indexed = true
17
17
  end
18
18
  end
@@ -20,7 +20,7 @@ module Mongoid #:nodoc
20
20
  # Adds an index on the field specified. Options can be :unique => true or
21
21
  # :unique => false. It will default to the latter.
22
22
  def index(name, options = { :unique => false })
23
- collection.create_index(name, options[:unique])
23
+ collection.create_index(name, options)
24
24
  end
25
25
  end
26
26
  end
@@ -18,8 +18,7 @@ module Mongoid #:nodoc:
18
18
  def matches?(selector)
19
19
  selector.each_pair do |key, value|
20
20
  return false unless matcher(key, value).matches?(value)
21
- end
22
- true
21
+ end; true
23
22
  end
24
23
 
25
24
  protected
@@ -2,14 +2,20 @@ module Mongoid #:nodoc
2
2
  module Memoization
3
3
 
4
4
  # Handles cases when accessing an association that should be memoized in
5
- # the Mongoid specific manner.
5
+ # the Mongoid specific manner. Does not memoize nil values though
6
6
  def memoized(name, &block)
7
7
  var = "@#{name}"
8
8
  if instance_variable_defined?(var)
9
9
  return instance_variable_get(var)
10
10
  end
11
11
  value = yield
12
- instance_variable_set(var, value)
12
+ instance_variable_set(var, value) if value
13
+ end
14
+
15
+ # Removes an memozied association if it exists
16
+ def unmemoize(name)
17
+ var = "@#{name}"
18
+ remove_instance_variable(var) if instance_variable_defined?(var)
13
19
  end
14
20
 
15
21
  # Mongoid specific behavior is to remove the memoized object when setting
@@ -27,16 +27,11 @@ module Mongoid #:nodoc:
27
27
  end
28
28
  EOT
29
29
  end
30
-
31
- alias :scope :named_scope
32
-
33
30
  alias :scope :named_scope
34
31
 
35
32
  # Return the scopes or default to an empty +Hash+.
36
33
  def scopes
37
34
  read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
38
35
  end
39
-
40
36
  end
41
37
  end
42
-
@@ -24,7 +24,7 @@ module Mongoid #:nodoc:
24
24
  #
25
25
  # <tt>document.notify_observers(self)</tt>
26
26
  def notify_observers(*args)
27
- @observers.dup.each { |observer| observer.update(*args) } if @observers
27
+ @observers.dup.each { |observer| observer.observe(*args) } if @observers
28
28
  end
29
29
  end
30
30
  end
@@ -3,29 +3,49 @@ module Mongoid #:nodoc:
3
3
  module Paths #:nodoc:
4
4
  extend ActiveSupport::Concern
5
5
  included do
6
- cattr_accessor :_path, :_position
7
- delegate :_path, :_position, :to => "self.class"
6
+ cattr_accessor :__path
7
+ attr_accessor :_index
8
8
  end
9
9
  module InstanceMethods
10
+ # Get the insertion modifier for the document. Will be nil on root
11
+ # documents, $set on embeds_one, $push on embeds_many.
12
+ #
13
+ # Example:
14
+ #
15
+ # <tt>name.inserter</tt>
16
+ def _inserter
17
+ embedded? ? (embedded_many? ? "$push" : "$set") : nil
18
+ end
19
+
10
20
  # Return the path to this +Document+ in JSON notation, used for atomic
11
21
  # updates via $set in MongoDB.
12
22
  #
13
23
  # Example:
14
24
  #
15
25
  # <tt>address.path # returns "addresses"</tt>
16
- def path
17
- self._path ||= climb("") do |document, value|
18
- value = "#{document.association_name}#{"." + value unless value.blank?}"
19
- end
26
+ def _path
27
+ _position.sub!(/\.\d+$/, '') || _position
20
28
  end
29
+ alias :_pull :_path
21
30
 
22
31
  # Returns the positional operator of this document for modification.
23
32
  #
24
33
  # Example:
25
34
  #
26
35
  # <tt>address.position</tt>
27
- def position
28
- self._position ||= (path.blank? ? "" : "#{path}.$")
36
+ def _position
37
+ locator = _index ? (new_record? ? "" : ".#{_index}") : ""
38
+ embedded? ? "#{_parent._position}#{"." unless _parent._position.blank?}#{@association_name}#{locator}" : ""
39
+ end
40
+
41
+ # Get the removal modifier for the document. Will be nil on root
42
+ # documents, $unset on embeds_one, $set on embeds_many.
43
+ #
44
+ # Example:
45
+ #
46
+ # <tt>name.remover</tt>
47
+ def _remover
48
+ embedded? ? (_index ? "$pull" : "$unset") : nil
29
49
  end
30
50
 
31
51
  # Return the selector for this document to be matched exactly for use
@@ -34,20 +54,8 @@ module Mongoid #:nodoc:
34
54
  # Example:
35
55
  #
36
56
  # <tt>address.selector</tt>
37
- def selector
38
- @selector ||= climb({ "_id" => _root.id }) do |document, value|
39
- value["#{document.path}._id"] = document.id; value
40
- end
41
- end
42
-
43
- protected
44
- def climb(value, &block)
45
- document = self;
46
- while (document._parent) do
47
- value = yield document, value
48
- document = document._parent
49
- end
50
- value
57
+ def _selector
58
+ embedded? ? _parent._selector.merge("#{_path}._id" => id) : { "_id" => id }
51
59
  end
52
60
  end
53
61
  end
@@ -0,0 +1,218 @@
1
+ # encoding: utf-8
2
+ require "mongoid/persistence/command"
3
+ require "mongoid/persistence/insert"
4
+ require "mongoid/persistence/insert_embedded"
5
+ require "mongoid/persistence/remove"
6
+ require "mongoid/persistence/remove_all"
7
+ require "mongoid/persistence/remove_embedded"
8
+ require "mongoid/persistence/update"
9
+
10
+ module Mongoid #:nodoc:
11
+ # The persistence module is a mixin to provide database accessor methods for
12
+ # the document. These correspond to the appropriate accessors on a
13
+ # +Mongo::Collection+ and retain the same DSL.
14
+ #
15
+ # Examples:
16
+ #
17
+ # <tt>document.insert</tt>
18
+ # <tt>document.update</tt>
19
+ # <tt>document.upsert</tt>
20
+ module Persistence
21
+ extend ActiveSupport::Concern
22
+ module InstanceMethods #:nodoc:
23
+ # Remove the +Document+ from the datbase with callbacks.
24
+ #
25
+ # Example:
26
+ #
27
+ # <tt>document.destroy</tt>
28
+ #
29
+ # TODO: Will get rid of other #destroy once new persistence complete.
30
+ def destroy
31
+ run_callbacks(:destroy) { self.destroyed = true if _remove }
32
+ end
33
+
34
+ # Insert a new +Document+ into the database. Will return the document
35
+ # itself whether or not the save was successful.
36
+ #
37
+ # Example:
38
+ #
39
+ # <tt>document.insert</tt>
40
+ def insert(validate = true)
41
+ Insert.new(self, validate).persist
42
+ end
43
+
44
+ # Remove the +Document+ from the datbase.
45
+ #
46
+ # Example:
47
+ #
48
+ # <tt>document._remove</tt>
49
+ #
50
+ # TODO: Will get rid of other #remove once observable pattern killed.
51
+ def _remove
52
+ Remove.new(self).persist
53
+ end
54
+
55
+ alias :delete :_remove
56
+
57
+ # Save the document - will perform an insert if the document is new, and
58
+ # update if not. If a validation error occurs a
59
+ # Mongoid::Errors::Validations error will get raised.
60
+ #
61
+ # Example:
62
+ #
63
+ # <tt>document.save!</tt>
64
+ #
65
+ # Returns:
66
+ #
67
+ # +true+ if validation passed, will raise error otherwise.
68
+ def save!
69
+ self.class.fail_validate!(self) unless upsert; true
70
+ end
71
+
72
+ # Update the +Document+ in the datbase.
73
+ #
74
+ # Example:
75
+ #
76
+ # <tt>document.update</tt>
77
+ def update(validate = true)
78
+ Update.new(self, validate).persist
79
+ end
80
+
81
+ # Update the +Document+ attributes in the datbase.
82
+ #
83
+ # Example:
84
+ #
85
+ # <tt>document.update_attributes(:title => "Sir")</tt>
86
+ #
87
+ # Returns:
88
+ #
89
+ # +true+ if validation passed, +false+ if not.
90
+ def update_attributes(attributes = {})
91
+ write_attributes(attributes); update
92
+ end
93
+
94
+ # Update the +Document+ attributes in the datbase.
95
+ #
96
+ # Example:
97
+ #
98
+ # <tt>document.update_attributes(:title => "Sir")</tt>
99
+ #
100
+ # Returns:
101
+ #
102
+ # +true+ if validation passed, raises an error if not
103
+ def update_attributes!(attributes = {})
104
+ write_attributes(attributes)
105
+ result = update
106
+ self.class.fail_validate!(self) unless result
107
+ result
108
+ end
109
+
110
+ # Upsert the document - will perform an insert if the document is new, and
111
+ # update if not.
112
+ #
113
+ # Example:
114
+ #
115
+ # <tt>document.upsert</tt>
116
+ #
117
+ # Returns:
118
+ #
119
+ # A +Boolean+ for updates.
120
+ def upsert(validate = true)
121
+ validate = parse_validate(validate)
122
+ if new_record?
123
+ insert(validate).persisted?
124
+ else
125
+ update(validate)
126
+ end
127
+ end
128
+
129
+ # Save is aliased so that users familiar with active record can have some
130
+ # semblance of a familiar API.
131
+ #
132
+ # Example:
133
+ #
134
+ # <tt>document.save</tt>
135
+ alias :save :upsert
136
+
137
+ protected
138
+ # Alternative validation params.
139
+ def parse_validate(validate)
140
+ if validate.is_a?(Hash) && validate.has_key?(:validate)
141
+ validate = validate[:validate]
142
+ end
143
+ validate
144
+ end
145
+ end
146
+
147
+ module ClassMethods #:nodoc:
148
+
149
+ # Create a new +Document+. This will instantiate a new document and
150
+ # insert it in a single call. Will always return the document
151
+ # whether save passed or not.
152
+ #
153
+ # Example:
154
+ #
155
+ # <tt>Person.create(:title => "Mr")</tt>
156
+ #
157
+ # Returns: the +Document+.
158
+ def create(attributes = {})
159
+ new(attributes).tap(&:insert)
160
+ end
161
+
162
+ # Create a new +Document+. This will instantiate a new document and
163
+ # insert it in a single call. Will always return the document
164
+ # whether save passed or not, and if validation fails an error will be
165
+ # raise.
166
+ #
167
+ # Example:
168
+ #
169
+ # <tt>Person.create!(:title => "Mr")</tt>
170
+ #
171
+ # Returns: the +Document+.
172
+ def create!(attributes = {})
173
+ document = new(attributes)
174
+ fail_validate!(document) if document.insert.errors.any?
175
+ document
176
+ end
177
+
178
+ # Delete all documents given the supplied conditions. If no conditions
179
+ # are passed, the entire collection will be dropped for performance
180
+ # benefits. Does not fire any callbacks.
181
+ #
182
+ # Example:
183
+ #
184
+ # <tt>Person.delete_all(:conditions => { :title => "Sir" })</tt>
185
+ # <tt>Person.delete_all</tt>
186
+ #
187
+ # Returns: true or raises an error.
188
+ def delete_all(conditions = {})
189
+ RemoveAll.new(
190
+ self,
191
+ false,
192
+ conditions[:conditions] || {}
193
+ ).persist
194
+ end
195
+
196
+ # Delete all documents given the supplied conditions. If no conditions
197
+ # are passed, the entire collection will be dropped for performance
198
+ # benefits. Fires the destroy callbacks if conditions were passed.
199
+ #
200
+ # Example:
201
+ #
202
+ # <tt>Person.destroy_all(:conditions => { :title => "Sir" })</tt>
203
+ # <tt>Person.destroy_all</tt>
204
+ #
205
+ # Returns: true or raises an error.
206
+ def destroy_all(conditions = {})
207
+ documents = all(conditions)
208
+ count = documents.count
209
+ documents.each { |doc| doc.destroy }; count
210
+ end
211
+
212
+ # Raise an error if validation failed.
213
+ def fail_validate!(document)
214
+ raise Errors::Validations.new(document.errors)
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Persistence #:nodoc:
4
+ # Persistence commands extend from this class to get basic functionality on
5
+ # initialization.
6
+ class Command
7
+ attr_reader \
8
+ :collection,
9
+ :document,
10
+ :klass,
11
+ :options,
12
+ :selector,
13
+ :validate
14
+
15
+ # Initialize the persistence +Command+.
16
+ #
17
+ # Options:
18
+ #
19
+ # document_or_class: The +Document+ or +Class+ to get the collection.
20
+ # validate: Is the document to be validated.
21
+ # selector: Optional selector to use in query.
22
+ #
23
+ # Example:
24
+ #
25
+ # <tt>DeleteAll.new(Person, false, {})</tt>
26
+ def initialize(document_or_class, validate = true, selector = {})
27
+ if document_or_class.is_a?(Mongoid::Document)
28
+ @document = document_or_class
29
+ @collection = @document.embedded? ? @document._root.collection : @document.collection
30
+ else
31
+ @klass = document_or_class
32
+ @collection = @klass.collection
33
+ end
34
+ @selector, @validate = selector, validate
35
+ @options = { :safe => Mongoid.persist_in_safe_mode }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Persistence #:nodoc:
4
+ # Insert is a persistence command responsible for taking a document that
5
+ # has not been saved to the database and saving it.
6
+ #
7
+ # The underlying query resembles the following MongoDB query:
8
+ #
9
+ # collection.insert(
10
+ # { "_id" : 1, "field" : "value" },
11
+ # false
12
+ # );
13
+ class Insert < Command
14
+ # Insert the new document in the database. This delegates to the standard
15
+ # MongoDB collection's insert command.
16
+ #
17
+ # Example:
18
+ #
19
+ # <tt>Insert.persist</tt>
20
+ #
21
+ # Returns:
22
+ #
23
+ # The +Document+, whether the insert succeeded or not.
24
+ def persist
25
+ return @document if @validate && !@document.valid?
26
+ @document.run_callbacks(:create) do
27
+ @document.run_callbacks(:save) do
28
+ if insert
29
+ @document.new_record = false
30
+ @document.move_changes
31
+ end
32
+ end
33
+ end; @document
34
+ end
35
+
36
+ protected
37
+ # Insert the document into the database.
38
+ def insert
39
+ if @document.embedded?
40
+ Persistence::InsertEmbedded.new(@document, @validate).persist
41
+ else
42
+ @collection.insert(@document.raw_attributes, @options)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end