mongoid 3.0.2 → 3.0.3

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.
@@ -3,7 +3,22 @@
3
3
  For instructions on upgrading to newer versions, visit
4
4
  [mongoid.org](http://mongoid.org/docs/upgrading.html).
5
5
 
6
- ## 3.0.2 (branch: 3.0.0-stable)
6
+ ## 3.0.3
7
+
8
+ ### Resolved Issues
9
+
10
+ * \#2259 Ensure subclassed documents can not be pulled from the identity map
11
+ via an id of another document in the same collection with a parent or
12
+ sibeling type.
13
+
14
+ * \#2254 $inc operations no longer convert all values to floats.
15
+
16
+ * \#2252 Don't fire autosave when before callbacks have terminated.
17
+
18
+ * \#2248 Improved the performance of `exists?` on criteria and relations.
19
+ (Jonathan Hyman)
20
+
21
+ ## 3.0.2
7
22
 
8
23
  ### Resolved Issues
9
24
 
@@ -34,6 +34,8 @@ module Mongoid
34
34
  define_model_callbacks :initialize, only: :after
35
35
  define_model_callbacks :build, only: :after
36
36
  define_model_callbacks :create, :destroy, :save, :update, :upsert
37
+
38
+ attr_accessor :before_callback_halted
37
39
  end
38
40
 
39
41
  # Run only the after callbacks for the specific event.
@@ -100,6 +102,21 @@ module Mongoid
100
102
 
101
103
  private
102
104
 
105
+ # We need to hook into this for autosave, since we don't want it firing if
106
+ # the before callbacks were halted.
107
+ #
108
+ # @api private
109
+ #
110
+ # @example Was a before callback halted?
111
+ # document.before_callback_halted?
112
+ #
113
+ # @return [ true, false ] If a before callback was halted.
114
+ #
115
+ # @since 3.0.3
116
+ def before_callback_halted?
117
+ !!@before_callback_halted
118
+ end
119
+
103
120
  # Get all the child embedded documents that are flagged as cascadable.
104
121
  #
105
122
  # @example Get all the cascading children.
@@ -169,6 +186,21 @@ module Mongoid
169
186
  end
170
187
  end
171
188
 
189
+ # We need to hook into this for autosave, since we don't want it firing if
190
+ # the before callbacks were halted.
191
+ #
192
+ # @api private
193
+ #
194
+ # @example Hook into the halt.
195
+ # document.halted_callback_hook(filter)
196
+ #
197
+ # @param [ Symbol ] filter The callback that halted.
198
+ #
199
+ # @since 3.0.3
200
+ def halted_callback_hook(filter)
201
+ @before_callback_halted = true
202
+ end
203
+
172
204
  # Run only the callbacks for the target location (before, after, around)
173
205
  # and kind (save, update, create).
174
206
  #
@@ -30,7 +30,7 @@ module Mongoid
30
30
  #
31
31
  # @since 3.0.0
32
32
  def blank?
33
- count == 0
33
+ !exists?
34
34
  end
35
35
  alias :empty? :blank?
36
36
 
@@ -151,7 +151,8 @@ module Mongoid
151
151
  #
152
152
  # @since 3.0.0
153
153
  def exists?
154
- count > 0
154
+ # Don't use count here since Mongo does not use counted b-tree indexes
155
+ !query.dup.select(_id: 1).limit(1).entries.first.nil?
155
156
  end
156
157
 
157
158
  # Run an explain on the criteria.
@@ -214,7 +215,7 @@ module Mongoid
214
215
  def initialize(criteria)
215
216
  @criteria, @klass, @cache = criteria, criteria.klass, criteria.options[:cache]
216
217
  @collection = klass.collection
217
- add_type_selection
218
+ criteria.send(:merge_type_selection)
218
219
  @query = collection.find(criteria.selector)
219
220
  apply_options
220
221
  end
@@ -325,21 +326,6 @@ module Mongoid
325
326
 
326
327
  private
327
328
 
328
- # For models where inheritance is at play we need to add the type
329
- # selection.
330
- #
331
- # @example Add the type selection.
332
- # context.add_type_selection
333
- #
334
- # @return [ true, false ] If type selection was added.
335
- #
336
- # @since 3.0.0
337
- def add_type_selection
338
- if klass.hereditary? && !criteria.selector.keys.include?(:_type)
339
- criteria.selector.merge!(_type: { "$in" => klass._types })
340
- end
341
- end
342
-
343
329
  # Apply the field limitations.
344
330
  #
345
331
  # @api private
@@ -178,18 +178,6 @@ module Mongoid
178
178
  multi ? result : result.first
179
179
  end
180
180
 
181
- # Return true if the criteria has some Document or not.
182
- #
183
- # @example Are there any documents for the criteria?
184
- # criteria.exists?
185
- #
186
- # @return [ true, false ] If documents match.
187
- #
188
- # @since 1.0.0
189
- def exists?
190
- context.count > 0
191
- end
192
-
193
181
  # Extract a single id from the provided criteria. Could be in an $and
194
182
  # query or a straight _id query.
195
183
  #
@@ -594,12 +582,11 @@ module Mongoid
594
582
  #
595
583
  # @since 1.0.0
596
584
  def initialize_copy(other)
597
- @selector = other.selector.dup
598
- @options = other.options.dup
599
585
  @inclusions = other.inclusions.dup
600
586
  @scoping_options = other.scoping_options
601
587
  @documents = other.documents.dup
602
588
  @context = nil
589
+ super
603
590
  end
604
591
 
605
592
  # Get documents from the database only.
@@ -632,9 +619,10 @@ module Mongoid
632
619
  # @since 3.0.0
633
620
  def from_identity_map(ids)
634
621
  result = []
622
+ selection = selector_with_type_selection
635
623
  ids.reject! do |id|
636
624
  doc = IdentityMap.get(klass, id)
637
- doc && doc.matches?(selector) ? result.push(doc) : false
625
+ doc && doc.matches?(selection) ? result.push(doc) : false
638
626
  end
639
627
  result
640
628
  end
@@ -661,6 +649,19 @@ module Mongoid
661
649
  end
662
650
  end
663
651
 
652
+ # For models where inheritance is at play we need to add the type
653
+ # selection.
654
+ #
655
+ # @example Add the type selection.
656
+ # criteria.merge_type_selection
657
+ #
658
+ # @return [ true, false ] If type selection was added.
659
+ #
660
+ # @since 3.0.3
661
+ def merge_type_selection
662
+ selector.merge!(type_selection) if type_selectable?
663
+ end
664
+
664
665
  # Convert all the ids to their proper types.
665
666
  #
666
667
  # @api private
@@ -688,5 +689,47 @@ module Mongoid
688
689
  def raise_invalid
689
690
  raise Errors::InvalidFind.new
690
691
  end
692
+
693
+ # Is the criteria type selectable?
694
+ #
695
+ # @api private
696
+ #
697
+ # @example If the criteria type selectable?
698
+ # criteria.type_selectable?
699
+ #
700
+ # @return [ true, false ] If type selection should be added.
701
+ #
702
+ # @since 3.0.3
703
+ def type_selectable?
704
+ klass.hereditary? && !selector.keys.include?(:_type)
705
+ end
706
+
707
+ # Get the selector for type selection.
708
+ #
709
+ # @api private
710
+ #
711
+ # @example Get a type selection hash.
712
+ # criteria.type_selection
713
+ #
714
+ # @return [ Hash ] The type selection.
715
+ #
716
+ # @since 3.0.3
717
+ def type_selection
718
+ { _type: { "$in" => klass._types }}
719
+ end
720
+
721
+ # Get a new selector with type selection in it.
722
+ #
723
+ # @api private
724
+ #
725
+ # @example Get a selector with type selection.
726
+ # criteria.selector_with_type_selection
727
+ #
728
+ # @return [ Hash ] The selector.
729
+ #
730
+ # @since 3.0.3
731
+ def selector_with_type_selection
732
+ type_selectable? ? selector.merge(type_selection) : selector
733
+ end
691
734
  end
692
735
  end
@@ -3,6 +3,18 @@ module Mongoid
3
3
  module Extensions
4
4
  module BigDecimal
5
5
 
6
+ # Convert the big decimal to an $inc-able value.
7
+ #
8
+ # @example Convert the big decimal.
9
+ # bd.__to_inc__
10
+ #
11
+ # @return [ Float ] The big decimal as a float.
12
+ #
13
+ # @since 3.0.3
14
+ def __to_inc__
15
+ to_f
16
+ end
17
+
6
18
  # Turn the object from the ruby type we deal with to a Mongo friendly
7
19
  # type.
8
20
  #
@@ -52,6 +52,18 @@ module Mongoid
52
52
  self
53
53
  end
54
54
 
55
+ # Conversion of an object to an $inc-able value.
56
+ #
57
+ # @example Convert the object.
58
+ # 1.__to_inc__
59
+ #
60
+ # @return [ Object ] The object.
61
+ #
62
+ # @since 3.0.3
63
+ def __to_inc__
64
+ self
65
+ end
66
+
55
67
  # Do or do not, there is no try. -- Yoda.
56
68
  #
57
69
  # @example Do or do not.
@@ -17,13 +17,28 @@ module Mongoid
17
17
  # @since 2.0.0
18
18
  def persist
19
19
  prepare do
20
- self.value = value.to_f
21
20
  current = document[field] || 0
22
21
  document[field] = current + value
23
22
  execute("$inc")
24
23
  document[field]
25
24
  end
26
25
  end
26
+
27
+ private
28
+
29
+ # In case we need to cast going to the database.
30
+ #
31
+ # @api private
32
+ #
33
+ # @example Cast the value.
34
+ # operation.cast_value
35
+ #
36
+ # @return [ Integer, Float ] The value casted.
37
+ #
38
+ # @since 3.0.3
39
+ def cast_value
40
+ value.__to_inc__
41
+ end
27
42
  end
28
43
  end
29
44
  end
@@ -47,7 +47,7 @@ module Mongoid
47
47
  #
48
48
  # @since 2.0.0
49
49
  def operation(modifier)
50
- { modifier => { path => value } }
50
+ { modifier => { path => cast_value } }
51
51
  end
52
52
 
53
53
  # Get the path to the field that is getting atomically updated.
@@ -82,6 +82,20 @@ module Mongoid
82
82
 
83
83
  private
84
84
 
85
+ # In case we need to cast going to the database.
86
+ #
87
+ # @api private
88
+ #
89
+ # @example Cast the value.
90
+ # operation.cast_value
91
+ #
92
+ # @return [ Object ] The value.
93
+ #
94
+ # @since 3.0.3
95
+ def cast_value
96
+ value
97
+ end
98
+
85
99
  # Executes the common functionality between operations.
86
100
  #
87
101
  # @api private
@@ -61,14 +61,19 @@ module Mongoid
61
61
  if metadata.autosave? && autosavable?(metadata)
62
62
  autosaved_relations.push(metadata.name)
63
63
  set_callback :save, :after, unless: :autosaved? do |document|
64
- begin_autosave
65
- relation = document.send(metadata.name)
66
- if relation
67
- (relation.do_or_do_not(:in_memory) || Array.wrap(relation)).each do |doc|
68
- doc.save
64
+ # @todo: Durran: Remove with Rails 4 after callback termination.
65
+ if before_callback_halted?
66
+ self.before_callback_halted = false
67
+ else
68
+ begin_autosave
69
+ relation = document.send(metadata.name)
70
+ if relation
71
+ (relation.do_or_do_not(:in_memory) || Array.wrap(relation)).each do |doc|
72
+ doc.save
73
+ end
69
74
  end
75
+ exit_autosave
70
76
  end
71
- exit_autosave
72
77
  end
73
78
  end
74
79
  end
@@ -178,6 +178,16 @@ module Mongoid
178
178
  remove_all(conditions, :destroy)
179
179
  end
180
180
 
181
+ # Determine if any documents in this relation exist in the database.
182
+ #
183
+ # @example Are there persisted documents?
184
+ # person.posts.exists?
185
+ #
186
+ # @return [ true, false ] True is persisted documents exist, false if not.
187
+ def exists?
188
+ count > 0
189
+ end
190
+
181
191
  # Finds a document in this association through several different
182
192
  # methods.
183
193
  #
@@ -72,16 +72,6 @@ module Mongoid
72
72
  doc
73
73
  end
74
74
 
75
- # Determine if any documents in this relation exist in the database.
76
- #
77
- # @example Are there persisted documents?
78
- # person.posts.exists?
79
- #
80
- # @return [ true, false ] True is persisted documents exist, false if not.
81
- def exists?
82
- count > 0
83
- end
84
-
85
75
  # Find the first document given the conditions, or creates a new document
86
76
  # with the conditions that were supplied.
87
77
  #
@@ -166,6 +166,16 @@ module Mongoid
166
166
  target.each { |doc| yield(doc) if block_given? }
167
167
  end
168
168
 
169
+ # Determine if any documents in this relation exist in the database.
170
+ #
171
+ # @example Are there persisted documents?
172
+ # person.posts.exists?
173
+ #
174
+ # @return [ true, false ] True is persisted documents exist, false if not.
175
+ def exists?
176
+ criteria.exists?
177
+ end
178
+
169
179
  # Find the matchind document on the association, either based on id or
170
180
  # conditions.
171
181
  #
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid
3
- VERSION = "3.0.2"
3
+ VERSION = "3.0.3"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 3.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-26 00:00:00.000000000 Z
12
+ date: 2012-07-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 1.1.3
53
+ version: '1.1'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +58,7 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 1.1.3
61
+ version: '1.1'
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: origin
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - ~>
68
68
  - !ruby/object:Gem::Version
69
- version: 1.0.3
69
+ version: '1.0'
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,7 +74,7 @@ dependencies:
74
74
  requirements:
75
75
  - - ~>
76
76
  - !ruby/object:Gem::Version
77
- version: 1.0.3
77
+ version: '1.0'
78
78
  description: Mongoid is an ODM (Object Document Mapper) Framework for MongoDB, written
79
79
  in Ruby.
80
80
  email:
@@ -354,7 +354,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
354
354
  version: '0'
355
355
  segments:
356
356
  - 0
357
- hash: -2401816609188543871
357
+ hash: -2363016562151284772
358
358
  required_rubygems_version: !ruby/object:Gem::Requirement
359
359
  none: false
360
360
  requirements: