mongoid 2.2.0 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGELOG.md +57 -3
  2. data/Rakefile +1 -1
  3. data/lib/mongoid/atomic/modifiers.rb +2 -1
  4. data/lib/mongoid/config.rb +0 -1
  5. data/lib/mongoid/config/replset_database.rb +2 -2
  6. data/lib/mongoid/contexts/mongo.rb +14 -5
  7. data/lib/mongoid/criteria.rb +4 -4
  8. data/lib/mongoid/criterion/inclusion.rb +16 -1
  9. data/lib/mongoid/document.rb +2 -4
  10. data/lib/mongoid/extensions.rb +7 -0
  11. data/lib/mongoid/extensions/integer/checks.rb +23 -0
  12. data/lib/mongoid/extensions/object/yoda.rb +16 -0
  13. data/lib/mongoid/extensions/object_id/conversions.rb +1 -1
  14. data/lib/mongoid/extensions/string/checks.rb +24 -0
  15. data/lib/mongoid/extensions/string/inflections.rb +1 -1
  16. data/lib/mongoid/fields.rb +4 -2
  17. data/lib/mongoid/fields/serializable.rb +26 -18
  18. data/lib/mongoid/fields/serializable/array.rb +0 -1
  19. data/lib/mongoid/fields/serializable/boolean.rb +0 -1
  20. data/lib/mongoid/fields/serializable/float.rb +0 -1
  21. data/lib/mongoid/fields/serializable/integer.rb +1 -2
  22. data/lib/mongoid/fields/serializable/object_id.rb +0 -1
  23. data/lib/mongoid/fields/serializable/string.rb +0 -1
  24. data/lib/mongoid/fields/serializable/symbol.rb +0 -1
  25. data/lib/mongoid/matchers/strategies.rb +25 -2
  26. data/lib/mongoid/nested_attributes.rb +1 -1
  27. data/lib/mongoid/persistence/atomic.rb +2 -2
  28. data/lib/mongoid/persistence/atomic/{set.rb → sets.rb} +1 -1
  29. data/lib/mongoid/persistence/deletion.rb +1 -1
  30. data/lib/mongoid/relations/bindings/referenced/in.rb +5 -5
  31. data/lib/mongoid/relations/bindings/referenced/many.rb +4 -4
  32. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +2 -2
  33. data/lib/mongoid/relations/bindings/referenced/one.rb +4 -4
  34. data/lib/mongoid/relations/builder.rb +1 -2
  35. data/lib/mongoid/relations/builders/nested_attributes/many.rb +5 -4
  36. data/lib/mongoid/relations/builders/nested_attributes/one.rb +1 -1
  37. data/lib/mongoid/relations/builders/referenced/many.rb +4 -2
  38. data/lib/mongoid/relations/cascading/destroy.rb +8 -1
  39. data/lib/mongoid/relations/embedded/in.rb +1 -1
  40. data/lib/mongoid/relations/embedded/many.rb +15 -2
  41. data/lib/mongoid/relations/embedded/one.rb +1 -1
  42. data/lib/mongoid/relations/nested_builder.rb +11 -4
  43. data/lib/mongoid/relations/referenced/many.rb +4 -2
  44. data/lib/mongoid/relations/referenced/many_to_many.rb +2 -1
  45. data/lib/mongoid/relations/synchronization.rb +39 -2
  46. data/lib/mongoid/relations/targets/enumerable.rb +2 -2
  47. data/lib/mongoid/serialization.rb +1 -1
  48. data/lib/mongoid/state.rb +1 -1
  49. data/lib/mongoid/version.rb +1 -1
  50. data/lib/mongoid/versioning.rb +15 -1
  51. metadata +26 -22
  52. data/lib/mongoid/criterion/unconvertable.rb +0 -20
@@ -21,7 +21,6 @@ module Mongoid #:nodoc:
21
21
  def serialize(object)
22
22
  raise_or_return(object)
23
23
  end
24
- alias :set :serialize
25
24
 
26
25
  protected
27
26
 
@@ -37,7 +37,6 @@ module Mongoid #:nodoc:
37
37
  object = MAPPINGS[object]
38
38
  object.nil? ? nil : object
39
39
  end
40
- alias :set :serialize
41
40
  end
42
41
  end
43
42
  end
@@ -26,7 +26,6 @@ module Mongoid #:nodoc:
26
26
  object
27
27
  end
28
28
  end
29
- alias :set :serialize
30
29
  end
31
30
  end
32
31
  end
@@ -21,12 +21,11 @@ module Mongoid #:nodoc:
21
21
  def serialize(object)
22
22
  return nil if object.blank?
23
23
  begin
24
- object.to_s =~ /\./ ? Float(object) : Integer(object)
24
+ object.to_s =~ /(^[-+]?[0-9]+$)|(\.0+)$/ ? Integer(object) : Float(object)
25
25
  rescue
26
26
  object
27
27
  end
28
28
  end
29
- alias :set :serialize
30
29
  end
31
30
  end
32
31
  end
@@ -25,7 +25,6 @@ module Mongoid #:nodoc:
25
25
  object
26
26
  end
27
27
  end
28
- alias :set :serialize
29
28
  end
30
29
  end
31
30
  end
@@ -21,7 +21,6 @@ module Mongoid #:nodoc:
21
21
  def serialize(object)
22
22
  object.try(:to_s)
23
23
  end
24
- alias :set :serialize
25
24
  end
26
25
  end
27
26
  end
@@ -21,7 +21,6 @@ module Mongoid #:nodoc:
21
21
  def serialize(object)
22
22
  object.blank? ? nil : object.to_sym
23
23
  end
24
- alias :set :serialize
25
24
  end
26
25
  end
27
26
  end
@@ -49,15 +49,38 @@ module Mongoid #:nodoc:
49
49
  # @since 2.0.0.rc.7
50
50
  def matcher(document, key, value)
51
51
  if value.is_a?(Hash)
52
- MATCHERS[value.keys.first].new(document.attributes[key.to_s])
52
+ MATCHERS[value.keys.first].new(extract_attribute(document, key))
53
53
  else
54
54
  if key == "$or"
55
55
  Matchers::Or.new(value, document)
56
56
  else
57
- Default.new(document.attributes[key.to_s])
57
+ Default.new(extract_attribute(document, key))
58
58
  end
59
59
  end
60
60
  end
61
+
62
+ private
63
+
64
+ # Extract the attribute from the key, being smarter about dot notation.
65
+ #
66
+ # @example Extract the attribute.
67
+ # strategy.extract_attribute(doc, "info.field")
68
+ #
69
+ # @param [ Document ] document The document.
70
+ # @param [ String ] key The key.
71
+ #
72
+ # @return [ Object ] The value of the attribute.
73
+ #
74
+ # @since 2.2.1
75
+ def extract_attribute(document, key)
76
+ if (key_string = key.to_s) =~ /.+\..+/
77
+ key_string.split('.').inject(document.attributes) do |attribs, key|
78
+ attribs.try(:[], key)
79
+ end
80
+ else
81
+ document.attributes[key_string]
82
+ end
83
+ end
61
84
  end
62
85
  end
63
86
  end
@@ -45,7 +45,7 @@ module Mongoid #:nodoc:
45
45
  # by a hash of options.
46
46
  #
47
47
  # @option *args [ true, false ] :allow_destroy Can deletion occur?
48
- # @option *args [ Proc ] :reject_if Block to reject documents with.
48
+ # @option *args [ Proc, Symbol ] :reject_if Block or symbol pointing to a class method to reject documents with.
49
49
  # @option *args [ Integer ] :limit The max number to create.
50
50
  # @option *args [ true, false ] :update_only Only update existing docs.
51
51
  def accepts_nested_attributes_for(*args)
@@ -9,7 +9,7 @@ require "mongoid/persistence/atomic/pull_all"
9
9
  require "mongoid/persistence/atomic/push"
10
10
  require "mongoid/persistence/atomic/push_all"
11
11
  require "mongoid/persistence/atomic/rename"
12
- require "mongoid/persistence/atomic/set"
12
+ require "mongoid/persistence/atomic/sets"
13
13
  require "mongoid/persistence/atomic/unset"
14
14
 
15
15
  module Mongoid #:nodoc:
@@ -201,7 +201,7 @@ module Mongoid #:nodoc:
201
201
  #
202
202
  # @since 2.1.0
203
203
  def set(field, value = nil, options = {})
204
- Set.new(self, field, value, options).persist
204
+ Sets.new(self, field, value, options).persist
205
205
  end
206
206
 
207
207
  # Performs the atomic $unset on the supplied field.
@@ -4,7 +4,7 @@ module Mongoid #:nodoc:
4
4
  module Atomic #:nodoc:
5
5
 
6
6
  # This class provides atomic $set behaviour.
7
- class Set
7
+ class Sets
8
8
  include Operation
9
9
 
10
10
  # Sends the atomic $set operation to the database.
@@ -19,10 +19,10 @@ module Mongoid #:nodoc:
19
19
  #
20
20
  # @since 2.1.0
21
21
  def prepare(&block)
22
+ document.cascade!
22
23
  yield(document)
23
24
  document.freeze
24
25
  document.destroyed = true
25
- document.cascade!
26
26
  IdentityMap.remove(document)
27
27
  Threaded.clear_safety_options!
28
28
  true
@@ -22,13 +22,13 @@ module Mongoid # :nodoc:
22
22
  unless binding?
23
23
  binding do
24
24
  inverse = metadata.inverse(target)
25
- base.send(metadata.foreign_key_setter, target.id)
25
+ base.you_must(metadata.foreign_key_setter, target.id)
26
26
  if metadata.inverse_type
27
- base.send(metadata.inverse_type_setter, target.class.model_name)
27
+ base.you_must(metadata.inverse_type_setter, target.class.model_name)
28
28
  end
29
29
  if inverse
30
30
  inverse_metadata = metadata.inverse_metadata(target)
31
- if inverse_metadata != metadata
31
+ if inverse_metadata != metadata && !inverse_metadata.nil?
32
32
  base.metadata = inverse_metadata
33
33
  if base.referenced_many?
34
34
  target.send(inverse).push(base)
@@ -54,9 +54,9 @@ module Mongoid # :nodoc:
54
54
  unless binding?
55
55
  binding do
56
56
  inverse = metadata.inverse(target)
57
- base.send(metadata.foreign_key_setter, nil)
57
+ base.you_must(metadata.foreign_key_setter, nil)
58
58
  if metadata.inverse_type
59
- base.send(metadata.inverse_type_setter, nil)
59
+ base.you_must(metadata.inverse_type_setter, nil)
60
60
  end
61
61
  if inverse
62
62
  if base.referenced_many?
@@ -19,9 +19,9 @@ module Mongoid # :nodoc:
19
19
  def bind_one(doc)
20
20
  unless binding?
21
21
  binding do
22
- doc.send(metadata.foreign_key_setter, base.id)
22
+ doc.you_must(metadata.foreign_key_setter, base.id)
23
23
  if metadata.type
24
- doc.send(metadata.type_setter, base.class.model_name)
24
+ doc.you_must(metadata.type_setter, base.class.model_name)
25
25
  end
26
26
  doc.send(metadata.inverse_setter, base)
27
27
  end
@@ -39,9 +39,9 @@ module Mongoid # :nodoc:
39
39
  def unbind_one(doc)
40
40
  unless binding?
41
41
  binding do
42
- doc.send(metadata.foreign_key_setter, nil)
42
+ doc.you_must(metadata.foreign_key_setter, nil)
43
43
  if metadata.type
44
- doc.send(metadata.type_setter, nil)
44
+ doc.you_must(metadata.type_setter, nil)
45
45
  end
46
46
  doc.send(metadata.inverse_setter, nil)
47
47
  end
@@ -19,7 +19,7 @@ module Mongoid # :nodoc:
19
19
  def bind_one(doc)
20
20
  unless binding?
21
21
  binding do
22
- inverse_keys = doc.do_or_do_not(metadata.inverse_foreign_key)
22
+ inverse_keys = doc.you_must(metadata.inverse_foreign_key)
23
23
  inverse_keys.push(base.id) if inverse_keys
24
24
  base.synced[metadata.foreign_key] = true
25
25
  doc.synced[metadata.inverse_foreign_key] = true
@@ -37,7 +37,7 @@ module Mongoid # :nodoc:
37
37
  unless binding?
38
38
  binding do
39
39
  base.send(metadata.foreign_key).delete_one(doc.id)
40
- inverse_keys = doc.do_or_do_not(metadata.inverse_foreign_key)
40
+ inverse_keys = doc.you_must(metadata.inverse_foreign_key)
41
41
  inverse_keys.delete_one(base.id) if inverse_keys
42
42
  base.synced[metadata.foreign_key] = true
43
43
  doc.synced[metadata.inverse_foreign_key] = true
@@ -21,10 +21,10 @@ module Mongoid # :nodoc:
21
21
  def bind
22
22
  unless binding?
23
23
  binding do
24
- target.send(metadata.foreign_key_setter, base.id)
24
+ target.you_must(metadata.foreign_key_setter, base.id)
25
25
  target.send(metadata.inverse_setter, base)
26
26
  if metadata.type
27
- target.send(metadata.type_setter, base.class.model_name)
27
+ target.you_must(metadata.type_setter, base.class.model_name)
28
28
  end
29
29
  end
30
30
  end
@@ -42,10 +42,10 @@ module Mongoid # :nodoc:
42
42
  def unbind
43
43
  unless binding?
44
44
  binding do
45
- target.send(metadata.foreign_key_setter, nil)
45
+ target.you_must(metadata.foreign_key_setter, nil)
46
46
  target.send(metadata.inverse_setter, nil)
47
47
  if metadata.type
48
- target.send(metadata.type_setter, nil)
48
+ target.you_must(metadata.type_setter, nil)
49
49
  end
50
50
  end
51
51
  end
@@ -35,8 +35,7 @@ module Mongoid # :nodoc:
35
35
  #
36
36
  # @since 2.0.0.rc.1
37
37
  def query?
38
- return true unless object.respond_to?(:to_a)
39
- obj = object.to_a.first
38
+ obj = Array(object).first
40
39
  !obj.is_a?(Mongoid::Document) && !obj.nil?
41
40
  end
42
41
  end
@@ -25,9 +25,9 @@ module Mongoid # :nodoc:
25
25
  end
26
26
  attributes.each do |attrs|
27
27
  if attrs.respond_to?(:with_indifferent_access)
28
- process(attrs)
28
+ process(parent, attrs)
29
29
  else
30
- process(attrs[1])
30
+ process(parent, attrs[1])
31
31
  end
32
32
  end
33
33
  end
@@ -89,12 +89,13 @@ module Mongoid # :nodoc:
89
89
  # builder.process({ "id" => 1, "street" => "Bond" })
90
90
  #
91
91
  # @param [ Hash ] attrs The single document attributes to process.
92
- def process(attrs)
93
- return if reject?(attrs)
92
+ def process(parent, attrs)
93
+ return if reject?(parent, attrs)
94
94
  if id = attrs["id"] || attrs["_id"]
95
95
  doc = existing.find(convert_id(id))
96
96
  if destroyable?(attrs)
97
97
  existing.delete(doc)
98
+ doc.destroy unless doc.embedded?
98
99
  else
99
100
  metadata.embedded? ? doc.attributes = attrs : doc.update_attributes(attrs)
100
101
  end
@@ -22,7 +22,7 @@ module Mongoid # :nodoc:
22
22
  #
23
23
  # parent: The parent document of the relation.
24
24
  def build(parent)
25
- return if reject?(attributes)
25
+ return if reject?(parent, attributes)
26
26
  @existing = parent.send(metadata.name)
27
27
  if update?
28
28
  existing.attributes = attributes
@@ -29,7 +29,7 @@ module Mongoid # :nodoc:
29
29
  # @example Get the value.
30
30
  # builder.convertable
31
31
  #
32
- # @return [ String, Unconvertable, BSON::ObjectId ] The string or object id.
32
+ # @return [ String, BSON::ObjectId ] The string or object id.
33
33
  #
34
34
  # @since 2.0.2
35
35
  def convertable(metadata, object)
@@ -37,7 +37,9 @@ module Mongoid # :nodoc:
37
37
  if inverse.using_object_ids? || object.is_a?(BSON::ObjectId)
38
38
  object
39
39
  else
40
- Criterion::Unconvertable.new(object)
40
+ object.tap do |obj|
41
+ obj.unconvertable_to_bson = true if obj.is_a?(String)
42
+ end
41
43
  end
42
44
  end
43
45
  end
@@ -11,7 +11,14 @@ module Mongoid # :nodoc:
11
11
  # @example Perform the cascading destroy.
12
12
  # strategy.cascade
13
13
  def cascade
14
- relation.to_a.each { |doc| doc.destroy } if relation
14
+ if relation
15
+ if relation.is_a?(Enumerable)
16
+ relation.entries
17
+ relation.each { |doc| doc.destroy }
18
+ else
19
+ relation.destroy
20
+ end
21
+ end
15
22
  end
16
23
  end
17
24
  end
@@ -41,7 +41,7 @@ module Mongoid # :nodoc:
41
41
  tap do |proxy|
42
42
  proxy.unbind_one
43
43
  unless replacement
44
- base.delete unless binding?
44
+ base.delete if persistable?
45
45
  return nil
46
46
  end
47
47
  base.new_record = true
@@ -268,6 +268,19 @@ module Mongoid # :nodoc:
268
268
  end
269
269
  end
270
270
 
271
+ # Get a criteria for the embedded documents without the default scoping
272
+ # applied.
273
+ #
274
+ # @example Get the unscoped criteria.
275
+ # person.addresses.unscoped
276
+ #
277
+ # @return [ Criteria ] The unscoped criteria.
278
+ #
279
+ # @since 2.2.1
280
+ def unscoped
281
+ criteria(false)
282
+ end
283
+
271
284
  private
272
285
 
273
286
  # Appends the document to the target array, updating the index on the
@@ -306,8 +319,8 @@ module Mongoid # :nodoc:
306
319
  # relation.criteria
307
320
  #
308
321
  # @return [ Criteria ] A new criteria.
309
- def criteria
310
- klass.criteria(true).tap do |criterion|
322
+ def criteria(scoped = true)
323
+ klass.criteria(true, scoped).tap do |criterion|
311
324
  criterion.documents = target
312
325
  end
313
326
  end
@@ -39,7 +39,7 @@ module Mongoid # :nodoc:
39
39
  if assigning?
40
40
  base.atomic_unsets.push(proxy.atomic_path)
41
41
  else
42
- proxy.delete
42
+ proxy.delete if persistable?
43
43
  end
44
44
  proxy.unbind_one
45
45
  return nil unless replacement
@@ -25,14 +25,21 @@ module Mongoid # :nodoc:
25
25
  # @example Is there a reject proc?
26
26
  # builder.reject?
27
27
  #
28
+ # @param The parent document of the relation
28
29
  # @param [ Hash ] attrs The attributes to check for rejection.
29
30
  #
30
- # @return [ true, false ] True and call proc if rejectable, false if not.
31
+ # @return [ true, false ] True and call proc or method if rejectable, false if not.
31
32
  #
32
33
  # @since 2.0.0.rc.1
33
- def reject?(attrs)
34
- criteria = options[:reject_if]
35
- criteria ? criteria.call(attrs) : false
34
+ def reject?(document, attrs)
35
+ case callback = options[:reject_if]
36
+ when Symbol
37
+ document.method(callback).arity == 0 ? document.send(callback) : document.send(callback, attrs)
38
+ when Proc
39
+ callback.call(attrs)
40
+ else
41
+ false
42
+ end
36
43
  end
37
44
 
38
45
  # Determines if only updates can occur. Only valid for one-to-one
@@ -329,7 +329,7 @@ module Mongoid #:nodoc:
329
329
  # @example Get the value.
330
330
  # relation.convertable
331
331
  #
332
- # @return [ String, Unconvertable, BSON::ObjectId ] The string or object id.
332
+ # @return [ String, BSON::ObjectId ] The string or object id.
333
333
  #
334
334
  # @since 2.0.2
335
335
  def convertable
@@ -337,7 +337,9 @@ module Mongoid #:nodoc:
337
337
  if inverse.using_object_ids? || base.id.is_a?(BSON::ObjectId)
338
338
  base.id
339
339
  else
340
- Criterion::Unconvertable.new(base.id)
340
+ base.id.tap do |id|
341
+ id.unconvertable_to_bson = true if id.is_a?(String)
342
+ end
341
343
  end
342
344
  end
343
345
 
@@ -35,6 +35,7 @@ module Mongoid # :nodoc:
35
35
  doc.save
36
36
  else
37
37
  base.send(metadata.foreign_key).push(doc.id)
38
+ base.synced[metadata.foreign_key] = false
38
39
  end
39
40
  end
40
41
  if persistable? || creating?
@@ -142,7 +143,7 @@ module Mongoid # :nodoc:
142
143
  # @since 2.0.0.rc.1
143
144
  def nullify
144
145
  criteria.pull(metadata.inverse_foreign_key, base.id)
145
- unless base.destroyed?
146
+ if persistable?
146
147
  base.set(
147
148
  metadata.foreign_key,
148
149
  base.send(metadata.foreign_key).clear