mongoid 7.2.6 → 7.3.3

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 (154) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Rakefile +16 -0
  4. data/lib/config/locales/en.yml +2 -2
  5. data/lib/mongoid/association/accessors.rb +13 -1
  6. data/lib/mongoid/association/constrainable.rb +1 -1
  7. data/lib/mongoid/association/depending.rb +4 -4
  8. data/lib/mongoid/association/embedded/batchable.rb +1 -1
  9. data/lib/mongoid/association/embedded/embedded_in.rb +1 -1
  10. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +10 -3
  11. data/lib/mongoid/association/nested/many.rb +1 -1
  12. data/lib/mongoid/association/nested/one.rb +4 -2
  13. data/lib/mongoid/association/proxy.rb +6 -1
  14. data/lib/mongoid/association/referenced/auto_save.rb +2 -2
  15. data/lib/mongoid/association/referenced/has_many/enumerable.rb +490 -496
  16. data/lib/mongoid/association/referenced/has_many/proxy.rb +2 -2
  17. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +2 -2
  18. data/lib/mongoid/atomic.rb +26 -2
  19. data/lib/mongoid/attributes/projector.rb +120 -0
  20. data/lib/mongoid/attributes.rb +24 -13
  21. data/lib/mongoid/cacheable.rb +2 -2
  22. data/lib/mongoid/clients/factory.rb +22 -8
  23. data/lib/mongoid/clients.rb +1 -1
  24. data/lib/mongoid/config.rb +19 -2
  25. data/lib/mongoid/contextual/aggregable/mongo.rb +10 -8
  26. data/lib/mongoid/copyable.rb +1 -1
  27. data/lib/mongoid/criteria/findable.rb +1 -1
  28. data/lib/mongoid/criteria/queryable/expandable.rb +0 -24
  29. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  30. data/lib/mongoid/criteria/queryable/extensions.rb +0 -4
  31. data/lib/mongoid/criteria/queryable/mergeable.rb +46 -20
  32. data/lib/mongoid/criteria/queryable/selectable.rb +8 -8
  33. data/lib/mongoid/criteria.rb +4 -5
  34. data/lib/mongoid/document.rb +1 -15
  35. data/lib/mongoid/errors/delete_restriction.rb +8 -9
  36. data/lib/mongoid/evolvable.rb +1 -1
  37. data/lib/mongoid/extensions/boolean.rb +1 -2
  38. data/lib/mongoid/extensions/false_class.rb +1 -1
  39. data/lib/mongoid/extensions/hash.rb +2 -2
  40. data/lib/mongoid/extensions/true_class.rb +1 -1
  41. data/lib/mongoid/fields.rb +43 -5
  42. data/lib/mongoid/inspectable.rb +1 -1
  43. data/lib/mongoid/matcher/bits.rb +41 -0
  44. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  45. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  46. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  47. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  48. data/lib/mongoid/matcher/expression.rb +4 -0
  49. data/lib/mongoid/matcher/field_operator.rb +6 -0
  50. data/lib/mongoid/matcher/mod.rb +17 -0
  51. data/lib/mongoid/matcher/type.rb +99 -0
  52. data/lib/mongoid/matcher.rb +7 -0
  53. data/lib/mongoid/persistable/deletable.rb +1 -2
  54. data/lib/mongoid/persistable/destroyable.rb +8 -2
  55. data/lib/mongoid/persistable/updatable.rb +27 -2
  56. data/lib/mongoid/query_cache.rb +35 -29
  57. data/lib/mongoid/selectable.rb +5 -7
  58. data/lib/mongoid/shardable.rb +21 -5
  59. data/lib/mongoid/touchable.rb +33 -4
  60. data/lib/mongoid/version.rb +1 -1
  61. data/spec/integration/associations/embeds_many_spec.rb +44 -0
  62. data/spec/integration/associations/has_one_spec.rb +48 -0
  63. data/spec/integration/criteria/date_field_spec.rb +1 -1
  64. data/spec/integration/document_spec.rb +9 -0
  65. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  66. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  67. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  68. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  69. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  70. data/spec/integration/matcher_operator_data/in.yml +16 -0
  71. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  72. data/spec/integration/matcher_operator_data/type.yml +70 -0
  73. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  74. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  75. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  76. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  77. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  78. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  79. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  80. data/spec/integration/matcher_operator_data/type_decimal.yml +40 -0
  81. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  82. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  83. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  84. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  85. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  86. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  87. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  88. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  89. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  90. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  91. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  92. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  93. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  94. data/spec/lite_spec_helper.rb +2 -0
  95. data/spec/mongoid/association/depending_spec.rb +391 -352
  96. data/spec/mongoid/association/nested/one_spec.rb +18 -14
  97. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +25 -8
  98. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +1 -1
  99. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +1 -1
  100. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +245 -93
  101. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +6 -6
  102. data/spec/mongoid/association/referenced/has_one_models.rb +8 -0
  103. data/spec/mongoid/atomic/paths_spec.rb +64 -12
  104. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  105. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  106. data/spec/mongoid/attributes/projector_spec.rb +41 -0
  107. data/spec/mongoid/attributes_spec.rb +98 -6
  108. data/spec/mongoid/clients/factory_spec.rb +48 -0
  109. data/spec/mongoid/config_spec.rb +106 -1
  110. data/spec/mongoid/contextual/mongo_spec.rb +2 -2
  111. data/spec/mongoid/criteria/modifiable_spec.rb +1 -1
  112. data/spec/mongoid/criteria/queryable/expandable_spec.rb +0 -73
  113. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +1 -1
  114. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +105 -7
  115. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +229 -24
  116. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +39 -0
  117. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -565
  118. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +590 -0
  119. data/spec/mongoid/criteria_projection_spec.rb +411 -0
  120. data/spec/mongoid/criteria_spec.rb +0 -275
  121. data/spec/mongoid/document_spec.rb +13 -13
  122. data/spec/mongoid/errors/delete_restriction_spec.rb +1 -1
  123. data/spec/mongoid/extensions/false_class_spec.rb +1 -1
  124. data/spec/mongoid/extensions/string_spec.rb +5 -5
  125. data/spec/mongoid/extensions/true_class_spec.rb +1 -1
  126. data/spec/mongoid/fields/localized_spec.rb +4 -4
  127. data/spec/mongoid/fields_spec.rb +4 -4
  128. data/spec/mongoid/inspectable_spec.rb +12 -4
  129. data/spec/mongoid/persistable/deletable_spec.rb +175 -1
  130. data/spec/mongoid/persistable/destroyable_spec.rb +191 -3
  131. data/spec/mongoid/persistable/savable_spec.rb +3 -5
  132. data/spec/mongoid/persistable/upsertable_spec.rb +1 -1
  133. data/spec/mongoid/query_cache_middleware_spec.rb +8 -0
  134. data/spec/mongoid/reloadable_spec.rb +18 -1
  135. data/spec/mongoid/shardable_spec.rb +44 -0
  136. data/spec/mongoid/touchable_spec.rb +122 -16
  137. data/spec/mongoid/touchable_spec_models.rb +54 -0
  138. data/spec/mongoid/validatable_spec.rb +1 -1
  139. data/spec/spec_helper.rb +6 -2
  140. data/spec/support/client_registry.rb +9 -0
  141. data/spec/support/models/bolt.rb +8 -0
  142. data/spec/support/models/hole.rb +13 -0
  143. data/spec/support/models/mop.rb +0 -1
  144. data/spec/support/models/nut.rb +8 -0
  145. data/spec/support/models/person.rb +6 -0
  146. data/spec/support/models/sealer.rb +8 -0
  147. data/spec/support/models/shirt.rb +12 -0
  148. data/spec/support/models/spacer.rb +8 -0
  149. data/spec/support/models/threadlocker.rb +8 -0
  150. data/spec/support/models/washer.rb +8 -0
  151. data.tar.gz.sig +0 -0
  152. metadata +97 -3
  153. metadata.gz.sig +0 -0
  154. data/spec/support/cluster_config.rb +0 -158
@@ -220,7 +220,7 @@ module Mongoid
220
220
  #
221
221
  # @since 2.0.0.beta.1
222
222
  def initialize(base, target, association)
223
- enum = HasMany::Targets::Enumerable.new(target, base, association)
223
+ enum = HasMany::Enumerable.new(target, base, association)
224
224
  init(base, enum, association) do
225
225
  raise_mixed if klass.embedded? && !klass.cyclic?
226
226
  end
@@ -367,7 +367,7 @@ module Mongoid
367
367
  document.persisted? &&
368
368
  document._association &&
369
369
  document.respond_to?(document._association.foreign_key) &&
370
- document.__send__(document._association.foreign_key) == _base.id
370
+ document.__send__(document._association.foreign_key) == _base._id
371
371
  end
372
372
 
373
373
  # Instantiate the binding associated with this association.
@@ -69,7 +69,7 @@ module Mongoid
69
69
  #
70
70
  # @since 2.0.0
71
71
  def acceptable_id?
72
- id = convert_id(existing.class, attributes[:id])
72
+ id = convert_id(existing.class, attributes[:_id])
73
73
  existing._id == id || id.nil? || (existing._id != id && update_only?)
74
74
  end
75
75
 
@@ -82,7 +82,7 @@ module Mongoid
82
82
  #
83
83
  # @since 2.0.0
84
84
  def delete?
85
- destroyable? && !attributes[:id].nil?
85
+ destroyable? && !attributes[:_id].nil?
86
86
  end
87
87
 
88
88
  # Can the existing association potentially be destroyed?
@@ -385,11 +385,35 @@ module Mongoid
385
385
  updates = atomic_updates
386
386
  return {} unless atomic_updates.key?("$set")
387
387
  touches = {}
388
+ wanted_keys = %w(updated_at u_at)
389
+ # TODO this permits field to be passed as an empty string in which case
390
+ # it is ignored, get rid of this behavior.
391
+ if field.present?
392
+ wanted_keys << field.to_s
393
+ end
388
394
  updates["$set"].each_pair do |key, value|
389
- key_regex = /updated_at|u_at#{"|" + field if field.present?}/
390
- touches.merge!({ key => value }) if key =~ key_regex
395
+ if wanted_keys.include?(key.split('.').last)
396
+ touches.update(key => value)
397
+ end
391
398
  end
392
399
  { "$set" => touches }
393
400
  end
401
+
402
+ # Returns the $set atomic updates affecting the specified field.
403
+ #
404
+ # @param [ String ] field The field name.
405
+ #
406
+ # @api private
407
+ def set_field_atomic_updates(field)
408
+ updates = atomic_updates
409
+ return {} unless atomic_updates.key?("$set")
410
+ sets = {}
411
+ updates["$set"].each_pair do |key, value|
412
+ if key.split('.').last == field
413
+ sets.update(key => value)
414
+ end
415
+ end
416
+ { "$set" => sets }
417
+ end
394
418
  end
395
419
  end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ module Mongoid
5
+ module Attributes
6
+
7
+ # This module defines projection helpers.
8
+ #
9
+ # Projection rules are rather non-trivial. See
10
+ # https://docs.mongodb.com/manual/reference/method/db.collection.find/#find-projection
11
+ # for server documentation.
12
+ # 4.4 server (and presumably all older ones) requires that a projection
13
+ # for content fields is either exclusionary or inclusionary, i.e. one
14
+ # cannot mix exclusions and inclusions in the same query.
15
+ # However, _id can be excluded in a projection that includes content
16
+ # fields.
17
+ # Integer projection values other than 0 and 1 aren't officially
18
+ # documented as of this writing; see DOCSP-15266.
19
+ # 4.4 server also allows nested hash projection specification
20
+ # in addition to dot notation, which I assume Mongoid doesn't handle yet.
21
+ #
22
+ # @api private
23
+ class Projector
24
+ def initialize(projection)
25
+ if projection
26
+ @content_projection = projection.dup
27
+ @content_projection.delete('_id')
28
+ @id_projection_value = projection['_id']
29
+ else
30
+ @content_projection = nil
31
+ @id_projection_value = nil
32
+ end
33
+ end
34
+
35
+ attr_reader :id_projection_value
36
+ attr_reader :content_projection
37
+
38
+ # Determine if the specified attribute, or a dot notation path, is allowed
39
+ # by the configured projection, if any.
40
+ #
41
+ # If there is no configured projection, returns true.
42
+ #
43
+ # @param [ String ] name The name of the attribute or a dot notation path.
44
+ #
45
+ # @return [ true, false ] Whether the attribute is allowed by projection.
46
+ #
47
+ # @api private
48
+ def attribute_or_path_allowed?(name)
49
+ # Special handling for _id.
50
+ if name == '_id'
51
+ result = unless id_projection_value.nil?
52
+ value_inclusionary?(id_projection_value)
53
+ else
54
+ true
55
+ end
56
+ return result
57
+ end
58
+
59
+ if content_projection.nil?
60
+ # No projection (as opposed to an empty projection).
61
+ # All attributes are allowed.
62
+ return true
63
+ end
64
+
65
+ # Find an item which matches or is a parent of the requested name/path.
66
+ # This handles the case when, for example, the projection was
67
+ # {foo: true} and we want to know if foo.bar is allowed.
68
+ item, value = content_projection.detect do |path, value|
69
+ (name + '.').start_with?(path + '.')
70
+ end
71
+ if item
72
+ return value_inclusionary?(value)
73
+ end
74
+
75
+ if content_inclusionary?
76
+ # Find an item which would be a strict child of the requested name/path.
77
+ # This handles the case when, for example, the projection was
78
+ # {"foo.bar" => true} and we want to know if foo is allowed.
79
+ # (It is as a container of bars.)
80
+ item, value = content_projection.detect do |path, value|
81
+ (path + '.').start_with?(name + '.')
82
+ end
83
+ if item
84
+ return true
85
+ end
86
+ end
87
+
88
+ !content_inclusionary?
89
+ end
90
+
91
+ private
92
+
93
+ # Determines whether the projection for content fields is inclusionary.
94
+ #
95
+ # An empty projection is inclusionary.
96
+ def content_inclusionary?
97
+ if content_projection.empty?
98
+ return value_inclusionary?(id_projection_value)
99
+ end
100
+
101
+ value_inclusionary?(content_projection.values.first)
102
+ end
103
+
104
+ def value_inclusionary?(value)
105
+ case value
106
+ when Integer
107
+ value >= 1
108
+ when true
109
+ true
110
+ when false
111
+ false
112
+ else
113
+ # The various expressions that are permitted as projection arguments
114
+ # imply an inclusionary projection.
115
+ true
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -5,6 +5,7 @@ require "active_model/attribute_methods"
5
5
  require "mongoid/attributes/dynamic"
6
6
  require "mongoid/attributes/nested"
7
7
  require "mongoid/attributes/processing"
8
+ require "mongoid/attributes/projector"
8
9
  require "mongoid/attributes/readonly"
9
10
 
10
11
  module Mongoid
@@ -238,11 +239,7 @@ module Mongoid
238
239
  #
239
240
  # @since 4.0.0
240
241
  def attribute_missing?(name)
241
- selection = __selected_fields
242
- return false unless selection
243
- field = fields[name]
244
- (selection.values.first == 0 && selection_excluded?(name, selection, field)) ||
245
- (selection.values.first == 1 && !selection_included?(name, selection, field))
242
+ !Projector.new(__selected_fields).attribute_or_path_allowed?(name)
246
243
  end
247
244
 
248
245
  # Return type-casted attributes.
@@ -259,14 +256,6 @@ module Mongoid
259
256
 
260
257
  private
261
258
 
262
- def selection_excluded?(name, selection, field)
263
- selection[name] == 0
264
- end
265
-
266
- def selection_included?(name, selection, field)
267
- selection.key?(name) || selection.keys.collect { |k| k.partition('.').first }.include?(name)
268
- end
269
-
270
259
  # Does the string contain dot syntax for accessing hashes?
271
260
  #
272
261
  # @api private
@@ -300,9 +289,11 @@ module Mongoid
300
289
 
301
290
  def read_raw_attribute(name)
302
291
  normalized = database_field_name(name.to_s)
292
+
303
293
  if attribute_missing?(normalized)
304
294
  raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'"
305
295
  end
296
+
306
297
  if hash_dot_syntax?(normalized)
307
298
  attributes.__nested__(normalized)
308
299
  else
@@ -341,6 +332,26 @@ module Mongoid
341
332
  alias_method "#{name}_will_change!", "#{original}_will_change!"
342
333
  alias_method "#{name}_before_type_cast", "#{original}_before_type_cast"
343
334
  end
335
+
336
+ # Removes a field alias.
337
+ #
338
+ # @param [ Symbol ] name The aliased field name to remove.
339
+ def unalias_attribute(name)
340
+ unless aliased_fields.delete(name.to_s)
341
+ raise AttributeError, "Field #{name} is not an aliased field"
342
+ end
343
+
344
+ remove_method name
345
+ remove_method "#{name}="
346
+ remove_method "#{name}?"
347
+ remove_method "#{name}_change"
348
+ remove_method "#{name}_changed?"
349
+ remove_method "reset_#{name}!"
350
+ remove_method "reset_#{name}_to_default!"
351
+ remove_method "#{name}_was"
352
+ remove_method "#{name}_will_change!"
353
+ remove_method "#{name}_before_type_cast"
354
+ end
344
355
  end
345
356
 
346
357
  private
@@ -31,8 +31,8 @@ module Mongoid
31
31
  # @since 2.4.0
32
32
  def cache_key
33
33
  return "#{model_key}/new" if new_record?
34
- return "#{model_key}/#{id}-#{updated_at.utc.to_s(cache_timestamp_format)}" if do_or_do_not(:updated_at)
35
- "#{model_key}/#{id}"
34
+ return "#{model_key}/#{_id}-#{updated_at.utc.to_s(cache_timestamp_format)}" if do_or_do_not(:updated_at)
35
+ "#{model_key}/#{_id}"
36
36
  end
37
37
  end
38
38
  end
@@ -5,6 +5,7 @@ module Mongoid
5
5
  module Clients
6
6
  module Factory
7
7
  extend self
8
+ extend Loggable
8
9
 
9
10
  # Create a new client given the named configuration. If no name is
10
11
  # provided, return a new client with the default configuration. If a
@@ -59,12 +60,20 @@ module Mongoid
59
60
  # @since 3.0.0
60
61
  def create_client(configuration)
61
62
  raise Errors::NoClientsConfig.new unless configuration
62
- if configuration[:uri]
63
- Mongo::Client.new(configuration[:uri], options(configuration))
63
+ config = configuration.dup
64
+ uri = config.delete(:uri)
65
+ database = config.delete(:database)
66
+ hosts = config.delete(:hosts)
67
+ opts = config.delete(:options) || {}
68
+ unless config.empty?
69
+ default_logger.warn("Unknown config options detected: #{config}.")
70
+ end
71
+ if uri
72
+ Mongo::Client.new(uri, options(opts))
64
73
  else
65
74
  Mongo::Client.new(
66
- configuration[:hosts],
67
- options(configuration).merge(database: configuration[:database])
75
+ hosts,
76
+ options(opts).merge(database: database)
68
77
  )
69
78
  end
70
79
  end
@@ -78,9 +87,14 @@ module Mongoid
78
87
  Mongo::VERSION.split('.')[0...2].map(&:to_i)
79
88
  end
80
89
 
81
- def options(configuration)
82
- config = configuration.dup
83
- options = config.delete(:options) || {}
90
+ # Prepare options for Mongo::Client based on Mongoid client configuration.
91
+ #
92
+ # @param [ Hash ] opts Parameters from options section of Mongoid client configuration.
93
+ # @return [ Hash ] Options that should be passed to Mongo::Client constructor.
94
+ #
95
+ # @api private
96
+ def options(opts)
97
+ options = opts.dup
84
98
  options[:platform] = PLATFORM_DETAILS
85
99
  options[:app_name] = Mongoid::Config.app_name if Mongoid::Config.app_name
86
100
  if (driver_version <=> [2, 13]) >= 0
@@ -91,7 +105,7 @@ module Mongoid
91
105
  end
92
106
  options[:wrapping_libraries] = wrap_lib
93
107
  end
94
- options.reject{ |k, v| k == :hosts }.to_hash.symbolize_keys!
108
+ options.reject{ |k, _v| k == :hosts }.to_hash.symbolize_keys!
95
109
  end
96
110
  end
97
111
  end
@@ -59,7 +59,7 @@ module Mongoid
59
59
  # @example Get a client with the name.
60
60
  # Mongoid::Clients.with_name(:replica)
61
61
  #
62
- # @param [ Symbol ] name The name of the client.
62
+ # @param [ String | Symbol ] name The name of the client.
63
63
  #
64
64
  # @return [ Mongo::Client ] The named client.
65
65
  #
@@ -220,7 +220,7 @@ module Mongoid
220
220
  #
221
221
  # @since 2.0.2
222
222
  def purge!
223
- Clients.default.database.collections.each(&:drop) and true
223
+ global_client.database.collections.each(&:drop) and true
224
224
  end
225
225
 
226
226
  # Truncate all data in all collections, but not the indexes.
@@ -234,7 +234,7 @@ module Mongoid
234
234
  #
235
235
  # @since 2.0.2
236
236
  def truncate!
237
- Clients.default.database.collections.each do |collection|
237
+ global_client.database.collections.each do |collection|
238
238
  collection.find.delete_many
239
239
  end and true
240
240
  end
@@ -305,5 +305,22 @@ module Mongoid
305
305
  Validators::Client.validate(c)
306
306
  @clients = c
307
307
  end
308
+
309
+ # Get database client that respects global overrides
310
+ # Config.override_database and Config.override_client.
311
+ #
312
+ # @return [Mongo::Client] Client according to global overrides.
313
+ def global_client
314
+ client = if Threaded.client_override
315
+ Clients.with_name(Threaded.client_override)
316
+ else
317
+ Clients.default
318
+ end
319
+ if Threaded.database_override
320
+ client.use(Threaded.database_override)
321
+ else
322
+ client
323
+ end
324
+ end
308
325
  end
309
326
  end
@@ -11,17 +11,19 @@ module Mongoid
11
11
  #
12
12
  # @example Get all the aggregate values.
13
13
  # aggregable.aggregates(:likes)
14
+ # # => {
15
+ # # "count" => 2.0,
16
+ # # "max" => 1000.0,
17
+ # # "min" => 500.0,
18
+ # # "sum" => 1500.0,
19
+ # # "avg" => 750.0
20
+ # # }
14
21
  #
15
22
  # @param [ String, Symbol ] field The field name.
16
23
  #
17
- # @return [ Hash ] count is a number of documents with the provided field. If there're none, then count is 0 and max, min, sum, avg are nil.
18
- # {
19
- # "count" => 2.0,
20
- # "max" => 1000.0,
21
- # "min" => 500.0,
22
- # "sum" => 1500.0,
23
- # "avg" => 750.0
24
- # }
24
+ # @return [ Hash ] count is a number of documents with the provided
25
+ # field. If there're none, then count is 0 and max, min, sum, avg
26
+ # are nil.
25
27
  #
26
28
  # @since 3.0.0
27
29
  def aggregates(field)
@@ -21,7 +21,7 @@ module Mongoid
21
21
  # @note This next line is here to address #2704, even though having an
22
22
  # _id and id field in the document would cause problems with Mongoid
23
23
  # elsewhere.
24
- attrs = clone_document.except("_id", "id")
24
+ attrs = clone_document.except(*self.class.id_fields)
25
25
  dynamic_attrs = {}
26
26
  _attribute_names = self.attribute_names
27
27
  attrs.reject! do |attr_name, value|
@@ -132,7 +132,7 @@ module Mongoid
132
132
  # @since 3.0.0
133
133
  def mongoize_ids(ids)
134
134
  ids.map do |id|
135
- id = id[:id] if id.respond_to?(:keys) && id[:id]
135
+ id = id[:_id] if id.respond_to?(:keys) && id[:_id]
136
136
  klass.fields["_id"].mongoize(id)
137
137
  end
138
138
  end
@@ -15,30 +15,6 @@ module Mongoid
15
15
 
16
16
  private
17
17
 
18
- # Expands the specified condition to MongoDB syntax.
19
- #
20
- # The condition must be a hash in one of the following forms:
21
- # - {field_name: value}
22
- # - {'field_name' => value}
23
- # - {key_instance: value}
24
- # - {'$operator' => operator_value_expression}
25
- #
26
- # This method expands the key instance form to the the operator form,
27
- # and also converts hash key to string.
28
- #
29
- # The hash may contain multiple items, each representing a separate
30
- # condition.
31
- #
32
- # @param [ Hash ] condition The condition to expand.
33
- #
34
- # @return [ Hash ] The expanded condition.
35
- def expand_condition(condition)
36
- mapped = condition.map do |field, value|
37
- expand_one_condition(field, value)
38
- end
39
- Hash[mapped]
40
- end
41
-
42
18
  # Expands the specified condition to MongoDB syntax.
43
19
  #
44
20
  # This method is meant to be called when processing the items of