mongoid 2.3.1 → 2.3.2

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