mongoid 7.1.0 → 7.1.6

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 (131) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +6 -6
  5. data/README.md +1 -1
  6. data/Rakefile +14 -5
  7. data/lib/config/locales/en.yml +5 -5
  8. data/lib/mongoid/association/accessors.rb +37 -2
  9. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  10. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  11. data/lib/mongoid/association/proxy.rb +1 -1
  12. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -1
  13. data/lib/mongoid/association/referenced/belongs_to/eager.rb +38 -2
  14. data/lib/mongoid/association/referenced/eager.rb +29 -9
  15. data/lib/mongoid/association/referenced/has_one/proxy.rb +6 -1
  16. data/lib/mongoid/atomic.rb +13 -3
  17. data/lib/mongoid/clients/factory.rb +2 -2
  18. data/lib/mongoid/clients/options.rb +8 -8
  19. data/lib/mongoid/clients/sessions.rb +20 -4
  20. data/lib/mongoid/clients/storage_options.rb +5 -5
  21. data/lib/mongoid/config.rb +39 -9
  22. data/lib/mongoid/criteria.rb +23 -4
  23. data/lib/mongoid/criteria/modifiable.rb +2 -1
  24. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  25. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +6 -6
  26. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +12 -0
  27. data/lib/mongoid/criteria/queryable/mergeable.rb +75 -8
  28. data/lib/mongoid/criteria/queryable/pipeline.rb +3 -2
  29. data/lib/mongoid/criteria/queryable/selectable.rb +120 -13
  30. data/lib/mongoid/criteria/queryable/storable.rb +104 -99
  31. data/lib/mongoid/errors/eager_load.rb +2 -0
  32. data/lib/mongoid/errors/no_client_config.rb +2 -2
  33. data/lib/mongoid/errors/no_default_client.rb +1 -1
  34. data/lib/mongoid/extensions/hash.rb +4 -2
  35. data/lib/mongoid/extensions/regexp.rb +1 -1
  36. data/lib/mongoid/fields.rb +2 -1
  37. data/lib/mongoid/fields/validators/macro.rb +4 -1
  38. data/lib/mongoid/matchable/regexp.rb +2 -2
  39. data/lib/mongoid/persistable/pushable.rb +11 -2
  40. data/lib/mongoid/persistence_context.rb +6 -6
  41. data/lib/mongoid/query_cache.rb +61 -18
  42. data/lib/mongoid/serializable.rb +9 -3
  43. data/lib/mongoid/tasks/database.rb +38 -3
  44. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  45. data/lib/mongoid/version.rb +1 -1
  46. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +32 -23
  47. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  48. data/spec/app/models/coding.rb +4 -0
  49. data/spec/app/models/coding/pull_request.rb +12 -0
  50. data/spec/app/models/delegating_patient.rb +16 -0
  51. data/spec/app/models/passport.rb +1 -0
  52. data/spec/app/models/person.rb +2 -0
  53. data/spec/app/models/phone.rb +1 -0
  54. data/spec/app/models/publication.rb +5 -0
  55. data/spec/app/models/publication/encyclopedia.rb +12 -0
  56. data/spec/app/models/publication/review.rb +14 -0
  57. data/spec/app/models/series.rb +1 -0
  58. data/spec/app/models/wiki_page.rb +1 -0
  59. data/spec/integration/app_spec.rb +254 -0
  60. data/spec/integration/associations/embedded_spec.rb +54 -0
  61. data/spec/integration/associations/embeds_many_spec.rb +24 -0
  62. data/spec/integration/associations/embeds_one_spec.rb +24 -0
  63. data/spec/integration/associations/has_many_spec.rb +76 -0
  64. data/spec/integration/associations/has_one_spec.rb +76 -0
  65. data/spec/integration/bson_regexp_raw_spec.rb +20 -0
  66. data/spec/integration/criteria/date_field_spec.rb +41 -0
  67. data/spec/integration/criteria/logical_spec.rb +13 -0
  68. data/spec/integration/document_spec.rb +22 -0
  69. data/spec/integration/shardable_spec.rb +20 -4
  70. data/spec/lite_spec_helper.rb +12 -4
  71. data/spec/mongoid/association/accessors_spec.rb +238 -63
  72. data/spec/mongoid/association/embedded/embeds_many_models.rb +19 -0
  73. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  74. data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
  75. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +193 -10
  76. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +140 -1
  77. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +105 -0
  78. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  79. data/spec/mongoid/clients/factory_spec.rb +8 -8
  80. data/spec/mongoid/clients/options_spec.rb +11 -11
  81. data/spec/mongoid/clients/sessions_spec.rb +8 -4
  82. data/spec/mongoid/clients/transactions_spec.rb +20 -8
  83. data/spec/mongoid/clients_spec.rb +2 -2
  84. data/spec/mongoid/contextual/atomic_spec.rb +22 -11
  85. data/spec/mongoid/contextual/geo_near_spec.rb +11 -2
  86. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  87. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  88. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +1 -1
  89. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  90. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  91. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +19 -7
  92. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +28 -1
  93. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +45 -12
  94. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +1051 -392
  95. data/spec/mongoid/criteria/queryable/selectable_spec.rb +52 -0
  96. data/spec/mongoid/criteria/queryable/storable_spec.rb +80 -2
  97. data/spec/mongoid/criteria_spec.rb +36 -2
  98. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  99. data/spec/mongoid/errors/no_client_config_spec.rb +2 -2
  100. data/spec/mongoid/errors/no_client_database_spec.rb +3 -3
  101. data/spec/mongoid/errors/no_client_hosts_spec.rb +3 -3
  102. data/spec/mongoid/fields_spec.rb +24 -1
  103. data/spec/mongoid/indexable_spec.rb +6 -4
  104. data/spec/mongoid/matchable/default_spec.rb +1 -1
  105. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  106. data/spec/mongoid/matchable_spec.rb +2 -2
  107. data/spec/mongoid/persistable/pushable_spec.rb +55 -1
  108. data/spec/mongoid/query_cache_spec.rb +77 -9
  109. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  110. data/spec/mongoid/scopable_spec.rb +2 -1
  111. data/spec/mongoid/serializable_spec.rb +129 -18
  112. data/spec/mongoid/shardable_models.rb +1 -1
  113. data/spec/mongoid/shardable_spec.rb +2 -2
  114. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  115. data/spec/mongoid/tasks/database_spec.rb +1 -1
  116. data/spec/shared/LICENSE +20 -0
  117. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  118. data/spec/shared/lib/mrss/cluster_config.rb +211 -0
  119. data/spec/shared/lib/mrss/constraints.rb +312 -0
  120. data/spec/shared/lib/mrss/lite_constraints.rb +175 -0
  121. data/spec/shared/lib/mrss/spec_organizer.rb +149 -0
  122. data/spec/spec_helper.rb +2 -31
  123. data/spec/support/child_process_helper.rb +76 -0
  124. data/spec/support/cluster_config.rb +3 -3
  125. data/spec/support/constraints.rb +26 -10
  126. data/spec/support/expectations.rb +3 -1
  127. data/spec/support/helpers.rb +11 -0
  128. data/spec/support/session_registry.rb +50 -0
  129. data/spec/support/spec_config.rb +12 -4
  130. metadata +520 -473
  131. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8352346c7b47e2323d4afee8968a5581b091735a11d3aacaf9a1c73197d511db
4
- data.tar.gz: 4780a1d8ec316330301e933a145957e48f4927c9fbcbe582404f062179280947
3
+ metadata.gz: 2dc047b0566d39e527a503400ca7bd624afcea9aebd7db795870333a795644c3
4
+ data.tar.gz: 600c7431bf9a3464f24794c02807510f22b56d74a3981826cb1c6f2013a6c5e5
5
5
  SHA512:
6
- metadata.gz: 870e9d5aff9bd06217cea69dd7b86b15ea9ec89464a8e6f579e24e58789a1e5612256026927e6cdd0e17cb39340cf4ef7758bc75fc1b5176939f8b11968bd76c
7
- data.tar.gz: fc095139739ed83771b35d9f2c91b2a0e33bb99125df7622fe0f8f24bf971c6d0cabcd5ac507d4bb72e8a178bc988661197258f20f0193b7e72c8d7a219d2459
6
+ metadata.gz: 6a430d43d0646baa0424f06471f4891330470d85dc23af4e2166779e36fa2e58cc44e1d645062290e8ec30dbad583dfc42f4d898b66ff5995422489e8868f577
7
+ data.tar.gz: d35537d5127ff1840f4b8c920a446a22bee7bedcf675fe8212989798cc949d1d0e01c03e6df1b782def1956bbd4ecc81f1812d3b768e17029cd87e5e6583df96
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1848,18 +1848,18 @@ child elements.
1848
1848
  set a child on a relation without the proper inverse_of definitions
1849
1849
  due to Mongoid not being able to determine it.
1850
1850
 
1851
- class Lush
1851
+ class Car
1852
1852
  include Mongoid::Document
1853
- embeds_one :whiskey, class_name: "Drink"
1853
+ embeds_one :engine, class_name: "Motor"
1854
1854
  end
1855
1855
 
1856
- class Drink
1856
+ class Motor
1857
1857
  include Mongoid::Document
1858
- embedded_in :alcoholic, class_name: "Lush"
1858
+ embedded_in :machine, class_name: "Car"
1859
1859
  end
1860
1860
 
1861
- lush = Lush.new
1862
- lush.whiskey = Drink.new # raises an InverseNotFound error.
1861
+ car = Car.new
1862
+ car.engine = Motor.new # raises an InverseNotFound error.
1863
1863
 
1864
1864
  * \#1680 Polymorphic relations now use `*_type` keys in lookup queries.
1865
1865
 
data/README.md CHANGED
@@ -31,7 +31,7 @@ Support
31
31
  -------
32
32
 
33
33
  * [Stack Overflow](http://stackoverflow.com/questions/tagged/mongoid)
34
- * [Mongoid Google Group](http://groups.google.com/group/mongoid)
34
+ * [MongoDB Community Forum](https://developer.mongodb.com/community/forums/tags/c/drivers-odms-connectors/7/mongoid-odm)
35
35
  * [#mongoid](http://webchat.freenode.net/?channels=mongoid) on Freenode IRC
36
36
 
37
37
  License
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler"
4
+ require "bundler/gem_tasks"
4
5
  Bundler.setup
5
6
 
6
7
  require "rake"
@@ -9,6 +10,9 @@ require "rspec/core/rake_task"
9
10
  $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
10
11
  require "mongoid/version"
11
12
 
13
+ tasks = Rake.application.instance_variable_get('@tasks')
14
+ tasks['release:do'] = tasks.delete('release')
15
+
12
16
  task :gem => :build
13
17
  task :build do
14
18
  system "gem build mongoid.gemspec"
@@ -18,11 +22,8 @@ task :install => :build do
18
22
  system "sudo gem install mongoid-#{Mongoid::VERSION}.gem"
19
23
  end
20
24
 
21
- task :release => :build do
22
- system "git tag -a v#{Mongoid::VERSION} -m 'Tagging #{Mongoid::VERSION}'"
23
- system "git push --tags"
24
- system "gem push mongoid-#{Mongoid::VERSION}.gem"
25
- system "rm mongoid-#{Mongoid::VERSION}.gem"
25
+ task :release do
26
+ raise "Please use ./release.sh to release"
26
27
  end
27
28
 
28
29
  RSpec::Core::RakeTask.new("spec") do |spec|
@@ -47,3 +48,11 @@ namespace :docs do
47
48
  system "yardoc -o #{out} --title mongoid-#{Mongoid::VERSION}"
48
49
  end
49
50
  end
51
+
52
+ namespace :release do
53
+ task :check_private_key do
54
+ unless File.exist?('gem-private_key.pem')
55
+ raise "No private key present, cannot release"
56
+ end
57
+ end
58
+ end
@@ -249,7 +249,7 @@ en:
249
249
  Example:\n
250
250
  \_\_class Band\n
251
251
  \_\_\_\_include Mongoid::Document\n
252
- \_\_\_\_store_in collection: 'artists', database: 'secondary'\n
252
+ \_\_\_\_store_in collection: 'artists', database: 'music'\n
253
253
  \_\_end\n\n"
254
254
  invalid_storage_parent:
255
255
  message: "Invalid store_in call on class %{klass}."
@@ -282,13 +282,13 @@ en:
282
282
  you will need to explicitly tell Mongoid on the association what
283
283
  the inverse is.\n\n
284
284
  Example:\n
285
- \_\_class Lush\n
285
+ \_\_class Car\n
286
286
  \_\_\_\_include Mongoid::Document\n
287
- \_\_\_\_has_one :whiskey, class_name: \"Drink\", inverse_of: :alcoholic\n
287
+ \_\_\_\_has_one :engine, class_name: \"Motor\", inverse_of: :machine\n
288
288
  \_\_end\n\n
289
- \_\_class Drink\n
289
+ \_\_class Motor\n
290
290
  \_\_\_\_include Mongoid::Document\n
291
- \_\_\_\_belongs_to :alcoholic, class_name: \"Lush\", inverse_of: :whiskey\n
291
+ \_\_\_\_belongs_to :machine, class_name: \"Car\", inverse_of: :engine\n
292
292
  \_\_end"
293
293
  invalid_set_polymorphic_relation:
294
294
  message: "The %{name} attribute can't be set to an instance of
@@ -131,15 +131,50 @@ module Mongoid
131
131
  # @api private
132
132
  def _mongoid_filter_selected_fields(assoc_key)
133
133
  return nil unless __selected_fields
134
+
135
+ projecting_assoc = false
136
+
134
137
  filtered = {}
135
138
  __selected_fields.each do |k, v|
136
139
  bits = k.split('.')
140
+
141
+ # If we are asked to project an association, we need all of that
142
+ # association's fields. However, we may be asked to project
143
+ # an association *and* its fields in the same query. In this case
144
+ # behavior differs according to server version:
145
+ #
146
+ # 4.2 and lower take the most recent projection specification, meaning
147
+ # projecting foo followed by foo.bar effectively projects foo.bar and
148
+ # projecting foo.bar followed by foo effectively projects foo.
149
+ # To match this behavior we need to track when we are being asked
150
+ # to project the association and when we are asked to project a field,
151
+ # and if we are asked to project the association last we need to
152
+ # remove any field projections.
153
+ #
154
+ # 4.4 (and presumably higher) do not allow projection to be on an
155
+ # association and its field, so it doesn't matter what we do. Hence
156
+ # we just need to handle the 4.2 and lower case correctly.
137
157
  if bits.first == assoc_key
138
- bits.shift
139
- filtered[bits.join('.')] = v
158
+ # Projecting the entire association OR some of its fields
159
+ if bits.length > 1
160
+ # Projecting a field
161
+ bits.shift
162
+ filtered[bits.join('.')] = v
163
+ projecting_assoc = false
164
+ else
165
+ # Projecting the entire association
166
+ projecting_assoc = true
167
+ end
140
168
  end
141
169
  end
142
170
 
171
+ if projecting_assoc
172
+ # The last projection was of the entire association; we may have
173
+ # also been projecting fields, but discard the field projections
174
+ # and return nil indicating we want the entire association.
175
+ return nil
176
+ end
177
+
143
178
  # Positional projection is specified as "foo.$". In this case the
144
179
  # document that the $ is referring to should be retrieved with all
145
180
  # fields. See https://docs.mongodb.com/manual/reference/operator/projection/positional/
@@ -200,7 +200,8 @@ module Mongoid
200
200
  def determine_inverses(other)
201
201
  matches = relation_class.relations.values.select do |rel|
202
202
  relation_complements.include?(rel.class) &&
203
- rel.relation_class_name == inverse_class_name
203
+ # https://jira.mongodb.org/browse/MONGOID-4882
204
+ rel.relation_class_name.sub(/\A::/, '') == inverse_class_name
204
205
  end
205
206
  if matches.size > 1
206
207
  raise Errors::AmbiguousRelationship.new(relation_class, @owner_class, name, matches)
@@ -162,7 +162,8 @@ module Mongoid
162
162
  def determine_inverses(other)
163
163
  matches = relation_class.relations.values.select do |rel|
164
164
  relation_complements.include?(rel.class) &&
165
- rel.relation_class_name == inverse_class_name
165
+ # https://jira.mongodb.org/browse/MONGOID-4882
166
+ rel.relation_class_name.sub(/\A::/, '') == inverse_class_name
166
167
 
167
168
  end
168
169
  if matches.size > 1
@@ -16,7 +16,7 @@ module Mongoid
16
16
  # We undefine most methods to get them sent through to the target.
17
17
  instance_methods.each do |method|
18
18
  undef_method(method) unless
19
- method =~ /^(__.*|send|object_id|equal\?|respond_to\?|tap|public_send|extend_proxy|extend_proxies)$/
19
+ method =~ /\A(__.*|send|object_id|equal\?|respond_to\?|tap|public_send|extend_proxy|extend_proxies)\z/
20
20
  end
21
21
 
22
22
  include Threaded::Lifecycle
@@ -76,7 +76,7 @@ module Mongoid
76
76
  # @since 3.0.0
77
77
  def check_polymorphic_inverses!(doc)
78
78
  inverses = _association.inverses(doc)
79
- if inverses.count > 1 && _base.send(_association.foreign_key).nil?
79
+ if inverses.length > 1 && _base.send(_association.foreign_key).nil?
80
80
  raise Errors::InvalidSetPolymorphicRelation.new(
81
81
  _association.name, _base.class.name, _target.class.name
82
82
  )
@@ -12,8 +12,6 @@ module Mongoid
12
12
  private
13
13
 
14
14
  def preload
15
- raise Errors::EagerLoad.new(@association.name) if @association.polymorphic?
16
-
17
15
  @docs.each do |d|
18
16
  set_relation(d, nil)
19
17
  end
@@ -24,6 +22,44 @@ module Mongoid
24
22
  end
25
23
  end
26
24
 
25
+ # Retrieves the documents referenced by the association, and
26
+ # yields each one sequentially to the provided block. If the
27
+ # association is not polymorphic, all documents are retrieved in
28
+ # a single query. If the association is polymorphic, one query is
29
+ # issued per association target class.
30
+ def each_loaded_document(&block)
31
+ if @association.polymorphic?
32
+ keys_by_type_from_docs.each do |type, keys|
33
+ each_loaded_document_of_class(Object.const_get(type), keys, &block)
34
+ end
35
+ else
36
+ super
37
+ end
38
+ end
39
+
40
+ # Returns a map from association target class name to foreign key
41
+ # values for the documents of that association target class,
42
+ # as referenced by this association.
43
+ def keys_by_type_from_docs
44
+ inverse_type_field = @association.inverse_type
45
+
46
+ @docs.each_with_object({}) do |doc, keys_by_type|
47
+ next unless doc.respond_to?(inverse_type_field) && doc.respond_to?(group_by_key)
48
+ inverse_type_name = doc.send(inverse_type_field)
49
+ # If a particular document does not have a value for this
50
+ # association, inverse_type_name will be nil.
51
+ next if inverse_type_name.nil?
52
+
53
+ key_value = doc.send(group_by_key)
54
+ # If a document has the *_type field set but the corresponding
55
+ # *_id field not set, the key value here will be nil.
56
+ next unless key_value
57
+
58
+ keys_by_type[inverse_type_name] ||= []
59
+ keys_by_type[inverse_type_name].push(key_value)
60
+ end
61
+ end
62
+
27
63
  def group_by_key
28
64
  @association.foreign_key
29
65
  end
@@ -59,17 +59,29 @@ module Mongoid
59
59
  raise NotImplementedError
60
60
  end
61
61
 
62
- # Run the preloader.
63
- #
64
- # @example Iterate over the documents loaded for the current association
65
- # loader.each_loaded_document { |doc| }
62
+ # Retrieves the documents referenced by the association, and
63
+ # yields each one sequentially to the provided block. If the
64
+ # association is not polymorphic, all documents are retrieved in
65
+ # a single query. If the association is polymorphic, one query is
66
+ # issued per association target class.
66
67
  #
67
68
  # @since 4.0.0
68
- def each_loaded_document
69
- doc_keys = keys_from_docs
70
- return @association.klass.none if doc_keys.all?(&:nil?)
69
+ def each_loaded_document(&block)
70
+ each_loaded_document_of_class(@association.klass, keys_from_docs, &block)
71
+ end
71
72
 
72
- criteria = @association.klass.any_in(key => doc_keys)
73
+ # Retrieves the documents of the specified class, that have the
74
+ # foreign key included in the specified list of keys.
75
+ #
76
+ # When the documents are retrieved, the set of inclusions applied
77
+ # is the set of inclusions applied to the host document minus the
78
+ # association that is being eagerly loaded.
79
+ private def each_loaded_document_of_class(cls, keys)
80
+ # Note: keys should not include nil elements.
81
+ # Upstream code is responsible for eliminating nils from keys.
82
+ return cls.none if keys.empty?
83
+
84
+ criteria = cls.any_in(key => keys)
73
85
  criteria.inclusions = criteria.inclusions - [@association]
74
86
  criteria.each do |doc|
75
87
  yield doc
@@ -93,6 +105,9 @@ module Mongoid
93
105
 
94
106
  # Return a hash with the current documents grouped by key.
95
107
  #
108
+ # Documents that do not have a value for the association being loaded
109
+ # are not returned.
110
+ #
96
111
  # @example Return a hash with the current documents grouped by key.
97
112
  # loader.grouped_docs
98
113
  #
@@ -102,10 +117,15 @@ module Mongoid
102
117
  def grouped_docs
103
118
  @grouped_docs[@association.name] ||= @docs.group_by do |doc|
104
119
  doc.send(group_by_key) if doc.respond_to?(group_by_key)
120
+ end.reject do |k, v|
121
+ k.nil?
105
122
  end
106
123
  end
107
124
 
108
- # Group the documents and return the keys
125
+ # Group the documents and return the keys.
126
+ #
127
+ # This method omits nil keys (i.e. keys from documents that do not
128
+ # have a value for the association being loaded).
109
129
  #
110
130
  # @example
111
131
  # loader.keys_from_docs
@@ -54,9 +54,14 @@ module Mongoid
54
54
  #
55
55
  # @since 2.0.0.rc.1
56
56
  def substitute(replacement)
57
+ # If the same object currently associated is being assigned,
58
+ # rebind the association and save the target but do not destroy
59
+ # the target.
60
+
57
61
  unbind_one
58
62
  if persistable?
59
- if _association.destructive?
63
+ # TODO can this entire method be skipped if self == replacement?
64
+ if _association.destructive? && self != replacement
60
65
  send(_association.dependent)
61
66
  else
62
67
  save if persisted?
@@ -38,7 +38,9 @@ module Mongoid
38
38
  # @since 2.2.0
39
39
  def add_atomic_pull(document)
40
40
  document.flagged_for_destroy = true
41
- (delayed_atomic_pulls[document.association_name.to_s] ||= []).push(document)
41
+ key = document.association_name.to_s
42
+ delayed_atomic_pulls[key] ||= []
43
+ delayed_atomic_pulls[key] << document
42
44
  end
43
45
 
44
46
  # Add an atomic unset for the document.
@@ -53,7 +55,9 @@ module Mongoid
53
55
  # @since 3.0.0
54
56
  def add_atomic_unset(document)
55
57
  document.flagged_for_destroy = true
56
- (delayed_atomic_unsets[document.association_name.to_s] ||= []).push(document)
58
+ key = document.association_name.to_s
59
+ delayed_atomic_unsets[key] ||= []
60
+ delayed_atomic_unsets[key] << document
57
61
  end
58
62
 
59
63
  # Returns path of the attribute for modification
@@ -191,7 +195,13 @@ module Mongoid
191
195
  #
192
196
  # @since 2.1.0
193
197
  def atomic_paths
194
- @atomic_paths ||= _association ? _association.path(self) : Atomic::Paths::Root.new(self)
198
+ @atomic_paths ||= begin
199
+ if _association
200
+ _association.path(self)
201
+ else
202
+ Atomic::Paths::Root.new(self)
203
+ end
204
+ end
195
205
  end
196
206
 
197
207
  # Get all the attributes that need to be pulled.
@@ -12,9 +12,9 @@ module Mongoid
12
12
  # raised.
13
13
  #
14
14
  # @example Create the client.
15
- # Factory.create(:secondary)
15
+ # Factory.create(:analytics)
16
16
  #
17
- # @param [ String, Symbol ] name The named client configuration.
17
+ # @param [ String | Symbol ] name The named client configuration.
18
18
  #
19
19
  # @raise [ Errors::NoClientConfig ] If no config could be found.
20
20
  #
@@ -9,16 +9,16 @@ module Mongoid
9
9
  # Change the persistence context for this object during the block.
10
10
  #
11
11
  # @example Save the current document to a different collection.
12
- # model.with(collection: "secondary") do |m|
12
+ # model.with(collection: "bands") do |m|
13
13
  # m.save
14
14
  # end
15
15
  #
16
16
  # @param [ Hash, Mongoid::PersistenceContext ] options_or_context
17
17
  # The storage options or a persistence context.
18
18
  #
19
- # @option options [ String, Symbol ] :collection The collection name.
20
- # @option options [ String, Symbol ] :database The database name.
21
- # @option options [ String, Symbol ] :client The client name.
19
+ # @option options [ String | Symbol ] :collection The collection name.
20
+ # @option options [ String | Symbol ] :database The database name.
21
+ # @option options [ String | Symbol ] :client The client name.
22
22
  #
23
23
  # @since 6.0.0
24
24
  def with(options_or_context, &block)
@@ -83,15 +83,15 @@ module Mongoid
83
83
  # Change the persistence context for this class during the block.
84
84
  #
85
85
  # @example Save the current document to a different collection.
86
- # Model.with(collection: "secondary") do |m|
86
+ # Model.with(collection: "bands") do |m|
87
87
  # m.create
88
88
  # end
89
89
  #
90
90
  # @param [ Hash ] options The storage options.
91
91
  #
92
- # @option options [ String, Symbol ] :collection The collection name.
93
- # @option options [ String, Symbol ] :database The database name.
94
- # @option options [ String, Symbol ] :client The client name.
92
+ # @option options [ String | Symbol ] :collection The collection name.
93
+ # @option options [ String | Symbol ] :database The database name.
94
+ # @option options [ String | Symbol ] :client The client name.
95
95
  #
96
96
  # @since 6.0.0
97
97
  def with(options, &block)
@@ -41,12 +41,20 @@ module Mongoid
41
41
  #
42
42
  # @since 6.4.0
43
43
  def with_session(options = {})
44
- raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting) if Threaded.get_session
44
+ if Threaded.get_session
45
+ raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting)
46
+ end
45
47
  session = persistence_context.client.start_session(options)
46
48
  Threaded.set_session(session)
47
49
  yield(session)
48
50
  rescue Mongo::Error::InvalidSession => ex
49
- if ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
51
+ if
52
+ # Driver 2.13.0+
53
+ defined?(Mongo::Error::SessionsNotSupported) &&
54
+ Mongo::Error::SessionsNotSupported === ex ||
55
+ # Legacy drivers
56
+ ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
57
+ then
50
58
  raise Mongoid::Errors::InvalidSessionUse.new(:sessions_not_supported)
51
59
  end
52
60
  raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_use)
@@ -92,12 +100,20 @@ module Mongoid
92
100
  #
93
101
  # @since 6.4.0
94
102
  def with_session(options = {})
95
- raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting) if Threaded.get_session
103
+ if Threaded.get_session
104
+ raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_nesting)
105
+ end
96
106
  session = persistence_context.client.start_session(options)
97
107
  Threaded.set_session(session)
98
108
  yield(session)
99
109
  rescue Mongo::Error::InvalidSession => ex
100
- if ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
110
+ if
111
+ # Driver 2.13.0+
112
+ defined?(Mongo::Error::SessionsNotSupported) &&
113
+ Mongo::Error::SessionsNotSupported === ex ||
114
+ # Legacy drivers
115
+ ex.message == Mongo::Session::SESSIONS_NOT_SUPPORTED
116
+ then
101
117
  raise Mongoid::Errors::InvalidSessionUse.new(:sessions_not_supported)
102
118
  end
103
119
  raise Mongoid::Errors::InvalidSessionUse.new(:invalid_session_use)