mongoid 7.2.0 → 7.3.0
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/Rakefile +16 -0
- data/lib/config/locales/en.yml +2 -2
- data/lib/mongoid/association/accessors.rb +1 -1
- data/lib/mongoid/association/constrainable.rb +1 -1
- data/lib/mongoid/association/depending.rb +4 -4
- data/lib/mongoid/association/embedded/batchable.rb +1 -1
- data/lib/mongoid/association/embedded/embedded_in.rb +1 -1
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +10 -3
- data/lib/mongoid/association/nested/many.rb +1 -1
- data/lib/mongoid/association/nested/one.rb +4 -2
- data/lib/mongoid/association/proxy.rb +6 -1
- data/lib/mongoid/association/referenced/auto_save.rb +2 -2
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +493 -495
- data/lib/mongoid/association/referenced/has_many/proxy.rb +2 -2
- data/lib/mongoid/association/referenced/has_one/nested_builder.rb +2 -2
- data/lib/mongoid/attributes/projector.rb +120 -0
- data/lib/mongoid/attributes.rb +32 -14
- data/lib/mongoid/cacheable.rb +2 -2
- data/lib/mongoid/clients/factory.rb +22 -8
- data/lib/mongoid/clients.rb +1 -1
- data/lib/mongoid/config.rb +19 -2
- data/lib/mongoid/contextual/aggregable/mongo.rb +10 -8
- data/lib/mongoid/copyable.rb +1 -1
- data/lib/mongoid/criteria/findable.rb +1 -1
- data/lib/mongoid/criteria/queryable/expandable.rb +0 -24
- data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions.rb +0 -4
- data/lib/mongoid/criteria/queryable/mergeable.rb +46 -20
- data/lib/mongoid/criteria/queryable/selectable.rb +8 -8
- data/lib/mongoid/criteria/queryable/selector.rb +0 -4
- data/lib/mongoid/criteria.rb +4 -5
- data/lib/mongoid/document.rb +4 -17
- data/lib/mongoid/errors/delete_restriction.rb +8 -9
- data/lib/mongoid/evolvable.rb +1 -1
- data/lib/mongoid/extensions/boolean.rb +1 -2
- data/lib/mongoid/extensions/false_class.rb +1 -1
- data/lib/mongoid/extensions/hash.rb +2 -2
- data/lib/mongoid/extensions/true_class.rb +1 -1
- data/lib/mongoid/fields.rb +43 -5
- data/lib/mongoid/inspectable.rb +1 -1
- data/lib/mongoid/interceptable.rb +3 -1
- data/lib/mongoid/matcher/bits.rb +41 -0
- data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
- data/lib/mongoid/matcher/bits_all_set.rb +20 -0
- data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
- data/lib/mongoid/matcher/bits_any_set.rb +20 -0
- data/lib/mongoid/matcher/elem_match.rb +2 -1
- data/lib/mongoid/matcher/expression.rb +9 -14
- data/lib/mongoid/matcher/field_expression.rb +4 -5
- data/lib/mongoid/matcher/field_operator.rb +13 -11
- data/lib/mongoid/matcher/mod.rb +17 -0
- data/lib/mongoid/matcher/type.rb +99 -0
- data/lib/mongoid/matcher.rb +26 -43
- data/lib/mongoid/persistable/deletable.rb +1 -2
- data/lib/mongoid/persistable/destroyable.rb +8 -2
- data/lib/mongoid/persistable/updatable.rb +27 -2
- data/lib/mongoid/query_cache.rb +35 -29
- data/lib/mongoid/reloadable.rb +5 -0
- data/lib/mongoid/selectable.rb +5 -7
- data/lib/mongoid/shardable.rb +21 -5
- data/lib/mongoid/touchable.rb +23 -4
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/config_generator.rb +8 -1
- data/spec/integration/app_spec.rb +171 -84
- data/spec/integration/associations/embeds_many_spec.rb +44 -0
- data/spec/integration/associations/has_one_spec.rb +48 -0
- data/spec/integration/callbacks_models.rb +49 -0
- data/spec/integration/callbacks_spec.rb +216 -0
- data/spec/integration/criteria/date_field_spec.rb +1 -1
- data/spec/integration/document_spec.rb +30 -0
- data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
- data/spec/integration/matcher_operator_data/comment.yml +22 -0
- data/spec/integration/matcher_operator_data/elem_match.yml +46 -0
- data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
- data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
- data/spec/integration/matcher_operator_data/implicit_traversal.yml +96 -0
- data/spec/integration/matcher_operator_data/in.yml +16 -0
- data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
- data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
- data/spec/integration/matcher_operator_data/mod.yml +55 -0
- data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
- data/spec/integration/matcher_operator_data/type.yml +70 -0
- data/spec/integration/matcher_operator_data/type_array.yml +16 -0
- data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
- data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
- data/spec/integration/matcher_operator_data/type_code.yml +26 -0
- data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
- data/spec/integration/matcher_operator_data/type_date.yml +39 -0
- data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
- data/spec/integration/matcher_operator_data/type_decimal.yml +40 -0
- data/spec/integration/matcher_operator_data/type_double.yml +15 -0
- data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
- data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
- data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
- data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
- data/spec/integration/matcher_operator_data/type_null.yml +23 -0
- data/spec/integration/matcher_operator_data/type_object.yml +23 -0
- data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
- data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
- data/spec/integration/matcher_operator_data/type_string.yml +15 -0
- data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
- data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
- data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
- data/spec/lite_spec_helper.rb +5 -4
- data/spec/mongoid/association/depending_spec.rb +391 -352
- data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +50 -0
- data/spec/mongoid/association/nested/one_spec.rb +18 -14
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +25 -8
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +1 -1
- data/spec/mongoid/association/referenced/has_many/binding_spec.rb +1 -1
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +1 -1
- data/spec/mongoid/association/referenced/has_one_models.rb +8 -0
- data/spec/mongoid/atomic/paths_spec.rb +105 -12
- data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
- data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
- data/spec/mongoid/attributes/projector_spec.rb +41 -0
- data/spec/mongoid/attributes_spec.rb +333 -0
- data/spec/mongoid/clients/factory_spec.rb +48 -0
- data/spec/mongoid/config_spec.rb +32 -0
- data/spec/mongoid/contextual/atomic_spec.rb +17 -4
- data/spec/mongoid/contextual/mongo_spec.rb +2 -2
- data/spec/mongoid/criteria/modifiable_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/expandable_spec.rb +0 -73
- data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/mergeable_spec.rb +105 -7
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +265 -24
- data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +39 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -565
- data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +590 -0
- data/spec/mongoid/criteria_projection_spec.rb +411 -0
- data/spec/mongoid/criteria_spec.rb +0 -275
- data/spec/mongoid/document_fields_spec.rb +26 -0
- data/spec/mongoid/document_spec.rb +13 -13
- data/spec/mongoid/errors/delete_restriction_spec.rb +1 -1
- data/spec/mongoid/extensions/false_class_spec.rb +1 -1
- data/spec/mongoid/extensions/string_spec.rb +5 -5
- data/spec/mongoid/extensions/true_class_spec.rb +1 -1
- data/spec/mongoid/fields/localized_spec.rb +4 -4
- data/spec/mongoid/fields_spec.rb +4 -4
- data/spec/mongoid/inspectable_spec.rb +12 -4
- data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
- data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +68 -88
- data/spec/mongoid/matcher/extract_attribute_spec.rb +3 -13
- data/spec/mongoid/persistable/deletable_spec.rb +175 -1
- data/spec/mongoid/persistable/destroyable_spec.rb +191 -3
- data/spec/mongoid/persistable/savable_spec.rb +3 -5
- data/spec/mongoid/persistable/settable_spec.rb +30 -0
- data/spec/mongoid/persistable/upsertable_spec.rb +1 -1
- data/spec/mongoid/query_cache_middleware_spec.rb +8 -0
- data/spec/mongoid/reloadable_spec.rb +18 -1
- data/spec/mongoid/shardable_spec.rb +44 -0
- data/spec/mongoid/touchable_spec.rb +104 -16
- data/spec/mongoid/touchable_spec_models.rb +52 -0
- data/spec/mongoid/validatable_spec.rb +1 -1
- data/spec/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/lib/mrss/cluster_config.rb +221 -0
- data/spec/shared/lib/mrss/constraints.rb +51 -0
- data/spec/shared/lib/mrss/docker_runner.rb +265 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +14 -1
- data/spec/shared/lib/mrss/utils.rb +15 -0
- data/spec/shared/share/Dockerfile.erb +231 -0
- data/spec/shared/shlib/distro.sh +73 -0
- data/spec/shared/shlib/server.sh +290 -0
- data/spec/shared/shlib/set_env.sh +128 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/support/client_registry.rb +9 -0
- data/spec/support/models/bolt.rb +8 -0
- data/spec/support/models/customer.rb +11 -0
- data/spec/support/models/customer_address.rb +12 -0
- data/spec/support/models/dictionary.rb +6 -0
- data/spec/support/models/hole.rb +13 -0
- data/spec/support/models/mop.rb +9 -0
- data/spec/support/models/nut.rb +8 -0
- data/spec/support/models/person.rb +6 -0
- data/spec/support/models/sealer.rb +8 -0
- data/spec/support/models/shirt.rb +12 -0
- data/spec/support/models/spacer.rb +8 -0
- data/spec/support/models/threadlocker.rb +8 -0
- data/spec/support/models/washer.rb +8 -0
- data/spec/support/spec_config.rb +8 -0
- data.tar.gz.sig +0 -0
- metadata +146 -14
- metadata.gz.sig +5 -2
- 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::
|
|
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.
|
|
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[:
|
|
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[:
|
|
85
|
+
destroyable? && !attributes[:_id].nil?
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Can the existing association potentially be destroyed?
|
|
@@ -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
|
data/lib/mongoid/attributes.rb
CHANGED
|
@@ -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
|
|
@@ -160,6 +161,11 @@ module Mongoid
|
|
|
160
161
|
# @since 1.0.0
|
|
161
162
|
def write_attribute(name, value)
|
|
162
163
|
field_name = database_field_name(name)
|
|
164
|
+
|
|
165
|
+
if attribute_missing?(field_name)
|
|
166
|
+
raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'"
|
|
167
|
+
end
|
|
168
|
+
|
|
163
169
|
if attribute_writable?(field_name)
|
|
164
170
|
_assigning do
|
|
165
171
|
validate_attribute_value(field_name, value)
|
|
@@ -177,6 +183,8 @@ module Mongoid
|
|
|
177
183
|
end
|
|
178
184
|
typed_value
|
|
179
185
|
end
|
|
186
|
+
else
|
|
187
|
+
# TODO: MONGOID-5072
|
|
180
188
|
end
|
|
181
189
|
end
|
|
182
190
|
alias :[]= :write_attribute
|
|
@@ -231,11 +239,7 @@ module Mongoid
|
|
|
231
239
|
#
|
|
232
240
|
# @since 4.0.0
|
|
233
241
|
def attribute_missing?(name)
|
|
234
|
-
|
|
235
|
-
return false unless selection
|
|
236
|
-
field = fields[name]
|
|
237
|
-
(selection.values.first == 0 && selection_excluded?(name, selection, field)) ||
|
|
238
|
-
(selection.values.first == 1 && !selection_included?(name, selection, field))
|
|
242
|
+
!Projector.new(__selected_fields).attribute_or_path_allowed?(name)
|
|
239
243
|
end
|
|
240
244
|
|
|
241
245
|
# Return type-casted attributes.
|
|
@@ -252,14 +256,6 @@ module Mongoid
|
|
|
252
256
|
|
|
253
257
|
private
|
|
254
258
|
|
|
255
|
-
def selection_excluded?(name, selection, field)
|
|
256
|
-
selection[name] == 0
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
def selection_included?(name, selection, field)
|
|
260
|
-
selection.key?(name) || selection.keys.collect { |k| k.partition('.').first }.include?(name)
|
|
261
|
-
end
|
|
262
|
-
|
|
263
259
|
# Does the string contain dot syntax for accessing hashes?
|
|
264
260
|
#
|
|
265
261
|
# @api private
|
|
@@ -293,9 +289,11 @@ module Mongoid
|
|
|
293
289
|
|
|
294
290
|
def read_raw_attribute(name)
|
|
295
291
|
normalized = database_field_name(name.to_s)
|
|
292
|
+
|
|
296
293
|
if attribute_missing?(normalized)
|
|
297
|
-
raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'
|
|
294
|
+
raise ActiveModel::MissingAttributeError, "Missing attribute: '#{name}'"
|
|
298
295
|
end
|
|
296
|
+
|
|
299
297
|
if hash_dot_syntax?(normalized)
|
|
300
298
|
attributes.__nested__(normalized)
|
|
301
299
|
else
|
|
@@ -334,6 +332,26 @@ module Mongoid
|
|
|
334
332
|
alias_method "#{name}_will_change!", "#{original}_will_change!"
|
|
335
333
|
alias_method "#{name}_before_type_cast", "#{original}_before_type_cast"
|
|
336
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
|
|
337
355
|
end
|
|
338
356
|
|
|
339
357
|
private
|
data/lib/mongoid/cacheable.rb
CHANGED
|
@@ -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}/#{
|
|
35
|
-
"#{model_key}/#{
|
|
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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
67
|
-
options(
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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,
|
|
108
|
+
options.reject{ |k, _v| k == :hosts }.to_hash.symbolize_keys!
|
|
95
109
|
end
|
|
96
110
|
end
|
|
97
111
|
end
|
data/lib/mongoid/clients.rb
CHANGED
|
@@ -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
|
#
|
data/lib/mongoid/config.rb
CHANGED
|
@@ -220,7 +220,7 @@ module Mongoid
|
|
|
220
220
|
#
|
|
221
221
|
# @since 2.0.2
|
|
222
222
|
def purge!
|
|
223
|
-
|
|
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
|
-
|
|
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
|
|
18
|
-
#
|
|
19
|
-
#
|
|
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)
|
data/lib/mongoid/copyable.rb
CHANGED
|
@@ -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(
|
|
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|
|
|
@@ -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
|
|
@@ -227,7 +227,16 @@ module Mongoid
|
|
|
227
227
|
end
|
|
228
228
|
|
|
229
229
|
# Takes a criteria hash and expands Key objects into hashes containing
|
|
230
|
-
# MQL corresponding to said key objects.
|
|
230
|
+
# MQL corresponding to said key objects. Also converts the input to
|
|
231
|
+
# BSON::Document to permit indifferent access.
|
|
232
|
+
#
|
|
233
|
+
# The argument must be a hash containing key-value pairs of the
|
|
234
|
+
# following forms:
|
|
235
|
+
# - {field_name: value}
|
|
236
|
+
# - {'field_name' => value}
|
|
237
|
+
# - {key_instance: value}
|
|
238
|
+
# - {:$operator => operator_value_expression}
|
|
239
|
+
# - {'$operator' => operator_value_expression}
|
|
231
240
|
#
|
|
232
241
|
# Ruby does not permit multiple symbol operators. For example,
|
|
233
242
|
# {:foo.gt => 1, :foo.gt => 2} is collapsed to {:foo.gt => 2} by the
|
|
@@ -237,19 +246,23 @@ module Mongoid
|
|
|
237
246
|
# Similarly, this method should never need to expand a literal value
|
|
238
247
|
# and an operator at the same time.
|
|
239
248
|
#
|
|
249
|
+
# This method effectively converts symbol keys to string keys in
|
|
250
|
+
# the input +expr+, such that the downstream code can assume that
|
|
251
|
+
# conditions always contain string keys.
|
|
252
|
+
#
|
|
240
253
|
# @param [ Hash ] expr Criteria including Key instances.
|
|
241
254
|
#
|
|
242
|
-
# @return [
|
|
255
|
+
# @return [ BSON::Document ] The expanded criteria.
|
|
243
256
|
private def _mongoid_expand_keys(expr)
|
|
244
257
|
unless expr.is_a?(Hash)
|
|
245
258
|
raise ArgumentError, 'Argument must be a Hash'
|
|
246
259
|
end
|
|
247
260
|
|
|
248
|
-
result =
|
|
261
|
+
result = BSON::Document.new
|
|
249
262
|
expr.each do |field, value|
|
|
250
|
-
field.__expr_part__(value.__expand_complex__).each do |k, v|
|
|
251
|
-
if result[k]
|
|
252
|
-
if
|
|
263
|
+
field.__expr_part__(value.__expand_complex__, negating?).each do |k, v|
|
|
264
|
+
if existing = result[k]
|
|
265
|
+
if existing.is_a?(Hash)
|
|
253
266
|
# Existing value is an operator.
|
|
254
267
|
# If new value is also an operator, ensure there are no
|
|
255
268
|
# conflicts and add
|
|
@@ -257,8 +270,8 @@ module Mongoid
|
|
|
257
270
|
# The new value is also an operator.
|
|
258
271
|
# If there are no conflicts, combine the hashes, otherwise
|
|
259
272
|
# add new conditions to top level with $and.
|
|
260
|
-
if (v.keys &
|
|
261
|
-
|
|
273
|
+
if (v.keys & existing.keys).empty?
|
|
274
|
+
existing.update(v)
|
|
262
275
|
else
|
|
263
276
|
raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
|
|
264
277
|
result['$and'] ||= []
|
|
@@ -266,26 +279,39 @@ module Mongoid
|
|
|
266
279
|
end
|
|
267
280
|
else
|
|
268
281
|
# The new value is a simple value.
|
|
269
|
-
#
|
|
270
|
-
#
|
|
271
|
-
#
|
|
272
|
-
#
|
|
273
|
-
|
|
282
|
+
# Transform the implicit equality to either $eq or $regexp
|
|
283
|
+
# depending on the type of the argument. See
|
|
284
|
+
# https://docs.mongodb.com/manual/reference/operator/query/eq/#std-label-eq-usage-examples
|
|
285
|
+
# for the description of relevant server behavior.
|
|
286
|
+
op = case v
|
|
287
|
+
when Regexp, BSON::Regexp::Raw
|
|
288
|
+
'$regex'
|
|
289
|
+
else
|
|
290
|
+
'$eq'
|
|
291
|
+
end
|
|
292
|
+
# If there isn't an $eq/$regex operator already in the
|
|
293
|
+
# query, transform the new value into an operator
|
|
294
|
+
# expression and add it to the existing hash. Otherwise
|
|
295
|
+
# add the new condition with $and to the top level.
|
|
296
|
+
if existing.key?(op)
|
|
274
297
|
raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
|
|
275
298
|
result['$and'] ||= []
|
|
276
299
|
result['$and'] << {k => v}
|
|
277
300
|
else
|
|
278
|
-
|
|
301
|
+
existing.update(op => v)
|
|
279
302
|
end
|
|
280
303
|
end
|
|
281
304
|
else
|
|
282
305
|
# Existing value is a simple value.
|
|
283
|
-
#
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
306
|
+
# See the notes above about transformations to $eq/$regex.
|
|
307
|
+
op = case existing
|
|
308
|
+
when Regexp, BSON::Regexp::Raw
|
|
309
|
+
'$regex'
|
|
310
|
+
else
|
|
311
|
+
'$eq'
|
|
312
|
+
end
|
|
313
|
+
if v.is_a?(Hash) && !v.key?(op)
|
|
314
|
+
result[k] = {op => existing}.update(v)
|
|
289
315
|
else
|
|
290
316
|
raise NotImplementedError, 'Ruby does not allow same symbol operator with different values'
|
|
291
317
|
result['$and'] ||= []
|
|
@@ -195,11 +195,11 @@ module Mongoid
|
|
|
195
195
|
end
|
|
196
196
|
|
|
197
197
|
typed_override(criterion, "$exists") do |value|
|
|
198
|
-
::Boolean.evolve(value)
|
|
198
|
+
Mongoid::Boolean.evolve(value)
|
|
199
199
|
end
|
|
200
200
|
end
|
|
201
201
|
key :exists, :override, "$exists" do |value|
|
|
202
|
-
::Boolean.evolve(value)
|
|
202
|
+
Mongoid::Boolean.evolve(value)
|
|
203
203
|
end
|
|
204
204
|
|
|
205
205
|
# Add a $geoIntersects or $geoWithin selection. Symbol operators must
|
|
@@ -882,19 +882,19 @@ module Mongoid
|
|
|
882
882
|
if criterion.nil?
|
|
883
883
|
raise ArgumentError, 'Criterion cannot be nil here'
|
|
884
884
|
end
|
|
885
|
+
unless Hash === criterion
|
|
886
|
+
raise Errors::InvalidQuery, "Expression must be a Hash: #{Errors::InvalidQuery.truncate_expr(criterion)}"
|
|
887
|
+
end
|
|
885
888
|
|
|
889
|
+
normalized = _mongoid_expand_keys(criterion)
|
|
886
890
|
clone.tap do |query|
|
|
887
|
-
|
|
888
|
-
raise Errors::InvalidQuery, "Expression must be a Hash: #{Errors::InvalidQuery.truncate_expr(criterion)}"
|
|
889
|
-
end
|
|
890
|
-
criterion.each do |field, value|
|
|
891
|
+
normalized.each do |field, value|
|
|
891
892
|
field_s = field.to_s
|
|
892
893
|
if field_s[0] == ?$
|
|
893
894
|
# Query expression-level operator, like $and or $where
|
|
894
895
|
query.add_operator_expression(field_s, value)
|
|
895
896
|
else
|
|
896
|
-
|
|
897
|
-
query.add_field_expression(exp_field, exp_value)
|
|
897
|
+
query.add_field_expression(field, value)
|
|
898
898
|
end
|
|
899
899
|
end
|
|
900
900
|
query.reset_strategies!
|
|
@@ -123,10 +123,6 @@ module Mongoid
|
|
|
123
123
|
# {'foo' => {'$lt' => 5}}. This step should be done after all
|
|
124
124
|
# value-based processing is complete.
|
|
125
125
|
if key.is_a?(Key)
|
|
126
|
-
if serializer && evolved_value != value
|
|
127
|
-
raise NotImplementedError, "This method is not prepared to handle key being a Key and serializer being not nil"
|
|
128
|
-
end
|
|
129
|
-
|
|
130
126
|
evolved_value = key.transform_value(evolved_value)
|
|
131
127
|
end
|
|
132
128
|
|
data/lib/mongoid/criteria.rb
CHANGED
|
@@ -336,16 +336,15 @@ module Mongoid
|
|
|
336
336
|
#
|
|
337
337
|
# @since 1.0.0
|
|
338
338
|
def only(*args)
|
|
339
|
-
return clone if args.flatten.empty?
|
|
340
339
|
args = args.flatten
|
|
340
|
+
return clone if args.empty?
|
|
341
341
|
if (args & Fields::IDS).empty?
|
|
342
342
|
args.unshift(:_id)
|
|
343
343
|
end
|
|
344
344
|
if klass.hereditary?
|
|
345
|
-
|
|
346
|
-
else
|
|
347
|
-
super(*args)
|
|
345
|
+
args.push(klass.discriminator_key.to_sym)
|
|
348
346
|
end
|
|
347
|
+
super(*args)
|
|
349
348
|
end
|
|
350
349
|
|
|
351
350
|
# Set the read preference for the criteria.
|
|
@@ -375,7 +374,7 @@ module Mongoid
|
|
|
375
374
|
#
|
|
376
375
|
# @since 4.0.3
|
|
377
376
|
def without(*args)
|
|
378
|
-
args -=
|
|
377
|
+
args -= id_fields
|
|
379
378
|
super(*args)
|
|
380
379
|
end
|
|
381
380
|
|