mongoid 7.0.2 → 8.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +33 -33
- data/LICENSE +1 -0
- data/README.md +34 -20
- data/Rakefile +100 -5
- data/lib/config/locales/en.yml +220 -105
- data/lib/mongoid/association/accessors.rb +176 -84
- data/lib/mongoid/association/bindable.rb +57 -28
- data/lib/mongoid/association/builders.rb +9 -15
- data/lib/mongoid/association/constrainable.rb +5 -7
- data/lib/mongoid/association/depending.rb +9 -18
- data/lib/mongoid/association/eager_loadable.rb +31 -10
- data/lib/mongoid/association/embedded/batchable.rb +68 -54
- data/lib/mongoid/association/embedded/cyclic.rb +10 -17
- data/lib/mongoid/association/embedded/embedded_in/binding.rb +27 -9
- data/lib/mongoid/association/embedded/embedded_in/buildable.rb +9 -6
- data/lib/mongoid/association/embedded/embedded_in/proxy.rb +16 -25
- data/lib/mongoid/association/embedded/embedded_in.rb +9 -28
- data/lib/mongoid/association/embedded/embeds_many/binding.rb +5 -8
- data/lib/mongoid/association/embedded/embeds_many/buildable.rb +10 -6
- data/lib/mongoid/association/embedded/embeds_many/proxy.rb +156 -135
- data/lib/mongoid/association/embedded/embeds_many.rb +10 -37
- data/lib/mongoid/association/embedded/embeds_one/binding.rb +4 -8
- data/lib/mongoid/association/embedded/embeds_one/buildable.rb +27 -10
- data/lib/mongoid/association/embedded/embeds_one/proxy.rb +64 -30
- data/lib/mongoid/association/embedded/embeds_one.rb +11 -34
- data/lib/mongoid/association/embedded.rb +2 -0
- data/lib/mongoid/association/macros.rb +65 -41
- data/lib/mongoid/association/many.rb +25 -35
- data/lib/mongoid/association/marshalable.rb +3 -6
- data/lib/mongoid/association/nested/many.rb +22 -30
- data/lib/mongoid/association/nested/nested_buildable.rb +9 -15
- data/lib/mongoid/association/nested/one.rb +57 -30
- data/lib/mongoid/association/nested.rb +3 -3
- data/lib/mongoid/association/one.rb +5 -12
- data/lib/mongoid/association/options.rb +16 -46
- data/lib/mongoid/association/proxy.rb +52 -40
- data/lib/mongoid/association/referenced/auto_save.rb +9 -14
- data/lib/mongoid/association/referenced/belongs_to/binding.rb +5 -9
- data/lib/mongoid/association/referenced/belongs_to/buildable.rb +11 -9
- data/lib/mongoid/association/referenced/belongs_to/eager.rb +40 -3
- data/lib/mongoid/association/referenced/belongs_to/proxy.rb +19 -31
- data/lib/mongoid/association/referenced/belongs_to.rb +16 -38
- data/lib/mongoid/association/referenced/counter_cache.rb +14 -25
- data/lib/mongoid/association/referenced/eager.rb +42 -38
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb +12 -11
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/buildable.rb +5 -5
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/eager.rb +2 -1
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +106 -67
- data/lib/mongoid/association/referenced/has_and_belongs_to_many.rb +29 -46
- data/lib/mongoid/association/referenced/has_many/binding.rb +3 -6
- data/lib/mongoid/association/referenced/has_many/buildable.rb +5 -5
- data/lib/mongoid/association/referenced/has_many/eager.rb +2 -1
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +440 -456
- data/lib/mongoid/association/referenced/has_many/proxy.rb +104 -127
- data/lib/mongoid/association/referenced/has_many.rb +21 -45
- data/lib/mongoid/association/referenced/has_one/binding.rb +4 -9
- data/lib/mongoid/association/referenced/has_one/buildable.rb +20 -6
- data/lib/mongoid/association/referenced/has_one/eager.rb +2 -1
- data/lib/mongoid/association/referenced/has_one/nested_builder.rb +16 -29
- data/lib/mongoid/association/referenced/has_one/proxy.rb +25 -30
- data/lib/mongoid/association/referenced/has_one.rb +16 -36
- data/lib/mongoid/association/referenced/syncable.rb +11 -26
- data/lib/mongoid/association/referenced.rb +2 -0
- data/lib/mongoid/association/reflections.rb +7 -6
- data/lib/mongoid/association/relatable.rb +149 -89
- data/lib/mongoid/association.rb +13 -27
- data/lib/mongoid/atomic/modifiers.rb +29 -53
- data/lib/mongoid/atomic/paths/embedded/many.rb +23 -7
- data/lib/mongoid/atomic/paths/embedded/one.rb +4 -7
- data/lib/mongoid/atomic/paths/embedded.rb +3 -4
- data/lib/mongoid/atomic/paths/root.rb +4 -7
- data/lib/mongoid/atomic/paths.rb +2 -1
- data/lib/mongoid/atomic.rb +49 -47
- data/lib/mongoid/attributes/dynamic.rb +22 -36
- data/lib/mongoid/attributes/nested.rb +12 -15
- data/lib/mongoid/attributes/processing.rb +19 -27
- data/lib/mongoid/attributes/projector.rb +119 -0
- data/lib/mongoid/attributes/readonly.rb +6 -9
- data/lib/mongoid/attributes.rb +103 -100
- data/lib/mongoid/cacheable.rb +7 -10
- data/lib/mongoid/changeable.rb +152 -73
- data/lib/mongoid/clients/factory.rb +42 -17
- data/lib/mongoid/clients/options.rb +21 -18
- data/lib/mongoid/clients/sessions.rb +10 -10
- data/lib/mongoid/clients/storage_options.rb +9 -17
- data/lib/mongoid/clients/validators/storage.rb +5 -24
- data/lib/mongoid/clients/validators.rb +2 -1
- data/lib/mongoid/clients.rb +3 -10
- data/lib/mongoid/collection_configurable.rb +58 -0
- data/lib/mongoid/composable.rb +7 -9
- data/lib/mongoid/config/defaults.rb +60 -0
- data/lib/mongoid/config/environment.rb +51 -13
- data/lib/mongoid/config/options.rb +20 -23
- data/lib/mongoid/config/validators/async_query_executor.rb +24 -0
- data/lib/mongoid/config/validators/client.rb +8 -23
- data/lib/mongoid/config/validators/option.rb +2 -3
- data/lib/mongoid/config/validators.rb +3 -1
- data/lib/mongoid/config.rb +235 -48
- data/lib/mongoid/contextual/aggregable/memory.rb +40 -27
- data/lib/mongoid/contextual/aggregable/mongo.rb +32 -33
- data/lib/mongoid/contextual/aggregable/none.rb +65 -0
- data/lib/mongoid/contextual/aggregable.rb +17 -0
- data/lib/mongoid/contextual/atomic.rb +29 -31
- data/lib/mongoid/contextual/command.rb +2 -5
- data/lib/mongoid/contextual/geo_near.rb +13 -44
- data/lib/mongoid/contextual/map_reduce.rb +7 -35
- data/lib/mongoid/contextual/memory.rb +387 -81
- data/lib/mongoid/contextual/mongo/documents_loader.rb +177 -0
- data/lib/mongoid/contextual/mongo.rb +641 -283
- data/lib/mongoid/contextual/none.rb +264 -31
- data/lib/mongoid/contextual/queryable.rb +3 -4
- data/lib/mongoid/contextual.rb +21 -11
- data/lib/mongoid/copyable.rb +46 -17
- data/lib/mongoid/criteria/findable.rb +20 -20
- data/lib/mongoid/criteria/includable.rb +32 -34
- data/lib/mongoid/criteria/inspectable.rb +2 -3
- data/lib/mongoid/criteria/marshalable.rb +12 -7
- data/lib/mongoid/criteria/modifiable.rb +15 -21
- data/lib/mongoid/criteria/options.rb +4 -5
- data/lib/mongoid/criteria/permission.rb +3 -2
- data/lib/mongoid/criteria/queryable/aggregable.rb +4 -15
- data/lib/mongoid/criteria/queryable/expandable.rb +68 -0
- data/lib/mongoid/criteria/queryable/extensions/array.rb +7 -41
- data/lib/mongoid/criteria/queryable/extensions/big_decimal.rb +28 -8
- data/lib/mongoid/criteria/queryable/extensions/boolean.rb +5 -6
- data/lib/mongoid/criteria/queryable/extensions/date.rb +9 -9
- data/lib/mongoid/criteria/queryable/extensions/date_time.rb +11 -12
- data/lib/mongoid/criteria/queryable/extensions/hash.rb +4 -41
- data/lib/mongoid/criteria/queryable/extensions/nil_class.rb +3 -14
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +4 -21
- data/lib/mongoid/criteria/queryable/extensions/object.rb +6 -30
- data/lib/mongoid/criteria/queryable/extensions/range.rb +49 -17
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +12 -19
- data/lib/mongoid/criteria/queryable/extensions/set.rb +4 -5
- data/lib/mongoid/criteria/queryable/extensions/string.rb +7 -32
- data/lib/mongoid/criteria/queryable/extensions/symbol.rb +7 -22
- data/lib/mongoid/criteria/queryable/extensions/time.rb +10 -10
- data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +19 -7
- data/lib/mongoid/criteria/queryable/extensions.rb +1 -4
- data/lib/mongoid/criteria/queryable/key.rb +105 -31
- data/lib/mongoid/criteria/queryable/macroable.rb +3 -4
- data/lib/mongoid/criteria/queryable/mergeable.rb +205 -44
- data/lib/mongoid/criteria/queryable/optional.rb +16 -65
- data/lib/mongoid/criteria/queryable/options.rb +4 -21
- data/lib/mongoid/criteria/queryable/pipeline.rb +5 -15
- data/lib/mongoid/criteria/queryable/selectable.rb +471 -168
- data/lib/mongoid/criteria/queryable/selector.rb +133 -58
- data/lib/mongoid/criteria/queryable/smash.rb +42 -18
- data/lib/mongoid/criteria/queryable/storable.rb +237 -0
- data/lib/mongoid/criteria/queryable.rb +18 -15
- data/lib/mongoid/criteria/scopable.rb +29 -21
- data/lib/mongoid/criteria/translator.rb +45 -0
- data/lib/mongoid/criteria.rb +106 -111
- data/lib/mongoid/deprecable.rb +36 -0
- data/lib/mongoid/deprecation.rb +25 -0
- data/lib/mongoid/document.rb +162 -103
- data/lib/mongoid/equality.rb +35 -18
- data/lib/mongoid/errors/ambiguous_relationship.rb +4 -5
- data/lib/mongoid/errors/callback.rb +2 -3
- data/lib/mongoid/errors/create_collection_failure.rb +33 -0
- data/lib/mongoid/errors/criteria_argument_required.rb +18 -0
- data/lib/mongoid/errors/delete_restriction.rb +10 -13
- data/lib/mongoid/errors/document_not_destroyed.rb +4 -7
- data/lib/mongoid/errors/document_not_found.rb +35 -21
- data/lib/mongoid/errors/drop_collection_failure.rb +27 -0
- data/lib/mongoid/errors/empty_config_file.rb +25 -0
- data/lib/mongoid/errors/immutable_attribute.rb +26 -0
- data/lib/mongoid/errors/in_memory_collation_not_supported.rb +2 -3
- data/lib/mongoid/errors/invalid_async_query_executor.rb +25 -0
- data/lib/mongoid/errors/invalid_collection.rb +2 -1
- data/lib/mongoid/errors/invalid_config_file.rb +25 -0
- data/lib/mongoid/errors/invalid_config_option.rb +3 -4
- data/lib/mongoid/errors/invalid_dependent_strategy.rb +3 -4
- data/lib/mongoid/errors/invalid_discriminator_key_target.rb +24 -0
- data/lib/mongoid/errors/invalid_dot_dollar_assignment.rb +23 -0
- data/lib/mongoid/errors/invalid_elem_match_operator.rb +32 -0
- data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +25 -0
- data/lib/mongoid/errors/invalid_expression_operator.rb +27 -0
- data/lib/mongoid/errors/invalid_field.rb +8 -7
- data/lib/mongoid/errors/invalid_field_operator.rb +32 -0
- data/lib/mongoid/errors/invalid_field_option.rb +2 -3
- data/lib/mongoid/errors/invalid_field_type.rb +26 -0
- data/lib/mongoid/errors/invalid_find.rb +2 -3
- data/lib/mongoid/errors/invalid_global_executor_concurrency.rb +22 -0
- data/lib/mongoid/errors/invalid_includes.rb +2 -3
- data/lib/mongoid/errors/invalid_index.rb +2 -3
- data/lib/mongoid/errors/invalid_options.rb +4 -5
- data/lib/mongoid/errors/invalid_path.rb +2 -3
- data/lib/mongoid/errors/invalid_persistence_option.rb +2 -5
- data/lib/mongoid/errors/invalid_query.rb +40 -0
- data/lib/mongoid/errors/invalid_relation.rb +5 -10
- data/lib/mongoid/errors/invalid_relation_option.rb +4 -5
- data/lib/mongoid/errors/invalid_scope.rb +2 -3
- data/lib/mongoid/errors/invalid_session_use.rb +3 -6
- data/lib/mongoid/errors/invalid_set_polymorphic_relation.rb +6 -5
- data/lib/mongoid/errors/invalid_storage_options.rb +3 -4
- data/lib/mongoid/errors/invalid_storage_parent.rb +4 -3
- data/lib/mongoid/errors/invalid_time.rb +2 -3
- data/lib/mongoid/errors/inverse_not_found.rb +3 -4
- data/lib/mongoid/errors/mixed_client_configuration.rb +2 -3
- data/lib/mongoid/errors/mixed_relations.rb +2 -3
- data/lib/mongoid/errors/mongoid_error.rb +6 -13
- data/lib/mongoid/errors/nested_attributes_metadata_not_found.rb +3 -4
- data/lib/mongoid/errors/no_client_config.rb +4 -5
- data/lib/mongoid/errors/no_client_database.rb +3 -4
- data/lib/mongoid/errors/no_client_hosts.rb +3 -4
- data/lib/mongoid/errors/no_clients_config.rb +2 -3
- data/lib/mongoid/errors/no_default_client.rb +3 -4
- data/lib/mongoid/errors/no_environment.rb +2 -3
- data/lib/mongoid/errors/no_map_reduce_output.rb +2 -3
- data/lib/mongoid/errors/no_metadata.rb +2 -3
- data/lib/mongoid/errors/no_parent.rb +2 -3
- data/lib/mongoid/errors/readonly_attribute.rb +3 -4
- data/lib/mongoid/errors/readonly_document.rb +3 -6
- data/lib/mongoid/errors/scope_overwrite.rb +2 -1
- data/lib/mongoid/errors/too_many_nested_attribute_records.rb +3 -1
- data/lib/mongoid/errors/unknown_attribute.rb +3 -4
- data/lib/mongoid/errors/unknown_model.rb +2 -3
- data/lib/mongoid/errors/unsaved_document.rb +3 -2
- data/lib/mongoid/errors/unsupported_javascript.rb +2 -3
- data/lib/mongoid/errors/validations.rb +2 -1
- data/lib/mongoid/errors.rb +18 -4
- data/lib/mongoid/evolvable.rb +4 -5
- data/lib/mongoid/extensions/array.rb +37 -44
- data/lib/mongoid/extensions/big_decimal.rb +35 -21
- data/lib/mongoid/extensions/binary.rb +42 -0
- data/lib/mongoid/extensions/boolean.rb +10 -6
- data/lib/mongoid/extensions/date.rb +32 -25
- data/lib/mongoid/extensions/date_time.rb +5 -13
- data/lib/mongoid/extensions/decimal128.rb +2 -5
- data/lib/mongoid/extensions/false_class.rb +5 -8
- data/lib/mongoid/extensions/float.rb +12 -14
- data/lib/mongoid/extensions/hash.rb +64 -42
- data/lib/mongoid/extensions/integer.rb +12 -16
- data/lib/mongoid/extensions/module.rb +3 -4
- data/lib/mongoid/extensions/nil_class.rb +2 -5
- data/lib/mongoid/extensions/object.rb +27 -52
- data/lib/mongoid/extensions/object_id.rb +2 -7
- data/lib/mongoid/extensions/range.rb +42 -20
- data/lib/mongoid/extensions/regexp.rb +14 -7
- data/lib/mongoid/extensions/set.rb +13 -11
- data/lib/mongoid/extensions/string.rb +35 -64
- data/lib/mongoid/extensions/symbol.rb +6 -22
- data/lib/mongoid/extensions/time.rb +38 -22
- data/lib/mongoid/extensions/time_with_zone.rb +26 -9
- data/lib/mongoid/extensions/true_class.rb +5 -8
- data/lib/mongoid/extensions.rb +19 -3
- data/lib/mongoid/factory.rb +104 -17
- data/lib/mongoid/fields/foreign_key.rb +14 -26
- data/lib/mongoid/fields/localized.rb +21 -15
- data/lib/mongoid/fields/standard.rb +23 -43
- data/lib/mongoid/fields/validators/macro.rb +32 -20
- data/lib/mongoid/fields/validators.rb +2 -1
- data/lib/mongoid/fields.rb +349 -76
- data/lib/mongoid/findable.rb +115 -34
- data/lib/mongoid/indexable/specification.rb +5 -18
- data/lib/mongoid/indexable/validators/options.rb +8 -9
- data/lib/mongoid/indexable.rb +6 -21
- data/lib/mongoid/inspectable.rb +4 -11
- data/lib/mongoid/interceptable.rb +85 -41
- data/lib/mongoid/loggable.rb +13 -16
- data/lib/mongoid/matchable.rb +4 -154
- data/lib/mongoid/matcher/all.rb +22 -0
- data/lib/mongoid/matcher/and.rb +21 -0
- data/lib/mongoid/matcher/bits.rb +41 -0
- data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
- data/lib/mongoid/matcher/bits_all_set.rb +20 -0
- data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
- data/lib/mongoid/matcher/bits_any_set.rb +20 -0
- data/lib/mongoid/matcher/elem_match.rb +36 -0
- data/lib/mongoid/matcher/elem_match_expression.rb +20 -0
- data/lib/mongoid/matcher/eq.rb +11 -0
- data/lib/mongoid/matcher/eq_impl.rb +67 -0
- data/lib/mongoid/matcher/eq_impl_with_regexp.rb +26 -0
- data/lib/mongoid/matcher/exists.rb +15 -0
- data/lib/mongoid/matcher/expression.rb +35 -0
- data/lib/mongoid/matcher/expression_operator.rb +19 -0
- data/lib/mongoid/matcher/field_expression.rb +62 -0
- data/lib/mongoid/matcher/field_operator.rb +54 -0
- data/lib/mongoid/matcher/gt.rb +17 -0
- data/lib/mongoid/matcher/gte.rb +17 -0
- data/lib/mongoid/matcher/in.rb +25 -0
- data/lib/mongoid/matcher/lt.rb +17 -0
- data/lib/mongoid/matcher/lte.rb +17 -0
- data/lib/mongoid/matcher/mod.rb +17 -0
- data/lib/mongoid/matcher/ne.rb +16 -0
- data/lib/mongoid/matcher/nin.rb +11 -0
- data/lib/mongoid/matcher/nor.rb +25 -0
- data/lib/mongoid/matcher/not.rb +29 -0
- data/lib/mongoid/matcher/or.rb +21 -0
- data/lib/mongoid/matcher/regex.rb +41 -0
- data/lib/mongoid/matcher/size.rb +26 -0
- data/lib/mongoid/matcher/type.rb +99 -0
- data/lib/mongoid/matcher.rb +130 -0
- data/lib/mongoid/persistable/creatable.rb +23 -30
- data/lib/mongoid/persistable/deletable.rb +7 -23
- data/lib/mongoid/persistable/destroyable.rb +12 -11
- data/lib/mongoid/persistable/incrementable.rb +6 -7
- data/lib/mongoid/persistable/logical.rb +4 -6
- data/lib/mongoid/persistable/poppable.rb +3 -6
- data/lib/mongoid/persistable/pullable.rb +3 -8
- data/lib/mongoid/persistable/pushable.rb +14 -10
- data/lib/mongoid/persistable/renamable.rb +10 -8
- data/lib/mongoid/persistable/savable.rb +16 -9
- data/lib/mongoid/persistable/settable.rb +3 -6
- data/lib/mongoid/persistable/unsettable.rb +10 -10
- data/lib/mongoid/persistable/updatable.rb +99 -30
- data/lib/mongoid/persistable/upsertable.rb +23 -9
- data/lib/mongoid/persistable.rb +138 -40
- data/lib/mongoid/persistence_context.rb +107 -52
- data/lib/mongoid/positional.rb +3 -6
- data/lib/mongoid/query_cache.rb +18 -234
- data/lib/mongoid/railtie.rb +20 -16
- data/lib/mongoid/railties/controller_runtime.rb +88 -0
- data/lib/mongoid/railties/database.rake +16 -2
- data/lib/mongoid/reloadable.rb +19 -22
- data/lib/mongoid/scopable.rb +37 -60
- data/lib/mongoid/selectable.rb +8 -18
- data/lib/mongoid/serializable.rb +33 -34
- data/lib/mongoid/shardable.rb +108 -21
- data/lib/mongoid/stateful.rb +60 -20
- data/lib/mongoid/stringified_symbol.rb +52 -0
- data/lib/mongoid/tasks/database.rake +24 -5
- data/lib/mongoid/tasks/database.rb +105 -7
- data/lib/mongoid/threaded/lifecycle.rb +7 -26
- data/lib/mongoid/threaded.rb +80 -67
- data/lib/mongoid/timestamps/created/short.rb +2 -1
- data/lib/mongoid/timestamps/created.rb +4 -3
- data/lib/mongoid/timestamps/short.rb +2 -1
- data/lib/mongoid/timestamps/timeless.rb +6 -9
- data/lib/mongoid/timestamps/updated/short.rb +2 -1
- data/lib/mongoid/timestamps/updated.rb +5 -6
- data/lib/mongoid/timestamps.rb +3 -2
- data/lib/mongoid/touchable.rb +54 -25
- data/lib/mongoid/traversable.rb +185 -61
- data/lib/mongoid/utils.rb +22 -0
- data/lib/mongoid/validatable/associated.rb +5 -6
- data/lib/mongoid/validatable/format.rb +2 -1
- data/lib/mongoid/validatable/length.rb +2 -1
- data/lib/mongoid/validatable/localizable.rb +3 -4
- data/lib/mongoid/validatable/macros.rb +8 -15
- data/lib/mongoid/validatable/presence.rb +10 -15
- data/lib/mongoid/validatable/queryable.rb +2 -3
- data/lib/mongoid/validatable/uniqueness.rb +30 -42
- data/lib/mongoid/validatable.rb +16 -32
- data/lib/mongoid/version.rb +3 -2
- data/lib/mongoid/warnings.rb +44 -0
- data/lib/mongoid.rb +50 -17
- data/lib/rails/generators/mongoid/config/config_generator.rb +10 -2
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +53 -32
- data/lib/rails/generators/mongoid/model/model_generator.rb +3 -2
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/mongoid_generator.rb +2 -1
- data/lib/rails/mongoid.rb +4 -5
- data/spec/README.md +33 -0
- data/spec/config/mongoid.yml +29 -3
- data/spec/config/mongoid_with_schema_map_uuid.yml +27 -0
- data/spec/integration/app_spec.rb +345 -0
- data/spec/integration/associations/belongs_to_spec.rb +33 -0
- data/spec/integration/associations/embedded_dirty_spec.rb +57 -0
- data/spec/integration/associations/embedded_spec.rb +283 -0
- data/spec/integration/associations/embeds_many_spec.rb +219 -0
- data/spec/integration/associations/embeds_one_spec.rb +41 -0
- data/spec/integration/associations/foreign_key_spec.rb +107 -0
- data/spec/integration/associations/foreign_key_spec_models.rb +64 -0
- data/spec/integration/associations/has_and_belongs_to_many_spec.rb +21 -0
- data/spec/integration/associations/has_many_spec.rb +128 -0
- data/spec/integration/associations/has_one_spec.rb +272 -0
- data/spec/integration/associations/nested_attributes_assignment_spec.rb +115 -0
- data/spec/integration/associations/reverse_population_spec.rb +34 -0
- data/spec/integration/associations/reverse_population_spec_models.rb +36 -0
- data/spec/integration/associations/scope_option_spec.rb +101 -0
- data/spec/integration/atomic/modifiers_spec.rb +116 -0
- data/spec/integration/bson_regexp_raw_spec.rb +19 -0
- data/spec/integration/callbacks_models.rb +192 -0
- data/spec/integration/callbacks_spec.rb +584 -0
- data/spec/integration/contextual/empty_spec.rb +141 -0
- data/spec/integration/criteria/alias_query_spec.rb +161 -0
- data/spec/integration/criteria/date_field_spec.rb +40 -0
- data/spec/integration/criteria/default_scope_spec.rb +72 -0
- data/spec/integration/criteria/logical_spec.rb +124 -0
- data/spec/integration/criteria/range_spec.rb +359 -0
- data/spec/integration/criteria/time_with_zone_spec.rb +142 -0
- data/spec/integration/discriminator_key_spec.rb +391 -0
- data/spec/integration/discriminator_value_spec.rb +206 -0
- data/spec/integration/document_spec.rb +51 -0
- data/spec/integration/dots_and_dollars_spec.rb +277 -0
- data/spec/integration/i18n_fallbacks_spec.rb +74 -0
- data/spec/integration/matcher_examples_spec.rb +765 -0
- data/spec/integration/matcher_operator_data/all.yml +140 -0
- data/spec/integration/matcher_operator_data/and.yml +93 -0
- data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
- data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
- data/spec/integration/matcher_operator_data/comment.yml +22 -0
- data/spec/integration/matcher_operator_data/elem_match.yml +409 -0
- data/spec/integration/matcher_operator_data/elem_match_expr.yml +213 -0
- data/spec/integration/matcher_operator_data/eq.yml +191 -0
- data/spec/integration/matcher_operator_data/exists.yml +213 -0
- data/spec/integration/matcher_operator_data/generic_op.yml +17 -0
- data/spec/integration/matcher_operator_data/gt.yml +132 -0
- data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
- data/spec/integration/matcher_operator_data/gte.yml +132 -0
- data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
- data/spec/integration/matcher_operator_data/implicit.yml +331 -0
- data/spec/integration/matcher_operator_data/implicit_traversal.yml +112 -0
- data/spec/integration/matcher_operator_data/in.yml +210 -0
- data/spec/integration/matcher_operator_data/invalid_op.yml +59 -0
- data/spec/integration/matcher_operator_data/invalid_syntax.yml +39 -0
- data/spec/integration/matcher_operator_data/lt.yml +132 -0
- data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
- data/spec/integration/matcher_operator_data/lte.yml +132 -0
- data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
- data/spec/integration/matcher_operator_data/mod.yml +55 -0
- data/spec/integration/matcher_operator_data/multiple.yml +29 -0
- data/spec/integration/matcher_operator_data/ne.yml +150 -0
- data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
- data/spec/integration/matcher_operator_data/nin.yml +114 -0
- data/spec/integration/matcher_operator_data/nor.yml +126 -0
- data/spec/integration/matcher_operator_data/not.yml +196 -0
- data/spec/integration/matcher_operator_data/or.yml +137 -0
- data/spec/integration/matcher_operator_data/regex.yml +174 -0
- data/spec/integration/matcher_operator_data/regex_options.yml +72 -0
- data/spec/integration/matcher_operator_data/size.yml +174 -0
- data/spec/integration/matcher_operator_data/type.yml +70 -0
- data/spec/integration/matcher_operator_data/type_array.yml +16 -0
- data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
- data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
- data/spec/integration/matcher_operator_data/type_code.yml +26 -0
- data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
- data/spec/integration/matcher_operator_data/type_date.yml +39 -0
- data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
- data/spec/integration/matcher_operator_data/type_decimal.yml +41 -0
- data/spec/integration/matcher_operator_data/type_double.yml +15 -0
- data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
- data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
- data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
- data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
- data/spec/integration/matcher_operator_data/type_null.yml +23 -0
- data/spec/integration/matcher_operator_data/type_object.yml +23 -0
- data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
- data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
- data/spec/integration/matcher_operator_data/type_string.yml +15 -0
- data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
- data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
- data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
- data/spec/integration/matcher_operator_spec.rb +122 -0
- data/spec/integration/matcher_spec.rb +283 -0
- data/spec/integration/persistence/range_field_spec.rb +350 -0
- data/spec/integration/server_query_spec.rb +141 -0
- data/spec/integration/shardable_spec.rb +148 -0
- data/spec/integration/stringified_symbol_field_spec.rb +203 -0
- data/spec/lite_spec_helper.rb +83 -0
- data/spec/mongoid/association/accessors_spec.rb +284 -77
- data/spec/mongoid/association/auto_save_spec.rb +74 -33
- data/spec/mongoid/association/builders_spec.rb +3 -1
- data/spec/mongoid/association/constrainable_spec.rb +2 -0
- data/spec/mongoid/association/counter_cache_spec.rb +35 -33
- data/spec/mongoid/association/depending_spec.rb +431 -338
- data/spec/mongoid/association/eager_spec.rb +8 -5
- data/spec/mongoid/association/embedded/cyclic_spec.rb +4 -2
- data/spec/mongoid/association/embedded/dirty_spec.rb +4 -2
- data/spec/mongoid/association/embedded/embedded_in/binding_spec.rb +4 -1
- data/spec/mongoid/association/embedded/embedded_in/buildable_spec.rb +56 -0
- data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +152 -13
- data/spec/mongoid/association/embedded/embedded_in_spec.rb +61 -1
- data/spec/mongoid/association/embedded/embeds_many/binding_spec.rb +2 -0
- data/spec/mongoid/association/embedded/embeds_many/buildable_spec.rb +114 -0
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +706 -197
- data/spec/mongoid/association/embedded/embeds_many_models.rb +227 -0
- data/spec/mongoid/association/embedded/embeds_many_query_spec.rb +63 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +81 -1
- data/spec/mongoid/association/embedded/embeds_one/binding_spec.rb +2 -0
- data/spec/mongoid/association/embedded/embeds_one/buildable_spec.rb +27 -0
- data/spec/mongoid/association/embedded/embeds_one/proxy_spec.rb +38 -23
- data/spec/mongoid/association/embedded/embeds_one_dnl_models.rb +8 -0
- data/spec/mongoid/association/embedded/embeds_one_models.rb +73 -0
- data/spec/mongoid/association/embedded/embeds_one_query_spec.rb +28 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +77 -1
- data/spec/mongoid/association/macros_spec.rb +11 -9
- data/spec/mongoid/association/nested/many_spec.rb +2 -0
- data/spec/mongoid/association/nested/one_spec.rb +18 -12
- data/spec/mongoid/association/options_spec.rb +2 -0
- data/spec/mongoid/association/polymorphic_spec.rb +2 -0
- data/spec/mongoid/association/referenced/belongs_to/binding_spec.rb +4 -1
- data/spec/mongoid/association/referenced/belongs_to/buildable_spec.rb +111 -16
- data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +266 -17
- data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +114 -58
- data/spec/mongoid/association/referenced/belongs_to_models.rb +11 -0
- data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +57 -0
- data/spec/mongoid/association/referenced/belongs_to_spec.rb +96 -29
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +3 -1
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/buildable_spec.rb +28 -1
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/eager_spec.rb +67 -4
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_persistence_spec.rb +76 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +559 -385
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_models.rb +92 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_query_spec.rb +39 -0
- data/spec/mongoid/association/referenced/has_and_belongs_to_many_spec.rb +84 -7
- data/spec/mongoid/association/referenced/has_many/binding_spec.rb +3 -1
- data/spec/mongoid/association/referenced/has_many/buildable_spec.rb +132 -0
- data/spec/mongoid/association/referenced/has_many/eager_spec.rb +40 -9
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +415 -129
- data/spec/mongoid/association/referenced/has_many/proxy_query_spec.rb +23 -0
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +859 -502
- data/spec/mongoid/association/referenced/has_many_models.rb +97 -0
- data/spec/mongoid/association/referenced/has_many_query_spec.rb +37 -0
- data/spec/mongoid/association/referenced/has_many_spec.rb +51 -3
- data/spec/mongoid/association/referenced/has_one/binding_spec.rb +2 -0
- data/spec/mongoid/association/referenced/has_one/buildable_spec.rb +55 -9
- data/spec/mongoid/association/referenced/has_one/eager_spec.rb +34 -4
- data/spec/mongoid/association/referenced/has_one/proxy_spec.rb +135 -27
- data/spec/mongoid/association/referenced/has_one_models.rb +113 -0
- data/spec/mongoid/association/referenced/has_one_query_spec.rb +37 -0
- data/spec/mongoid/association/referenced/has_one_spec.rb +87 -7
- data/spec/mongoid/association/reflections_spec.rb +2 -0
- data/spec/mongoid/association/syncable_spec.rb +48 -32
- data/spec/mongoid/association_spec.rb +2 -0
- data/spec/mongoid/atomic/modifiers_spec.rb +49 -0
- data/spec/mongoid/atomic/paths/embedded/many_spec.rb +2 -0
- data/spec/mongoid/atomic/paths/embedded/one_spec.rb +2 -0
- data/spec/mongoid/atomic/paths/root_spec.rb +2 -0
- data/spec/mongoid/atomic/paths_spec.rb +93 -12
- data/spec/mongoid/atomic_spec.rb +53 -6
- data/spec/mongoid/attributes/dynamic_spec.rb +152 -0
- data/spec/mongoid/attributes/nested_spec.rb +149 -78
- data/spec/mongoid/attributes/nested_spec_models.rb +48 -0
- data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
- data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
- data/spec/mongoid/attributes/projector_spec.rb +40 -0
- data/spec/mongoid/attributes/readonly_spec.rb +24 -22
- data/spec/mongoid/attributes_spec.rb +895 -54
- data/spec/mongoid/cacheable_spec.rb +6 -4
- data/spec/mongoid/changeable_spec.rb +484 -67
- data/spec/mongoid/clients/factory_spec.rb +139 -33
- data/spec/mongoid/clients/options_spec.rb +76 -54
- data/spec/mongoid/clients/sessions_spec.rb +35 -63
- data/spec/mongoid/clients/transactions_spec.rb +87 -41
- data/spec/mongoid/clients_spec.rb +257 -31
- data/spec/mongoid/collection_configurable_spec.rb +158 -0
- data/spec/mongoid/composable_spec.rb +2 -0
- data/spec/mongoid/config/defaults_spec.rb +160 -0
- data/spec/mongoid/config/environment_spec.rb +126 -8
- data/spec/mongoid/config/options_spec.rb +22 -3
- data/spec/mongoid/config_spec.rb +507 -2
- data/spec/mongoid/contextual/aggregable/memory_spec.rb +433 -153
- 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/aggregable/mongo_spec.rb +122 -20
- data/spec/mongoid/contextual/aggregable/none_spec.rb +60 -0
- data/spec/mongoid/contextual/atomic_spec.rb +242 -81
- data/spec/mongoid/contextual/geo_near_spec.rb +31 -19
- data/spec/mongoid/contextual/map_reduce_spec.rb +22 -19
- data/spec/mongoid/contextual/memory_spec.rb +1828 -303
- data/spec/mongoid/contextual/mongo/documents_loader_spec.rb +187 -0
- data/spec/mongoid/contextual/mongo_spec.rb +3505 -1268
- data/spec/mongoid/contextual/none_spec.rb +80 -67
- data/spec/mongoid/copyable_spec.rb +697 -40
- data/spec/mongoid/copyable_spec_models.rb +47 -0
- data/spec/mongoid/criteria/findable_spec.rb +161 -228
- data/spec/mongoid/criteria/includable_spec.rb +1492 -0
- data/spec/mongoid/criteria/includable_spec_models.rb +54 -0
- data/spec/mongoid/criteria/inspectable_spec.rb +2 -0
- data/spec/mongoid/criteria/marshalable_spec.rb +20 -1
- data/spec/mongoid/criteria/modifiable_spec.rb +100 -48
- data/spec/mongoid/criteria/options_spec.rb +2 -0
- data/spec/mongoid/criteria/queryable/aggregable_spec.rb +3 -1
- data/spec/mongoid/criteria/queryable/expandable_spec.rb +61 -0
- data/spec/mongoid/criteria/queryable/extensions/array_spec.rb +9 -19
- data/spec/mongoid/criteria/queryable/extensions/big_decimal_spec.rb +136 -26
- data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +3 -1
- data/spec/mongoid/criteria/queryable/extensions/date_spec.rb +13 -0
- data/spec/mongoid/criteria/queryable/extensions/date_time_spec.rb +46 -17
- data/spec/mongoid/criteria/queryable/extensions/float_spec.rb +2 -0
- data/spec/mongoid/criteria/queryable/extensions/hash_spec.rb +2 -15
- data/spec/mongoid/criteria/queryable/extensions/integer_spec.rb +2 -0
- data/spec/mongoid/criteria/queryable/extensions/nil_class_spec.rb +2 -0
- data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +119 -0
- data/spec/mongoid/criteria/queryable/extensions/object_spec.rb +2 -0
- data/spec/mongoid/criteria/queryable/extensions/range_spec.rb +239 -178
- data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +3 -1
- data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +9 -7
- data/spec/mongoid/criteria/queryable/extensions/set_spec.rb +2 -0
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +7 -70
- data/spec/mongoid/criteria/queryable/extensions/symbol_spec.rb +2 -59
- data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +53 -23
- data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +41 -1
- data/spec/mongoid/criteria/queryable/key_spec.rb +50 -6
- data/spec/mongoid/criteria/queryable/mergeable_spec.rb +145 -12
- data/spec/mongoid/criteria/queryable/optional_spec.rb +18 -485
- data/spec/mongoid/criteria/queryable/options_spec.rb +3 -1
- data/spec/mongoid/criteria/queryable/pipeline_spec.rb +2 -0
- data/spec/mongoid/criteria/queryable/queryable_spec.rb +3 -1
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +2538 -0
- data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +38 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +1193 -2934
- data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +589 -0
- data/spec/mongoid/criteria/queryable/selector_spec.rb +56 -5
- data/spec/mongoid/criteria/queryable/smash_spec.rb +2 -0
- data/spec/mongoid/criteria/queryable/storable_spec.rb +226 -0
- data/spec/mongoid/criteria/scopable_spec.rb +210 -0
- data/spec/mongoid/criteria/translator_spec.rb +132 -0
- data/spec/mongoid/criteria_projection_spec.rb +406 -0
- data/spec/mongoid/criteria_spec.rb +1334 -1719
- data/spec/mongoid/document_fields_spec.rb +262 -0
- data/spec/mongoid/document_persistence_context_spec.rb +32 -0
- data/spec/mongoid/document_query_spec.rb +89 -0
- data/spec/mongoid/document_spec.rb +212 -67
- data/spec/mongoid/equality_spec.rb +144 -41
- data/spec/mongoid/errors/ambiguous_relationship_spec.rb +5 -3
- data/spec/mongoid/errors/callback_spec.rb +2 -0
- data/spec/mongoid/errors/delete_restriction_spec.rb +4 -2
- data/spec/mongoid/errors/document_not_destroyed_spec.rb +2 -0
- data/spec/mongoid/errors/document_not_found_spec.rb +78 -0
- data/spec/mongoid/errors/invalid_collection_spec.rb +2 -0
- data/spec/mongoid/errors/{eager_load_spec.rb → invalid_config_file_spec.rb} +7 -5
- data/spec/mongoid/errors/invalid_config_option_spec.rb +2 -0
- data/spec/mongoid/errors/invalid_field_option_spec.rb +2 -0
- data/spec/mongoid/errors/invalid_field_spec.rb +3 -1
- data/spec/mongoid/errors/invalid_field_type_spec.rb +55 -0
- data/spec/mongoid/errors/invalid_find_spec.rb +2 -0
- data/spec/mongoid/errors/invalid_includes_spec.rb +2 -0
- data/spec/mongoid/errors/invalid_index_spec.rb +2 -0
- data/spec/mongoid/errors/invalid_options_spec.rb +4 -2
- data/spec/mongoid/errors/invalid_path_spec.rb +2 -0
- data/spec/mongoid/errors/invalid_relation_spec.rb +4 -2
- data/spec/mongoid/errors/invalid_scope_spec.rb +3 -1
- data/spec/mongoid/errors/invalid_set_polymorphic_relation_spec.rb +2 -0
- data/spec/mongoid/errors/invalid_storage_options_spec.rb +2 -0
- data/spec/mongoid/errors/invalid_time_spec.rb +2 -0
- data/spec/mongoid/errors/inverse_not_found_spec.rb +3 -1
- data/spec/mongoid/errors/mixed_client_configuration_spec.rb +2 -0
- data/spec/mongoid/errors/mixed_relations_spec.rb +2 -0
- data/spec/mongoid/errors/mongoid_error_spec.rb +24 -8
- data/spec/mongoid/errors/nested_attributes_metadata_not_found_spec.rb +5 -3
- data/spec/mongoid/errors/no_client_config_spec.rb +4 -2
- data/spec/mongoid/errors/no_client_database_spec.rb +5 -3
- data/spec/mongoid/errors/no_client_hosts_spec.rb +5 -3
- data/spec/mongoid/errors/no_clients_config_spec.rb +2 -0
- data/spec/mongoid/errors/no_environment_spec.rb +5 -3
- data/spec/mongoid/errors/no_map_reduce_output_spec.rb +2 -0
- data/spec/mongoid/errors/no_metadata_spec.rb +4 -2
- data/spec/mongoid/errors/no_parent_spec.rb +3 -1
- data/spec/mongoid/errors/readonly_attribute_spec.rb +2 -0
- data/spec/mongoid/errors/readonly_document_spec.rb +4 -2
- data/spec/mongoid/errors/scope_overwrite_spec.rb +2 -0
- data/spec/mongoid/errors/too_many_nested_attribute_records_spec.rb +3 -1
- data/spec/mongoid/errors/unknown_attribute_spec.rb +4 -2
- data/spec/mongoid/errors/unsaved_document_spec.rb +3 -1
- data/spec/mongoid/errors/unsupported_javascript_spec.rb +2 -0
- data/spec/mongoid/errors/validations_spec.rb +2 -0
- data/spec/mongoid/extensions/array_spec.rb +41 -45
- data/spec/mongoid/extensions/big_decimal_spec.rb +715 -213
- data/spec/mongoid/extensions/binary_spec.rb +46 -9
- data/spec/mongoid/extensions/boolean_spec.rb +70 -82
- data/spec/mongoid/extensions/date_class_mongoize_spec.rb +339 -0
- data/spec/mongoid/extensions/date_spec.rb +58 -140
- data/spec/mongoid/extensions/date_time_spec.rb +32 -69
- data/spec/mongoid/extensions/decimal128_spec.rb +2 -0
- data/spec/mongoid/extensions/false_class_spec.rb +3 -1
- data/spec/mongoid/extensions/float_spec.rb +66 -73
- data/spec/mongoid/extensions/hash_spec.rb +135 -0
- data/spec/mongoid/extensions/integer_spec.rb +61 -63
- data/spec/mongoid/extensions/module_spec.rb +2 -0
- data/spec/mongoid/extensions/nil_class_spec.rb +2 -0
- data/spec/mongoid/extensions/object_id_spec.rb +2 -0
- data/spec/mongoid/extensions/object_spec.rb +13 -24
- data/spec/mongoid/extensions/range_spec.rb +257 -54
- data/spec/mongoid/extensions/regexp_spec.rb +70 -20
- data/spec/mongoid/extensions/set_spec.rb +108 -0
- data/spec/mongoid/extensions/string_spec.rb +146 -57
- data/spec/mongoid/extensions/stringified_symbol_spec.rb +84 -0
- data/spec/mongoid/extensions/symbol_spec.rb +20 -25
- data/spec/mongoid/extensions/time_spec.rb +668 -106
- data/spec/mongoid/extensions/time_with_zone_spec.rb +57 -83
- data/spec/mongoid/extensions/true_class_spec.rb +3 -1
- data/spec/mongoid/extensions_spec.rb +16 -2
- data/spec/mongoid/factory_spec.rb +347 -27
- data/spec/mongoid/fields/foreign_key_spec.rb +2 -0
- data/spec/mongoid/fields/localized_spec.rb +86 -41
- data/spec/mongoid/fields/standard_spec.rb +2 -0
- data/spec/mongoid/fields_spec.rb +869 -114
- data/spec/mongoid/findable_spec.rb +521 -65
- data/spec/mongoid/indexable/specification_spec.rb +4 -2
- data/spec/mongoid/indexable_spec.rb +87 -32
- data/spec/mongoid/inspectable_spec.rb +39 -2
- data/spec/mongoid/interceptable_spec.rb +761 -98
- data/spec/mongoid/interceptable_spec_models.rb +307 -0
- data/spec/mongoid/loggable_spec.rb +2 -0
- data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
- data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +239 -0
- data/spec/mongoid/matcher/extract_attribute_spec.rb +36 -0
- data/spec/mongoid/mongoizable_spec.rb +285 -0
- data/spec/mongoid/persistable/creatable_spec.rb +114 -29
- data/spec/mongoid/persistable/deletable_spec.rb +300 -18
- data/spec/mongoid/persistable/destroyable_spec.rb +228 -18
- data/spec/mongoid/persistable/incrementable_spec.rb +66 -13
- data/spec/mongoid/persistable/logical_spec.rb +56 -3
- data/spec/mongoid/persistable/poppable_spec.rb +55 -3
- data/spec/mongoid/persistable/pullable_spec.rb +108 -6
- data/spec/mongoid/persistable/pushable_spec.rb +163 -7
- data/spec/mongoid/persistable/renamable_spec.rb +54 -2
- data/spec/mongoid/persistable/savable_spec.rb +284 -25
- data/spec/mongoid/persistable/settable_spec.rb +91 -8
- data/spec/mongoid/persistable/unsettable_spec.rb +55 -3
- data/spec/mongoid/persistable/updatable_spec.rb +63 -49
- data/spec/mongoid/persistable/upsertable_spec.rb +93 -3
- data/spec/mongoid/persistable_spec.rb +85 -9
- data/spec/mongoid/persistence_context_spec.rb +60 -59
- data/spec/mongoid/positional_spec.rb +2 -0
- data/spec/mongoid/query_cache_middleware_spec.rb +50 -0
- data/spec/mongoid/query_cache_spec.rb +446 -78
- data/spec/mongoid/relations/proxy_spec.rb +9 -7
- data/spec/mongoid/reloadable_spec.rb +381 -26
- data/spec/mongoid/scopable_spec.rb +206 -38
- data/spec/mongoid/selectable_spec.rb +8 -6
- data/spec/mongoid/serializable_spec.rb +148 -38
- data/spec/mongoid/shardable_models.rb +75 -0
- data/spec/mongoid/shardable_spec.rb +239 -34
- data/spec/mongoid/stateful_spec.rb +153 -9
- data/spec/mongoid/tasks/database_rake_spec.rb +89 -13
- data/spec/mongoid/tasks/database_spec.rb +130 -1
- data/spec/mongoid/threaded_spec.rb +72 -2
- data/spec/mongoid/timestamps/created/short_spec.rb +3 -1
- data/spec/mongoid/timestamps/created_spec.rb +3 -1
- data/spec/mongoid/timestamps/timeless_spec.rb +4 -2
- data/spec/mongoid/timestamps/updated/short_spec.rb +5 -3
- data/spec/mongoid/timestamps/updated_spec.rb +5 -3
- data/spec/mongoid/timestamps_spec.rb +400 -10
- data/spec/mongoid/timestamps_spec_models.rb +67 -0
- data/spec/mongoid/touchable_spec.rb +568 -33
- data/spec/mongoid/touchable_spec_models.rb +59 -0
- data/spec/mongoid/traversable_spec.rb +1145 -1
- data/spec/mongoid/validatable/associated_spec.rb +2 -0
- data/spec/mongoid/validatable/format_spec.rb +2 -0
- data/spec/mongoid/validatable/length_spec.rb +2 -0
- data/spec/mongoid/validatable/numericality_spec.rb +2 -0
- data/spec/mongoid/validatable/presence_spec.rb +28 -22
- data/spec/mongoid/validatable/uniqueness_spec.rb +159 -103
- data/spec/mongoid/validatable_spec.rb +5 -3
- data/spec/mongoid/warnings_spec.rb +35 -0
- data/spec/mongoid_spec.rb +36 -10
- data/spec/rails/controller_extension/controller_runtime_spec.rb +112 -0
- data/spec/rails/mongoid_spec.rb +8 -18
- data/spec/shared/LICENSE +20 -0
- data/spec/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/bin/s3-copy +45 -0
- data/spec/shared/bin/s3-upload +69 -0
- data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
- data/spec/shared/lib/mrss/cluster_config.rb +231 -0
- data/spec/shared/lib/mrss/constraints.rb +378 -0
- data/spec/shared/lib/mrss/docker_runner.rb +298 -0
- data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
- data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
- data/spec/shared/lib/mrss/session_registry.rb +69 -0
- data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
- data/spec/shared/lib/mrss/utils.rb +37 -0
- data/spec/shared/share/Dockerfile.erb +321 -0
- data/spec/shared/share/haproxy-1.conf +16 -0
- data/spec/shared/share/haproxy-2.conf +17 -0
- data/spec/shared/shlib/config.sh +27 -0
- data/spec/shared/shlib/distro.sh +74 -0
- data/spec/shared/shlib/server.sh +416 -0
- data/spec/shared/shlib/set_env.sh +169 -0
- data/spec/spec_helper.rb +74 -88
- data/spec/support/authorization.rb +2 -0
- data/spec/support/client_registry.rb +9 -0
- data/spec/support/constraints.rb +77 -0
- data/spec/support/expectations.rb +21 -3
- data/spec/support/helpers.rb +11 -0
- data/spec/support/immutable_ids.rb +118 -0
- data/spec/support/macros.rb +129 -0
- data/spec/{app → support}/models/account.rb +3 -1
- data/spec/{app → support}/models/acolyte.rb +2 -0
- data/spec/{app → support}/models/actor.rb +3 -1
- data/spec/support/models/actress.rb +4 -0
- data/spec/{app → support}/models/address.rb +6 -0
- data/spec/{app → support}/models/address_component.rb +2 -0
- data/spec/{app → support}/models/address_number.rb +2 -0
- data/spec/{app → support}/models/agency.rb +2 -0
- data/spec/{app → support}/models/agent.rb +2 -0
- data/spec/{app → support}/models/album.rb +2 -0
- data/spec/{app → support}/models/alert.rb +2 -0
- data/spec/{app → support}/models/animal.rb +2 -0
- data/spec/{app → support}/models/answer.rb +2 -0
- data/spec/{app → support}/models/appointment.rb +2 -0
- data/spec/support/models/armrest.rb +9 -0
- data/spec/{app → support}/models/article.rb +2 -0
- data/spec/{app → support}/models/artist.rb +4 -1
- data/spec/{app → support}/models/artwork.rb +2 -0
- data/spec/support/models/audible_sound.rb +3 -0
- data/spec/{app → support}/models/audio.rb +2 -0
- data/spec/support/models/augmentation.rb +25 -0
- data/spec/{app → support}/models/author.rb +2 -0
- data/spec/{app → support}/models/baby.rb +2 -0
- data/spec/{app → support}/models/band.rb +10 -0
- data/spec/{app → support}/models/bar.rb +2 -0
- data/spec/{app → support}/models/basic.rb +2 -0
- data/spec/support/models/bed.rb +3 -0
- data/spec/{app → support}/models/big_palette.rb +2 -0
- data/spec/{app → support}/models/birthday.rb +2 -0
- data/spec/support/models/bolt.rb +7 -0
- data/spec/{app → support}/models/bomb.rb +2 -0
- data/spec/{app → support}/models/book.rb +3 -0
- data/spec/{app → support}/models/breed.rb +2 -0
- data/spec/{app → support}/models/browser.rb +3 -1
- data/spec/{app → support}/models/building.rb +4 -0
- data/spec/{app → support}/models/building_address.rb +2 -0
- data/spec/{app → support}/models/bus.rb +2 -0
- data/spec/{app → support}/models/business.rb +2 -0
- data/spec/{app → support}/models/callback_test.rb +2 -0
- data/spec/{app → support}/models/canvas.rb +3 -1
- data/spec/support/models/car.rb +3 -0
- data/spec/{app → support}/models/cat.rb +2 -0
- data/spec/support/models/catalog.rb +24 -0
- data/spec/{app → support}/models/category.rb +2 -0
- data/spec/{app → support}/models/child.rb +2 -0
- data/spec/{app → support}/models/child_doc.rb +5 -3
- data/spec/{app → support}/models/church.rb +2 -0
- data/spec/{app → support}/models/circle.rb +2 -0
- data/spec/{app → support}/models/circuit.rb +2 -0
- data/spec/support/models/circus.rb +12 -0
- data/spec/{app → support}/models/code.rb +4 -0
- data/spec/support/models/coding/pull_request.rb +11 -0
- data/spec/support/models/coding.rb +3 -0
- data/spec/{app → support}/models/comment.rb +2 -0
- data/spec/{app → support}/models/company.rb +2 -0
- data/spec/{app → support}/models/consumption_period.rb +2 -0
- data/spec/{app → support}/models/contextable_item.rb +2 -0
- data/spec/{app → support}/models/contractor.rb +2 -0
- data/spec/{app → support}/models/cookie.rb +2 -0
- data/spec/{app → support}/models/country_code.rb +4 -0
- data/spec/{app → support}/models/courier_job.rb +2 -0
- data/spec/support/models/cover.rb +10 -0
- data/spec/support/models/crate.rb +12 -0
- data/spec/support/models/customer.rb +10 -0
- data/spec/support/models/customer_address.rb +11 -0
- data/spec/support/models/deed.rb +7 -0
- data/spec/{app → support}/models/definition.rb +2 -0
- data/spec/support/models/delegating_patient.rb +15 -0
- data/spec/{app → support}/models/description.rb +2 -0
- data/spec/{app → support}/models/dictionary.rb +8 -0
- data/spec/{app → support}/models/division.rb +2 -0
- data/spec/{app → support}/models/doctor.rb +2 -0
- data/spec/{app → support}/models/dog.rb +2 -0
- data/spec/{app → support}/models/dokument.rb +2 -0
- data/spec/{app → support}/models/draft.rb +2 -0
- data/spec/{app → support}/models/dragon.rb +2 -0
- data/spec/{app → support}/models/driver.rb +3 -1
- data/spec/{app → support}/models/drug.rb +2 -0
- data/spec/{app → support}/models/dungeon.rb +2 -0
- data/spec/{app → support}/models/edit.rb +2 -0
- data/spec/{app → support}/models/email.rb +2 -0
- data/spec/{app → support}/models/employer.rb +2 -0
- data/spec/{app → support}/models/entry.rb +2 -0
- data/spec/support/models/eraser.rb +3 -0
- data/spec/{app → support}/models/even.rb +2 -0
- data/spec/{app → support}/models/event.rb +2 -0
- data/spec/{app → support}/models/exhibition.rb +2 -0
- data/spec/{app → support}/models/exhibitor.rb +2 -0
- data/spec/{app → support}/models/explosion.rb +2 -0
- data/spec/{app → support}/models/eye.rb +2 -0
- data/spec/{app → support}/models/eye_bowl.rb +2 -0
- data/spec/{app → support}/models/face.rb +2 -0
- data/spec/support/models/fanatic.rb +8 -0
- data/spec/{app → support}/models/favorite.rb +2 -0
- data/spec/{app → support}/models/filesystem.rb +2 -0
- data/spec/{app → support}/models/fire_hydrant.rb +2 -0
- data/spec/{app → support}/models/firefox.rb +2 -0
- data/spec/{app → support}/models/fish.rb +2 -0
- data/spec/{app → support}/models/folder.rb +2 -0
- data/spec/{app → support}/models/folder_item.rb +2 -0
- data/spec/{app → support}/models/fruits.rb +2 -0
- data/spec/{app → support}/models/game.rb +2 -0
- data/spec/{app → support}/models/ghost.rb +2 -0
- data/spec/support/models/guitar.rb +4 -0
- data/spec/support/models/hole.rb +12 -0
- data/spec/{app → support}/models/home.rb +2 -0
- data/spec/{app → support}/models/house.rb +2 -0
- data/spec/{app → support}/models/html_writer.rb +2 -0
- data/spec/{app → support}/models/id_key.rb +2 -0
- data/spec/support/models/idnodef.rb +7 -0
- data/spec/{app → support}/models/image.rb +2 -0
- data/spec/{app → support}/models/implant.rb +11 -0
- data/spec/support/models/instrument.rb +8 -0
- data/spec/{app → support}/models/item.rb +3 -1
- data/spec/{app → support}/models/jar.rb +2 -0
- data/spec/{app → support}/models/kaleidoscope.rb +2 -0
- data/spec/{app → support}/models/kangaroo.rb +3 -1
- data/spec/{app → support}/models/label.rb +6 -1
- data/spec/{app → support}/models/language.rb +2 -0
- data/spec/{app → support}/models/lat_lng.rb +2 -0
- data/spec/{app → support}/models/league.rb +2 -0
- data/spec/support/models/learner.rb +4 -0
- data/spec/{app → support}/models/line_item.rb +2 -0
- data/spec/{app → support}/models/location.rb +2 -0
- data/spec/{app → support}/models/login.rb +2 -0
- data/spec/{app → support}/models/manufacturer.rb +2 -0
- data/spec/{app → support}/models/meat.rb +2 -0
- data/spec/{app → support}/models/membership.rb +3 -0
- data/spec/{app → support}/models/message.rb +2 -0
- data/spec/support/models/minim.rb +6 -0
- data/spec/{app → support}/models/mixed_drink.rb +2 -0
- data/spec/support/models/mop.rb +24 -0
- data/spec/{app → support}/models/movie.rb +2 -0
- data/spec/support/models/my_hash.rb +4 -0
- data/spec/{app → support}/models/name.rb +2 -0
- data/spec/support/models/name_only.rb +8 -0
- data/spec/{app → support}/models/node.rb +2 -0
- data/spec/{app → support}/models/note.rb +2 -0
- data/spec/support/models/nut.rb +7 -0
- data/spec/{app → support}/models/odd.rb +2 -0
- data/spec/support/models/order.rb +12 -0
- data/spec/{app → support}/models/ordered_post.rb +3 -1
- data/spec/{app → support}/models/ordered_preference.rb +2 -0
- data/spec/{app → support}/models/oscar.rb +2 -0
- data/spec/support/models/other_owner_object.rb +4 -0
- data/spec/{app → support}/models/override.rb +2 -0
- data/spec/{app → support}/models/ownable.rb +2 -0
- data/spec/{app → support}/models/owner.rb +4 -0
- data/spec/{app → support}/models/pack.rb +2 -0
- data/spec/{app → support}/models/page.rb +2 -0
- data/spec/{app → support}/models/page_question.rb +2 -0
- data/spec/{app → support}/models/palette.rb +3 -1
- data/spec/{app → support}/models/parent.rb +2 -0
- data/spec/{app → support}/models/parent_doc.rb +2 -0
- data/spec/support/models/passport.rb +22 -0
- data/spec/{app → support}/models/patient.rb +2 -0
- data/spec/{app → support}/models/pdf_writer.rb +2 -0
- data/spec/support/models/pencil.rb +3 -0
- data/spec/{app → support}/models/person.rb +22 -1
- data/spec/{app → support}/models/pet.rb +2 -0
- data/spec/{app → support}/models/pet_owner.rb +2 -0
- data/spec/{app → support}/models/phone.rb +5 -1
- data/spec/support/models/piano.rb +4 -0
- data/spec/{app → support}/models/pizza.rb +2 -0
- data/spec/{app → support}/models/player.rb +4 -0
- data/spec/{app → support}/models/post.rb +2 -0
- data/spec/{app → support}/models/post_genre.rb +2 -0
- data/spec/support/models/powerup.rb +25 -0
- data/spec/{app → support}/models/preference.rb +2 -0
- data/spec/{app → support}/models/princess.rb +2 -0
- data/spec/{app → support}/models/product.rb +3 -0
- data/spec/support/models/profile.rb +17 -0
- data/spec/{app → support}/models/pronunciation.rb +2 -0
- data/spec/{app → support}/models/pub.rb +2 -0
- data/spec/support/models/publication/encyclopedia.rb +11 -0
- data/spec/support/models/publication/review.rb +13 -0
- data/spec/support/models/publication.rb +4 -0
- data/spec/{app → support}/models/purchase.rb +2 -0
- data/spec/support/models/purchased_item.rb +10 -0
- data/spec/{app → support}/models/question.rb +2 -0
- data/spec/{app → support}/models/quiz.rb +2 -0
- data/spec/{app → support}/models/rating.rb +2 -0
- data/spec/{app → support}/models/record.rb +2 -0
- data/spec/{app → support}/models/registry.rb +3 -0
- data/spec/{app → support}/models/role.rb +2 -0
- data/spec/{app → support}/models/root_category.rb +2 -0
- data/spec/{app → support}/models/sandwich.rb +2 -0
- data/spec/{app → support}/models/scheduler.rb +2 -0
- data/spec/support/models/school.rb +14 -0
- data/spec/support/models/scribe.rb +7 -0
- data/spec/support/models/sealer.rb +7 -0
- data/spec/support/models/seat.rb +24 -0
- data/spec/{app → support}/models/seo.rb +2 -0
- data/spec/support/models/series.rb +7 -0
- data/spec/{app → support}/models/server.rb +2 -0
- data/spec/{app → support}/models/service.rb +2 -0
- data/spec/{app → support}/models/shape.rb +4 -2
- data/spec/{app → support}/models/shelf.rb +2 -0
- data/spec/support/models/shield.rb +18 -0
- data/spec/{app → support}/models/shipment_address.rb +2 -0
- data/spec/{app → support}/models/shipping_container.rb +2 -0
- data/spec/{app → support}/models/shipping_pack.rb +2 -0
- data/spec/support/models/shirt.rb +11 -0
- data/spec/{app → support}/models/shop.rb +2 -0
- data/spec/{app → support}/models/short_agent.rb +2 -0
- data/spec/{app → support}/models/short_quiz.rb +2 -0
- data/spec/{app → support}/models/simple.rb +2 -0
- data/spec/{app → support}/models/slave.rb +2 -0
- data/spec/{app → support}/models/song.rb +2 -0
- data/spec/{app → support}/models/sound.rb +2 -0
- data/spec/support/models/spacer.rb +7 -0
- data/spec/{app → support}/models/square.rb +2 -0
- data/spec/{app → support}/models/staff.rb +2 -0
- data/spec/{app → support}/models/store_as_dup_test1.rb +2 -0
- data/spec/{app → support}/models/store_as_dup_test2.rb +2 -0
- data/spec/support/models/store_as_dup_test3.rb +7 -0
- data/spec/support/models/store_as_dup_test4.rb +7 -0
- data/spec/{app → support}/models/strategy.rb +2 -0
- data/spec/support/models/student.rb +14 -0
- data/spec/{app → support}/models/sub_item.rb +2 -0
- data/spec/{app → support}/models/subscription.rb +2 -0
- data/spec/{app → support}/models/survey.rb +2 -0
- data/spec/{app → support}/models/symptom.rb +2 -0
- data/spec/support/models/system_role.rb +7 -0
- data/spec/{app → support}/models/tag.rb +2 -0
- data/spec/{app → support}/models/target.rb +2 -0
- data/spec/{app → support}/models/template.rb +2 -0
- data/spec/{app → support}/models/thing.rb +2 -0
- data/spec/support/models/threadlocker.rb +7 -0
- data/spec/{app → support}/models/title.rb +2 -0
- data/spec/{app → support}/models/tool.rb +4 -2
- data/spec/{app → support}/models/topping.rb +2 -0
- data/spec/support/models/toy.rb +9 -0
- data/spec/{app → support}/models/track.rb +2 -0
- data/spec/{app → support}/models/translation.rb +2 -0
- data/spec/{app → support}/models/tree.rb +2 -0
- data/spec/support/models/truck.rb +7 -0
- data/spec/{app → support}/models/user.rb +2 -0
- data/spec/{app → support}/models/user_account.rb +2 -0
- data/spec/{app → support}/models/validation_callback.rb +2 -0
- data/spec/support/models/vehicle.rb +18 -0
- data/spec/{app → support}/models/version.rb +2 -0
- data/spec/{app → support}/models/vertex.rb +3 -1
- data/spec/{app → support}/models/vet_visit.rb +2 -0
- data/spec/{app → support}/models/video.rb +2 -0
- data/spec/support/models/video_game.rb +3 -0
- data/spec/support/models/washer.rb +7 -0
- data/spec/support/models/weapon.rb +25 -0
- data/spec/{app → support}/models/wiki_page.rb +3 -0
- data/spec/{app → support}/models/word.rb +2 -0
- data/spec/{app → support}/models/word_origin.rb +2 -0
- data/spec/{app → support}/models/writer.rb +4 -2
- data/spec/support/schema_maps/schema_map_aws.json +17 -0
- data/spec/support/schema_maps/schema_map_aws_key_alt_names.json +12 -0
- data/spec/support/schema_maps/schema_map_azure.json +17 -0
- data/spec/support/schema_maps/schema_map_azure_key_alt_names.json +12 -0
- data/spec/support/schema_maps/schema_map_gcp.json +17 -0
- data/spec/support/schema_maps/schema_map_gcp_key_alt_names.json +12 -0
- data/spec/support/schema_maps/schema_map_kmip.json +17 -0
- data/spec/support/schema_maps/schema_map_kmip_key_alt_names.json +12 -0
- data/spec/support/schema_maps/schema_map_local.json +18 -0
- data/spec/support/schema_maps/schema_map_local_key_alt_names.json +12 -0
- data/spec/support/shared/time.rb +53 -0
- data/spec/support/spec_config.rb +64 -0
- data.tar.gz.sig +1 -2
- metadata +1158 -615
- metadata.gz.sig +0 -0
- data/lib/mongoid/criteria/queryable/forwardable.rb +0 -65
- data/lib/mongoid/errors/eager_load.rb +0 -22
- data/lib/mongoid/errors/invalid_value.rb +0 -16
- data/lib/mongoid/matchable/all.rb +0 -27
- data/lib/mongoid/matchable/and.rb +0 -30
- data/lib/mongoid/matchable/default.rb +0 -72
- data/lib/mongoid/matchable/elem_match.rb +0 -34
- data/lib/mongoid/matchable/exists.rb +0 -23
- data/lib/mongoid/matchable/gt.rb +0 -23
- data/lib/mongoid/matchable/gte.rb +0 -23
- data/lib/mongoid/matchable/in.rb +0 -24
- data/lib/mongoid/matchable/lt.rb +0 -23
- data/lib/mongoid/matchable/lte.rb +0 -23
- data/lib/mongoid/matchable/ne.rb +0 -21
- data/lib/mongoid/matchable/nin.rb +0 -22
- data/lib/mongoid/matchable/nor.rb +0 -37
- data/lib/mongoid/matchable/or.rb +0 -33
- data/lib/mongoid/matchable/regexp.rb +0 -27
- data/lib/mongoid/matchable/size.rb +0 -21
- data/lib/support/ruby_version.rb +0 -26
- data/spec/app/models/actress.rb +0 -2
- data/spec/app/models/augmentation.rb +0 -11
- data/spec/app/models/bed.rb +0 -1
- data/spec/app/models/car.rb +0 -1
- data/spec/app/models/circus.rb +0 -7
- data/spec/app/models/eraser.rb +0 -1
- data/spec/app/models/learner.rb +0 -2
- data/spec/app/models/my_hash.rb +0 -2
- data/spec/app/models/passport.rb +0 -5
- data/spec/app/models/pencil.rb +0 -1
- data/spec/app/models/powerup.rb +0 -11
- data/spec/app/models/profile.rb +0 -5
- data/spec/app/models/series.rb +0 -4
- data/spec/app/models/truck.rb +0 -3
- data/spec/app/models/vehicle.rb +0 -11
- data/spec/app/models/video_game.rb +0 -1
- data/spec/app/models/weapon.rb +0 -11
- data/spec/mongoid/criteria/queryable/extensions/bignum_spec.rb +0 -58
- data/spec/mongoid/criteria/queryable/extensions/fixnum_spec.rb +0 -58
- data/spec/mongoid/criteria/queryable/forwardable_spec.rb +0 -87
- data/spec/mongoid/matchable/all_spec.rb +0 -31
- data/spec/mongoid/matchable/and_spec.rb +0 -187
- data/spec/mongoid/matchable/default_spec.rb +0 -130
- data/spec/mongoid/matchable/elem_match_spec.rb +0 -106
- data/spec/mongoid/matchable/exists_spec.rb +0 -57
- data/spec/mongoid/matchable/gt_spec.rb +0 -86
- data/spec/mongoid/matchable/gte_spec.rb +0 -84
- data/spec/mongoid/matchable/in_spec.rb +0 -49
- data/spec/mongoid/matchable/lt_spec.rb +0 -85
- data/spec/mongoid/matchable/lte_spec.rb +0 -85
- data/spec/mongoid/matchable/ne_spec.rb +0 -46
- data/spec/mongoid/matchable/nin_spec.rb +0 -48
- data/spec/mongoid/matchable/nor_spec.rb +0 -209
- data/spec/mongoid/matchable/or_spec.rb +0 -131
- data/spec/mongoid/matchable/regexp_spec.rb +0 -59
- data/spec/mongoid/matchable/size_spec.rb +0 -25
- data/spec/mongoid/matchable_spec.rb +0 -853
- /data/spec/{app → support}/models/array_field.rb +0 -0
- /data/spec/{app → support}/models/updatable.rb +0 -0
|
@@ -0,0 +1,2538 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe Mongoid::Criteria::Queryable::Selectable do
|
|
6
|
+
|
|
7
|
+
let(:query) do
|
|
8
|
+
Mongoid::Query.new("id" => "_id")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
shared_examples_for 'returns a cloned query' do
|
|
12
|
+
|
|
13
|
+
it "returns a cloned query" do
|
|
14
|
+
expect(selection).to_not equal(query)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Hoisting means the operator can be elided, for example
|
|
19
|
+
# Foo.and(a: 1) produces simply {'a' => 1}.
|
|
20
|
+
shared_examples_for 'a hoisting logical operation' do
|
|
21
|
+
|
|
22
|
+
let(:query) do
|
|
23
|
+
Mongoid::Query.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context "when provided a single criterion" do
|
|
27
|
+
|
|
28
|
+
shared_examples_for 'adds the conditions to top level' do
|
|
29
|
+
|
|
30
|
+
it "adds the conditions to top level" do
|
|
31
|
+
expect(selection.selector).to eq(
|
|
32
|
+
"field" => [ 1, 2 ]
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it_behaves_like 'returns a cloned query'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
let(:selection) do
|
|
40
|
+
query.send(tested_method, field: [ 1, 2 ])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it_behaves_like 'adds the conditions to top level'
|
|
44
|
+
|
|
45
|
+
context 'when the criterion is wrapped in an array' do
|
|
46
|
+
let(:selection) do
|
|
47
|
+
query.send(tested_method, [{field: [ 1, 2 ] }])
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it_behaves_like 'adds the conditions to top level'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context 'when the criterion is wrapped in a deep array with nil elements' do
|
|
54
|
+
let(:selection) do
|
|
55
|
+
query.send(tested_method, [[[{field: [ 1, 2 ] }]], [nil]])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it_behaves_like 'adds the conditions to top level'
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'when argument is a Criteria' do
|
|
63
|
+
let(:base) do
|
|
64
|
+
query.where(hello: 'world')
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
let(:other) do
|
|
68
|
+
query.where(foo: 'bar')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
let(:result) { base.send(tested_method, other) }
|
|
72
|
+
|
|
73
|
+
it 'combines' do
|
|
74
|
+
expect(result.selector).to eq(
|
|
75
|
+
'hello' => 'world',
|
|
76
|
+
'foo' => 'bar',
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context "when provided a single criterion that is handled via Key" do
|
|
82
|
+
|
|
83
|
+
shared_examples_for 'adds the conditions to top level' do
|
|
84
|
+
|
|
85
|
+
it "adds the conditions to top level" do
|
|
86
|
+
expect(selection.selector).to eq({
|
|
87
|
+
"field" => {'$gt' => 3},
|
|
88
|
+
})
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it_behaves_like 'returns a cloned query'
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
let(:selection) do
|
|
95
|
+
query.send(tested_method, :field.gt => 3)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it_behaves_like 'adds the conditions to top level'
|
|
99
|
+
|
|
100
|
+
context 'when the criterion is wrapped in an array' do
|
|
101
|
+
let(:selection) do
|
|
102
|
+
query.send(tested_method, [{ :field.gt => 3 }])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it_behaves_like 'adds the conditions to top level'
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context 'when the criterion is wrapped in a deep array with nil elements' do
|
|
109
|
+
let(:selection) do
|
|
110
|
+
query.send(tested_method, [[[{ :field.gt => 3 }]], [nil]])
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it_behaves_like 'adds the conditions to top level'
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
context 'when the criterion is a time' do
|
|
117
|
+
let(:selection) do
|
|
118
|
+
query.send(tested_method, :field.gte => Time.new(2020, 1, 1))
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'adds the conditions' do
|
|
122
|
+
expect(selection.selector).to eq({
|
|
123
|
+
"field" => {'$gte' => Time.new(2020, 1, 1)},
|
|
124
|
+
})
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'keeps argument type' do
|
|
128
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
context 'when the criterion is a datetime' do
|
|
133
|
+
let(:selection) do
|
|
134
|
+
query.send(tested_method, :field.gte => DateTime.new(2020, 1, 1))
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'adds the conditions' do
|
|
138
|
+
expect(selection.selector).to eq({
|
|
139
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
|
140
|
+
})
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it 'converts argument to a time' do
|
|
144
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
context 'when the criterion is a date' do
|
|
149
|
+
let(:selection) do
|
|
150
|
+
query.send(tested_method, :field.gte => Date.new(2020, 1, 1))
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it 'adds the conditions' do
|
|
154
|
+
expect(selection.selector).to eq({
|
|
155
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
|
156
|
+
})
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'converts argument to a time' do
|
|
160
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
context "when provided a nested criterion" do
|
|
166
|
+
|
|
167
|
+
let(:selection) do
|
|
168
|
+
query.send(tested_method, :test.elem_match => { :field.in => [ 1, 2 ] })
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "builds the correct selector" do
|
|
172
|
+
expect(selection.selector).to eq({
|
|
173
|
+
"test" => { "$elemMatch" => { "field" => { "$in" => [ 1, 2 ] }}}
|
|
174
|
+
})
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it_behaves_like 'returns a cloned query'
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
context "when chaining the criteria" do
|
|
181
|
+
|
|
182
|
+
context "when the criteria are for different fields" do
|
|
183
|
+
|
|
184
|
+
let(:selection) do
|
|
185
|
+
query.and(first: [ 1, 2 ]).send(tested_method, second: [ 3, 4 ])
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "adds the conditions to top level" do
|
|
189
|
+
expect(selection.selector).to eq({
|
|
190
|
+
"first" => [ 1, 2 ],
|
|
191
|
+
"second" => [ 3, 4 ],
|
|
192
|
+
})
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it_behaves_like 'returns a cloned query'
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
context "when the criteria are on the same field" do
|
|
199
|
+
|
|
200
|
+
let(:selection) do
|
|
201
|
+
query.and(first: [ 1, 2 ]).send(tested_method, first: [ 3, 4 ])
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "combines via $and operator" do
|
|
205
|
+
expect(selection.selector).to eq({
|
|
206
|
+
"first" => [ 1, 2 ],
|
|
207
|
+
"$and" => [
|
|
208
|
+
{ "first" => [ 3, 4 ] }
|
|
209
|
+
]
|
|
210
|
+
})
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
it_behaves_like 'returns a cloned query'
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Non-hoisting means the operator is always present, for example
|
|
219
|
+
# Foo.or(a: 1) produces {'$or' => [{'a' => 1}]}.
|
|
220
|
+
shared_examples_for 'a non-hoisting logical operation' do
|
|
221
|
+
|
|
222
|
+
context 'when there is a single predicate' do
|
|
223
|
+
let(:query) do
|
|
224
|
+
Mongoid::Query.new.send(tested_method, hello: 'world')
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it 'adds the predicate' do
|
|
228
|
+
expect(query.selector).to eq(expected_operator => [{'hello' => 'world'}])
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context 'when the single predicate is wrapped in an array' do
|
|
233
|
+
let(:query) do
|
|
234
|
+
Mongoid::Query.new.send(tested_method, [{hello: 'world'}])
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'adds the predicate' do
|
|
238
|
+
expect(query.selector).to eq(expected_operator => [{'hello' => 'world'}])
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
context 'when argument is a Criteria' do
|
|
243
|
+
let(:query) do
|
|
244
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
let(:other) do
|
|
248
|
+
Mongoid::Query.new.where(foo: 'bar')
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
let(:result) { query.send(tested_method, other) }
|
|
252
|
+
|
|
253
|
+
it 'combines' do
|
|
254
|
+
# This is used for $or / $nor, the two conditions should remain
|
|
255
|
+
# as separate hashes
|
|
256
|
+
expect(result.selector).to eq(expected_operator => [{'hello' => 'world'}, {'foo' => 'bar'}])
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
context 'when argument is a mix of Criteria and hashes' do
|
|
261
|
+
let(:query) do
|
|
262
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
let(:other1) do
|
|
266
|
+
Mongoid::Query.new.where(foo: 'bar')
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
let(:other2) do
|
|
270
|
+
{bar: 42}
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
let(:other3) do
|
|
274
|
+
Mongoid::Query.new.where(a: 2)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
let(:result) { query.send(tested_method, other1, other2, other3) }
|
|
278
|
+
|
|
279
|
+
it 'combines' do
|
|
280
|
+
expect(result.selector).to eq(expected_operator => [
|
|
281
|
+
{'hello' => 'world'},
|
|
282
|
+
{'foo' => 'bar'},
|
|
283
|
+
{'bar' => 42},
|
|
284
|
+
{'a' => 2},
|
|
285
|
+
])
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
describe "#and" do
|
|
291
|
+
|
|
292
|
+
let(:tested_method) { :and }
|
|
293
|
+
let(:expected_operator) { '$and' }
|
|
294
|
+
|
|
295
|
+
it_behaves_like 'a hoisting logical operation'
|
|
296
|
+
|
|
297
|
+
context "when provided no criterion" do
|
|
298
|
+
|
|
299
|
+
let(:selection) do
|
|
300
|
+
query.and
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it "does not add any criterion" do
|
|
304
|
+
expect(selection.selector).to eq({})
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
it "returns the query" do
|
|
308
|
+
expect(selection).to eq(query)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it_behaves_like 'returns a cloned query'
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
context "when provided nil" do
|
|
315
|
+
|
|
316
|
+
let(:selection) do
|
|
317
|
+
query.and(nil)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it "does not add any criterion" do
|
|
321
|
+
expect(selection.selector).to eq({})
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
it "returns the query" do
|
|
325
|
+
expect(selection).to eq(query)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it_behaves_like 'returns a cloned query'
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
context "when provided multiple criteria" do
|
|
332
|
+
|
|
333
|
+
context "when the criterion is already included" do
|
|
334
|
+
|
|
335
|
+
context 'simple criterion' do
|
|
336
|
+
let(:selection) do
|
|
337
|
+
query.and({ first: [ 1, 2 ] }).and({ first: [ 1, 2 ] })
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it "adds all conditions" do
|
|
341
|
+
expect(selection.selector).to eq({
|
|
342
|
+
'first' => [1, 2],
|
|
343
|
+
"$and" => [
|
|
344
|
+
{ "first" => [ 1, 2 ] }
|
|
345
|
+
]
|
|
346
|
+
})
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
it_behaves_like 'returns a cloned query'
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
context 'Key criterion' do
|
|
353
|
+
let(:selection) do
|
|
354
|
+
query.and({ first: [ 1, 2 ] }).and(:first.gt => 3)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
it "adds all conditions" do
|
|
358
|
+
expect(selection.selector).to eq({
|
|
359
|
+
'first' => [1, 2],
|
|
360
|
+
"$and" => [
|
|
361
|
+
{ "first" => {'$gt' => 3} }
|
|
362
|
+
]
|
|
363
|
+
})
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
it_behaves_like 'returns a cloned query'
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
context 'Key criterion when existing criterion is an operator' do
|
|
370
|
+
let(:selection) do
|
|
371
|
+
query.and(:first.lt => 5).and(:first.gt => 3)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
it "adds all conditions" do
|
|
375
|
+
expect(selection.selector).to eq({
|
|
376
|
+
'first' => {'$lt' => 5, '$gt' => 3},
|
|
377
|
+
})
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
it_behaves_like 'returns a cloned query'
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
context "when the new criteria are for different fields" do
|
|
385
|
+
|
|
386
|
+
let(:selection) do
|
|
387
|
+
query.and({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
it "adds all conditions to top level" do
|
|
391
|
+
expect(selection.selector).to eq({
|
|
392
|
+
"first" => [ 1, 2 ],
|
|
393
|
+
"second" => [ 3, 4 ],
|
|
394
|
+
})
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
it_behaves_like 'returns a cloned query'
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
context "when the new criteria are for the same field" do
|
|
401
|
+
|
|
402
|
+
context 'when criteria are simple' do
|
|
403
|
+
let(:selection) do
|
|
404
|
+
query.and({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
it "combines via $and operator" do
|
|
408
|
+
expect(selection.selector).to eq({
|
|
409
|
+
"first" => [ 1, 2 ],
|
|
410
|
+
"$and" => [
|
|
411
|
+
{ "first" => [ 3, 4 ] }
|
|
412
|
+
]
|
|
413
|
+
})
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it_behaves_like 'returns a cloned query'
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
context 'when criteria use operators' do
|
|
420
|
+
shared_examples 'behave correctly' do
|
|
421
|
+
let(:selection) do
|
|
422
|
+
query.and(
|
|
423
|
+
{ field: {first_operator => [ 1, 2 ] }},
|
|
424
|
+
{ field: {second_operator => [ 3, 4 ] }},
|
|
425
|
+
)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
it "combines via $and operator and stringifies all keys" do
|
|
429
|
+
expect(selection.selector).to eq({
|
|
430
|
+
"field" => {'$in' => [ 1, 2 ]},
|
|
431
|
+
"$and" => [
|
|
432
|
+
{ "field" => {'$in' => [ 3, 4 ] }}
|
|
433
|
+
]
|
|
434
|
+
})
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
[
|
|
439
|
+
['$in', '$in'],
|
|
440
|
+
[:$in, '$in'],
|
|
441
|
+
['$in', :$in],
|
|
442
|
+
[:$in, :$in],
|
|
443
|
+
].each do |first_operator, second_operator|
|
|
444
|
+
context "when first operator is #{first_operator.inspect} and second operator is #{second_operator.inspect}" do
|
|
445
|
+
let(:first_operator) { first_operator }
|
|
446
|
+
let(:second_operator) { second_operator }
|
|
447
|
+
|
|
448
|
+
include_examples 'behave correctly'
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
context 'when criteria are handled via Key' do
|
|
454
|
+
shared_examples_for 'adds the conditions to top level' do
|
|
455
|
+
|
|
456
|
+
it "adds the conditions to top level" do
|
|
457
|
+
expect(selection.selector).to eq({
|
|
458
|
+
"field" => {'$gt' => 3, '$lt' => 5},
|
|
459
|
+
})
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
it_behaves_like 'returns a cloned query'
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
context 'criteria are provided in the same hash' do
|
|
466
|
+
let(:selection) do
|
|
467
|
+
query.send(tested_method, :field.gt => 3, :field.lt => 5)
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
it_behaves_like 'adds the conditions to top level'
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
context 'criteria are provided in separate hashes' do
|
|
474
|
+
let(:selection) do
|
|
475
|
+
query.send(tested_method, {:field.gt => 3}, {:field.lt => 5})
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
it_behaves_like 'adds the conditions to top level'
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
context 'when the criterion is wrapped in an array' do
|
|
482
|
+
let(:selection) do
|
|
483
|
+
query.send(tested_method, [:field.gt => 3], [:field.lt => 5])
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
it_behaves_like 'adds the conditions to top level'
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
context 'when criteria are simple and handled via Key' do
|
|
491
|
+
shared_examples_for 'combines conditions with $and' do
|
|
492
|
+
|
|
493
|
+
it "combines conditions with $and" do
|
|
494
|
+
expect(selection.selector).to eq({
|
|
495
|
+
"field" => 3,
|
|
496
|
+
'$and' => ['field' => {'$lt' => 5}],
|
|
497
|
+
})
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
it_behaves_like 'returns a cloned query'
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
shared_examples_for 'combines conditions with $eq' do
|
|
504
|
+
|
|
505
|
+
it "combines conditions with $eq" do
|
|
506
|
+
expect(selection.selector).to eq({
|
|
507
|
+
"field" => {'$eq' => 3, '$lt' => 5},
|
|
508
|
+
})
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
it_behaves_like 'returns a cloned query'
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
shared_examples_for 'combines conditions with $regex' do
|
|
515
|
+
|
|
516
|
+
it "combines conditions with $regex" do
|
|
517
|
+
expect(selection.selector).to eq({
|
|
518
|
+
"field" => {'$regex' => /t/, '$lt' => 5},
|
|
519
|
+
})
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
it_behaves_like 'returns a cloned query'
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
context 'criteria are provided in the same hash' do
|
|
526
|
+
context 'non-regexp argument' do
|
|
527
|
+
let(:selection) do
|
|
528
|
+
query.send(tested_method, :field => 3, :field.lt => 5)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
it_behaves_like 'combines conditions with $eq'
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
context 'regexp argument' do
|
|
535
|
+
let(:selection) do
|
|
536
|
+
query.send(tested_method, :field => /t/, :field.lt => 5)
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
it_behaves_like 'combines conditions with $regex'
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
context 'criteria are provided in separate hashes' do
|
|
544
|
+
let(:selection) do
|
|
545
|
+
query.send(tested_method, {:field => 3}, {:field.lt => 5})
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
it_behaves_like 'combines conditions with $and'
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
context 'when the criterion is wrapped in an array' do
|
|
552
|
+
let(:selection) do
|
|
553
|
+
query.send(tested_method, [:field => 3], [:field.lt => 5])
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
it_behaves_like 'combines conditions with $and'
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
context 'when criteria are handled via Key and simple' do
|
|
561
|
+
shared_examples_for 'combines conditions with $and' do
|
|
562
|
+
|
|
563
|
+
it "combines conditions with $and" do
|
|
564
|
+
expect(selection.selector).to eq({
|
|
565
|
+
"field" => {'$gt' => 3},
|
|
566
|
+
'$and' => ['field' => 5],
|
|
567
|
+
})
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
it_behaves_like 'returns a cloned query'
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
shared_examples_for 'combines conditions with $eq' do
|
|
574
|
+
|
|
575
|
+
it "combines conditions with $eq" do
|
|
576
|
+
expect(selection.selector).to eq({
|
|
577
|
+
"field" => {'$gt' => 3, '$eq' => 5},
|
|
578
|
+
})
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
it_behaves_like 'returns a cloned query'
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
shared_examples_for 'combines conditions with $regex' do
|
|
585
|
+
|
|
586
|
+
it "combines conditions with $regex" do
|
|
587
|
+
expect(selection.selector).to eq({
|
|
588
|
+
"field" => {'$gt' => 3, '$regex' => /t/},
|
|
589
|
+
})
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
it_behaves_like 'returns a cloned query'
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
context 'criteria are provided in the same hash' do
|
|
596
|
+
context 'non-regexp argument' do
|
|
597
|
+
let(:selection) do
|
|
598
|
+
query.send(tested_method, :field.gt => 3, :field => 5)
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
it_behaves_like 'combines conditions with $eq'
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
context 'regexp argument' do
|
|
605
|
+
let(:selection) do
|
|
606
|
+
query.send(tested_method, :field.gt => 3, :field => /t/)
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
it_behaves_like 'combines conditions with $regex'
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
context 'criteria are provided in separate hashes' do
|
|
614
|
+
let(:selection) do
|
|
615
|
+
query.send(tested_method, {:field.gt => 3}, {:field => 5})
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
it_behaves_like 'combines conditions with $and'
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
context 'when the criterion is wrapped in an array' do
|
|
622
|
+
let(:selection) do
|
|
623
|
+
query.send(tested_method, [:field.gt => 3], [:field => 5])
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
it_behaves_like 'combines conditions with $and'
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
context 'when argument is a Criteria' do
|
|
633
|
+
let(:query) do
|
|
634
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
let(:result) { query.and(other) }
|
|
638
|
+
|
|
639
|
+
context 'different fields' do
|
|
640
|
+
|
|
641
|
+
let(:other) do
|
|
642
|
+
Mongoid::Query.new.where(foo: 'bar')
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
it 'combines both fields at top level' do
|
|
646
|
+
expect(result.selector).to eq('hello' => 'world', 'foo' => 'bar')
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
context 'same field' do
|
|
651
|
+
|
|
652
|
+
let(:other) do
|
|
653
|
+
Mongoid::Query.new.where(hello: /bar/)
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
it 'combines fields with $and' do
|
|
657
|
+
expect(result.selector).to eq('hello' => 'world', '$and' => [{'hello' => /bar/}])
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
context 'when argument is a mix of Criteria and hashes' do
|
|
663
|
+
let(:query) do
|
|
664
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
let(:other1) do
|
|
668
|
+
Mongoid::Query.new.where(foo: 'bar')
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
let(:other2) do
|
|
672
|
+
{bar: 42}
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
let(:other3) do
|
|
676
|
+
Mongoid::Query.new.where(a: 2)
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
let(:result) { query.and(other1, other2, other3) }
|
|
680
|
+
|
|
681
|
+
it 'combines' do
|
|
682
|
+
expect(result.selector).to eq('hello' => 'world',
|
|
683
|
+
'foo' => 'bar',
|
|
684
|
+
'bar' => 42,
|
|
685
|
+
'a' => 2,
|
|
686
|
+
)
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
context 'when Key instances are used and types involved have serializers' do
|
|
691
|
+
let(:time) { Time.now }
|
|
692
|
+
|
|
693
|
+
let(:query) do
|
|
694
|
+
Band.all.and(:created_at.gt => time)
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
let(:expected) do
|
|
698
|
+
{'created_at' => {'$gt' => time.utc}}
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
it 'combines and evolves' do
|
|
702
|
+
expect(query.selector).to eq(expected)
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
describe 'query shape' do
|
|
707
|
+
shared_examples_for 'adds most recent criterion as $and' do
|
|
708
|
+
let(:selector) { scope.selector }
|
|
709
|
+
|
|
710
|
+
it 'adds most recent criterion as $and' do
|
|
711
|
+
expect(selector).to eq('foo' => 1, '$and' => [{'foo' => 2}])
|
|
712
|
+
end
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
context 'and/and' do
|
|
716
|
+
let(:scope) do
|
|
717
|
+
Band.and(foo: 1).and(foo: 2)
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
it_behaves_like 'adds most recent criterion as $and'
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
context 'and/and' do
|
|
724
|
+
let(:scope) do
|
|
725
|
+
Band.and(foo: 1).and(foo: 2)
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
it_behaves_like 'adds most recent criterion as $and'
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
context 'and/where' do
|
|
732
|
+
let(:scope) do
|
|
733
|
+
Band.and(foo: 1).where(foo: 2)
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
it_behaves_like 'adds most recent criterion as $and'
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
context 'where/and' do
|
|
740
|
+
let(:scope) do
|
|
741
|
+
Band.where(foo: 1).and(foo: 2)
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
it_behaves_like 'adds most recent criterion as $and'
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
context 'where/where' do
|
|
748
|
+
let(:scope) do
|
|
749
|
+
Band.where(foo: 1).where(foo: 2)
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
it_behaves_like 'adds most recent criterion as $and'
|
|
753
|
+
end
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
context 'when conditions already exist in criteria' do
|
|
757
|
+
let(:base_selection) do
|
|
758
|
+
query.where(foo: 'bar')
|
|
759
|
+
end
|
|
760
|
+
|
|
761
|
+
context 'when hash conditions are given' do
|
|
762
|
+
let(:selection) do
|
|
763
|
+
base_selection.and(hello: 'world')
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
it 'adds new conditions to top level' do
|
|
767
|
+
selection.selector.should == {
|
|
768
|
+
'foo' => 'bar',
|
|
769
|
+
'hello' => 'world',
|
|
770
|
+
}
|
|
771
|
+
end
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
context 'when criteria conditions are given' do
|
|
775
|
+
let(:selection) do
|
|
776
|
+
base_selection.and(query.where(hello: 'world'))
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
it 'adds new conditions to top level' do
|
|
780
|
+
selection.selector.should == {
|
|
781
|
+
'foo' => 'bar',
|
|
782
|
+
'hello' => 'world',
|
|
783
|
+
}
|
|
784
|
+
end
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
context 'when complex criteria conditions are given' do
|
|
788
|
+
let(:selection) do
|
|
789
|
+
base_selection.and(query.or([one: 'one'], [two: 'two']))
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
it 'adds new conditions to top level' do
|
|
793
|
+
selection.selector.should == {
|
|
794
|
+
'foo' => 'bar',
|
|
795
|
+
'$or' => [
|
|
796
|
+
{'one' => 'one'},
|
|
797
|
+
{'two' => 'two'},
|
|
798
|
+
],
|
|
799
|
+
}
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
end
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
shared_examples '$or/$nor' do
|
|
806
|
+
|
|
807
|
+
it_behaves_like 'a non-hoisting logical operation'
|
|
808
|
+
|
|
809
|
+
context "when provided no arguments" do
|
|
810
|
+
|
|
811
|
+
let(:selection) do
|
|
812
|
+
query.send(tested_method)
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
it_behaves_like 'returns a cloned query'
|
|
816
|
+
|
|
817
|
+
it "does not add any criteria" do
|
|
818
|
+
expect(selection.selector).to eq({})
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
it "returns the query" do
|
|
822
|
+
expect(selection).to eq(query)
|
|
823
|
+
end
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
context "when provided nil" do
|
|
827
|
+
|
|
828
|
+
let(:selection) do
|
|
829
|
+
query.send(tested_method, nil)
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
it_behaves_like 'returns a cloned query'
|
|
833
|
+
|
|
834
|
+
it "does not add any criteria" do
|
|
835
|
+
expect(selection.selector).to eq({})
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
it "returns the query" do
|
|
839
|
+
expect(selection).to eq(query)
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
context "when provided a single criterion" do
|
|
844
|
+
|
|
845
|
+
let(:selection) do
|
|
846
|
+
query.send(tested_method, field: [ 1, 2 ])
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
it_behaves_like 'returns a cloned query'
|
|
850
|
+
|
|
851
|
+
it "adds the $or/$nor selector" do
|
|
852
|
+
expect(selection.selector).to eq({
|
|
853
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
|
854
|
+
})
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
context 'when the criterion is wrapped in array' do
|
|
858
|
+
|
|
859
|
+
let(:selection) do
|
|
860
|
+
query.send(tested_method, [{ field: [ 1, 2 ] }])
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
it_behaves_like 'returns a cloned query'
|
|
864
|
+
|
|
865
|
+
it "adds the $or/$nor selector" do
|
|
866
|
+
expect(selection.selector).to eq({
|
|
867
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
|
868
|
+
})
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
context 'when the array has nil as one of the elements' do
|
|
872
|
+
|
|
873
|
+
let(:selection) do
|
|
874
|
+
query.send(tested_method, [{ field: [ 1, 2 ] }, nil])
|
|
875
|
+
end
|
|
876
|
+
|
|
877
|
+
it_behaves_like 'returns a cloned query'
|
|
878
|
+
|
|
879
|
+
it "adds the $or/$nor selector ignoring the nil element" do
|
|
880
|
+
expect(selection.selector).to eq({
|
|
881
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
|
882
|
+
})
|
|
883
|
+
end
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
|
|
887
|
+
context 'when query already has a condition on another field' do
|
|
888
|
+
|
|
889
|
+
let(:selection) do
|
|
890
|
+
query.where(foo: 'bar').send(tested_method, field: [ 1, 2 ])
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
it 'moves original conditions under $or/$nor' do
|
|
894
|
+
expect(selection.selector).to eq({
|
|
895
|
+
expected_operator => [{'foo' => 'bar'}, { "field" => [ 1, 2 ] }]
|
|
896
|
+
})
|
|
897
|
+
end
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
context 'when query already has an $or/$nor condition and another condition' do
|
|
901
|
+
|
|
902
|
+
let(:selection) do
|
|
903
|
+
query.send(tested_method, field: [ 1, 2 ]).where(foo: 'bar').send(tested_method, test: 1)
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
it 'unions existing conditions' do
|
|
907
|
+
expect(selection.selector).to eq(
|
|
908
|
+
expected_operator => [
|
|
909
|
+
{
|
|
910
|
+
expected_operator => [{ "field" => [ 1, 2 ] }],
|
|
911
|
+
'foo' => 'bar',
|
|
912
|
+
},
|
|
913
|
+
{'test' => 1},
|
|
914
|
+
]
|
|
915
|
+
)
|
|
916
|
+
end
|
|
917
|
+
end
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
context "when provided multiple criteria" do
|
|
921
|
+
|
|
922
|
+
context "when the criteria are for different fields" do
|
|
923
|
+
|
|
924
|
+
let(:selection) do
|
|
925
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
it_behaves_like 'returns a cloned query'
|
|
929
|
+
|
|
930
|
+
it "adds the $or/$nor selector" do
|
|
931
|
+
expect(selection.selector).to eq({
|
|
932
|
+
expected_operator => [
|
|
933
|
+
{ "first" => [ 1, 2 ] },
|
|
934
|
+
{ "second" => [ 3, 4 ] }
|
|
935
|
+
]
|
|
936
|
+
})
|
|
937
|
+
end
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
context "when the criteria uses a Key instance" do
|
|
941
|
+
|
|
942
|
+
let(:selection) do
|
|
943
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { :second.gt => 3 })
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
it "adds the $or/$nor selector" do
|
|
947
|
+
expect(selection.selector).to eq({
|
|
948
|
+
expected_operator => [
|
|
949
|
+
{ "first" => [ 1, 2 ] },
|
|
950
|
+
{ "second" => { "$gt" => 3 }}
|
|
951
|
+
]
|
|
952
|
+
})
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
it_behaves_like 'returns a cloned query'
|
|
956
|
+
|
|
957
|
+
context 'when the criterion is a time' do
|
|
958
|
+
let(:selection) do
|
|
959
|
+
query.send(tested_method, :field.gte => Time.new(2020, 1, 1))
|
|
960
|
+
end
|
|
961
|
+
|
|
962
|
+
it 'adds the conditions' do
|
|
963
|
+
expect(selection.selector).to eq(expected_operator => [
|
|
964
|
+
"field" => {'$gte' => Time.new(2020, 1, 1)},
|
|
965
|
+
])
|
|
966
|
+
end
|
|
967
|
+
|
|
968
|
+
it 'keeps the type' do
|
|
969
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
|
970
|
+
end
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
context 'when the criterion is a datetime' do
|
|
974
|
+
let(:selection) do
|
|
975
|
+
query.send(tested_method, :field.gte => DateTime.new(2020, 1, 1))
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
it 'adds the conditions' do
|
|
979
|
+
expect(selection.selector).to eq(expected_operator => [
|
|
980
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
|
981
|
+
])
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
it 'converts argument to a time' do
|
|
985
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
|
986
|
+
end
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
context 'when the criterion is a date' do
|
|
990
|
+
let(:selection) do
|
|
991
|
+
query.send(tested_method, :field.gte => Date.new(2020, 1, 1))
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
it 'adds the conditions' do
|
|
995
|
+
expect(selection.selector).to eq(expected_operator => [
|
|
996
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
|
997
|
+
])
|
|
998
|
+
end
|
|
999
|
+
|
|
1000
|
+
it 'converts argument to a time' do
|
|
1001
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
|
1002
|
+
end
|
|
1003
|
+
end
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
context "when a criterion has an aliased field" do
|
|
1007
|
+
|
|
1008
|
+
let(:selection) do
|
|
1009
|
+
query.send(tested_method, { id: 1 })
|
|
1010
|
+
end
|
|
1011
|
+
|
|
1012
|
+
it "adds the $or/$nor selector and aliases the field" do
|
|
1013
|
+
expect(selection.selector).to eq({
|
|
1014
|
+
expected_operator => [ { "_id" => 1 } ]
|
|
1015
|
+
})
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
it_behaves_like 'returns a cloned query'
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
context "when a criterion is wrapped in an array" do
|
|
1022
|
+
|
|
1023
|
+
let(:selection) do
|
|
1024
|
+
query.send(tested_method, [{ first: [ 1, 2 ] }, { :second.gt => 3 }])
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
it_behaves_like 'returns a cloned query'
|
|
1028
|
+
|
|
1029
|
+
it "adds the $or/$nor selector" do
|
|
1030
|
+
expect(selection.selector).to eq({
|
|
1031
|
+
expected_operator => [
|
|
1032
|
+
{ "first" => [ 1, 2 ] },
|
|
1033
|
+
{ "second" => { "$gt" => 3 }}
|
|
1034
|
+
]
|
|
1035
|
+
})
|
|
1036
|
+
end
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
context "when the criteria are on the same field" do
|
|
1040
|
+
|
|
1041
|
+
context 'simple criteria' do
|
|
1042
|
+
let(:selection) do
|
|
1043
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
|
1044
|
+
end
|
|
1045
|
+
|
|
1046
|
+
it_behaves_like 'returns a cloned query'
|
|
1047
|
+
|
|
1048
|
+
it "appends both $or/$nor expressions" do
|
|
1049
|
+
expect(selection.selector).to eq({
|
|
1050
|
+
expected_operator => [
|
|
1051
|
+
{ "first" => [ 1, 2 ] },
|
|
1052
|
+
{ "first" => [ 3, 4 ] }
|
|
1053
|
+
]
|
|
1054
|
+
})
|
|
1055
|
+
end
|
|
1056
|
+
end
|
|
1057
|
+
|
|
1058
|
+
context 'Key criteria as one argument' do
|
|
1059
|
+
let(:selection) do
|
|
1060
|
+
query.send(tested_method, :first.gt => 3, :first.lt => 5)
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
it_behaves_like 'returns a cloned query'
|
|
1064
|
+
|
|
1065
|
+
it "adds all criteria" do
|
|
1066
|
+
expect(selection.selector).to eq({
|
|
1067
|
+
expected_operator => [
|
|
1068
|
+
{ "first" => {'$gt' => 3, '$lt' => 5} },
|
|
1069
|
+
]
|
|
1070
|
+
})
|
|
1071
|
+
end
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
context 'Key criteria as multiple arguments' do
|
|
1075
|
+
let(:selection) do
|
|
1076
|
+
query.send(tested_method, {:first.gt => 3}, {:first.lt => 5})
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
it_behaves_like 'returns a cloned query'
|
|
1080
|
+
|
|
1081
|
+
it "adds all criteria" do
|
|
1082
|
+
expect(selection.selector).to eq({
|
|
1083
|
+
expected_operator => [
|
|
1084
|
+
{ "first" => {'$gt' => 3} },
|
|
1085
|
+
{ "first" => {'$lt' => 5} },
|
|
1086
|
+
]
|
|
1087
|
+
})
|
|
1088
|
+
end
|
|
1089
|
+
end
|
|
1090
|
+
end
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
context "when chaining the criterion" do
|
|
1094
|
+
|
|
1095
|
+
context "when the criterion are for different fields" do
|
|
1096
|
+
|
|
1097
|
+
let(:selection) do
|
|
1098
|
+
query.send(tested_method, first: [ 1, 2 ]).send(tested_method, second: [ 3, 4 ])
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
it_behaves_like 'returns a cloned query'
|
|
1102
|
+
|
|
1103
|
+
it "adds the $or/$nor selectors" do
|
|
1104
|
+
expect(selection.selector).to eq({
|
|
1105
|
+
expected_operator => [
|
|
1106
|
+
{ "first" => [ 1, 2 ] },
|
|
1107
|
+
{ "second" => [ 3, 4 ] }
|
|
1108
|
+
]
|
|
1109
|
+
})
|
|
1110
|
+
end
|
|
1111
|
+
end
|
|
1112
|
+
|
|
1113
|
+
context "when the criterion are on the same field" do
|
|
1114
|
+
|
|
1115
|
+
let(:selection) do
|
|
1116
|
+
query.send(tested_method, first: [ 1, 2 ]).send(tested_method, first: [ 3, 4 ])
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
it_behaves_like 'returns a cloned query'
|
|
1120
|
+
|
|
1121
|
+
it "appends both $or/$nor expressions" do
|
|
1122
|
+
expect(selection.selector).to eq({
|
|
1123
|
+
expected_operator => [
|
|
1124
|
+
{ "first" => [ 1, 2 ] },
|
|
1125
|
+
{ "first" => [ 3, 4 ] }
|
|
1126
|
+
]
|
|
1127
|
+
})
|
|
1128
|
+
end
|
|
1129
|
+
end
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
context 'when giving multiple conditions in one call on the same key with symbol operator' do
|
|
1133
|
+
|
|
1134
|
+
context 'non-regexp argument' do
|
|
1135
|
+
let(:selection) do
|
|
1136
|
+
query.send(tested_method, field: 1, :field.gt => 0)
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
it 'combines conditions with $eq' do
|
|
1140
|
+
selection.selector.should == {
|
|
1141
|
+
expected_operator => [
|
|
1142
|
+
'field' => {'$eq' => 1, '$gt' => 0},
|
|
1143
|
+
]
|
|
1144
|
+
}
|
|
1145
|
+
end
|
|
1146
|
+
end
|
|
1147
|
+
|
|
1148
|
+
context 'regexp argument' do
|
|
1149
|
+
let(:selection) do
|
|
1150
|
+
query.send(tested_method, field: /t/, :field.gt => 0)
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
it 'combines conditions with $regex' do
|
|
1154
|
+
selection.selector.should == {
|
|
1155
|
+
expected_operator => [
|
|
1156
|
+
'field' => {'$regex' => /t/, '$gt' => 0},
|
|
1157
|
+
]
|
|
1158
|
+
}
|
|
1159
|
+
end
|
|
1160
|
+
end
|
|
1161
|
+
|
|
1162
|
+
end
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
describe "#or" do
|
|
1166
|
+
|
|
1167
|
+
let(:tested_method) { :or }
|
|
1168
|
+
let(:expected_operator) { '$or' }
|
|
1169
|
+
|
|
1170
|
+
it_behaves_like '$or/$nor'
|
|
1171
|
+
end
|
|
1172
|
+
|
|
1173
|
+
describe "#nor" do
|
|
1174
|
+
|
|
1175
|
+
let(:tested_method) { :nor }
|
|
1176
|
+
let(:expected_operator) { '$nor' }
|
|
1177
|
+
|
|
1178
|
+
it_behaves_like '$or/$nor'
|
|
1179
|
+
end
|
|
1180
|
+
|
|
1181
|
+
describe "#any_of" do
|
|
1182
|
+
|
|
1183
|
+
let(:tested_method) { :any_of }
|
|
1184
|
+
let(:expected_operator) { '$or' }
|
|
1185
|
+
|
|
1186
|
+
it_behaves_like 'a hoisting logical operation'
|
|
1187
|
+
|
|
1188
|
+
# When multiple arguments are given to any_of, it behaves differently
|
|
1189
|
+
# from and.
|
|
1190
|
+
context 'when argument is a mix of Criteria and hashes' do
|
|
1191
|
+
let(:query) do
|
|
1192
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1195
|
+
let(:other1) do
|
|
1196
|
+
Mongoid::Query.new.where(foo: 'bar')
|
|
1197
|
+
end
|
|
1198
|
+
|
|
1199
|
+
let(:other2) do
|
|
1200
|
+
{bar: 42}
|
|
1201
|
+
end
|
|
1202
|
+
|
|
1203
|
+
let(:other3) do
|
|
1204
|
+
Mongoid::Query.new.where(a: 2)
|
|
1205
|
+
end
|
|
1206
|
+
|
|
1207
|
+
let(:result) { query.send(tested_method, other1, other2, other3) }
|
|
1208
|
+
|
|
1209
|
+
it 'combines' do
|
|
1210
|
+
expect(result.selector).to eq(
|
|
1211
|
+
'hello' => 'world',
|
|
1212
|
+
expected_operator => [
|
|
1213
|
+
{'foo' => 'bar'},
|
|
1214
|
+
{'bar' => 42},
|
|
1215
|
+
{'a' => 2},
|
|
1216
|
+
],
|
|
1217
|
+
)
|
|
1218
|
+
end
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1221
|
+
context "when provided no arguments" do
|
|
1222
|
+
|
|
1223
|
+
let(:selection) do
|
|
1224
|
+
query.any_of
|
|
1225
|
+
end
|
|
1226
|
+
|
|
1227
|
+
it_behaves_like 'returns a cloned query'
|
|
1228
|
+
|
|
1229
|
+
it "does not add any criteria" do
|
|
1230
|
+
expect(selection.selector).to eq({})
|
|
1231
|
+
end
|
|
1232
|
+
|
|
1233
|
+
it "returns the query" do
|
|
1234
|
+
expect(selection).to eq(query)
|
|
1235
|
+
end
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
context "when provided nil" do
|
|
1239
|
+
|
|
1240
|
+
let(:selection) do
|
|
1241
|
+
query.any_of(nil)
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1244
|
+
it_behaves_like 'returns a cloned query'
|
|
1245
|
+
|
|
1246
|
+
it "does not add any criteria" do
|
|
1247
|
+
expect(selection.selector).to eq({})
|
|
1248
|
+
end
|
|
1249
|
+
|
|
1250
|
+
it "returns the query" do
|
|
1251
|
+
expect(selection).to eq(query)
|
|
1252
|
+
end
|
|
1253
|
+
end
|
|
1254
|
+
|
|
1255
|
+
context "when provided a single criterion" do
|
|
1256
|
+
|
|
1257
|
+
let(:selection) do
|
|
1258
|
+
query.any_of(field: [ 1, 2 ])
|
|
1259
|
+
end
|
|
1260
|
+
|
|
1261
|
+
it_behaves_like 'returns a cloned query'
|
|
1262
|
+
|
|
1263
|
+
it "adds the $or selector" do
|
|
1264
|
+
expect(selection.selector).to eq(
|
|
1265
|
+
"field" => [ 1, 2 ],
|
|
1266
|
+
)
|
|
1267
|
+
end
|
|
1268
|
+
|
|
1269
|
+
context 'when the criterion is wrapped in array' do
|
|
1270
|
+
|
|
1271
|
+
let(:selection) do
|
|
1272
|
+
query.any_of([{ field: [ 1, 2 ] }])
|
|
1273
|
+
end
|
|
1274
|
+
|
|
1275
|
+
it_behaves_like 'returns a cloned query'
|
|
1276
|
+
|
|
1277
|
+
it "adds the condition" do
|
|
1278
|
+
expect(selection.selector).to eq(
|
|
1279
|
+
"field" => [ 1, 2 ],
|
|
1280
|
+
)
|
|
1281
|
+
end
|
|
1282
|
+
|
|
1283
|
+
context 'when the array has nil as one of the elements' do
|
|
1284
|
+
|
|
1285
|
+
let(:selection) do
|
|
1286
|
+
query.any_of([{ field: [ 1, 2 ] }, nil])
|
|
1287
|
+
end
|
|
1288
|
+
|
|
1289
|
+
it_behaves_like 'returns a cloned query'
|
|
1290
|
+
|
|
1291
|
+
it "adds the $or selector ignoring the nil element" do
|
|
1292
|
+
expect(selection.selector).to eq(
|
|
1293
|
+
"field" => [ 1, 2 ],
|
|
1294
|
+
)
|
|
1295
|
+
end
|
|
1296
|
+
end
|
|
1297
|
+
end
|
|
1298
|
+
|
|
1299
|
+
context 'when query already has a condition on another field' do
|
|
1300
|
+
|
|
1301
|
+
context 'when there is one argument' do
|
|
1302
|
+
|
|
1303
|
+
let(:selection) do
|
|
1304
|
+
query.where(foo: 'bar').any_of(field: [ 1, 2 ])
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
it 'adds the new condition' do
|
|
1308
|
+
expect(selection.selector).to eq(
|
|
1309
|
+
'foo' => 'bar',
|
|
1310
|
+
'field' => [1, 2],
|
|
1311
|
+
)
|
|
1312
|
+
end
|
|
1313
|
+
end
|
|
1314
|
+
|
|
1315
|
+
context 'when there are multiple arguments' do
|
|
1316
|
+
|
|
1317
|
+
let(:selection) do
|
|
1318
|
+
query.where(foo: 'bar').any_of({field: [ 1, 2 ]}, {hello: 'world'})
|
|
1319
|
+
end
|
|
1320
|
+
|
|
1321
|
+
it 'adds the new condition' do
|
|
1322
|
+
expect(selection.selector).to eq(
|
|
1323
|
+
'foo' => 'bar',
|
|
1324
|
+
'$or' => [
|
|
1325
|
+
{'field' => [1, 2]},
|
|
1326
|
+
{'hello' => 'world'},
|
|
1327
|
+
],
|
|
1328
|
+
)
|
|
1329
|
+
end
|
|
1330
|
+
end
|
|
1331
|
+
end
|
|
1332
|
+
|
|
1333
|
+
context 'when query already has an $or condition and another condition' do
|
|
1334
|
+
|
|
1335
|
+
let(:selection) do
|
|
1336
|
+
query.or(field: [ 1, 2 ]).where(foo: 'bar').any_of(test: 1)
|
|
1337
|
+
end
|
|
1338
|
+
|
|
1339
|
+
it 'adds the new condition' do
|
|
1340
|
+
expect(selection.selector).to eq(
|
|
1341
|
+
'$or' => [{'field' => [1, 2]}],
|
|
1342
|
+
'foo' => 'bar',
|
|
1343
|
+
'test' => 1,
|
|
1344
|
+
)
|
|
1345
|
+
end
|
|
1346
|
+
end
|
|
1347
|
+
|
|
1348
|
+
context 'when any_of has multiple arguments' do
|
|
1349
|
+
|
|
1350
|
+
let(:selection) do
|
|
1351
|
+
query.or(field: [ 1, 2 ]).where(foo: 'bar').any_of({a: 1}, {b: 2})
|
|
1352
|
+
end
|
|
1353
|
+
|
|
1354
|
+
it 'adds the new condition to top level' do
|
|
1355
|
+
expect(selection.selector).to eq(
|
|
1356
|
+
'$or' => [{'field' => [1, 2]}],
|
|
1357
|
+
'foo' => 'bar',
|
|
1358
|
+
'$and' => [{'$or' => [{'a' => 1}, {'b' => 2}]}],
|
|
1359
|
+
)
|
|
1360
|
+
end
|
|
1361
|
+
|
|
1362
|
+
context 'when query already has a top-level $and' do
|
|
1363
|
+
let(:selection) do
|
|
1364
|
+
query.or(field: [ 1, 2 ]).where('$and' => [foo: 'bar']).any_of({a: 1}, {b: 2})
|
|
1365
|
+
end
|
|
1366
|
+
|
|
1367
|
+
it 'adds the new condition to top level $and' do
|
|
1368
|
+
expect(selection.selector).to eq(
|
|
1369
|
+
'$or' => [{'field' => [1, 2]}],
|
|
1370
|
+
'$and' => [{'foo' => 'bar'}, {'$or' => [{'a' => 1}, {'b' => 2}]}],
|
|
1371
|
+
)
|
|
1372
|
+
end
|
|
1373
|
+
end
|
|
1374
|
+
end
|
|
1375
|
+
end
|
|
1376
|
+
|
|
1377
|
+
context "when provided multiple criteria" do
|
|
1378
|
+
|
|
1379
|
+
context "when the criteria are for different fields" do
|
|
1380
|
+
|
|
1381
|
+
let(:selection) do
|
|
1382
|
+
query.any_of({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
it_behaves_like 'returns a cloned query'
|
|
1386
|
+
|
|
1387
|
+
it "adds the $or selector" do
|
|
1388
|
+
expect(selection.selector).to eq({
|
|
1389
|
+
"$or" => [
|
|
1390
|
+
{ "first" => [ 1, 2 ] },
|
|
1391
|
+
{ "second" => [ 3, 4 ] }
|
|
1392
|
+
]
|
|
1393
|
+
})
|
|
1394
|
+
end
|
|
1395
|
+
end
|
|
1396
|
+
|
|
1397
|
+
context "when the criteria uses a Key instance" do
|
|
1398
|
+
|
|
1399
|
+
let(:selection) do
|
|
1400
|
+
query.any_of({ first: [ 1, 2 ] }, { :second.gt => 3 })
|
|
1401
|
+
end
|
|
1402
|
+
|
|
1403
|
+
it "adds the $or selector" do
|
|
1404
|
+
expect(selection.selector).to eq({
|
|
1405
|
+
"$or" => [
|
|
1406
|
+
{ "first" => [ 1, 2 ] },
|
|
1407
|
+
{ "second" => { "$gt" => 3 }}
|
|
1408
|
+
]
|
|
1409
|
+
})
|
|
1410
|
+
end
|
|
1411
|
+
|
|
1412
|
+
it_behaves_like 'returns a cloned query'
|
|
1413
|
+
end
|
|
1414
|
+
|
|
1415
|
+
context 'when criteria are simple and handled via Key' do
|
|
1416
|
+
shared_examples_for 'adds conditions with $or' do
|
|
1417
|
+
|
|
1418
|
+
it "adds conditions with $or" do
|
|
1419
|
+
expect(selection.selector).to eq({
|
|
1420
|
+
'$or' => [
|
|
1421
|
+
{'field' => 3},
|
|
1422
|
+
{'field' => {'$lt' => 5}},
|
|
1423
|
+
],
|
|
1424
|
+
})
|
|
1425
|
+
end
|
|
1426
|
+
|
|
1427
|
+
it_behaves_like 'returns a cloned query'
|
|
1428
|
+
end
|
|
1429
|
+
|
|
1430
|
+
shared_examples_for 'combines conditions with $eq' do
|
|
1431
|
+
|
|
1432
|
+
it "combines conditions with $eq" do
|
|
1433
|
+
expect(selection.selector).to eq({
|
|
1434
|
+
'field' => {
|
|
1435
|
+
'$eq' => 3,
|
|
1436
|
+
'$lt' => 5,
|
|
1437
|
+
},
|
|
1438
|
+
})
|
|
1439
|
+
end
|
|
1440
|
+
|
|
1441
|
+
it_behaves_like 'returns a cloned query'
|
|
1442
|
+
end
|
|
1443
|
+
|
|
1444
|
+
shared_examples_for 'combines conditions with $regex' do
|
|
1445
|
+
|
|
1446
|
+
it "combines conditions with $regex" do
|
|
1447
|
+
expect(selection.selector).to eq({
|
|
1448
|
+
'field' => {
|
|
1449
|
+
'$regex' => /t/,
|
|
1450
|
+
'$lt' => 5,
|
|
1451
|
+
},
|
|
1452
|
+
})
|
|
1453
|
+
end
|
|
1454
|
+
|
|
1455
|
+
it_behaves_like 'returns a cloned query'
|
|
1456
|
+
end
|
|
1457
|
+
|
|
1458
|
+
context 'criteria are provided in the same hash' do
|
|
1459
|
+
context 'non-regexp argument' do
|
|
1460
|
+
let(:selection) do
|
|
1461
|
+
query.send(tested_method, :field => 3, :field.lt => 5)
|
|
1462
|
+
end
|
|
1463
|
+
|
|
1464
|
+
it_behaves_like 'combines conditions with $eq'
|
|
1465
|
+
end
|
|
1466
|
+
|
|
1467
|
+
context 'regexp argument' do
|
|
1468
|
+
let(:selection) do
|
|
1469
|
+
query.send(tested_method, :field => /t/, :field.lt => 5)
|
|
1470
|
+
end
|
|
1471
|
+
|
|
1472
|
+
it_behaves_like 'combines conditions with $regex'
|
|
1473
|
+
end
|
|
1474
|
+
end
|
|
1475
|
+
|
|
1476
|
+
context 'criteria are provided in separate hashes' do
|
|
1477
|
+
let(:selection) do
|
|
1478
|
+
query.send(tested_method, {:field => 3}, {:field.lt => 5})
|
|
1479
|
+
end
|
|
1480
|
+
|
|
1481
|
+
it_behaves_like 'adds conditions with $or'
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1484
|
+
context 'when the criterion is wrapped in an array' do
|
|
1485
|
+
let(:selection) do
|
|
1486
|
+
query.send(tested_method, [:field => 3], [:field.lt => 5])
|
|
1487
|
+
end
|
|
1488
|
+
|
|
1489
|
+
it_behaves_like 'adds conditions with $or'
|
|
1490
|
+
end
|
|
1491
|
+
end
|
|
1492
|
+
|
|
1493
|
+
context 'when criteria are handled via Key and simple' do
|
|
1494
|
+
shared_examples_for 'adds conditions with $or' do
|
|
1495
|
+
|
|
1496
|
+
it "adds conditions with $or" do
|
|
1497
|
+
expect(selection.selector).to eq({
|
|
1498
|
+
'$or' => [
|
|
1499
|
+
{'field' => {'$gt' => 3}},
|
|
1500
|
+
{'field' => 5},
|
|
1501
|
+
],
|
|
1502
|
+
})
|
|
1503
|
+
end
|
|
1504
|
+
|
|
1505
|
+
it_behaves_like 'returns a cloned query'
|
|
1506
|
+
end
|
|
1507
|
+
|
|
1508
|
+
shared_examples_for 'combines conditions with $eq' do
|
|
1509
|
+
|
|
1510
|
+
it "combines conditions with $eq" do
|
|
1511
|
+
expect(selection.selector).to eq(
|
|
1512
|
+
'field' => {'$gt' => 3, '$eq' => 5},
|
|
1513
|
+
)
|
|
1514
|
+
end
|
|
1515
|
+
|
|
1516
|
+
it_behaves_like 'returns a cloned query'
|
|
1517
|
+
end
|
|
1518
|
+
|
|
1519
|
+
shared_examples_for 'combines conditions with $regex' do
|
|
1520
|
+
|
|
1521
|
+
it "combines conditions with $regex" do
|
|
1522
|
+
expect(selection.selector).to eq(
|
|
1523
|
+
'field' => {'$gt' => 3, '$regex' => /t/},
|
|
1524
|
+
)
|
|
1525
|
+
end
|
|
1526
|
+
|
|
1527
|
+
it_behaves_like 'returns a cloned query'
|
|
1528
|
+
end
|
|
1529
|
+
|
|
1530
|
+
context 'criteria are provided in the same hash' do
|
|
1531
|
+
context 'non-regexp argument' do
|
|
1532
|
+
let(:selection) do
|
|
1533
|
+
query.send(tested_method, :field.gt => 3, :field => 5)
|
|
1534
|
+
end
|
|
1535
|
+
|
|
1536
|
+
it_behaves_like 'combines conditions with $eq'
|
|
1537
|
+
end
|
|
1538
|
+
|
|
1539
|
+
context 'regexp argument' do
|
|
1540
|
+
let(:selection) do
|
|
1541
|
+
query.send(tested_method, :field.gt => 3, :field => /t/)
|
|
1542
|
+
end
|
|
1543
|
+
|
|
1544
|
+
it_behaves_like 'combines conditions with $regex'
|
|
1545
|
+
end
|
|
1546
|
+
end
|
|
1547
|
+
|
|
1548
|
+
context 'criteria are provided in separate hashes' do
|
|
1549
|
+
let(:selection) do
|
|
1550
|
+
query.send(tested_method, {:field.gt => 3}, {:field => 5})
|
|
1551
|
+
end
|
|
1552
|
+
|
|
1553
|
+
it_behaves_like 'adds conditions with $or'
|
|
1554
|
+
end
|
|
1555
|
+
|
|
1556
|
+
context 'when the criterion is wrapped in an array' do
|
|
1557
|
+
let(:selection) do
|
|
1558
|
+
query.send(tested_method, [:field.gt => 3], [:field => 5])
|
|
1559
|
+
end
|
|
1560
|
+
|
|
1561
|
+
it_behaves_like 'adds conditions with $or'
|
|
1562
|
+
end
|
|
1563
|
+
end
|
|
1564
|
+
|
|
1565
|
+
context "when a criterion has an aliased field" do
|
|
1566
|
+
|
|
1567
|
+
let(:selection) do
|
|
1568
|
+
query.any_of({ id: 1 })
|
|
1569
|
+
end
|
|
1570
|
+
|
|
1571
|
+
it "adds the $or selector and aliases the field" do
|
|
1572
|
+
expect(selection.selector).to eq(
|
|
1573
|
+
"_id" => 1,
|
|
1574
|
+
)
|
|
1575
|
+
end
|
|
1576
|
+
|
|
1577
|
+
it_behaves_like 'returns a cloned query'
|
|
1578
|
+
end
|
|
1579
|
+
|
|
1580
|
+
context "when a criterion is wrapped in an array" do
|
|
1581
|
+
|
|
1582
|
+
let(:selection) do
|
|
1583
|
+
query.any_of([{ first: [ 1, 2 ] }, { :second.gt => 3 }])
|
|
1584
|
+
end
|
|
1585
|
+
|
|
1586
|
+
it_behaves_like 'returns a cloned query'
|
|
1587
|
+
|
|
1588
|
+
it "adds the $or selector" do
|
|
1589
|
+
expect(selection.selector).to eq({
|
|
1590
|
+
"$or" => [
|
|
1591
|
+
{ "first" => [ 1, 2 ] },
|
|
1592
|
+
{ "second" => { "$gt" => 3 }}
|
|
1593
|
+
]
|
|
1594
|
+
})
|
|
1595
|
+
end
|
|
1596
|
+
end
|
|
1597
|
+
|
|
1598
|
+
context "when the criteria are on the same field" do
|
|
1599
|
+
|
|
1600
|
+
let(:selection) do
|
|
1601
|
+
query.any_of({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
|
1602
|
+
end
|
|
1603
|
+
|
|
1604
|
+
it_behaves_like 'returns a cloned query'
|
|
1605
|
+
|
|
1606
|
+
it "appends both $or expressions" do
|
|
1607
|
+
expect(selection.selector).to eq({
|
|
1608
|
+
"$or" => [
|
|
1609
|
+
{ "first" => [ 1, 2 ] },
|
|
1610
|
+
{ "first" => [ 3, 4 ] }
|
|
1611
|
+
]
|
|
1612
|
+
})
|
|
1613
|
+
end
|
|
1614
|
+
end
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
context "when chaining the criteria" do
|
|
1618
|
+
|
|
1619
|
+
context "when the criteria are for different fields" do
|
|
1620
|
+
|
|
1621
|
+
let(:selection) do
|
|
1622
|
+
query.any_of(first: [ 1, 2 ]).any_of(second: [ 3, 4 ])
|
|
1623
|
+
end
|
|
1624
|
+
|
|
1625
|
+
it_behaves_like 'returns a cloned query'
|
|
1626
|
+
|
|
1627
|
+
it "adds the conditions separately" do
|
|
1628
|
+
expect(selection.selector).to eq(
|
|
1629
|
+
"first" => [ 1, 2 ],
|
|
1630
|
+
"second" => [ 3, 4 ],
|
|
1631
|
+
)
|
|
1632
|
+
end
|
|
1633
|
+
end
|
|
1634
|
+
|
|
1635
|
+
context "when the criteria are on the same field" do
|
|
1636
|
+
|
|
1637
|
+
let(:selection) do
|
|
1638
|
+
query.any_of(first: [ 1, 2 ]).any_of(first: [ 3, 4 ])
|
|
1639
|
+
end
|
|
1640
|
+
|
|
1641
|
+
it_behaves_like 'returns a cloned query'
|
|
1642
|
+
|
|
1643
|
+
it "adds the conditions separately" do
|
|
1644
|
+
expect(selection.selector).to eq(
|
|
1645
|
+
"first" => [ 1, 2 ],
|
|
1646
|
+
'$and' => [{"first" => [ 3, 4 ]}],
|
|
1647
|
+
)
|
|
1648
|
+
end
|
|
1649
|
+
end
|
|
1650
|
+
end
|
|
1651
|
+
|
|
1652
|
+
context 'when using multiple criteria and symbol operators' do
|
|
1653
|
+
context 'when using fields that meaningfully evolve values' do
|
|
1654
|
+
|
|
1655
|
+
let(:query) do
|
|
1656
|
+
Dictionary.any_of({a: 1}, :published.gt => Date.new(2020, 2, 3))
|
|
1657
|
+
end
|
|
1658
|
+
|
|
1659
|
+
it 'generates the expected query' do
|
|
1660
|
+
query.selector.should == {'$or' => [
|
|
1661
|
+
{'a' => 1},
|
|
1662
|
+
# Date instance is converted to a Time instance in local time,
|
|
1663
|
+
# because we are querying on a Time field and dates are interpreted
|
|
1664
|
+
# in local time when assigning to Time fields
|
|
1665
|
+
{'published' => {'$gt' => Time.local(2020, 2, 3)}},
|
|
1666
|
+
]}
|
|
1667
|
+
end
|
|
1668
|
+
end
|
|
1669
|
+
|
|
1670
|
+
context 'when using fields that do not meaningfully evolve values' do
|
|
1671
|
+
|
|
1672
|
+
let(:query) do
|
|
1673
|
+
Dictionary.any_of({a: 1}, :submitted_on.gt => Date.new(2020, 2, 3))
|
|
1674
|
+
end
|
|
1675
|
+
|
|
1676
|
+
it 'generates the expected query' do
|
|
1677
|
+
query.selector.should == {'$or' => [
|
|
1678
|
+
{'a' => 1},
|
|
1679
|
+
# Date instance is converted to a Time instance in UTC,
|
|
1680
|
+
# because we are querying on a Date field and dates are interpreted
|
|
1681
|
+
# in UTC when persisted as dates by Mongoid
|
|
1682
|
+
{'submitted_on' => {'$gt' => Time.utc(2020, 2, 3)}},
|
|
1683
|
+
]}
|
|
1684
|
+
end
|
|
1685
|
+
end
|
|
1686
|
+
end
|
|
1687
|
+
end
|
|
1688
|
+
|
|
1689
|
+
describe "#not" do
|
|
1690
|
+
|
|
1691
|
+
context "when provided no criterion" do
|
|
1692
|
+
|
|
1693
|
+
let(:selection) do
|
|
1694
|
+
query.not
|
|
1695
|
+
end
|
|
1696
|
+
|
|
1697
|
+
it "does not add any criterion" do
|
|
1698
|
+
expect(selection.selector).to eq({})
|
|
1699
|
+
end
|
|
1700
|
+
|
|
1701
|
+
it "returns the query" do
|
|
1702
|
+
expect(selection).to eq(query)
|
|
1703
|
+
end
|
|
1704
|
+
|
|
1705
|
+
it "returns a cloned query" do
|
|
1706
|
+
expect(selection).not_to equal(query)
|
|
1707
|
+
end
|
|
1708
|
+
|
|
1709
|
+
it 'does not mutate receiver' do
|
|
1710
|
+
expect(query.negating).to be nil
|
|
1711
|
+
|
|
1712
|
+
selection
|
|
1713
|
+
expect(query.negating).to be nil
|
|
1714
|
+
end
|
|
1715
|
+
|
|
1716
|
+
shared_examples_for 'negates the next condition' do
|
|
1717
|
+
let(:selection) do
|
|
1718
|
+
query.not.send(query_method, field: [ 1, 2 ])
|
|
1719
|
+
end
|
|
1720
|
+
|
|
1721
|
+
it "negates the next condition" do
|
|
1722
|
+
expect(selection.selector).to eq(
|
|
1723
|
+
{ "field" => { "$not" => { operator => [ 1, 2 ] }}}
|
|
1724
|
+
)
|
|
1725
|
+
end
|
|
1726
|
+
|
|
1727
|
+
it_behaves_like 'returns a cloned query'
|
|
1728
|
+
|
|
1729
|
+
it "removes the negation on the clone" do
|
|
1730
|
+
expect(selection).to_not be_negating
|
|
1731
|
+
end
|
|
1732
|
+
end
|
|
1733
|
+
|
|
1734
|
+
context "when the next condition is #all" do
|
|
1735
|
+
let(:query_method) { :all }
|
|
1736
|
+
let(:operator) { '$all' }
|
|
1737
|
+
|
|
1738
|
+
it_behaves_like 'negates the next condition'
|
|
1739
|
+
end
|
|
1740
|
+
|
|
1741
|
+
context "when the next condition is #in" do
|
|
1742
|
+
let(:query_method) { :in }
|
|
1743
|
+
let(:operator) { '$in' }
|
|
1744
|
+
|
|
1745
|
+
it_behaves_like 'negates the next condition'
|
|
1746
|
+
end
|
|
1747
|
+
|
|
1748
|
+
context "when the next condition is #nin" do
|
|
1749
|
+
let(:query_method) { :nin }
|
|
1750
|
+
let(:operator) { '$nin' }
|
|
1751
|
+
|
|
1752
|
+
it_behaves_like 'negates the next condition'
|
|
1753
|
+
end
|
|
1754
|
+
|
|
1755
|
+
context "when the following criteria is a gt method" do
|
|
1756
|
+
|
|
1757
|
+
let(:selection) do
|
|
1758
|
+
query.not.gt(age: 50)
|
|
1759
|
+
end
|
|
1760
|
+
|
|
1761
|
+
it "negates the gt selection" do
|
|
1762
|
+
expect(selection.selector).to eq(
|
|
1763
|
+
{ "age" => { "$not" => { "$gt" => 50 }}}
|
|
1764
|
+
)
|
|
1765
|
+
end
|
|
1766
|
+
|
|
1767
|
+
it_behaves_like 'returns a cloned query'
|
|
1768
|
+
|
|
1769
|
+
it "removes the negation on the clone" do
|
|
1770
|
+
expect(selection).to_not be_negating
|
|
1771
|
+
end
|
|
1772
|
+
end
|
|
1773
|
+
|
|
1774
|
+
context "when the criteria uses Key" do
|
|
1775
|
+
|
|
1776
|
+
let(:selection) do
|
|
1777
|
+
query.not(:age.gt => 50)
|
|
1778
|
+
end
|
|
1779
|
+
|
|
1780
|
+
it "negates the gt selection" do
|
|
1781
|
+
expect(selection.selector).to eq(
|
|
1782
|
+
'$and' => ['$nor' => ['age' => {'$gt' => 50}]]
|
|
1783
|
+
)
|
|
1784
|
+
end
|
|
1785
|
+
|
|
1786
|
+
it_behaves_like 'returns a cloned query'
|
|
1787
|
+
|
|
1788
|
+
it "removes the negation on the clone" do
|
|
1789
|
+
expect(selection).to_not be_negating
|
|
1790
|
+
end
|
|
1791
|
+
end
|
|
1792
|
+
|
|
1793
|
+
context "when the following criteria is a where" do
|
|
1794
|
+
|
|
1795
|
+
let(:selection) do
|
|
1796
|
+
query.not.where(field: 1, :other.in => [ 1, 2 ])
|
|
1797
|
+
end
|
|
1798
|
+
|
|
1799
|
+
it "negates the selection with an operator" do
|
|
1800
|
+
expect(selection.selector).to eq(
|
|
1801
|
+
{ "field" => { "$ne" => 1 }, "other" => { "$not" => { "$in" => [ 1, 2 ] }}}
|
|
1802
|
+
)
|
|
1803
|
+
end
|
|
1804
|
+
|
|
1805
|
+
it_behaves_like 'returns a cloned query'
|
|
1806
|
+
|
|
1807
|
+
it "removes the negation on the clone" do
|
|
1808
|
+
expect(selection).to_not be_negating
|
|
1809
|
+
end
|
|
1810
|
+
end
|
|
1811
|
+
|
|
1812
|
+
context "when the following criteria is a where with a regexp" do
|
|
1813
|
+
|
|
1814
|
+
let(:selection) do
|
|
1815
|
+
query.not.where(field: 1, other: /test/)
|
|
1816
|
+
end
|
|
1817
|
+
|
|
1818
|
+
it "negates the selection with an operator" do
|
|
1819
|
+
expect(selection.selector).to eq(
|
|
1820
|
+
{ "field" => { "$ne" => 1 }, "other" => { "$not" => /test/ } }
|
|
1821
|
+
)
|
|
1822
|
+
end
|
|
1823
|
+
|
|
1824
|
+
it_behaves_like 'returns a cloned query'
|
|
1825
|
+
|
|
1826
|
+
it "removes the negation on the clone" do
|
|
1827
|
+
expect(selection).to_not be_negating
|
|
1828
|
+
end
|
|
1829
|
+
end
|
|
1830
|
+
|
|
1831
|
+
context 'when the following criteria uses string were form' do
|
|
1832
|
+
|
|
1833
|
+
let(:selection) do
|
|
1834
|
+
query.not.where('hello world')
|
|
1835
|
+
end
|
|
1836
|
+
|
|
1837
|
+
it "negates the selection with an operator" do
|
|
1838
|
+
expect(selection.selector).to eq(
|
|
1839
|
+
'$and' => [{'$nor' => [{'$where' => 'hello world'}]}]
|
|
1840
|
+
)
|
|
1841
|
+
end
|
|
1842
|
+
|
|
1843
|
+
it_behaves_like 'returns a cloned query'
|
|
1844
|
+
|
|
1845
|
+
it "removes the negation on the clone" do
|
|
1846
|
+
expect(selection).to_not be_negating
|
|
1847
|
+
end
|
|
1848
|
+
|
|
1849
|
+
end
|
|
1850
|
+
end
|
|
1851
|
+
|
|
1852
|
+
context "when provided nil" do
|
|
1853
|
+
|
|
1854
|
+
let(:selection) do
|
|
1855
|
+
query.not(nil)
|
|
1856
|
+
end
|
|
1857
|
+
|
|
1858
|
+
it "does not add any criterion" do
|
|
1859
|
+
expect(selection.selector).to eq({})
|
|
1860
|
+
end
|
|
1861
|
+
|
|
1862
|
+
it "returns the query" do
|
|
1863
|
+
expect(selection).to eq(query)
|
|
1864
|
+
end
|
|
1865
|
+
|
|
1866
|
+
it_behaves_like 'returns a cloned query'
|
|
1867
|
+
end
|
|
1868
|
+
|
|
1869
|
+
context "when provided a single criterion" do
|
|
1870
|
+
|
|
1871
|
+
let(:selection) do
|
|
1872
|
+
query.not(field: /test/)
|
|
1873
|
+
end
|
|
1874
|
+
|
|
1875
|
+
it "adds the $not selector" do
|
|
1876
|
+
expect(selection.selector).to eq({
|
|
1877
|
+
"field" => { "$not" => /test/ }
|
|
1878
|
+
})
|
|
1879
|
+
end
|
|
1880
|
+
|
|
1881
|
+
it_behaves_like 'returns a cloned query'
|
|
1882
|
+
end
|
|
1883
|
+
|
|
1884
|
+
context "when negating a field in the original selector" do
|
|
1885
|
+
let(:query) do
|
|
1886
|
+
Mongoid::Query.new("id" => "_id").where(field: 'foo')
|
|
1887
|
+
end
|
|
1888
|
+
|
|
1889
|
+
let(:selection) do
|
|
1890
|
+
query.not(field: 'bar')
|
|
1891
|
+
end
|
|
1892
|
+
|
|
1893
|
+
it "combines the conditions" do
|
|
1894
|
+
expect(selection.selector).to eq({
|
|
1895
|
+
"field" => 'foo',
|
|
1896
|
+
'$and' => [{'$nor' => [{ "field" => 'bar' }]}],
|
|
1897
|
+
})
|
|
1898
|
+
end
|
|
1899
|
+
|
|
1900
|
+
it_behaves_like 'returns a cloned query'
|
|
1901
|
+
end
|
|
1902
|
+
|
|
1903
|
+
context "when provided multiple criteria" do
|
|
1904
|
+
|
|
1905
|
+
context "when the criteria are for different fields" do
|
|
1906
|
+
|
|
1907
|
+
let(:selection) do
|
|
1908
|
+
query.not(first: /1/, second: /2/)
|
|
1909
|
+
end
|
|
1910
|
+
|
|
1911
|
+
it "adds the $not selectors" do
|
|
1912
|
+
expect(selection.selector).to eq({
|
|
1913
|
+
"first" => { "$not" => /1/ },
|
|
1914
|
+
"second" => { "$not" => /2/ }
|
|
1915
|
+
})
|
|
1916
|
+
end
|
|
1917
|
+
|
|
1918
|
+
it_behaves_like 'returns a cloned query'
|
|
1919
|
+
end
|
|
1920
|
+
|
|
1921
|
+
context "when the criteria are given in separate arguments" do
|
|
1922
|
+
|
|
1923
|
+
let(:selection) do
|
|
1924
|
+
query.not({first: /1/}, {second: /2/})
|
|
1925
|
+
end
|
|
1926
|
+
|
|
1927
|
+
it "adds the $not selectors" do
|
|
1928
|
+
expect(selection.selector).to eq({
|
|
1929
|
+
"first" => { "$not" => /1/ },
|
|
1930
|
+
"second" => { "$not" => /2/ }
|
|
1931
|
+
})
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1934
|
+
it_behaves_like 'returns a cloned query'
|
|
1935
|
+
end
|
|
1936
|
+
end
|
|
1937
|
+
|
|
1938
|
+
context "when chaining the criterion" do
|
|
1939
|
+
|
|
1940
|
+
context "when the criterion are for different fields" do
|
|
1941
|
+
|
|
1942
|
+
let(:selection) do
|
|
1943
|
+
query.not(first: /1/).not(second: /2/)
|
|
1944
|
+
end
|
|
1945
|
+
|
|
1946
|
+
it "adds the $not selectors" do
|
|
1947
|
+
expect(selection.selector).to eq({
|
|
1948
|
+
"first" => { "$not" => /1/ },
|
|
1949
|
+
"second" => { "$not" => /2/ }
|
|
1950
|
+
})
|
|
1951
|
+
end
|
|
1952
|
+
|
|
1953
|
+
it_behaves_like 'returns a cloned query'
|
|
1954
|
+
end
|
|
1955
|
+
|
|
1956
|
+
context "when the criterion are on the same field" do
|
|
1957
|
+
|
|
1958
|
+
let(:selection) do
|
|
1959
|
+
query.not(first: /1/).not(first: /2/)
|
|
1960
|
+
end
|
|
1961
|
+
|
|
1962
|
+
it "combines conditions" do
|
|
1963
|
+
expect(selection.selector).to eq(
|
|
1964
|
+
"first" => { "$not" => /1/ },
|
|
1965
|
+
'$and' => [{'$nor' => [{'first' => /2/}]}],
|
|
1966
|
+
)
|
|
1967
|
+
end
|
|
1968
|
+
|
|
1969
|
+
it_behaves_like 'returns a cloned query'
|
|
1970
|
+
end
|
|
1971
|
+
|
|
1972
|
+
context "when the criterion are a double negative" do
|
|
1973
|
+
|
|
1974
|
+
let(:selection) do
|
|
1975
|
+
query.not.where(:first.not => /1/)
|
|
1976
|
+
end
|
|
1977
|
+
|
|
1978
|
+
it "does not double the $not selector" do
|
|
1979
|
+
expect(selection.selector).to eq({
|
|
1980
|
+
"first" => { "$not" => /1/ }
|
|
1981
|
+
})
|
|
1982
|
+
end
|
|
1983
|
+
|
|
1984
|
+
it_behaves_like 'returns a cloned query'
|
|
1985
|
+
end
|
|
1986
|
+
end
|
|
1987
|
+
|
|
1988
|
+
context 'when argument is a Criteria' do
|
|
1989
|
+
let(:query) do
|
|
1990
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
1991
|
+
end
|
|
1992
|
+
|
|
1993
|
+
let(:other) do
|
|
1994
|
+
Mongoid::Query.new.where(foo: 'bar')
|
|
1995
|
+
end
|
|
1996
|
+
|
|
1997
|
+
let(:result) { query.not(other) }
|
|
1998
|
+
|
|
1999
|
+
it 'combines' do
|
|
2000
|
+
expect(result.selector).to eq('hello' => 'world', 'foo' => {'$ne' => 'bar'})
|
|
2001
|
+
end
|
|
2002
|
+
end
|
|
2003
|
+
|
|
2004
|
+
context 'when argument is a simple Criteria with multiple fields' do
|
|
2005
|
+
let(:query) do
|
|
2006
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
2007
|
+
end
|
|
2008
|
+
|
|
2009
|
+
let(:other) do
|
|
2010
|
+
Mongoid::Query.new.where(a: 1, b: 2)
|
|
2011
|
+
end
|
|
2012
|
+
|
|
2013
|
+
let(:result) { query.not(other) }
|
|
2014
|
+
|
|
2015
|
+
it 'combines fields into top level criteria' do
|
|
2016
|
+
expect(result.selector).to eq('hello' => 'world',
|
|
2017
|
+
'a' => {'$ne' => 1}, 'b' => {'$ne' => 2})
|
|
2018
|
+
end
|
|
2019
|
+
end
|
|
2020
|
+
|
|
2021
|
+
context 'when argument is a complex Criteria' do
|
|
2022
|
+
let(:query) do
|
|
2023
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
2024
|
+
end
|
|
2025
|
+
|
|
2026
|
+
let(:other) do
|
|
2027
|
+
Mongoid::Query.new.where('$nor' => [{a: 1, b: 2}])
|
|
2028
|
+
end
|
|
2029
|
+
|
|
2030
|
+
let(:result) { query.not(other) }
|
|
2031
|
+
|
|
2032
|
+
it 'combines with $and of $nor' do
|
|
2033
|
+
expect(result.selector).to eq('hello' => 'world', '$and' => [{'$nor' => [{
|
|
2034
|
+
'$nor' => [{'a' => 1, 'b' => 2}]}]}])
|
|
2035
|
+
end
|
|
2036
|
+
end
|
|
2037
|
+
|
|
2038
|
+
context 'when argument is a mix of Criteria and hashes' do
|
|
2039
|
+
let(:query) do
|
|
2040
|
+
Mongoid::Query.new.where(hello: 'world')
|
|
2041
|
+
end
|
|
2042
|
+
|
|
2043
|
+
let(:other1) do
|
|
2044
|
+
Mongoid::Query.new.where(foo: 'bar')
|
|
2045
|
+
end
|
|
2046
|
+
|
|
2047
|
+
let(:other2) do
|
|
2048
|
+
{bar: 42}
|
|
2049
|
+
end
|
|
2050
|
+
|
|
2051
|
+
let(:other3) do
|
|
2052
|
+
Mongoid::Query.new.where(a: 2)
|
|
2053
|
+
end
|
|
2054
|
+
|
|
2055
|
+
let(:result) { query.not(other1, other2, other3) }
|
|
2056
|
+
|
|
2057
|
+
it 'combines' do
|
|
2058
|
+
expect(result.selector).to eq('hello' => 'world',
|
|
2059
|
+
'foo' => {'$ne' => 'bar'},
|
|
2060
|
+
'bar' => {'$ne' => 42},
|
|
2061
|
+
'a' => {'$ne' => 2},
|
|
2062
|
+
)
|
|
2063
|
+
end
|
|
2064
|
+
end
|
|
2065
|
+
|
|
2066
|
+
context 'when giving multiple conditions in one call on the same key with symbol operator' do
|
|
2067
|
+
|
|
2068
|
+
context 'non-regexp argument' do
|
|
2069
|
+
let(:selection) do
|
|
2070
|
+
query.not(field: 1, :field.gt => 0)
|
|
2071
|
+
end
|
|
2072
|
+
|
|
2073
|
+
it 'combines conditions with $eq' do
|
|
2074
|
+
selection.selector.should == {
|
|
2075
|
+
'$and' => ['$nor' => [
|
|
2076
|
+
'field' => {'$eq' => 1, '$gt' => 0},
|
|
2077
|
+
]]
|
|
2078
|
+
}
|
|
2079
|
+
end
|
|
2080
|
+
end
|
|
2081
|
+
|
|
2082
|
+
context 'regexp argument' do
|
|
2083
|
+
let(:selection) do
|
|
2084
|
+
query.not(field: /t/, :field.gt => 0)
|
|
2085
|
+
end
|
|
2086
|
+
|
|
2087
|
+
it 'combines conditions with $regex' do
|
|
2088
|
+
selection.selector.should == {
|
|
2089
|
+
'$and' => ['$nor' => [
|
|
2090
|
+
'field' => {'$regex' => /t/, '$gt' => 0},
|
|
2091
|
+
]]
|
|
2092
|
+
}
|
|
2093
|
+
end
|
|
2094
|
+
end
|
|
2095
|
+
end
|
|
2096
|
+
|
|
2097
|
+
# This test confirms that MONGOID-5097 has been repaired.
|
|
2098
|
+
context "when using exists on a field of type Time" do
|
|
2099
|
+
let(:criteria) do
|
|
2100
|
+
Dictionary.any_of({:published.exists => true}, published: nil)
|
|
2101
|
+
end
|
|
2102
|
+
|
|
2103
|
+
it "doesn't raise an error" do
|
|
2104
|
+
expect do
|
|
2105
|
+
criteria
|
|
2106
|
+
end.to_not raise_error
|
|
2107
|
+
end
|
|
2108
|
+
|
|
2109
|
+
it "generates the correct selector" do
|
|
2110
|
+
expect(criteria.selector).to eq({
|
|
2111
|
+
"$or" => [ {
|
|
2112
|
+
"published" => { "$exists" => true }
|
|
2113
|
+
}, {
|
|
2114
|
+
"published" => nil
|
|
2115
|
+
} ] } )
|
|
2116
|
+
end
|
|
2117
|
+
end
|
|
2118
|
+
end
|
|
2119
|
+
|
|
2120
|
+
describe "#none_of" do
|
|
2121
|
+
context 'when argument is a mix of Criteria and hashes' do
|
|
2122
|
+
let(:query) { Mongoid::Query.new.where(hello: 'world') }
|
|
2123
|
+
let(:other1) { Mongoid::Query.new.where(foo: 'bar') }
|
|
2124
|
+
let(:other2) { { bar: 42 } }
|
|
2125
|
+
let(:other3) { Mongoid::Query.new.where(a: 2) }
|
|
2126
|
+
|
|
2127
|
+
let(:result) { query.none_of(other1, other2, other3) }
|
|
2128
|
+
|
|
2129
|
+
it 'combines' do
|
|
2130
|
+
expect(result.selector).to eq(
|
|
2131
|
+
'hello' => 'world',
|
|
2132
|
+
'$nor' => [
|
|
2133
|
+
{'foo' => 'bar'},
|
|
2134
|
+
{'bar' => 42},
|
|
2135
|
+
{'a' => 2},
|
|
2136
|
+
],
|
|
2137
|
+
)
|
|
2138
|
+
end
|
|
2139
|
+
end
|
|
2140
|
+
|
|
2141
|
+
context "when provided no arguments" do
|
|
2142
|
+
let(:selection) { query.none_of }
|
|
2143
|
+
|
|
2144
|
+
it_behaves_like 'returns a cloned query'
|
|
2145
|
+
|
|
2146
|
+
it "does not add any criteria" do
|
|
2147
|
+
expect(selection.selector).to eq({})
|
|
2148
|
+
end
|
|
2149
|
+
|
|
2150
|
+
it "returns the query" do
|
|
2151
|
+
expect(selection).to eq(query)
|
|
2152
|
+
end
|
|
2153
|
+
end
|
|
2154
|
+
|
|
2155
|
+
context "when provided nil" do
|
|
2156
|
+
let(:selection) { query.none_of(nil) }
|
|
2157
|
+
|
|
2158
|
+
it_behaves_like 'returns a cloned query'
|
|
2159
|
+
|
|
2160
|
+
it "does not add any criteria" do
|
|
2161
|
+
expect(selection.selector).to eq({})
|
|
2162
|
+
end
|
|
2163
|
+
|
|
2164
|
+
it "returns the query" do
|
|
2165
|
+
expect(selection).to eq(query)
|
|
2166
|
+
end
|
|
2167
|
+
end
|
|
2168
|
+
|
|
2169
|
+
context "when provided a single criterion" do
|
|
2170
|
+
let(:selection) { query.none_of(field: [ 1, 2 ]) }
|
|
2171
|
+
|
|
2172
|
+
it_behaves_like 'returns a cloned query'
|
|
2173
|
+
|
|
2174
|
+
it 'adds the $nor selector' do
|
|
2175
|
+
expect(selection.selector).to eq(
|
|
2176
|
+
'$nor' => [ { 'field' => [ 1, 2 ] } ],
|
|
2177
|
+
)
|
|
2178
|
+
end
|
|
2179
|
+
|
|
2180
|
+
context 'when the criterion is wrapped in array' do
|
|
2181
|
+
let(:selection) { query.none_of([{ field: [ 1, 2 ] }]) }
|
|
2182
|
+
|
|
2183
|
+
it_behaves_like 'returns a cloned query'
|
|
2184
|
+
|
|
2185
|
+
it 'adds the condition' do
|
|
2186
|
+
expect(selection.selector).to eq(
|
|
2187
|
+
'$nor' => [ { 'field' => [ 1, 2 ] } ],
|
|
2188
|
+
)
|
|
2189
|
+
end
|
|
2190
|
+
|
|
2191
|
+
context 'when the array has nil as one of the elements' do
|
|
2192
|
+
let(:selection) { query.none_of([{ field: [ 1, 2 ] }, nil]) }
|
|
2193
|
+
|
|
2194
|
+
it_behaves_like 'returns a cloned query'
|
|
2195
|
+
|
|
2196
|
+
it 'adds the $nor selector ignoring the nil element' do
|
|
2197
|
+
expect(selection.selector).to eq(
|
|
2198
|
+
'$nor' => [ { 'field' => [ 1, 2 ] } ],
|
|
2199
|
+
)
|
|
2200
|
+
end
|
|
2201
|
+
end
|
|
2202
|
+
end
|
|
2203
|
+
|
|
2204
|
+
context 'when query already has a condition on another field' do
|
|
2205
|
+
context 'when there is one argument' do
|
|
2206
|
+
let(:selection) { query.where(foo: 'bar').none_of(field: [ 1, 2 ]) }
|
|
2207
|
+
|
|
2208
|
+
it 'adds the new condition' do
|
|
2209
|
+
expect(selection.selector).to eq(
|
|
2210
|
+
'foo' => 'bar',
|
|
2211
|
+
'$nor' => [ { 'field' => [1, 2] } ],
|
|
2212
|
+
)
|
|
2213
|
+
end
|
|
2214
|
+
end
|
|
2215
|
+
|
|
2216
|
+
context 'when there are multiple arguments' do
|
|
2217
|
+
let(:selection) do
|
|
2218
|
+
query.where(foo: 'bar').none_of({ field: [ 1, 2 ] }, { hello: 'world' })
|
|
2219
|
+
end
|
|
2220
|
+
|
|
2221
|
+
it 'adds the new condition' do
|
|
2222
|
+
expect(selection.selector).to eq(
|
|
2223
|
+
'foo' => 'bar',
|
|
2224
|
+
'$nor' => [
|
|
2225
|
+
{ 'field' => [1, 2] },
|
|
2226
|
+
{ 'hello' => 'world' },
|
|
2227
|
+
],
|
|
2228
|
+
)
|
|
2229
|
+
end
|
|
2230
|
+
end
|
|
2231
|
+
end
|
|
2232
|
+
|
|
2233
|
+
context 'when query already has a $nor condition and another condition' do
|
|
2234
|
+
let(:selection) do
|
|
2235
|
+
query.nor(field: [ 1, 2 ]).where(foo: 'bar').none_of(test: 1)
|
|
2236
|
+
end
|
|
2237
|
+
|
|
2238
|
+
it 'adds the new condition' do
|
|
2239
|
+
expect(selection.selector).to eq(
|
|
2240
|
+
'$nor' => [ { 'field' => [1, 2] } ],
|
|
2241
|
+
'foo' => 'bar',
|
|
2242
|
+
'$and' => [ { '$nor' => [ { 'test' => 1 } ] } ]
|
|
2243
|
+
)
|
|
2244
|
+
end
|
|
2245
|
+
end
|
|
2246
|
+
|
|
2247
|
+
context 'when none_of has multiple arguments' do
|
|
2248
|
+
let(:selection) do
|
|
2249
|
+
query.nor(field: [ 1, 2 ]).where(foo: 'bar').none_of({a: 1}, {b: 2})
|
|
2250
|
+
end
|
|
2251
|
+
|
|
2252
|
+
it 'adds the new condition to top level' do
|
|
2253
|
+
expect(selection.selector).to eq(
|
|
2254
|
+
'foo' => 'bar',
|
|
2255
|
+
'$nor' => [ { 'field' => [1, 2] } ],
|
|
2256
|
+
'$and' => [ { '$nor' => [ { 'a' => 1 }, { 'b' => 2 } ] } ]
|
|
2257
|
+
)
|
|
2258
|
+
end
|
|
2259
|
+
|
|
2260
|
+
context 'when query already has a top-level $and' do
|
|
2261
|
+
let(:selection) do
|
|
2262
|
+
query.nor(field: [ 1, 2 ]).where('$and' => [foo: 'bar']).none_of({a: 1}, {b: 2})
|
|
2263
|
+
end
|
|
2264
|
+
|
|
2265
|
+
it 'adds the new condition to top level $and' do
|
|
2266
|
+
expect(selection.selector).to eq(
|
|
2267
|
+
'$nor' => [ { 'field' => [1, 2] } ],
|
|
2268
|
+
'$and' => [
|
|
2269
|
+
{ 'foo' => 'bar' },
|
|
2270
|
+
{ '$nor' => [ { 'a' => 1 }, { 'b' => 2 } ] }
|
|
2271
|
+
],
|
|
2272
|
+
)
|
|
2273
|
+
end
|
|
2274
|
+
end
|
|
2275
|
+
end
|
|
2276
|
+
end
|
|
2277
|
+
|
|
2278
|
+
context "when provided multiple criteria" do
|
|
2279
|
+
context "when the criteria are for different fields" do
|
|
2280
|
+
let(:selection) do
|
|
2281
|
+
query.none_of({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
|
2282
|
+
end
|
|
2283
|
+
|
|
2284
|
+
it_behaves_like 'returns a cloned query'
|
|
2285
|
+
|
|
2286
|
+
it "adds the $nor selector" do
|
|
2287
|
+
expect(selection.selector).to eq({
|
|
2288
|
+
"$nor" => [
|
|
2289
|
+
{ "first" => [ 1, 2 ] },
|
|
2290
|
+
{ "second" => [ 3, 4 ] }
|
|
2291
|
+
]
|
|
2292
|
+
})
|
|
2293
|
+
end
|
|
2294
|
+
end
|
|
2295
|
+
|
|
2296
|
+
context "when the criteria uses a Key instance" do
|
|
2297
|
+
let(:selection) do
|
|
2298
|
+
query.none_of({ first: [ 1, 2 ] }, { :second.gt => 3 })
|
|
2299
|
+
end
|
|
2300
|
+
|
|
2301
|
+
it "adds the $nor selector" do
|
|
2302
|
+
expect(selection.selector).to eq({
|
|
2303
|
+
"$nor" => [
|
|
2304
|
+
{ "first" => [ 1, 2 ] },
|
|
2305
|
+
{ "second" => { "$gt" => 3 }}
|
|
2306
|
+
]
|
|
2307
|
+
})
|
|
2308
|
+
end
|
|
2309
|
+
|
|
2310
|
+
it_behaves_like 'returns a cloned query'
|
|
2311
|
+
end
|
|
2312
|
+
|
|
2313
|
+
context 'when criteria are simple and handled via Key' do
|
|
2314
|
+
shared_examples_for 'adds conditions with $nor' do
|
|
2315
|
+
it "adds conditions with $nor" do
|
|
2316
|
+
expect(selection.selector).to eq({
|
|
2317
|
+
'$nor' => [
|
|
2318
|
+
{'field' => 3},
|
|
2319
|
+
{'field' => {'$lt' => 5}},
|
|
2320
|
+
],
|
|
2321
|
+
})
|
|
2322
|
+
end
|
|
2323
|
+
|
|
2324
|
+
it_behaves_like 'returns a cloned query'
|
|
2325
|
+
end
|
|
2326
|
+
|
|
2327
|
+
shared_examples_for 'combines conditions with $eq' do
|
|
2328
|
+
it "combines conditions with $eq" do
|
|
2329
|
+
expect(selection.selector).to eq({
|
|
2330
|
+
'$nor' => [ { 'field' => { '$eq' => 3, '$lt' => 5 } } ]
|
|
2331
|
+
})
|
|
2332
|
+
end
|
|
2333
|
+
|
|
2334
|
+
it_behaves_like 'returns a cloned query'
|
|
2335
|
+
end
|
|
2336
|
+
|
|
2337
|
+
shared_examples_for 'combines conditions with $regex' do
|
|
2338
|
+
it 'combines conditions with $regex' do
|
|
2339
|
+
expect(selection.selector).to eq({
|
|
2340
|
+
'$nor' => [ { 'field' => { '$regex' => /t/, '$lt' => 5 } } ]
|
|
2341
|
+
})
|
|
2342
|
+
end
|
|
2343
|
+
|
|
2344
|
+
it_behaves_like 'returns a cloned query'
|
|
2345
|
+
end
|
|
2346
|
+
|
|
2347
|
+
context 'criteria are provided in the same hash' do
|
|
2348
|
+
context 'non-regexp argument' do
|
|
2349
|
+
let(:selection) { query.none_of(:field => 3, :field.lt => 5) }
|
|
2350
|
+
it_behaves_like 'combines conditions with $eq'
|
|
2351
|
+
end
|
|
2352
|
+
|
|
2353
|
+
context 'regexp argument' do
|
|
2354
|
+
let(:selection) { query.none_of(:field => /t/, :field.lt => 5) }
|
|
2355
|
+
it_behaves_like 'combines conditions with $regex'
|
|
2356
|
+
end
|
|
2357
|
+
end
|
|
2358
|
+
|
|
2359
|
+
context 'criteria are provided in separate hashes' do
|
|
2360
|
+
let(:selection) { query.none_of({:field => 3}, {:field.lt => 5}) }
|
|
2361
|
+
it_behaves_like 'adds conditions with $nor'
|
|
2362
|
+
end
|
|
2363
|
+
|
|
2364
|
+
context 'when the criterion is wrapped in an array' do
|
|
2365
|
+
let(:selection) { query.none_of([:field => 3], [:field.lt => 5]) }
|
|
2366
|
+
it_behaves_like 'adds conditions with $nor'
|
|
2367
|
+
end
|
|
2368
|
+
end
|
|
2369
|
+
|
|
2370
|
+
context 'when criteria are handled via Key and simple' do
|
|
2371
|
+
shared_examples_for 'adds conditions with $nor' do
|
|
2372
|
+
it 'adds conditions with $nor' do
|
|
2373
|
+
expect(selection.selector).to eq({
|
|
2374
|
+
'$nor' => [
|
|
2375
|
+
{ 'field' => { '$gt' => 3 } },
|
|
2376
|
+
{ 'field' => 5 },
|
|
2377
|
+
],
|
|
2378
|
+
})
|
|
2379
|
+
end
|
|
2380
|
+
|
|
2381
|
+
it_behaves_like 'returns a cloned query'
|
|
2382
|
+
end
|
|
2383
|
+
|
|
2384
|
+
shared_examples_for 'combines conditions with $eq' do
|
|
2385
|
+
it 'combines conditions with $eq' do
|
|
2386
|
+
expect(selection.selector).to eq(
|
|
2387
|
+
'$nor' => [ { 'field' => {'$gt' => 3, '$eq' => 5} } ],
|
|
2388
|
+
)
|
|
2389
|
+
end
|
|
2390
|
+
|
|
2391
|
+
it_behaves_like 'returns a cloned query'
|
|
2392
|
+
end
|
|
2393
|
+
|
|
2394
|
+
shared_examples_for 'combines conditions with $regex' do
|
|
2395
|
+
it 'combines conditions with $regex' do
|
|
2396
|
+
expect(selection.selector).to eq(
|
|
2397
|
+
'$nor' => [ { 'field' => {'$gt' => 3, '$regex' => /t/} } ],
|
|
2398
|
+
)
|
|
2399
|
+
end
|
|
2400
|
+
|
|
2401
|
+
it_behaves_like 'returns a cloned query'
|
|
2402
|
+
end
|
|
2403
|
+
|
|
2404
|
+
context 'criteria are provided in the same hash' do
|
|
2405
|
+
context 'non-regexp argument' do
|
|
2406
|
+
let(:selection) { query.none_of(:field.gt => 3, :field => 5) }
|
|
2407
|
+
it_behaves_like 'combines conditions with $eq'
|
|
2408
|
+
end
|
|
2409
|
+
|
|
2410
|
+
context 'regexp argument' do
|
|
2411
|
+
let(:selection) { query.none_of(:field.gt => 3, :field => /t/) }
|
|
2412
|
+
it_behaves_like 'combines conditions with $regex'
|
|
2413
|
+
end
|
|
2414
|
+
end
|
|
2415
|
+
|
|
2416
|
+
context 'criteria are provided in separate hashes' do
|
|
2417
|
+
let(:selection) { query.none_of({:field.gt => 3}, {:field => 5}) }
|
|
2418
|
+
it_behaves_like 'adds conditions with $nor'
|
|
2419
|
+
end
|
|
2420
|
+
|
|
2421
|
+
context 'when the criterion is wrapped in an array' do
|
|
2422
|
+
let(:selection) { query.none_of([:field.gt => 3], [:field => 5]) }
|
|
2423
|
+
it_behaves_like 'adds conditions with $nor'
|
|
2424
|
+
end
|
|
2425
|
+
end
|
|
2426
|
+
|
|
2427
|
+
context 'when a criterion has an aliased field' do
|
|
2428
|
+
let(:selection) { query.none_of({ id: 1 }) }
|
|
2429
|
+
|
|
2430
|
+
it 'adds the $nor selector and aliases the field' do
|
|
2431
|
+
expect(selection.selector).to eq('$nor' => [{ '_id' => 1 }])
|
|
2432
|
+
end
|
|
2433
|
+
|
|
2434
|
+
it_behaves_like 'returns a cloned query'
|
|
2435
|
+
end
|
|
2436
|
+
|
|
2437
|
+
context 'when a criterion is wrapped in an array' do
|
|
2438
|
+
let(:selection) do
|
|
2439
|
+
query.none_of([{ first: [ 1, 2 ] }, { :second.gt => 3 }])
|
|
2440
|
+
end
|
|
2441
|
+
|
|
2442
|
+
it_behaves_like 'returns a cloned query'
|
|
2443
|
+
|
|
2444
|
+
it 'adds the $ nor selector' do
|
|
2445
|
+
expect(selection.selector).to eq({
|
|
2446
|
+
'$nor' => [
|
|
2447
|
+
{ 'first' => [ 1, 2 ] },
|
|
2448
|
+
{ 'second' => { '$gt' => 3 }}
|
|
2449
|
+
]
|
|
2450
|
+
})
|
|
2451
|
+
end
|
|
2452
|
+
end
|
|
2453
|
+
|
|
2454
|
+
context "when the criteria are on the same field" do
|
|
2455
|
+
let(:selection) do
|
|
2456
|
+
query.none_of({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
|
2457
|
+
end
|
|
2458
|
+
|
|
2459
|
+
it_behaves_like 'returns a cloned query'
|
|
2460
|
+
|
|
2461
|
+
it 'appends both $nor expressions' do
|
|
2462
|
+
expect(selection.selector).to eq({
|
|
2463
|
+
"$nor" => [
|
|
2464
|
+
{ "first" => [ 1, 2 ] },
|
|
2465
|
+
{ "first" => [ 3, 4 ] }
|
|
2466
|
+
]
|
|
2467
|
+
})
|
|
2468
|
+
end
|
|
2469
|
+
end
|
|
2470
|
+
end
|
|
2471
|
+
|
|
2472
|
+
context 'when chaining the criteria' do
|
|
2473
|
+
context 'when the criteria are for different fields' do
|
|
2474
|
+
let(:selection) do
|
|
2475
|
+
query.none_of(first: [ 1, 2 ]).none_of(second: [ 3, 4 ])
|
|
2476
|
+
end
|
|
2477
|
+
|
|
2478
|
+
it_behaves_like 'returns a cloned query'
|
|
2479
|
+
|
|
2480
|
+
it 'adds the conditions separately' do
|
|
2481
|
+
expect(selection.selector).to eq(
|
|
2482
|
+
'$nor' => [ { 'first' => [ 1, 2 ] } ],
|
|
2483
|
+
'$and' => [ { '$nor' => [ { 'second' => [ 3, 4 ] } ] } ],
|
|
2484
|
+
)
|
|
2485
|
+
end
|
|
2486
|
+
end
|
|
2487
|
+
|
|
2488
|
+
context "when the criteria are on the same field" do
|
|
2489
|
+
let(:selection) do
|
|
2490
|
+
query.none_of(first: [ 1, 2 ]).none_of(first: [ 3, 4 ])
|
|
2491
|
+
end
|
|
2492
|
+
|
|
2493
|
+
it_behaves_like 'returns a cloned query'
|
|
2494
|
+
|
|
2495
|
+
it 'adds the conditions separately' do
|
|
2496
|
+
expect(selection.selector).to eq(
|
|
2497
|
+
'$nor' => [ { 'first' => [ 1, 2 ] } ],
|
|
2498
|
+
'$and' => [ { '$nor' => [ { 'first' => [ 3, 4 ] } ] } ]
|
|
2499
|
+
)
|
|
2500
|
+
end
|
|
2501
|
+
end
|
|
2502
|
+
end
|
|
2503
|
+
|
|
2504
|
+
context 'when using multiple criteria and symbol operators' do
|
|
2505
|
+
context 'when using fields that meaningfully evolve values' do
|
|
2506
|
+
let(:query) do
|
|
2507
|
+
Dictionary.none_of({a: 1}, :published.gt => Date.new(2020, 2, 3))
|
|
2508
|
+
end
|
|
2509
|
+
|
|
2510
|
+
it 'generates the expected query' do
|
|
2511
|
+
query.selector.should == {'$nor' => [
|
|
2512
|
+
{'a' => 1},
|
|
2513
|
+
# Date instance is converted to a Time instance in local time,
|
|
2514
|
+
# because we are querying on a Time field and dates are interpreted
|
|
2515
|
+
# in local time when assigning to Time fields
|
|
2516
|
+
{'published' => {'$gt' => Time.local(2020, 2, 3) } },
|
|
2517
|
+
] }
|
|
2518
|
+
end
|
|
2519
|
+
end
|
|
2520
|
+
|
|
2521
|
+
context 'when using fields that do not meaningfully evolve values' do
|
|
2522
|
+
let(:query) do
|
|
2523
|
+
Dictionary.none_of({a: 1}, :submitted_on.gt => Date.new(2020, 2, 3))
|
|
2524
|
+
end
|
|
2525
|
+
|
|
2526
|
+
it 'generates the expected query' do
|
|
2527
|
+
query.selector.should == {'$nor' => [
|
|
2528
|
+
{'a' => 1},
|
|
2529
|
+
# Date instance is converted to a Time instance in UTC,
|
|
2530
|
+
# because we are querying on a Date field and dates are interpreted
|
|
2531
|
+
# in UTC when persisted as dates by Mongoid
|
|
2532
|
+
{'submitted_on' => {'$gt' => Time.utc(2020, 2, 3)}},
|
|
2533
|
+
]}
|
|
2534
|
+
end
|
|
2535
|
+
end
|
|
2536
|
+
end
|
|
2537
|
+
end
|
|
2538
|
+
end
|