mongoid 2.3.1 → 2.3.2

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 (47) hide show
  1. data/CHANGELOG.md +34 -1
  2. data/lib/mongoid.rb +3 -2
  3. data/lib/mongoid/atomic.rb +23 -2
  4. data/lib/mongoid/attributes.rb +0 -21
  5. data/lib/mongoid/callbacks.rb +9 -1
  6. data/lib/mongoid/components.rb +2 -0
  7. data/lib/mongoid/config.rb +4 -2
  8. data/lib/mongoid/contexts/mongo.rb +19 -8
  9. data/lib/mongoid/criterion/inclusion.rb +6 -4
  10. data/lib/mongoid/dirty.rb +1 -0
  11. data/lib/mongoid/document.rb +1 -25
  12. data/lib/mongoid/extensions/hash/criteria_helpers.rb +13 -0
  13. data/lib/mongoid/extensions/object/yoda.rb +1 -0
  14. data/lib/mongoid/matchers/strategies.rb +6 -1
  15. data/lib/mongoid/persistence.rb +2 -21
  16. data/lib/mongoid/railtie.rb +8 -1
  17. data/lib/mongoid/relations/accessors.rb +7 -5
  18. data/lib/mongoid/relations/binding.rb +2 -29
  19. data/lib/mongoid/relations/bindings/embedded/in.rb +4 -4
  20. data/lib/mongoid/relations/bindings/embedded/many.rb +4 -4
  21. data/lib/mongoid/relations/bindings/embedded/one.rb +4 -4
  22. data/lib/mongoid/relations/bindings/referenced/in.rb +4 -4
  23. data/lib/mongoid/relations/bindings/referenced/many.rb +4 -4
  24. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +4 -4
  25. data/lib/mongoid/relations/bindings/referenced/one.rb +4 -4
  26. data/lib/mongoid/relations/builder.rb +18 -4
  27. data/lib/mongoid/relations/builders.rb +0 -17
  28. data/lib/mongoid/relations/builders/embedded/in.rb +3 -3
  29. data/lib/mongoid/relations/builders/embedded/many.rb +4 -4
  30. data/lib/mongoid/relations/builders/embedded/one.rb +3 -3
  31. data/lib/mongoid/relations/builders/nested_attributes/many.rb +1 -1
  32. data/lib/mongoid/relations/builders/referenced/one.rb +1 -0
  33. data/lib/mongoid/relations/embedded/in.rb +4 -3
  34. data/lib/mongoid/relations/embedded/many.rb +6 -5
  35. data/lib/mongoid/relations/embedded/one.rb +4 -3
  36. data/lib/mongoid/relations/metadata.rb +20 -5
  37. data/lib/mongoid/relations/proxy.rb +1 -48
  38. data/lib/mongoid/relations/referenced/in.rb +4 -3
  39. data/lib/mongoid/relations/referenced/many.rb +4 -3
  40. data/lib/mongoid/relations/referenced/many_to_many.rb +5 -4
  41. data/lib/mongoid/relations/referenced/one.rb +4 -3
  42. data/lib/mongoid/reloading.rb +91 -0
  43. data/lib/mongoid/state.rb +15 -22
  44. data/lib/mongoid/threaded.rb +51 -0
  45. data/lib/mongoid/threaded/lifecycle.rb +163 -0
  46. data/lib/mongoid/version.rb +1 -1
  47. metadata +21 -19
@@ -5,6 +5,7 @@ module Mongoid # :nodoc:
5
5
  # This class is the superclass for all relation proxy objects, and contains
6
6
  # common behaviour for all of them.
7
7
  class Proxy
8
+ include Threaded::Lifecycle
8
9
 
9
10
  # We undefine most methods to get them sent through to the target.
10
11
  instance_methods.each do |method|
@@ -50,54 +51,6 @@ module Mongoid # :nodoc:
50
51
 
51
52
  protected
52
53
 
53
- # Is the current thread in assigning mode?
54
- #
55
- # @example Is the current thread in assigning mode?
56
- # proxy._assigning?
57
- #
58
- # @return [ true, false ] If the thread is assigning.
59
- #
60
- # @since 2.1.0
61
- def _assigning?
62
- Threaded.assigning?
63
- end
64
-
65
- # Is the current thread in binding mode?
66
- #
67
- # @example Is the current thread in binding mode?
68
- # proxy.binding?
69
- #
70
- # @return [ true, false ] If the thread is binding.
71
- #
72
- # @since 2.1.0
73
- def binding?
74
- Threaded.binding?
75
- end
76
-
77
- # Is the current thread in building mode?
78
- #
79
- # @example Is the current thread in building mode?
80
- # proxy._building?
81
- #
82
- # @return [ true, false ] If the thread is building.
83
- #
84
- # @since 2.1.0
85
- def _building?
86
- Threaded.building?
87
- end
88
-
89
- # Is the current thread in creating mode?
90
- #
91
- # @example Is the current thread in creating mode?
92
- # proxy.creating?
93
- #
94
- # @return [ true, false ] If the thread is creating.
95
- #
96
- # @since 2.1.0
97
- def creating?
98
- Threaded.creating?
99
- end
100
-
101
54
  # Get the collection from the root of the hierarchy.
102
55
  #
103
56
  # @example Get the collection.
@@ -71,7 +71,7 @@ module Mongoid # :nodoc:
71
71
  #
72
72
  # @since 2.1.0
73
73
  def persistable?
74
- target.persisted? && !binding? && !_building?
74
+ target.persisted? && !_binding? && !_building?
75
75
  end
76
76
 
77
77
  class << self
@@ -82,6 +82,7 @@ module Mongoid # :nodoc:
82
82
  # @example Get the builder.
83
83
  # Referenced::In.builder(meta, object)
84
84
  #
85
+ # @param [ Document ] base The base document.
85
86
  # @param [ Metadata ] meta The metadata of the relation.
86
87
  # @param [ Document, Hash ] object A document or attributes to build
87
88
  # with.
@@ -89,8 +90,8 @@ module Mongoid # :nodoc:
89
90
  # @return [ Builder ] A new builder object.
90
91
  #
91
92
  # @since 2.0.0.rc.1
92
- def builder(meta, object, loading = false)
93
- Builders::Referenced::In.new(meta, object, loading)
93
+ def builder(base, meta, object)
94
+ Builders::Referenced::In.new(base, meta, object)
94
95
  end
95
96
 
96
97
  # Get the standard criteria used for querying this relation.
@@ -408,7 +408,7 @@ module Mongoid #:nodoc:
408
408
  #
409
409
  # @since 2.1.0
410
410
  def persistable?
411
- base.persisted? && !binding? && !_building?
411
+ _creating? || base.persisted? && !_binding? && !_building?
412
412
  end
413
413
 
414
414
  # Deletes all related documents from the database given the supplied
@@ -445,6 +445,7 @@ module Mongoid #:nodoc:
445
445
  # @example Get the builder.
446
446
  # Referenced::Many.builder(meta, object)
447
447
  #
448
+ # @param [ Document ] base The base document.
448
449
  # @param [ Metadata ] meta The metadata of the relation.
449
450
  # @param [ Document, Hash ] object A document or attributes to build
450
451
  # with.
@@ -452,8 +453,8 @@ module Mongoid #:nodoc:
452
453
  # @return [ Builder ] A new builder object.
453
454
  #
454
455
  # @since 2.0.0.rc.1
455
- def builder(meta, object, loading = false)
456
- Builders::Referenced::Many.new(meta, object || [], loading)
456
+ def builder(base, meta, object)
457
+ Builders::Referenced::Many.new(base, meta, object || [])
457
458
  end
458
459
 
459
460
  # Get the standard criteria used for querying this relation.
@@ -30,7 +30,7 @@ module Mongoid # :nodoc:
30
30
  args.flatten.each do |doc|
31
31
  next unless doc
32
32
  append(doc)
33
- if persistable? || creating?
33
+ if persistable? || _creating?
34
34
  ids.push(doc.id)
35
35
  doc.save
36
36
  else
@@ -38,7 +38,7 @@ module Mongoid # :nodoc:
38
38
  base.synced[metadata.foreign_key] = false
39
39
  end
40
40
  end
41
- if persistable? || creating?
41
+ if persistable? || _creating?
42
42
  base.push_all(metadata.foreign_key, ids)
43
43
  base.synced[metadata.foreign_key] = false
44
44
  end
@@ -216,6 +216,7 @@ module Mongoid # :nodoc:
216
216
  # @example Get the builder.
217
217
  # Referenced::ManyToMany.builder(meta, object)
218
218
  #
219
+ # @param [ Document ] base The base document.
219
220
  # @param [ Metadata ] meta The metadata of the relation.
220
221
  # @param [ Document, Hash ] object A document or attributes to build
221
222
  # with.
@@ -223,8 +224,8 @@ module Mongoid # :nodoc:
223
224
  # @return [ Builder ] A new builder object.
224
225
  #
225
226
  # @since 2.0.0.rc.1
226
- def builder(meta, object, loading = false)
227
- Builders::Referenced::ManyToMany.new(meta, object, loading)
227
+ def builder(base, meta, object)
228
+ Builders::Referenced::ManyToMany.new(base, meta, object)
228
229
  end
229
230
 
230
231
  # Create the standard criteria for this relation given the supplied
@@ -82,7 +82,7 @@ module Mongoid # :nodoc:
82
82
  #
83
83
  # @since 2.1.0
84
84
  def persistable?
85
- base.persisted? && !binding? && !_building?
85
+ base.persisted? && !_binding? && !_building?
86
86
  end
87
87
 
88
88
  class << self
@@ -93,6 +93,7 @@ module Mongoid # :nodoc:
93
93
  # @example Get the builder.
94
94
  # Referenced::One.builder(meta, object)
95
95
  #
96
+ # @param [ Document ] base The base document.
96
97
  # @param [ Metadata ] meta The metadata of the relation.
97
98
  # @param [ Document, Hash ] object A document or attributes to build
98
99
  # with.
@@ -100,8 +101,8 @@ module Mongoid # :nodoc:
100
101
  # @return [ Builder ] A new builder object.
101
102
  #
102
103
  # @since 2.0.0.rc.1
103
- def builder(meta, object, loading = false)
104
- Builders::Referenced::One.new(meta, object, loading)
104
+ def builder(base, meta, object)
105
+ Builders::Referenced::One.new(base, meta, object)
105
106
  end
106
107
 
107
108
  # Get the standard criteria used for querying this relation.
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ # This module handles reloading behaviour of documents.
4
+ module Reloading
5
+
6
+ # Reloads the +Document+ attributes from the database. If the document has
7
+ # not been saved then an error will get raised if the configuration option
8
+ # was set. This can reload root documents or embedded documents.
9
+ #
10
+ # @example Reload the document.
11
+ # person.reload
12
+ #
13
+ # @raise [ Errors::DocumentNotFound ] If the document was deleted.
14
+ #
15
+ # @return [ Document ] The document, reloaded.
16
+ #
17
+ # @since 1.0.0
18
+ def reload
19
+ _reload.tap do |reloaded|
20
+ if Mongoid.raise_not_found_error && reloaded.empty?
21
+ raise Errors::DocumentNotFound.new(self.class, id)
22
+ end
23
+ @attributes = reloaded
24
+ end
25
+ tap do |doc|
26
+ doc.changed_attributes.clear
27
+ doc.apply_defaults
28
+ doc.reload_relations
29
+ doc.run_callbacks(:initialize)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # Reload the document, determining if it's embedded or not and what
36
+ # behaviour to use.
37
+ #
38
+ # @example Reload the document.
39
+ # document._reload
40
+ #
41
+ # @return [ Hash ] The reloaded attributes.
42
+ #
43
+ # @since 2.3.2
44
+ def _reload
45
+ embedded? ? reload_embedded_document : reload_root_document
46
+ end
47
+
48
+ # Reload the root document.
49
+ #
50
+ # @example Reload the document.
51
+ # document.reload_root_document
52
+ #
53
+ # @return [ Hash ] The reloaded attributes.
54
+ #
55
+ # @since 2.3.2
56
+ def reload_root_document
57
+ {}.merge(collection.find_one(id) || {})
58
+ end
59
+
60
+ # Reload the embedded document.
61
+ #
62
+ # @example Reload the document.
63
+ # document.reload_embedded_document
64
+ #
65
+ # @return [ Hash ] The reloaded attributes.
66
+ #
67
+ # @since 2.3.2
68
+ def reload_embedded_document
69
+ extract_embedded_attributes({}.merge(
70
+ _root.collection.find_one(_root.id)
71
+ ))
72
+ end
73
+
74
+ # Extract only the desired embedded document from the attributes.
75
+ #
76
+ # @example Extract the embedded document.
77
+ # document.extract_embedded_attributes(attributes)
78
+ #
79
+ # @param [ Hash ] attributes The document in the db.
80
+ #
81
+ # @return [ Hash ] The document's extracted attributes.
82
+ #
83
+ # @since 2.3.2
84
+ def extract_embedded_attributes(attributes)
85
+ atomic_position.split(".").inject(attributes) do |attrs, part|
86
+ attrs = attrs[part =~ /\d/ ? part.to_i : part]
87
+ attrs
88
+ end
89
+ end
90
+ end
91
+ end
@@ -5,6 +5,8 @@ module Mongoid #:nodoc:
5
5
  # document can transition through.
6
6
  module State
7
7
 
8
+ attr_writer :destroyed, :flagged_for_destroy, :new_record
9
+
8
10
  # Returns true if the +Document+ has not been persisted to the database,
9
11
  # false if it has. This is determined by the variable @new_record
10
12
  # and NOT if the object has an id.
@@ -18,18 +20,6 @@ module Mongoid #:nodoc:
18
20
  end
19
21
  alias :new? :new_record?
20
22
 
21
- # Sets the new_record boolean - used after document is saved.
22
- #
23
- # @example Set whether the document is new.
24
- # person.new_record = true
25
- #
26
- # @param [ true, false ] saved The value to set for new_record.
27
- #
28
- # @return [ true, false ] The new_record value.
29
- def new_record=(saved)
30
- @new_record = saved
31
- end
32
-
33
23
  # Checks if the document has been saved to the database. Returns false
34
24
  # if the document has been destroyed.
35
25
  #
@@ -41,6 +31,19 @@ module Mongoid #:nodoc:
41
31
  !new_record? && !destroyed?
42
32
  end
43
33
 
34
+ # Returns whether or not the document has been flagged for deletion, but
35
+ # not destroyed yet. Used for atomic pulls of child documents.
36
+ #
37
+ # @example Is the document flagged?
38
+ # document.flagged_for_destroy?
39
+ #
40
+ # @return [ true, false ] If the document is flagged.
41
+ #
42
+ # @since 2.3.2
43
+ def flagged_for_destroy?
44
+ !!@flagged_for_destroy
45
+ end
46
+
44
47
  # Returns true if the +Document+ has been succesfully destroyed, and false
45
48
  # if it hasn't. This is determined by the variable @destroyed and NOT
46
49
  # by checking the database.
@@ -54,16 +57,6 @@ module Mongoid #:nodoc:
54
57
  end
55
58
  alias :deleted? :destroyed?
56
59
 
57
- # Sets the destroyed boolean - used after document is destroyed.
58
- #
59
- # @example Set the destroyed flag.
60
- # person.destroyed = true
61
- #
62
- # @return [ true, false ] The value set for destroyed.
63
- def destroyed=(destroyed)
64
- @destroyed = destroyed && true
65
- end
66
-
67
60
  # Determine if the document can be pushed.
68
61
  #
69
62
  # @example Is this pushable?
@@ -1,4 +1,6 @@
1
1
  # encoding: utf-8
2
+ require "mongoid/threaded/lifecycle"
3
+
2
4
  module Mongoid #:nodoc:
3
5
 
4
6
  # This module contains logic for easy access to objects that have a lifecycle
@@ -54,6 +56,18 @@ module Mongoid #:nodoc:
54
56
  create_stack.push(true)
55
57
  end
56
58
 
59
+ # Begins a creating block.
60
+ #
61
+ # @example Begin the load.
62
+ # Threaded.begin_load
63
+ #
64
+ # @return [ true ] Always true.
65
+ #
66
+ # @since 2.3.2
67
+ def begin_load
68
+ load_stack.push(true)
69
+ end
70
+
57
71
  # Begin validating a document on the current thread.
58
72
  #
59
73
  # @example Begin validation.
@@ -114,6 +128,18 @@ module Mongoid #:nodoc:
114
128
  !create_stack.empty?
115
129
  end
116
130
 
131
+ # Is the current thread in creating mode?
132
+ #
133
+ # @example Is the thread in creating mode?
134
+ # Threaded.creating?
135
+ #
136
+ # @return [ true, false ] If the thread is in creating mode?
137
+ #
138
+ # @since 2.3.2
139
+ def loading?
140
+ !load_stack.empty?
141
+ end
142
+
117
143
  # Get the assign stack for the current thread. Is simply an array of calls
118
144
  # to Mongoid's assigning method.
119
145
  #
@@ -166,6 +192,19 @@ module Mongoid #:nodoc:
166
192
  Thread.current[:"[mongoid]:create-stack"] ||= []
167
193
  end
168
194
 
195
+ # Get the load stack for the current thread. Is simply an array of calls
196
+ # to Mongoid's loading method.
197
+ #
198
+ # @example Get the load stack.
199
+ # Threaded.load_stack
200
+ #
201
+ # @return [ Array ] The array of load calls.
202
+ #
203
+ # @since 2.3.2
204
+ def load_stack
205
+ Thread.current[:"[mongoid]:load-stack"] ||= []
206
+ end
207
+
169
208
  # Clear out all the safety options set using the safely proxy.
170
209
  #
171
210
  # @example Clear out the options.
@@ -237,6 +276,18 @@ module Mongoid #:nodoc:
237
276
  create_stack.pop
238
277
  end
239
278
 
279
+ # Exit the loading block.
280
+ #
281
+ # @example Exit the loading block.
282
+ # Threaded.exit_load
283
+ #
284
+ # @return [ true ] The last element in the stack.
285
+ #
286
+ # @since 2.1.9
287
+ def exit_load
288
+ load_stack.pop
289
+ end
290
+
240
291
  # Exit validating a document on the current thread.
241
292
  #
242
293
  # @example Exit validation.
@@ -0,0 +1,163 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Threaded #:nodoc:
4
+
5
+ # This module contains convenience methods for document lifecycle that
6
+ # resides on thread locals.
7
+ module Lifecycle
8
+ extend ActiveSupport::Concern
9
+
10
+ private
11
+
12
+ # Begin the assignment of attributes. While in this block embedded
13
+ # documents will not autosave themselves in order to allow the document to
14
+ # be in a valid state.
15
+ #
16
+ # @example Execute the assignment.
17
+ # _assigning do
18
+ # person.attributes = { :addresses => [ address ] }
19
+ # end
20
+ #
21
+ # @return [ Object ] The yielded value.
22
+ #
23
+ # @since 2.2.0
24
+ def _assigning
25
+ Threaded.begin_assign
26
+ yield
27
+ ensure
28
+ Threaded.exit_assign
29
+ end
30
+
31
+ # Is the current thread in assigning mode?
32
+ #
33
+ # @example Is the current thread in assigning mode?
34
+ # proxy._assigning?
35
+ #
36
+ # @return [ true, false ] If the thread is assigning.
37
+ #
38
+ # @since 2.1.0
39
+ def _assigning?
40
+ Threaded.assigning?
41
+ end
42
+
43
+ # Execute a block in binding mode.
44
+ #
45
+ # @example Execute in binding mode.
46
+ # binding do
47
+ # relation.push(doc)
48
+ # end
49
+ #
50
+ # @return [ Object ] The return value of the block.
51
+ #
52
+ # @since 2.1.0
53
+ def _binding
54
+ Threaded.begin_bind
55
+ yield
56
+ ensure
57
+ Threaded.exit_bind
58
+ end
59
+
60
+ # Is the current thread in binding mode?
61
+ #
62
+ # @example Is the current thread in binding mode?
63
+ # proxy.binding?
64
+ #
65
+ # @return [ true, false ] If the thread is binding.
66
+ #
67
+ # @since 2.1.0
68
+ def _binding?
69
+ Threaded.binding?
70
+ end
71
+
72
+ # Execute a block in building mode.
73
+ #
74
+ # @example Execute in building mode.
75
+ # _building do
76
+ # relation.push(doc)
77
+ # end
78
+ #
79
+ # @return [ Object ] The return value of the block.
80
+ #
81
+ # @since 2.1.0
82
+ def _building
83
+ Threaded.begin_build
84
+ yield
85
+ ensure
86
+ Threaded.exit_build
87
+ end
88
+
89
+ # Is the current thread in building mode?
90
+ #
91
+ # @example Is the current thread in building mode?
92
+ # proxy._building?
93
+ #
94
+ # @return [ true, false ] If the thread is building.
95
+ #
96
+ # @since 2.1.0
97
+ def _building?
98
+ Threaded.building?
99
+ end
100
+
101
+ # Is the current thread in creating mode?
102
+ #
103
+ # @example Is the current thread in creating mode?
104
+ # proxy.creating?
105
+ #
106
+ # @return [ true, false ] If the thread is creating.
107
+ #
108
+ # @since 2.1.0
109
+ def _creating?
110
+ Threaded.creating?
111
+ end
112
+
113
+ # Execute a block in loading mode.
114
+ #
115
+ # @example Execute in loading mode.
116
+ # _loading do
117
+ # relation.push(doc)
118
+ # end
119
+ #
120
+ # @return [ Object ] The return value of the block.
121
+ #
122
+ # @since 2.3.2
123
+ def _loading
124
+ Threaded.begin_load
125
+ yield
126
+ ensure
127
+ Threaded.exit_load
128
+ end
129
+
130
+ # Is the current thread in loading mode?
131
+ #
132
+ # @example Is the current thread in loading mode?
133
+ # proxy._loading?
134
+ #
135
+ # @return [ true, false ] If the thread is loading.
136
+ #
137
+ # @since 2.3.2
138
+ def _loading?
139
+ Threaded.loading?
140
+ end
141
+
142
+ module ClassMethods #:nodoc:
143
+
144
+ # Execute a block in creating mode.
145
+ #
146
+ # @example Execute in creating mode.
147
+ # creating do
148
+ # relation.push(doc)
149
+ # end
150
+ #
151
+ # @return [ Object ] The return value of the block.
152
+ #
153
+ # @since 2.1.0
154
+ def _creating
155
+ Threaded.begin_create
156
+ yield
157
+ ensure
158
+ Threaded.exit_create
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end