mongoid 7.1.0.rc0 → 7.2.0.rc1
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.tar.gz.sig +0 -0
- data/CHANGELOG.md +6 -6
- data/LICENSE +1 -1
- data/README.md +14 -7
- data/Rakefile +21 -0
- data/lib/config/locales/en.yml +42 -6
- data/lib/mongoid.rb +26 -2
- data/lib/mongoid/association/accessors.rb +37 -2
- data/lib/mongoid/association/depending.rb +1 -6
- data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
- data/lib/mongoid/association/many.rb +5 -4
- data/lib/mongoid/association/proxy.rb +6 -4
- data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -1
- data/lib/mongoid/association/referenced/belongs_to/buildable.rb +1 -1
- data/lib/mongoid/association/referenced/belongs_to/eager.rb +38 -2
- data/lib/mongoid/association/referenced/eager.rb +29 -9
- data/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb +1 -1
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +30 -15
- data/lib/mongoid/association/referenced/has_many/proxy.rb +11 -3
- data/lib/mongoid/association/referenced/has_one/buildable.rb +1 -1
- data/lib/mongoid/atomic.rb +13 -3
- data/lib/mongoid/atomic/modifiers.rb +1 -1
- data/lib/mongoid/attributes.rb +28 -20
- data/lib/mongoid/attributes/dynamic.rb +1 -1
- data/lib/mongoid/clients/factory.rb +19 -2
- data/lib/mongoid/clients/options.rb +8 -8
- data/lib/mongoid/clients/sessions.rb +20 -4
- data/lib/mongoid/clients/storage_options.rb +5 -5
- data/lib/mongoid/composable.rb +1 -0
- data/lib/mongoid/config.rb +45 -12
- data/lib/mongoid/config/options.rb +5 -2
- data/lib/mongoid/contextual.rb +5 -4
- data/lib/mongoid/contextual/geo_near.rb +3 -2
- data/lib/mongoid/contextual/map_reduce.rb +3 -2
- data/lib/mongoid/contextual/mongo.rb +25 -5
- data/lib/mongoid/copyable.rb +2 -2
- data/lib/mongoid/criteria.rb +80 -11
- data/lib/mongoid/criteria/modifiable.rb +2 -1
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +6 -6
- data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +12 -0
- data/lib/mongoid/criteria/queryable/key.rb +1 -1
- data/lib/mongoid/criteria/queryable/mergeable.rb +75 -8
- data/lib/mongoid/criteria/queryable/pipeline.rb +3 -2
- data/lib/mongoid/criteria/queryable/selectable.rb +141 -19
- data/lib/mongoid/criteria/queryable/selector.rb +3 -3
- data/lib/mongoid/criteria/queryable/storable.rb +106 -101
- data/lib/mongoid/document.rb +15 -3
- data/lib/mongoid/errors.rb +7 -0
- data/lib/mongoid/errors/eager_load.rb +2 -0
- data/lib/mongoid/errors/invalid_discriminator_key_target.rb +25 -0
- data/lib/mongoid/errors/invalid_elem_match_operator.rb +33 -0
- data/lib/mongoid/errors/invalid_estimated_count_criteria.rb +26 -0
- data/lib/mongoid/errors/invalid_expression_operator.rb +28 -0
- data/lib/mongoid/errors/invalid_field_operator.rb +33 -0
- data/lib/mongoid/errors/invalid_query.rb +41 -0
- data/lib/mongoid/errors/no_client_config.rb +2 -2
- data/lib/mongoid/errors/no_default_client.rb +1 -1
- data/lib/mongoid/extensions/hash.rb +4 -2
- data/lib/mongoid/extensions/regexp.rb +1 -1
- data/lib/mongoid/factory.rb +27 -10
- data/lib/mongoid/fields.rb +2 -1
- data/lib/mongoid/fields/standard.rb +2 -1
- data/lib/mongoid/fields/validators/macro.rb +26 -10
- data/lib/mongoid/findable.rb +55 -18
- data/lib/mongoid/indexable.rb +2 -2
- data/lib/mongoid/interceptable.rb +5 -1
- data/lib/mongoid/matchable.rb +1 -149
- data/lib/mongoid/matcher.rb +127 -0
- data/lib/mongoid/matcher/all.rb +22 -0
- data/lib/mongoid/matcher/and.rb +21 -0
- data/lib/mongoid/matcher/elem_match.rb +35 -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 +32 -0
- data/lib/mongoid/matcher/eq_impl_with_regexp.rb +21 -0
- data/lib/mongoid/matcher/exists.rb +15 -0
- data/lib/mongoid/matcher/expression.rb +40 -0
- data/lib/mongoid/matcher/expression_operator.rb +19 -0
- data/lib/mongoid/matcher/field_expression.rb +63 -0
- data/lib/mongoid/matcher/field_operator.rb +52 -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/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/persistable/deletable.rb +1 -1
- data/lib/mongoid/persistable/pushable.rb +11 -2
- data/lib/mongoid/persistence_context.rb +6 -6
- data/lib/mongoid/query_cache.rb +83 -38
- data/lib/mongoid/railties/database.rake +7 -0
- data/lib/mongoid/reloadable.rb +2 -2
- data/lib/mongoid/serializable.rb +11 -3
- data/lib/mongoid/shardable.rb +56 -4
- data/lib/mongoid/tasks/database.rake +10 -5
- data/lib/mongoid/tasks/database.rb +83 -0
- data/lib/mongoid/timestamps/timeless.rb +3 -1
- data/lib/mongoid/traversable.rb +111 -4
- data/lib/mongoid/validatable/uniqueness.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/lib/rails/generators/mongoid/config/templates/mongoid.yml +32 -23
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
- data/spec/integration/app_spec.rb +254 -0
- data/spec/integration/associations/embedded_spec.rb +148 -0
- data/spec/integration/associations/has_many_spec.rb +69 -0
- data/spec/integration/associations/has_one_spec.rb +69 -0
- data/spec/integration/associations/nested_attributes_assignment_spec.rb +116 -0
- data/spec/integration/atomic/modifiers_spec.rb +117 -0
- data/spec/integration/bson_regexp_raw_spec.rb +20 -0
- data/spec/integration/criteria/date_field_spec.rb +41 -0
- data/spec/integration/criteria/logical_spec.rb +13 -0
- data/spec/integration/discriminator_key_spec.rb +354 -0
- data/spec/integration/discriminator_value_spec.rb +207 -0
- data/spec/integration/document_spec.rb +22 -0
- data/spec/integration/{matchable_spec.rb → matcher_examples_spec.rb} +120 -41
- 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/elem_match.yml +363 -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/gte.yml +132 -0
- data/spec/integration/matcher_operator_data/implicit.yml +331 -0
- data/spec/integration/matcher_operator_data/implicit_traversal.yml +16 -0
- data/spec/integration/matcher_operator_data/in.yml +194 -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/lte.yml +132 -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/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_spec.rb +100 -0
- data/spec/integration/matcher_spec.rb +189 -0
- data/spec/integration/server_query_spec.rb +142 -0
- data/spec/integration/shardable_spec.rb +149 -0
- data/spec/lite_spec_helper.rb +15 -4
- data/spec/mongoid/association/accessors_spec.rb +238 -63
- data/spec/mongoid/association/depending_spec.rb +78 -26
- data/spec/mongoid/association/embedded/embeds_many/proxy_spec.rb +33 -0
- data/spec/mongoid/association/embedded/embeds_many_models.rb +20 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
- data/spec/mongoid/association/embedded/embeds_one_models.rb +1 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
- data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +193 -10
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +140 -1
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +146 -68
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +462 -187
- data/spec/mongoid/association/referenced/has_many_models.rb +9 -0
- data/spec/mongoid/association/referenced/has_one_models.rb +9 -0
- data/spec/mongoid/atomic/modifiers_spec.rb +47 -0
- data/spec/mongoid/atomic_spec.rb +23 -0
- data/spec/mongoid/attributes/nested_spec.rb +1 -1
- data/spec/mongoid/attributes_spec.rb +19 -7
- data/spec/mongoid/changeable_spec.rb +23 -0
- data/spec/mongoid/clients/factory_spec.rb +45 -8
- data/spec/mongoid/clients/options_spec.rb +11 -11
- data/spec/mongoid/clients/sessions_spec.rb +9 -10
- data/spec/mongoid/clients/transactions_spec.rb +20 -8
- data/spec/mongoid/clients_spec.rb +2 -2
- data/spec/mongoid/config_spec.rb +28 -0
- data/spec/mongoid/contextual/atomic_spec.rb +22 -11
- data/spec/mongoid/contextual/geo_near_spec.rb +11 -2
- data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
- data/spec/mongoid/contextual/mongo_spec.rb +146 -69
- data/spec/mongoid/copyable_spec.rb +153 -1
- data/spec/mongoid/copyable_spec_models.rb +14 -0
- data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +19 -7
- data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +28 -1
- data/spec/mongoid/criteria/queryable/mergeable_spec.rb +45 -12
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +1051 -392
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +136 -82
- data/spec/mongoid/criteria/queryable/storable_spec.rb +80 -2
- data/spec/mongoid/criteria_spec.rb +240 -41
- data/spec/mongoid/document_fields_spec.rb +29 -0
- data/spec/mongoid/document_persistence_context_spec.rb +33 -0
- data/spec/mongoid/document_spec.rb +89 -15
- data/spec/mongoid/errors/delete_restriction_spec.rb +1 -1
- data/spec/mongoid/errors/no_client_config_spec.rb +2 -2
- data/spec/mongoid/errors/no_client_database_spec.rb +3 -3
- data/spec/mongoid/errors/no_client_hosts_spec.rb +3 -3
- data/spec/mongoid/factory_spec.rb +261 -28
- data/spec/mongoid/fields_spec.rb +72 -3
- data/spec/mongoid/findable_spec.rb +32 -0
- data/spec/mongoid/indexable_spec.rb +34 -6
- data/spec/mongoid/inspectable_spec.rb +29 -2
- data/spec/mongoid/interceptable_spec.rb +64 -2
- data/spec/mongoid/interceptable_spec_models.rb +76 -0
- data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +259 -0
- data/spec/mongoid/matcher/extract_attribute_spec.rb +47 -0
- data/spec/mongoid/persistable/creatable_spec.rb +108 -25
- data/spec/mongoid/persistable/deletable_spec.rb +86 -0
- data/spec/mongoid/persistable/pushable_spec.rb +55 -1
- data/spec/mongoid/persistable/savable_spec.rb +174 -16
- data/spec/mongoid/query_cache_middleware_spec.rb +16 -3
- data/spec/mongoid/query_cache_spec.rb +498 -29
- data/spec/mongoid/relations/proxy_spec.rb +1 -1
- data/spec/mongoid/reloadable_spec.rb +72 -0
- data/spec/mongoid/scopable_spec.rb +2 -1
- data/spec/mongoid/serializable_spec.rb +149 -20
- data/spec/mongoid/shardable_models.rb +61 -0
- data/spec/mongoid/shardable_spec.rb +69 -16
- data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
- data/spec/mongoid/tasks/database_spec.rb +1 -1
- data/spec/mongoid/traversable_spec.rb +1100 -0
- data/spec/spec_helper.rb +4 -33
- data/spec/support/child_process_helper.rb +79 -0
- data/spec/support/cluster_config.rb +3 -3
- data/spec/support/constraints.rb +50 -10
- data/spec/support/expectations.rb +3 -1
- data/spec/support/helpers.rb +11 -0
- data/spec/support/lite_constraints.rb +22 -0
- data/spec/{app → support}/models/account.rb +0 -0
- data/spec/{app → support}/models/acolyte.rb +0 -0
- data/spec/{app → support}/models/actor.rb +1 -1
- data/spec/{app → support}/models/actress.rb +0 -0
- data/spec/{app → support}/models/address.rb +0 -0
- data/spec/{app → support}/models/address_component.rb +0 -0
- data/spec/{app → support}/models/address_number.rb +0 -0
- data/spec/{app → support}/models/agency.rb +0 -0
- data/spec/{app → support}/models/agent.rb +0 -0
- data/spec/{app → support}/models/album.rb +0 -0
- data/spec/{app → support}/models/alert.rb +0 -0
- data/spec/{app → support}/models/animal.rb +0 -0
- data/spec/{app → support}/models/answer.rb +0 -0
- data/spec/{app → support}/models/appointment.rb +0 -0
- data/spec/support/models/armrest.rb +10 -0
- data/spec/{app → support}/models/array_field.rb +0 -0
- data/spec/{app → support}/models/article.rb +0 -0
- data/spec/{app → support}/models/artist.rb +0 -0
- data/spec/{app → support}/models/artwork.rb +0 -0
- data/spec/{app → support}/models/audio.rb +0 -0
- data/spec/{app → support}/models/augmentation.rb +0 -0
- data/spec/{app → support}/models/author.rb +0 -0
- data/spec/{app → support}/models/baby.rb +0 -0
- data/spec/{app → support}/models/band.rb +0 -0
- data/spec/{app → support}/models/bar.rb +0 -0
- data/spec/{app → support}/models/basic.rb +0 -0
- data/spec/{app → support}/models/bed.rb +0 -0
- data/spec/{app → support}/models/big_palette.rb +0 -0
- data/spec/{app → support}/models/birthday.rb +0 -0
- data/spec/{app → support}/models/bomb.rb +0 -0
- data/spec/{app → support}/models/book.rb +0 -0
- data/spec/{app → support}/models/breed.rb +0 -0
- data/spec/{app → support}/models/browser.rb +1 -1
- data/spec/{app → support}/models/building.rb +0 -0
- data/spec/{app → support}/models/building_address.rb +0 -0
- data/spec/{app → support}/models/bus.rb +0 -0
- data/spec/{app → support}/models/business.rb +0 -0
- data/spec/{app → support}/models/callback_test.rb +0 -0
- data/spec/{app → support}/models/canvas.rb +1 -1
- data/spec/{app → support}/models/car.rb +0 -0
- data/spec/{app → support}/models/cat.rb +0 -0
- data/spec/{app → support}/models/category.rb +0 -0
- data/spec/{app → support}/models/child.rb +0 -0
- data/spec/{app → support}/models/child_doc.rb +0 -0
- data/spec/{app → support}/models/church.rb +0 -0
- data/spec/{app → support}/models/circle.rb +0 -0
- data/spec/{app → support}/models/circuit.rb +0 -0
- data/spec/{app → support}/models/circus.rb +0 -0
- data/spec/{app → support}/models/code.rb +0 -0
- data/spec/support/models/coding.rb +4 -0
- data/spec/support/models/coding/pull_request.rb +12 -0
- data/spec/{app → support}/models/comment.rb +0 -0
- data/spec/{app → support}/models/company.rb +0 -0
- data/spec/{app → support}/models/consumption_period.rb +0 -0
- data/spec/{app → support}/models/contextable_item.rb +0 -0
- data/spec/{app → support}/models/contractor.rb +0 -0
- data/spec/{app → support}/models/cookie.rb +0 -0
- data/spec/{app → support}/models/country_code.rb +0 -0
- data/spec/{app → support}/models/courier_job.rb +0 -0
- data/spec/support/models/crate.rb +13 -0
- data/spec/support/models/deed.rb +8 -0
- data/spec/{app → support}/models/definition.rb +0 -0
- data/spec/support/models/delegating_patient.rb +16 -0
- data/spec/{app → support}/models/description.rb +0 -0
- data/spec/{app → support}/models/dictionary.rb +0 -0
- data/spec/{app → support}/models/division.rb +0 -0
- data/spec/{app → support}/models/doctor.rb +0 -0
- data/spec/{app → support}/models/dog.rb +0 -0
- data/spec/{app → support}/models/dokument.rb +0 -0
- data/spec/{app → support}/models/draft.rb +0 -0
- data/spec/{app → support}/models/dragon.rb +0 -0
- data/spec/{app → support}/models/driver.rb +1 -1
- data/spec/{app → support}/models/drug.rb +0 -0
- data/spec/{app → support}/models/dungeon.rb +0 -0
- data/spec/{app → support}/models/edit.rb +0 -0
- data/spec/{app → support}/models/email.rb +0 -0
- data/spec/{app → support}/models/employer.rb +0 -0
- data/spec/{app → support}/models/entry.rb +0 -0
- data/spec/{app → support}/models/eraser.rb +0 -0
- data/spec/{app → support}/models/even.rb +0 -0
- data/spec/{app → support}/models/event.rb +0 -0
- data/spec/{app → support}/models/exhibition.rb +0 -0
- data/spec/{app → support}/models/exhibitor.rb +0 -0
- data/spec/{app → support}/models/explosion.rb +0 -0
- data/spec/{app → support}/models/eye.rb +0 -0
- data/spec/{app → support}/models/eye_bowl.rb +0 -0
- data/spec/{app → support}/models/face.rb +0 -0
- data/spec/{app → support}/models/favorite.rb +0 -0
- data/spec/{app → support}/models/filesystem.rb +0 -0
- data/spec/{app → support}/models/fire_hydrant.rb +0 -0
- data/spec/{app → support}/models/firefox.rb +0 -0
- data/spec/{app → support}/models/fish.rb +0 -0
- data/spec/{app → support}/models/folder.rb +0 -0
- data/spec/{app → support}/models/folder_item.rb +0 -0
- data/spec/{app → support}/models/fruits.rb +0 -0
- data/spec/{app → support}/models/game.rb +0 -0
- data/spec/{app → support}/models/ghost.rb +0 -0
- data/spec/support/models/guitar.rb +5 -0
- data/spec/{app → support}/models/home.rb +0 -0
- data/spec/{app → support}/models/house.rb +0 -0
- data/spec/{app → support}/models/html_writer.rb +0 -0
- data/spec/{app → support}/models/id_key.rb +0 -0
- data/spec/support/models/idnodef.rb +8 -0
- data/spec/{app → support}/models/image.rb +0 -0
- data/spec/{app → support}/models/implant.rb +0 -0
- data/spec/support/models/instrument.rb +9 -0
- data/spec/{app → support}/models/item.rb +1 -1
- data/spec/{app → support}/models/jar.rb +0 -0
- data/spec/{app → support}/models/kaleidoscope.rb +0 -0
- data/spec/{app → support}/models/kangaroo.rb +0 -0
- data/spec/{app → support}/models/label.rb +0 -0
- data/spec/{app → support}/models/language.rb +0 -0
- data/spec/{app → support}/models/lat_lng.rb +0 -0
- data/spec/{app → support}/models/league.rb +0 -0
- data/spec/{app → support}/models/learner.rb +0 -0
- data/spec/{app → support}/models/line_item.rb +0 -0
- data/spec/{app → support}/models/location.rb +0 -0
- data/spec/{app → support}/models/login.rb +0 -0
- data/spec/{app → support}/models/manufacturer.rb +0 -0
- data/spec/{app → support}/models/meat.rb +0 -0
- data/spec/{app → support}/models/membership.rb +0 -0
- data/spec/{app → support}/models/message.rb +0 -0
- data/spec/{app → support}/models/minim.rb +0 -0
- data/spec/{app → support}/models/mixed_drink.rb +0 -0
- data/spec/support/models/mop.rb +16 -0
- data/spec/{app → support}/models/movie.rb +0 -0
- data/spec/{app → support}/models/my_hash.rb +0 -0
- data/spec/{app → support}/models/name.rb +0 -0
- data/spec/{app → support}/models/name_only.rb +0 -0
- data/spec/{app → support}/models/node.rb +0 -0
- data/spec/{app → support}/models/note.rb +0 -0
- data/spec/{app → support}/models/odd.rb +0 -0
- data/spec/{app → support}/models/ordered_post.rb +0 -0
- data/spec/{app → support}/models/ordered_preference.rb +0 -0
- data/spec/{app → support}/models/oscar.rb +0 -0
- data/spec/{app → support}/models/other_owner_object.rb +0 -0
- data/spec/{app → support}/models/override.rb +0 -0
- data/spec/{app → support}/models/ownable.rb +0 -0
- data/spec/{app → support}/models/owner.rb +2 -0
- data/spec/{app → support}/models/pack.rb +0 -0
- data/spec/{app → support}/models/page.rb +0 -0
- data/spec/{app → support}/models/page_question.rb +0 -0
- data/spec/{app → support}/models/palette.rb +1 -1
- data/spec/{app → support}/models/parent.rb +0 -0
- data/spec/{app → support}/models/parent_doc.rb +0 -0
- data/spec/{app → support}/models/passport.rb +1 -0
- data/spec/{app → support}/models/patient.rb +0 -0
- data/spec/{app → support}/models/pdf_writer.rb +0 -0
- data/spec/{app → support}/models/pencil.rb +0 -0
- data/spec/{app → support}/models/person.rb +1 -1
- data/spec/{app → support}/models/pet.rb +0 -0
- data/spec/{app → support}/models/pet_owner.rb +0 -0
- data/spec/{app → support}/models/phone.rb +1 -0
- data/spec/support/models/piano.rb +5 -0
- data/spec/{app → support}/models/pizza.rb +0 -0
- data/spec/{app → support}/models/player.rb +0 -0
- data/spec/{app → support}/models/post.rb +0 -0
- data/spec/{app → support}/models/post_genre.rb +0 -0
- data/spec/{app → support}/models/powerup.rb +0 -0
- data/spec/{app → support}/models/preference.rb +0 -0
- data/spec/{app → support}/models/princess.rb +0 -0
- data/spec/{app → support}/models/product.rb +0 -0
- data/spec/support/models/profile.rb +18 -0
- data/spec/{app → support}/models/pronunciation.rb +0 -0
- data/spec/{app → support}/models/pub.rb +0 -0
- data/spec/support/models/publication.rb +5 -0
- data/spec/support/models/publication/encyclopedia.rb +12 -0
- data/spec/support/models/publication/review.rb +14 -0
- data/spec/{app → support}/models/purchase.rb +0 -0
- data/spec/{app → support}/models/question.rb +0 -0
- data/spec/{app → support}/models/quiz.rb +0 -0
- data/spec/{app → support}/models/rating.rb +0 -0
- data/spec/{app → support}/models/record.rb +0 -0
- data/spec/{app → support}/models/registry.rb +0 -0
- data/spec/{app → support}/models/role.rb +0 -0
- data/spec/{app → support}/models/root_category.rb +0 -0
- data/spec/{app → support}/models/sandwich.rb +0 -0
- data/spec/{app → support}/models/scheduler.rb +0 -0
- data/spec/{app/models/profile.rb → support/models/scribe.rb} +2 -2
- data/spec/support/models/seat.rb +25 -0
- data/spec/{app → support}/models/seo.rb +0 -0
- data/spec/{app → support}/models/series.rb +0 -0
- data/spec/{app → support}/models/server.rb +0 -0
- data/spec/{app → support}/models/service.rb +0 -0
- data/spec/{app → support}/models/shape.rb +2 -2
- data/spec/{app → support}/models/shelf.rb +0 -0
- data/spec/{app → support}/models/shipment_address.rb +0 -0
- data/spec/{app → support}/models/shipping_container.rb +0 -0
- data/spec/{app → support}/models/shipping_pack.rb +0 -0
- data/spec/{app → support}/models/shop.rb +0 -0
- data/spec/{app → support}/models/short_agent.rb +0 -0
- data/spec/{app → support}/models/short_quiz.rb +0 -0
- data/spec/{app → support}/models/simple.rb +0 -0
- data/spec/{app → support}/models/slave.rb +0 -0
- data/spec/{app → support}/models/song.rb +0 -0
- data/spec/{app → support}/models/sound.rb +0 -0
- data/spec/{app → support}/models/square.rb +0 -0
- data/spec/{app → support}/models/staff.rb +0 -0
- data/spec/{app → support}/models/store_as_dup_test1.rb +0 -0
- data/spec/{app → support}/models/store_as_dup_test2.rb +0 -0
- data/spec/{app → support}/models/store_as_dup_test3.rb +0 -0
- data/spec/{app → support}/models/store_as_dup_test4.rb +0 -0
- data/spec/{app → support}/models/strategy.rb +0 -0
- data/spec/{app → support}/models/sub_item.rb +0 -0
- data/spec/{app → support}/models/subscription.rb +0 -0
- data/spec/{app → support}/models/survey.rb +0 -0
- data/spec/{app → support}/models/symptom.rb +0 -0
- data/spec/support/models/system_role.rb +7 -0
- data/spec/{app → support}/models/tag.rb +0 -0
- data/spec/{app → support}/models/target.rb +0 -0
- data/spec/{app → support}/models/template.rb +0 -0
- data/spec/{app → support}/models/thing.rb +0 -0
- data/spec/{app → support}/models/title.rb +0 -0
- data/spec/{app → support}/models/tool.rb +2 -2
- data/spec/{app → support}/models/topping.rb +0 -0
- data/spec/support/models/toy.rb +10 -0
- data/spec/{app → support}/models/track.rb +0 -0
- data/spec/{app → support}/models/translation.rb +0 -0
- data/spec/{app → support}/models/tree.rb +0 -0
- data/spec/{app → support}/models/truck.rb +2 -0
- data/spec/{app → support}/models/updatable.rb +0 -0
- data/spec/{app → support}/models/user.rb +0 -0
- data/spec/{app → support}/models/user_account.rb +0 -0
- data/spec/{app → support}/models/validation_callback.rb +0 -0
- data/spec/{app → support}/models/vehicle.rb +7 -2
- data/spec/{app → support}/models/version.rb +0 -0
- data/spec/{app → support}/models/vertex.rb +0 -0
- data/spec/{app → support}/models/vet_visit.rb +0 -0
- data/spec/{app → support}/models/video.rb +0 -0
- data/spec/{app → support}/models/video_game.rb +0 -0
- data/spec/{app → support}/models/weapon.rb +0 -0
- data/spec/{app → support}/models/wiki_page.rb +0 -0
- data/spec/{app → support}/models/word.rb +0 -0
- data/spec/{app → support}/models/word_origin.rb +0 -0
- data/spec/{app → support}/models/writer.rb +2 -2
- data/spec/support/session_registry.rb +50 -0
- data/spec/support/spec_config.rb +13 -5
- data/spec/support/spec_organizer.rb +130 -0
- metadata +882 -752
- metadata.gz.sig +0 -0
- data/lib/mongoid/matchable/all.rb +0 -30
- data/lib/mongoid/matchable/and.rb +0 -32
- data/lib/mongoid/matchable/default.rb +0 -121
- data/lib/mongoid/matchable/elem_match.rb +0 -36
- data/lib/mongoid/matchable/eq.rb +0 -23
- data/lib/mongoid/matchable/exists.rb +0 -25
- data/lib/mongoid/matchable/gt.rb +0 -25
- data/lib/mongoid/matchable/gte.rb +0 -25
- data/lib/mongoid/matchable/in.rb +0 -26
- data/lib/mongoid/matchable/lt.rb +0 -25
- data/lib/mongoid/matchable/lte.rb +0 -25
- data/lib/mongoid/matchable/ne.rb +0 -23
- data/lib/mongoid/matchable/nin.rb +0 -24
- data/lib/mongoid/matchable/nor.rb +0 -38
- data/lib/mongoid/matchable/or.rb +0 -35
- data/lib/mongoid/matchable/regexp.rb +0 -30
- data/lib/mongoid/matchable/size.rb +0 -23
- data/spec/mongoid/matchable/all_spec.rb +0 -34
- data/spec/mongoid/matchable/and_spec.rb +0 -190
- data/spec/mongoid/matchable/default_spec.rb +0 -140
- data/spec/mongoid/matchable/elem_match_spec.rb +0 -109
- data/spec/mongoid/matchable/eq_spec.rb +0 -49
- data/spec/mongoid/matchable/exists_spec.rb +0 -60
- data/spec/mongoid/matchable/gt_spec.rb +0 -89
- data/spec/mongoid/matchable/gte_spec.rb +0 -87
- data/spec/mongoid/matchable/in_spec.rb +0 -52
- data/spec/mongoid/matchable/lt_spec.rb +0 -88
- data/spec/mongoid/matchable/lte_spec.rb +0 -88
- data/spec/mongoid/matchable/ne_spec.rb +0 -49
- data/spec/mongoid/matchable/nin_spec.rb +0 -51
- data/spec/mongoid/matchable/nor_spec.rb +0 -210
- data/spec/mongoid/matchable/or_spec.rb +0 -134
- data/spec/mongoid/matchable/regexp_spec.rb +0 -62
- data/spec/mongoid/matchable/size_spec.rb +0 -28
- data/spec/mongoid/matchable_spec.rb +0 -856
@@ -195,7 +195,7 @@ describe Mongoid::Copyable do
|
|
195
195
|
I18n.enforce_available_locales = false
|
196
196
|
I18n.locale = 'pt_BR'
|
197
197
|
person.addresses.type(ShipmentAddress).each { |address| address.shipping_name = "Título" }
|
198
|
-
person.save
|
198
|
+
person.save!
|
199
199
|
end
|
200
200
|
|
201
201
|
after do
|
@@ -353,6 +353,83 @@ describe Mongoid::Copyable do
|
|
353
353
|
end
|
354
354
|
end
|
355
355
|
end
|
356
|
+
|
357
|
+
context "when using a custom discriminator_key" do
|
358
|
+
before do
|
359
|
+
Person.discriminator_key = "dkey"
|
360
|
+
end
|
361
|
+
|
362
|
+
after do
|
363
|
+
Person.discriminator_key = nil
|
364
|
+
end
|
365
|
+
|
366
|
+
let(:copy) do
|
367
|
+
person.send(method)
|
368
|
+
end
|
369
|
+
|
370
|
+
before do
|
371
|
+
person[:versions] = [ { number: 1 } ]
|
372
|
+
end
|
373
|
+
|
374
|
+
it "copys embeds many documents" do
|
375
|
+
expect(copy.addresses).to eq(person.addresses)
|
376
|
+
end
|
377
|
+
|
378
|
+
it "copys deep embeds many documents" do
|
379
|
+
expect(copy.name.translations).to eq(person.name.translations)
|
380
|
+
end
|
381
|
+
|
382
|
+
it "sets the embedded many documents as new" do
|
383
|
+
expect(copy.addresses.first).to be_new_record
|
384
|
+
end
|
385
|
+
|
386
|
+
it "sets the deep embedded many documents as new" do
|
387
|
+
expect(copy.name.translations.first).to be_new_record
|
388
|
+
end
|
389
|
+
|
390
|
+
it "creates new embeds many instances" do
|
391
|
+
expect(copy.addresses).to_not equal(person.addresses)
|
392
|
+
end
|
393
|
+
|
394
|
+
it "creates new deep embeds many instances" do
|
395
|
+
expect(copy.name.translations).to_not equal(person.name.translations)
|
396
|
+
end
|
397
|
+
|
398
|
+
it "copys embeds one documents" do
|
399
|
+
expect(copy.name).to eq(person.name)
|
400
|
+
end
|
401
|
+
|
402
|
+
it "flags the embeds one documents as new" do
|
403
|
+
expect(copy.name).to be_new_record
|
404
|
+
end
|
405
|
+
|
406
|
+
it "creates a new embeds one instance" do
|
407
|
+
expect(copy.name).to_not equal(person.name)
|
408
|
+
end
|
409
|
+
|
410
|
+
context "when saving the copy" do
|
411
|
+
|
412
|
+
let(:reloaded) do
|
413
|
+
copy.reload
|
414
|
+
end
|
415
|
+
|
416
|
+
before do
|
417
|
+
copy.save(validate: false)
|
418
|
+
end
|
419
|
+
|
420
|
+
it "persists the attributes" do
|
421
|
+
expect(reloaded.title).to eq("Sir")
|
422
|
+
end
|
423
|
+
|
424
|
+
it "persists the embeds many relation" do
|
425
|
+
expect(reloaded.addresses).to eq(person.addresses)
|
426
|
+
end
|
427
|
+
|
428
|
+
it "persists the embeds one relation" do
|
429
|
+
expect(reloaded.name).to eq(person.name)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
356
433
|
end
|
357
434
|
|
358
435
|
context "when the document is not new" do
|
@@ -517,6 +594,81 @@ describe Mongoid::Copyable do
|
|
517
594
|
end
|
518
595
|
end
|
519
596
|
end
|
597
|
+
|
598
|
+
context "when cloning a document with an embedded child class and a custom discriminator value" do
|
599
|
+
|
600
|
+
before do
|
601
|
+
ShipmentAddress.discriminator_value = "dvalue"
|
602
|
+
end
|
603
|
+
|
604
|
+
after do
|
605
|
+
ShipmentAddress.discriminator_value = nil
|
606
|
+
end
|
607
|
+
|
608
|
+
let!(:shipment_address) do
|
609
|
+
person.addresses.build({}, ShipmentAddress)
|
610
|
+
end
|
611
|
+
|
612
|
+
before do
|
613
|
+
person.save
|
614
|
+
end
|
615
|
+
|
616
|
+
let!(:from_db) do
|
617
|
+
Person.find(person.id)
|
618
|
+
end
|
619
|
+
|
620
|
+
let(:copy) do
|
621
|
+
from_db.send(method)
|
622
|
+
end
|
623
|
+
|
624
|
+
it "copys embeds many documents" do
|
625
|
+
expect(copy.addresses).to eq(person.addresses)
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
context 'when cloning a document with embedded child that uses inheritance' do
|
630
|
+
let(:original) do
|
631
|
+
CopyableSpec::A.new(influencers: [child_cls.new])
|
632
|
+
end
|
633
|
+
|
634
|
+
let(:copy) do
|
635
|
+
original.send(method)
|
636
|
+
end
|
637
|
+
|
638
|
+
context 'embedded child is root of hierarchy' do
|
639
|
+
let(:child_cls) do
|
640
|
+
CopyableSpec::Influencer
|
641
|
+
end
|
642
|
+
|
643
|
+
before do
|
644
|
+
# When embedded class is the root in hierarchy, their
|
645
|
+
# discriminator value is not explicitly stored.
|
646
|
+
child_cls.discriminator_mapping[child_cls.name].should be nil
|
647
|
+
end
|
648
|
+
|
649
|
+
it 'works' do
|
650
|
+
copy.class.should be original.class
|
651
|
+
copy.object_id.should_not == original.object_id
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
context 'embedded child is leaf of hierarchy' do
|
656
|
+
let(:child_cls) do
|
657
|
+
CopyableSpec::Youtuber
|
658
|
+
end
|
659
|
+
|
660
|
+
before do
|
661
|
+
# When embedded class is a leaf in hierarchy, their
|
662
|
+
# discriminator value is explicitly stored.
|
663
|
+
child_cls.discriminator_mapping[child_cls.name].should_not be nil
|
664
|
+
end
|
665
|
+
|
666
|
+
it 'works' do
|
667
|
+
copy.class.should be original.class
|
668
|
+
copy.object_id.should_not == original.object_id
|
669
|
+
end
|
670
|
+
end
|
671
|
+
end
|
520
672
|
end
|
521
673
|
end
|
522
674
|
end
|
@@ -6,6 +6,7 @@ module CopyableSpec
|
|
6
6
|
include Mongoid::Document
|
7
7
|
|
8
8
|
embeds_many :locations
|
9
|
+
embeds_many :influencers
|
9
10
|
end
|
10
11
|
|
11
12
|
class Location
|
@@ -17,4 +18,17 @@ module CopyableSpec
|
|
17
18
|
class Building
|
18
19
|
include Mongoid::Document
|
19
20
|
end
|
21
|
+
|
22
|
+
class Influencer
|
23
|
+
include Mongoid::Document
|
24
|
+
|
25
|
+
embeds_many :blurbs
|
26
|
+
end
|
27
|
+
|
28
|
+
class Youtuber < Influencer
|
29
|
+
end
|
30
|
+
|
31
|
+
class Blurb
|
32
|
+
include Mongoid::Document
|
33
|
+
end
|
20
34
|
end
|
@@ -11,7 +11,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
11
11
|
context "when provided a regexp" do
|
12
12
|
|
13
13
|
let(:regexp) do
|
14
|
-
|
14
|
+
/\A[123]/
|
15
15
|
end
|
16
16
|
|
17
17
|
let(:evolved) do
|
@@ -26,7 +26,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
26
26
|
context "when provided a string" do
|
27
27
|
|
28
28
|
let(:regexp) do
|
29
|
-
"
|
29
|
+
"\\A[123]"
|
30
30
|
end
|
31
31
|
|
32
32
|
let(:evolved) do
|
@@ -34,7 +34,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
it "returns the converted regexp" do
|
37
|
-
expect(evolved).to eq(
|
37
|
+
expect(evolved).to eq(/\A[123]/)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -43,7 +43,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
43
43
|
context "when the elements are regexps" do
|
44
44
|
|
45
45
|
let(:regexp) do
|
46
|
-
|
46
|
+
/\A[123]/
|
47
47
|
end
|
48
48
|
|
49
49
|
let(:array) do
|
@@ -66,7 +66,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
66
66
|
context "when the elements are strings" do
|
67
67
|
|
68
68
|
let(:regexp) do
|
69
|
-
"
|
69
|
+
"\\A[123]"
|
70
70
|
end
|
71
71
|
|
72
72
|
let(:evolved) do
|
@@ -74,7 +74,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
74
74
|
end
|
75
75
|
|
76
76
|
it "returns the regexps" do
|
77
|
-
expect(evolved).to eq([
|
77
|
+
expect(evolved).to eq([ /\A[123]/ ])
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
@@ -83,7 +83,7 @@ describe Mongoid::Criteria::Queryable::Extensions::Regexp do
|
|
83
83
|
describe "#regexp?" do
|
84
84
|
|
85
85
|
let(:regexp) do
|
86
|
-
|
86
|
+
/\A[123]/
|
87
87
|
end
|
88
88
|
|
89
89
|
it "returns true" do
|
@@ -354,23 +354,35 @@ describe Time do
|
|
354
354
|
|
355
355
|
describe "#__evolve_date__" do
|
356
356
|
|
357
|
-
let(:time) do
|
358
|
-
Time.new(2010, 1, 1, 12, 0, 0)
|
359
|
-
end
|
360
|
-
|
361
357
|
let(:evolved) do
|
362
358
|
time.__evolve_date__
|
363
359
|
end
|
364
360
|
|
365
|
-
|
366
|
-
|
361
|
+
context 'beginning of day' do
|
362
|
+
let(:time) do
|
363
|
+
Time.new(2010, 1, 1, 0, 0, 1).freeze
|
364
|
+
end
|
365
|
+
|
366
|
+
it "returns midnight utc" do
|
367
|
+
expect(evolved).to eq(Time.utc(2010, 1, 1, 0, 0, 0))
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
context 'end of day' do
|
372
|
+
let(:time) do
|
373
|
+
Time.new(2010, 1, 1, 23, 59, 59).freeze
|
374
|
+
end
|
375
|
+
|
376
|
+
it "returns midnight utc" do
|
377
|
+
expect(evolved).to eq(Time.utc(2010, 1, 1, 0, 0, 0))
|
378
|
+
end
|
367
379
|
end
|
368
380
|
end
|
369
381
|
|
370
382
|
describe "#__evolve_time__" do
|
371
383
|
|
372
384
|
let(:time) do
|
373
|
-
Time.new(2010, 1, 1, 12, 0, 0)
|
385
|
+
Time.new(2010, 1, 1, 12, 0, 0).freeze
|
374
386
|
end
|
375
387
|
|
376
388
|
let(:evolved) do
|
@@ -325,10 +325,37 @@ describe ActiveSupport::TimeWithZone do
|
|
325
325
|
end
|
326
326
|
end
|
327
327
|
|
328
|
+
describe "#__evolve_date__" do
|
329
|
+
|
330
|
+
let(:evolved) do
|
331
|
+
time.__evolve_date__
|
332
|
+
end
|
333
|
+
|
334
|
+
context 'beginning of day' do
|
335
|
+
let(:time) do
|
336
|
+
time_zone.local(2010, 1, 1, 0, 0, 1).freeze
|
337
|
+
end
|
338
|
+
|
339
|
+
it "returns midnight utc" do
|
340
|
+
expect(evolved).to eq(Time.utc(2010, 1, 1, 0, 0, 0))
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
context 'end of day' do
|
345
|
+
let(:time) do
|
346
|
+
time_zone.local(2010, 1, 1, 23, 59, 59).freeze
|
347
|
+
end
|
348
|
+
|
349
|
+
it "returns midnight utc" do
|
350
|
+
expect(evolved).to eq(Time.utc(2010, 1, 1, 0, 0, 0))
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
328
355
|
describe "#__evolve_time__" do
|
329
356
|
|
330
357
|
let(:date) do
|
331
|
-
time_zone.local(2010, 1, 1, 12, 0, 0)
|
358
|
+
time_zone.local(2010, 1, 1, 12, 0, 0).freeze
|
332
359
|
end
|
333
360
|
|
334
361
|
let(:evolved) do
|
@@ -5,11 +5,11 @@ require "spec_helper"
|
|
5
5
|
|
6
6
|
describe Mongoid::Criteria::Queryable::Mergeable do
|
7
7
|
|
8
|
-
|
8
|
+
let(:query) do
|
9
|
+
Mongoid::Query.new
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
Mongoid::Query.new
|
12
|
-
end
|
12
|
+
describe "#intersect" do
|
13
13
|
|
14
14
|
before do
|
15
15
|
query.intersect
|
@@ -22,10 +22,6 @@ describe Mongoid::Criteria::Queryable::Mergeable do
|
|
22
22
|
|
23
23
|
describe "#override" do
|
24
24
|
|
25
|
-
let(:query) do
|
26
|
-
Mongoid::Query.new
|
27
|
-
end
|
28
|
-
|
29
25
|
before do
|
30
26
|
query.override
|
31
27
|
end
|
@@ -37,10 +33,6 @@ describe Mongoid::Criteria::Queryable::Mergeable do
|
|
37
33
|
|
38
34
|
describe "#union" do
|
39
35
|
|
40
|
-
let(:query) do
|
41
|
-
Mongoid::Query.new
|
42
|
-
end
|
43
|
-
|
44
36
|
before do
|
45
37
|
query.union
|
46
38
|
end
|
@@ -49,4 +41,45 @@ describe Mongoid::Criteria::Queryable::Mergeable do
|
|
49
41
|
expect(query.strategy).to eq(:__union__)
|
50
42
|
end
|
51
43
|
end
|
44
|
+
|
45
|
+
describe '#_mongoid_expand_keys' do
|
46
|
+
it 'expands simple keys' do
|
47
|
+
query.send(:_mongoid_expand_keys, {a: 1}).should == {a: 1}
|
48
|
+
end
|
49
|
+
|
50
|
+
let(:gt) do
|
51
|
+
Mongoid::Criteria::Queryable::Key.new("age", :__override__, "$gt")
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:gtp) do
|
55
|
+
Mongoid::Criteria::Queryable::Key.new("age", :__override__, "$gt")
|
56
|
+
end
|
57
|
+
|
58
|
+
let(:lt) do
|
59
|
+
Mongoid::Criteria::Queryable::Key.new("age", :__override__, "$lt")
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'expands Key instances' do
|
63
|
+
query.send(:_mongoid_expand_keys, {gt => 42}).should == {'age' => {'$gt' => 42}}
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'expands multiple Key instances on the same field' do
|
67
|
+
query.send(:_mongoid_expand_keys, {gt => 42, lt => 50}).should == {
|
68
|
+
'age' => {'$gt' => 42, '$lt' => 50}}
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'expands simple and Key instances on the same field' do
|
72
|
+
query.send(:_mongoid_expand_keys, {'age' => 42, lt => 50}).should == {
|
73
|
+
'age' => {'$eq' => 42, '$lt' => 50}}
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'expands Key and simple instances on the same field' do
|
77
|
+
query.send(:_mongoid_expand_keys, {gt => 42, 'age' => 50}).should == {
|
78
|
+
'age' => {'$gt' => 42, '$eq' => 50}}
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'Ruby does not allow same symbol operator with different values' do
|
82
|
+
{gt => 42, gtp => 50}.should == {gtp => 50}
|
83
|
+
end
|
84
|
+
end
|
52
85
|
end
|
@@ -16,110 +16,12 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
# Hoisting means the operator can be elided, for example
|
20
|
+
# Foo.and(a: 1) produces simply {'a' => 1}.
|
21
|
+
shared_examples_for 'a hoisting logical operation' do
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
Mongoid::Query.new.send(tested_method, hello: 'world')
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'adds the predicate' do
|
27
|
-
expect(query.selector).to eq(expected_operator => [{'hello' => 'world'}])
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
context 'when the single predicate is wrapped in an array' do
|
32
|
-
let(:query) do
|
33
|
-
Mongoid::Query.new.send(tested_method, [{hello: 'world'}])
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'adds the predicate' do
|
37
|
-
expect(query.selector).to eq(expected_operator => [{'hello' => 'world'}])
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
context 'when argument is a Criteria' do
|
42
|
-
let(:query) do
|
43
|
-
Mongoid::Query.new.where(hello: 'world')
|
44
|
-
end
|
45
|
-
|
46
|
-
let(:other) do
|
47
|
-
Mongoid::Query.new.where(foo: 'bar')
|
48
|
-
end
|
49
|
-
|
50
|
-
let(:result) { query.send(tested_method, other) }
|
51
|
-
|
52
|
-
it 'combines' do
|
53
|
-
# This is used for $or / $nor, the two conditions should remain
|
54
|
-
# as separate hashes
|
55
|
-
expect(result.selector).to eq(expected_operator => [{'hello' => 'world'}, {'foo' => 'bar'}])
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'when argument is a mix of Criteria and hashes' do
|
60
|
-
let(:query) do
|
61
|
-
Mongoid::Query.new.where(hello: 'world')
|
62
|
-
end
|
63
|
-
|
64
|
-
let(:other1) do
|
65
|
-
Mongoid::Query.new.where(foo: 'bar')
|
66
|
-
end
|
67
|
-
|
68
|
-
let(:other2) do
|
69
|
-
{bar: 42}
|
70
|
-
end
|
71
|
-
|
72
|
-
let(:other3) do
|
73
|
-
Mongoid::Query.new.where(a: 2)
|
74
|
-
end
|
75
|
-
|
76
|
-
let(:result) { query.send(tested_method, other1, other2, other3) }
|
77
|
-
|
78
|
-
it 'combines' do
|
79
|
-
expect(result.selector).to eq(expected_operator => [
|
80
|
-
{'hello' => 'world'},
|
81
|
-
{'foo' => 'bar'},
|
82
|
-
{'bar' => 42},
|
83
|
-
{'a' => 2},
|
84
|
-
])
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
describe "#and" do
|
90
|
-
|
91
|
-
context "when provided no criterion" do
|
92
|
-
|
93
|
-
let(:selection) do
|
94
|
-
query.and
|
95
|
-
end
|
96
|
-
|
97
|
-
it "does not add any criterion" do
|
98
|
-
expect(selection.selector).to eq({})
|
99
|
-
end
|
100
|
-
|
101
|
-
it "returns the query" do
|
102
|
-
expect(selection).to eq(query)
|
103
|
-
end
|
104
|
-
|
105
|
-
it_behaves_like 'returns a cloned query'
|
106
|
-
end
|
107
|
-
|
108
|
-
context "when provided nil" do
|
109
|
-
|
110
|
-
let(:selection) do
|
111
|
-
query.and(nil)
|
112
|
-
end
|
113
|
-
|
114
|
-
it "does not add any criterion" do
|
115
|
-
expect(selection.selector).to eq({})
|
116
|
-
end
|
117
|
-
|
118
|
-
it "returns the query" do
|
119
|
-
expect(selection).to eq(query)
|
120
|
-
end
|
121
|
-
|
122
|
-
it_behaves_like 'returns a cloned query'
|
23
|
+
let(:query) do
|
24
|
+
Mongoid::Query.new
|
123
25
|
end
|
124
26
|
|
125
27
|
context "when provided a single criterion" do
|
@@ -127,23 +29,23 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
127
29
|
shared_examples_for 'adds the conditions to top level' do
|
128
30
|
|
129
31
|
it "adds the conditions to top level" do
|
130
|
-
expect(selection.selector).to eq(
|
32
|
+
expect(selection.selector).to eq(
|
131
33
|
"field" => [ 1, 2 ]
|
132
|
-
|
34
|
+
)
|
133
35
|
end
|
134
36
|
|
135
37
|
it_behaves_like 'returns a cloned query'
|
136
38
|
end
|
137
39
|
|
138
40
|
let(:selection) do
|
139
|
-
query.
|
41
|
+
query.send(tested_method, field: [ 1, 2 ])
|
140
42
|
end
|
141
43
|
|
142
44
|
it_behaves_like 'adds the conditions to top level'
|
143
45
|
|
144
46
|
context 'when the criterion is wrapped in an array' do
|
145
47
|
let(:selection) do
|
146
|
-
query.
|
48
|
+
query.send(tested_method, [{field: [ 1, 2 ] }])
|
147
49
|
end
|
148
50
|
|
149
51
|
it_behaves_like 'adds the conditions to top level'
|
@@ -151,20 +53,39 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
151
53
|
|
152
54
|
context 'when the criterion is wrapped in a deep array with nil elements' do
|
153
55
|
let(:selection) do
|
154
|
-
query.
|
56
|
+
query.send(tested_method, [[[{field: [ 1, 2 ] }]], [nil]])
|
155
57
|
end
|
156
58
|
|
157
59
|
it_behaves_like 'adds the conditions to top level'
|
158
60
|
end
|
159
61
|
end
|
160
62
|
|
63
|
+
context 'when argument is a Criteria' do
|
64
|
+
let(:base) do
|
65
|
+
query.where(hello: 'world')
|
66
|
+
end
|
67
|
+
|
68
|
+
let(:other) do
|
69
|
+
query.where(foo: 'bar')
|
70
|
+
end
|
71
|
+
|
72
|
+
let(:result) { base.send(tested_method, other) }
|
73
|
+
|
74
|
+
it 'combines' do
|
75
|
+
expect(result.selector).to eq(
|
76
|
+
'hello' => 'world',
|
77
|
+
'foo' => 'bar',
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
161
82
|
context "when provided a single criterion that is handled via Key" do
|
162
83
|
|
163
84
|
shared_examples_for 'adds the conditions to top level' do
|
164
85
|
|
165
86
|
it "adds the conditions to top level" do
|
166
87
|
expect(selection.selector).to eq({
|
167
|
-
"field" => {'$gt' => 3
|
88
|
+
"field" => {'$gt' => 3},
|
168
89
|
})
|
169
90
|
end
|
170
91
|
|
@@ -172,14 +93,14 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
172
93
|
end
|
173
94
|
|
174
95
|
let(:selection) do
|
175
|
-
query.
|
96
|
+
query.send(tested_method, :field.gt => 3)
|
176
97
|
end
|
177
98
|
|
178
99
|
it_behaves_like 'adds the conditions to top level'
|
179
100
|
|
180
101
|
context 'when the criterion is wrapped in an array' do
|
181
102
|
let(:selection) do
|
182
|
-
query.
|
103
|
+
query.send(tested_method, [{ :field.gt => 3 }])
|
183
104
|
end
|
184
105
|
|
185
106
|
it_behaves_like 'adds the conditions to top level'
|
@@ -187,81 +108,74 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
187
108
|
|
188
109
|
context 'when the criterion is wrapped in a deep array with nil elements' do
|
189
110
|
let(:selection) do
|
190
|
-
query.
|
111
|
+
query.send(tested_method, [[[{ :field.gt => 3 }]], [nil]])
|
191
112
|
end
|
192
113
|
|
193
114
|
it_behaves_like 'adds the conditions to top level'
|
194
115
|
end
|
195
|
-
end
|
196
|
-
|
197
|
-
context "when provided a nested criterion" do
|
198
|
-
|
199
|
-
let(:selection) do
|
200
|
-
query.and(:test.elem_match => { :field.in => [ 1, 2 ] })
|
201
|
-
end
|
202
|
-
|
203
|
-
it "builds the correct selector" do
|
204
|
-
expect(selection.selector).to eq({
|
205
|
-
"test" => { "$elemMatch" => { "field" => { "$in" => [ 1, 2 ] }}}
|
206
|
-
})
|
207
|
-
end
|
208
|
-
|
209
|
-
it_behaves_like 'returns a cloned query'
|
210
|
-
end
|
211
|
-
|
212
|
-
context "when provided multiple criteria" do
|
213
|
-
|
214
|
-
context "when the criteria is already included" do
|
215
116
|
|
117
|
+
context 'when the criterion is a time' do
|
216
118
|
let(:selection) do
|
217
|
-
query.
|
119
|
+
query.send(tested_method, :field.gte => Time.new(2020, 1, 1))
|
218
120
|
end
|
219
121
|
|
220
|
-
it
|
122
|
+
it 'adds the conditions' do
|
221
123
|
expect(selection.selector).to eq({
|
222
|
-
'
|
223
|
-
"$and" => [
|
224
|
-
{ "first" => [ 1, 2 ] }
|
225
|
-
]
|
124
|
+
"field" => {'$gte' => Time.new(2020, 1, 1)},
|
226
125
|
})
|
227
126
|
end
|
228
127
|
|
229
|
-
|
128
|
+
it 'keeps argument type' do
|
129
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
130
|
+
end
|
230
131
|
end
|
231
132
|
|
232
|
-
context
|
233
|
-
|
133
|
+
context 'when the criterion is a datetime' do
|
234
134
|
let(:selection) do
|
235
|
-
query.
|
135
|
+
query.send(tested_method, :field.gte => DateTime.new(2020, 1, 1))
|
236
136
|
end
|
237
137
|
|
238
|
-
it
|
138
|
+
it 'adds the conditions' do
|
239
139
|
expect(selection.selector).to eq({
|
240
|
-
"
|
241
|
-
"second" => [ 3, 4 ],
|
140
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
242
141
|
})
|
243
142
|
end
|
244
143
|
|
245
|
-
|
144
|
+
it 'converts argument to a time' do
|
145
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
146
|
+
end
|
246
147
|
end
|
247
148
|
|
248
|
-
context
|
249
|
-
|
149
|
+
context 'when the criterion is a date' do
|
250
150
|
let(:selection) do
|
251
|
-
query.
|
151
|
+
query.send(tested_method, :field.gte => Date.new(2020, 1, 1))
|
252
152
|
end
|
253
153
|
|
254
|
-
it
|
154
|
+
it 'adds the conditions' do
|
255
155
|
expect(selection.selector).to eq({
|
256
|
-
"
|
257
|
-
"$and" => [
|
258
|
-
{ "first" => [ 3, 4 ] }
|
259
|
-
]
|
156
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
260
157
|
})
|
261
158
|
end
|
262
159
|
|
263
|
-
|
160
|
+
it 'converts argument to a time' do
|
161
|
+
selection.selector['field']['$gte'].should be_a(Time)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "when provided a nested criterion" do
|
167
|
+
|
168
|
+
let(:selection) do
|
169
|
+
query.send(tested_method, :test.elem_match => { :field.in => [ 1, 2 ] })
|
170
|
+
end
|
171
|
+
|
172
|
+
it "builds the correct selector" do
|
173
|
+
expect(selection.selector).to eq({
|
174
|
+
"test" => { "$elemMatch" => { "field" => { "$in" => [ 1, 2 ] }}}
|
175
|
+
})
|
264
176
|
end
|
177
|
+
|
178
|
+
it_behaves_like 'returns a cloned query'
|
265
179
|
end
|
266
180
|
|
267
181
|
context "when chaining the criteria" do
|
@@ -269,7 +183,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
269
183
|
context "when the criteria are for different fields" do
|
270
184
|
|
271
185
|
let(:selection) do
|
272
|
-
query.and(first: [ 1, 2 ]).
|
186
|
+
query.and(first: [ 1, 2 ]).send(tested_method, second: [ 3, 4 ])
|
273
187
|
end
|
274
188
|
|
275
189
|
it "adds the conditions to top level" do
|
@@ -285,7 +199,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
285
199
|
context "when the criteria are on the same field" do
|
286
200
|
|
287
201
|
let(:selection) do
|
288
|
-
query.and(first: [ 1, 2 ]).
|
202
|
+
query.and(first: [ 1, 2 ]).send(tested_method, first: [ 3, 4 ])
|
289
203
|
end
|
290
204
|
|
291
205
|
it "combines via $and operator" do
|
@@ -300,34 +214,47 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
300
214
|
it_behaves_like 'returns a cloned query'
|
301
215
|
end
|
302
216
|
end
|
217
|
+
end
|
303
218
|
|
304
|
-
|
219
|
+
# Non-hoisting means the operator is always present, for example
|
220
|
+
# Foo.or(a: 1) produces {'$or' => [{'a' => 1}]}.
|
221
|
+
shared_examples_for 'a non-hoisting logical operation' do
|
222
|
+
|
223
|
+
context 'when there is a single predicate' do
|
305
224
|
let(:query) do
|
306
|
-
Mongoid::Query.new.
|
225
|
+
Mongoid::Query.new.send(tested_method, hello: 'world')
|
307
226
|
end
|
308
227
|
|
309
|
-
|
228
|
+
it 'adds the predicate' do
|
229
|
+
expect(query.selector).to eq(expected_operator => [{'hello' => 'world'}])
|
230
|
+
end
|
231
|
+
end
|
310
232
|
|
311
|
-
|
233
|
+
context 'when the single predicate is wrapped in an array' do
|
234
|
+
let(:query) do
|
235
|
+
Mongoid::Query.new.send(tested_method, [{hello: 'world'}])
|
236
|
+
end
|
312
237
|
|
313
|
-
|
314
|
-
|
315
|
-
|
238
|
+
it 'adds the predicate' do
|
239
|
+
expect(query.selector).to eq(expected_operator => [{'hello' => 'world'}])
|
240
|
+
end
|
241
|
+
end
|
316
242
|
|
317
|
-
|
318
|
-
|
319
|
-
|
243
|
+
context 'when argument is a Criteria' do
|
244
|
+
let(:query) do
|
245
|
+
Mongoid::Query.new.where(hello: 'world')
|
320
246
|
end
|
321
247
|
|
322
|
-
|
248
|
+
let(:other) do
|
249
|
+
Mongoid::Query.new.where(foo: 'bar')
|
250
|
+
end
|
323
251
|
|
324
|
-
|
325
|
-
Mongoid::Query.new.where(hello: /bar/)
|
326
|
-
end
|
252
|
+
let(:result) { query.send(tested_method, other) }
|
327
253
|
|
328
|
-
|
329
|
-
|
330
|
-
|
254
|
+
it 'combines' do
|
255
|
+
# This is used for $or / $nor, the two conditions should remain
|
256
|
+
# as separate hashes
|
257
|
+
expect(result.selector).to eq(expected_operator => [{'hello' => 'world'}, {'foo' => 'bar'}])
|
331
258
|
end
|
332
259
|
end
|
333
260
|
|
@@ -348,40 +275,344 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
348
275
|
Mongoid::Query.new.where(a: 2)
|
349
276
|
end
|
350
277
|
|
351
|
-
let(:result) { query.
|
278
|
+
let(:result) { query.send(tested_method, other1, other2, other3) }
|
352
279
|
|
353
280
|
it 'combines' do
|
354
|
-
expect(result.selector).to eq(
|
355
|
-
'
|
356
|
-
'
|
357
|
-
'
|
358
|
-
|
281
|
+
expect(result.selector).to eq(expected_operator => [
|
282
|
+
{'hello' => 'world'},
|
283
|
+
{'foo' => 'bar'},
|
284
|
+
{'bar' => 42},
|
285
|
+
{'a' => 2},
|
286
|
+
])
|
359
287
|
end
|
360
288
|
end
|
289
|
+
end
|
361
290
|
|
362
|
-
|
363
|
-
let(:time) { Time.now }
|
291
|
+
describe "#and" do
|
364
292
|
|
365
|
-
|
366
|
-
|
293
|
+
let(:tested_method) { :and }
|
294
|
+
let(:expected_operator) { '$and' }
|
295
|
+
|
296
|
+
it_behaves_like 'a hoisting logical operation'
|
297
|
+
|
298
|
+
context "when provided no criterion" do
|
299
|
+
|
300
|
+
let(:selection) do
|
301
|
+
query.and
|
367
302
|
end
|
368
303
|
|
369
|
-
|
370
|
-
|
304
|
+
it "does not add any criterion" do
|
305
|
+
expect(selection.selector).to eq({})
|
371
306
|
end
|
372
307
|
|
373
|
-
it
|
374
|
-
expect(
|
308
|
+
it "returns the query" do
|
309
|
+
expect(selection).to eq(query)
|
375
310
|
end
|
311
|
+
|
312
|
+
it_behaves_like 'returns a cloned query'
|
376
313
|
end
|
377
314
|
|
378
|
-
|
379
|
-
shared_examples_for 'adds most recent criterion as $and' do
|
380
|
-
let(:selector) { scope.selector }
|
315
|
+
context "when provided nil" do
|
381
316
|
|
382
|
-
|
383
|
-
|
384
|
-
|
317
|
+
let(:selection) do
|
318
|
+
query.and(nil)
|
319
|
+
end
|
320
|
+
|
321
|
+
it "does not add any criterion" do
|
322
|
+
expect(selection.selector).to eq({})
|
323
|
+
end
|
324
|
+
|
325
|
+
it "returns the query" do
|
326
|
+
expect(selection).to eq(query)
|
327
|
+
end
|
328
|
+
|
329
|
+
it_behaves_like 'returns a cloned query'
|
330
|
+
end
|
331
|
+
|
332
|
+
context "when provided multiple criteria" do
|
333
|
+
|
334
|
+
context "when the criterion is already included" do
|
335
|
+
|
336
|
+
context 'simple criterion' do
|
337
|
+
let(:selection) do
|
338
|
+
query.and({ first: [ 1, 2 ] }).and({ first: [ 1, 2 ] })
|
339
|
+
end
|
340
|
+
|
341
|
+
it "adds all conditions" do
|
342
|
+
expect(selection.selector).to eq({
|
343
|
+
'first' => [1, 2],
|
344
|
+
"$and" => [
|
345
|
+
{ "first" => [ 1, 2 ] }
|
346
|
+
]
|
347
|
+
})
|
348
|
+
end
|
349
|
+
|
350
|
+
it_behaves_like 'returns a cloned query'
|
351
|
+
end
|
352
|
+
|
353
|
+
context 'Key criterion' do
|
354
|
+
let(:selection) do
|
355
|
+
query.and({ first: [ 1, 2 ] }).and(:first.gt => 3)
|
356
|
+
end
|
357
|
+
|
358
|
+
it "adds all conditions" do
|
359
|
+
expect(selection.selector).to eq({
|
360
|
+
'first' => [1, 2],
|
361
|
+
"$and" => [
|
362
|
+
{ "first" => {'$gt' => 3} }
|
363
|
+
]
|
364
|
+
})
|
365
|
+
end
|
366
|
+
|
367
|
+
it_behaves_like 'returns a cloned query'
|
368
|
+
end
|
369
|
+
|
370
|
+
context 'Key criterion when existing criterion is an operator' do
|
371
|
+
let(:selection) do
|
372
|
+
query.and(:first.lt => 5).and(:first.gt => 3)
|
373
|
+
end
|
374
|
+
|
375
|
+
it "adds all conditions" do
|
376
|
+
expect(selection.selector).to eq({
|
377
|
+
'first' => {'$lt' => 5, '$gt' => 3},
|
378
|
+
})
|
379
|
+
end
|
380
|
+
|
381
|
+
it_behaves_like 'returns a cloned query'
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
context "when the new criteria are for different fields" do
|
386
|
+
|
387
|
+
let(:selection) do
|
388
|
+
query.and({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
389
|
+
end
|
390
|
+
|
391
|
+
it "adds all conditions to top level" do
|
392
|
+
expect(selection.selector).to eq({
|
393
|
+
"first" => [ 1, 2 ],
|
394
|
+
"second" => [ 3, 4 ],
|
395
|
+
})
|
396
|
+
end
|
397
|
+
|
398
|
+
it_behaves_like 'returns a cloned query'
|
399
|
+
end
|
400
|
+
|
401
|
+
context "when the new criteria are for the same field" do
|
402
|
+
|
403
|
+
context 'when criteria are simple' do
|
404
|
+
let(:selection) do
|
405
|
+
query.and({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
406
|
+
end
|
407
|
+
|
408
|
+
it "combines via $and operator" do
|
409
|
+
expect(selection.selector).to eq({
|
410
|
+
"first" => [ 1, 2 ],
|
411
|
+
"$and" => [
|
412
|
+
{ "first" => [ 3, 4 ] }
|
413
|
+
]
|
414
|
+
})
|
415
|
+
end
|
416
|
+
|
417
|
+
it_behaves_like 'returns a cloned query'
|
418
|
+
end
|
419
|
+
|
420
|
+
context 'when criteria are handled via Key' do
|
421
|
+
shared_examples_for 'adds the conditions to top level' do
|
422
|
+
|
423
|
+
it "adds the conditions to top level" do
|
424
|
+
expect(selection.selector).to eq({
|
425
|
+
"field" => {'$gt' => 3, '$lt' => 5},
|
426
|
+
})
|
427
|
+
end
|
428
|
+
|
429
|
+
it_behaves_like 'returns a cloned query'
|
430
|
+
end
|
431
|
+
|
432
|
+
context 'criteria are provided in the same hash' do
|
433
|
+
let(:selection) do
|
434
|
+
query.send(tested_method, :field.gt => 3, :field.lt => 5)
|
435
|
+
end
|
436
|
+
|
437
|
+
it_behaves_like 'adds the conditions to top level'
|
438
|
+
end
|
439
|
+
|
440
|
+
context 'criteria are provided in separate hashes' do
|
441
|
+
let(:selection) do
|
442
|
+
query.send(tested_method, {:field.gt => 3}, {:field.lt => 5})
|
443
|
+
end
|
444
|
+
|
445
|
+
it_behaves_like 'adds the conditions to top level'
|
446
|
+
end
|
447
|
+
|
448
|
+
context 'when the criterion is wrapped in an array' do
|
449
|
+
let(:selection) do
|
450
|
+
query.send(tested_method, [:field.gt => 3], [:field.lt => 5])
|
451
|
+
end
|
452
|
+
|
453
|
+
it_behaves_like 'adds the conditions to top level'
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
context 'when criteria are simple and handled via Key' do
|
458
|
+
shared_examples_for 'combines conditions with $and' do
|
459
|
+
|
460
|
+
it "combines conditions with $and" do
|
461
|
+
expect(selection.selector).to eq({
|
462
|
+
"field" => 3,
|
463
|
+
'$and' => ['field' => {'$lt' => 5}],
|
464
|
+
})
|
465
|
+
end
|
466
|
+
|
467
|
+
it_behaves_like 'returns a cloned query'
|
468
|
+
end
|
469
|
+
|
470
|
+
context 'criteria are provided in the same hash' do
|
471
|
+
let(:selection) do
|
472
|
+
query.send(tested_method, :field => 3, :field.lt => 5)
|
473
|
+
end
|
474
|
+
|
475
|
+
it_behaves_like 'combines conditions with $and'
|
476
|
+
end
|
477
|
+
|
478
|
+
context 'criteria are provided in separate hashes' do
|
479
|
+
let(:selection) do
|
480
|
+
query.send(tested_method, {:field => 3}, {:field.lt => 5})
|
481
|
+
end
|
482
|
+
|
483
|
+
it_behaves_like 'combines conditions with $and'
|
484
|
+
end
|
485
|
+
|
486
|
+
context 'when the criterion is wrapped in an array' do
|
487
|
+
let(:selection) do
|
488
|
+
query.send(tested_method, [:field => 3], [:field.lt => 5])
|
489
|
+
end
|
490
|
+
|
491
|
+
it_behaves_like 'combines conditions with $and'
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
context 'when criteria are handled via Key and simple' do
|
496
|
+
shared_examples_for 'combines conditions with $and' do
|
497
|
+
|
498
|
+
it "combines conditions with $and" do
|
499
|
+
expect(selection.selector).to eq({
|
500
|
+
"field" => {'$gt' => 3},
|
501
|
+
'$and' => ['field' => 5],
|
502
|
+
})
|
503
|
+
end
|
504
|
+
|
505
|
+
it_behaves_like 'returns a cloned query'
|
506
|
+
end
|
507
|
+
|
508
|
+
context 'criteria are provided in the same hash' do
|
509
|
+
let(:selection) do
|
510
|
+
query.send(tested_method, :field.gt => 3, :field => 5)
|
511
|
+
end
|
512
|
+
|
513
|
+
it_behaves_like 'combines conditions with $and'
|
514
|
+
end
|
515
|
+
|
516
|
+
context 'criteria are provided in separate hashes' do
|
517
|
+
let(:selection) do
|
518
|
+
query.send(tested_method, {:field.gt => 3}, {:field => 5})
|
519
|
+
end
|
520
|
+
|
521
|
+
it_behaves_like 'combines conditions with $and'
|
522
|
+
end
|
523
|
+
|
524
|
+
context 'when the criterion is wrapped in an array' do
|
525
|
+
let(:selection) do
|
526
|
+
query.send(tested_method, [:field.gt => 3], [:field => 5])
|
527
|
+
end
|
528
|
+
|
529
|
+
it_behaves_like 'combines conditions with $and'
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
context 'when argument is a Criteria' do
|
536
|
+
let(:query) do
|
537
|
+
Mongoid::Query.new.where(hello: 'world')
|
538
|
+
end
|
539
|
+
|
540
|
+
let(:result) { query.and(other) }
|
541
|
+
|
542
|
+
context 'different fields' do
|
543
|
+
|
544
|
+
let(:other) do
|
545
|
+
Mongoid::Query.new.where(foo: 'bar')
|
546
|
+
end
|
547
|
+
|
548
|
+
it 'combines both fields at top level' do
|
549
|
+
expect(result.selector).to eq('hello' => 'world', 'foo' => 'bar')
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
context 'same field' do
|
554
|
+
|
555
|
+
let(:other) do
|
556
|
+
Mongoid::Query.new.where(hello: /bar/)
|
557
|
+
end
|
558
|
+
|
559
|
+
it 'combines fields with $and' do
|
560
|
+
expect(result.selector).to eq('hello' => 'world', '$and' => [{'hello' => /bar/}])
|
561
|
+
end
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
context 'when argument is a mix of Criteria and hashes' do
|
566
|
+
let(:query) do
|
567
|
+
Mongoid::Query.new.where(hello: 'world')
|
568
|
+
end
|
569
|
+
|
570
|
+
let(:other1) do
|
571
|
+
Mongoid::Query.new.where(foo: 'bar')
|
572
|
+
end
|
573
|
+
|
574
|
+
let(:other2) do
|
575
|
+
{bar: 42}
|
576
|
+
end
|
577
|
+
|
578
|
+
let(:other3) do
|
579
|
+
Mongoid::Query.new.where(a: 2)
|
580
|
+
end
|
581
|
+
|
582
|
+
let(:result) { query.and(other1, other2, other3) }
|
583
|
+
|
584
|
+
it 'combines' do
|
585
|
+
expect(result.selector).to eq('hello' => 'world',
|
586
|
+
'foo' => 'bar',
|
587
|
+
'bar' => 42,
|
588
|
+
'a' => 2,
|
589
|
+
)
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
context 'when Key instances are used and types involved have serializers' do
|
594
|
+
let(:time) { Time.now }
|
595
|
+
|
596
|
+
let(:query) do
|
597
|
+
Band.all.and(:created_at.gt => time)
|
598
|
+
end
|
599
|
+
|
600
|
+
let(:expected) do
|
601
|
+
{'created_at' => {'$gt' => time.utc}}
|
602
|
+
end
|
603
|
+
|
604
|
+
it 'combines and evolves' do
|
605
|
+
expect(query.selector).to eq(expected)
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
describe 'query shape' do
|
610
|
+
shared_examples_for 'adds most recent criterion as $and' do
|
611
|
+
let(:selector) { scope.selector }
|
612
|
+
|
613
|
+
it 'adds most recent criterion as $and' do
|
614
|
+
expect(selector).to eq('foo' => 1, '$and' => [{'foo' => 2}])
|
615
|
+
end
|
385
616
|
end
|
386
617
|
|
387
618
|
context 'and/and' do
|
@@ -405,38 +636,463 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
405
636
|
Band.and(foo: 1).where(foo: 2)
|
406
637
|
end
|
407
638
|
|
408
|
-
it_behaves_like 'adds most recent criterion as $and'
|
639
|
+
it_behaves_like 'adds most recent criterion as $and'
|
640
|
+
end
|
641
|
+
|
642
|
+
context 'where/and' do
|
643
|
+
let(:scope) do
|
644
|
+
Band.where(foo: 1).and(foo: 2)
|
645
|
+
end
|
646
|
+
|
647
|
+
it_behaves_like 'adds most recent criterion as $and'
|
648
|
+
end
|
649
|
+
|
650
|
+
context 'where/where' do
|
651
|
+
let(:scope) do
|
652
|
+
Band.where(foo: 1).where(foo: 2)
|
653
|
+
end
|
654
|
+
|
655
|
+
it_behaves_like 'adds most recent criterion as $and'
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
context 'when conditions already exist in criteria' do
|
660
|
+
let(:base_selection) do
|
661
|
+
query.where(foo: 'bar')
|
662
|
+
end
|
663
|
+
|
664
|
+
context 'when hash conditions are given' do
|
665
|
+
let(:selection) do
|
666
|
+
base_selection.and(hello: 'world')
|
667
|
+
end
|
668
|
+
|
669
|
+
it 'adds new conditions to top level' do
|
670
|
+
selection.selector.should == {
|
671
|
+
'foo' => 'bar',
|
672
|
+
'hello' => 'world',
|
673
|
+
}
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
677
|
+
context 'when criteria conditions are given' do
|
678
|
+
let(:selection) do
|
679
|
+
base_selection.and(query.where(hello: 'world'))
|
680
|
+
end
|
681
|
+
|
682
|
+
it 'adds new conditions to top level' do
|
683
|
+
selection.selector.should == {
|
684
|
+
'foo' => 'bar',
|
685
|
+
'hello' => 'world',
|
686
|
+
}
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
context 'when complex criteria conditions are given' do
|
691
|
+
let(:selection) do
|
692
|
+
base_selection.and(query.or([one: 'one'], [two: 'two']))
|
693
|
+
end
|
694
|
+
|
695
|
+
it 'adds new conditions to top level' do
|
696
|
+
selection.selector.should == {
|
697
|
+
'foo' => 'bar',
|
698
|
+
'$or' => [
|
699
|
+
{'one' => 'one'},
|
700
|
+
{'two' => 'two'},
|
701
|
+
],
|
702
|
+
}
|
703
|
+
end
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
shared_examples '$or/$nor' do
|
709
|
+
|
710
|
+
it_behaves_like 'a non-hoisting logical operation'
|
711
|
+
|
712
|
+
context "when provided no arguments" do
|
713
|
+
|
714
|
+
let(:selection) do
|
715
|
+
query.send(tested_method)
|
716
|
+
end
|
717
|
+
|
718
|
+
it_behaves_like 'returns a cloned query'
|
719
|
+
|
720
|
+
it "does not add any criteria" do
|
721
|
+
expect(selection.selector).to eq({})
|
722
|
+
end
|
723
|
+
|
724
|
+
it "returns the query" do
|
725
|
+
expect(selection).to eq(query)
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
context "when provided nil" do
|
730
|
+
|
731
|
+
let(:selection) do
|
732
|
+
query.send(tested_method, nil)
|
733
|
+
end
|
734
|
+
|
735
|
+
it_behaves_like 'returns a cloned query'
|
736
|
+
|
737
|
+
it "does not add any criteria" do
|
738
|
+
expect(selection.selector).to eq({})
|
739
|
+
end
|
740
|
+
|
741
|
+
it "returns the query" do
|
742
|
+
expect(selection).to eq(query)
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
context "when provided a single criterion" do
|
747
|
+
|
748
|
+
let(:selection) do
|
749
|
+
query.send(tested_method, field: [ 1, 2 ])
|
750
|
+
end
|
751
|
+
|
752
|
+
it_behaves_like 'returns a cloned query'
|
753
|
+
|
754
|
+
it "adds the $or/$nor selector" do
|
755
|
+
expect(selection.selector).to eq({
|
756
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
757
|
+
})
|
758
|
+
end
|
759
|
+
|
760
|
+
context 'when the criterion is wrapped in array' do
|
761
|
+
|
762
|
+
let(:selection) do
|
763
|
+
query.send(tested_method, [{ field: [ 1, 2 ] }])
|
764
|
+
end
|
765
|
+
|
766
|
+
it_behaves_like 'returns a cloned query'
|
767
|
+
|
768
|
+
it "adds the $or/$nor selector" do
|
769
|
+
expect(selection.selector).to eq({
|
770
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
771
|
+
})
|
772
|
+
end
|
773
|
+
|
774
|
+
context 'when the array has nil as one of the elements' do
|
775
|
+
|
776
|
+
let(:selection) do
|
777
|
+
query.send(tested_method, [{ field: [ 1, 2 ] }, nil])
|
778
|
+
end
|
779
|
+
|
780
|
+
it_behaves_like 'returns a cloned query'
|
781
|
+
|
782
|
+
it "adds the $or/$nor selector ignoring the nil element" do
|
783
|
+
expect(selection.selector).to eq({
|
784
|
+
expected_operator => [{ "field" => [ 1, 2 ] }]
|
785
|
+
})
|
786
|
+
end
|
787
|
+
end
|
788
|
+
end
|
789
|
+
|
790
|
+
context 'when query already has a condition on another field' do
|
791
|
+
|
792
|
+
let(:selection) do
|
793
|
+
query.where(foo: 'bar').send(tested_method, field: [ 1, 2 ])
|
794
|
+
end
|
795
|
+
|
796
|
+
it 'moves original conditions under $or/$nor' do
|
797
|
+
expect(selection.selector).to eq({
|
798
|
+
expected_operator => [{'foo' => 'bar'}, { "field" => [ 1, 2 ] }]
|
799
|
+
})
|
800
|
+
end
|
801
|
+
end
|
802
|
+
|
803
|
+
context 'when query already has an $or/$nor condition and another condition' do
|
804
|
+
|
805
|
+
let(:selection) do
|
806
|
+
query.send(tested_method, field: [ 1, 2 ]).where(foo: 'bar').send(tested_method, test: 1)
|
807
|
+
end
|
808
|
+
|
809
|
+
it 'unions existing conditions' do
|
810
|
+
expect(selection.selector).to eq(
|
811
|
+
expected_operator => [
|
812
|
+
{
|
813
|
+
expected_operator => [{ "field" => [ 1, 2 ] }],
|
814
|
+
'foo' => 'bar',
|
815
|
+
},
|
816
|
+
{'test' => 1},
|
817
|
+
]
|
818
|
+
)
|
819
|
+
end
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
context "when provided multiple criteria" do
|
824
|
+
|
825
|
+
context "when the criteria are for different fields" do
|
826
|
+
|
827
|
+
let(:selection) do
|
828
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
829
|
+
end
|
830
|
+
|
831
|
+
it_behaves_like 'returns a cloned query'
|
832
|
+
|
833
|
+
it "adds the $or/$nor selector" do
|
834
|
+
expect(selection.selector).to eq({
|
835
|
+
expected_operator => [
|
836
|
+
{ "first" => [ 1, 2 ] },
|
837
|
+
{ "second" => [ 3, 4 ] }
|
838
|
+
]
|
839
|
+
})
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
context "when the criteria uses a Key instance" do
|
844
|
+
|
845
|
+
let(:selection) do
|
846
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { :second.gt => 3 })
|
847
|
+
end
|
848
|
+
|
849
|
+
it "adds the $or/$nor selector" do
|
850
|
+
expect(selection.selector).to eq({
|
851
|
+
expected_operator => [
|
852
|
+
{ "first" => [ 1, 2 ] },
|
853
|
+
{ "second" => { "$gt" => 3 }}
|
854
|
+
]
|
855
|
+
})
|
856
|
+
end
|
857
|
+
|
858
|
+
it_behaves_like 'returns a cloned query'
|
859
|
+
|
860
|
+
context 'when the criterion is a time' do
|
861
|
+
let(:selection) do
|
862
|
+
query.send(tested_method, :field.gte => Time.new(2020, 1, 1))
|
863
|
+
end
|
864
|
+
|
865
|
+
it 'adds the conditions' do
|
866
|
+
expect(selection.selector).to eq(expected_operator => [
|
867
|
+
"field" => {'$gte' => Time.new(2020, 1, 1)},
|
868
|
+
])
|
869
|
+
end
|
870
|
+
|
871
|
+
it 'keeps the type' do
|
872
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
873
|
+
end
|
874
|
+
end
|
875
|
+
|
876
|
+
context 'when the criterion is a datetime' do
|
877
|
+
let(:selection) do
|
878
|
+
query.send(tested_method, :field.gte => DateTime.new(2020, 1, 1))
|
879
|
+
end
|
880
|
+
|
881
|
+
it 'adds the conditions' do
|
882
|
+
expect(selection.selector).to eq(expected_operator => [
|
883
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
884
|
+
])
|
885
|
+
end
|
886
|
+
|
887
|
+
it 'converts argument to a time' do
|
888
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
context 'when the criterion is a date' do
|
893
|
+
let(:selection) do
|
894
|
+
query.send(tested_method, :field.gte => Date.new(2020, 1, 1))
|
895
|
+
end
|
896
|
+
|
897
|
+
it 'adds the conditions' do
|
898
|
+
expect(selection.selector).to eq(expected_operator => [
|
899
|
+
"field" => {'$gte' => Time.utc(2020, 1, 1)},
|
900
|
+
])
|
901
|
+
end
|
902
|
+
|
903
|
+
it 'converts argument to a time' do
|
904
|
+
selection.selector[expected_operator].first['field']['$gte'].should be_a(Time)
|
905
|
+
end
|
906
|
+
end
|
907
|
+
end
|
908
|
+
|
909
|
+
context "when a criterion has an aliased field" do
|
910
|
+
|
911
|
+
let(:selection) do
|
912
|
+
query.send(tested_method, { id: 1 })
|
913
|
+
end
|
914
|
+
|
915
|
+
it "adds the $or/$nor selector and aliases the field" do
|
916
|
+
expect(selection.selector).to eq({
|
917
|
+
expected_operator => [ { "_id" => 1 } ]
|
918
|
+
})
|
919
|
+
end
|
920
|
+
|
921
|
+
it_behaves_like 'returns a cloned query'
|
922
|
+
end
|
923
|
+
|
924
|
+
context "when a criterion is wrapped in an array" do
|
925
|
+
|
926
|
+
let(:selection) do
|
927
|
+
query.send(tested_method, [{ first: [ 1, 2 ] }, { :second.gt => 3 }])
|
928
|
+
end
|
929
|
+
|
930
|
+
it_behaves_like 'returns a cloned query'
|
931
|
+
|
932
|
+
it "adds the $or/$nor selector" do
|
933
|
+
expect(selection.selector).to eq({
|
934
|
+
expected_operator => [
|
935
|
+
{ "first" => [ 1, 2 ] },
|
936
|
+
{ "second" => { "$gt" => 3 }}
|
937
|
+
]
|
938
|
+
})
|
939
|
+
end
|
940
|
+
end
|
941
|
+
|
942
|
+
context "when the criteria are on the same field" do
|
943
|
+
|
944
|
+
context 'simple criteria' do
|
945
|
+
let(:selection) do
|
946
|
+
query.send(tested_method, { first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
947
|
+
end
|
948
|
+
|
949
|
+
it_behaves_like 'returns a cloned query'
|
950
|
+
|
951
|
+
it "appends both $or/$nor expressions" do
|
952
|
+
expect(selection.selector).to eq({
|
953
|
+
expected_operator => [
|
954
|
+
{ "first" => [ 1, 2 ] },
|
955
|
+
{ "first" => [ 3, 4 ] }
|
956
|
+
]
|
957
|
+
})
|
958
|
+
end
|
959
|
+
end
|
960
|
+
|
961
|
+
context 'Key criteria as one argument' do
|
962
|
+
let(:selection) do
|
963
|
+
query.send(tested_method, :first.gt => 3, :first.lt => 5)
|
964
|
+
end
|
965
|
+
|
966
|
+
it_behaves_like 'returns a cloned query'
|
967
|
+
|
968
|
+
it "adds all criteria" do
|
969
|
+
expect(selection.selector).to eq({
|
970
|
+
expected_operator => [
|
971
|
+
{ "first" => {'$gt' => 3, '$lt' => 5} },
|
972
|
+
]
|
973
|
+
})
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
977
|
+
context 'Key criteria as multiple arguments' do
|
978
|
+
let(:selection) do
|
979
|
+
query.send(tested_method, {:first.gt => 3}, {:first.lt => 5})
|
980
|
+
end
|
981
|
+
|
982
|
+
it_behaves_like 'returns a cloned query'
|
983
|
+
|
984
|
+
it "adds all criteria" do
|
985
|
+
expect(selection.selector).to eq({
|
986
|
+
expected_operator => [
|
987
|
+
{ "first" => {'$gt' => 3} },
|
988
|
+
{ "first" => {'$lt' => 5} },
|
989
|
+
]
|
990
|
+
})
|
991
|
+
end
|
992
|
+
end
|
993
|
+
end
|
994
|
+
end
|
995
|
+
|
996
|
+
context "when chaining the criterion" do
|
997
|
+
|
998
|
+
context "when the criterion are for different fields" do
|
999
|
+
|
1000
|
+
let(:selection) do
|
1001
|
+
query.send(tested_method, first: [ 1, 2 ]).send(tested_method, second: [ 3, 4 ])
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
it_behaves_like 'returns a cloned query'
|
1005
|
+
|
1006
|
+
it "adds the $or/$nor selectors" do
|
1007
|
+
expect(selection.selector).to eq({
|
1008
|
+
expected_operator => [
|
1009
|
+
{ "first" => [ 1, 2 ] },
|
1010
|
+
{ "second" => [ 3, 4 ] }
|
1011
|
+
]
|
1012
|
+
})
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
context "when the criterion are on the same field" do
|
1017
|
+
|
1018
|
+
let(:selection) do
|
1019
|
+
query.send(tested_method, first: [ 1, 2 ]).send(tested_method, first: [ 3, 4 ])
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
it_behaves_like 'returns a cloned query'
|
1023
|
+
|
1024
|
+
it "appends both $or/$nor expressions" do
|
1025
|
+
expect(selection.selector).to eq({
|
1026
|
+
expected_operator => [
|
1027
|
+
{ "first" => [ 1, 2 ] },
|
1028
|
+
{ "first" => [ 3, 4 ] }
|
1029
|
+
]
|
1030
|
+
})
|
1031
|
+
end
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
describe "#or" do
|
1037
|
+
|
1038
|
+
let(:tested_method) { :or }
|
1039
|
+
let(:expected_operator) { '$or' }
|
1040
|
+
|
1041
|
+
it_behaves_like '$or/$nor'
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
describe "#nor" do
|
1045
|
+
|
1046
|
+
let(:tested_method) { :nor }
|
1047
|
+
let(:expected_operator) { '$nor' }
|
1048
|
+
|
1049
|
+
it_behaves_like '$or/$nor'
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
describe "#any_of" do
|
1053
|
+
|
1054
|
+
let(:tested_method) { :any_of }
|
1055
|
+
let(:expected_operator) { '$or' }
|
1056
|
+
|
1057
|
+
it_behaves_like 'a hoisting logical operation'
|
1058
|
+
|
1059
|
+
# When multiple arguments are given to any_of, it behaves differently
|
1060
|
+
# from and.
|
1061
|
+
context 'when argument is a mix of Criteria and hashes' do
|
1062
|
+
let(:query) do
|
1063
|
+
Mongoid::Query.new.where(hello: 'world')
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
let(:other1) do
|
1067
|
+
Mongoid::Query.new.where(foo: 'bar')
|
409
1068
|
end
|
410
1069
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
end
|
1070
|
+
let(:other2) do
|
1071
|
+
{bar: 42}
|
1072
|
+
end
|
415
1073
|
|
416
|
-
|
1074
|
+
let(:other3) do
|
1075
|
+
Mongoid::Query.new.where(a: 2)
|
417
1076
|
end
|
418
1077
|
|
419
|
-
|
420
|
-
let(:scope) do
|
421
|
-
Band.where(foo: 1).where(foo: 2)
|
422
|
-
end
|
1078
|
+
let(:result) { query.send(tested_method, other1, other2, other3) }
|
423
1079
|
|
424
|
-
|
1080
|
+
it 'combines' do
|
1081
|
+
expect(result.selector).to eq(
|
1082
|
+
'hello' => 'world',
|
1083
|
+
expected_operator => [
|
1084
|
+
{'foo' => 'bar'},
|
1085
|
+
{'bar' => 42},
|
1086
|
+
{'a' => 2},
|
1087
|
+
],
|
1088
|
+
)
|
425
1089
|
end
|
426
1090
|
end
|
427
|
-
end
|
428
|
-
|
429
|
-
describe "#or" do
|
430
|
-
|
431
|
-
let(:tested_method) { :or }
|
432
|
-
let(:expected_operator) { '$or' }
|
433
|
-
|
434
|
-
it_behaves_like 'a non-combining logical operation'
|
435
1091
|
|
436
1092
|
context "when provided no arguments" do
|
437
1093
|
|
438
1094
|
let(:selection) do
|
439
|
-
query.
|
1095
|
+
query.any_of
|
440
1096
|
end
|
441
1097
|
|
442
1098
|
it_behaves_like 'returns a cloned query'
|
@@ -453,7 +1109,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
453
1109
|
context "when provided nil" do
|
454
1110
|
|
455
1111
|
let(:selection) do
|
456
|
-
query.
|
1112
|
+
query.any_of(nil)
|
457
1113
|
end
|
458
1114
|
|
459
1115
|
it_behaves_like 'returns a cloned query'
|
@@ -470,75 +1126,92 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
470
1126
|
context "when provided a single criterion" do
|
471
1127
|
|
472
1128
|
let(:selection) do
|
473
|
-
query.
|
1129
|
+
query.any_of(field: [ 1, 2 ])
|
474
1130
|
end
|
475
1131
|
|
476
1132
|
it_behaves_like 'returns a cloned query'
|
477
1133
|
|
478
1134
|
it "adds the $or selector" do
|
479
|
-
expect(selection.selector).to eq(
|
480
|
-
"
|
481
|
-
|
1135
|
+
expect(selection.selector).to eq(
|
1136
|
+
"field" => [ 1, 2 ],
|
1137
|
+
)
|
482
1138
|
end
|
483
1139
|
|
484
1140
|
context 'when the criterion is wrapped in array' do
|
485
1141
|
|
486
1142
|
let(:selection) do
|
487
|
-
query.
|
1143
|
+
query.any_of([{ field: [ 1, 2 ] }])
|
488
1144
|
end
|
489
1145
|
|
490
1146
|
it_behaves_like 'returns a cloned query'
|
491
1147
|
|
492
|
-
it "adds the
|
493
|
-
expect(selection.selector).to eq(
|
494
|
-
"
|
495
|
-
|
1148
|
+
it "adds the condition" do
|
1149
|
+
expect(selection.selector).to eq(
|
1150
|
+
"field" => [ 1, 2 ],
|
1151
|
+
)
|
496
1152
|
end
|
497
1153
|
|
498
1154
|
context 'when the array has nil as one of the elements' do
|
499
1155
|
|
500
1156
|
let(:selection) do
|
501
|
-
query.
|
1157
|
+
query.any_of([{ field: [ 1, 2 ] }, nil])
|
502
1158
|
end
|
503
1159
|
|
504
1160
|
it_behaves_like 'returns a cloned query'
|
505
1161
|
|
506
1162
|
it "adds the $or selector ignoring the nil element" do
|
507
|
-
expect(selection.selector).to eq(
|
508
|
-
"
|
509
|
-
|
1163
|
+
expect(selection.selector).to eq(
|
1164
|
+
"field" => [ 1, 2 ],
|
1165
|
+
)
|
510
1166
|
end
|
511
1167
|
end
|
512
1168
|
end
|
513
1169
|
|
514
1170
|
context 'when query already has a condition on another field' do
|
515
1171
|
|
516
|
-
|
517
|
-
|
1172
|
+
context 'when there is one argument' do
|
1173
|
+
|
1174
|
+
let(:selection) do
|
1175
|
+
query.where(foo: 'bar').any_of(field: [ 1, 2 ])
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
it 'adds the new condition' do
|
1179
|
+
expect(selection.selector).to eq(
|
1180
|
+
'foo' => 'bar',
|
1181
|
+
'field' => [1, 2],
|
1182
|
+
)
|
1183
|
+
end
|
518
1184
|
end
|
519
1185
|
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
1186
|
+
context 'when there are multiple arguments' do
|
1187
|
+
|
1188
|
+
let(:selection) do
|
1189
|
+
query.where(foo: 'bar').any_of({field: [ 1, 2 ]}, {hello: 'world'})
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
it 'adds the new condition' do
|
1193
|
+
expect(selection.selector).to eq(
|
1194
|
+
'foo' => 'bar',
|
1195
|
+
'$or' => [
|
1196
|
+
{'field' => [1, 2]},
|
1197
|
+
{'hello' => 'world'},
|
1198
|
+
],
|
1199
|
+
)
|
1200
|
+
end
|
524
1201
|
end
|
525
1202
|
end
|
526
1203
|
|
527
1204
|
context 'when query already has an $or condition and another condition' do
|
528
1205
|
|
529
1206
|
let(:selection) do
|
530
|
-
query.or(field: [ 1, 2 ]).where(foo: 'bar').
|
1207
|
+
query.or(field: [ 1, 2 ]).where(foo: 'bar').any_of(test: 1)
|
531
1208
|
end
|
532
1209
|
|
533
|
-
it '
|
1210
|
+
it 'adds the new condition' do
|
534
1211
|
expect(selection.selector).to eq(
|
535
|
-
'$or' => [
|
536
|
-
|
537
|
-
|
538
|
-
'foo' => 'bar',
|
539
|
-
},
|
540
|
-
{'test' => 1},
|
541
|
-
]
|
1212
|
+
'$or' => [{'field' => [1, 2]}],
|
1213
|
+
'foo' => 'bar',
|
1214
|
+
'test' => 1,
|
542
1215
|
)
|
543
1216
|
end
|
544
1217
|
end
|
@@ -549,7 +1222,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
549
1222
|
context "when the criteria are for different fields" do
|
550
1223
|
|
551
1224
|
let(:selection) do
|
552
|
-
query.
|
1225
|
+
query.any_of({ first: [ 1, 2 ] }, { second: [ 3, 4 ] })
|
553
1226
|
end
|
554
1227
|
|
555
1228
|
it_behaves_like 'returns a cloned query'
|
@@ -567,7 +1240,7 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
567
1240
|
context "when the criteria uses a Key instance" do
|
568
1241
|
|
569
1242
|
let(:selection) do
|
570
|
-
query.
|
1243
|
+
query.any_of({ first: [ 1, 2 ] }, { :second.gt => 3 })
|
571
1244
|
end
|
572
1245
|
|
573
1246
|
it "adds the $or selector" do
|
@@ -582,229 +1255,196 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
582
1255
|
it_behaves_like 'returns a cloned query'
|
583
1256
|
end
|
584
1257
|
|
585
|
-
context
|
1258
|
+
context 'when criteria are simple and handled via Key' do
|
1259
|
+
shared_examples_for 'adds conditions with $or' do
|
586
1260
|
|
587
|
-
|
588
|
-
|
589
|
-
|
1261
|
+
it "adds conditions with $or" do
|
1262
|
+
expect(selection.selector).to eq({
|
1263
|
+
'$or' => [
|
1264
|
+
{'field' => 3},
|
1265
|
+
{'field' => {'$lt' => 5}},
|
1266
|
+
],
|
1267
|
+
})
|
1268
|
+
end
|
590
1269
|
|
591
|
-
|
592
|
-
expect(selection.selector).to eq({
|
593
|
-
"$or" => [ { "_id" => 1 } ]
|
594
|
-
})
|
1270
|
+
it_behaves_like 'returns a cloned query'
|
595
1271
|
end
|
596
1272
|
|
597
|
-
|
598
|
-
end
|
1273
|
+
shared_examples_for 'adds one condition' do
|
599
1274
|
|
600
|
-
|
1275
|
+
it "adds one condition" do
|
1276
|
+
expect(selection.selector).to eq({
|
1277
|
+
'field' => 3,
|
1278
|
+
'$and' => [
|
1279
|
+
{'field' => {'$lt' => 5}},
|
1280
|
+
],
|
1281
|
+
})
|
1282
|
+
end
|
601
1283
|
|
602
|
-
|
603
|
-
query.or([{ first: [ 1, 2 ] }, { :second.gt => 3 }])
|
1284
|
+
it_behaves_like 'returns a cloned query'
|
604
1285
|
end
|
605
1286
|
|
606
|
-
|
1287
|
+
context 'criteria are provided in the same hash' do
|
1288
|
+
let(:selection) do
|
1289
|
+
query.send(tested_method, :field => 3, :field.lt => 5)
|
1290
|
+
end
|
607
1291
|
|
608
|
-
|
609
|
-
expect(selection.selector).to eq({
|
610
|
-
"$or" => [
|
611
|
-
{ "first" => [ 1, 2 ] },
|
612
|
-
{ "second" => { "$gt" => 3 }}
|
613
|
-
]
|
614
|
-
})
|
1292
|
+
it_behaves_like 'adds one condition'
|
615
1293
|
end
|
616
|
-
end
|
617
1294
|
|
618
|
-
|
1295
|
+
context 'criteria are provided in separate hashes' do
|
1296
|
+
let(:selection) do
|
1297
|
+
query.send(tested_method, {:field => 3}, {:field.lt => 5})
|
1298
|
+
end
|
619
1299
|
|
620
|
-
|
621
|
-
query.or({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
1300
|
+
it_behaves_like 'adds conditions with $or'
|
622
1301
|
end
|
623
1302
|
|
624
|
-
|
1303
|
+
context 'when the criterion is wrapped in an array' do
|
1304
|
+
let(:selection) do
|
1305
|
+
query.send(tested_method, [:field => 3], [:field.lt => 5])
|
1306
|
+
end
|
625
1307
|
|
626
|
-
|
627
|
-
expect(selection.selector).to eq({
|
628
|
-
"$or" => [
|
629
|
-
{ "first" => [ 1, 2 ] },
|
630
|
-
{ "first" => [ 3, 4 ] }
|
631
|
-
]
|
632
|
-
})
|
1308
|
+
it_behaves_like 'adds conditions with $or'
|
633
1309
|
end
|
634
1310
|
end
|
635
|
-
end
|
636
1311
|
|
637
|
-
|
1312
|
+
context 'when criteria are handled via Key and simple' do
|
1313
|
+
shared_examples_for 'adds conditions with $or' do
|
638
1314
|
|
639
|
-
|
1315
|
+
it "adds conditions with $or" do
|
1316
|
+
expect(selection.selector).to eq({
|
1317
|
+
'$or' => [
|
1318
|
+
{'field' => {'$gt' => 3}},
|
1319
|
+
{'field' => 5},
|
1320
|
+
],
|
1321
|
+
})
|
1322
|
+
end
|
640
1323
|
|
641
|
-
|
642
|
-
query.or(first: [ 1, 2 ]).or(second: [ 3, 4 ])
|
1324
|
+
it_behaves_like 'returns a cloned query'
|
643
1325
|
end
|
644
1326
|
|
645
|
-
|
646
|
-
|
647
|
-
it "adds the $or selectors" do
|
648
|
-
expect(selection.selector).to eq({
|
649
|
-
"$or" => [
|
650
|
-
{ "first" => [ 1, 2 ] },
|
651
|
-
{ "second" => [ 3, 4 ] }
|
652
|
-
]
|
653
|
-
})
|
654
|
-
end
|
655
|
-
end
|
1327
|
+
shared_examples_for 'adds one condition' do
|
656
1328
|
|
657
|
-
|
1329
|
+
it "adds one condition" do
|
1330
|
+
expect(selection.selector).to eq({
|
1331
|
+
'field' => {'$gt' => 3},
|
1332
|
+
'$and' => ['field' => 5],
|
1333
|
+
})
|
1334
|
+
end
|
658
1335
|
|
659
|
-
|
660
|
-
query.or(first: [ 1, 2 ]).or(first: [ 3, 4 ])
|
1336
|
+
it_behaves_like 'returns a cloned query'
|
661
1337
|
end
|
662
1338
|
|
663
|
-
|
1339
|
+
context 'criteria are provided in the same hash' do
|
1340
|
+
let(:selection) do
|
1341
|
+
query.send(tested_method, :field.gt => 3, :field => 5)
|
1342
|
+
end
|
664
1343
|
|
665
|
-
|
666
|
-
expect(selection.selector).to eq({
|
667
|
-
"$or" => [
|
668
|
-
{ "first" => [ 1, 2 ] },
|
669
|
-
{ "first" => [ 3, 4 ] }
|
670
|
-
]
|
671
|
-
})
|
1344
|
+
it_behaves_like 'adds one condition'
|
672
1345
|
end
|
673
|
-
end
|
674
|
-
end
|
675
|
-
end
|
676
|
-
|
677
|
-
describe "#nor" do
|
678
|
-
|
679
|
-
let(:tested_method) { :nor }
|
680
|
-
let(:expected_operator) { '$nor' }
|
681
|
-
|
682
|
-
it_behaves_like 'a non-combining logical operation'
|
683
|
-
|
684
|
-
context "when provided no criterion" do
|
685
|
-
|
686
|
-
let(:selection) do
|
687
|
-
query.nor
|
688
|
-
end
|
689
|
-
|
690
|
-
it "does not add any criterion" do
|
691
|
-
expect(selection.selector).to eq({})
|
692
|
-
end
|
693
|
-
|
694
|
-
it "returns the query" do
|
695
|
-
expect(selection).to eq(query)
|
696
|
-
end
|
697
|
-
|
698
|
-
it_behaves_like 'returns a cloned query'
|
699
|
-
end
|
700
1346
|
|
701
|
-
|
1347
|
+
context 'criteria are provided in separate hashes' do
|
1348
|
+
let(:selection) do
|
1349
|
+
query.send(tested_method, {:field.gt => 3}, {:field => 5})
|
1350
|
+
end
|
702
1351
|
|
703
|
-
|
704
|
-
|
705
|
-
end
|
1352
|
+
it_behaves_like 'adds conditions with $or'
|
1353
|
+
end
|
706
1354
|
|
707
|
-
|
708
|
-
|
709
|
-
|
1355
|
+
context 'when the criterion is wrapped in an array' do
|
1356
|
+
let(:selection) do
|
1357
|
+
query.send(tested_method, [:field.gt => 3], [:field => 5])
|
1358
|
+
end
|
710
1359
|
|
711
|
-
|
712
|
-
|
1360
|
+
it_behaves_like 'adds conditions with $or'
|
1361
|
+
end
|
713
1362
|
end
|
714
1363
|
|
715
|
-
|
716
|
-
end
|
1364
|
+
context "when a criterion has an aliased field" do
|
717
1365
|
|
718
|
-
|
1366
|
+
let(:selection) do
|
1367
|
+
query.any_of({ id: 1 })
|
1368
|
+
end
|
719
1369
|
|
720
|
-
|
721
|
-
|
722
|
-
|
1370
|
+
it "adds the $or selector and aliases the field" do
|
1371
|
+
expect(selection.selector).to eq(
|
1372
|
+
"_id" => 1,
|
1373
|
+
)
|
1374
|
+
end
|
723
1375
|
|
724
|
-
|
725
|
-
expect(selection.selector).to eq({
|
726
|
-
"$nor" => [{"field" => [ 1, 2 ] }]
|
727
|
-
})
|
1376
|
+
it_behaves_like 'returns a cloned query'
|
728
1377
|
end
|
729
1378
|
|
730
|
-
|
731
|
-
end
|
732
|
-
|
733
|
-
context "when provided multiple criterion" do
|
734
|
-
|
735
|
-
context "when the criterion are fnor different fields" do
|
1379
|
+
context "when a criterion is wrapped in an array" do
|
736
1380
|
|
737
1381
|
let(:selection) do
|
738
|
-
query.
|
1382
|
+
query.any_of([{ first: [ 1, 2 ] }, { :second.gt => 3 }])
|
739
1383
|
end
|
740
1384
|
|
741
|
-
|
1385
|
+
it_behaves_like 'returns a cloned query'
|
1386
|
+
|
1387
|
+
it "adds the $or selector" do
|
742
1388
|
expect(selection.selector).to eq({
|
743
|
-
"$
|
1389
|
+
"$or" => [
|
744
1390
|
{ "first" => [ 1, 2 ] },
|
745
|
-
{ "second" =>
|
1391
|
+
{ "second" => { "$gt" => 3 }}
|
746
1392
|
]
|
747
1393
|
})
|
748
1394
|
end
|
749
|
-
|
750
|
-
it_behaves_like 'returns a cloned query'
|
751
1395
|
end
|
752
1396
|
|
753
|
-
context "when the
|
1397
|
+
context "when the criteria are on the same field" do
|
754
1398
|
|
755
1399
|
let(:selection) do
|
756
|
-
query.
|
1400
|
+
query.any_of({ first: [ 1, 2 ] }, { first: [ 3, 4 ] })
|
757
1401
|
end
|
758
1402
|
|
759
|
-
|
1403
|
+
it_behaves_like 'returns a cloned query'
|
1404
|
+
|
1405
|
+
it "appends both $or expressions" do
|
760
1406
|
expect(selection.selector).to eq({
|
761
|
-
"$
|
1407
|
+
"$or" => [
|
762
1408
|
{ "first" => [ 1, 2 ] },
|
763
1409
|
{ "first" => [ 3, 4 ] }
|
764
1410
|
]
|
765
1411
|
})
|
766
1412
|
end
|
767
|
-
|
768
|
-
it_behaves_like 'returns a cloned query'
|
769
1413
|
end
|
770
1414
|
end
|
771
1415
|
|
772
|
-
context "when chaining the
|
1416
|
+
context "when chaining the criteria" do
|
773
1417
|
|
774
|
-
context "when the
|
1418
|
+
context "when the criteria are for different fields" do
|
775
1419
|
|
776
1420
|
let(:selection) do
|
777
|
-
query.
|
778
|
-
end
|
779
|
-
|
780
|
-
it "adds the $nor selectors" do
|
781
|
-
expect(selection.selector).to eq({
|
782
|
-
"$nor" => [
|
783
|
-
{ "first" => [ 1, 2 ] },
|
784
|
-
{ "second" => [ 3, 4 ] }
|
785
|
-
]
|
786
|
-
})
|
1421
|
+
query.any_of(first: [ 1, 2 ]).any_of(second: [ 3, 4 ])
|
787
1422
|
end
|
788
1423
|
|
789
1424
|
it_behaves_like 'returns a cloned query'
|
1425
|
+
|
1426
|
+
it "adds the conditions separately" do
|
1427
|
+
expect(selection.selector).to eq(
|
1428
|
+
"first" => [ 1, 2 ],
|
1429
|
+
"second" => [ 3, 4 ],
|
1430
|
+
)
|
1431
|
+
end
|
790
1432
|
end
|
791
1433
|
|
792
|
-
context "when the
|
1434
|
+
context "when the criteria are on the same field" do
|
793
1435
|
|
794
1436
|
let(:selection) do
|
795
|
-
query.
|
796
|
-
end
|
797
|
-
|
798
|
-
it "appends both $nor expressions" do
|
799
|
-
expect(selection.selector).to eq({
|
800
|
-
"$nor" => [
|
801
|
-
{ "first" => [ 1, 2 ] },
|
802
|
-
{ "first" => [ 3, 4 ] }
|
803
|
-
]
|
804
|
-
})
|
1437
|
+
query.any_of(first: [ 1, 2 ]).any_of(first: [ 3, 4 ])
|
805
1438
|
end
|
806
1439
|
|
807
1440
|
it_behaves_like 'returns a cloned query'
|
1441
|
+
|
1442
|
+
it "adds the conditions separately" do
|
1443
|
+
expect(selection.selector).to eq(
|
1444
|
+
"first" => [ 1, 2 ],
|
1445
|
+
'$and' => [{"first" => [ 3, 4 ]}],
|
1446
|
+
)
|
1447
|
+
end
|
808
1448
|
end
|
809
1449
|
end
|
810
1450
|
end
|
@@ -894,6 +1534,25 @@ describe Mongoid::Criteria::Queryable::Selectable do
|
|
894
1534
|
end
|
895
1535
|
end
|
896
1536
|
|
1537
|
+
context "when the criteria uses Key" do
|
1538
|
+
|
1539
|
+
let(:selection) do
|
1540
|
+
query.not(:age.gt => 50)
|
1541
|
+
end
|
1542
|
+
|
1543
|
+
it "negates the gt selection" do
|
1544
|
+
expect(selection.selector).to eq(
|
1545
|
+
'$and' => ['$nor' => ['age' => {'$gt' => 50}]]
|
1546
|
+
)
|
1547
|
+
end
|
1548
|
+
|
1549
|
+
it_behaves_like 'returns a cloned query'
|
1550
|
+
|
1551
|
+
it "removes the negation on the clone" do
|
1552
|
+
expect(selection).to_not be_negating
|
1553
|
+
end
|
1554
|
+
end
|
1555
|
+
|
897
1556
|
context "when the following criteria is a where" do
|
898
1557
|
|
899
1558
|
let(:selection) do
|