mongoid 9.1.0 → 9.1.1
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
- data/lib/config/locales/en.yml +49 -0
- data/lib/mongoid/association/accessors.rb +9 -1
- data/lib/mongoid/association/depending.rb +14 -10
- data/lib/mongoid/association/eager.rb +9 -0
- data/lib/mongoid/association/eager_load/discriminated_inclusion.rb +88 -0
- data/lib/mongoid/association/eager_load/embedded_distributor.rb +151 -0
- data/lib/mongoid/association/eager_load/inclusion.rb +173 -0
- data/lib/mongoid/association/eager_load/inclusion_tree.rb +96 -0
- data/lib/mongoid/association/eager_load/lookup_pipeline.rb +121 -0
- data/lib/mongoid/association/eager_load/polymorphic_preloader.rb +61 -0
- data/lib/mongoid/association/eager_load/polymorphic_targets.rb +151 -0
- data/lib/mongoid/association/eager_loadable.rb +57 -100
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -1
- data/lib/mongoid/association/embedded/embeds_one.rb +1 -0
- data/lib/mongoid/association/macros.rb +13 -1
- data/lib/mongoid/association/nested/many.rb +34 -5
- data/lib/mongoid/association/nested/nested_buildable.rb +14 -0
- data/lib/mongoid/association/nested/one.rb +6 -1
- data/lib/mongoid/association/options.rb +17 -0
- data/lib/mongoid/association/referenced/belongs_to/eager.rb +6 -1
- data/lib/mongoid/association/referenced/belongs_to.rb +1 -0
- data/lib/mongoid/association/referenced/counter_cache.rb +3 -3
- data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +5 -0
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +3 -1
- data/lib/mongoid/association/referenced/has_many/proxy.rb +100 -1
- data/lib/mongoid/association/referenced/has_many_through/eager.rb +99 -0
- data/lib/mongoid/association/referenced/has_many_through/proxy.rb +68 -0
- data/lib/mongoid/association/referenced/has_many_through.rb +201 -0
- data/lib/mongoid/association/referenced/has_one.rb +1 -0
- data/lib/mongoid/association/referenced/has_one_through/eager.rb +65 -0
- data/lib/mongoid/association/referenced/has_one_through/proxy.rb +30 -0
- data/lib/mongoid/association/referenced/has_one_through.rb +167 -0
- data/lib/mongoid/association/referenced.rb +2 -0
- data/lib/mongoid/association/relatable.rb +40 -0
- data/lib/mongoid/association.rb +7 -0
- data/lib/mongoid/clients/factory.rb +7 -13
- data/lib/mongoid/collection_configurable.rb +8 -0
- data/lib/mongoid/config/defaults.rb +0 -1
- data/lib/mongoid/config/encryption.rb +36 -19
- data/lib/mongoid/config.rb +56 -5
- data/lib/mongoid/contextual/aggregable/memory.rb +6 -2
- data/lib/mongoid/contextual/memory.rb +18 -7
- data/lib/mongoid/criteria/includable.rb +35 -11
- data/lib/mongoid/criteria/queryable/mergeable.rb +4 -0
- data/lib/mongoid/criteria/queryable/selectable.rb +123 -7
- data/lib/mongoid/deprecable.rb +45 -2
- data/lib/mongoid/encryptable.rb +46 -0
- data/lib/mongoid/errors/config_redactor.rb +43 -0
- data/lib/mongoid/errors/in_memory_regexp_timeout.rb +26 -0
- data/lib/mongoid/errors/mixed_client_configuration.rb +1 -1
- data/lib/mongoid/errors/no_client_database.rb +1 -1
- data/lib/mongoid/errors/no_client_hosts.rb +1 -1
- data/lib/mongoid/errors/no_encryption_schema.rb +28 -0
- data/lib/mongoid/errors/readonly_association.rb +29 -0
- data/lib/mongoid/errors.rb +4 -0
- data/lib/mongoid/extensions/vector.rb +64 -0
- data/lib/mongoid/extensions.rb +1 -0
- data/lib/mongoid/field_readable.rb +69 -0
- data/lib/mongoid/indexable.rb +38 -26
- data/lib/mongoid/matchable.rb +6 -1
- data/lib/mongoid/matcher/eq_impl_with_regexp.rb +2 -4
- data/lib/mongoid/matcher/regex.rb +11 -12
- data/lib/mongoid/matcher/regexp_budget.rb +372 -0
- data/lib/mongoid/matcher.rb +1 -0
- data/lib/mongoid/persistable/creatable.rb +1 -1
- data/lib/mongoid/persistable/updatable.rb +9 -11
- data/lib/mongoid/persistence_context.rb +35 -0
- data/lib/mongoid/search_indexable.rb +64 -23
- data/lib/mongoid/serializable.rb +12 -4
- data/lib/mongoid/tasks/database.rb +23 -9
- data/lib/mongoid/threaded.rb +36 -0
- data/lib/mongoid/timestamps/timeless.rb +84 -10
- data/lib/mongoid/traversable.rb +2 -2
- data/lib/mongoid/validatable/associated.rb +18 -2
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/app_spec.rb +7 -1
- data/spec/integration/associations/belongs_to_spec.rb +13 -0
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +17 -2
- data/spec/integration/dots_and_dollars_spec.rb +12 -2
- data/spec/integration/encryption_spec.rb +151 -0
- data/spec/integration/matcher_operator_data/regex.yml +21 -0
- data/spec/integration/matcher_regexp_timeout_spec.rb +215 -0
- data/spec/integration/query_operator_guard_spec.rb +89 -0
- data/spec/mongoid/association/eager_loadable_spec.rb +47 -0
- data/spec/mongoid/association/eager_spec.rb +2 -2
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +33 -0
- data/spec/mongoid/association/fallback_spec.rb +425 -0
- data/spec/mongoid/association/macros_spec.rb +26 -0
- data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +17 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +48 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +50 -0
- data/spec/mongoid/association/referenced/has_many/eager_spec.rb +33 -0
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +145 -0
- data/spec/mongoid/association/referenced/has_many_through/eager_spec.rb +58 -0
- data/spec/mongoid/association/referenced/has_many_through/proxy_spec.rb +62 -0
- data/spec/mongoid/association/referenced/has_many_through_spec.rb +399 -0
- data/spec/mongoid/association/referenced/has_one_through/eager_spec.rb +58 -0
- data/spec/mongoid/association/referenced/has_one_through/proxy_spec.rb +49 -0
- data/spec/mongoid/association/referenced/has_one_through_spec.rb +211 -0
- data/spec/mongoid/attributes/nested_spec.rb +249 -8
- data/spec/mongoid/config/defaults_spec.rb +33 -0
- data/spec/mongoid/config/encryption_spec.rb +228 -0
- data/spec/mongoid/contextual/aggregable/memory_spec.rb +91 -0
- data/spec/mongoid/contextual/memory_spec.rb +177 -0
- data/spec/mongoid/criteria/includable_spec.rb +875 -0
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +15 -1
- data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +201 -0
- data/spec/mongoid/criteria_spec.rb +3 -0
- data/spec/mongoid/encryptable_spec.rb +61 -0
- data/spec/mongoid/errors/config_redactor_spec.rb +112 -0
- data/spec/mongoid/errors/mixed_client_configuration_spec.rb +31 -0
- data/spec/mongoid/errors/no_client_database_spec.rb +29 -0
- data/spec/mongoid/errors/no_client_hosts_spec.rb +26 -0
- data/spec/mongoid/errors/readonly_association_spec.rb +34 -0
- data/spec/mongoid/extensions/vector_spec.rb +175 -0
- data/spec/mongoid/matcher/regexp_budget_spec.rb +570 -0
- data/spec/mongoid/search_indexable_spec.rb +295 -9
- data/spec/mongoid/tasks/database_spec.rb +18 -0
- data/spec/mongoid/timestamps/timeless_spec.rb +197 -5
- data/spec/mongoid/touchable_spec.rb +25 -0
- data/spec/mongoid/touchable_spec_models.rb +10 -0
- data/spec/mongoid/validatable/associated_spec.rb +19 -0
- data/spec/spec_helper.rb +5 -1
- data/spec/support/crypt/models.rb +157 -0
- metadata +52 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Errors
|
|
5
|
+
# This error is raised when evaluating a query in memory exceeds
|
|
6
|
+
# Mongoid::Config.in_memory_regexp_time_limit.
|
|
7
|
+
#
|
|
8
|
+
# What the limit bounds depends on the Ruby in use. Where per-Regexp
|
|
9
|
+
# timeouts are available it is the time spent executing regular
|
|
10
|
+
# expressions; elsewhere it is the elapsed time of the whole in-memory
|
|
11
|
+
# evaluation. The message is worded to hold either way.
|
|
12
|
+
class InMemoryRegexpTimeout < MongoidError
|
|
13
|
+
# Create the new error.
|
|
14
|
+
#
|
|
15
|
+
# @example Create the new in-memory regexp timeout error.
|
|
16
|
+
# InMemoryRegexpTimeout.new(5.0)
|
|
17
|
+
#
|
|
18
|
+
# @param [ Float ] limit The limit that was exceeded, in seconds. Not
|
|
19
|
+
# always the configured one: a global Regexp.timeout stricter than the
|
|
20
|
+
# configuration takes its place.
|
|
21
|
+
def initialize(limit)
|
|
22
|
+
super(compose_message('in_memory_regexp_timeout', limit: limit))
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Errors
|
|
5
|
+
# This error is raised when a model declares encrypted fields, but the
|
|
6
|
+
# namespace it is about to be persisted to is not covered by the automatic
|
|
7
|
+
# encryption schema of the client in use. Without a schema the driver has
|
|
8
|
+
# nothing to encrypt with, and the fields would be stored in plaintext.
|
|
9
|
+
class NoEncryptionSchema < MongoidError
|
|
10
|
+
# Create the new error.
|
|
11
|
+
#
|
|
12
|
+
# @example Create the error.
|
|
13
|
+
# NoEncryptionSchema.new(Band, 'music.bands', :default)
|
|
14
|
+
#
|
|
15
|
+
# @param [ Class ] klass The model class.
|
|
16
|
+
# @param [ String ] namespace The namespace the model resolved to.
|
|
17
|
+
# @param [ String | Symbol ] client The name of the client in use.
|
|
18
|
+
def initialize(klass, namespace, client)
|
|
19
|
+
super(
|
|
20
|
+
compose_message(
|
|
21
|
+
'no_encryption_schema',
|
|
22
|
+
{ klass: klass, namespace: namespace, client: client }
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Errors
|
|
5
|
+
# Raised when attempting to write to a :through association, which is
|
|
6
|
+
# read-only.
|
|
7
|
+
class ReadonlyAssociation < MongoidError
|
|
8
|
+
# Instantiate the exception.
|
|
9
|
+
#
|
|
10
|
+
# @example Create the error.
|
|
11
|
+
# ReadonlyAssociation.new(Physician, association)
|
|
12
|
+
#
|
|
13
|
+
# @param [ Class ] klass The owner class.
|
|
14
|
+
# @param [ Mongoid::Association::Relatable ] association The through association.
|
|
15
|
+
def initialize(klass, association)
|
|
16
|
+
super(
|
|
17
|
+
compose_message(
|
|
18
|
+
'readonly_association',
|
|
19
|
+
{
|
|
20
|
+
klass: klass,
|
|
21
|
+
name: association.name,
|
|
22
|
+
through: association.options[:through]
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/mongoid/errors.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'mongoid/errors/mongoid_error'
|
|
4
|
+
require 'mongoid/errors/config_redactor'
|
|
4
5
|
require 'mongoid/errors/ambiguous_relationship'
|
|
5
6
|
require 'mongoid/errors/attribute_not_loaded'
|
|
6
7
|
require 'mongoid/errors/callback'
|
|
@@ -11,6 +12,7 @@ require 'mongoid/errors/document_not_found'
|
|
|
11
12
|
require 'mongoid/errors/empty_config_file'
|
|
12
13
|
require 'mongoid/errors/immutable_attribute'
|
|
13
14
|
require 'mongoid/errors/in_memory_collation_not_supported'
|
|
15
|
+
require 'mongoid/errors/in_memory_regexp_timeout'
|
|
14
16
|
require 'mongoid/errors/invalid_auto_encryption_configuration'
|
|
15
17
|
require 'mongoid/errors/invalid_around_callback'
|
|
16
18
|
require 'mongoid/errors/invalid_async_query_executor'
|
|
@@ -51,6 +53,7 @@ require 'mongoid/errors/mixed_client_configuration'
|
|
|
51
53
|
require 'mongoid/errors/nested_attributes_metadata_not_found'
|
|
52
54
|
require 'mongoid/errors/no_default_client'
|
|
53
55
|
require 'mongoid/errors/no_environment'
|
|
56
|
+
require 'mongoid/errors/no_encryption_schema'
|
|
54
57
|
require 'mongoid/errors/no_map_reduce_output'
|
|
55
58
|
require 'mongoid/errors/no_metadata'
|
|
56
59
|
require 'mongoid/errors/no_parent'
|
|
@@ -60,6 +63,7 @@ require 'mongoid/errors/no_client_database'
|
|
|
60
63
|
require 'mongoid/errors/no_client_hosts'
|
|
61
64
|
require 'mongoid/errors/readonly_attribute'
|
|
62
65
|
require 'mongoid/errors/readonly_document'
|
|
66
|
+
require 'mongoid/errors/readonly_association'
|
|
63
67
|
require 'mongoid/errors/rollback'
|
|
64
68
|
require 'mongoid/errors/sessions_not_supported'
|
|
65
69
|
require 'mongoid/errors/scope_overwrite'
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Extensions
|
|
5
|
+
# Adds type-casting behavior to BSON::Vector class so that a field
|
|
6
|
+
# declared with +type: BSON::Vector+ is stored as a BSON binary of the
|
|
7
|
+
# vector subtype and read back as a BSON::Vector.
|
|
8
|
+
#
|
|
9
|
+
# Querying by an exact vector value (e.g. +where(embedding: vector)+) is
|
|
10
|
+
# not supported: BSON::Vector subclasses Array, so the criteria selector
|
|
11
|
+
# treats it as a list of elements rather than a scalar. Use Atlas Vector
|
|
12
|
+
# Search ($vectorSearch) for similarity queries on vector fields.
|
|
13
|
+
module Vector
|
|
14
|
+
# Turn the object from the ruby type we deal with to a Mongo friendly
|
|
15
|
+
# type.
|
|
16
|
+
#
|
|
17
|
+
# @example Mongoize the object.
|
|
18
|
+
# object.mongoize
|
|
19
|
+
#
|
|
20
|
+
# @return [ BSON::Binary | nil ] The object as a vector binary.
|
|
21
|
+
def mongoize
|
|
22
|
+
BSON::Vector.mongoize(self)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module ClassMethods
|
|
26
|
+
# Mongoize an object of any type to how it's stored in the db.
|
|
27
|
+
#
|
|
28
|
+
# @example Mongoize the object.
|
|
29
|
+
# BSON::Vector.mongoize(vector)
|
|
30
|
+
#
|
|
31
|
+
# @param [ Object ] object The object to Mongoize.
|
|
32
|
+
#
|
|
33
|
+
# @return [ BSON::Binary | nil ] A vector binary or nil.
|
|
34
|
+
def mongoize(object)
|
|
35
|
+
case object
|
|
36
|
+
when BSON::Vector then BSON::Binary.from_vector(object)
|
|
37
|
+
when BSON::Binary then object
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Convert the object from its mongo friendly ruby type back to a
|
|
42
|
+
# BSON::Vector.
|
|
43
|
+
#
|
|
44
|
+
# @example Demongoize the object.
|
|
45
|
+
# BSON::Vector.demongoize(binary)
|
|
46
|
+
#
|
|
47
|
+
# @param [ Object ] object The object to demongoize.
|
|
48
|
+
#
|
|
49
|
+
# @return [ BSON::Vector | nil ] The vector or nil.
|
|
50
|
+
def demongoize(object)
|
|
51
|
+
case object
|
|
52
|
+
when BSON::Binary then (object.type == :vector) ? object.as_vector : nil
|
|
53
|
+
when BSON::Vector then object
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if defined?(BSON::Vector)
|
|
62
|
+
BSON::Vector.include Mongoid::Extensions::Vector
|
|
63
|
+
BSON::Vector.extend(Mongoid::Extensions::Vector::ClassMethods)
|
|
64
|
+
end
|
data/lib/mongoid/extensions.rb
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
# Reads the value of a field name from a document without dispatching the
|
|
5
|
+
# name as an arbitrary method.
|
|
6
|
+
#
|
|
7
|
+
# Field names may come from application input, where a name like +destroy+
|
|
8
|
+
# or +attributes+ would delete the document or disclose its contents.
|
|
9
|
+
# Declared field and association names are validated when they are declared
|
|
10
|
+
# (see Mongoid.destructive_fields), so a name that resolves to one of them
|
|
11
|
+
# is safe to send to a document. Any other name is read from the attributes
|
|
12
|
+
# hash, which is what the database-backed query contexts do.
|
|
13
|
+
#
|
|
14
|
+
# @api private
|
|
15
|
+
module FieldReadable
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Read the value of the given field name from the given document.
|
|
19
|
+
#
|
|
20
|
+
# @param [ Document ] document The document to read from.
|
|
21
|
+
# @param [ String | Symbol ] name The name of the field.
|
|
22
|
+
#
|
|
23
|
+
# @return [ Object | nil ] The value of the field, or nil when the name
|
|
24
|
+
# is neither a declared field nor present in the attributes.
|
|
25
|
+
def read_field_value(document, name)
|
|
26
|
+
name = name.to_s
|
|
27
|
+
# A blank name cannot name a field. Return nil, which is what reading
|
|
28
|
+
# one has always done.
|
|
29
|
+
return nil if name.blank?
|
|
30
|
+
|
|
31
|
+
if (meth = readable_method_for(document.class, name))
|
|
32
|
+
document.public_send(meth)
|
|
33
|
+
else
|
|
34
|
+
document.attributes[document.class.database_field_name(name)]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Resolve the given name to a method that is declared by the given class,
|
|
39
|
+
# and therefore safe to send to one of its instances.
|
|
40
|
+
#
|
|
41
|
+
# @param [ Class ] klass The document class.
|
|
42
|
+
# @param [ String ] name The name of the field.
|
|
43
|
+
#
|
|
44
|
+
# @return [ String | nil ] The method to send, or nil when the name is
|
|
45
|
+
# not declared by the class.
|
|
46
|
+
def readable_method_for(klass, name)
|
|
47
|
+
# Fields, associations, and field aliases each define a reader of their
|
|
48
|
+
# own name. Note that associations must be resolved before aliases: a
|
|
49
|
+
# belongs_to aliases its own name to its foreign key, and reading
|
|
50
|
+
# `band` must give the document, not the id.
|
|
51
|
+
return name if klass.relations.key?(name) ||
|
|
52
|
+
klass.fields.key?(name) ||
|
|
53
|
+
klass.aliased_fields.key?(name)
|
|
54
|
+
|
|
55
|
+
# An association may also be named by its `store_as`, which has no
|
|
56
|
+
# reader of its own, or by its ids accessor, which does.
|
|
57
|
+
if (assoc = klass.relations[klass.aliased_associations[name]])
|
|
58
|
+
return (assoc.store_as == name) ? assoc.name.to_s : name
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Localized fields also get a _translations reader, which does not
|
|
62
|
+
# appear in the fields hash.
|
|
63
|
+
base = name.delete_suffix(Fields::TRANSLATIONS_SFX)
|
|
64
|
+
return nil if base == name
|
|
65
|
+
|
|
66
|
+
name if klass.fields[klass.database_field_name(base)]&.localized?
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/mongoid/indexable.rb
CHANGED
|
@@ -24,18 +24,9 @@ module Mongoid
|
|
|
24
24
|
def create_indexes
|
|
25
25
|
return unless index_specifications
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
key, options = spec.key, default_options.merge(spec.options)
|
|
31
|
-
if database = options[:database]
|
|
32
|
-
with(database: database) do |klass|
|
|
33
|
-
klass.collection.indexes(session: _session).create_one(key, options.except(:database))
|
|
34
|
-
end
|
|
35
|
-
else
|
|
36
|
-
collection.indexes(session: _session).create_one(key, options)
|
|
37
|
-
end
|
|
38
|
-
end and true
|
|
27
|
+
Threaded.with_collection_management do
|
|
28
|
+
perform_create_indexes
|
|
29
|
+
end
|
|
39
30
|
end
|
|
40
31
|
|
|
41
32
|
# Send the actual index removal comments to the MongoDB driver,
|
|
@@ -46,20 +37,9 @@ module Mongoid
|
|
|
46
37
|
#
|
|
47
38
|
# @return [ true ] If the operation succeeded.
|
|
48
39
|
def remove_indexes
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
next if spec['name'] == '_id_'
|
|
53
|
-
|
|
54
|
-
klass.collection.indexes(session: _session).drop_one(spec['key'])
|
|
55
|
-
logger.info(
|
|
56
|
-
"MONGOID: Removed index '#{spec['name']}' on collection " +
|
|
57
|
-
"'#{klass.collection.name}' in database '#{database}'."
|
|
58
|
-
)
|
|
59
|
-
end
|
|
60
|
-
rescue Mongo::Error::OperationFailure
|
|
61
|
-
end
|
|
62
|
-
end and true
|
|
40
|
+
Threaded.with_collection_management do
|
|
41
|
+
perform_remove_indexes
|
|
42
|
+
end
|
|
63
43
|
end
|
|
64
44
|
|
|
65
45
|
# Add the default indexes to the root document if they do not already
|
|
@@ -119,6 +99,38 @@ module Mongoid
|
|
|
119
99
|
|
|
120
100
|
private
|
|
121
101
|
|
|
102
|
+
def perform_create_indexes
|
|
103
|
+
default_options = { background: Config.background_indexing }
|
|
104
|
+
|
|
105
|
+
index_specifications.each do |spec|
|
|
106
|
+
key, options = spec.key, default_options.merge(spec.options)
|
|
107
|
+
if database = options[:database]
|
|
108
|
+
with(database: database) do |klass|
|
|
109
|
+
klass.collection.indexes(session: _session).create_one(key, options.except(:database))
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
collection.indexes(session: _session).create_one(key, options)
|
|
113
|
+
end
|
|
114
|
+
end and true
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def perform_remove_indexes
|
|
118
|
+
indexed_database_names.each do |database|
|
|
119
|
+
with(database: database) do |klass|
|
|
120
|
+
klass.collection.indexes(session: _session).each do |spec|
|
|
121
|
+
next if spec['name'] == '_id_'
|
|
122
|
+
|
|
123
|
+
klass.collection.indexes(session: _session).drop_one(spec['key'])
|
|
124
|
+
logger.info(
|
|
125
|
+
"MONGOID: Removed index '#{spec['name']}' on collection " +
|
|
126
|
+
"'#{klass.collection.name}' in database '#{database}'."
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
rescue Mongo::Error::OperationFailure
|
|
130
|
+
end
|
|
131
|
+
end and true
|
|
132
|
+
end
|
|
133
|
+
|
|
122
134
|
# Get the names of all databases for this model that have index
|
|
123
135
|
# definitions.
|
|
124
136
|
#
|
data/lib/mongoid/matchable.rb
CHANGED
|
@@ -16,7 +16,12 @@ module Mongoid
|
|
|
16
16
|
#
|
|
17
17
|
# @return [ true | false ] True if matches, false if not.
|
|
18
18
|
def _matches?(selector)
|
|
19
|
-
|
|
19
|
+
# Opens a regexp budget for this document only. Callers that match many
|
|
20
|
+
# documents against one selector open a budget of their own first, and
|
|
21
|
+
# this one joins it rather than giving every document a fresh limit.
|
|
22
|
+
Matcher::RegexpBudget.open(selector) do
|
|
23
|
+
Matcher::Expression.matches?(self, selector)
|
|
24
|
+
end
|
|
20
25
|
end
|
|
21
26
|
end
|
|
22
27
|
end
|
|
@@ -18,10 +18,8 @@ module Mongoid
|
|
|
18
18
|
# @api private
|
|
19
19
|
module_function def matches?(_original_operator, value, condition)
|
|
20
20
|
case condition
|
|
21
|
-
when Regexp
|
|
22
|
-
value.respond_to?(:=~) && value
|
|
23
|
-
when ::BSON::Regexp::Raw
|
|
24
|
-
value.respond_to?(:=~) && value =~ condition.compile
|
|
21
|
+
when Regexp, ::BSON::Regexp::Raw
|
|
22
|
+
value.respond_to?(:=~) && RegexpBudget.match?(value, condition)
|
|
25
23
|
else
|
|
26
24
|
if value.is_a?(Time) && condition.is_a?(Time)
|
|
27
25
|
EqImpl.time_eq?(value, condition)
|
|
@@ -16,24 +16,23 @@ module Mongoid
|
|
|
16
16
|
#
|
|
17
17
|
# @api private
|
|
18
18
|
module_function def matches?(_exists, value, condition)
|
|
19
|
-
condition
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
else
|
|
25
|
-
# Note that strings must have been converted to a regular expression
|
|
26
|
-
# instance already (with $options taken into account, if provided).
|
|
27
|
-
raise Errors::InvalidQuery, "$regex requires a regular expression argument: #{Errors::InvalidQuery.truncate_expr(condition)}"
|
|
28
|
-
end
|
|
19
|
+
unless condition.is_a?(Regexp) || condition.is_a?(BSON::Regexp::Raw)
|
|
20
|
+
# Note that strings must have been converted to a regular expression
|
|
21
|
+
# instance already (with $options taken into account, if provided).
|
|
22
|
+
raise Errors::InvalidQuery, "$regex requires a regular expression argument: #{Errors::InvalidQuery.truncate_expr(condition)}"
|
|
23
|
+
end
|
|
29
24
|
|
|
25
|
+
# The condition is compiled by RegexpBudget rather than here, so that
|
|
26
|
+
# the budget's timeout can be baked into the pattern.
|
|
30
27
|
case value
|
|
31
28
|
when Array
|
|
29
|
+
# Object#=~ is gone as of Ruby 3.2, so an element that cannot be
|
|
30
|
+
# matched against has to be rejected rather than passed to =~.
|
|
32
31
|
value.any? do |v|
|
|
33
|
-
v
|
|
32
|
+
v.respond_to?(:=~) && RegexpBudget.match?(v, condition)
|
|
34
33
|
end
|
|
35
34
|
when String
|
|
36
|
-
value
|
|
35
|
+
RegexpBudget.match?(value, condition)
|
|
37
36
|
else
|
|
38
37
|
false
|
|
39
38
|
end
|