mongoid 8.0.13 → 8.1.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/CHANGELOG.md +3 -3
- data/README.md +3 -3
- data/Rakefile +17 -66
- data/lib/config/locales/en.yml +46 -40
- data/lib/mongoid/association/accessors.rb +3 -7
- data/lib/mongoid/association/builders.rb +1 -1
- data/lib/mongoid/association/depending.rb +4 -8
- data/lib/mongoid/association/eager_loadable.rb +0 -3
- data/lib/mongoid/association/embedded/batchable.rb +2 -2
- data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
- data/lib/mongoid/association/embedded/embedded_in/proxy.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_many/buildable.rb +3 -2
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +6 -6
- data/lib/mongoid/association/embedded/embeds_one/buildable.rb +1 -1
- data/lib/mongoid/association/embedded/embeds_one/proxy.rb +2 -2
- data/lib/mongoid/association/macros.rb +0 -6
- data/lib/mongoid/association/nested/many.rb +3 -38
- data/lib/mongoid/association/nested/nested_buildable.rb +0 -14
- data/lib/mongoid/association/nested/one.rb +40 -2
- data/lib/mongoid/association/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/counter_cache.rb +2 -2
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +6 -23
- data/lib/mongoid/association/referenced/has_many/proxy.rb +4 -103
- data/lib/mongoid/association/reflections.rb +2 -2
- data/lib/mongoid/atomic.rb +7 -16
- data/lib/mongoid/attributes/dynamic.rb +1 -1
- data/lib/mongoid/attributes/nested.rb +2 -2
- data/lib/mongoid/attributes/processing.rb +5 -29
- data/lib/mongoid/attributes/projector.rb +1 -1
- data/lib/mongoid/attributes/readonly.rb +1 -1
- data/lib/mongoid/attributes.rb +8 -2
- data/lib/mongoid/changeable.rb +107 -5
- data/lib/mongoid/clients/factory.rb +0 -4
- data/lib/mongoid/clients/storage_options.rb +2 -5
- data/lib/mongoid/clients/validators/storage.rb +1 -13
- data/lib/mongoid/collection_configurable.rb +58 -0
- data/lib/mongoid/composable.rb +2 -0
- data/lib/mongoid/config/defaults.rb +60 -0
- data/lib/mongoid/config/options.rb +0 -3
- data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
- data/lib/mongoid/config/validators.rb +1 -0
- data/lib/mongoid/config.rb +88 -89
- data/lib/mongoid/contextual/aggregable/memory.rb +2 -5
- data/lib/mongoid/contextual/atomic.rb +1 -1
- data/lib/mongoid/contextual/memory.rb +240 -51
- data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
- data/lib/mongoid/contextual/mongo.rb +370 -133
- data/lib/mongoid/contextual/none.rb +162 -7
- data/lib/mongoid/contextual.rb +12 -0
- data/lib/mongoid/criteria/findable.rb +2 -2
- data/lib/mongoid/criteria/includable.rb +4 -3
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -15
- data/lib/mongoid/criteria/queryable/key.rb +1 -1
- data/lib/mongoid/criteria/queryable/mergeable.rb +1 -13
- data/lib/mongoid/criteria/queryable/optional.rb +8 -8
- data/lib/mongoid/criteria/queryable/selectable.rb +43 -121
- data/lib/mongoid/criteria/queryable/selector.rb +1 -1
- data/lib/mongoid/criteria/queryable/storable.rb +1 -1
- data/lib/mongoid/criteria.rb +6 -5
- data/lib/mongoid/deprecable.rb +1 -2
- data/lib/mongoid/deprecation.rb +3 -3
- data/lib/mongoid/document.rb +1 -8
- data/lib/mongoid/errors/create_collection_failure.rb +33 -0
- data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
- data/lib/mongoid/errors/immutable_attribute.rb +26 -0
- data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
- data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
- data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
- data/lib/mongoid/errors.rb +4 -2
- data/lib/mongoid/extensions/hash.rb +3 -51
- data/lib/mongoid/extensions/object.rb +2 -2
- data/lib/mongoid/extensions/time.rb +2 -0
- data/lib/mongoid/fields/localized.rb +10 -0
- data/lib/mongoid/fields/standard.rb +10 -0
- data/lib/mongoid/fields.rb +59 -35
- data/lib/mongoid/findable.rb +27 -3
- data/lib/mongoid/interceptable.rb +6 -116
- data/lib/mongoid/matchable.rb +1 -6
- data/lib/mongoid/matcher/eq_impl.rb +1 -1
- data/lib/mongoid/matcher/eq_impl_with_regexp.rb +5 -3
- data/lib/mongoid/matcher/regex.rb +9 -8
- data/lib/mongoid/matcher/type.rb +1 -1
- data/lib/mongoid/matcher.rb +0 -1
- data/lib/mongoid/persistable/creatable.rb +1 -0
- data/lib/mongoid/persistable/deletable.rb +1 -1
- data/lib/mongoid/persistable/savable.rb +13 -1
- data/lib/mongoid/persistable/unsettable.rb +2 -2
- data/lib/mongoid/persistable/updatable.rb +51 -1
- data/lib/mongoid/persistable/upsertable.rb +20 -1
- data/lib/mongoid/persistable.rb +3 -0
- data/lib/mongoid/query_cache.rb +5 -1
- data/lib/mongoid/railties/database.rake +7 -2
- data/lib/mongoid/reloadable.rb +5 -3
- data/lib/mongoid/stateful.rb +22 -1
- data/lib/mongoid/tasks/database.rake +12 -0
- data/lib/mongoid/tasks/database.rb +20 -0
- data/lib/mongoid/threaded.rb +0 -3
- data/lib/mongoid/timestamps/created.rb +1 -8
- data/lib/mongoid/traversable.rb +0 -12
- data/lib/mongoid/utils.rb +22 -0
- data/lib/mongoid/validatable/associated.rb +17 -98
- data/lib/mongoid/validatable/macros.rb +5 -20
- data/lib/mongoid/validatable.rb +4 -10
- data/lib/mongoid/version.rb +1 -5
- data/lib/mongoid/warnings.rb +17 -2
- data/lib/mongoid.rb +16 -3
- data/spec/integration/app_spec.rb +2 -20
- data/spec/integration/associations/embeds_one_spec.rb +5 -25
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +0 -55
- data/spec/integration/callbacks_spec.rb +99 -12
- data/spec/integration/discriminator_key_spec.rb +4 -5
- data/spec/integration/dots_and_dollars_spec.rb +2 -12
- data/spec/integration/i18n_fallbacks_spec.rb +3 -2
- data/spec/integration/matcher_operator_data/regex.yml +0 -21
- data/spec/mongoid/association/eager_spec.rb +2 -24
- data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +27 -0
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +20 -25
- data/spec/mongoid/association/embedded/embeds_many_models.rb +1 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +0 -4
- data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +2 -18
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +42 -103
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +9 -195
- data/spec/mongoid/association/syncable_spec.rb +1 -1
- data/spec/mongoid/attributes/nested_spec.rb +10 -204
- data/spec/mongoid/attributes_spec.rb +3 -33
- data/spec/mongoid/changeable_spec.rb +299 -24
- data/spec/mongoid/clients/factory_spec.rb +0 -30
- data/spec/mongoid/clients_spec.rb +122 -13
- data/spec/mongoid/collection_configurable_spec.rb +158 -0
- data/spec/mongoid/config/defaults_spec.rb +160 -0
- data/spec/mongoid/config_spec.rb +154 -27
- data/spec/mongoid/contextual/aggregable/memory_spec.rb +0 -91
- data/spec/mongoid/contextual/memory_spec.rb +332 -253
- data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
- data/spec/mongoid/contextual/mongo_spec.rb +1009 -125
- data/spec/mongoid/contextual/none_spec.rb +49 -2
- data/spec/mongoid/copyable_spec.rb +2 -10
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -10
- data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +419 -2
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +0 -235
- data/spec/mongoid/criteria/queryable/selector_spec.rb +3 -76
- data/spec/mongoid/criteria/queryable/storable_spec.rb +0 -72
- data/spec/mongoid/criteria_projection_spec.rb +1 -4
- data/spec/mongoid/criteria_spec.rb +5 -11
- data/spec/mongoid/document_spec.rb +0 -27
- data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
- data/spec/mongoid/extensions/hash_spec.rb +3 -239
- data/spec/mongoid/extensions/time_spec.rb +8 -43
- data/spec/mongoid/extensions/time_with_zone_spec.rb +7 -52
- data/spec/mongoid/fields/localized_spec.rb +46 -28
- data/spec/mongoid/fields_spec.rb +136 -77
- data/spec/mongoid/findable_spec.rb +391 -34
- data/spec/mongoid/indexable_spec.rb +16 -10
- data/spec/mongoid/interceptable_spec.rb +153 -442
- data/spec/mongoid/interceptable_spec_models.rb +111 -51
- data/spec/mongoid/persistable/deletable_spec.rb +26 -6
- data/spec/mongoid/persistable/destroyable_spec.rb +26 -6
- data/spec/mongoid/persistable/incrementable_spec.rb +37 -0
- data/spec/mongoid/persistable/logical_spec.rb +37 -0
- data/spec/mongoid/persistable/poppable_spec.rb +36 -0
- data/spec/mongoid/persistable/pullable_spec.rb +72 -0
- data/spec/mongoid/persistable/pushable_spec.rb +72 -0
- data/spec/mongoid/persistable/renamable_spec.rb +36 -0
- data/spec/mongoid/persistable/savable_spec.rb +96 -0
- data/spec/mongoid/persistable/settable_spec.rb +37 -0
- data/spec/mongoid/persistable/unsettable_spec.rb +36 -0
- data/spec/mongoid/persistable/updatable_spec.rb +20 -28
- data/spec/mongoid/persistable/upsertable_spec.rb +80 -6
- data/spec/mongoid/persistence_context_spec.rb +7 -57
- data/spec/mongoid/query_cache_spec.rb +56 -61
- data/spec/mongoid/reloadable_spec.rb +24 -28
- data/spec/mongoid/scopable_spec.rb +70 -0
- data/spec/mongoid/serializable_spec.rb +23 -44
- data/spec/mongoid/stateful_spec.rb +122 -8
- data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
- data/spec/mongoid/tasks/database_spec.rb +127 -0
- data/spec/mongoid/timestamps/created_spec.rb +0 -23
- data/spec/mongoid/timestamps_spec.rb +9 -11
- data/spec/mongoid/touchable_spec.rb +277 -5
- data/spec/mongoid/touchable_spec_models.rb +3 -1
- data/spec/mongoid/traversable_spec.rb +9 -24
- data/spec/mongoid/validatable/associated_spec.rb +34 -27
- data/spec/mongoid/validatable/numericality_spec.rb +0 -16
- data/spec/mongoid/validatable/uniqueness_spec.rb +2 -3
- data/spec/mongoid_spec.rb +36 -10
- data/spec/shared/lib/mrss/docker_runner.rb +1 -1
- data/spec/shared/lib/mrss/server_version_registry.rb +1 -1
- data/spec/shared/lib/mrss/spec_organizer.rb +3 -32
- data/spec/shared/share/Dockerfile.erb +85 -15
- data/spec/shared/shlib/distro.sh +0 -10
- data/spec/shared/shlib/server.sh +27 -34
- data/spec/shared/shlib/set_env.sh +68 -9
- data/spec/spec_helper.rb +5 -0
- data/spec/support/expectations.rb +17 -20
- data/spec/support/immutable_ids.rb +118 -0
- data/spec/support/macros.rb +47 -15
- data/spec/support/models/artist.rb +0 -1
- data/spec/support/models/band.rb +1 -0
- data/spec/support/models/building.rb +2 -0
- data/spec/support/models/name.rb +0 -10
- data/spec/support/models/person.rb +0 -1
- data/spec/support/models/product.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +715 -671
- metadata.gz.sig +2 -0
- data/lib/mongoid/errors/in_memory_regexp_timeout.rb +0 -26
- data/lib/mongoid/field_readable.rb +0 -70
- data/lib/mongoid/matcher/regexp_budget.rb +0 -389
- data/lib/mongoid/validatable/numericality.rb +0 -19
- data/spec/integration/matcher_regexp_timeout_spec.rb +0 -215
- data/spec/integration/query_operator_guard_spec.rb +0 -89
- data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -61
- data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -61
- data/spec/mongoid/matcher/regexp_budget_spec.rb +0 -570
- data/spec/shared/CANDIDATE.md +0 -28
- data/spec/shared/lib/mrss/release/candidate.rb +0 -281
- data/spec/shared/lib/mrss/release/product_data.rb +0 -144
- data/spec/shared/lib/tasks/candidate.rake +0 -64
- data/spec/support/models/purse.rb +0 -9
|
@@ -5,6 +5,11 @@ namespace :db do
|
|
|
5
5
|
task :load_models do
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
desc "Create collections for Mongoid models"
|
|
9
|
+
task :create_collections => [:environment, :load_models] do
|
|
10
|
+
::Mongoid::Tasks::Database.create_collections
|
|
11
|
+
end
|
|
12
|
+
|
|
8
13
|
desc "Create indexes specified in Mongoid models"
|
|
9
14
|
task :create_indexes => [:environment, :load_models] do
|
|
10
15
|
::Mongoid::Tasks::Database.create_indexes
|
|
@@ -34,5 +39,12 @@ namespace :db do
|
|
|
34
39
|
task :purge => :environment do
|
|
35
40
|
::Mongoid.purge!
|
|
36
41
|
end
|
|
42
|
+
|
|
43
|
+
namespace :create_collections do
|
|
44
|
+
desc "Drop and create collections for Mongoid models"
|
|
45
|
+
task :force => [:environment, :load_models] do
|
|
46
|
+
::Mongoid::Tasks::Database.create_collections(force: true)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
37
49
|
end
|
|
38
50
|
end
|
|
@@ -5,6 +5,26 @@ module Mongoid
|
|
|
5
5
|
module Database
|
|
6
6
|
extend self
|
|
7
7
|
|
|
8
|
+
# Create collections for each model given the provided globs and the class is
|
|
9
|
+
# not embedded.
|
|
10
|
+
#
|
|
11
|
+
# @param [ Array<Mongoid::Document> ] models. Array of document classes for
|
|
12
|
+
# which collections should be created. Defaulted to all document classes
|
|
13
|
+
# in the application.
|
|
14
|
+
# @param [ true | false ] force If true, the method will drop existing
|
|
15
|
+
# collections before creating new ones. If false, the method will create
|
|
16
|
+
# only new collection (that do not exist in the database).
|
|
17
|
+
def create_collections(models = ::Mongoid.models, force: false)
|
|
18
|
+
models.each do |model|
|
|
19
|
+
if !model.embedded? || model.cyclic?
|
|
20
|
+
model.create_collection(force: force)
|
|
21
|
+
logger.info("MONGOID: Created collection for #{model}:")
|
|
22
|
+
else
|
|
23
|
+
logger.info("MONGOID: collection options ignored on: #{model}, please define in the root model.")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
8
28
|
# Create indexes for each model given the provided globs and the class is
|
|
9
29
|
# not embedded.
|
|
10
30
|
#
|
data/lib/mongoid/threaded.rb
CHANGED
|
@@ -30,9 +30,6 @@ module Mongoid
|
|
|
30
30
|
# executed on documents.
|
|
31
31
|
EXECUTE_CALLBACKS = '[mongoid]:execute-callbacks'
|
|
32
32
|
|
|
33
|
-
# The key for the time left in the current in-memory regexp budget.
|
|
34
|
-
REGEXP_BUDGET_KEY = 'regexp-budget'
|
|
35
|
-
|
|
36
33
|
extend self
|
|
37
34
|
|
|
38
35
|
# Begin entry into a named thread local stack.
|
|
@@ -22,20 +22,13 @@ module Mongoid
|
|
|
22
22
|
# @example Set the created at time.
|
|
23
23
|
# person.set_created_at
|
|
24
24
|
def set_created_at
|
|
25
|
-
if
|
|
25
|
+
if !timeless? && !created_at
|
|
26
26
|
time = Time.configured.now
|
|
27
27
|
self.updated_at = time if is_a?(Updated) && !updated_at_changed?
|
|
28
28
|
self.created_at = time
|
|
29
29
|
end
|
|
30
30
|
clear_timeless_option
|
|
31
31
|
end
|
|
32
|
-
|
|
33
|
-
# Is the created timestamp able to be set?
|
|
34
|
-
#
|
|
35
|
-
# @return [ true, false ] If the timestamp can be set.
|
|
36
|
-
def able_to_set_created_at?
|
|
37
|
-
!frozen? && !timeless? && !created_at
|
|
38
|
-
end
|
|
39
32
|
end
|
|
40
33
|
end
|
|
41
34
|
end
|
data/lib/mongoid/traversable.rb
CHANGED
|
@@ -300,18 +300,6 @@ module Mongoid
|
|
|
300
300
|
!!(Mongoid::Document > superclass)
|
|
301
301
|
end
|
|
302
302
|
|
|
303
|
-
# Returns the root class of the STI tree that the current
|
|
304
|
-
# class participates in. If the class is not an STI subclass, this
|
|
305
|
-
# returns the class itself.
|
|
306
|
-
#
|
|
307
|
-
# @return [ Mongoid::Document ] the root of the STI tree
|
|
308
|
-
def root_class
|
|
309
|
-
root = self
|
|
310
|
-
root = root.superclass while root.hereditary?
|
|
311
|
-
|
|
312
|
-
root
|
|
313
|
-
end
|
|
314
|
-
|
|
315
303
|
# When inheriting, we want to copy the fields from the parent class and
|
|
316
304
|
# set the on the child to start, mimicking the behavior of the old
|
|
317
305
|
# class_inheritable_accessor that was deprecated in Rails edge.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
|
|
5
|
+
# @api private
|
|
6
|
+
module Utils
|
|
7
|
+
|
|
8
|
+
# This function should be used if you need to measure time.
|
|
9
|
+
# @example Calculate elapsed time.
|
|
10
|
+
# starting = Utils.monotonic_time
|
|
11
|
+
# # do something time consuming
|
|
12
|
+
# ending = Utils.monotonic_time
|
|
13
|
+
# puts "It took #{(ending - starting).to_i} seconds"
|
|
14
|
+
#
|
|
15
|
+
# @see https://blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way/
|
|
16
|
+
#
|
|
17
|
+
# @return [Float] seconds according to monotonic clock
|
|
18
|
+
module_function def monotonic_time
|
|
19
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -15,113 +15,32 @@ module Mongoid
|
|
|
15
15
|
#
|
|
16
16
|
# validates_associated :name, :addresses
|
|
17
17
|
# end
|
|
18
|
-
class AssociatedValidator < ActiveModel::
|
|
19
|
-
# Required by `validates_with` so that the validator
|
|
20
|
-
# gets added to the correct attributes.
|
|
21
|
-
def attributes
|
|
22
|
-
options[:attributes]
|
|
23
|
-
end
|
|
18
|
+
class AssociatedValidator < ActiveModel::EachValidator
|
|
24
19
|
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# or unpersisted.
|
|
20
|
+
# Validates that the associations provided are either all nil or all
|
|
21
|
+
# valid. If neither is true then the appropriate errors will be added to
|
|
22
|
+
# the parent document.
|
|
29
23
|
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# @param [ Mongoid::Document ] document the document with the
|
|
34
|
-
# associations to validate.
|
|
35
|
-
def validate(document)
|
|
36
|
-
options[:attributes].each do |attr_name|
|
|
37
|
-
validate_association(document, attr_name)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
# Validates that the given association provided is either nil,
|
|
44
|
-
# persisted and unchanged, or invalid. Otherwise, the appropriate errors
|
|
45
|
-
# will be added to the parent document.
|
|
24
|
+
# @example Validate the association.
|
|
25
|
+
# validator.validate_each(document, :name, name)
|
|
46
26
|
#
|
|
47
27
|
# @param [ Document ] document The document to validate.
|
|
48
28
|
# @param [ Symbol ] attribute The association to validate.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# if the variable exists, now we see if it is a proxy, or an actual
|
|
57
|
-
# document. It might be a literal document instead of a proxy if this
|
|
58
|
-
# document was created with a Document instance as a provided attribute,
|
|
59
|
-
# e.g. "Post.new(message: Message.new)".
|
|
60
|
-
target = proxy.respond_to?(:_target) ? proxy._target : proxy
|
|
61
|
-
|
|
62
|
-
# Now, fetch the list of documents from the target. Target may be a
|
|
63
|
-
# single value, or a list of values, and in the case of HasMany,
|
|
64
|
-
# might be a rather complex collection. We need to do this without
|
|
65
|
-
# triggering a load, so it's a bit of a delicate dance.
|
|
66
|
-
list = get_target_documents(target)
|
|
67
|
-
|
|
68
|
-
valid = document.validating do
|
|
69
|
-
# Now, treating the target as an array, look at each element
|
|
70
|
-
# and see if it is valid, but only if it has already been
|
|
71
|
-
# persisted, or changed, and hasn't been flagged for destroy.
|
|
72
|
-
#
|
|
73
|
-
# use map.all? instead of just all?, because all? will do short-circuit
|
|
74
|
-
# evaluation and terminate on the first failed validation.
|
|
75
|
-
list.map do |value|
|
|
76
|
-
if value && !value.flagged_for_destroy? && (!value.persisted? || value.changed?)
|
|
77
|
-
value.validated? ? true : value.valid?
|
|
78
|
-
else
|
|
29
|
+
# @param [ Object ] value The value of the association.
|
|
30
|
+
def validate_each(document, attribute, value)
|
|
31
|
+
begin
|
|
32
|
+
document.begin_validate
|
|
33
|
+
valid = Array.wrap(value).collect do |doc|
|
|
34
|
+
if doc.nil? || doc.flagged_for_destroy?
|
|
79
35
|
true
|
|
36
|
+
else
|
|
37
|
+
doc.validated? ? true : doc.valid?
|
|
80
38
|
end
|
|
81
39
|
end.all?
|
|
40
|
+
ensure
|
|
41
|
+
document.exit_validate
|
|
82
42
|
end
|
|
83
|
-
|
|
84
|
-
document.errors.add(attribute, :invalid) unless valid
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
private
|
|
88
|
-
|
|
89
|
-
# Examine the given target object and return an array of
|
|
90
|
-
# documents (possibly empty) that the target represents.
|
|
91
|
-
#
|
|
92
|
-
# @param [ Array | Mongoid::Document | Mongoid::Association::Proxy | HasMany::Enumerable ] target
|
|
93
|
-
# the target object to examine.
|
|
94
|
-
#
|
|
95
|
-
# @return [ Array<Mongoid::Document> ] the list of documents
|
|
96
|
-
def get_target_documents(target)
|
|
97
|
-
if target.respond_to?(:_loaded?)
|
|
98
|
-
get_target_documents_for_has_many(target)
|
|
99
|
-
else
|
|
100
|
-
get_target_documents_for_other(target)
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# Returns the list of all currently in-memory values held by
|
|
105
|
-
# the target. The target will not be loaded.
|
|
106
|
-
#
|
|
107
|
-
# @param [ HasMany::Enumerable ] target the target that will
|
|
108
|
-
# be examined for in-memory documents.
|
|
109
|
-
#
|
|
110
|
-
# @return [ Array<Mongoid::Document> ] the in-memory documents
|
|
111
|
-
# held by the target.
|
|
112
|
-
def get_target_documents_for_has_many(target)
|
|
113
|
-
[ *target._loaded.values, *target._added.values ]
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# Returns the target as an array. If the target represents a single
|
|
117
|
-
# value, it is wrapped in an array.
|
|
118
|
-
#
|
|
119
|
-
# @param [ Array | Mongoid::Document | Mongoid::Association::Proxy ] target
|
|
120
|
-
# the target to return.
|
|
121
|
-
#
|
|
122
|
-
# @return [ Array<Mongoid::Document> ] the target, as an array.
|
|
123
|
-
def get_target_documents_for_other(target)
|
|
124
|
-
Array.wrap(target)
|
|
43
|
+
document.errors.add(attribute, :invalid, **options) unless valid
|
|
125
44
|
end
|
|
126
45
|
end
|
|
127
46
|
end
|
|
@@ -18,7 +18,7 @@ module Mongoid
|
|
|
18
18
|
# validates_associated :name, :addresses
|
|
19
19
|
# end
|
|
20
20
|
#
|
|
21
|
-
# @param [
|
|
21
|
+
# @param [ Object... ] *args The arguments to pass to the validator.
|
|
22
22
|
def validates_associated(*args)
|
|
23
23
|
validates_with(AssociatedValidator, _merge_attributes(args))
|
|
24
24
|
end
|
|
@@ -35,7 +35,7 @@ module Mongoid
|
|
|
35
35
|
# validates_uniqueness_of :title
|
|
36
36
|
# end
|
|
37
37
|
#
|
|
38
|
-
# @param [
|
|
38
|
+
# @param [ Object... ] *args The arguments to pass to the validator.
|
|
39
39
|
def validates_uniqueness_of(*args)
|
|
40
40
|
validates_with(UniquenessValidator, _merge_attributes(args))
|
|
41
41
|
end
|
|
@@ -50,7 +50,7 @@ module Mongoid
|
|
|
50
50
|
# validates_format_of :title, with: /\A[a-z0-9 \-_]*\z/i
|
|
51
51
|
# end
|
|
52
52
|
#
|
|
53
|
-
# @param [
|
|
53
|
+
# @param [ Object... ] *args The names of the field(s) to validate.
|
|
54
54
|
def validates_format_of(*args)
|
|
55
55
|
validates_with(FormatValidator, _merge_attributes(args))
|
|
56
56
|
end
|
|
@@ -65,7 +65,7 @@ module Mongoid
|
|
|
65
65
|
# validates_length_of :title, minimum: 100
|
|
66
66
|
# end
|
|
67
67
|
#
|
|
68
|
-
# @param [
|
|
68
|
+
# @param [ Object... ] *args The names of the field(s) to validate.
|
|
69
69
|
def validates_length_of(*args)
|
|
70
70
|
validates_with(LengthValidator, _merge_attributes(args))
|
|
71
71
|
end
|
|
@@ -80,25 +80,10 @@ module Mongoid
|
|
|
80
80
|
# validates_presence_of :title
|
|
81
81
|
# end
|
|
82
82
|
#
|
|
83
|
-
# @param [
|
|
83
|
+
# @param [ Object... ] *args The names of the field(s) to validate.
|
|
84
84
|
def validates_presence_of(*args)
|
|
85
85
|
validates_with(PresenceValidator, _merge_attributes(args))
|
|
86
86
|
end
|
|
87
|
-
|
|
88
|
-
# Validates whether or not a field contains a numeric value.
|
|
89
|
-
#
|
|
90
|
-
# @example
|
|
91
|
-
# class Person
|
|
92
|
-
# include Mongoid::Document
|
|
93
|
-
# field :cost
|
|
94
|
-
#
|
|
95
|
-
# validates_numericality_of :cost
|
|
96
|
-
# end
|
|
97
|
-
#
|
|
98
|
-
# @param [ Object... ] *args The names of the field(s) to validate.
|
|
99
|
-
def validates_numericality_of(*args)
|
|
100
|
-
validates_with(NumericalityValidator, _merge_attributes(args))
|
|
101
|
-
end
|
|
102
87
|
end
|
|
103
88
|
end
|
|
104
89
|
end
|
data/lib/mongoid/validatable.rb
CHANGED
|
@@ -5,7 +5,6 @@ require "mongoid/validatable/localizable"
|
|
|
5
5
|
require "mongoid/validatable/associated"
|
|
6
6
|
require "mongoid/validatable/format"
|
|
7
7
|
require "mongoid/validatable/length"
|
|
8
|
-
require "mongoid/validatable/numericality"
|
|
9
8
|
require "mongoid/validatable/queryable"
|
|
10
9
|
require "mongoid/validatable/presence"
|
|
11
10
|
require "mongoid/validatable/uniqueness"
|
|
@@ -38,14 +37,6 @@ module Mongoid
|
|
|
38
37
|
Threaded.exit_validate(self)
|
|
39
38
|
end
|
|
40
39
|
|
|
41
|
-
# Perform a validation within the associated block.
|
|
42
|
-
def validating
|
|
43
|
-
begin_validate
|
|
44
|
-
yield
|
|
45
|
-
ensure
|
|
46
|
-
exit_validate
|
|
47
|
-
end
|
|
48
|
-
|
|
49
40
|
# Given the provided options, are we performing validations?
|
|
50
41
|
#
|
|
51
42
|
# @example Are we performing validations?
|
|
@@ -53,6 +44,8 @@ module Mongoid
|
|
|
53
44
|
#
|
|
54
45
|
# @param [ Hash ] options The options to check.
|
|
55
46
|
#
|
|
47
|
+
# @option options [ true | false ] :validate Whether or not to validate.
|
|
48
|
+
#
|
|
56
49
|
# @return [ true | false ] If we are validating.
|
|
57
50
|
def performing_validations?(options = {})
|
|
58
51
|
options[:validate].nil? ? true : options[:validate]
|
|
@@ -138,7 +131,8 @@ module Mongoid
|
|
|
138
131
|
# @example Validate with a specific validator.
|
|
139
132
|
# validates_with MyValidator, on: :create
|
|
140
133
|
#
|
|
141
|
-
# @param [
|
|
134
|
+
# @param [ ActiveModel::Validator..., Hash ] *args The validator classes
|
|
135
|
+
# and options hash.
|
|
142
136
|
#
|
|
143
137
|
# @note See ActiveModel::Validations::With for full options. This is
|
|
144
138
|
# overridden to add autosave functionality when presence validation is
|
data/lib/mongoid/version.rb
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Mongoid
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# Note that this file is automatically updated via `rake candidate:create`.
|
|
7
|
-
# Manual changes to this file will be overwritten by that rake task.
|
|
8
|
-
VERSION = '8.0.13'
|
|
4
|
+
VERSION = "8.1.0"
|
|
9
5
|
end
|
data/lib/mongoid/warnings.rb
CHANGED
|
@@ -23,7 +23,22 @@ module Mongoid
|
|
|
23
23
|
|
|
24
24
|
warning :geo_haystack_deprecated, 'The geoHaystack type is deprecated.'
|
|
25
25
|
warning :as_json_compact_deprecated, '#as_json :compact option is deprecated. Please call #compact on the returned Hash object instead.'
|
|
26
|
-
warning :symbol_type_deprecated, 'The BSON Symbol type is deprecated by MongoDB. Please use String or StringifiedSymbol field types instead of the Symbol field type'
|
|
27
|
-
warning :
|
|
26
|
+
warning :symbol_type_deprecated, 'The BSON Symbol type is deprecated by MongoDB. Please use String or StringifiedSymbol field types instead of the Symbol field type.'
|
|
27
|
+
warning :legacy_readonly, 'The readonly! method will only mark the document readonly when the legacy_readonly feature flag is switched off.'
|
|
28
|
+
warning :use_activesupport_time_zone_deprecated, 'Config option :use_activesupport_time_zone is deprecated and should be removed from your config. It will always be true beginning in Mongoid 9.0.'
|
|
29
|
+
warning :broken_aggregables_deprecated, 'Config option :broken_aggregables is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
30
|
+
warning :broken_alias_handling_deprecated, 'Config option :broken_alias_handling is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
31
|
+
warning :broken_and_deprecated, 'Config option :broken_and is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
32
|
+
warning :broken_scoping_deprecated, 'Config option :broken_scoping is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
33
|
+
warning :broken_updates_deprecated, 'Config option :broken_updates is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
34
|
+
warning :compare_time_by_ms_deprecated, 'Config option :compare_time_by_ms is deprecated. It will always be true beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
35
|
+
warning :legacy_attributes_deprecated, 'Config option :legacy_attributes is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
36
|
+
warning :legacy_pluck_distinct_deprecated, 'Config option :legacy_pluck_distinct is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
37
|
+
warning :legacy_triple_equals_deprecated, 'Config option :legacy_triple_equals is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
38
|
+
warning :object_id_as_json_oid_deprecated, 'Config option :object_id_as_json_oid is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
39
|
+
warning :overwrite_chained_operators_deprecated, 'Config option :overwrite_chained_operators is deprecated. It will always be false beginning in Mongoid 9.0. Please use load_defaults for Mongoid 8.0 or later, then remove it from your config.'
|
|
40
|
+
warning :mutable_ids, 'In Mongoid 9.0 the _id field will be immutable. In earlier versions of 8.x, mutating the _id field was supported inconsistently. Prepare your code for 9.0 by setting Mongoid::Config.immutable_ids to true.'
|
|
41
|
+
warning :mongoid_query_cache, 'In Mongoid 9.0, Mongoid::QueryCache will be removed. Please replace it with Mongo::QueryCache.'
|
|
42
|
+
warning :mongoid_query_cache_clear, 'In Mongoid 9.0, Mongoid::QueryCache#clear_cache should be replaced it with Mongo::QueryCache#clear.'
|
|
28
43
|
end
|
|
29
44
|
end
|
data/lib/mongoid.rb
CHANGED
|
@@ -12,8 +12,10 @@ require "active_support/inflector"
|
|
|
12
12
|
require "active_support/time_with_zone"
|
|
13
13
|
require "active_model"
|
|
14
14
|
|
|
15
|
+
require 'concurrent-ruby'
|
|
16
|
+
|
|
15
17
|
require "mongo"
|
|
16
|
-
require
|
|
18
|
+
require "mongo/active_support"
|
|
17
19
|
|
|
18
20
|
require "mongoid/version"
|
|
19
21
|
require "mongoid/deprecable"
|
|
@@ -25,6 +27,7 @@ require "mongoid/document"
|
|
|
25
27
|
require "mongoid/tasks/database"
|
|
26
28
|
require "mongoid/query_cache"
|
|
27
29
|
require "mongoid/warnings"
|
|
30
|
+
require "mongoid/utils"
|
|
28
31
|
|
|
29
32
|
# If we are using Rails then we will include the Mongoid railtie. This has all
|
|
30
33
|
# the nifty initializers that Mongoid needs.
|
|
@@ -58,9 +61,19 @@ module Mongoid
|
|
|
58
61
|
# }
|
|
59
62
|
# end
|
|
60
63
|
#
|
|
64
|
+
# @example Using a block without an argument. Use `config` inside
|
|
65
|
+
# the block to perform variable assignment.
|
|
66
|
+
#
|
|
67
|
+
# Mongoid.configure do
|
|
68
|
+
# connect_to("mongoid_test")
|
|
69
|
+
#
|
|
70
|
+
# config.preload_models = true
|
|
71
|
+
#
|
|
61
72
|
# @return [ Config ] The configuration object.
|
|
62
|
-
def configure
|
|
63
|
-
|
|
73
|
+
def configure(&block)
|
|
74
|
+
return Config unless block_given?
|
|
75
|
+
|
|
76
|
+
block.arity == 0 ? Config.instance_exec(&block) : yield(Config)
|
|
64
77
|
end
|
|
65
78
|
|
|
66
79
|
# Convenience method for getting the default client.
|
|
@@ -16,10 +16,6 @@ describe 'Mongoid application tests' do
|
|
|
16
16
|
skip 'Set APP_TESTS=1 in environment to run application tests'
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
if SpecConfig.instance.rails_version < '7.1'
|
|
20
|
-
skip 'App tests require Rails > 7.0 (see https://stackoverflow.com/questions/79360526)'
|
|
21
|
-
end
|
|
22
|
-
|
|
23
19
|
require 'fileutils'
|
|
24
20
|
require 'mrss/child_process_helper'
|
|
25
21
|
require 'open-uri'
|
|
@@ -91,12 +87,6 @@ describe 'Mongoid application tests' do
|
|
|
91
87
|
end
|
|
92
88
|
|
|
93
89
|
context 'new application - rails' do
|
|
94
|
-
before(:all) do
|
|
95
|
-
if SpecConfig.instance.rails_version < '7.1'
|
|
96
|
-
skip '`rails new` with rails < 7.1 fails because modern concurrent-ruby removed logger dependency'
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
90
|
it 'creates' do
|
|
101
91
|
install_rails
|
|
102
92
|
|
|
@@ -280,14 +270,6 @@ describe 'Mongoid application tests' do
|
|
|
280
270
|
line =~ /mongoid/
|
|
281
271
|
end
|
|
282
272
|
gemfile_lines << "gem 'mongoid', path: '#{File.expand_path(BASE)}'\n"
|
|
283
|
-
|
|
284
|
-
# json 3.0 removed the quirks_mode and max_nesting keywords that
|
|
285
|
-
# ActiveSupport::JSON (every 7.x) still passes to JSON.generate and
|
|
286
|
-
# JSON.parse, so a freshly resolved bundle picks a 3.x json and the app
|
|
287
|
-
# fails to encode any response with ArgumentError: unknown keyword:
|
|
288
|
-
# quirks_mode. Cap json at 2.x, which still accepts those keywords.
|
|
289
|
-
gemfile_lines << "gem 'json', '< 3'\n"
|
|
290
|
-
|
|
291
273
|
if rails_version
|
|
292
274
|
gemfile_lines.delete_if do |line|
|
|
293
275
|
line =~ /rails/
|
|
@@ -344,7 +326,7 @@ describe 'Mongoid application tests' do
|
|
|
344
326
|
end
|
|
345
327
|
|
|
346
328
|
def wait_for_port(port, timeout, process)
|
|
347
|
-
deadline =
|
|
329
|
+
deadline = Mongoid::Utils.monotonic_time + timeout
|
|
348
330
|
loop do
|
|
349
331
|
begin
|
|
350
332
|
Socket.tcp('localhost', port, nil, nil, connect_timeout: 0.5) do |socket|
|
|
@@ -354,7 +336,7 @@ describe 'Mongoid application tests' do
|
|
|
354
336
|
unless process.alive?
|
|
355
337
|
raise "Process #{process} died while waiting for port #{port}"
|
|
356
338
|
end
|
|
357
|
-
if
|
|
339
|
+
if Mongoid::Utils.monotonic_time > deadline
|
|
358
340
|
raise
|
|
359
341
|
end
|
|
360
342
|
end
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
describe 'embeds_one associations' do
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
context 're-associating the same object' do
|
|
7
8
|
context 'with dependent: destroy' do
|
|
8
9
|
let(:canvas) do
|
|
9
10
|
Canvas.create!(palette: Palette.new)
|
|
@@ -15,7 +16,7 @@ describe 'embeds_one associations' do
|
|
|
15
16
|
canvas.palette = canvas.palette
|
|
16
17
|
canvas.save!
|
|
17
18
|
canvas.reload
|
|
18
|
-
|
|
19
|
+
canvas.palette.should == palette
|
|
19
20
|
end
|
|
20
21
|
end
|
|
21
22
|
end
|
|
@@ -29,33 +30,12 @@ describe 'embeds_one associations' do
|
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
it 'loads the association correctly' do
|
|
32
|
-
expect { klass }.
|
|
33
|
-
expect { klass.new.address }.
|
|
33
|
+
expect { klass }.to_not raise_error
|
|
34
|
+
expect { klass.new.address }.to_not raise_error
|
|
34
35
|
instance = klass.new
|
|
35
36
|
address = Address.new
|
|
36
37
|
instance.address = address
|
|
37
38
|
expect(instance.address).to eq address
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
|
-
|
|
41
|
-
context 'when parent is persisted' do
|
|
42
|
-
let!(:person) do
|
|
43
|
-
Person.create!
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
context 'when assigning the new child' do
|
|
47
|
-
context 'when assigning an attribute to the child' do
|
|
48
|
-
before do
|
|
49
|
-
# person.reload
|
|
50
|
-
person.name = Name.new
|
|
51
|
-
person.name.first_name = 'Dmitry'
|
|
52
|
-
person.save!
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it 'persists the child' do
|
|
56
|
-
expect(person.reload.name.first_name).to eq 'Dmitry'
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
41
|
end
|
|
@@ -2,28 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
|
-
module HabtmSpec
|
|
6
|
-
class Page
|
|
7
|
-
include Mongoid::Document
|
|
8
|
-
embeds_many :blocks, class_name: 'HabtmSpec::Block'
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
class Block
|
|
12
|
-
include Mongoid::Document
|
|
13
|
-
embedded_in :page, class_name: 'HabtmSpec::Page'
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class ImageBlock < Block
|
|
17
|
-
has_and_belongs_to_many :attachments, inverse_of: nil, class_name: 'HabtmSpec::Attachment'
|
|
18
|
-
accepts_nested_attributes_for :attachments
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
class Attachment
|
|
22
|
-
include Mongoid::Document
|
|
23
|
-
field :file, type: String
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
5
|
describe 'has_and_belongs_to_many associations' do
|
|
28
6
|
|
|
29
7
|
context 'when an anonymous class defines a has_and_belongs_to_many association' do
|
|
@@ -40,37 +18,4 @@ describe 'has_and_belongs_to_many associations' do
|
|
|
40
18
|
expect(klass.new.movies.build).to be_a Movie
|
|
41
19
|
end
|
|
42
20
|
end
|
|
43
|
-
|
|
44
|
-
context 'when an embedded has habtm relation' do
|
|
45
|
-
let(:attachment) { HabtmSpec::Attachment.create!(file: 'foo.jpg') }
|
|
46
|
-
|
|
47
|
-
let(:page) { HabtmSpec::Page.create! }
|
|
48
|
-
|
|
49
|
-
let(:image_block) do
|
|
50
|
-
image_block = page.blocks.build({
|
|
51
|
-
_type: 'HabtmSpec::ImageBlock',
|
|
52
|
-
attachment_ids: [ attachment.id.to_s ],
|
|
53
|
-
attachments_attributes: { '1234' => { file: 'bar.jpg', id: attachment.id.to_s } }
|
|
54
|
-
})
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# The nested attributes are processed before the attachment_ids
|
|
58
|
-
# assignment is applied, so at that point the id is not yet in the
|
|
59
|
-
# association and resolving it requires a collection-wide lookup.
|
|
60
|
-
context 'when allow_reparenting_via_nested_attributes is false' do
|
|
61
|
-
config_override :allow_reparenting_via_nested_attributes, false
|
|
62
|
-
|
|
63
|
-
it 'raises a document not found error' do
|
|
64
|
-
expect { image_block.save! }.to raise_error(Mongoid::Errors::DocumentNotFound)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
context 'when allow_reparenting_via_nested_attributes is true' do
|
|
69
|
-
config_override :allow_reparenting_via_nested_attributes, true
|
|
70
|
-
|
|
71
|
-
it 'does not raise on save' do
|
|
72
|
-
expect { image_block.save! }.not_to raise_error
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
21
|
end
|