mongoid 7.5.1 → 8.1.4
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 +6 -6
- data/Rakefile +25 -0
- data/lib/config/locales/en.yml +92 -43
- data/lib/mongoid/association/accessors.rb +40 -11
- data/lib/mongoid/association/bindable.rb +50 -2
- data/lib/mongoid/association/builders.rb +5 -3
- data/lib/mongoid/association/constrainable.rb +0 -1
- data/lib/mongoid/association/eager_loadable.rb +29 -7
- data/lib/mongoid/association/embedded/batchable.rb +54 -14
- data/lib/mongoid/association/embedded/cyclic.rb +1 -1
- data/lib/mongoid/association/embedded/embedded_in/binding.rb +24 -2
- data/lib/mongoid/association/embedded/embedded_in/buildable.rb +2 -2
- data/lib/mongoid/association/embedded/embedded_in/proxy.rb +4 -3
- data/lib/mongoid/association/embedded/embedded_in.rb +3 -2
- data/lib/mongoid/association/embedded/embeds_many/binding.rb +1 -0
- data/lib/mongoid/association/embedded/embeds_many/buildable.rb +4 -3
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +85 -46
- data/lib/mongoid/association/embedded/embeds_many.rb +2 -2
- data/lib/mongoid/association/embedded/embeds_one/buildable.rb +19 -5
- data/lib/mongoid/association/embedded/embeds_one/proxy.rb +24 -5
- data/lib/mongoid/association/embedded/embeds_one.rb +3 -3
- data/lib/mongoid/association/macros.rb +8 -1
- data/lib/mongoid/association/many.rb +11 -7
- data/lib/mongoid/association/nested/many.rb +5 -4
- data/lib/mongoid/association/nested/nested_buildable.rb +4 -4
- data/lib/mongoid/association/nested/one.rb +45 -7
- data/lib/mongoid/association/one.rb +2 -2
- data/lib/mongoid/association/options.rb +9 -9
- data/lib/mongoid/association/proxy.rb +15 -4
- data/lib/mongoid/association/referenced/auto_save.rb +4 -3
- data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -0
- data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
- data/lib/mongoid/association/referenced/belongs_to/proxy.rb +5 -6
- data/lib/mongoid/association/referenced/belongs_to.rb +2 -2
- data/lib/mongoid/association/referenced/counter_cache.rb +10 -10
- data/lib/mongoid/association/referenced/eager.rb +2 -2
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +70 -13
- data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +6 -3
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +22 -30
- data/lib/mongoid/association/referenced/has_many/proxy.rb +40 -21
- data/lib/mongoid/association/referenced/has_many.rb +3 -3
- data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
- data/lib/mongoid/association/referenced/has_one/nested_builder.rb +5 -5
- data/lib/mongoid/association/referenced/has_one/proxy.rb +9 -12
- data/lib/mongoid/association/referenced/has_one.rb +3 -3
- data/lib/mongoid/association/referenced/syncable.rb +4 -4
- data/lib/mongoid/association/reflections.rb +4 -4
- data/lib/mongoid/association/relatable.rb +44 -10
- data/lib/mongoid/association.rb +5 -5
- data/lib/mongoid/atomic/modifiers.rb +2 -2
- data/lib/mongoid/atomic/paths/embedded/many.rb +19 -0
- data/lib/mongoid/atomic.rb +7 -0
- data/lib/mongoid/attributes/dynamic.rb +4 -4
- data/lib/mongoid/attributes/nested.rb +6 -6
- data/lib/mongoid/attributes/processing.rb +37 -6
- data/lib/mongoid/attributes/projector.rb +2 -2
- data/lib/mongoid/attributes/readonly.rb +3 -3
- data/lib/mongoid/attributes.rb +51 -42
- data/lib/mongoid/cacheable.rb +2 -2
- data/lib/mongoid/changeable.rb +147 -14
- data/lib/mongoid/clients/options.rb +5 -1
- data/lib/mongoid/clients/sessions.rb +2 -14
- data/lib/mongoid/clients/storage_options.rb +2 -5
- data/lib/mongoid/clients/validators/storage.rb +3 -15
- 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 +3 -0
- data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
- data/lib/mongoid/config/validators/client.rb +6 -6
- data/lib/mongoid/config/validators.rb +1 -0
- data/lib/mongoid/config.rb +158 -17
- data/lib/mongoid/contextual/aggregable/memory.rb +24 -16
- data/lib/mongoid/contextual/aggregable/mongo.rb +5 -5
- data/lib/mongoid/contextual/aggregable/none.rb +1 -1
- data/lib/mongoid/contextual/atomic.rb +1 -1
- data/lib/mongoid/contextual/geo_near.rb +7 -7
- data/lib/mongoid/contextual/map_reduce.rb +2 -2
- data/lib/mongoid/contextual/memory.rb +285 -58
- data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
- data/lib/mongoid/contextual/mongo.rb +544 -333
- data/lib/mongoid/contextual/none.rb +193 -20
- data/lib/mongoid/contextual/queryable.rb +1 -1
- data/lib/mongoid/contextual.rb +14 -2
- data/lib/mongoid/copyable.rb +32 -8
- data/lib/mongoid/criteria/findable.rb +8 -5
- data/lib/mongoid/criteria/includable.rb +27 -22
- data/lib/mongoid/criteria/marshalable.rb +10 -2
- data/lib/mongoid/criteria/permission.rb +1 -1
- data/lib/mongoid/criteria/queryable/aggregable.rb +2 -2
- data/lib/mongoid/criteria/queryable/extensions/array.rb +3 -16
- data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +25 -4
- data/lib/mongoid/criteria/queryable/extensions/boolean.rb +2 -2
- data/lib/mongoid/criteria/queryable/extensions/date.rb +6 -1
- data/lib/mongoid/criteria/queryable/extensions/date_time.rb +6 -1
- data/lib/mongoid/criteria/queryable/extensions/hash.rb +1 -17
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -9
- data/lib/mongoid/criteria/queryable/extensions/object.rb +2 -1
- data/lib/mongoid/criteria/queryable/extensions/range.rb +13 -5
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
- data/lib/mongoid/criteria/queryable/extensions/set.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/string.rb +4 -14
- data/lib/mongoid/criteria/queryable/extensions/symbol.rb +4 -12
- data/lib/mongoid/criteria/queryable/extensions/time.rb +6 -1
- data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +6 -1
- data/lib/mongoid/criteria/queryable/key.rb +4 -4
- data/lib/mongoid/criteria/queryable/mergeable.rb +1 -1
- data/lib/mongoid/criteria/queryable/optional.rb +11 -17
- data/lib/mongoid/criteria/queryable/options.rb +2 -2
- data/lib/mongoid/criteria/queryable/pipeline.rb +1 -1
- data/lib/mongoid/criteria/queryable/selectable.rb +47 -38
- data/lib/mongoid/criteria/queryable/selector.rb +93 -8
- data/lib/mongoid/criteria/queryable/smash.rb +40 -7
- data/lib/mongoid/criteria/queryable/storable.rb +1 -1
- data/lib/mongoid/criteria/queryable.rb +12 -7
- data/lib/mongoid/criteria/scopable.rb +2 -2
- data/lib/mongoid/criteria/translator.rb +45 -0
- data/lib/mongoid/criteria.rb +20 -40
- data/lib/mongoid/deprecable.rb +37 -0
- data/lib/mongoid/deprecation.rb +25 -0
- data/lib/mongoid/document.rb +135 -36
- data/lib/mongoid/equality.rb +8 -8
- data/lib/mongoid/errors/create_collection_failure.rb +33 -0
- data/lib/mongoid/errors/document_not_found.rb +10 -6
- 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_config_option.rb +1 -1
- data/lib/mongoid/errors/invalid_dependent_strategy.rb +1 -1
- data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
- data/lib/mongoid/errors/invalid_field.rb +6 -2
- data/lib/mongoid/errors/invalid_field_type.rb +26 -0
- data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
- data/lib/mongoid/errors/invalid_relation.rb +1 -1
- data/lib/mongoid/errors/invalid_relation_option.rb +1 -1
- data/lib/mongoid/errors/invalid_session_use.rb +1 -1
- data/lib/mongoid/errors/invalid_storage_options.rb +1 -1
- data/lib/mongoid/errors/invalid_storage_parent.rb +2 -0
- data/lib/mongoid/errors/mongoid_error.rb +3 -3
- data/lib/mongoid/errors/nested_attributes_metadata_not_found.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/readonly_attribute.rb +1 -1
- data/lib/mongoid/errors/too_many_nested_attribute_records.rb +1 -1
- data/lib/mongoid/errors/unknown_attribute.rb +1 -1
- data/lib/mongoid/errors.rb +6 -3
- data/lib/mongoid/extensions/array.rb +9 -7
- data/lib/mongoid/extensions/big_decimal.rb +33 -10
- data/lib/mongoid/extensions/binary.rb +42 -0
- data/lib/mongoid/extensions/boolean.rb +8 -2
- data/lib/mongoid/extensions/date.rb +26 -20
- data/lib/mongoid/extensions/date_time.rb +1 -1
- data/lib/mongoid/extensions/false_class.rb +1 -1
- data/lib/mongoid/extensions/float.rb +7 -4
- data/lib/mongoid/extensions/hash.rb +37 -8
- data/lib/mongoid/extensions/integer.rb +7 -4
- data/lib/mongoid/extensions/module.rb +1 -1
- data/lib/mongoid/extensions/object.rb +10 -8
- data/lib/mongoid/extensions/range.rb +41 -10
- data/lib/mongoid/extensions/regexp.rb +11 -4
- data/lib/mongoid/extensions/set.rb +11 -4
- data/lib/mongoid/extensions/string.rb +11 -22
- data/lib/mongoid/extensions/symbol.rb +4 -15
- data/lib/mongoid/extensions/time.rb +29 -16
- data/lib/mongoid/extensions/time_with_zone.rb +1 -2
- data/lib/mongoid/extensions/true_class.rb +1 -1
- data/lib/mongoid/extensions.rb +1 -0
- data/lib/mongoid/factory.rb +55 -7
- data/lib/mongoid/fields/foreign_key.rb +11 -4
- data/lib/mongoid/fields/localized.rb +19 -4
- data/lib/mongoid/fields/standard.rb +17 -7
- data/lib/mongoid/fields/validators/macro.rb +3 -9
- data/lib/mongoid/fields.rb +129 -20
- data/lib/mongoid/findable.rb +54 -24
- data/lib/mongoid/indexable/specification.rb +2 -2
- data/lib/mongoid/indexable/validators/options.rb +6 -2
- data/lib/mongoid/interceptable.rb +186 -16
- data/lib/mongoid/matchable.rb +1 -1
- data/lib/mongoid/matcher/eq_impl.rb +1 -1
- data/lib/mongoid/matcher/type.rb +1 -1
- data/lib/mongoid/matcher.rb +33 -13
- data/lib/mongoid/persistable/creatable.rb +19 -9
- data/lib/mongoid/persistable/deletable.rb +2 -2
- data/lib/mongoid/persistable/destroyable.rb +1 -1
- data/lib/mongoid/persistable/savable.rb +14 -2
- data/lib/mongoid/persistable/unsettable.rb +2 -2
- data/lib/mongoid/persistable/updatable.rb +69 -12
- data/lib/mongoid/persistable/upsertable.rb +21 -2
- data/lib/mongoid/persistable.rb +6 -3
- data/lib/mongoid/persistence_context.rb +63 -10
- data/lib/mongoid/query_cache.rb +13 -261
- data/lib/mongoid/railties/controller_runtime.rb +1 -1
- data/lib/mongoid/railties/database.rake +7 -2
- data/lib/mongoid/reloadable.rb +10 -8
- data/lib/mongoid/scopable.rb +15 -13
- data/lib/mongoid/selectable.rb +1 -2
- data/lib/mongoid/serializable.rb +10 -6
- data/lib/mongoid/shardable.rb +35 -11
- data/lib/mongoid/stateful.rb +57 -10
- data/lib/mongoid/tasks/database.rake +12 -0
- data/lib/mongoid/tasks/database.rb +20 -2
- data/lib/mongoid/threaded/lifecycle.rb +5 -5
- data/lib/mongoid/threaded.rb +42 -12
- data/lib/mongoid/timestamps/created.rb +1 -1
- data/lib/mongoid/timestamps/updated.rb +2 -2
- data/lib/mongoid/touchable.rb +2 -3
- data/lib/mongoid/traversable.rb +5 -4
- data/lib/mongoid/utils.rb +22 -0
- data/lib/mongoid/validatable/localizable.rb +1 -1
- data/lib/mongoid/validatable/macros.rb +5 -7
- data/lib/mongoid/validatable/presence.rb +2 -2
- data/lib/mongoid/validatable/uniqueness.rb +9 -8
- data/lib/mongoid/validatable.rb +9 -6
- data/lib/mongoid/version.rb +1 -1
- data/lib/mongoid/warnings.rb +19 -4
- data/lib/mongoid.rb +17 -3
- data/spec/config/mongoid.yml +16 -0
- data/spec/integration/app_spec.rb +10 -14
- data/spec/integration/associations/belongs_to_spec.rb +18 -0
- data/spec/integration/associations/embedded_spec.rb +15 -0
- data/spec/integration/associations/embeds_many_spec.rb +15 -2
- data/spec/integration/associations/embeds_one_spec.rb +18 -0
- data/spec/integration/associations/foreign_key_spec.rb +9 -0
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
- data/spec/integration/associations/has_one_spec.rb +97 -1
- data/spec/integration/associations/scope_option_spec.rb +1 -1
- data/spec/integration/callbacks_models.rb +132 -1
- data/spec/integration/callbacks_spec.rb +381 -4
- data/spec/integration/criteria/range_spec.rb +95 -1
- data/spec/integration/discriminator_key_spec.rb +118 -80
- data/spec/integration/dots_and_dollars_spec.rb +277 -0
- data/spec/integration/i18n_fallbacks_spec.rb +3 -32
- data/spec/integration/matcher_examples_spec.rb +20 -13
- data/spec/integration/matcher_operator_data/type_decimal.yml +3 -2
- data/spec/integration/matcher_operator_spec.rb +3 -5
- data/spec/integration/persistence/range_field_spec.rb +350 -0
- data/spec/mongoid/association/counter_cache_spec.rb +1 -1
- data/spec/mongoid/association/depending_spec.rb +9 -9
- data/spec/mongoid/association/eager_spec.rb +2 -1
- data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +2 -1
- data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +54 -0
- data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +96 -9
- data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +112 -0
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +311 -65
- data/spec/mongoid/association/embedded/embeds_many_models.rb +158 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +12 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +68 -0
- data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +25 -0
- data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +15 -2
- data/spec/mongoid/association/embedded/embeds_one_models.rb +19 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +28 -0
- data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +2 -1
- data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +54 -0
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +15 -0
- data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +4 -20
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +215 -228
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +25 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +35 -2
- data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +109 -0
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +2 -56
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +235 -177
- data/spec/mongoid/association/referenced/has_many_models.rb +3 -1
- data/spec/mongoid/association/referenced/has_many_spec.rb +25 -0
- data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +2 -2
- data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +107 -1
- data/spec/mongoid/association/referenced/has_one_models.rb +16 -0
- data/spec/mongoid/association/syncable_spec.rb +15 -1
- data/spec/mongoid/atomic/paths_spec.rb +0 -14
- data/spec/mongoid/attributes/nested_spec.rb +80 -11
- data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
- data/spec/mongoid/attributes/projector_spec.rb +1 -5
- data/spec/mongoid/attributes_spec.rb +554 -33
- data/spec/mongoid/cacheable_spec.rb +3 -3
- data/spec/mongoid/changeable_spec.rb +429 -37
- data/spec/mongoid/clients/factory_spec.rb +23 -30
- data/spec/mongoid/clients/sessions_spec.rb +0 -38
- data/spec/mongoid/clients_spec.rb +179 -15
- data/spec/mongoid/collection_configurable_spec.rb +158 -0
- data/spec/mongoid/config/defaults_spec.rb +160 -0
- data/spec/mongoid/config_spec.rb +220 -30
- data/spec/mongoid/contextual/aggregable/memory_spec.rb +396 -158
- data/spec/mongoid/contextual/aggregable/memory_table.yml +88 -0
- data/spec/mongoid/contextual/aggregable/memory_table_spec.rb +62 -0
- data/spec/mongoid/contextual/map_reduce_spec.rb +2 -16
- data/spec/mongoid/contextual/memory_spec.rb +850 -88
- data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
- data/spec/mongoid/contextual/mongo_spec.rb +2307 -1105
- data/spec/mongoid/contextual/none_spec.rb +60 -21
- data/spec/mongoid/copyable_spec.rb +453 -11
- data/spec/mongoid/criteria/findable_spec.rb +86 -210
- data/spec/mongoid/criteria/includable_spec.rb +1492 -0
- data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
- data/spec/mongoid/criteria/marshalable_spec.rb +18 -1
- data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +7 -19
- data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +134 -26
- data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +11 -0
- data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +11 -0
- data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +0 -15
- data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +73 -7
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +4 -69
- data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +0 -59
- data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +11 -0
- data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +11 -0
- data/spec/mongoid/criteria/queryable/optional_spec.rb +15 -484
- data/spec/mongoid/criteria/queryable/options_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +469 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +78 -86
- data/spec/mongoid/criteria/queryable/selector_spec.rb +90 -5
- data/spec/mongoid/criteria/queryable/storable_spec.rb +72 -0
- data/spec/mongoid/criteria/translator_spec.rb +132 -0
- data/spec/mongoid/criteria_projection_spec.rb +1 -5
- data/spec/mongoid/criteria_spec.rb +469 -1205
- data/spec/mongoid/document_fields_spec.rb +173 -24
- data/spec/mongoid/document_spec.rb +32 -41
- data/spec/mongoid/errors/document_not_found_spec.rb +29 -2
- data/spec/mongoid/errors/invalid_field_spec.rb +1 -1
- data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
- data/spec/mongoid/errors/mongoid_error_spec.rb +3 -1
- data/spec/mongoid/errors/no_environment_spec.rb +3 -3
- data/spec/mongoid/errors/readonly_document_spec.rb +2 -2
- data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +1 -1
- data/spec/mongoid/extensions/array_spec.rb +16 -2
- data/spec/mongoid/extensions/big_decimal_spec.rb +712 -212
- data/spec/mongoid/extensions/binary_spec.rb +44 -9
- data/spec/mongoid/extensions/boolean_spec.rb +68 -82
- data/spec/mongoid/extensions/date_class_mongoize_spec.rb +7 -3
- data/spec/mongoid/extensions/date_spec.rb +71 -1
- data/spec/mongoid/extensions/date_time_spec.rb +15 -9
- data/spec/mongoid/extensions/float_spec.rb +53 -74
- data/spec/mongoid/extensions/hash_spec.rb +33 -3
- data/spec/mongoid/extensions/integer_spec.rb +50 -64
- data/spec/mongoid/extensions/range_spec.rb +255 -54
- data/spec/mongoid/extensions/regexp_spec.rb +58 -33
- data/spec/mongoid/extensions/set_spec.rb +106 -0
- data/spec/mongoid/extensions/string_spec.rb +53 -25
- data/spec/mongoid/extensions/symbol_spec.rb +18 -25
- data/spec/mongoid/extensions/time_spec.rb +639 -106
- data/spec/mongoid/extensions/time_with_zone_spec.rb +24 -83
- data/spec/mongoid/factory_spec.rb +61 -1
- data/spec/mongoid/fields/localized_spec.rb +80 -37
- data/spec/mongoid/fields_spec.rb +500 -84
- data/spec/mongoid/findable_spec.rb +450 -58
- data/spec/mongoid/indexable/specification_spec.rb +2 -2
- data/spec/mongoid/indexable_spec.rb +55 -30
- data/spec/mongoid/interceptable_spec.rb +824 -22
- data/spec/mongoid/interceptable_spec_models.rb +235 -4
- data/spec/mongoid/matcher/extract_attribute_spec.rb +1 -5
- data/spec/mongoid/mongoizable_spec.rb +285 -0
- data/spec/mongoid/persistable/creatable_spec.rb +2 -2
- data/spec/mongoid/persistable/deletable_spec.rb +28 -8
- data/spec/mongoid/persistable/destroyable_spec.rb +28 -8
- 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 +89 -1
- data/spec/mongoid/persistence_context_spec.rb +57 -58
- data/spec/mongoid/query_cache_middleware_spec.rb +0 -18
- data/spec/mongoid/query_cache_spec.rb +56 -215
- data/spec/mongoid/reloadable_spec.rb +83 -6
- data/spec/mongoid/scopable_spec.rb +91 -1
- data/spec/mongoid/serializable_spec.rb +9 -30
- data/spec/mongoid/shardable_models.rb +14 -0
- data/spec/mongoid/shardable_spec.rb +157 -51
- data/spec/mongoid/stateful_spec.rb +150 -8
- data/spec/mongoid/tasks/database_rake_spec.rb +74 -0
- data/spec/mongoid/tasks/database_spec.rb +127 -0
- data/spec/mongoid/timestamps_spec.rb +392 -4
- data/spec/mongoid/timestamps_spec_models.rb +67 -0
- data/spec/mongoid/touchable_spec.rb +390 -2
- data/spec/mongoid/touchable_spec_models.rb +14 -8
- data/spec/mongoid/traversable_spec.rb +13 -35
- data/spec/mongoid/validatable/presence_spec.rb +1 -1
- data/spec/mongoid/validatable/uniqueness_spec.rb +58 -31
- data/spec/mongoid/warnings_spec.rb +35 -0
- data/spec/mongoid_spec.rb +34 -10
- data/spec/rails/controller_extension/controller_runtime_spec.rb +2 -2
- data/spec/rails/mongoid_spec.rb +4 -16
- data/spec/shared/lib/mrss/docker_runner.rb +8 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +10 -2
- data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
- data/spec/shared/lib/mrss/utils.rb +28 -6
- data/spec/shared/share/Dockerfile.erb +36 -40
- data/spec/shared/shlib/server.sh +32 -8
- data/spec/shared/shlib/set_env.sh +4 -4
- data/spec/spec_helper.rb +5 -0
- data/spec/support/constraints.rb +24 -0
- data/spec/support/immutable_ids.rb +118 -0
- data/spec/support/macros.rb +78 -0
- data/spec/support/models/artist.rb +0 -1
- data/spec/support/models/augmentation.rb +12 -0
- data/spec/support/models/band.rb +4 -0
- data/spec/support/models/book.rb +1 -0
- data/spec/support/models/building.rb +2 -0
- data/spec/support/models/catalog.rb +24 -0
- data/spec/support/models/circus.rb +3 -0
- data/spec/support/models/cover.rb +10 -0
- data/spec/support/models/fanatic.rb +8 -0
- data/spec/support/models/implant.rb +9 -0
- data/spec/support/models/label.rb +2 -0
- data/spec/support/models/passport.rb +9 -0
- data/spec/support/models/person.rb +2 -0
- data/spec/support/models/player.rb +2 -0
- data/spec/support/models/powerup.rb +12 -0
- data/spec/support/models/product.rb +1 -0
- data/spec/support/models/purse.rb +9 -0
- data/spec/support/models/registry.rb +1 -0
- data/spec/support/models/school.rb +14 -0
- data/spec/support/models/shield.rb +18 -0
- data/spec/support/models/student.rb +14 -0
- data/spec/support/models/weapon.rb +12 -0
- data.tar.gz.sig +0 -0
- metadata +722 -640
- metadata.gz.sig +0 -0
- data/lib/mongoid/errors/eager_load.rb +0 -23
- data/lib/mongoid/errors/invalid_value.rb +0 -17
- data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -60
- data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -60
- data/spec/mongoid/errors/eager_load_spec.rb +0 -31
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "mongoid/contextual/mongo/documents_loader"
|
|
3
4
|
require "mongoid/contextual/atomic"
|
|
4
5
|
require "mongoid/contextual/aggregable/mongo"
|
|
5
6
|
require "mongoid/contextual/command"
|
|
@@ -17,6 +18,8 @@ module Mongoid
|
|
|
17
18
|
include Association::EagerLoadable
|
|
18
19
|
include Queryable
|
|
19
20
|
|
|
21
|
+
Mongoid.deprecate(self, :geo_near)
|
|
22
|
+
|
|
20
23
|
# Options constant.
|
|
21
24
|
OPTIONS = [ :hint,
|
|
22
25
|
:limit,
|
|
@@ -35,16 +38,17 @@ module Mongoid
|
|
|
35
38
|
# @attribute [r] view The Mongo collection view.
|
|
36
39
|
attr_reader :view
|
|
37
40
|
|
|
38
|
-
#
|
|
41
|
+
# Run an explain on the criteria.
|
|
42
|
+
#
|
|
43
|
+
# @example Explain the criteria.
|
|
44
|
+
# Band.where(name: "Depeche Mode").explain
|
|
39
45
|
#
|
|
40
|
-
# @
|
|
41
|
-
# context.cached?
|
|
46
|
+
# @param [ Hash ] options customizable options (See Mongo::Collection::View::Explainable)
|
|
42
47
|
#
|
|
43
|
-
# @return [
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
end
|
|
48
|
+
# @return [ Hash ] The explain result.
|
|
49
|
+
def_delegator :view, :explain
|
|
50
|
+
|
|
51
|
+
attr_reader :documents_loader
|
|
48
52
|
|
|
49
53
|
# Get the number of documents matching the query.
|
|
50
54
|
#
|
|
@@ -65,7 +69,12 @@ module Mongoid
|
|
|
65
69
|
# @return [ Integer ] The number of matches.
|
|
66
70
|
def count(options = {}, &block)
|
|
67
71
|
return super(&block) if block_given?
|
|
68
|
-
|
|
72
|
+
|
|
73
|
+
if valid_for_count_documents?
|
|
74
|
+
view.count_documents(options)
|
|
75
|
+
else
|
|
76
|
+
view.count(options)
|
|
77
|
+
end
|
|
69
78
|
end
|
|
70
79
|
|
|
71
80
|
# Get the estimated number of documents matching the query.
|
|
@@ -84,7 +93,7 @@ module Mongoid
|
|
|
84
93
|
unless self.criteria.selector.empty?
|
|
85
94
|
raise Mongoid::Errors::InvalidEstimatedCountCriteria.new(self.klass)
|
|
86
95
|
end
|
|
87
|
-
|
|
96
|
+
view.estimated_document_count(options)
|
|
88
97
|
end
|
|
89
98
|
|
|
90
99
|
# Delete all documents in the database that match the selector.
|
|
@@ -118,7 +127,7 @@ module Mongoid
|
|
|
118
127
|
# @example Get the distinct values.
|
|
119
128
|
# context.distinct(:name)
|
|
120
129
|
#
|
|
121
|
-
# @param [ String
|
|
130
|
+
# @param [ String | Symbol ] field The name of the field.
|
|
122
131
|
#
|
|
123
132
|
# @return [ Array<Object> ] The distinct values for the field.
|
|
124
133
|
def distinct(field)
|
|
@@ -152,7 +161,6 @@ module Mongoid
|
|
|
152
161
|
documents_for_iteration.each do |doc|
|
|
153
162
|
yield_document(doc, &block)
|
|
154
163
|
end
|
|
155
|
-
@cache_loaded = true
|
|
156
164
|
self
|
|
157
165
|
else
|
|
158
166
|
to_enum
|
|
@@ -164,28 +172,28 @@ module Mongoid
|
|
|
164
172
|
# @example Do any documents exist for the context.
|
|
165
173
|
# context.exists?
|
|
166
174
|
#
|
|
167
|
-
# @
|
|
168
|
-
#
|
|
169
|
-
# used to determine the value.
|
|
175
|
+
# @example Do any documents exist for given _id.
|
|
176
|
+
# context.exists?(BSON::ObjectId(...))
|
|
170
177
|
#
|
|
171
|
-
# @
|
|
172
|
-
|
|
173
|
-
return !documents.empty? if cached? && cache_loaded?
|
|
174
|
-
return @count > 0 if instance_variable_defined?(:@count)
|
|
175
|
-
|
|
176
|
-
try_cache(:exists) do
|
|
177
|
-
!!(view.projection(_id: 1).limit(1).first)
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
# Run an explain on the criteria.
|
|
178
|
+
# @example Do any documents exist for given conditions.
|
|
179
|
+
# context.exists?(name: "...")
|
|
182
180
|
#
|
|
183
|
-
# @
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
# @
|
|
187
|
-
|
|
188
|
-
|
|
181
|
+
# @note We don't use count here since Mongo does not use counted
|
|
182
|
+
# b-tree indexes.
|
|
183
|
+
#
|
|
184
|
+
# @param [ Hash | Object | false ] id_or_conditions an _id to
|
|
185
|
+
# search for, a hash of conditions, nil or false.
|
|
186
|
+
#
|
|
187
|
+
# @return [ true | false ] If the count is more than zero.
|
|
188
|
+
# Always false if passed nil or false.
|
|
189
|
+
def exists?(id_or_conditions = :none)
|
|
190
|
+
return false if self.view.limit == 0
|
|
191
|
+
case id_or_conditions
|
|
192
|
+
when :none then !!(view.projection(_id: 1).limit(1).first)
|
|
193
|
+
when nil, false then false
|
|
194
|
+
when Hash then Mongo.new(criteria.where(id_or_conditions)).exists?
|
|
195
|
+
else Mongo.new(criteria.where(_id: id_or_conditions)).exists?
|
|
196
|
+
end
|
|
189
197
|
end
|
|
190
198
|
|
|
191
199
|
# Execute the find and modify command, used for MongoDB's
|
|
@@ -197,9 +205,9 @@ module Mongoid
|
|
|
197
205
|
# @param [ Hash ] update The updates.
|
|
198
206
|
# @param [ Hash ] options The command options.
|
|
199
207
|
#
|
|
200
|
-
# @option options [ :before
|
|
208
|
+
# @option options [ :before | :after ] :return_document Return the updated document
|
|
201
209
|
# from before or after update.
|
|
202
|
-
# @option options [ true
|
|
210
|
+
# @option options [ true | false ] :upsert Create the document if it doesn't exist.
|
|
203
211
|
#
|
|
204
212
|
# @return [ Document ] The result of the command.
|
|
205
213
|
def find_one_and_update(update, options = {})
|
|
@@ -217,9 +225,9 @@ module Mongoid
|
|
|
217
225
|
# @param [ Hash ] replacement The replacement.
|
|
218
226
|
# @param [ Hash ] options The command options.
|
|
219
227
|
#
|
|
220
|
-
# @option options [ :before
|
|
228
|
+
# @option options [ :before | :after ] :return_document Return the updated document
|
|
221
229
|
# from before or after update.
|
|
222
|
-
# @option options [ true
|
|
230
|
+
# @option options [ true | false ] :upsert Create the document if it doesn't exist.
|
|
223
231
|
#
|
|
224
232
|
# @return [ Document ] The result of the command.
|
|
225
233
|
def find_one_and_replace(replacement, options = {})
|
|
@@ -241,49 +249,10 @@ module Mongoid
|
|
|
241
249
|
end
|
|
242
250
|
end
|
|
243
251
|
|
|
244
|
-
# Get the first document in the database for the criteria's selector.
|
|
245
|
-
#
|
|
246
|
-
# @example Get the first document.
|
|
247
|
-
# context.first
|
|
248
|
-
#
|
|
249
|
-
# @note Automatically adding a sort on _id when no other sort is
|
|
250
|
-
# defined on the criteria has the potential to cause bad performance issues.
|
|
251
|
-
# If you experience unexpected poor performance when using #first or #last
|
|
252
|
-
# and have no sort defined on the criteria, use the option { id_sort: :none }.
|
|
253
|
-
# Be aware that #first/#last won't guarantee order in this case.
|
|
254
|
-
#
|
|
255
|
-
# @param [ Integer | Hash ] limit_or_opts The number of documents to
|
|
256
|
-
# return, or a hash of options.
|
|
257
|
-
#
|
|
258
|
-
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
|
|
259
|
-
# Don't apply a sort on _id if no other sort is defined on the criteria.
|
|
260
|
-
#
|
|
261
|
-
# @return [ Document ] The first document.
|
|
262
|
-
def first(limit_or_opts = nil)
|
|
263
|
-
limit = limit_or_opts unless limit_or_opts.is_a?(Hash)
|
|
264
|
-
if cached? && cache_loaded?
|
|
265
|
-
return limit ? documents.first(limit) : documents.first
|
|
266
|
-
end
|
|
267
|
-
try_numbered_cache(:first, limit) do
|
|
268
|
-
if limit_or_opts.try(:key?, :id_sort)
|
|
269
|
-
Mongoid::Warnings.warn_id_sort_deprecated
|
|
270
|
-
end
|
|
271
|
-
sorted_view = view
|
|
272
|
-
if sort = view.sort || ({ _id: 1 } unless limit_or_opts.try(:fetch, :id_sort) == :none)
|
|
273
|
-
sorted_view = view.sort(sort)
|
|
274
|
-
end
|
|
275
|
-
if raw_docs = sorted_view.limit(limit || 1).to_a
|
|
276
|
-
process_raw_docs(raw_docs, limit)
|
|
277
|
-
end
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
alias :one :first
|
|
281
|
-
|
|
282
252
|
# Return the first result without applying sort
|
|
283
253
|
#
|
|
284
254
|
# @api private
|
|
285
255
|
def find_first
|
|
286
|
-
return documents.first if cached? && cache_loaded?
|
|
287
256
|
if raw_doc = view.first
|
|
288
257
|
doc = Factory.from_db(klass, raw_doc, criteria)
|
|
289
258
|
eager_load([doc]).first
|
|
@@ -313,33 +282,6 @@ module Mongoid
|
|
|
313
282
|
GeoNear.new(collection, criteria, coordinates)
|
|
314
283
|
end
|
|
315
284
|
|
|
316
|
-
# Invoke the block for each element of Contextual. Create a new array
|
|
317
|
-
# containing the values returned by the block.
|
|
318
|
-
#
|
|
319
|
-
# If the symbol field name is passed instead of the block, additional
|
|
320
|
-
# optimizations would be used.
|
|
321
|
-
#
|
|
322
|
-
# @example Map by some field.
|
|
323
|
-
# context.map(:field1)
|
|
324
|
-
#
|
|
325
|
-
# @example Map with block.
|
|
326
|
-
# context.map(&:field1)
|
|
327
|
-
#
|
|
328
|
-
# @param [ Symbol ] field The field name.
|
|
329
|
-
#
|
|
330
|
-
# @return [ Array ] The result of mapping.
|
|
331
|
-
def map(field = nil, &block)
|
|
332
|
-
if !field.nil?
|
|
333
|
-
Mongoid::Warnings.warn_map_field_deprecated
|
|
334
|
-
end
|
|
335
|
-
|
|
336
|
-
if block_given?
|
|
337
|
-
super(&block)
|
|
338
|
-
else
|
|
339
|
-
criteria.pluck(field)
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
|
|
343
285
|
# Create the new Mongo context. This delegates operations to the
|
|
344
286
|
# underlying driver.
|
|
345
287
|
#
|
|
@@ -348,7 +290,7 @@ module Mongoid
|
|
|
348
290
|
#
|
|
349
291
|
# @param [ Criteria ] criteria The criteria.
|
|
350
292
|
def initialize(criteria)
|
|
351
|
-
@criteria, @klass
|
|
293
|
+
@criteria, @klass = criteria, criteria.klass
|
|
352
294
|
@collection = @klass.collection
|
|
353
295
|
criteria.send(:merge_type_selection)
|
|
354
296
|
@view = collection.find(criteria.selector, session: _session)
|
|
@@ -357,47 +299,15 @@ module Mongoid
|
|
|
357
299
|
|
|
358
300
|
def_delegator :@klass, :database_field_name
|
|
359
301
|
|
|
360
|
-
#
|
|
361
|
-
#
|
|
362
|
-
# @example Get the last document.
|
|
363
|
-
# context.last
|
|
364
|
-
#
|
|
365
|
-
# @note Automatically adding a sort on _id when no other sort is
|
|
366
|
-
# defined on the criteria has the potential to cause bad performance issues.
|
|
367
|
-
# If you experience unexpected poor performance when using #first or #last
|
|
368
|
-
# and have no sort defined on the criteria, use the option { id_sort: :none }.
|
|
369
|
-
# Be aware that #first/#last won't guarantee order in this case.
|
|
370
|
-
#
|
|
371
|
-
# @param [ Integer | Hash ] limit_or_opts The number of documents to
|
|
372
|
-
# return, or a hash of options.
|
|
373
|
-
#
|
|
374
|
-
# @option limit_or_opts [ :none ] :id_sort This option is deprecated.
|
|
375
|
-
# Don't apply a sort on _id if no other sort is defined on the criteria.
|
|
376
|
-
#
|
|
377
|
-
# @return [ Document ] The last document.
|
|
378
|
-
def last(limit_or_opts = nil)
|
|
379
|
-
limit = limit_or_opts unless limit_or_opts.is_a?(Hash)
|
|
380
|
-
if cached? && cache_loaded?
|
|
381
|
-
return limit ? documents.last(limit) : documents.last
|
|
382
|
-
end
|
|
383
|
-
res = try_numbered_cache(:last, limit) do
|
|
384
|
-
with_inverse_sorting(limit_or_opts) do
|
|
385
|
-
if raw_docs = view.limit(limit || 1).to_a
|
|
386
|
-
process_raw_docs(raw_docs, limit)
|
|
387
|
-
end
|
|
388
|
-
end
|
|
389
|
-
end
|
|
390
|
-
res.is_a?(Array) ? res.reverse : res
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
# Get's the number of documents matching the query selector.
|
|
302
|
+
# Returns the number of documents in the database matching
|
|
303
|
+
# the query selector.
|
|
394
304
|
#
|
|
395
305
|
# @example Get the length.
|
|
396
306
|
# context.length
|
|
397
307
|
#
|
|
398
308
|
# @return [ Integer ] The number of documents.
|
|
399
309
|
def length
|
|
400
|
-
|
|
310
|
+
self.count
|
|
401
311
|
end
|
|
402
312
|
alias :size :length
|
|
403
313
|
|
|
@@ -413,6 +323,76 @@ module Mongoid
|
|
|
413
323
|
@view = view.limit(value) and self
|
|
414
324
|
end
|
|
415
325
|
|
|
326
|
+
# Initiate a map/reduce operation from the context.
|
|
327
|
+
#
|
|
328
|
+
# @example Initiate a map/reduce.
|
|
329
|
+
# context.map_reduce(map, reduce)
|
|
330
|
+
#
|
|
331
|
+
# @param [ String ] map The map js function.
|
|
332
|
+
# @param [ String ] reduce The reduce js function.
|
|
333
|
+
#
|
|
334
|
+
# @return [ MapReduce ] The map/reduce lazy wrapper.
|
|
335
|
+
def map_reduce(map, reduce)
|
|
336
|
+
MapReduce.new(collection, criteria, map, reduce)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Pluck the field value(s) from the database. Returns one
|
|
340
|
+
# result for each document found in the database for
|
|
341
|
+
# the context. The results are normalized according to their
|
|
342
|
+
# Mongoid field types. Note that the results may include
|
|
343
|
+
# duplicates and nil values.
|
|
344
|
+
#
|
|
345
|
+
# @example Pluck a field.
|
|
346
|
+
# context.pluck(:_id)
|
|
347
|
+
#
|
|
348
|
+
# @param [ [ String | Symbol ]... ] *fields Field(s) to pluck,
|
|
349
|
+
# which may include nested fields using dot-notation.
|
|
350
|
+
#
|
|
351
|
+
# @return [ Array<Object> | Array<Array<Object>> ] The plucked values.
|
|
352
|
+
# If the *fields arg contains a single value, each result
|
|
353
|
+
# in the array will be a single value. Otherwise, each
|
|
354
|
+
# result in the array will be an array of values.
|
|
355
|
+
def pluck(*fields)
|
|
356
|
+
# Multiple fields can map to the same field name. For example, plucking
|
|
357
|
+
# a field and its _translations field map to the same field in the database.
|
|
358
|
+
# because of this, we need to keep track of the fields requested.
|
|
359
|
+
normalized_field_names = []
|
|
360
|
+
normalized_select = fields.inject({}) do |hash, f|
|
|
361
|
+
db_fn = klass.database_field_name(f)
|
|
362
|
+
normalized_field_names.push(db_fn)
|
|
363
|
+
|
|
364
|
+
if Mongoid.legacy_pluck_distinct
|
|
365
|
+
hash[db_fn] = true
|
|
366
|
+
else
|
|
367
|
+
hash[klass.cleanse_localized_field_names(f)] = true
|
|
368
|
+
end
|
|
369
|
+
hash
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
view.projection(normalized_select).reduce([]) do |plucked, doc|
|
|
373
|
+
values = normalized_field_names.map do |n|
|
|
374
|
+
if Mongoid.legacy_pluck_distinct
|
|
375
|
+
n.include?('.') ? doc[n.partition('.')[0]] : doc[n]
|
|
376
|
+
else
|
|
377
|
+
extract_value(doc, n)
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
plucked << (values.size == 1 ? values.first : values)
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Pick the single field values from the database.
|
|
385
|
+
#
|
|
386
|
+
# @example Pick a field.
|
|
387
|
+
# context.pick(:_id)
|
|
388
|
+
#
|
|
389
|
+
# @param [ [ String | Symbol ]... ] *fields Field(s) to pick.
|
|
390
|
+
#
|
|
391
|
+
# @return [ Object | Array<Object> ] The picked values.
|
|
392
|
+
def pick(*fields)
|
|
393
|
+
limit(1).pluck(*fields).first
|
|
394
|
+
end
|
|
395
|
+
|
|
416
396
|
# Take the given number of documents from the database.
|
|
417
397
|
#
|
|
418
398
|
# @example Take 10 documents
|
|
@@ -451,57 +431,72 @@ module Mongoid
|
|
|
451
431
|
end
|
|
452
432
|
end
|
|
453
433
|
|
|
454
|
-
#
|
|
434
|
+
# Get a hash of counts for the values of a single field. For example,
|
|
435
|
+
# if the following documents were in the database:
|
|
455
436
|
#
|
|
456
|
-
#
|
|
457
|
-
#
|
|
437
|
+
# { _id: 1, age: 21 }
|
|
438
|
+
# { _id: 2, age: 21 }
|
|
439
|
+
# { _id: 3, age: 22 }
|
|
458
440
|
#
|
|
459
|
-
#
|
|
460
|
-
# @param [ String ] reduce The reduce js function.
|
|
441
|
+
# Model.tally("age")
|
|
461
442
|
#
|
|
462
|
-
#
|
|
463
|
-
def map_reduce(map, reduce)
|
|
464
|
-
MapReduce.new(collection, criteria, map, reduce)
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
# Pluck the single field values from the database. Will return duplicates
|
|
468
|
-
# if they exist and only works for top level fields.
|
|
443
|
+
# would yield the following result:
|
|
469
444
|
#
|
|
470
|
-
#
|
|
471
|
-
# context.pluck(:_id)
|
|
445
|
+
# { 21 => 2, 22 => 1 }
|
|
472
446
|
#
|
|
473
|
-
#
|
|
474
|
-
# serialization.
|
|
447
|
+
# When tallying a field inside an array or embeds_many association:
|
|
475
448
|
#
|
|
476
|
-
#
|
|
449
|
+
# { _id: 1, array: [ { x: 1 }, { x: 2 } ] }
|
|
450
|
+
# { _id: 2, array: [ { x: 1 }, { x: 2 } ] }
|
|
451
|
+
# { _id: 3, array: [ { x: 1 }, { x: 3 } ] }
|
|
477
452
|
#
|
|
478
|
-
#
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
453
|
+
# Model.tally("array.x")
|
|
454
|
+
#
|
|
455
|
+
# The keys of the resulting hash are arrays:
|
|
456
|
+
#
|
|
457
|
+
# { [ 1, 2 ] => 2, [ 1, 3 ] => 1 }
|
|
458
|
+
#
|
|
459
|
+
# Note that if tallying an element in an array of hashes, and the key
|
|
460
|
+
# doesn't exist in some of the hashes, tally will not include those
|
|
461
|
+
# nil keys in the resulting hash:
|
|
462
|
+
#
|
|
463
|
+
# { _id: 1, array: [ { x: 1 }, { x: 2 }, { y: 3 } ] }
|
|
464
|
+
#
|
|
465
|
+
# Model.tally("array.x")
|
|
466
|
+
# # => { [ 1, 2 ] => 1 }
|
|
467
|
+
#
|
|
468
|
+
# @param [ String | Symbol ] field The field name.
|
|
469
|
+
#
|
|
470
|
+
# @return [ Hash ] The hash of counts.
|
|
471
|
+
def tally(field)
|
|
472
|
+
name = klass.cleanse_localized_field_names(field)
|
|
487
473
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
hash[klass.cleanse_localized_field_names(f)] = true
|
|
492
|
-
end
|
|
493
|
-
hash
|
|
494
|
-
end
|
|
474
|
+
fld = klass.traverse_association_tree(name)
|
|
475
|
+
pipeline = [ { "$group" => { _id: "$#{name}", counts: { "$sum": 1 } } } ]
|
|
476
|
+
pipeline.unshift("$match" => view.filter) unless view.filter.blank?
|
|
495
477
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
478
|
+
collection.aggregate(pipeline).reduce({}) do |tallies, doc|
|
|
479
|
+
is_translation = "#{name}_translations" == field.to_s
|
|
480
|
+
val = doc["_id"]
|
|
481
|
+
|
|
482
|
+
key = if val.is_a?(Array)
|
|
483
|
+
val.map do |v|
|
|
484
|
+
demongoize_with_field(fld, v, is_translation)
|
|
502
485
|
end
|
|
486
|
+
else
|
|
487
|
+
demongoize_with_field(fld, val, is_translation)
|
|
503
488
|
end
|
|
504
|
-
|
|
489
|
+
|
|
490
|
+
# The only time where a key will already exist in the tallies hash
|
|
491
|
+
# is when the values are stored differently in the database, but
|
|
492
|
+
# demongoize to the same value. A good example of when this happens
|
|
493
|
+
# is when using localized fields. While the server query won't group
|
|
494
|
+
# together hashes that have other values in different languages, the
|
|
495
|
+
# demongoized value is just the translation in the current locale,
|
|
496
|
+
# which can be the same across multiple of those unequal hashes.
|
|
497
|
+
tallies[key] ||= 0
|
|
498
|
+
tallies[key] += doc["counts"]
|
|
499
|
+
tallies
|
|
505
500
|
end
|
|
506
501
|
end
|
|
507
502
|
|
|
@@ -548,7 +543,7 @@ module Mongoid
|
|
|
548
543
|
# @option opts [ Array ] :array_filters A set of filters specifying to which array elements
|
|
549
544
|
# an update should apply.
|
|
550
545
|
#
|
|
551
|
-
# @return [ nil
|
|
546
|
+
# @return [ nil | false ] False if no attributes were provided.
|
|
552
547
|
def update(attributes = nil, opts = {})
|
|
553
548
|
update_documents(attributes, :update_one, opts)
|
|
554
549
|
end
|
|
@@ -564,54 +559,257 @@ module Mongoid
|
|
|
564
559
|
# @option opts [ Array ] :array_filters A set of filters specifying to which array elements
|
|
565
560
|
# an update should apply.
|
|
566
561
|
#
|
|
567
|
-
# @return [ nil
|
|
562
|
+
# @return [ nil | false ] False if no attributes were provided.
|
|
568
563
|
def update_all(attributes = nil, opts = {})
|
|
569
564
|
update_documents(attributes, :update_many, opts)
|
|
570
565
|
end
|
|
571
566
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
#
|
|
567
|
+
# Get the first document in the database for the criteria's selector.
|
|
568
|
+
#
|
|
569
|
+
# @example Get the first document.
|
|
570
|
+
# context.first
|
|
571
|
+
#
|
|
572
|
+
# @note Automatically adding a sort on _id when no other sort is
|
|
573
|
+
# defined on the criteria has the potential to cause bad performance issues.
|
|
574
|
+
# If you experience unexpected poor performance when using #first or #last
|
|
575
|
+
# and have no sort defined on the criteria, use #take instead.
|
|
576
|
+
# Be aware that #take won't guarantee order.
|
|
575
577
|
#
|
|
576
|
-
# @param [
|
|
578
|
+
# @param [ Integer ] limit The number of documents to return.
|
|
577
579
|
#
|
|
578
|
-
# @return
|
|
579
|
-
def
|
|
580
|
-
|
|
581
|
-
|
|
580
|
+
# @return [ Document | nil ] The first document or nil if none is found.
|
|
581
|
+
def first(limit = nil)
|
|
582
|
+
if limit.nil?
|
|
583
|
+
retrieve_nth(0)
|
|
582
584
|
else
|
|
583
|
-
|
|
584
|
-
instance_variable_set("@#{key}", ret = yield)
|
|
585
|
-
end
|
|
586
|
-
ret
|
|
585
|
+
retrieve_nth_with_limit(0, limit)
|
|
587
586
|
end
|
|
588
587
|
end
|
|
588
|
+
alias :one :first
|
|
589
589
|
|
|
590
|
-
#
|
|
590
|
+
# Get the first document in the database for the criteria's selector or
|
|
591
|
+
# raise an error if none is found.
|
|
592
|
+
#
|
|
593
|
+
# @example Get the first document.
|
|
594
|
+
# context.first!
|
|
595
|
+
#
|
|
596
|
+
# @note Automatically adding a sort on _id when no other sort is
|
|
597
|
+
# defined on the criteria has the potential to cause bad performance issues.
|
|
598
|
+
# If you experience unexpected poor performance when using #first! or #last!
|
|
599
|
+
# and have no sort defined on the criteria, use #take! instead.
|
|
600
|
+
# Be aware that #take! won't guarantee order.
|
|
591
601
|
#
|
|
592
|
-
# @
|
|
593
|
-
# @param [ Integer | nil ] n The number of documents requested or nil
|
|
594
|
-
# if none is requested.
|
|
602
|
+
# @return [ Document ] The first document.
|
|
595
603
|
#
|
|
596
|
-
# @
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
604
|
+
# @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
|
|
605
|
+
# documents available.
|
|
606
|
+
def first!
|
|
607
|
+
first || raise_document_not_found_error
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
# Get the last document in the database for the criteria's selector.
|
|
611
|
+
#
|
|
612
|
+
# @example Get the last document.
|
|
613
|
+
# context.last
|
|
614
|
+
#
|
|
615
|
+
# @note Automatically adding a sort on _id when no other sort is
|
|
616
|
+
# defined on the criteria has the potential to cause bad performance issues.
|
|
617
|
+
# If you experience unexpected poor performance when using #first or #last
|
|
618
|
+
# and have no sort defined on the criteria, use #take instead.
|
|
619
|
+
# Be aware that #take won't guarantee order.
|
|
620
|
+
#
|
|
621
|
+
# @param [ Integer ] limit The number of documents to return.
|
|
622
|
+
#
|
|
623
|
+
# @return [ Document | nil ] The last document or nil if none is found.
|
|
624
|
+
def last(limit = nil)
|
|
625
|
+
if limit.nil?
|
|
626
|
+
retrieve_nth_to_last(0)
|
|
600
627
|
else
|
|
601
|
-
|
|
602
|
-
ret = instance_variable_get("@#{key}")
|
|
603
|
-
if !ret || ret.length < len
|
|
604
|
-
instance_variable_set("@#{key}", ret = Array.wrap(yield))
|
|
605
|
-
elsif !n
|
|
606
|
-
ret.is_a?(Array) ? ret.first : ret
|
|
607
|
-
elsif ret.length > len
|
|
608
|
-
ret.first(n)
|
|
609
|
-
else
|
|
610
|
-
ret
|
|
611
|
-
end
|
|
628
|
+
retrieve_nth_to_last_with_limit(0, limit)
|
|
612
629
|
end
|
|
613
630
|
end
|
|
614
631
|
|
|
632
|
+
# Get the last document in the database for the criteria's selector or
|
|
633
|
+
# raise an error if none is found.
|
|
634
|
+
#
|
|
635
|
+
# @example Get the last document.
|
|
636
|
+
# context.last!
|
|
637
|
+
#
|
|
638
|
+
# @note Automatically adding a sort on _id when no other sort is
|
|
639
|
+
# defined on the criteria has the potential to cause bad performance issues.
|
|
640
|
+
# If you experience unexpected poor performance when using #first! or #last!
|
|
641
|
+
# and have no sort defined on the criteria, use #take! instead.
|
|
642
|
+
# Be aware that #take! won't guarantee order.
|
|
643
|
+
#
|
|
644
|
+
# @return [ Document ] The last document.
|
|
645
|
+
#
|
|
646
|
+
# @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
|
|
647
|
+
# documents available.
|
|
648
|
+
def last!
|
|
649
|
+
last || raise_document_not_found_error
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
# Get the second document in the database for the criteria's selector.
|
|
653
|
+
#
|
|
654
|
+
# @example Get the second document.
|
|
655
|
+
# context.second
|
|
656
|
+
#
|
|
657
|
+
# @return [ Document | nil ] The second document or nil if none is found.
|
|
658
|
+
def second
|
|
659
|
+
retrieve_nth(1)
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
# Get the second document in the database for the criteria's selector or
|
|
663
|
+
# raise an error if none is found.
|
|
664
|
+
#
|
|
665
|
+
# @example Get the second document.
|
|
666
|
+
# context.second!
|
|
667
|
+
#
|
|
668
|
+
# @return [ Document ] The second document.
|
|
669
|
+
#
|
|
670
|
+
# @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
|
|
671
|
+
# documents available.
|
|
672
|
+
def second!
|
|
673
|
+
second || raise_document_not_found_error
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
# Get the third document in the database for the criteria's selector.
|
|
677
|
+
#
|
|
678
|
+
# @example Get the third document.
|
|
679
|
+
# context.third
|
|
680
|
+
#
|
|
681
|
+
# @return [ Document | nil ] The third document or nil if none is found.
|
|
682
|
+
def third
|
|
683
|
+
retrieve_nth(2)
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
# Get the third document in the database for the criteria's selector or
|
|
687
|
+
# raise an error if none is found.
|
|
688
|
+
#
|
|
689
|
+
# @example Get the third document.
|
|
690
|
+
# context.third!
|
|
691
|
+
#
|
|
692
|
+
# @return [ Document ] The third document.
|
|
693
|
+
#
|
|
694
|
+
# @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
|
|
695
|
+
# documents available.
|
|
696
|
+
def third!
|
|
697
|
+
third || raise_document_not_found_error
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
# Get the fourth document in the database for the criteria's selector.
|
|
701
|
+
#
|
|
702
|
+
# @example Get the fourth document.
|
|
703
|
+
# context.fourth
|
|
704
|
+
#
|
|
705
|
+
# @return [ Document | nil ] The fourth document or nil if none is found.
|
|
706
|
+
def fourth
|
|
707
|
+
retrieve_nth(3)
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
# Get the fourth document in the database for the criteria's selector or
|
|
711
|
+
# raise an error if none is found.
|
|
712
|
+
#
|
|
713
|
+
# @example Get the fourth document.
|
|
714
|
+
# context.fourth!
|
|
715
|
+
#
|
|
716
|
+
# @return [ Document ] The fourth document.
|
|
717
|
+
#
|
|
718
|
+
# @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
|
|
719
|
+
# documents available.
|
|
720
|
+
def fourth!
|
|
721
|
+
fourth || raise_document_not_found_error
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
# Get the fifth document in the database for the criteria's selector.
|
|
725
|
+
#
|
|
726
|
+
# @example Get the fifth document.
|
|
727
|
+
# context.fifth
|
|
728
|
+
#
|
|
729
|
+
# @return [ Document | nil ] The fifth document or nil if none is found.
|
|
730
|
+
def fifth
|
|
731
|
+
retrieve_nth(4)
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
# Get the fifth document in the database for the criteria's selector or
|
|
735
|
+
# raise an error if none is found.
|
|
736
|
+
#
|
|
737
|
+
# @example Get the fifth document.
|
|
738
|
+
# context.fifth!
|
|
739
|
+
#
|
|
740
|
+
# @return [ Document ] The fifth document.
|
|
741
|
+
#
|
|
742
|
+
# @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
|
|
743
|
+
# documents available.
|
|
744
|
+
def fifth!
|
|
745
|
+
fifth || raise_document_not_found_error
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
# Get the second to last document in the database for the criteria's
|
|
749
|
+
# selector.
|
|
750
|
+
#
|
|
751
|
+
# @example Get the second to last document.
|
|
752
|
+
# context.second_to_last
|
|
753
|
+
#
|
|
754
|
+
# @return [ Document | nil ] The second to last document or nil if none
|
|
755
|
+
# is found.
|
|
756
|
+
def second_to_last
|
|
757
|
+
retrieve_nth_to_last(1)
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
# Get the second to last document in the database for the criteria's
|
|
761
|
+
# selector or raise an error if none is found.
|
|
762
|
+
#
|
|
763
|
+
# @example Get the second to last document.
|
|
764
|
+
# context.second_to_last!
|
|
765
|
+
#
|
|
766
|
+
# @return [ Document ] The second to last document.
|
|
767
|
+
#
|
|
768
|
+
# @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
|
|
769
|
+
# documents available.
|
|
770
|
+
def second_to_last!
|
|
771
|
+
second_to_last || raise_document_not_found_error
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
# Get the third to last document in the database for the criteria's
|
|
775
|
+
# selector.
|
|
776
|
+
#
|
|
777
|
+
# @example Get the third to last document.
|
|
778
|
+
# context.third_to_last
|
|
779
|
+
#
|
|
780
|
+
# @return [ Document | nil ] The third to last document or nil if none
|
|
781
|
+
# is found.
|
|
782
|
+
def third_to_last
|
|
783
|
+
retrieve_nth_to_last(2)
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
# Get the third to last document in the database for the criteria's
|
|
787
|
+
# selector or raise an error if none is found.
|
|
788
|
+
#
|
|
789
|
+
# @example Get the third to last document.
|
|
790
|
+
# context.third_to_last!
|
|
791
|
+
#
|
|
792
|
+
# @return [ Document ] The third to last document.
|
|
793
|
+
#
|
|
794
|
+
# @raises [ Mongoid::Errors::DocumentNotFound ] raises when there are no
|
|
795
|
+
# documents available.
|
|
796
|
+
def third_to_last!
|
|
797
|
+
third_to_last || raise_document_not_found_error
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
# Schedule a task to load documents for the context.
|
|
801
|
+
#
|
|
802
|
+
# Depending on the Mongoid configuration, the scheduled task can be executed
|
|
803
|
+
# immediately on the caller's thread, or can be scheduled for an
|
|
804
|
+
# asynchronous execution.
|
|
805
|
+
#
|
|
806
|
+
# @api private
|
|
807
|
+
def load_async
|
|
808
|
+
@documents_loader ||= DocumentsLoader.new(view, klass, criteria)
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
private
|
|
812
|
+
|
|
615
813
|
# Update the documents for the provided method.
|
|
616
814
|
#
|
|
617
815
|
# @api private
|
|
@@ -622,7 +820,7 @@ module Mongoid
|
|
|
622
820
|
# @param [ Hash ] attributes The updates.
|
|
623
821
|
# @param [ Symbol ] method The method to use.
|
|
624
822
|
#
|
|
625
|
-
# @return [ true
|
|
823
|
+
# @return [ true | false ] If the update succeeded.
|
|
626
824
|
def update_documents(attributes, method = :update_one, opts = {})
|
|
627
825
|
return false unless attributes
|
|
628
826
|
attributes = Hash[attributes.map { |k, v| [klass.database_field_name(k.to_s), v] }]
|
|
@@ -672,78 +870,34 @@ module Mongoid
|
|
|
672
870
|
# Map the inverse sort symbols to the correct MongoDB values.
|
|
673
871
|
#
|
|
674
872
|
# @api private
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
def with_inverse_sorting(opts = {})
|
|
679
|
-
Mongoid::Warnings.warn_id_sort_deprecated if opts.try(:key?, :id_sort)
|
|
680
|
-
|
|
681
|
-
begin
|
|
682
|
-
if sort = criteria.options[:sort] || ( { _id: 1 } unless opts.try(:fetch, :id_sort) == :none )
|
|
683
|
-
@view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
|
|
684
|
-
end
|
|
685
|
-
yield
|
|
686
|
-
ensure
|
|
687
|
-
apply_option(:sort)
|
|
688
|
-
end
|
|
873
|
+
def inverse_sorting
|
|
874
|
+
sort = view.sort || { _id: 1 }
|
|
875
|
+
Hash[sort.map{|k, v| [k, -1*v]}]
|
|
689
876
|
end
|
|
690
877
|
|
|
691
|
-
#
|
|
878
|
+
# Get the documents the context should iterate.
|
|
692
879
|
#
|
|
693
|
-
#
|
|
880
|
+
# If the documents have been already preloaded by `Document::Loader`
|
|
881
|
+
# instance, they will be used.
|
|
694
882
|
#
|
|
695
|
-
# @
|
|
696
|
-
# context.cacheable?
|
|
697
|
-
#
|
|
698
|
-
# @return [ true, false ] If caching, and the cache isn't loaded.
|
|
699
|
-
def cacheable?
|
|
700
|
-
cached? && !cache_loaded?
|
|
701
|
-
end
|
|
702
|
-
|
|
703
|
-
# Is the cache fully loaded? Will be true if caching after one full
|
|
704
|
-
# iteration.
|
|
883
|
+
# @return [ Array<Document> | Mongo::Collection::View ] The docs to iterate.
|
|
705
884
|
#
|
|
706
885
|
# @api private
|
|
707
|
-
#
|
|
708
|
-
# @example Is the cache loaded?
|
|
709
|
-
# context.cache_loaded?
|
|
710
|
-
#
|
|
711
|
-
# @return [ true, false ] If the cache is loaded.
|
|
712
|
-
def cache_loaded?
|
|
713
|
-
!!@cache_loaded
|
|
714
|
-
end
|
|
715
|
-
|
|
716
|
-
# Get the documents for cached queries.
|
|
717
|
-
#
|
|
718
|
-
# @api private
|
|
719
|
-
#
|
|
720
|
-
# @example Get the cached documents.
|
|
721
|
-
# context.documents
|
|
722
|
-
#
|
|
723
|
-
# @return [ Array<Document> ] The documents.
|
|
724
|
-
def documents
|
|
725
|
-
@documents ||= []
|
|
726
|
-
end
|
|
727
|
-
|
|
728
|
-
# Get the documents the context should iterate. This follows 3 rules:
|
|
729
|
-
#
|
|
730
|
-
# 1. If the query is cached, and we already have documents loaded, use
|
|
731
|
-
# them.
|
|
732
|
-
# 2. If we are eager loading, then eager load the documents and use
|
|
733
|
-
# those.
|
|
734
|
-
# 3. Use the query.
|
|
735
|
-
#
|
|
736
|
-
# @api private
|
|
737
|
-
#
|
|
738
|
-
# @example Get the documents for iteration.
|
|
739
|
-
# context.documents_for_iteration
|
|
740
|
-
#
|
|
741
|
-
# @return [ Array<Document>, Mongo::Collection::View ] The docs to iterate.
|
|
742
886
|
def documents_for_iteration
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
887
|
+
if @documents_loader
|
|
888
|
+
if @documents_loader.started?
|
|
889
|
+
@documents_loader.value!
|
|
890
|
+
else
|
|
891
|
+
@documents_loader.unschedule
|
|
892
|
+
@documents_loader.execute
|
|
893
|
+
end
|
|
894
|
+
else
|
|
895
|
+
return view unless eager_loadable?
|
|
896
|
+
docs = view.map do |doc|
|
|
897
|
+
Factory.from_db(klass, doc, criteria)
|
|
898
|
+
end
|
|
899
|
+
eager_load(docs)
|
|
900
|
+
end
|
|
747
901
|
end
|
|
748
902
|
|
|
749
903
|
# Yield to the document.
|
|
@@ -760,11 +914,8 @@ module Mongoid
|
|
|
760
914
|
doc = document.respond_to?(:_id) ?
|
|
761
915
|
document : Factory.from_db(klass, document, criteria)
|
|
762
916
|
yield(doc)
|
|
763
|
-
documents.push(doc) if cacheable?
|
|
764
917
|
end
|
|
765
918
|
|
|
766
|
-
private
|
|
767
|
-
|
|
768
919
|
def _session
|
|
769
920
|
@criteria.send(:_session)
|
|
770
921
|
end
|
|
@@ -773,6 +924,26 @@ module Mongoid
|
|
|
773
924
|
collection.write_concern.nil? || collection.write_concern.acknowledged?
|
|
774
925
|
end
|
|
775
926
|
|
|
927
|
+
# Fetch the element from the given hash and demongoize it using the
|
|
928
|
+
# given field. If the obj is an array, map over it and call this method
|
|
929
|
+
# on all of its elements.
|
|
930
|
+
#
|
|
931
|
+
# @param [ Hash | Array<Hash> ] obj The hash or array of hashes to fetch from.
|
|
932
|
+
# @param [ String ] meth The key to fetch from the hash.
|
|
933
|
+
# @param [ Field ] field The field to use for demongoization.
|
|
934
|
+
#
|
|
935
|
+
# @return [ Object ] The demongoized value.
|
|
936
|
+
#
|
|
937
|
+
# @api private
|
|
938
|
+
def fetch_and_demongoize(obj, meth, field)
|
|
939
|
+
if obj.is_a?(Array)
|
|
940
|
+
obj.map { |doc| fetch_and_demongoize(doc, meth, field) }
|
|
941
|
+
else
|
|
942
|
+
res = obj.try(:fetch, meth, nil)
|
|
943
|
+
field ? field.demongoize(res) : res.class.demongoize(res)
|
|
944
|
+
end
|
|
945
|
+
end
|
|
946
|
+
|
|
776
947
|
# Extracts the value for the given field name from the given attribute
|
|
777
948
|
# hash.
|
|
778
949
|
#
|
|
@@ -781,24 +952,18 @@ module Mongoid
|
|
|
781
952
|
#
|
|
782
953
|
# @param [ Object ] The value for the given field name
|
|
783
954
|
def extract_value(attrs, field_name)
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
field.demongoize(res)
|
|
788
|
-
else
|
|
789
|
-
res.class.demongoize(res)
|
|
790
|
-
end
|
|
791
|
-
end
|
|
955
|
+
i = 1
|
|
956
|
+
num_meths = field_name.count('.') + 1
|
|
957
|
+
curr = attrs.dup
|
|
792
958
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
meths.each_with_index.inject(attrs) do |curr, (meth, i)|
|
|
959
|
+
klass.traverse_association_tree(field_name) do |meth, obj, is_field|
|
|
960
|
+
field = obj if is_field
|
|
796
961
|
is_translation = false
|
|
797
|
-
if
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
962
|
+
# If no association or field was found, check if the meth is an
|
|
963
|
+
# _translations field.
|
|
964
|
+
if obj.nil? & tr = meth.match(/(.*)_translations\z/)&.captures&.first
|
|
965
|
+
is_translation = true
|
|
966
|
+
meth = tr
|
|
802
967
|
end
|
|
803
968
|
|
|
804
969
|
# 1. If curr is an array fetch from all elements in the array.
|
|
@@ -811,31 +976,24 @@ module Mongoid
|
|
|
811
976
|
# 3. If the meth is an _translations field, do not demongoize the
|
|
812
977
|
# value so the full hash is returned.
|
|
813
978
|
# 4. Otherwise, fetch and demongoize the value for the key meth.
|
|
814
|
-
if curr.is_a? Array
|
|
815
|
-
res =
|
|
979
|
+
curr = if curr.is_a? Array
|
|
980
|
+
res = fetch_and_demongoize(curr, meth, field)
|
|
816
981
|
res.empty? ? nil : res
|
|
817
|
-
elsif !is_translation &&
|
|
818
|
-
if i <
|
|
982
|
+
elsif !is_translation && field&.localized?
|
|
983
|
+
if i < num_meths
|
|
819
984
|
curr.try(:fetch, meth, nil)
|
|
820
985
|
else
|
|
821
|
-
fetch_and_demongoize(curr, meth,
|
|
986
|
+
fetch_and_demongoize(curr, meth, field)
|
|
822
987
|
end
|
|
823
988
|
elsif is_translation
|
|
824
989
|
curr.try(:fetch, meth, nil)
|
|
825
990
|
else
|
|
826
|
-
fetch_and_demongoize(curr, meth,
|
|
827
|
-
end.tap do
|
|
828
|
-
if as = k.try(:aliased_associations)
|
|
829
|
-
if a = as.fetch(meth, nil)
|
|
830
|
-
meth = a
|
|
831
|
-
end
|
|
832
|
-
end
|
|
833
|
-
|
|
834
|
-
if relation = k.relations[meth]
|
|
835
|
-
k = relation.klass
|
|
836
|
-
end
|
|
991
|
+
fetch_and_demongoize(curr, meth, field)
|
|
837
992
|
end
|
|
993
|
+
|
|
994
|
+
i += 1
|
|
838
995
|
end
|
|
996
|
+
curr
|
|
839
997
|
end
|
|
840
998
|
|
|
841
999
|
# Recursively demongoize the given value. This method recursively traverses
|
|
@@ -843,34 +1001,41 @@ module Mongoid
|
|
|
843
1001
|
#
|
|
844
1002
|
# @param [ String ] field_name The name of the field to demongoize.
|
|
845
1003
|
# @param [ Object ] value The value to demongoize.
|
|
846
|
-
# @param [
|
|
1004
|
+
# @param [ true | false ] is_translation The field we are retrieving is an
|
|
847
1005
|
# _translations field.
|
|
848
1006
|
#
|
|
849
1007
|
# @return [ Object ] The demongoized value.
|
|
850
1008
|
def recursive_demongoize(field_name, value, is_translation)
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
if a = as.fetch(meth, nil)
|
|
855
|
-
meth = a.to_s
|
|
856
|
-
end
|
|
857
|
-
end
|
|
1009
|
+
field = klass.traverse_association_tree(field_name)
|
|
1010
|
+
demongoize_with_field(field, value, is_translation)
|
|
1011
|
+
end
|
|
858
1012
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1013
|
+
# Demongoize the value for the given field. If the field is nil or the
|
|
1014
|
+
# field is a translations field, the value is demongoized using its class.
|
|
1015
|
+
#
|
|
1016
|
+
# @param [ Field ] field The field to use to demongoize.
|
|
1017
|
+
# @param [ Object ] value The value to demongoize.
|
|
1018
|
+
# @param [ true | false ] is_translation The field we are retrieving is an
|
|
1019
|
+
# _translations field.
|
|
1020
|
+
#
|
|
1021
|
+
# @return [ Object ] The demongoized value.
|
|
1022
|
+
#
|
|
1023
|
+
# @api private
|
|
1024
|
+
def demongoize_with_field(field, value, is_translation)
|
|
1025
|
+
if field
|
|
1026
|
+
# If it's a localized field that's not a hash, don't demongoize
|
|
1027
|
+
# again, we already have the translation. If it's an _translations
|
|
1028
|
+
# field, don't demongoize, we want the full hash not just a
|
|
1029
|
+
# specific translation.
|
|
1030
|
+
# If it is a hash, and it's not a translations field, we need to
|
|
1031
|
+
# demongoize to get the correct translation.
|
|
1032
|
+
if field.localized? && (!value.is_a?(Hash) || is_translation)
|
|
1033
|
+
value.class.demongoize(value)
|
|
871
1034
|
else
|
|
872
|
-
|
|
1035
|
+
field.demongoize(value)
|
|
873
1036
|
end
|
|
1037
|
+
else
|
|
1038
|
+
value.class.demongoize(value)
|
|
874
1039
|
end
|
|
875
1040
|
end
|
|
876
1041
|
|
|
@@ -885,6 +1050,52 @@ module Mongoid
|
|
|
885
1050
|
docs = eager_load(docs)
|
|
886
1051
|
limit ? docs : docs.first
|
|
887
1052
|
end
|
|
1053
|
+
|
|
1054
|
+
# Queries whether the current context is valid for use with
|
|
1055
|
+
# the #count_documents? predicate. A context is valid if it
|
|
1056
|
+
# does not include a `$where` operator.
|
|
1057
|
+
#
|
|
1058
|
+
# @return [ true | false ] whether or not the current context
|
|
1059
|
+
# excludes a `$where` operator.
|
|
1060
|
+
def valid_for_count_documents?(hash = view.filter)
|
|
1061
|
+
# Note that `view.filter` is a BSON::Document, and all keys in a
|
|
1062
|
+
# BSON::Document are strings; we don't need to worry about symbol
|
|
1063
|
+
# representations of `$where`.
|
|
1064
|
+
hash.keys.each do |key|
|
|
1065
|
+
return false if key == '$where'
|
|
1066
|
+
return false if hash[key].is_a?(Hash) && !valid_for_count_documents?(hash[key])
|
|
1067
|
+
end
|
|
1068
|
+
|
|
1069
|
+
true
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
def raise_document_not_found_error
|
|
1073
|
+
raise Errors::DocumentNotFound.new(klass, nil, nil)
|
|
1074
|
+
end
|
|
1075
|
+
|
|
1076
|
+
def retrieve_nth(n)
|
|
1077
|
+
retrieve_nth_with_limit(n, 1).first
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
def retrieve_nth_with_limit(n, limit)
|
|
1081
|
+
sort = view.sort || { _id: 1 }
|
|
1082
|
+
v = view.sort(sort).limit(limit || 1)
|
|
1083
|
+
v = v.skip(n) if n > 0
|
|
1084
|
+
if raw_docs = v.to_a
|
|
1085
|
+
process_raw_docs(raw_docs, limit)
|
|
1086
|
+
end
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
def retrieve_nth_to_last(n)
|
|
1090
|
+
retrieve_nth_to_last_with_limit(n, 1).first
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
def retrieve_nth_to_last_with_limit(n, limit)
|
|
1094
|
+
v = view.sort(inverse_sorting).skip(n).limit(limit || 1)
|
|
1095
|
+
v = v.skip(n) if n > 0
|
|
1096
|
+
raw_docs = v.to_a.reverse
|
|
1097
|
+
process_raw_docs(raw_docs, limit)
|
|
1098
|
+
end
|
|
888
1099
|
end
|
|
889
1100
|
end
|
|
890
1101
|
end
|