mongoid 2.0.0.alpha → 2.0.0.beta.5

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 (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