mongoid 3.0.2 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: