mongoid 2.3.5 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/CHANGELOG.md +34 -176
  2. data/LICENSE +1 -1
  3. data/lib/config/locales/bg.yml +6 -0
  4. data/lib/config/locales/de.yml +6 -0
  5. data/lib/config/locales/en-GB.yml +8 -0
  6. data/lib/config/locales/en.yml +8 -0
  7. data/lib/config/locales/es.yml +9 -3
  8. data/lib/config/locales/fr.yml +6 -0
  9. data/lib/config/locales/hi.yml +6 -0
  10. data/lib/config/locales/hu.yml +6 -0
  11. data/lib/config/locales/id.yml +6 -0
  12. data/lib/config/locales/it.yml +6 -0
  13. data/lib/config/locales/ja.yml +6 -0
  14. data/lib/config/locales/kr.yml +6 -0
  15. data/lib/config/locales/nl.yml +8 -0
  16. data/lib/config/locales/pl.yml +6 -0
  17. data/lib/config/locales/pt-BR.yml +6 -0
  18. data/lib/config/locales/pt.yml +8 -2
  19. data/lib/config/locales/ro.yml +6 -0
  20. data/lib/config/locales/ru.yml +6 -0
  21. data/lib/config/locales/sv.yml +6 -0
  22. data/lib/config/locales/vi.yml +14 -8
  23. data/lib/config/locales/zh-CN.yml +6 -0
  24. data/lib/mongoid/atomic.rb +62 -13
  25. data/lib/mongoid/atomic/modifiers.rb +33 -1
  26. data/lib/mongoid/attributes.rb +5 -19
  27. data/lib/mongoid/callbacks.rb +2 -1
  28. data/lib/mongoid/collection.rb +2 -2
  29. data/lib/mongoid/collections/retry.rb +18 -6
  30. data/lib/mongoid/components.rb +2 -0
  31. data/lib/mongoid/config.rb +8 -63
  32. data/lib/mongoid/config/environment.rb +41 -0
  33. data/lib/mongoid/config/options.rb +74 -0
  34. data/lib/mongoid/contexts/enumerable.rb +0 -24
  35. data/lib/mongoid/contexts/mongo.rb +33 -3
  36. data/lib/mongoid/copyable.rb +1 -1
  37. data/lib/mongoid/criteria.rb +4 -2
  38. data/lib/mongoid/criterion/inclusion.rb +1 -16
  39. data/lib/mongoid/criterion/optional.rb +37 -10
  40. data/lib/mongoid/criterion/scoping.rb +83 -0
  41. data/lib/mongoid/criterion/selector.rb +9 -6
  42. data/lib/mongoid/default_scope.rb +1 -1
  43. data/lib/mongoid/dirty.rb +163 -29
  44. data/lib/mongoid/document.rb +58 -7
  45. data/lib/mongoid/errors.rb +2 -0
  46. data/lib/mongoid/errors/no_environment.rb +19 -0
  47. data/lib/mongoid/errors/scope_overwrite.rb +21 -0
  48. data/lib/mongoid/extensions.rb +6 -0
  49. data/lib/mongoid/extensions/array/deep_copy.rb +25 -0
  50. data/lib/mongoid/extensions/hash/deep_copy.rb +25 -0
  51. data/lib/mongoid/extensions/hash/scoping.rb +1 -1
  52. data/lib/mongoid/extensions/object/deep_copy.rb +21 -0
  53. data/lib/mongoid/extensions/proc/scoping.rb +2 -2
  54. data/lib/mongoid/extensions/symbol/inflections.rb +1 -0
  55. data/lib/mongoid/fields.rb +171 -104
  56. data/lib/mongoid/fields/{serializable → internal}/array.rb +33 -1
  57. data/lib/mongoid/fields/{serializable → internal}/big_decimal.rb +16 -1
  58. data/lib/mongoid/fields/{serializable → internal}/bignum.rb +1 -1
  59. data/lib/mongoid/fields/{serializable → internal}/binary.rb +1 -1
  60. data/lib/mongoid/fields/{serializable → internal}/boolean.rb +16 -1
  61. data/lib/mongoid/fields/{serializable → internal}/date.rb +1 -1
  62. data/lib/mongoid/fields/{serializable → internal}/date_time.rb +1 -1
  63. data/lib/mongoid/fields/{serializable → internal}/fixnum.rb +1 -1
  64. data/lib/mongoid/fields/{serializable → internal}/float.rb +16 -1
  65. data/lib/mongoid/fields/internal/foreign_keys/array.rb +74 -0
  66. data/lib/mongoid/fields/{serializable → internal}/foreign_keys/object.rb +11 -2
  67. data/lib/mongoid/fields/{serializable → internal}/hash.rb +1 -1
  68. data/lib/mongoid/fields/{serializable → internal}/integer.rb +16 -1
  69. data/lib/mongoid/fields/{serializable → internal}/localized.rb +23 -2
  70. data/lib/mongoid/fields/{serializable → internal}/nil_class.rb +16 -1
  71. data/lib/mongoid/fields/{serializable → internal}/object.rb +1 -1
  72. data/lib/mongoid/fields/{serializable → internal}/object_id.rb +16 -1
  73. data/lib/mongoid/fields/{serializable → internal}/range.rb +21 -2
  74. data/lib/mongoid/fields/{serializable → internal}/set.rb +16 -1
  75. data/lib/mongoid/fields/{serializable → internal}/string.rb +16 -1
  76. data/lib/mongoid/fields/{serializable → internal}/symbol.rb +17 -1
  77. data/lib/mongoid/fields/{serializable → internal}/time.rb +1 -1
  78. data/lib/mongoid/fields/{serializable → internal}/time_with_zone.rb +1 -1
  79. data/lib/mongoid/fields/{serializable → internal}/timekeeping.rb +16 -1
  80. data/lib/mongoid/fields/mappings.rb +8 -3
  81. data/lib/mongoid/fields/serializable.rb +34 -3
  82. data/lib/mongoid/hierarchy.rb +14 -14
  83. data/lib/mongoid/identity_map.rb +3 -2
  84. data/lib/mongoid/logger.rb +1 -7
  85. data/lib/mongoid/named_scope.rb +16 -12
  86. data/lib/mongoid/observer.rb +5 -1
  87. data/lib/mongoid/paranoia.rb +1 -0
  88. data/lib/mongoid/persistence.rb +11 -4
  89. data/lib/mongoid/persistence/atomic.rb +4 -1
  90. data/lib/mongoid/persistence/atomic/add_to_set.rb +17 -1
  91. data/lib/mongoid/persistence/atomic/sets.rb +1 -1
  92. data/lib/mongoid/railties/database.rake +1 -1
  93. data/lib/mongoid/relations.rb +1 -3
  94. data/lib/mongoid/relations/auto_save.rb +1 -1
  95. data/lib/mongoid/relations/builders.rb +1 -1
  96. data/lib/mongoid/relations/builders/embedded/many.rb +2 -6
  97. data/lib/mongoid/relations/builders/nested_attributes/many.rb +1 -1
  98. data/lib/mongoid/relations/builders/nested_attributes/one.rb +1 -1
  99. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +1 -1
  100. data/lib/mongoid/relations/cascading/delete.rb +1 -1
  101. data/lib/mongoid/relations/cyclic.rb +10 -6
  102. data/lib/mongoid/relations/embedded/atomic.rb +3 -3
  103. data/lib/mongoid/relations/embedded/many.rb +98 -20
  104. data/lib/mongoid/relations/macros.rb +2 -0
  105. data/lib/mongoid/relations/many.rb +13 -0
  106. data/lib/mongoid/relations/metadata.rb +3 -3
  107. data/lib/mongoid/relations/nested_builder.rb +4 -3
  108. data/lib/mongoid/relations/proxy.rb +0 -1
  109. data/lib/mongoid/relations/referenced/batch.rb +3 -2
  110. data/lib/mongoid/relations/referenced/in.rb +3 -3
  111. data/lib/mongoid/relations/referenced/many.rb +89 -10
  112. data/lib/mongoid/relations/referenced/many_to_many.rb +34 -43
  113. data/lib/mongoid/relations/referenced/one.rb +8 -4
  114. data/lib/mongoid/relations/synchronization.rb +22 -5
  115. data/lib/mongoid/threaded.rb +38 -276
  116. data/lib/mongoid/threaded/lifecycle.rb +18 -18
  117. data/lib/mongoid/timestamps/updated.rb +13 -3
  118. data/lib/mongoid/validations.rb +22 -1
  119. data/lib/mongoid/validations/presence.rb +40 -0
  120. data/lib/mongoid/validations/uniqueness.rb +14 -3
  121. data/lib/mongoid/version.rb +1 -1
  122. data/lib/mongoid/versioning.rb +6 -2
  123. data/lib/rails/mongoid.rb +7 -1
  124. metadata +64 -45
  125. data/lib/mongoid/fields/serializable/foreign_keys/array.rb +0 -42
  126. data/lib/mongoid/relations/embedded/sort.rb +0 -31
@@ -116,6 +116,19 @@ module Mongoid #:nodoc:
116
116
  target.map { |document| document.serializable_hash(options) }
117
117
  end
118
118
 
119
+ # Get a criteria for the embedded documents without the default scoping
120
+ # applied.
121
+ #
122
+ # @example Get the unscoped criteria.
123
+ # person.addresses.unscoped
124
+ #
125
+ # @return [ Criteria ] The unscoped criteria.
126
+ #
127
+ # @since 2.4.0
128
+ def unscoped
129
+ criteria.unscoped
130
+ end
131
+
119
132
  private
120
133
 
121
134
  # Find the first object given the supplied attributes or create/initialize it.
@@ -197,13 +197,13 @@ module Mongoid # :nodoc:
197
197
  # @example Get the eager loading criteria.
198
198
  # metadata.eager_load(criteria)
199
199
  #
200
- # @param [ Criteria ] criteria The criteria to load from.
200
+ # @param [ Array<Object> ] ids The ids of the returned parents.
201
201
  #
202
202
  # @return [ Criteria ] The eager loading criteria.
203
203
  #
204
204
  # @since 2.2.0
205
- def eager_load(criteria)
206
- relation.eager_load(self, criteria.clone)
205
+ def eager_load(ids)
206
+ relation.eager_load(self, ids)
207
207
  end
208
208
 
209
209
  # Will determine if the relation is an embedded one or not. Currently
@@ -60,15 +60,16 @@ module Mongoid # :nodoc:
60
60
  # @todo Durran: Move this into a common reusable place.
61
61
  #
62
62
  # @example Convert the id.
63
- # builder.convert_id("4d371b444835d98b8b000010")
63
+ # builder.convert_id(Person, "4d371b444835d98b8b000010")
64
64
  #
65
+ # @param [ Class ] klass The class we're trying to convert for.
65
66
  # @param [ String ] id The id, usually coming from the form.
66
67
  #
67
68
  # @return [ BSON::ObjectId, String, Object ] The converted id.
68
69
  #
69
70
  # @since 2.0.0.rc.6
70
- def convert_id(id)
71
- metadata.constraint.convert(id)
71
+ def convert_id(klass, id)
72
+ BSON::ObjectId.convert(klass, id)
72
73
  end
73
74
  end
74
75
  end
@@ -18,7 +18,6 @@ module Mongoid # :nodoc:
18
18
  # Backwards compatibility with Mongoid beta releases.
19
19
  delegate :klass, :to => :metadata
20
20
  delegate :bind_one, :unbind_one, :to => :binding
21
- delegate :collection_name, :to => :base
22
21
 
23
22
  # Convenience for setting the target and the metadata properties since
24
23
  # all proxies will need to do this.
@@ -38,11 +38,12 @@ module Mongoid #:nodoc:
38
38
  #
39
39
  # @since 2.0.2, batch-relational-insert
40
40
  def batched(&block)
41
- inserter = Threaded.insert ||= Insert.new
41
+ name = collection.name
42
+ inserter = Threaded.insert(name) || Threaded.set_insert(name, Insert.new)
42
43
  count_executions(&block)
43
44
  ensure
44
45
  if @executions.zero?
45
- Threaded.insert = nil
46
+ Threaded.set_insert(name, nil)
46
47
  inserter.execute(collection)
47
48
  end
48
49
  end
@@ -117,15 +117,15 @@ module Mongoid # :nodoc:
117
117
  # Proxy.eager_load(metadata, criteria)
118
118
  #
119
119
  # @param [ Metadata ] metadata The relation metadata.
120
- # @param [ Criteria ] criteria The criteria being used.
120
+ # @param [ Array<Object> ] ids The ids of the target docs.
121
121
  #
122
122
  # @return [ Criteria ] The criteria to eager load the relation.
123
123
  #
124
124
  # @since 2.2.0
125
- def eager_load(metadata, criteria)
125
+ def eager_load(metadata, ids)
126
126
  raise Errors::EagerLoad.new(metadata.name) if metadata.polymorphic?
127
127
  klass, foreign_key = metadata.klass, metadata.foreign_key
128
- klass.any_in("_id" => criteria.load_ids(foreign_key).uniq).each do |doc|
128
+ klass.any_in("_id" => ids).each do |doc|
129
129
  IdentityMap.set(doc)
130
130
  end
131
131
  end
@@ -29,16 +29,40 @@ module Mongoid #:nodoc:
29
29
  #
30
30
  # @since 2.0.0.beta.1
31
31
  def <<(*args)
32
+ docs = args.flatten
33
+ return concat(docs) if docs.size > 1
34
+ if doc = docs.first
35
+ append(doc)
36
+ doc.save if persistable? && !_assigning? && !doc.validated?
37
+ end
38
+ end
39
+ alias :push :<<
40
+
41
+ # Appends an array of documents to the relation. Performs a batch
42
+ # insert of the documents instead of persisting one at a time.
43
+ #
44
+ # @note When performing batch inserts the *after* callbacks will get
45
+ # executed before the documents have actually been persisted to the
46
+ # database due to an issue with Active Support's callback system - we
47
+ # cannot explicitly fire the after callbacks by themselves.
48
+ #
49
+ # @example Concat with other documents.
50
+ # person.posts.concat([ post_one, post_two ])
51
+ #
52
+ # @param [ Array<Document> ] documents The docs to add.
53
+ #
54
+ # @return [ Array<Document> ] The documents.
55
+ #
56
+ # @since 2.4.0
57
+ def concat(documents)
32
58
  batched do
33
- args.flatten.each do |doc|
59
+ documents.each do |doc|
34
60
  next unless doc
35
61
  append(doc)
36
- doc.save if persistable? && !doc.validated?
62
+ doc.save if persistable?
37
63
  end
38
64
  end
39
65
  end
40
- alias :concat :<<
41
- alias :push :<<
42
66
 
43
67
  # Build a new document from the attributes and append it to this
44
68
  # relation without saving.
@@ -66,6 +90,7 @@ module Mongoid #:nodoc:
66
90
  Factory.build(type || klass, attributes, options).tap do |doc|
67
91
  append(doc)
68
92
  yield(doc) if block_given?
93
+ doc.run_callbacks(:build) { doc }
69
94
  end
70
95
  end
71
96
  alias :new :build
@@ -293,13 +318,37 @@ module Mongoid #:nodoc:
293
318
  # @since 2.0.0.rc.1
294
319
  def substitute(replacement)
295
320
  tap do |proxy|
296
- if replacement != proxy.in_memory
321
+ if replacement
322
+ if replacement != proxy.in_memory
323
+ new_docs, docs = replacement.compact.uniq, []
324
+ new_ids = new_docs.map { |doc| doc.id }
325
+ remove_not_in(new_ids)
326
+ new_docs.each do |doc|
327
+ docs.push(doc) if doc.send(metadata.foreign_key) != base.id
328
+ end
329
+ proxy.concat(docs)
330
+ end
331
+ else
297
332
  proxy.purge
298
- proxy.push(replacement.compact.uniq) if replacement
299
333
  end
300
334
  end
301
335
  end
302
336
 
337
+ # Get a criteria for the documents without the default scoping
338
+ # applied.
339
+ #
340
+ # @example Get the unscoped criteria.
341
+ # person.posts.unscoped
342
+ #
343
+ # @return [ Criteria ] The unscoped criteria.
344
+ #
345
+ # @since 2.4.0
346
+ def unscoped
347
+ klass.unscoped.where(
348
+ metadata.foreign_key => Conversions.flag(base.id, metadata)
349
+ )
350
+ end
351
+
303
352
  private
304
353
 
305
354
  # Appends the document to the target array, updating the index on the
@@ -408,7 +457,7 @@ module Mongoid #:nodoc:
408
457
  #
409
458
  # @since 2.1.0
410
459
  def persistable?
411
- _creating? || base.persisted? && !_binding? && !_building?
460
+ !_binding? && (_creating? || base.persisted? && !_building?)
412
461
  end
413
462
 
414
463
  # Deletes all related documents from the database given the supplied
@@ -437,6 +486,36 @@ module Mongoid #:nodoc:
437
486
  end
438
487
  end
439
488
 
489
+ # Remove all the documents in the proxy that do not have the provided
490
+ # ids.
491
+ #
492
+ # @todo: Durran: Refactor 3.0. Temp for bug fix in 2.4.
493
+ #
494
+ # @example Remove all documents without the ids.
495
+ # proxy.remove_not_in([ id ])
496
+ #
497
+ # @param [ Array<Object> ] ids The ids.
498
+ #
499
+ # @since 2.4.0
500
+ def remove_not_in(ids)
501
+ removed = criteria.not_in(:_id => ids)
502
+ if metadata.destructive?
503
+ removed.delete_all
504
+ else
505
+ removed.update(metadata.foreign_key => nil)
506
+ end
507
+ in_memory.each do |doc|
508
+ if !ids.include?(doc.id)
509
+ unbind_one(doc)
510
+ added.try { |p| p.delete_one(doc) }
511
+ loaded.try { |p| p.delete_one(doc) }
512
+ if metadata.destructive?
513
+ doc.destroyed = true
514
+ end
515
+ end
516
+ end
517
+ end
518
+
440
519
  class << self
441
520
 
442
521
  # Return the builder that is responsible for generating the documents
@@ -479,14 +558,14 @@ module Mongoid #:nodoc:
479
558
  # Proxy.eager_load(metadata, criteria)
480
559
  #
481
560
  # @param [ Metadata ] metadata The relation metadata.
482
- # @param [ Criteria ] criteria The criteria being used.
561
+ # @param [ Array<Object> ] ids The ids of the base docs.
483
562
  #
484
563
  # @return [ Criteria ] The criteria to eager load the relation.
485
564
  #
486
565
  # @since 2.2.0
487
- def eager_load(metadata, criteria)
566
+ def eager_load(metadata, ids)
488
567
  klass, foreign_key = metadata.klass, metadata.foreign_key
489
- klass.any_in(foreign_key => criteria.load_ids("_id").uniq).each do |doc|
568
+ klass.any_in(foreign_key => ids).each do |doc|
490
569
  IdentityMap.set_many(doc, foreign_key => doc.send(foreign_key))
491
570
  end
492
571
  end
@@ -81,49 +81,6 @@ module Mongoid # :nodoc:
81
81
  end
82
82
  alias :new :build
83
83
 
84
- # Creates a new document on the references many relation. This will
85
- # save the document if the parent has been persisted.
86
- #
87
- # @example Create and save the new document.
88
- # person.posts.create(:text => "Testing")
89
- #
90
- # @param [ Hash ] attributes The attributes to create with.
91
- # @param [ Class ] type The optional type of document to create.
92
- #
93
- # @return [ Document ] The newly created document.
94
- #
95
- # @since 2.0.0.beta.1
96
- def create(attributes = nil, type = nil, &block)
97
- super.tap do |doc|
98
- base.send(metadata.foreign_key).delete_one(doc.id)
99
- base.push(metadata.foreign_key, doc.id)
100
- base.synced[metadata.foreign_key] = false
101
- end
102
- end
103
-
104
- # Creates a new document on the references many relation. This will
105
- # save the document if the parent has been persisted and will raise an
106
- # error if validation fails.
107
- #
108
- # @example Create and save the new document.
109
- # person.posts.create!(:text => "Testing")
110
- #
111
- # @param [ Hash ] attributes The attributes to create with.
112
- # @param [ Class ] type The optional type of document to create.
113
- #
114
- # @raise [ Errors::Validations ] If validation failed.
115
- #
116
- # @return [ Document ] The newly created document.
117
- #
118
- # @since 2.0.0.beta.1
119
- def create!(attributes = nil, type = nil, &block)
120
- super.tap do |doc|
121
- base.send(metadata.foreign_key).delete_one(doc.id)
122
- base.push(metadata.foreign_key, doc.id)
123
- base.synced[metadata.foreign_key] = false
124
- end
125
- end
126
-
127
84
  # Delete the document from the relation. This will set the foreign key
128
85
  # on the document to nil. If the dependent options on the relation are
129
86
  # :delete or :destroy the appropriate removal will occur.
@@ -171,6 +128,40 @@ module Mongoid # :nodoc:
171
128
  alias :clear :nullify
172
129
  alias :purge :nullify
173
130
 
131
+ # Substitutes the supplied target documents for the existing documents
132
+ # in the relation. If the new target is nil, perform the necessary
133
+ # deletion.
134
+ #
135
+ # @example Replace the relation.
136
+ # person.preferences.substitute([ new_post ])
137
+ #
138
+ # @param [ Array<Document> ] replacement The replacement target.
139
+ #
140
+ # @return [ Many ] The relation.
141
+ #
142
+ # @since 2.0.0.rc.1
143
+ def substitute(replacement)
144
+ tap do |proxy|
145
+ if replacement != proxy.in_memory
146
+ proxy.purge
147
+ proxy.push(replacement.compact.uniq) if replacement
148
+ end
149
+ end
150
+ end
151
+
152
+ # Get a criteria for the documents without the default scoping
153
+ # applied.
154
+ #
155
+ # @example Get the unscoped criteria.
156
+ # person.preferences.unscoped
157
+ #
158
+ # @return [ Criteria ] The unscoped criteria.
159
+ #
160
+ # @since 2.4.0
161
+ def unscoped
162
+ klass.unscoped.any_in(:_id => base.send(metadata.foreign_key))
163
+ end
164
+
174
165
  private
175
166
 
176
167
  # Appends the document to the target array, updating the index on the
@@ -53,7 +53,11 @@ module Mongoid # :nodoc:
53
53
  def substitute(replacement)
54
54
  unbind_one
55
55
  if persistable?
56
- metadata.destructive? ? send(metadata.dependent) : save
56
+ if metadata.destructive?
57
+ send(metadata.dependent)
58
+ else
59
+ save if persisted?
60
+ end
57
61
  end
58
62
  return nil unless replacement
59
63
  One.new(base, replacement, metadata)
@@ -128,14 +132,14 @@ module Mongoid # :nodoc:
128
132
  # Proxy.eager_load(metadata, criteria)
129
133
  #
130
134
  # @param [ Metadata ] metadata The relation metadata.
131
- # @param [ Criteria ] criteria The criteria being used.
135
+ # @param [ Array<Object> ] ids The ids of the base docs.
132
136
  #
133
137
  # @return [ Criteria ] The criteria to eager load the relation.
134
138
  #
135
139
  # @since 2.2.0
136
- def eager_load(metadata, criteria)
140
+ def eager_load(metadata, ids)
137
141
  klass, foreign_key = metadata.klass, metadata.foreign_key
138
- klass.any_in(foreign_key => criteria.load_ids("_id").uniq).each do |doc|
142
+ klass.any_in(foreign_key => ids).each do |doc|
139
143
  IdentityMap.set_one(doc, foreign_key => doc.send(foreign_key))
140
144
  end
141
145
  end
@@ -75,11 +75,28 @@ module Mongoid # :nodoc:
75
75
  #
76
76
  # @since 2.1.0
77
77
  def update_inverse_keys(meta)
78
- return unless changes.has_key?(meta.foreign_key)
79
- old, new = changes[meta.foreign_key]
80
- adds, subs = new - (old || []), (old || []) - new
81
- meta.criteria(adds).add_to_set(meta.inverse_foreign_key, id) unless adds.empty?
82
- meta.criteria(subs).pull(meta.inverse_foreign_key, id) unless subs.empty?
78
+ if changes.has_key?(meta.foreign_key)
79
+ old, new = changes[meta.foreign_key]
80
+ adds, subs = new - (old || []), (old || []) - new
81
+
82
+ # If we are autosaving we don't want a duplicate to get added - the
83
+ # $addToSet would run previously and then the $pushAll from the
84
+ # inverse on the autosave would cause this. We delete each id from
85
+ # what's in memory in case a mix of id addition and object addition
86
+ # had occurred.
87
+ if meta.autosave?
88
+ send(meta.name).in_memory.each do |doc|
89
+ adds.delete_one(doc.id)
90
+ end
91
+ end
92
+
93
+ unless adds.empty?
94
+ meta.criteria(adds).add_to_set(meta.inverse_foreign_key, id)
95
+ end
96
+ unless subs.empty?
97
+ meta.criteria(subs).pull(meta.inverse_foreign_key, id)
98
+ end
99
+ end
83
100
  end
84
101
 
85
102
  module ClassMethods #:nodoc:
@@ -8,76 +8,60 @@ module Mongoid #:nodoc:
8
8
  module Threaded
9
9
  extend self
10
10
 
11
- # Begins a assigning block.
11
+ # Begin entry into a named thread local stack.
12
12
  #
13
- # @example Begin the assign.
14
- # Threaded.begin_assign
13
+ # @example Begin entry into the stack.
14
+ # Threaded.begin(:create)
15
15
  #
16
- # @return [ true ] Always true.
16
+ # @param [ Symbol ] name The name of the stack
17
17
  #
18
- # @since 2.1.9
19
- def begin_assign
20
- assign_stack.push(true)
21
- end
22
-
23
- # Begins a binding block.
24
- #
25
- # @example Begin the bind.
26
- # Threaded.begin_bind
18
+ # @return [ true ] True.
27
19
  #
28
- # @return [ true ] Always true.
29
- #
30
- # @since 2.1.9
31
- def begin_bind
32
- bind_stack.push(true)
20
+ # @since 2.4.0
21
+ def begin(name)
22
+ stack(name).push(true)
33
23
  end
34
24
 
35
- # Begins a building block.
25
+ # Are in the middle of executing the named stack
36
26
  #
37
- # @example Begin the build.
38
- # Threaded.begin_build
27
+ # @example Are we in the stack execution?
28
+ # Threaded.executing?(:create)
39
29
  #
40
- # @return [ true ] Always true.
30
+ # @param [ Symbol ] name The name of the stack
41
31
  #
42
- # @since 2.1.9
43
- def begin_build
44
- build_stack.push(true)
45
- end
46
-
47
- # Begins a creating block.
48
- #
49
- # @example Begin the create.
50
- # Threaded.begin_create
32
+ # @return [ true ] If the stack is being executed.
51
33
  #
52
- # @return [ true ] Always true.
53
- #
54
- # @since 2.1.9
55
- def begin_create
56
- create_stack.push(true)
34
+ # @since 2.4.0
35
+ def executing?(name)
36
+ !stack(name).empty?
57
37
  end
58
38
 
59
- # Begins a loading block.
39
+ # Exit from a named thread local stack.
60
40
  #
61
- # @example Begin the load.
62
- # Threaded.begin_load
41
+ # @example Exit from the stack.
42
+ # Threaded.exit(:create)
63
43
  #
64
- # @return [ true ] Always true.
44
+ # @param [ Symbol ] name The name of the stack
65
45
  #
66
- # @since 2.3.2
67
- def begin_load
68
- load_stack.push(true)
46
+ # @return [ true ] True.
47
+ #
48
+ # @since 2.4.0
49
+ def exit(name)
50
+ stack(name).pop
69
51
  end
70
52
 
71
- # Begins a loading revision block.
53
+ # Get the named stack.
54
+ #
55
+ # @example Get a stack by name
56
+ # Threaded.stack(:create)
72
57
  #
73
- # @example Begin the revision load.
74
- # Threaded.begin_load_revision
58
+ # @param [ Symbol ] name The name of the stack
75
59
  #
76
- # @return [ true ] Always true.
60
+ # @return [ Array ] The stack.
77
61
  #
78
- # @since 2.3.4
79
- def begin_load_revision
80
- load_revision_stack.push(true)
62
+ # @since 2.4.0
63
+ def stack(name)
64
+ Thread.current[:"[mongoid]:#{name}-stack"] ||= []
81
65
  end
82
66
 
83
67
  # Begin validating a document on the current thread.
@@ -92,156 +76,6 @@ module Mongoid #:nodoc:
92
76
  validations_for(document.class).push(document.id)
93
77
  end
94
78
 
95
- # Is the current thread in assigning mode?
96
- #
97
- # @example Is the thread in assigning mode?
98
- # Threaded.assigning?
99
- #
100
- # @return [ true, false ] If the thread is in assigning mode?
101
- #
102
- # @since 2.1.0
103
- def assigning?
104
- !assign_stack.empty?
105
- end
106
-
107
- # Is the current thread in binding mode?
108
- #
109
- # @example Is the thread in binding mode?
110
- # Threaded.binding?
111
- #
112
- # @return [ true, false ] If the thread is in binding mode?
113
- #
114
- # @since 2.1.0
115
- def binding?
116
- !bind_stack.empty?
117
- end
118
-
119
- # Is the current thread in building mode?
120
- #
121
- # @example Is the thread in building mode?
122
- # Threaded.building?
123
- #
124
- # @return [ true, false ] If the thread is in building mode?
125
- #
126
- # @since 2.1.0
127
- def building?
128
- !build_stack.empty?
129
- end
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.1.0
139
- def creating?
140
- !create_stack.empty?
141
- end
142
-
143
- # Is the current thread in loading mode?
144
- #
145
- # @example Is the thread in loading mode?
146
- # Threaded.loading?
147
- #
148
- # @return [ true, false ] If the thread is in loading mode?
149
- #
150
- # @since 2.3.2
151
- def loading?
152
- !load_stack.empty?
153
- end
154
-
155
- # Is the current thread in revision load mode?
156
- #
157
- # @example Is the thread in revision load mode?
158
- # Threaded.loading_revision?
159
- #
160
- # @return [ true, false ] If the thread is in revision load mode?
161
- #
162
- # @since 2.3.4
163
- def loading_revision?
164
- !load_revision_stack.empty?
165
- end
166
-
167
- # Get the assign stack for the current thread. Is simply an array of calls
168
- # to Mongoid's assigning method.
169
- #
170
- # @example Get the assign stack.
171
- # Threaded.assign_stack
172
- #
173
- # @return [ Array ] The array of assign calls.
174
- #
175
- # @since 2.1.9
176
- def assign_stack
177
- Thread.current[:"[mongoid]:assign-stack"] ||= []
178
- end
179
-
180
- # Get the bind stack for the current thread. Is simply an array of calls
181
- # to Mongoid's binding method.
182
- #
183
- # @example Get the bind stack.
184
- # Threaded.bind_stack
185
- #
186
- # @return [ Array ] The array of bind calls.
187
- #
188
- # @since 2.1.9
189
- def bind_stack
190
- Thread.current[:"[mongoid]:bind-stack"] ||= []
191
- end
192
-
193
- # Get the build stack for the current thread. Is simply an array of calls
194
- # to Mongoid's building method.
195
- #
196
- # @example Get the build stack.
197
- # Threaded.build_stack
198
- #
199
- # @return [ Array ] The array of build calls.
200
- #
201
- # @since 2.1.9
202
- def build_stack
203
- Thread.current[:"[mongoid]:build-stack"] ||= []
204
- end
205
-
206
- # Get the create stack for the current thread. Is simply an array of calls
207
- # to Mongoid's creating method.
208
- #
209
- # @example Get the create stack.
210
- # Threaded.create_stack
211
- #
212
- # @return [ Array ] The array of create calls.
213
- #
214
- # @since 2.1.9
215
- def create_stack
216
- Thread.current[:"[mongoid]:create-stack"] ||= []
217
- end
218
-
219
- # Get the load stack for the current thread. Is simply an array of calls
220
- # to Mongoid's loading method.
221
- #
222
- # @example Get the load stack.
223
- # Threaded.load_stack
224
- #
225
- # @return [ Array ] The array of load calls.
226
- #
227
- # @since 2.3.2
228
- def load_stack
229
- Thread.current[:"[mongoid]:load-stack"] ||= []
230
- end
231
-
232
- # Get the revision load stack for the current thread. Is simply an array
233
- # of calls to Mongoid's loading_revision method.
234
- #
235
- # @example Get the revision load stack.
236
- # Threaded.load_revision_stack
237
- #
238
- # @return [ Array ] The array of load revision calls.
239
- #
240
- # @since 2.3.4
241
- def load_revision_stack
242
- Thread.current[:"[mongoid]:load-revision-stack"] ||= []
243
- end
244
-
245
79
  # Clear out all the safety options set using the safely proxy.
246
80
  #
247
81
  # @example Clear out the options.
@@ -265,78 +99,6 @@ module Mongoid #:nodoc:
265
99
  self.timeless = false
266
100
  end
267
101
 
268
- # Exit the assigning block.
269
- #
270
- # @example Exit the assigning block.
271
- # Threaded.exit_assign
272
- #
273
- # @return [ true ] The last element in the stack.
274
- #
275
- # @since 2.1.9
276
- def exit_assign
277
- assign_stack.pop
278
- end
279
-
280
- # Exit the binding block.
281
- #
282
- # @example Exit the binding block.
283
- # Threaded.exit_bind
284
- #
285
- # @return [ true ] The last element in the stack.
286
- #
287
- # @since 2.1.9
288
- def exit_bind
289
- bind_stack.pop
290
- end
291
-
292
- # Exit the building block.
293
- #
294
- # @example Exit the building block.
295
- # Threaded.exit_build
296
- #
297
- # @return [ true ] The last element in the stack.
298
- #
299
- # @since 2.1.9
300
- def exit_build
301
- build_stack.pop
302
- end
303
-
304
- # Exit the creating block.
305
- #
306
- # @example Exit the creating block.
307
- # Threaded.exit_create
308
- #
309
- # @return [ true ] The last element in the stack.
310
- #
311
- # @since 2.1.9
312
- def exit_create
313
- create_stack.pop
314
- end
315
-
316
- # Exit the loading block.
317
- #
318
- # @example Exit the loading block.
319
- # Threaded.exit_load
320
- #
321
- # @return [ true ] The last element in the stack.
322
- #
323
- # @since 2.1.9
324
- def exit_load
325
- load_stack.pop
326
- end
327
-
328
- # Exit the revision loading block.
329
- #
330
- # @example Exit the revision loading block.
331
- # Threaded.exit_load_revision
332
- #
333
- # @return [ true ] The last element in the stack.
334
- #
335
- # @since 2.3.4
336
- def exit_load_revision
337
- load_revision_stack.pop
338
- end
339
-
340
102
  # Exit validating a document on the current thread.
341
103
  #
342
104
  # @example Exit validation.
@@ -369,8 +131,8 @@ module Mongoid #:nodoc:
369
131
  # @return [ Object ] The batch insert consumer.
370
132
  #
371
133
  # @since 2.1.0
372
- def insert
373
- Thread.current[:"[mongoid]:insert-consumer"]
134
+ def insert(name)
135
+ Thread.current[:"[mongoid][#{name}]:insert-consumer"]
374
136
  end
375
137
 
376
138
  # Set the insert consumer on the current thread.
@@ -383,8 +145,8 @@ module Mongoid #:nodoc:
383
145
  # @return [ Object ] The insert consumer.
384
146
  #
385
147
  # @since 2.1.0
386
- def insert=(consumer)
387
- Thread.current[:"[mongoid]:insert-consumer"] = consumer
148
+ def set_insert(name, consumer)
149
+ Thread.current[:"[mongoid][#{name}]:insert-consumer"] = consumer
388
150
  end
389
151
 
390
152
  # Get the safety options for the current thread.