From 891472d0266e6c5b6bc53108d4bdd0f06765e799 Mon Sep 17 00:00:00 2001 From: VitalinaVakulchyk Date: Fri, 12 Mar 2021 17:22:04 +0200 Subject: [PATCH] Update rubocop version & fix offences (#768) * Update Rubocop to 1.11 * Fix a bunch of offenses --- .rubocop.yml | 19 +- .rubocop_todo.yml | 136 ++++++++-- Guardfile | 4 +- chewy.gemspec | 6 +- gemfiles/rails.5.2.activerecord.gemfile | 24 +- gemfiles/rails.5.2.mongoid.6.4.gemfile | 24 +- gemfiles/rails.6.0.activerecord.gemfile | 24 +- gemfiles/rails.6.1.activerecord.gemfile | 24 +- gemfiles/sequel.4.45.gemfile | 14 +- lib/chewy.rb | 19 +- lib/chewy/config.rb | 70 ++--- lib/chewy/fields/base.rb | 2 +- lib/chewy/fields/root.rb | 7 +- lib/chewy/index.rb | 10 +- lib/chewy/index/actions.rb | 7 +- lib/chewy/index/specification.rb | 1 + lib/chewy/journal.rb | 9 +- lib/chewy/minitest/helpers.rb | 12 +- lib/chewy/minitest/search_index_receiver.rb | 8 +- lib/chewy/railtie.rb | 4 +- lib/chewy/rake_helper.rb | 36 ++- lib/chewy/rspec/update_index.rb | 34 +-- lib/chewy/search/loader.rb | 1 + lib/chewy/search/parameters.rb | 6 +- .../parameters/concerns/query_storage.rb | 2 +- lib/chewy/search/parameters/source.rb | 6 +- lib/chewy/search/query_proxy.rb | 11 +- lib/chewy/search/request.rb | 44 +-- lib/chewy/search/scrolling.rb | 16 +- lib/chewy/stash.rb | 1 + lib/chewy/strategy.rb | 9 +- lib/chewy/strategy/shoryuken.rb | 1 + lib/chewy/strategy/sidekiq.rb | 1 + lib/chewy/type.rb | 5 +- lib/chewy/type/actions.rb | 3 +- lib/chewy/type/adapter/active_record.rb | 11 +- lib/chewy/type/adapter/mongoid.rb | 24 +- lib/chewy/type/adapter/object.rb | 13 +- lib/chewy/type/adapter/orm.rb | 6 +- lib/chewy/type/adapter/sequel.rb | 15 +- lib/chewy/type/import.rb | 17 +- lib/chewy/type/import/bulk_builder.rb | 2 + lib/chewy/type/import/journal_builder.rb | 1 + lib/chewy/type/import/routine.rb | 1 + lib/chewy/type/syncer.rb | 24 +- lib/chewy/type/witchcraft.rb | 18 +- lib/generators/chewy/install_generator.rb | 2 +- lib/tasks/chewy.rake | 2 +- spec/chewy/fields/base_spec.rb | 197 +++++++++----- spec/chewy/fields/root_spec.rb | 6 +- spec/chewy/fields/time_fields_spec.rb | 4 +- spec/chewy/index/actions_spec.rb | 31 ++- spec/chewy/index/settings_spec.rb | 4 +- spec/chewy/index_spec.rb | 40 ++- spec/chewy/rspec/update_index_spec.rb | 65 ++--- .../pagination/will_paginate_examples.rb | 12 +- spec/chewy/search/parameters/order_spec.rb | 2 +- .../parameters/query_storage_examples.rb | 88 ++++-- .../search/parameters/search_after_spec.rb | 5 +- spec/chewy/search/parameters/source_spec.rb | 10 +- spec/chewy/search/parameters_spec.rb | 15 +- spec/chewy/search/query_proxy_spec.rb | 85 ++++-- spec/chewy/search/request_spec.rb | 252 ++++++++++++++---- spec/chewy/search/response_spec.rb | 4 +- spec/chewy/search_spec.rb | 20 +- spec/chewy/stash_spec.rb | 12 +- spec/chewy/strategy_spec.rb | 10 +- spec/chewy/type/adapter/active_record_spec.rb | 78 ++++-- spec/chewy/type/adapter/mongoid_spec.rb | 86 ++++-- spec/chewy/type/adapter/object_spec.rb | 25 +- spec/chewy/type/adapter/sequel_spec.rb | 78 ++++-- spec/chewy/type/import/routine_spec.rb | 4 +- spec/chewy/type/import_spec.rb | 61 ++++- spec/chewy/type/observe_spec.rb | 5 +- spec/chewy/type_spec.rb | 5 +- spec/chewy_spec.rb | 49 +++- spec/support/active_record.rb | 8 +- 77 files changed, 1415 insertions(+), 582 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 0167eb51d..02efd02fa 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,24 +1,30 @@ inherit_from: .rubocop_todo.yml +AllCops: + NewCops: enable + Layout/AccessModifierIndentation: EnforcedStyle: outdent -Layout/AlignHash: +Layout/HashAlignment: EnforcedLastArgumentHashStyle: always_ignore -Layout/AlignParameters: +Layout/ParameterAlignment: EnforcedStyle: with_fixed_indentation Layout/CaseIndentation: EnforcedStyle: end -Layout/IndentArray: +Layout/EndAlignment: + EnforcedStyleAlignWith: variable + +Layout/FirstArrayElementIndentation: EnforcedStyle: consistent -Layout/IndentHash: +Layout/FirstHashElementIndentation: EnforcedStyle: consistent -Layout/IndentHeredoc: +Layout/HeredocIndentation: Enabled: false Layout/MultilineMethodCallIndentation: @@ -33,9 +39,6 @@ Layout/SpaceInsideHashLiteralBraces: Lint/AmbiguousBlockAssociation: Enabled: false -Lint/EndAlignment: - EnforcedStyleAlignWith: variable - Style/Alias: EnforcedStyle: prefer_alias_method diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index c9c137925..c200d789e 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,44 +1,136 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2016-09-09 17:05:47 +0700 using RuboCop version 0.42.0. +# on 2021-03-11 12:44:08 UTC using RuboCop version 1.11.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 42 +# Offense count: 1 +# Configuration parameters: Include. +# Include: **/*.gemspec +Gemspec/RequiredRubyVersion: + Exclude: + - 'chewy.gemspec' + +# Offense count: 3 +# Configuration parameters: AllowedMethods. +# AllowedMethods: enums +Lint/ConstantDefinitionInBlock: + Exclude: + - 'lib/chewy.rb' + - 'lib/chewy/rspec/update_index.rb' + - 'spec/chewy/config_spec.rb' + +# Offense count: 12 +# Configuration parameters: AllowComments, AllowEmptyLambdas. +Lint/EmptyBlock: + Exclude: + - 'lib/sequel/plugins/chewy_observe.rb' + - 'spec/chewy/minitest/helpers_spec.rb' + - 'spec/chewy/rspec/update_index_spec.rb' + - 'spec/chewy/search/scrolling_spec.rb' + - 'spec/chewy/strategy/atomic_spec.rb' + - 'spec/chewy/strategy_spec.rb' + - 'spec/chewy/type/import/bulk_request_spec.rb' + - 'spec/chewy/type/witchcraft_spec.rb' + - 'spec/chewy_spec.rb' + +# Offense count: 3 +Lint/MissingSuper: + Exclude: + - 'lib/chewy/strategy/atomic.rb' + - 'lib/chewy/type/adapter/object.rb' + - 'lib/chewy/type/adapter/orm.rb' + +# Offense count: 36 +# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. Metrics/AbcSize: - Max: 48 + Max: 41 # Offense count: 4 -# Configuration parameters: CountComments. +# Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: - Max: 300 + Max: 269 -# Offense count: 14 +# Offense count: 13 +# Configuration parameters: IgnoredMethods. Metrics/CyclomaticComplexity: - Max: 13 - -# Offense count: 1450 -# Configuration parameters: AllowHeredoc, AllowURI, URISchemes. -# URISchemes: http, https -Metrics/LineLength: - Max: 198 + Max: 12 -# Offense count: 38 -# Configuration parameters: CountComments. +# Offense count: 44 +# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. Metrics/MethodLength: - Max: 33 + Max: 29 -# Offense count: 1 -# Configuration parameters: CountComments. +# Offense count: 2 +# Configuration parameters: CountComments, CountAsOne. Metrics/ModuleLength: - Max: 180 + Max: 174 -# Offense count: 14 +# Offense count: 18 +# Configuration parameters: IgnoredMethods. Metrics/PerceivedComplexity: - Max: 15 + Max: 13 -# Offense count: 93 +# Offense count: 11 +# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers. +# SupportedStyles: snake_case, normalcase, non_integer +# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339 +Naming/VariableNumber: + Exclude: + - 'spec/chewy/fields/root_spec.rb' + +# Offense count: 5 +Style/DocumentDynamicEvalDefinition: + Exclude: + - 'lib/chewy/index/actions.rb' + - 'lib/chewy/repository.rb' + - 'lib/chewy/search/pagination/kaminari.rb' + - 'lib/chewy/type/crutch.rb' + - 'lib/chewy/type/witchcraft.rb' + +# Offense count: 63 Style/Documentation: Enabled: false + +# Offense count: 2 +# Cop supports --auto-correct. +Style/EvalWithLocation: + Exclude: + - 'spec/chewy/index_spec.rb' + +# Offense count: 208 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Enabled: false + +# Offense count: 2 +# Configuration parameters: MinBodyLength. +Style/GuardClause: + Exclude: + - 'lib/chewy.rb' + - 'spec/support/active_record.rb' + +# Offense count: 12 +# Cop supports --auto-correct. +Style/IfUnlessModifier: + Exclude: + - 'lib/chewy.rb' + - 'lib/chewy/railtie.rb' + - 'lib/chewy/rspec/update_index.rb' + - 'lib/chewy/search/query_proxy.rb' + - 'lib/chewy/type/adapter/mongoid.rb' + - 'lib/chewy/type/adapter/sequel.rb' + - 'lib/chewy/type/import.rb' + - 'lib/chewy/type/witchcraft.rb' + - 'spec/support/active_record.rb' + +# Offense count: 64 +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 191 diff --git a/Guardfile b/Guardfile index 67d4c153b..5d5e8f113 100644 --- a/Guardfile +++ b/Guardfile @@ -9,7 +9,9 @@ guard :rspec, cmd: 'rspec' do # Rails example watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } - watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] } + watch(%r{^app/controllers/(.+)_(controller)\.rb$}) do |m| + ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] + end watch(%r{^spec/support/(.+)\.rb$}) { 'spec' } watch('config/routes.rb') { 'spec/routing' } watch('app/controllers/application_controller.rb') { 'spec/controllers' } diff --git a/chewy.gemspec b/chewy.gemspec index 5e6505616..fb1948ab6 100644 --- a/chewy.gemspec +++ b/chewy.gemspec @@ -1,8 +1,8 @@ -lib = File.expand_path('../lib', __FILE__) +lib = File.expand_path('lib', __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'chewy/version' -Gem::Specification.new do |spec| # rubocop:disable BlockLength +Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength spec.name = 'chewy' spec.version = Chewy::VERSION spec.authors = ['Toptal, LLC', 'pyromaniac'] @@ -25,7 +25,7 @@ Gem::Specification.new do |spec| # rubocop:disable BlockLength spec.add_development_dependency 'rspec', '>= 3.7.0' spec.add_development_dependency 'rspec-collection_matchers' spec.add_development_dependency 'rspec-its' - spec.add_development_dependency 'rubocop', '0.52.1' + spec.add_development_dependency 'rubocop', '1.11' spec.add_development_dependency 'sqlite3' spec.add_development_dependency 'timecop' diff --git a/gemfiles/rails.5.2.activerecord.gemfile b/gemfiles/rails.5.2.activerecord.gemfile index 8564c7b45..d03a97674 100644 --- a/gemfiles/rails.5.2.activerecord.gemfile +++ b/gemfiles/rails.5.2.activerecord.gemfile @@ -1,17 +1,17 @@ # This file was generated by Appraisal -source "https://rubygems.org" +source 'https://rubygems.org' -gem "activerecord", "~> 5.2.0" -gem "activesupport", "~> 5.2.0" -gem "activejob", "~> 5.2.0" -gem "resque", require: false -gem "shoryuken", require: false -gem "aws-sdk-sqs", require: false -gem "sidekiq", require: false -gem "kaminari-core", "~> 1.1.0", require: false -gem "will_paginate", require: false -gem "parallel", require: false +gem 'activejob', '~> 5.2.0' +gem 'activerecord', '~> 5.2.0' +gem 'activesupport', '~> 5.2.0' +gem 'aws-sdk-sqs', require: false +gem 'kaminari-core', '~> 1.1.0', require: false +gem 'parallel', require: false +gem 'resque', require: false gem 'rspec_junit_formatter', '~> 0.4.1' +gem 'shoryuken', require: false +gem 'sidekiq', require: false +gem 'will_paginate', require: false -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/rails.5.2.mongoid.6.4.gemfile b/gemfiles/rails.5.2.mongoid.6.4.gemfile index 446f4c170..a57167d28 100644 --- a/gemfiles/rails.5.2.mongoid.6.4.gemfile +++ b/gemfiles/rails.5.2.mongoid.6.4.gemfile @@ -1,17 +1,17 @@ # This file was generated by Appraisal -source "https://rubygems.org" +source 'https://rubygems.org' -gem "mongoid", "~> 6.4.0" -gem "activesupport", "~> 5.2.0" -gem "activejob", "~> 5.2.0" -gem "resque", require: false -gem "shoryuken", require: false -gem "aws-sdk-sqs", require: false -gem "sidekiq", require: false -gem "kaminari-core", "~> 1.1.0", require: false -gem "will_paginate", require: false -gem "parallel", require: false +gem 'activejob', '~> 5.2.0' +gem 'activesupport', '~> 5.2.0' +gem 'aws-sdk-sqs', require: false +gem 'kaminari-core', '~> 1.1.0', require: false +gem 'mongoid', '~> 6.4.0' +gem 'parallel', require: false +gem 'resque', require: false gem 'rspec_junit_formatter', '~> 0.4.1' +gem 'shoryuken', require: false +gem 'sidekiq', require: false +gem 'will_paginate', require: false -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/rails.6.0.activerecord.gemfile b/gemfiles/rails.6.0.activerecord.gemfile index de1b2a0a2..14a1021d2 100644 --- a/gemfiles/rails.6.0.activerecord.gemfile +++ b/gemfiles/rails.6.0.activerecord.gemfile @@ -1,17 +1,17 @@ # This file was generated by Appraisal -source "https://rubygems.org" +source 'https://rubygems.org' -gem "activerecord", "~> 6.0.0" -gem "activesupport", "~> 6.0.0" -gem "activejob", "~> 6.0.0" -gem "resque", require: false -gem "shoryuken", require: false -gem "aws-sdk-sqs", require: false -gem "sidekiq", require: false -gem "kaminari-core", "~> 1.1.0", require: false -gem "will_paginate", require: false -gem "parallel", require: false +gem 'activejob', '~> 6.0.0' +gem 'activerecord', '~> 6.0.0' +gem 'activesupport', '~> 6.0.0' +gem 'aws-sdk-sqs', require: false +gem 'kaminari-core', '~> 1.1.0', require: false +gem 'parallel', require: false +gem 'resque', require: false gem 'rspec_junit_formatter', '~> 0.4.1' +gem 'shoryuken', require: false +gem 'sidekiq', require: false +gem 'will_paginate', require: false -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/rails.6.1.activerecord.gemfile b/gemfiles/rails.6.1.activerecord.gemfile index ee552e6d2..9dada0db4 100644 --- a/gemfiles/rails.6.1.activerecord.gemfile +++ b/gemfiles/rails.6.1.activerecord.gemfile @@ -1,19 +1,19 @@ # This file was generated by Appraisal -source "https://rubygems.org" +source 'https://rubygems.org' -gem "activerecord", "~> 6.1.0" -gem "activesupport", "~> 6.1.0" -gem "activejob", "~> 6.1.0" -gem "resque", require: false -gem "shoryuken", require: false -gem "aws-sdk-sqs", require: false -gem "sidekiq", require: false -gem "kaminari-core", "~> 1.1.0", require: false -gem "will_paginate", require: false -gem "parallel", require: false +gem 'activejob', '~> 6.1.0' +gem 'activerecord', '~> 6.1.0' +gem 'activesupport', '~> 6.1.0' +gem 'aws-sdk-sqs', require: false +gem 'kaminari-core', '~> 1.1.0', require: false +gem 'parallel', require: false +gem 'resque', require: false gem 'rspec_junit_formatter', '~> 0.4.1' +gem 'shoryuken', require: false +gem 'sidekiq', require: false +gem 'will_paginate', require: false gem 'rexml' if RUBY_VERSION >= '3.0.0' -gemspec path: "../" +gemspec path: '../' diff --git a/gemfiles/sequel.4.45.gemfile b/gemfiles/sequel.4.45.gemfile index 407b18bcd..31997dcca 100644 --- a/gemfiles/sequel.4.45.gemfile +++ b/gemfiles/sequel.4.45.gemfile @@ -1,11 +1,11 @@ # This file was generated by Appraisal -source "https://rubygems.org" +source 'https://rubygems.org' -gem "sequel", "~> 4.45.0" -gem "activesupport", "~> 5.1.0" -gem "kaminari-core", "~> 1.1.0", require: false -gem "will_paginate", require: false -gem "parallel", require: false +gem 'activesupport', '~> 5.1.0' +gem 'kaminari-core', '~> 1.1.0', require: false +gem 'parallel', require: false +gem 'sequel', '~> 4.45.0' +gem 'will_paginate', require: false -gemspec path: "../" +gemspec path: '../' diff --git a/lib/chewy.rb b/lib/chewy.rb index 7fe0238e2..d9e2235c4 100644 --- a/lib/chewy.rb +++ b/lib/chewy.rb @@ -98,7 +98,11 @@ def derive_type(name) return name if name.is_a?(Class) && name < Chewy::Type types = derive_types(name) - raise Chewy::UnderivableType, "Index `#{types.first.index}` has more than one type, please specify type via `#{types.first.index.derivable_name}#type_name`" unless types.one? + unless types.one? + raise Chewy::UnderivableType, + "Index `#{types.first.index}` has more than one type, please specify type via `#{types.first.index.derivable_name}#type_name`" + end + types.first end @@ -119,8 +123,10 @@ def derive_types(from) class_name = "#{index_name.camelize.gsub(/Index\z/, '')}Index" index = class_name.safe_constantize raise Chewy::UnderivableType, "Can not find index named `#{class_name}`" unless index && index < Chewy::Index + if type_name.present? - type = index.type_hash[type_name] or raise Chewy::UnderivableType, "Index `#{class_name}` doesn`t have type named `#{type_name}`" + type = index.type_hash[type_name] or raise Chewy::UnderivableType, + "Index `#{class_name}` doesn`t have type named `#{type_name}`" [type] else index.types @@ -159,7 +165,9 @@ def client # Does nothing in case of config `wait_for_status` is undefined. # def wait_for_status - client.cluster.health wait_for_status: Chewy.configuration[:wait_for_status] if Chewy.configuration[:wait_for_status].present? + if Chewy.configuration[:wait_for_status].present? + client.cluster.health wait_for_status: Chewy.configuration[:wait_for_status] + end end # Deletes all corresponding indexes with current prefix from ElasticSearch. @@ -227,7 +235,10 @@ def create_indices! def eager_load! return unless defined?(Chewy::Railtie) - dirs = Chewy::Railtie.all_engines.map { |engine| engine.paths[Chewy.configuration[:indices_path]] }.compact.map(&:existent).flatten.uniq + + dirs = Chewy::Railtie.all_engines.map do |engine| + engine.paths[Chewy.configuration[:indices_path]] + end.compact.map(&:existent).flatten.uniq dirs.each do |dir| Dir.glob(File.join(dir, '**/*.rb')).each do |file| diff --git a/lib/chewy/config.rb b/lib/chewy/config.rb index 856675df0..526390544 100644 --- a/lib/chewy/config.rb +++ b/lib/chewy/config.rb @@ -3,43 +3,43 @@ class Config include Singleton attr_accessor :settings, :logger, - # The first strategy in stack. `:base` by default. - # If you need to return to the previous chewy behavior - - # just set it to `:bypass` - # - :root_strategy, - # Default request strategy middleware, used in e.g - # Rails controllers. See Chewy::Railtie::RequestStrategy - # for more info. - # - :request_strategy, - # Use after_commit callbacks for RDBMS instead of - # after_save and after_destroy. True by default. Useful - # in tests with transactional fixtures or transactional - # DatabaseCleaner strategy. - # - :use_after_commit_callbacks, - # Where Chewy expects to find index definitions - # within a Rails app folder. - :indices_path, - # Set index refresh_interval setting to -1 before reset and put the original value after. - # If setting not present, put back to default 1s - # https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html - :reset_disable_refresh_interval, - # Set number_of_replicas to 0 before reset and put the original value after - # https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html - :reset_no_replicas, - # Refresh or not when import async (sidekiq, resque, activejob) - :disable_refresh_async, - # Default options for root of Chewy type. Allows to set default options - # for type mappings like `_all`. - :default_root_options, - # Default field type for any field in any Chewy type. Defaults to 'text'. - :default_field_type + # The first strategy in stack. `:base` by default. + # If you need to return to the previous chewy behavior - + # just set it to `:bypass` + # + :root_strategy, + # Default request strategy middleware, used in e.g + # Rails controllers. See Chewy::Railtie::RequestStrategy + # for more info. + # + :request_strategy, + # Use after_commit callbacks for RDBMS instead of + # after_save and after_destroy. True by default. Useful + # in tests with transactional fixtures or transactional + # DatabaseCleaner strategy. + # + :use_after_commit_callbacks, + # Where Chewy expects to find index definitions + # within a Rails app folder. + :indices_path, + # Set index refresh_interval setting to -1 before reset and put the original value after. + # If setting not present, put back to default 1s + # https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html + :reset_disable_refresh_interval, + # Set number_of_replicas to 0 before reset and put the original value after + # https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html + :reset_no_replicas, + # Refresh or not when import async (sidekiq, resque, activejob) + :disable_refresh_async, + # Default options for root of Chewy type. Allows to set default options + # for type mappings like `_all`. + :default_root_options, + # Default field type for any field in any Chewy type. Defaults to 'text'. + :default_field_type attr_reader :transport_logger, :transport_tracer, - # Chewy search request DSL base class, used by every index. - :search_class + # Chewy search request DSL base class, used by every index. + :search_class def self.delegated public_instance_methods - superclass.public_instance_methods - Singleton.public_instance_methods diff --git a/lib/chewy/fields/base.rb b/lib/chewy/fields/base.rb index 047f6c39a..e75c2c6df 100644 --- a/lib/chewy/fields/base.rb +++ b/lib/chewy/fields/base.rb @@ -59,7 +59,7 @@ def evaluate(objects) if value.is_a?(Proc) if value.arity.zero? object.instance_exec(&value) - elsif value.arity < 0 + elsif value.arity.negative? value.call(*object) else value.call(*objects.first(value.arity)) diff --git a/lib/chewy/fields/root.rb b/lib/chewy/fields/root.rb index e97c171fa..decb1c929 100644 --- a/lib/chewy/fields/root.rb +++ b/lib/chewy/fields/root.rb @@ -1,10 +1,7 @@ module Chewy module Fields class Root < Chewy::Fields::Base - attr_reader :dynamic_templates - attr_reader :id - attr_reader :parent - attr_reader :parent_id + attr_reader :dynamic_templates, :id, :parent, :parent_id def initialize(name, **options) super(name, **options) @@ -55,11 +52,13 @@ def dynamic_template(*args) def compose_parent(object) return unless parent_id + parent_id.arity.zero? ? object.instance_exec(&parent_id) : parent_id.call(object) end def compose_id(object) return unless id + id.arity.zero? ? object.instance_exec(&id) : id.call(object) end diff --git a/lib/chewy/index.rb b/lib/chewy/index.rb index 48b940aa8..f7057817d 100644 --- a/lib/chewy/index.rb +++ b/lib/chewy/index.rb @@ -47,7 +47,8 @@ class << self # UsersIndex.index_name(prefix: '', suffix: '2017') # => 'users_2017' # # @param prefix [String] index name prefix, uses {.prefix} method by default - # @param suffix [String] index name suffix, used for creating several indexes for the same alias during the zero-downtime reset + # @param suffix [String] index name suffix, used for creating several indexes for the same + # alias during the zero-downtime reset # @raise [UndefinedIndex] if the base name is blank # @return [String] result index name def index_name(suggest = nil, prefix: nil, suffix: nil) @@ -77,6 +78,7 @@ def index_name(suggest = nil, prefix: nil, suffix: nil) def base_name @base_name ||= name.sub(/Index\z/, '').demodulize.underscore if name raise UndefinedIndex if @base_name.blank? + @base_name end @@ -240,7 +242,7 @@ def derivable_index_name end # Handling old default_prefix if it is not defined. - def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissing + def method_missing(name, *args, &block) if name == :default_prefix ActiveSupport::Deprecation.warn '`Chewy::Index.default_prefix` is deprecated and will be removed soon, use `Chewy::Index.prefix` instead' prefix @@ -249,6 +251,10 @@ def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissing end end + def respond_to_missing?(name, *args, &block) + name == :default_prefix || super + end + def prefix_with_deprecation if respond_to?(:default_prefix) ActiveSupport::Deprecation.warn '`Chewy::Index.default_prefix` is deprecated and will be removed soon, define `Chewy::Index.prefix` method instead' diff --git a/lib/chewy/index/actions.rb b/lib/chewy/index/actions.rb index ed25d4d00..eac3c7a1d 100644 --- a/lib/chewy/index/actions.rb +++ b/lib/chewy/index/actions.rb @@ -187,7 +187,11 @@ def reset!(suffix = nil, apply_journal: true, journal: false, **import_options) suffixed_name = index_name(suffix: suffix) optimize_index_settings suffixed_name - result = import import_options.merge(suffix: suffix, journal: journal, refresh: !Chewy.reset_disable_refresh_interval) + result = import import_options.merge( + suffix: suffix, + journal: journal, + refresh: !Chewy.reset_disable_refresh_interval + ) original_index_settings suffixed_name delete if indexes.blank? @@ -242,6 +246,7 @@ def update_settings(index_name, **options) def index_settings(setting_name) return {} unless settings_hash.key?(:settings) && settings_hash[:settings].key?(:index) + settings_hash[:settings][:index].slice(setting_name) end end diff --git a/lib/chewy/index/specification.rb b/lib/chewy/index/specification.rb index 1aa3f7b74..4f7bbc6d5 100644 --- a/lib/chewy/index/specification.rb +++ b/lib/chewy/index/specification.rb @@ -36,6 +36,7 @@ def locked filter = {ids: {values: [@index.derivable_name]}} document = Chewy::Stash::Specification.filter(filter).first return {} unless document + JSON.load(Base64.decode64(document.specification)) # rubocop:disable Security/JSONLoad end diff --git a/lib/chewy/journal.rb b/lib/chewy/journal.rb index 455ed770d..90e6ab80f 100644 --- a/lib/chewy/journal.rb +++ b/lib/chewy/journal.rb @@ -7,7 +7,8 @@ module Chewy # journal.clean # class Journal - # @param only [Array] indexes/types or even string references to perform actions on + # @param only [Array] indexes/types or even string references to + # perform actions on def initialize(*only) @only = only end @@ -47,9 +48,9 @@ def clean(until_time = nil) private def reference_groups(entries) - entries.group_by(&:type).map do |type, grouped_entries| - [type, grouped_entries.map(&:references).inject(:|)] - end.to_h + entries.group_by(&:type).transform_values do |grouped_entries| + grouped_entries.map(&:references).inject(:|) + end end end end diff --git a/lib/chewy/minitest/helpers.rb b/lib/chewy/minitest/helpers.rb index 796e62b4d..c09316d20 100644 --- a/lib/chewy/minitest/helpers.rb +++ b/lib/chewy/minitest/helpers.rb @@ -14,7 +14,7 @@ module Helpers # # @return [SearchIndexReceiver] for optional further assertions on the nature of the index changes. # - def assert_indexes(index, strategy: :atomic, bypass_actual_index: true) + def assert_indexes(index, strategy: :atomic, bypass_actual_index: true, &block) type = Chewy.derive_type index receiver = SearchIndexReceiver.new @@ -30,9 +30,7 @@ def assert_indexes(index, strategy: :atomic, bypass_actual_index: true) type.define_singleton_method :bulk, bulk_mock - Chewy.strategy(strategy) do - yield - end + Chewy.strategy(strategy, &block) type.define_singleton_method :bulk, bulk_method @@ -44,10 +42,8 @@ def assert_indexes(index, strategy: :atomic, bypass_actual_index: true) # Run indexing for the database changes during the block provided. # By default, indexing is run at the end of the block. # @param strategy [Symbol] the Chewy index update strategy see Chewy docs. - def run_indexing(strategy: :atomic) - Chewy.strategy strategy do - yield - end + def run_indexing(strategy: :atomic, &block) + Chewy.strategy strategy, &block end module ClassMethods diff --git a/lib/chewy/minitest/search_index_receiver.rb b/lib/chewy/minitest/search_index_receiver.rb index efc7067c7..e4d3a935b 100644 --- a/lib/chewy/minitest/search_index_receiver.rb +++ b/lib/chewy/minitest/search_index_receiver.rb @@ -28,9 +28,7 @@ def indexes_for(index = nil) if index mutation_for(index).indexes else - Hash[ - @mutations.map { |a, b| [a, b.indexes] } - ] + @mutations.transform_values(&:indexes) end end alias_method :indexes, :indexes_for @@ -41,9 +39,7 @@ def deletes_for(index = nil) if index mutation_for(index).deletes else - Hash[ - @mutations.map { |a, b| [a, b.deletes] } - ] + @mutations.transform_values(&:deletes) end end alias_method :deletes, :deletes_for diff --git a/lib/chewy/railtie.rb b/lib/chewy/railtie.rb index 5d1c48104..ac69fa1bc 100644 --- a/lib/chewy/railtie.rb +++ b/lib/chewy/railtie.rb @@ -14,7 +14,9 @@ def call(env) if Rails.application.config.respond_to?(:assets) && env['PATH_INFO'].start_with?(Rails.application.config.assets.prefix) @app.call(env) else - Chewy.logger.info("Chewy request strategy is `#{Chewy.request_strategy}`") if Chewy.logger && @request_strategy != Chewy.request_strategy + if Chewy.logger && @request_strategy != Chewy.request_strategy + Chewy.logger.info("Chewy request strategy is `#{Chewy.request_strategy}`") + end @request_strategy = Chewy.request_strategy Chewy.strategy(Chewy.request_strategy) { @app.call(env) } end diff --git a/lib/chewy/rake_helper.rb b/lib/chewy/rake_helper.rb index d2cfd5ee5..ff4e12b34 100644 --- a/lib/chewy/rake_helper.rb +++ b/lib/chewy/rake_helper.rb @@ -4,13 +4,11 @@ module RakeHelper duration = (finish - start).ceil stats = payload.fetch(:import, {}).map { |key, count| "#{key} #{count}" }.join(', ') output.puts " Imported #{payload[:type]} in #{human_duration(duration)}, stats: #{stats}" - if payload[:errors] - payload[:errors].each do |action, errors| - output.puts " #{action.to_s.humanize} errors:" - errors.each do |error, documents| - output.puts " `#{error}`" - output.puts " on #{documents.count} documents: #{documents}" - end + payload[:errors]&.each do |action, errors| + output.puts " #{action.to_s.humanize} errors:" + errors.each do |error, documents| + output.puts " `#{error}`" + output.puts " on #{documents.count} documents: #{documents}" end end end @@ -36,7 +34,7 @@ class << self # @param parallel [true, Integer, Hash] any acceptable parallel options for import # @param output [IO] output io for logging # @return [Array] indexes that were reset - def reset(only: nil, except: nil, parallel: nil, output: STDOUT) + def reset(only: nil, except: nil, parallel: nil, output: $stdout) subscribed_task_stats(output) do indexes_from(only: only, except: except).each do |index| reset_one(index, output, parallel: parallel) @@ -59,7 +57,7 @@ def reset(only: nil, except: nil, parallel: nil, output: STDOUT) # @param parallel [true, Integer, Hash] any acceptable parallel options for import # @param output [IO] output io for logging # @return [Array] indexes that were actually reset - def upgrade(only: nil, except: nil, parallel: nil, output: STDOUT) + def upgrade(only: nil, except: nil, parallel: nil, output: $stdout) subscribed_task_stats(output) do indexes = indexes_from(only: only, except: except) @@ -97,7 +95,7 @@ def upgrade(only: nil, except: nil, parallel: nil, output: STDOUT) # @param parallel [true, Integer, Hash] any acceptable parallel options for import # @param output [IO] output io for logging # @return [Array] types that were actually updated - def update(only: nil, except: nil, parallel: nil, output: STDOUT) + def update(only: nil, except: nil, parallel: nil, output: $stdout) subscribed_task_stats(output) do types_from(only: only, except: except).group_by(&:index).each_with_object([]) do |(index, types), update_types| if index.exists? @@ -125,7 +123,7 @@ def update(only: nil, except: nil, parallel: nil, output: STDOUT) # @param parallel [true, Integer, Hash] any acceptable parallel options for sync # @param output [IO] output io for logging # @return [Array] types that were actually updated - def sync(only: nil, except: nil, parallel: nil, output: STDOUT) + def sync(only: nil, except: nil, parallel: nil, output: $stdout) subscribed_task_stats(output) do types_from(only: only, except: except).each_with_object([]) do |type, synced_types| output.puts "Synchronizing #{type}" @@ -134,7 +132,7 @@ def sync(only: nil, except: nil, parallel: nil, output: STDOUT) sync_result = type.sync(parallel: parallel) if !sync_result output.puts " Something went wrong with the #{type} synchronization" - elsif sync_result[:count] > 0 + elsif (sync_result[:count]).positive? output.puts " Missing documents: #{sync_result[:missing]}" if sync_result[:missing].present? output.puts " Outdated documents: #{sync_result[:outdated]}" if sync_result[:outdated].present? synced_types.push(type) @@ -161,8 +159,9 @@ def sync(only: nil, except: nil, parallel: nil, output: STDOUT) # @param except [Array, Chewy::Index, Chewy::Type, String] indexes or types to exclude from processing # @param output [IO] output io for logging # @return [Array] types that were actually updated - def journal_apply(time: nil, only: nil, except: nil, output: STDOUT) + def journal_apply(time: nil, only: nil, except: nil, output: $stdout) raise ArgumentError, 'Please specify the time to start with' unless time + subscribed_task_stats(output) do output.puts "Applying journal entries created after #{time}" count = Chewy::Journal.new(types_from(only: only, except: except)).apply(time) @@ -186,7 +185,7 @@ def journal_apply(time: nil, only: nil, except: nil, output: STDOUT) # @param except [Array, Chewy::Index, Chewy::Type, String] indexes or types to exclude from processing # @param output [IO] output io for logging # @return [Array] types that were actually updated - def journal_clean(time: nil, only: nil, except: nil, output: STDOUT) + def journal_clean(time: nil, only: nil, except: nil, output: $stdout) subscribed_task_stats(output) do output.puts "Cleaning journal entries created before #{time}" if time response = Chewy::Journal.new(types_from(only: only, except: except)).clean(time) @@ -210,15 +209,14 @@ def normalize_indexes(*identifiers) def normalize_index(identifier) return identifier if identifier.is_a?(Class) && identifier < Chewy::Index + "#{identifier.to_s.gsub(/identifier\z/i, '').camelize}Index".constantize end - def subscribed_task_stats(output = STDOUT) + def subscribed_task_stats(output = $stdout, &block) start = Time.now ActiveSupport::Notifications.subscribed(JOURNAL_CALLBACK.curry[output], 'apply_journal.chewy') do - ActiveSupport::Notifications.subscribed(IMPORT_CALLBACK.curry[output], 'import_objects.chewy') do - yield - end + ActiveSupport::Notifications.subscribed(IMPORT_CALLBACK.curry[output], 'import_objects.chewy', &block) end output.puts "Total: #{human_duration(Time.now - start)}" end @@ -287,7 +285,7 @@ def normalize_type(identifier) def human_duration(seconds) [[60, :s], [60, :m], [24, :h]].map do |amount, unit| - if seconds > 0 + if seconds.positive? seconds, n = seconds.divmod(amount) "#{n.to_i}#{unit}" end diff --git a/lib/chewy/rspec/update_index.rb b/lib/chewy/rspec/update_index.rb index 1e505eba9..ced885629 100644 --- a/lib/chewy/rspec/update_index.rb +++ b/lib/chewy/rspec/update_index.rb @@ -20,7 +20,7 @@ # specify { expect { user1.destroy!; user2.save! } } # .to update_index(UsersIndex::User).and_reindex(user2).and_delete(user1) } # -RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disable BlockLength +RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disable Metrics/BlockLength if !respond_to?(:failure_message) && respond_to?(:failure_message_for_should) alias_method :failure_message, :failure_message_for_should alias_method :failure_message_when_negated, :failure_message_for_should_not @@ -92,7 +92,7 @@ def supports_block_expectations? true end - match do |block| # rubocop:disable BlockLength + match do |block| # rubocop:disable Metrics/BlockLength @reindex ||= {} @delete ||= {} @missed_reindex = [] @@ -127,13 +127,13 @@ def supports_block_expectations? end @reindex.each_value do |document| - document[:match_count] = (!document[:expected_count] && document[:real_count] > 0) || + document[:match_count] = (!document[:expected_count] && (document[:real_count]).positive?) || (document[:expected_count] && document[:expected_count] == document[:real_count]) document[:match_attributes] = document[:expected_attributes].blank? || compare_attributes(document[:expected_attributes], document[:real_attributes]) end @delete.each_value do |document| - document[:match_count] = (!document[:expected_count] && document[:real_count] > 0) || + document[:match_count] = (!document[:expected_count] && (document[:real_count]).positive?) || (document[:expected_count] && document[:expected_count] == document[:real_count]) end @@ -142,7 +142,7 @@ def supports_block_expectations? @delete.all? { |_, document| document[:match_count] } end - failure_message do # rubocop:disable BlockLength + failure_message do # rubocop:disable Metrics/BlockLength output = '' if mock_bulk_request.updates.none? @@ -166,9 +166,13 @@ def supports_block_expectations? output << @reindex.each.with_object('') do |(id, document), result| unless document[:match_count] && document[:match_attributes] result << "Expected document with id `#{id}` to be reindexed" - if document[:real_count] > 0 - result << "\n #{document[:expected_count]} times, but was reindexed #{document[:real_count]} times" if document[:expected_count] && !document[:match_count] - result << "\n with #{document[:expected_attributes]}, but it was reindexed with #{document[:real_attributes]}" if document[:expected_attributes].present? && !document[:match_attributes] + if (document[:real_count]).positive? + if document[:expected_count] && !document[:match_count] + result << "\n #{document[:expected_count]} times, but was reindexed #{document[:real_count]} times" + end + if document[:expected_attributes].present? && !document[:match_attributes] + result << "\n with #{document[:expected_attributes]}, but it was reindexed with #{document[:real_attributes]}" + end else result << ', but it was not' end @@ -179,11 +183,11 @@ def supports_block_expectations? output << @delete.each.with_object('') do |(id, document), result| unless document[:match_count] result << "Expected document with id `#{id}` to be deleted" - result << if document[:real_count] > 0 && document[:expected_count] - "\n #{document[:expected_count]} times, but was deleted #{document[:real_count]} times" - else - ', but it was not' - end + result << if (document[:real_count]).positive? && document[:expected_count] + "\n #{document[:expected_count]} times, but was deleted #{document[:real_count]} times" + else + ', but it was not' + end result << "\n" end end @@ -209,7 +213,7 @@ def extract_documents(*args) expected_count = options[:times] || options[:count] expected_attributes = (options[:with] || options[:attributes] || {}).deep_symbolize_keys - Hash[args.flatten.map do |document| + args.flatten.map do |document| id = document.respond_to?(:id) ? document.id.to_s : document.to_s [id, { document: document, @@ -218,7 +222,7 @@ def extract_documents(*args) real_count: 0, real_attributes: {} }] - end] + end.to_h end def compare_attributes(expected, real) diff --git a/lib/chewy/search/loader.rb b/lib/chewy/search/loader.rb index 1a86d07bb..5f8c3c066 100644 --- a/lib/chewy/search/loader.rb +++ b/lib/chewy/search/loader.rb @@ -27,6 +27,7 @@ def derive_type(index, type) (@derive_type ||= {})[[index, type]] ||= begin index_class = derive_index(index) raise Chewy::UnderivableType, "Can not find index named `#{index}`" unless index_class + index_class.type_hash.values.first end end diff --git a/lib/chewy/search/parameters.rb b/lib/chewy/search/parameters.rb index bdf652189..931531d8c 100644 --- a/lib/chewy/search/parameters.rb +++ b/lib/chewy/search/parameters.rb @@ -1,5 +1,5 @@ -Dir.glob(File.join(File.dirname(__FILE__), 'parameters', 'concerns', '*.rb')) { |f| require f } -Dir.glob(File.join(File.dirname(__FILE__), 'parameters', '*.rb')) { |f| require f } +Dir.glob(File.join(File.dirname(__FILE__), 'parameters', 'concerns', '*.rb')).sort.each { |f| require f } +Dir.glob(File.join(File.dirname(__FILE__), 'parameters', '*.rb')).sort.each { |f| require f } module Chewy module Search @@ -24,6 +24,7 @@ def self.storages # @return [{Symbol => Chewy::Search::Parameters::Storage}] attr_accessor :storages + delegate :[], :[]=, to: :storages # Accepts an initial hash as basic values or parameter storages. @@ -120,6 +121,7 @@ def compare_storages(other) def assert_storages(names) raise ArgumentError, 'No storage names were specified' if names.empty? + names = names.map(&:to_sym) self.class.storages.values_at(*names) names diff --git a/lib/chewy/search/parameters/concerns/query_storage.rb b/lib/chewy/search/parameters/concerns/query_storage.rb index 0871881f6..ec9bc5e3a 100644 --- a/lib/chewy/search/parameters/concerns/query_storage.rb +++ b/lib/chewy/search/parameters/concerns/query_storage.rb @@ -86,7 +86,7 @@ def to_h def reduce value = to_h .reject { |_, v| v.blank? } - .map { |k, v| [k, v.is_a?(Array) && v.one? ? v.first : v] }.to_h + .transform_values { |v| v.is_a?(Array) && v.one? ? v.first : v } value.delete(:minimum_should_match) if should.empty? value end diff --git a/lib/chewy/search/parameters/source.rb b/lib/chewy/search/parameters/source.rb index fa27e93a9..a9015fb0c 100644 --- a/lib/chewy/search/parameters/source.rb +++ b/lib/chewy/search/parameters/source.rb @@ -17,7 +17,11 @@ class Source < Storage # In case of hash, respective values are concatenated as well. # # @see Chewy::Search::Parameters::Storage#update! - # @param other_value [true, false, {Symbol => Array, String, Symbol}, Array, String, Symbol] any acceptable storage value + # @param other_value + # [true, false, { + # Symbol => Array, String, Symbol}, + # Array, String, Symbol + # ] any acceptable storage value # @return [{Symbol => Array, true, false}] updated value def update!(other_value) new_value = normalize(other_value) diff --git a/lib/chewy/search/query_proxy.rb b/lib/chewy/search/query_proxy.rb index 9103493c1..17aef879e 100644 --- a/lib/chewy/search/query_proxy.rb +++ b/lib/chewy/search/query_proxy.rb @@ -102,6 +102,7 @@ def initialize(parameter_name, request) %i[must should must_not].each do |method| define_method method do |query_hash = nil, &block| raise ArgumentError, "Please provide a parameter or a block to `#{method}`" unless query_hash || block + @request.send(:modify, @parameter_name) { send(method, block || query_hash) } end end @@ -237,8 +238,14 @@ def initialize(parameter_name, request) # @yield the block is processed by `elasticsearch-dsl` gem %i[and or not].each do |method| define_method method do |query_hash_or_scope = nil, &block| - raise ArgumentError, "Please provide a parameter or a block to `#{method}`" unless query_hash_or_scope || block - query_hash_or_scope = query_hash_or_scope.parameters[@parameter_name].value if !block && query_hash_or_scope.is_a?(Chewy::Search::Request) + unless query_hash_or_scope || block + raise ArgumentError, + "Please provide a parameter or a block to `#{method}`" + end + + if !block && query_hash_or_scope.is_a?(Chewy::Search::Request) + query_hash_or_scope = query_hash_or_scope.parameters[@parameter_name].value + end @request.send(:modify, @parameter_name) { send(method, block || query_hash_or_scope) } end end diff --git a/lib/chewy/search/request.rb b/lib/chewy/search/request.rb index e151a8936..ff4679e88 100644 --- a/lib/chewy/search/request.rb +++ b/lib/chewy/search/request.rb @@ -45,8 +45,8 @@ class Request ].freeze delegate :hits, :wrappers, :objects, :records, :documents, - :object_hash, :record_hash, :document_hash, - :total, :max_score, :took, :timed_out?, to: :response + :object_hash, :record_hash, :document_hash, + :total, :max_score, :took, :timed_out?, to: :response delegate :each, :size, :to_a, :[], to: :wrappers alias_method :to_ary, :to_a alias_method :total_count, :total @@ -728,7 +728,10 @@ def merge(other) # scope1.and(scope2) # # => {:query=>{:bool=>{ # # :must=>[{:match=>{:name=>"London"}}, {:match=>{:name=>"Washington"}}], - # # :filter=>{:bool=>{:must=>[{:term=>{:name=>"Moscow"}}, {:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}}]}}}}}}> + # # :filter=>{ + # # :bool=>{:must=>[{:term=>{:name=>"Moscow"}}, {:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}}]} + # # } + # # }}}}> # @param other [Chewy::Search::Request] scope to merge # @return [Chewy::Search::Request] new scope # @@ -745,7 +748,10 @@ def merge(other) # scope1.or(scope2) # # => {:query=>{:bool=>{ # # :should=>[{:match=>{:name=>"London"}}, {:match=>{:name=>"Washington"}}], - # # :filter=>{:bool=>{:should=>[{:term=>{:name=>"Moscow"}}, {:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}}]}}}}}}> + # # :filter=>{ + # # :bool=>{:should=>[{:term=>{:name=>"Moscow"}}, {:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}}]} + # # } + # # }}}}> # @param other [Chewy::Search::Request] scope to merge # @return [Chewy::Search::Request] new scope # @@ -762,7 +768,13 @@ def merge(other) # scope1.not(scope2) # # => {:query=>{:bool=>{ # # :must=>{:match=>{:name=>"London"}}, :must_not=>{:match=>{:name=>"Washington"}}, - # # :filter=>{:bool=>{:must=>{:term=>{:name=>"Moscow"}}, :must_not=>{:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}}}}}}}}> + # # :filter=>{ + # # :bool=>{ + # # :must=>{:term=>{:name=>"Moscow"}}, + # # :must_not=>{:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}} + # # } + # # } + # # }}}}> # @param other [Chewy::Search::Request] scope to merge # @return [Chewy::Search::Request] new scope %i[and or not].each do |name| @@ -931,11 +943,10 @@ def pluck(*fields) # @return [Hash] the result of query execution def delete_all(refresh: true) request_body = only(WHERE_STORAGES).render.merge(refresh: refresh) - ActiveSupport::Notifications.instrument 'delete_query.chewy', - notification_payload(request: request_body) do - request_body[:body] = {query: {match_all: {}}} if request_body[:body].empty? - Chewy.client.delete_by_query(request_body) - end + ActiveSupport::Notifications.instrument 'delete_query.chewy', notification_payload(request: request_body) do + request_body[:body] = {query: {match_all: {}}} if request_body[:body].empty? + Chewy.client.delete_by_query(request_body) + end end # Returns whether or not the query has been performed. @@ -976,14 +987,13 @@ def reset def perform(additional = {}) request_body = render.merge(additional) - ActiveSupport::Notifications.instrument 'search_query.chewy', - notification_payload(request: request_body) do - begin - Chewy.client.search(request_body) - rescue Elasticsearch::Transport::Transport::Errors::NotFound - {} - end + ActiveSupport::Notifications.instrument 'search_query.chewy', notification_payload(request: request_body) do + begin + Chewy.client.search(request_body) + rescue Elasticsearch::Transport::Transport::Errors::NotFound + {} end + end end def notification_payload(additional) diff --git a/lib/chewy/search/scrolling.rb b/lib/chewy/search/scrolling.rb index b71f21d75..25e35e88f 100644 --- a/lib/chewy/search/scrolling.rb +++ b/lib/chewy/search/scrolling.rb @@ -40,6 +40,7 @@ def scroll_batches(batch_size: Request::DEFAULT_BATCH_SIZE, scroll: Request::DEF yield(hits) if hits.present? scroll_id = result['_scroll_id'] break if fetched >= total + result = perform_scroll(scroll: scroll, scroll_id: scroll_id) end ensure @@ -61,11 +62,11 @@ def scroll_batches(batch_size: Request::DEFAULT_BATCH_SIZE, scroll: Request::DEF # @example # PlaceIndex.scroll_hits.map { |hit| hit['_id'] } # @return [Enumerator] a standard ruby Enumerator - def scroll_hits(**options) + def scroll_hits(**options, &block) return enum_for(:scroll_hits, **options) unless block_given? scroll_batches(**options).each do |batch| - batch.each { |hit| yield hit } + batch.each(&block) end end @@ -113,12 +114,12 @@ def scroll_wrappers(**options) # @example # PlaceIndex.scroll_objects.map { |record| record.id } # @return [Enumerator] a standard ruby Enumerator - def scroll_objects(**options) + def scroll_objects(**options, &block) return enum_for(:scroll_objects, **options) unless block_given? except(:source, :stored_fields, :script_fields, :docvalue_fields) .source(false).scroll_batches(**options).each do |batch| - loader.load(batch).each { |object| yield object } + loader.load(batch).each(&block) end end alias_method :scroll_records, :scroll_objects @@ -127,10 +128,9 @@ def scroll_objects(**options) private def perform_scroll(body) - ActiveSupport::Notifications.instrument 'search_query.chewy', - notification_payload(request: body) do - Chewy.client.scroll(body) - end + ActiveSupport::Notifications.instrument 'search_query.chewy', notification_payload(request: body) do + Chewy.client.scroll(body) + end end end end diff --git a/lib/chewy/stash.rb b/lib/chewy/stash.rb index 6d461d116..b9fc900d2 100644 --- a/lib/chewy/stash.rb +++ b/lib/chewy/stash.rb @@ -45,6 +45,7 @@ def self.for(*something) something = something.flatten.compact types = something.flat_map { |s| Chewy.derive_types(s) } return none if something.present? && types.blank? + scope = all types.map(&:index).uniq.each do |index| scope = scope.or(filter(term: {index_name: index.derivable_name})) diff --git a/lib/chewy/strategy.rb b/lib/chewy/strategy.rb index f3c15f1c5..4509b9bb7 100644 --- a/lib/chewy/strategy.rb +++ b/lib/chewy/strategy.rb @@ -60,6 +60,7 @@ def push(name) def pop raise "Can't pop root strategy" if @stack.one? + result = @stack.pop.tap(&:leave) debug "[#{@stack.size}] -> #{result.name}, now #{current.name}" if @stack.size > 1 result @@ -75,16 +76,18 @@ def wrap(name) private def debug(string) - return unless Chewy.logger && Chewy.logger.debug? + return unless Chewy.logger&.debug? + line = caller.detect { |l| l !~ %r{lib/chewy/strategy.rb:|lib/chewy.rb:} } Chewy.logger.debug(["Chewy strategies stack: #{string}", line.sub(/:in\s.+$/, '')].join(' @ ')) end def resolve(name) "Chewy::Strategy::#{name.to_s.camelize}".safe_constantize or raise "Can't find update strategy `#{name}`" - rescue NameError => ex + rescue NameError => e # WORKAROUND: Strange behavior of `safe_constantize` with mongoid gem - raise "Can't find update strategy `#{name}`" if ex.name.to_s.demodulize == name.to_s.camelize + raise "Can't find update strategy `#{name}`" if e.name.to_s.demodulize == name.to_s.camelize + raise end end diff --git a/lib/chewy/strategy/shoryuken.rb b/lib/chewy/strategy/shoryuken.rb index 7326b1ab4..1418c8281 100644 --- a/lib/chewy/strategy/shoryuken.rb +++ b/lib/chewy/strategy/shoryuken.rb @@ -26,6 +26,7 @@ def perform(_sqs_msg, body) def leave @stash.each do |type, ids| next if ids.empty? + Shoryuken::Worker.perform_async({type: type.name, ids: ids}, queue: shoryuken_queue) end end diff --git a/lib/chewy/strategy/sidekiq.rb b/lib/chewy/strategy/sidekiq.rb index 635e1fc8b..ba4a1aa9e 100644 --- a/lib/chewy/strategy/sidekiq.rb +++ b/lib/chewy/strategy/sidekiq.rb @@ -22,6 +22,7 @@ def perform(type, ids, options = {}) def leave @stash.each do |type, ids| next if ids.empty? + ::Sidekiq::Client.push( 'queue' => sidekiq_queue, 'class' => Chewy::Strategy::Sidekiq::Worker, diff --git a/lib/chewy/type.rb b/lib/chewy/type.rb index 4d21da1cf..e95c6661f 100644 --- a/lib/chewy/type.rb +++ b/lib/chewy/type.rb @@ -37,7 +37,8 @@ class << self # Chewy index current type belongs to. Defined inside `Chewy.create_type` # def index - raise NotImplementedError, 'Looks like this type was defined outside the index scope and `.index` method is undefined for it' + raise NotImplementedError, + 'Looks like this type was defined outside the index scope and `.index` method is undefined for it' end # Current type adapter. Defined inside `Chewy.create_type`, derived from @@ -64,7 +65,7 @@ def type_name # @see Chewy::Index.derivable_name # @return [String, nil] derivable name or nil when it is impossible to calculate def derivable_name - @derivable_name ||= [index.derivable_name, type_name].join('#') if index && index.derivable_name + @derivable_name ||= [index.derivable_name, type_name].join('#') if index&.derivable_name end # This method is an API shared with {Chewy::Index}, added for convenience. diff --git a/lib/chewy/type/actions.rb b/lib/chewy/type/actions.rb index 43730ab3a..452b4216a 100644 --- a/lib/chewy/type/actions.rb +++ b/lib/chewy/type/actions.rb @@ -24,7 +24,8 @@ def reset # # @see Chewy::Type::Syncer # @param parallel [true, Integer, Hash] options for parallel execution or the number of processes - # @return [Hash{Symbol, Object}, nil] a number of missing and outdated documents reindexed and their ids, nil in case of errors + # @return [Hash{Symbol, Object}, nil] a number of missing and outdated documents reindexed and their ids, + # nil in case of errors def sync(parallel: nil) syncer = Syncer.new(self, parallel: parallel) count = syncer.perform diff --git a/lib/chewy/type/adapter/active_record.rb b/lib/chewy/type/adapter/active_record.rb index f2f96960d..371eeb05b 100644 --- a/lib/chewy/type/adapter/active_record.rb +++ b/lib/chewy/type/adapter/active_record.rb @@ -60,7 +60,15 @@ def pluck(scope, fields: [], typecast: true) end def pluck_in_batches(scope, fields: [], batch_size: nil, typecast: true) - return enum_for(:pluck_in_batches, scope, fields: fields, batch_size: batch_size, typecast: typecast) unless block_given? + unless block_given? + return enum_for( + :pluck_in_batches, + scope, + fields: fields, + batch_size: batch_size, + typecast: typecast + ) + end scope = scope.reorder(target_id.asc).limit(batch_size) ids = pluck(scope, fields: fields, typecast: typecast) @@ -69,6 +77,7 @@ def pluck_in_batches(scope, fields: [], batch_size: nil, typecast: true) while ids.present? yield ids break if ids.size < batch_size + last_id = ids.last.is_a?(Array) ? ids.last.first : ids.last ids = pluck(scope.where(target_id.gt(last_id)), fields: fields, typecast: typecast) end diff --git a/lib/chewy/type/adapter/mongoid.rb b/lib/chewy/type/adapter/mongoid.rb index 472de1ff3..a3652ac7b 100644 --- a/lib/chewy/type/adapter/mongoid.rb +++ b/lib/chewy/type/adapter/mongoid.rb @@ -17,13 +17,19 @@ def identify(collection) private def cleanup_default_scope! - Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified') if Chewy.logger && @default_scope.options.values_at(:sort, :limit, :skip).compact.present? + if Chewy.logger && sort_or_limit_or_skip_options? + Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified') + end @default_scope.options.delete(:limit) @default_scope.options.delete(:skip) @default_scope = @default_scope.reorder(nil) end + def sort_or_limit_or_skip_options? + @default_scope.options.values_at(:sort, :limit, :skip).compact.present? + end + def import_scope(scope, options) pluck_in_batches(scope, **options.slice(:batch_size)).map do |ids| yield grouped_objects(default_scope_where_ids_in(ids)) @@ -38,12 +44,18 @@ def pluck(scope, fields: []) scope.pluck(primary_key, *fields) end - def pluck_in_batches(scope, fields: [], batch_size: nil, **options) - return enum_for(:pluck_in_batches, scope, fields: fields, batch_size: batch_size, **options) unless block_given? - - scope.batch_size(batch_size).no_timeout.pluck(primary_key, *fields).each_slice(batch_size) do |batch| - yield batch + def pluck_in_batches(scope, fields: [], batch_size: nil, **options, &block) + unless block_given? + return enum_for( + :pluck_in_batches, + scope, + fields: fields, + batch_size: batch_size, + **options + ) end + + scope.batch_size(batch_size).no_timeout.pluck(primary_key, *fields).each_slice(batch_size, &block) end def scope_where_ids_in(scope, ids) diff --git a/lib/chewy/type/adapter/object.rb b/lib/chewy/type/adapter/object.rb index 8120717f1..3ea167656 100644 --- a/lib/chewy/type/adapter/object.rb +++ b/lib/chewy/type/adapter/object.rb @@ -114,15 +114,14 @@ def import(*args, &block) # end # # @see Chewy::Type::Adapter::Base#import_fields - def import_fields(*args) + def import_fields(*args, &block) return enum_for(:import_fields, *args) unless block_given? + options = args.extract_options! options[:batch_size] ||= BATCH_SIZE if args.empty? && @target.respond_to?(pluck_method) - @target.send(pluck_method, :id, *options[:fields]).each_slice(options[:batch_size]) do |batch| - yield batch - end + @target.send(pluck_method, :id, *options[:fields]).each_slice(options[:batch_size], &block) elsif options[:fields].blank? import_references(*args, options) do |batch| yield batch.map { |object| object_field(object, :id) || object } @@ -141,13 +140,11 @@ def import_fields(*args) # For the Object adapter returns the objects themselves in batches. # # @see Chewy::Type::Adapter::Base#import_references - def import_references(*args) + def import_references(*args, &block) return enum_for(:import_references, *args) unless block_given? collection, options = import_args(*args) - collection.each_slice(options[:batch_size]) do |batch| - yield batch - end + collection.each_slice(options[:batch_size], &block) end # This method is used internally by the request DSL when the diff --git a/lib/chewy/type/adapter/orm.rb b/lib/chewy/type/adapter/orm.rb index d9a663432..d516b4b15 100644 --- a/lib/chewy/type/adapter/orm.rb +++ b/lib/chewy/type/adapter/orm.rb @@ -92,9 +92,7 @@ def import_fields(*args, &block) collection = all_scope_where_ids_in(identify(collection)) unless collection.is_a?(relation_class) pluck_in_batches(collection, **options.slice(:fields, :batch_size, :typecast), &block) else - identify(collection).each_slice(options[:batch_size]) do |batch| - yield batch - end + identify(collection).each_slice(options[:batch_size], &block) end end alias_method :import_references, :import_fields @@ -115,7 +113,7 @@ def load(ids, **options) def import_objects(collection, options) collection_ids = identify(collection) - hash = Hash[collection_ids.map(&:to_s).zip(collection)] + hash = collection_ids.map(&:to_s).zip(collection).to_h indexed = collection_ids.each_slice(options[:batch_size]).map do |ids| batch = if options[:raw_import] diff --git a/lib/chewy/type/adapter/sequel.rb b/lib/chewy/type/adapter/sequel.rb index 751a00836..fc427bb7d 100644 --- a/lib/chewy/type/adapter/sequel.rb +++ b/lib/chewy/type/adapter/sequel.rb @@ -16,7 +16,9 @@ def self.accepts?(target) private def cleanup_default_scope! - Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified') if Chewy.logger && @default_scope != @default_scope.unordered.unlimited + if Chewy.logger && @default_scope != @default_scope.unordered.unlimited + Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified') + end @default_scope = @default_scope.unordered.unlimited end @@ -51,7 +53,15 @@ def pluck(scope, fields: []) end def pluck_in_batches(scope, fields: [], batch_size: nil, **options) - return enum_for(:pluck_in_batches, scope, fields: fields, batch_size: batch_size, **options) unless block_given? + unless block_given? + return enum_for( + :pluck_in_batches, + scope, + fields: fields, + batch_size: batch_size, + **options + ) + end scope = scope.unordered.order(full_column_name(primary_key).asc).limit(batch_size) @@ -61,6 +71,7 @@ def pluck_in_batches(scope, fields: [], batch_size: nil, **options) while ids.present? yield ids break if ids.size < batch_size + last_id = ids.last.is_a?(Array) ? ids.last.first : ids.last ids = pluck(scope.where { |_o| full_column_name(primary_key) > last_id }, fields: fields) end diff --git a/lib/chewy/type/import.rb b/lib/chewy/type/import.rb index 6cc7f4591..3dcc8be3c 100644 --- a/lib/chewy/type/import.rb +++ b/lib/chewy/type/import.rb @@ -87,6 +87,7 @@ def import(*args) def import!(*args) errors = import_routine(*args) raise Chewy::ImportFailed.new(self, errors) if errors.present? + true end @@ -160,19 +161,29 @@ def import_linear(objects, routine) end def import_parallel(objects, routine) - raise "The `parallel` gem is required for parallel import, please add `gem 'parallel'` to your Gemfile" unless '::Parallel'.safe_constantize + unless '::Parallel'.safe_constantize + raise "The `parallel` gem is required for parallel import, please add `gem 'parallel'` to your Gemfile" + end ActiveSupport::Notifications.instrument 'import_objects.chewy', type: self do |payload| batches = adapter.import_references(*objects, routine.options.slice(:batch_size)).to_a ::ActiveRecord::Base.connection.close if defined?(::ActiveRecord::Base) - results = ::Parallel.map_with_index(batches, routine.parallel_options, &IMPORT_WORKER.curry[self, routine.options, batches.size]) + results = ::Parallel.map_with_index( + batches, + routine.parallel_options, + &IMPORT_WORKER.curry[self, routine.options, batches.size] + ) ::ActiveRecord::Base.connection.reconnect! if defined?(::ActiveRecord::Base) errors, import, leftovers = process_parallel_import_results(results) if leftovers.present? batches = leftovers.each_slice(routine.options[:batch_size]) - results = ::Parallel.map_with_index(batches, routine.parallel_options, &LEFTOVERS_WORKER.curry[self, routine.options, batches.size]) + results = ::Parallel.map_with_index( + batches, + routine.parallel_options, + &LEFTOVERS_WORKER.curry[self, routine.options, batches.size] + ) errors.concat(results.flatten(1)) end diff --git a/lib/chewy/type/import/bulk_builder.rb b/lib/chewy/type/import/bulk_builder.rb index 3b1f1cd4a..4f87c3e09 100644 --- a/lib/chewy/type/import/bulk_builder.rb +++ b/lib/chewy/type/import/bulk_builder.rb @@ -71,6 +71,7 @@ def index_entry(object) [{delete: entry.except(:data).merge(parent: parent)}, {index: entry}] elsif @fields.present? return [] unless entry[:_id] + entry[:data] = {doc: @type.compose(object, crutches, fields: @fields)} [{update: entry}] else @@ -89,6 +90,7 @@ def delete_entry(object) if parents parent = entry[:_id].present? && parents[entry[:_id].to_s] return [] unless parent + entry[:parent] = parent end diff --git a/lib/chewy/type/import/journal_builder.rb b/lib/chewy/type/import/journal_builder.rb index 510c96a93..cd88b21b8 100644 --- a/lib/chewy/type/import/journal_builder.rb +++ b/lib/chewy/type/import/journal_builder.rb @@ -26,6 +26,7 @@ def bulk_body def entries(action, objects) return unless objects.present? + { index_name: @type.index.derivable_name, type_name: @type.type_name, diff --git a/lib/chewy/type/import/routine.rb b/lib/chewy/type/import/routine.rb index 777838356..bcc71c134 100644 --- a/lib/chewy/type/import/routine.rb +++ b/lib/chewy/type/import/routine.rb @@ -66,6 +66,7 @@ def initialize(type, **options) def create_indexes! Chewy::Stash::Journal.create if @options[:journal] return if Chewy.configuration[:skip_index_creation_on_import] + @type.index.create!(**@bulk_options.slice(:suffix)) unless @type.index.exists? end diff --git a/lib/chewy/type/syncer.rb b/lib/chewy/type/syncer.rb index 01121b50b..67448234a 100644 --- a/lib/chewy/type/syncer.rb +++ b/lib/chewy/type/syncer.rb @@ -27,7 +27,7 @@ class Type # @see Chewy::Type::Actions::ClassMethods#sync class Syncer DEFAULT_SYNC_BATCH_SIZE = 20_000 - ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/ + ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/.freeze OUTDATED_IDS_WORKER = lambda do |outdated_sync_field_type, source_data_hash, type, total, index_data| ::Process.setproctitle("chewy [#{type}]: sync outdated calculation (#{::Parallel.worker_number + 1}/#{total})") if type index_data.each_with_object([]) do |(id, index_sync_value), result| @@ -56,7 +56,10 @@ class Syncer def self.typecast_date(string) if string.is_a?(String) && (match = ISO_DATETIME.match(string)) microsec = (match[7].to_r * 1_000_000).to_i - date = "#{match[1]}-#{match[2]}-#{match[3]}T#{match[4]}:#{match[5]}:#{match[6]}.#{format('%06d', microsec)}+00:00" + day = "#{match[1]}-#{match[2]}-#{match[3]}" + time_with_seconds = "#{match[4]}:#{match[5]}:#{match[6]}" + microseconds = format('%06d', microsec) + date = "#{day}T#{time_with_seconds}.#{microseconds}+00:00" Time.iso8601(date) else string @@ -95,6 +98,7 @@ def initialize(type, parallel: nil) def perform ids = missing_ids | outdated_ids return 0 if ids.blank? + @type.import(ids, parallel: @parallel) && ids.count end @@ -122,6 +126,7 @@ def missing_ids # @return [Array] an array of outdated ids def outdated_ids return [] if source_data.blank? || index_data.blank? || !@type.supports_outdated_sync? + @outdated_ids ||= begin if @parallel parallel_outdated_ids @@ -160,7 +165,12 @@ def source_and_index_data def fetch_source_data if @type.supports_outdated_sync? - @type.adapter.import_fields(fields: [@type.outdated_sync_field], batch_size: DEFAULT_SYNC_BATCH_SIZE, typecast: false).to_a.flatten(1).each do |data| + import_fields_args = { + fields: [@type.outdated_sync_field], + batch_size: DEFAULT_SYNC_BATCH_SIZE, + typecast: false + } + @type.adapter.import_fields(import_fields_args).to_a.flatten(1).each do |data| data[0] = data[0].to_s end else @@ -180,6 +190,7 @@ def fetch_index_data def data_ids(data) return data unless @type.supports_outdated_sync? + data.map(&:first) end @@ -192,7 +203,12 @@ def parallel_outdated_ids batches = index_data.each_slice(size) ::ActiveRecord::Base.connection.close if defined?(::ActiveRecord::Base) - result = ::Parallel.map(batches, @parallel, &OUTDATED_IDS_WORKER.curry[outdated_sync_field_type, source_data.to_h, @type, batches.size]).flatten(1) + curried_outdated_ids_worker = OUTDATED_IDS_WORKER.curry[outdated_sync_field_type, source_data.to_h, @type, batches.size] + result = ::Parallel.map( + batches, + @parallel, + &curried_outdated_ids_worker + ).flatten(1) ::ActiveRecord::Base.connection.reconnect! if defined?(::ActiveRecord::Base) result end diff --git a/lib/chewy/type/witchcraft.rb b/lib/chewy/type/witchcraft.rb index f2d4f5197..3655d074d 100644 --- a/lib/chewy/type/witchcraft.rb +++ b/lib/chewy/type/witchcraft.rb @@ -23,9 +23,15 @@ def witchcraft! def check_requirements! messages = [] - messages << "MethodSource gem is required for the Witchcraft, please add `gem 'method_source'` to your Gemfile" unless Proc.method_defined?(:source) - messages << "Parser gem is required for the Witchcraft, please add `gem 'parser'` to your Gemfile" unless '::Parser'.safe_constantize - messages << "Unparser gem is required for the Witchcraft, please add `gem 'unparser'` to your Gemfile" unless '::Unparser'.safe_constantize + unless Proc.method_defined?(:source) + messages << "MethodSource gem is required for the Witchcraft, please add `gem 'method_source'` to your Gemfile" + end + unless '::Parser'.safe_constantize + messages << "Parser gem is required for the Witchcraft, please add `gem 'parser'` to your Gemfile" + end + unless '::Unparser'.safe_constantize + messages << "Unparser gem is required for the Witchcraft, please add `gem 'unparser'` to your Gemfile" + end messages = messages.join("\n") raise messages if messages.present? @@ -141,6 +147,7 @@ def proc_values(field, nesting) def non_proc_fields_for(parent, nesting) return [] unless parent + fields = (parent.children || []).reject { |field| field.value.is_a?(Proc) } if nesting.zero? && @fields.present? @@ -152,6 +159,7 @@ def non_proc_fields_for(parent, nesting) def proc_fields_for(parent, nesting) return [] unless parent + fields = (parent.children || []).select { |field| field.value.is_a?(Proc) } if nesting.zero? && @fields.present? @@ -173,7 +181,7 @@ def source_for(proc, nesting) if proc.arity.zero? source = replace_self(source, :"object#{nesting}") source = replace_send(source, :"object#{nesting}") - elsif proc.arity < 0 + elsif proc.arity.negative? raise "Splat arguments are unsupported by witchcraft:\n`#{proc.source}" else (nesting + 1).times do |n| @@ -192,6 +200,7 @@ def source_for(proc, nesting) def exctract_lambdas(node) return unless node.is_a?(Parser::AST::Node) + if node.type == :block && node.children[0].type == :send && node.children[0].to_a == [nil, :lambda] [node.children[2]] else @@ -253,6 +262,7 @@ def replace_local(node, variable, local_index) def binding_variable_list(node) return unless node.is_a?(Parser::AST::Node) + if node.type == :send && node.children[0].nil? node.children[1] else diff --git a/lib/generators/chewy/install_generator.rb b/lib/generators/chewy/install_generator.rb index 3c144f6de..be513b377 100644 --- a/lib/generators/chewy/install_generator.rb +++ b/lib/generators/chewy/install_generator.rb @@ -1,7 +1,7 @@ module Chewy module Generators class InstallGenerator < Rails::Generators::Base - source_root File.expand_path('../../templates', __FILE__) + source_root File.expand_path('../templates', __dir__) def copy_configuration template 'chewy.yml', 'config/chewy.yml' diff --git a/lib/tasks/chewy.rake b/lib/tasks/chewy.rake index 9a0c4ea76..28337db6d 100644 --- a/lib/tasks/chewy.rake +++ b/lib/tasks/chewy.rake @@ -99,7 +99,7 @@ namespace :chewy do else timestamp, retries = params time = Time.at(timestamp.to_i) - Chewy::Journal.new.apply(time, retries: (retries.to_i if retries)) + Chewy::Journal.new.apply(time, retries: retries.to_i) end end end diff --git a/spec/chewy/fields/base_spec.rb b/spec/chewy/fields/base_spec.rb index 8240c0e33..ed8ce301e 100644 --- a/spec/chewy/fields/base_spec.rb +++ b/spec/chewy/fields/base_spec.rb @@ -10,8 +10,12 @@ specify { expect(field.compose(double(value: 'hello'))).to eq(name: 'hello') } specify { expect(field.compose(double(value: %w[hello world]))).to eq(name: %w[hello world]) } - specify { expect(described_class.new(:name, value: :last_name).compose(double(last_name: 'hello'))).to eq(name: 'hello') } - specify { expect(described_class.new(:name, value: :last_name).compose('last_name' => 'hello')).to eq(name: 'hello') } + specify do + expect(described_class.new(:name, value: :last_name).compose(double(last_name: 'hello'))).to eq(name: 'hello') + end + specify do + expect(described_class.new(:name, value: :last_name).compose('last_name' => 'hello')).to eq(name: 'hello') + end specify { expect(described_class.new(:name).compose(double(name: 'hello'))).to eq(name: 'hello') } specify { expect(described_class.new(:false_value).compose(false_value: false)).to eq(false_value: false) } specify { expect(described_class.new(:true_value).compose(true_value: true)).to eq(true_value: true) } @@ -40,9 +44,24 @@ end context 'parent objects' do - let!(:country) { described_class.new(:name, value: ->(country, crutches) { country.cities.map { |city| double(districts: city.districts, name: crutches.city_name) } }) } - let!(:city) { described_class.new(:name, value: ->(city, country, crutches) { city.districts.map { |district| [district, country.name, crutches.suffix] } }) } - let!(:district) { described_class.new(:name, value: ->(district, city, country, crutches) { [district, city.name, country.name, crutches] }) } + let!(:country) do + described_class.new(:name, value: lambda { |country, crutches| + country.cities.map do |city| + double(districts: city.districts, name: crutches.city_name) + end + }) + end + let!(:city) do + described_class.new(:name, value: lambda { |city, country, crutches| + city.districts.map do |district| + [district, country.name, crutches.suffix] + end + }) + end + let(:district_value) { ->(district, city, country, crutches) { [district, city.name, country.name, crutches] } } + let!(:district) do + described_class.new(:name, value: district_value) + end let(:crutches) { double(suffix: 'suffix', city_name: 'Bangkok') } before do @@ -180,82 +199,110 @@ end end - # rubocop:disable Style/BracesAroundHashParameters specify do - expect(EventsIndex::Event.root.compose({ - id: 1, category: {id: 2, licenses: {id: 3, name: 'Name'}} - })).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}) + expect( + EventsIndex::Event.root.compose({id: 1, category: {id: 2, licenses: {id: 3, name: 'Name'}}}) + ).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}) end specify do - expect(EventsIndex::Event.root.compose({id: 1, category: [ - {id: 2, 'licenses' => {id: 3, name: 'Name1'}}, - {id: 4, licenses: nil} - ]})).to eq('id' => 1, 'category' => [ + expect( + EventsIndex::Event.root.compose({id: 1, category: [ + {id: 2, 'licenses' => {id: 3, name: 'Name1'}}, + {id: 4, licenses: nil} + ]}) + ).to eq('id' => 1, 'category' => [ {'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name1'}}, {'id' => 4, 'licenses' => nil.as_json} ]) end specify do - expect(EventsIndex::Event.root.compose({'id' => 1, category: {id: 2, licenses: [ - {id: 3, name: 'Name1'}, {id: 4, name: 'Name2'} - ]}})).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => [ - {'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'} - ]}) + expect( + EventsIndex::Event.root.compose({ + 'id' => 1, + category: { + id: 2, licenses: [ + {id: 3, name: 'Name1'}, + {id: 4, name: 'Name2'} + ] + } + }) + ).to eq( + 'id' => 1, + 'category' => { + 'id' => 2, + 'licenses' => [ + {'id' => 3, 'name' => 'Name1'}, + {'id' => 4, 'name' => 'Name2'} + ] + } + ) end specify do - expect(EventsIndex::Event.root.compose({id: 1, category: [ - {id: 2, licenses: [ - {id: 3, 'name' => 'Name1'}, {id: 4, name: 'Name2'} - ]}, - {id: 5, licenses: []} - ]})).to eq('id' => 1, 'category' => [ - {'id' => 2, 'licenses' => [ - {'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'} - ]}, - {'id' => 5, 'licenses' => []} - ]) + expect( + EventsIndex::Event.root.compose({id: 1, category: [ + {id: 2, licenses: [ + {id: 3, 'name' => 'Name1'}, {id: 4, name: 'Name2'} + ]}, + {id: 5, licenses: []} + ]}) + ).to eq( + 'id' => 1, + 'category' => [ + {'id' => 2, 'licenses' => [ + {'id' => 3, 'name' => 'Name1'}, + {'id' => 4, 'name' => 'Name2'} + ]}, + {'id' => 5, 'licenses' => []} + ] + ) end - # rubocop:enable Style/BracesAroundHashParameters - specify do - expect(EventsIndex::Event.root.compose( - double(id: 1, category: double(id: 2, licenses: double(id: 3, name: 'Name'))) - )).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}) + expect( + EventsIndex::Event.root.compose(double(id: 1, category: double(id: 2, licenses: double(id: 3, name: 'Name')))) + ).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}) end specify do - expect(EventsIndex::Event.root.compose(double(id: 1, category: [ - double(id: 2, licenses: double(id: 3, name: 'Name1')), - double(id: 4, licenses: nil) - ]))).to eq('id' => 1, 'category' => [ + expect( + EventsIndex::Event.root.compose(double(id: 1, category: [ + double(id: 2, licenses: double(id: 3, name: 'Name1')), + double(id: 4, licenses: nil) + ])) + ).to eq('id' => 1, 'category' => [ {'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name1'}}, {'id' => 4, 'licenses' => nil.as_json} ]) end specify do - expect(EventsIndex::Event.root.compose(double(id: 1, category: double(id: 2, licenses: [ - double(id: 3, name: 'Name1'), double(id: 4, name: 'Name2') - ])))).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => [ + expect( + EventsIndex::Event.root.compose(double(id: 1, category: double(id: 2, licenses: [ + double(id: 3, name: 'Name1'), double(id: 4, name: 'Name2') + ]))) + ).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => [ {'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'} ]}) end specify do - expect(EventsIndex::Event.root.compose(double(id: 1, category: [ - double(id: 2, licenses: [ - double(id: 3, name: 'Name1'), double(id: 4, name: 'Name2') - ]), - double(id: 5, licenses: []) - ]))).to eq('id' => 1, 'category' => [ - {'id' => 2, 'licenses' => [ - {'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'} - ]}, - {'id' => 5, 'licenses' => []} - ]) + expect( + EventsIndex::Event.root.compose(double(id: 1, category: [ + double(id: 2, licenses: [ + double(id: 3, name: 'Name1'), double(id: 4, name: 'Name2') + ]), + double(id: 5, licenses: []) + ])) + ).to eq( + 'id' => 1, 'category' => [ + {'id' => 2, 'licenses' => [ + {'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'} + ]}, + {'id' => 5, 'licenses' => []} + ] + ) end end @@ -276,9 +323,17 @@ end specify do - expect(EventsIndex::Event.root.compose( - double(id: 1, categories: double(id: 2, license: double(id: 3, name: 'Name'))) - )).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}) + expect( + EventsIndex::Event.root.compose( + double( + id: 1, categories: double( + id: 2, license: double( + id: 3, name: 'Name' + ) + ) + ) + ) + ).to eq('id' => 1, 'category' => {'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}) end end @@ -311,9 +366,15 @@ end specify do - expect(EventsIndex::Event.root.compose( - double(id: 1, name: 'Jonny', category: double(id: 2, as_json: {'name' => 'Borogoves'})) - )).to eq( + expect( + EventsIndex::Event.root.compose( + double( + id: 1, name: 'Jonny', category: double( + id: 2, as_json: {'name' => 'Borogoves'} + ) + ) + ) + ).to eq( 'id' => 1, 'name' => 'Jonny', 'category' => {'name' => 'Borogoves'} @@ -321,12 +382,14 @@ end specify do - expect(EventsIndex::Event.root.compose( - double(id: 1, name: 'Jonny', category: [ - double(id: 2, as_json: {'name' => 'Borogoves1'}), - double(id: 3, as_json: {'name' => 'Borogoves2'}) - ]) - )).to eq( + expect( + EventsIndex::Event.root.compose( + double(id: 1, name: 'Jonny', category: [ + double(id: 2, as_json: {'name' => 'Borogoves1'}), + double(id: 3, as_json: {'name' => 'Borogoves2'}) + ]) + ) + ).to eq( 'id' => 1, 'name' => 'Jonny', 'category' => [ @@ -405,9 +468,9 @@ end specify do - expect(CitiesIndex::City.root.compose( - City.create!(id: 1, country: Country.create!(id: 1, name: 'Country')) - )).to eq('id' => 1, 'country' => {'id' => 1, 'name' => 'Country'}) + expect( + CitiesIndex::City.root.compose(City.create!(id: 1, country: Country.create!(id: 1, name: 'Country'))) + ).to eq('id' => 1, 'country' => {'id' => 1, 'name' => 'Country'}) end end end diff --git a/spec/chewy/fields/root_spec.rb b/spec/chewy/fields/root_spec.rb index 6bf1dbeca..dc6bfb3c7 100644 --- a/spec/chewy/fields/root_spec.rb +++ b/spec/chewy/fields/root_spec.rb @@ -87,7 +87,7 @@ before do stub_index(:places) do define_type :city do - root value: ->(o) { {name: o.name + 'Modified', rating: o.rating.next} } + root value: ->(o) { {name: "#{o.name}Modified", rating: o.rating.next} } end end end @@ -109,8 +109,8 @@ before do stub_index(:places) do define_type :city do - root value: ->(o) { {name: o.name + 'Modified', rating: o.rating.next} } do - field :name, value: ->(o) { o[:name] + 'Modified' } + root value: ->(o) { {name: "#{o.name}Modified", rating: o.rating.next} } do + field :name, value: ->(o) { "#{o[:name]}Modified" } field :rating end end diff --git a/spec/chewy/fields/time_fields_spec.rb b/spec/chewy/fields/time_fields_spec.rb index c012d023d..395033f34 100644 --- a/spec/chewy/fields/time_fields_spec.rb +++ b/spec/chewy/fields/time_fields_spec.rb @@ -24,5 +24,7 @@ specify { expect(PostsIndex.total).to eq(3) } specify { expect(PostsIndex.filter(range: {published_at: {gte: range.min, lte: range.max}}).size).to eq(1) } - specify { expect(PostsIndex.filter(range: {published_at: {gt: range.min.utc, lt: (range.max + 1.hour).utc}}).size).to eq(2) } + specify do + expect(PostsIndex.filter(range: {published_at: {gt: range.min.utc, lt: (range.max + 1.hour).utc}}).size).to eq(2) + end end diff --git a/spec/chewy/index/actions_spec.rb b/spec/chewy/index/actions_spec.rb index d8c50ac12..e020da9f0 100644 --- a/spec/chewy/index/actions_spec.rb +++ b/spec/chewy/index/actions_spec.rb @@ -76,9 +76,15 @@ end specify do - expect { DummiesIndex.create! }.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/already exists.*dummies/) + expect do + DummiesIndex.create! + end.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/already exists.*dummies/) + end + specify do + expect do + DummiesIndex.create!('2013') + end.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/Invalid alias name \[dummies\]/) end - specify { expect { DummiesIndex.create!('2013') }.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/Invalid alias name \[dummies\]/) } end context do @@ -92,7 +98,9 @@ specify { expect(DummiesIndex.aliases).to eq(['dummies']) } specify { expect(DummiesIndex.indexes).to eq(['dummies_2013']) } specify do - expect { DummiesIndex.create!('2013') }.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/already exists.*dummies_2013/) + expect do + DummiesIndex.create!('2013') + end.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/already exists.*dummies_2013/) end specify { expect(DummiesIndex.create!('2014')['acknowledged']).to eq(true) } @@ -183,7 +191,11 @@ describe '.delete!' do specify { expect { DummiesIndex.delete! }.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound) } - specify { expect { DummiesIndex.delete!('2013') }.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound) } + specify do + expect do + DummiesIndex.delete!('2013') + end.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound) + end context do before do @@ -511,9 +523,11 @@ end specify do - expect(CitiesIndex.client.indices).to receive(:put_settings).with(index: name, body: before_import_body).once + expect(CitiesIndex.client.indices) + .to receive(:put_settings).with(index: name, body: before_import_body).once expect(CitiesIndex.client.indices).to receive(:put_settings).with(index: name, body: after_import_body).once - expect(CitiesIndex).to receive(:import).with(suffix: suffix, journal: false, refresh: false).and_call_original + expect(CitiesIndex) + .to receive(:import).with(suffix: suffix, journal: false, refresh: false).and_call_original expect(CitiesIndex.reset!(suffix)).to eq(true) end @@ -654,7 +668,10 @@ end specify do - expect(CitiesIndex::City).to receive(:import).with(suffix: 'suffix', parallel: true, journal: false, refresh: true).once.and_return(true) + expect(CitiesIndex::City) + .to receive(:import) + .with(suffix: 'suffix', parallel: true, journal: false, refresh: true) + .once.and_return(true) expect(CitiesIndex.reset!('suffix', parallel: true)).to eq(true) end end diff --git a/spec/chewy/index/settings_spec.rb b/spec/chewy/index/settings_spec.rb index 17dc4b777..723ab7bf5 100644 --- a/spec/chewy/index/settings_spec.rb +++ b/spec/chewy/index/settings_spec.rb @@ -118,7 +118,9 @@ def self.synonyms end context do - before { allow(Chewy).to receive_messages(configuration: {index: {number_of_shards: 7, number_of_replicas: 2}}) } + before do + allow(Chewy).to receive_messages(configuration: {index: {number_of_shards: 7, number_of_replicas: 2}}) + end specify do expect(described_class.new.to_hash) diff --git a/spec/chewy/index_spec.rb b/spec/chewy/index_spec.rb index 4bcb57b93..964ca31b3 100644 --- a/spec/chewy/index_spec.rb +++ b/spec/chewy/index_spec.rb @@ -35,8 +35,10 @@ end specify do - expect { CitiesIndex.import city: cities.first, country: countries.last }.to update_index(CitiesIndex).and_reindex(cities.first).only - expect { CountriesIndex.import city: cities.first, country: countries.last }.to update_index(CountriesIndex).and_reindex(countries.last).only + expect { CitiesIndex.import city: cities.first, country: countries.last } + .to update_index(CitiesIndex).and_reindex(cities.first).only + expect { CountriesIndex.import city: cities.first, country: countries.last } + .to update_index(CountriesIndex).and_reindex(countries.last).only end specify do @@ -64,10 +66,18 @@ specify { expect(stub_const('DeveloperIndex', Class.new(Chewy::Index)).index_name).to eq('developer') } specify { expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name).to eq('developers') } - specify { expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name(suffix: '')).to eq('developers') } - specify { expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name(suffix: '2013')).to eq('developers_2013') } - specify { expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name(prefix: '')).to eq('developers') } - specify { expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name(prefix: 'test')).to eq('test_developers') } + specify do + expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name(suffix: '')).to eq('developers') + end + specify do + expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name(suffix: '2013')).to eq('developers_2013') + end + specify do + expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name(prefix: '')).to eq('developers') + end + specify do + expect(stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name(prefix: 'test')).to eq('test_developers') + end context do before { allow(Chewy).to receive_messages(configuration: {prefix: 'testing'}) } @@ -156,7 +166,11 @@ class DummyCityIndex2 < Chewy::Index Chewy.filter :names_nysiis, type: 'phonetic', encoder: 'nysiis', replace: false end - let(:documents) { stub_index(:documents) { settings analysis: {analyzer: [:name, :phone, {sorted: {option: :baz}}]} } } + let(:documents) do + stub_index(:documents) do + settings analysis: {analyzer: [:name, :phone, {sorted: {option: :baz}}]} + end + end specify { expect { documents.settings_hash }.to_not change(documents._settings, :inspect) } specify do @@ -220,7 +234,11 @@ def self.by_id; end before { allow(Chewy).to receive_messages(config: Chewy::Config.send(:new)) } specify { expect(stub_index(:documents).settings_hash).to eq({}) } - specify { expect(stub_index(:documents) { settings number_of_shards: 1 }.settings_hash).to eq(settings: {number_of_shards: 1}) } + specify do + expect(stub_index(:documents) do + settings number_of_shards: 1 + end.settings_hash).to eq(settings: {number_of_shards: 1}) + end end describe '.mappings_hash' do @@ -239,7 +257,11 @@ def self.by_id; end before { allow(Chewy).to receive_messages(config: Chewy::Config.send(:new)) } specify { expect(stub_index(:documents).specification_hash).to eq({}) } - specify { expect(stub_index(:documents) { settings number_of_shards: 1 }.specification_hash.keys).to eq([:settings]) } + specify do + expect(stub_index(:documents) do + settings number_of_shards: 1 + end.specification_hash.keys).to eq([:settings]) + end specify do expect(stub_index(:documents) do define_type :document do diff --git a/spec/chewy/rspec/update_index_spec.rb b/spec/chewy/rspec/update_index_spec.rb index dc919c072..b1cea443f 100644 --- a/spec/chewy/rspec/update_index_spec.rb +++ b/spec/chewy/rspec/update_index_spec.rb @@ -74,15 +74,13 @@ expect do expect { DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {index: {_id: 41, data: {}}}] } .to update_index(DummiesIndex).and_reindex(41).only - end - .to fail_matching 'to update documents ["41"] only, but ["42"] was updated also' + end.to fail_matching 'to update documents ["41"] only, but ["42"] was updated also' end specify do expect do expect { DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {index: {_id: 41, data: {}}}] } .to update_index(DummiesIndex).and_reindex(41, times: 2).only - end - .to fail_matching 'to update documents ["41"] only, but ["42"] was updated also' + end.to fail_matching 'to update documents ["41"] only, but ["42"] was updated also' end specify do @@ -93,44 +91,41 @@ expect do expect { DummiesIndex::Dummy.bulk body: [{delete: {_id: 42}}, {delete: {_id: 41}}] } .to update_index(DummiesIndex).and_delete(41).only - end - .to fail_matching 'to delete documents ["41"] only, but ["42"] was deleted also' + end.to fail_matching 'to delete documents ["41"] only, but ["42"] was deleted also' end specify do expect do expect { DummiesIndex::Dummy.bulk body: [{delete: {_id: 42}}, {delete: {_id: 41}}] } .to update_index(DummiesIndex).and_delete(41, times: 2).only - end - .to fail_matching 'to delete documents ["41"] only, but ["42"] was deleted also' + end.to fail_matching 'to delete documents ["41"] only, but ["42"] was deleted also' end specify do expect do expect { DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {delete: {_id: 41}}] } .to update_index(DummiesIndex).and_reindex(42).only - end - .to fail_matching 'to update documents ["42"] only, but ["41"] was deleted also' + end.to fail_matching 'to update documents ["42"] only, but ["41"] was deleted also' end specify do expect do - expect { DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {index: {_id: 43, data: {}}}, {delete: {_id: 41}}] } - .to update_index(DummiesIndex).and_reindex(42).only - end - .to fail_matching 'to update documents ["42"] only, but ["43"] was updated and ["41"] was deleted also' + expect do + DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {index: {_id: 43, data: {}}}, + {delete: {_id: 41}}] + end.to update_index(DummiesIndex).and_reindex(42).only + end.to fail_matching 'to update documents ["42"] only, but ["43"] was updated and ["41"] was deleted also' end specify do expect do expect { DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {delete: {_id: 41}}] } .to update_index(DummiesIndex).and_delete(41).only - end - .to fail_matching 'to delete documents ["41"] only, but ["42"] was updated also' + end.to fail_matching 'to delete documents ["41"] only, but ["42"] was updated also' end specify do expect do - expect { DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {delete: {_id: 41}}, {delete: {_id: 43}}] } - .to update_index(DummiesIndex).and_delete(41).only - end - .to fail_matching 'to delete documents ["41"] only, but ["42"] was updated and ["43"] was deleted also' + expect do + DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {delete: {_id: 41}}, {delete: {_id: 43}}] + end.to update_index(DummiesIndex).and_delete(41).only + end.to fail_matching 'to delete documents ["41"] only, but ["42"] was updated and ["43"] was deleted also' end end @@ -166,7 +161,8 @@ expect do expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {index: {_id: 43, data: {}}}] - end.to update_index(DummiesIndex).and_reindex(44, double(id: 47)) end + end.to update_index(DummiesIndex).and_reindex(44, double(id: 47)) + end end specify { expectation.to fail_matching('Expected document with id `44` to be reindexed, but it was not') } @@ -178,14 +174,16 @@ expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {index: {_id: 43, data: {}}}] DummiesIndex::Dummy.bulk body: [{index: {_id: 43, data: {}}}, {index: {_id: 44, data: {}}}] - end.to update_index(DummiesIndex).and_reindex(42, 44, times: 1).and_reindex(43, times: 2) end + end.to update_index(DummiesIndex).and_reindex(42, 44, times: 1).and_reindex(43, times: 2) + end specify do expect do expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 43, data: {a: '1'}}}] end.to update_index(DummiesIndex).and_reindex(42, times: 3) - end.to fail_matching('Expected document with id `42` to be reindexed, but it was not') end + end.to fail_matching('Expected document with id `42` to be reindexed, but it was not') + end context do let(:expectation) do @@ -193,7 +191,8 @@ expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {}}}, {index: {_id: 43, data: {}}}] DummiesIndex::Dummy.bulk body: [{index: {_id: 43, data: {}}}, {index: {_id: 44, data: {}}}] - end.to update_index(DummiesIndex).and_reindex(42, times: 3).and_reindex(44, 43, times: 4) end + end.to update_index(DummiesIndex).and_reindex(42, times: 3).and_reindex(44, 43, times: 4) + end end specify { expectation.to fail_matching 'Expected document with id `44` to be reindexed' } @@ -207,19 +206,22 @@ specify do expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {a: '1'}}}, {index: {_id: 42, data: {'a' => 2}}}] - end.to update_index(DummiesIndex).and_reindex(42, with: {a: 2}) end + end.to update_index(DummiesIndex).and_reindex(42, with: {a: 2}) + end specify do expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: {a: '1'}}}, {index: {_id: 42, data: {'b' => 2}}}] - end.to update_index(DummiesIndex).and_reindex(42, with: {a: '1', b: 2}) end + end.to update_index(DummiesIndex).and_reindex(42, with: {a: '1', b: 2}) + end specify do expect do expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 43, data: {a: '1'}}}] end.to update_index(DummiesIndex).and_reindex(42, with: {a: 1}) - end.to fail_matching('Expected document with id `42` to be reindexed, but it was not') end + end.to fail_matching('Expected document with id `42` to be reindexed, but it was not') + end [ [{a: %w[one two]}, {a: %w[one two]}], @@ -231,7 +233,8 @@ specify do expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: data}}] - end.to update_index(DummiesIndex).and_reindex(42, with: with) end + end.to update_index(DummiesIndex).and_reindex(42, with: with) + end end [ @@ -246,7 +249,8 @@ expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 42, data: data}}] end.to update_index(DummiesIndex).and_reindex(42, with: with) - end.to fail_matching('Expected document with id `42` to be reindexed') end + end.to fail_matching('Expected document with id `42` to be reindexed') + end end context do @@ -254,7 +258,8 @@ expect do expect do DummiesIndex::Dummy.bulk body: [{index: {_id: 43, data: {a: '1'}}}, {index: {_id: 42, data: {'a' => 2}}}] - end.to update_index(DummiesIndex).and_reindex(43, times: 2, with: {a: 2}) end + end.to update_index(DummiesIndex).and_reindex(43, times: 2, with: {a: 2}) + end end specify { expectation.to fail_matching 'Expected document with id `43` to be reindexed' } diff --git a/spec/chewy/search/pagination/will_paginate_examples.rb b/spec/chewy/search/pagination/will_paginate_examples.rb index 5ea3544e9..ab3fc66ed 100644 --- a/spec/chewy/search/pagination/will_paginate_examples.rb +++ b/spec/chewy/search/pagination/will_paginate_examples.rb @@ -35,8 +35,16 @@ end describe '#paginate' do - specify { expect(search.paginate(page: 2, per_page: 4).map { |e| e.attributes.except(*except_fields) }).to eq(data[4..7]) } - specify { expect(search.paginate(per_page: 2, page: 3).page(3).map { |e| e.attributes.except(*except_fields) }).to eq(data[4..5]) } + specify do + expect(search.paginate(page: 2, per_page: 4).map do |e| + e.attributes.except(*except_fields) + end).to eq(data[4..7]) + end + specify do + expect(search.paginate(per_page: 2, page: 3).page(3).map do |e| + e.attributes.except(*except_fields) + end).to eq(data[4..5]) + end specify { expect(search.paginate(per_page: 5).map { |e| e.attributes.except(*except_fields) }).to eq(data[0..4]) } specify { expect(search.paginate(per_page: 4).map { |e| e.attributes.except(*except_fields) }).to eq(data[0..3]) } end diff --git a/spec/chewy/search/parameters/order_spec.rb b/spec/chewy/search/parameters/order_spec.rb index ab546710d..fc556b352 100644 --- a/spec/chewy/search/parameters/order_spec.rb +++ b/spec/chewy/search/parameters/order_spec.rb @@ -10,7 +10,7 @@ specify { expect(described_class.new(42).value).to eq('42' => nil) } specify { expect(described_class.new([42, 43]).value).to eq('42' => nil, '43' => nil) } specify { expect(described_class.new(a: 1).value).to eq('a' => 1) } - specify { expect(described_class.new(['', 43, a: 1]).value).to eq('a' => 1, '43' => nil) } + specify { expect(described_class.new(['', 43, {a: 1}]).value).to eq('a' => 1, '43' => nil) } end describe '#replace!' do diff --git a/spec/chewy/search/parameters/query_storage_examples.rb b/spec/chewy/search/parameters/query_storage_examples.rb index e02284c55..6b2c4f66e 100644 --- a/spec/chewy/search/parameters/query_storage_examples.rb +++ b/spec/chewy/search/parameters/query_storage_examples.rb @@ -4,19 +4,46 @@ subject { described_class.new(must: {foo: 'bar'}, should: {moo: 'baz'}) } describe '#initialize' do - specify { expect(described_class.new.value.to_h).to eq(must: [], should: [], must_not: [], minimum_should_match: nil) } - specify { expect(described_class.new(nil).value.to_h).to eq(must: [], should: [], must_not: [], minimum_should_match: nil) } - specify { expect(described_class.new(foobar: {}).value.to_h).to eq(must: [{foobar: {}}], should: [], must_not: [], minimum_should_match: nil) } - specify { expect(described_class.new(must: {}, should: {}, must_not: {}).value.to_h).to eq(must: [], should: [], must_not: [], minimum_should_match: nil) } + specify do + expect(described_class.new.value.to_h) + .to eq(must: [], should: [], must_not: [], minimum_should_match: nil) + end + specify do + expect(described_class.new(nil).value.to_h) + .to eq(must: [], should: [], must_not: [], minimum_should_match: nil) + end + specify do + expect(described_class.new(foobar: {}).value.to_h) + .to eq(must: [{foobar: {}}], should: [], must_not: [], minimum_should_match: nil) + end + specify do + expect(described_class.new(must: {}, should: {}, must_not: {}).value.to_h) + .to eq(must: [], should: [], must_not: [], minimum_should_match: nil) + end specify do expect(described_class.new(must: {foo: 'bar'}, should: {foo: 'bar'}, foobar: {}).value.to_h) .to eq(must: [{foo: 'bar'}], should: [{foo: 'bar'}], must_not: [], minimum_should_match: nil) end - specify { expect(subject.value.to_h).to eq(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) } - specify { expect(described_class.new(proc { match foo: 'bar' }).value.to_h).to eq(must: [match: {foo: 'bar'}], should: [], must_not: [], minimum_should_match: nil) } - specify { expect(described_class.new(must: proc { match foo: 'bar' }).value.to_h).to eq(must: [match: {foo: 'bar'}], should: [], must_not: [], minimum_should_match: nil) } - specify { expect(described_class.new(minimum_should_match: 3).value.to_h).to eq(must: [], should: [], must_not: [], minimum_should_match: 3) } - specify { expect(described_class.new(must: {foo: 'bar'}, minimum_should_match: 3).value.to_h).to eq(must: [{foo: 'bar'}], should: [], must_not: [], minimum_should_match: 3) } + specify do + expect(subject.value.to_h) + .to eq(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) + end + specify do + expect(described_class.new(proc { match foo: 'bar' }).value.to_h) + .to eq(must: [match: {foo: 'bar'}], should: [], must_not: [], minimum_should_match: nil) + end + specify do + expect(described_class.new(must: proc { match foo: 'bar' }).value.to_h) + .to eq(must: [match: {foo: 'bar'}], should: [], must_not: [], minimum_should_match: nil) + end + specify do + expect(described_class.new(minimum_should_match: 3).value.to_h) + .to eq(must: [], should: [], must_not: [], minimum_should_match: 3) + end + specify do + expect(described_class.new(must: {foo: 'bar'}, minimum_should_match: 3).value.to_h) + .to eq(must: [{foo: 'bar'}], should: [], must_not: [], minimum_should_match: 3) + end specify do expect(described_class.new(must: [proc { match foo: 'bar' }, {moo: 'baz'}]).value.to_h) .to eq(must: [{match: {foo: 'bar'}}, {moo: 'baz'}], should: [], must_not: [], minimum_should_match: nil) @@ -73,14 +100,16 @@ expect { subject.and(moo: 'baz') } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, {moo: 'baz'}], should: [], must_not: [], minimum_should_match: nil) + .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, + {moo: 'baz'}], should: [], must_not: [], minimum_should_match: nil) end specify do expect { subject.and([{moo: 'baz'}, {doo: 'scooby'}]) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, bool: {must: [{moo: 'baz'}, {doo: 'scooby'}]}], should: [], must_not: [], minimum_should_match: nil) + .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, + bool: {must: [{moo: 'baz'}, {doo: 'scooby'}]}], should: [], must_not: [], minimum_should_match: nil) end specify do @@ -93,7 +122,8 @@ expect { subject.and(should: {foo: 'bar'}) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, {bool: {should: {foo: 'bar'}}}], should: [], must_not: [], minimum_should_match: nil) + .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, + {bool: {should: {foo: 'bar'}}}], should: [], must_not: [], minimum_should_match: nil) end context do @@ -113,14 +143,16 @@ expect { subject.or(moo: 'baz') } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [], should: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, {moo: 'baz'}], must_not: [], minimum_should_match: nil) + .to(must: [], should: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, + {moo: 'baz'}], must_not: [], minimum_should_match: nil) end specify do expect { subject.or([{moo: 'baz'}, {doo: 'scooby'}]) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [], should: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, bool: {must: [{moo: 'baz'}, {doo: 'scooby'}]}], must_not: [], minimum_should_match: nil) + .to(must: [], should: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, + bool: {must: [{moo: 'baz'}, {doo: 'scooby'}]}], must_not: [], minimum_should_match: nil) end specify do @@ -133,7 +165,8 @@ expect { subject.or(should: {foo: 'bar'}) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [], should: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, {bool: {should: {foo: 'bar'}}}], must_not: [], minimum_should_match: nil) + .to(must: [], should: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, + {bool: {should: {foo: 'bar'}}}], must_not: [], minimum_should_match: nil) end context do @@ -160,7 +193,12 @@ expect { subject.not([{moo: 'baz'}, {doo: 'scooby'}]) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [{bool: {must: [{moo: 'baz'}, {doo: 'scooby'}]}}], minimum_should_match: nil) + .to( + must: [{foo: 'bar'}], + should: [{moo: 'baz'}], + must_not: [{bool: {must: [{moo: 'baz'}, {doo: 'scooby'}]}}], + minimum_should_match: nil + ) end specify do @@ -173,7 +211,11 @@ expect { subject.not(should: {foo: 'bar'}) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [{bool: {should: {foo: 'bar'}}}], minimum_should_match: nil) + .to( + must: [{foo: 'bar'}], should: [{moo: 'baz'}], + must_not: [{bool: {should: {foo: 'bar'}}}], + minimum_should_match: nil + ) end context do @@ -223,7 +265,8 @@ expect { subject.update!(must: proc { match foo: 'bar' }) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{foo: 'bar'}, {match: {foo: 'bar'}}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) + .to(must: [{foo: 'bar'}, + {match: {foo: 'bar'}}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) end specify do @@ -237,7 +280,8 @@ expect { subject.update!(foobar: {foo: 'bar'}) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{foo: 'bar'}, {foobar: {foo: 'bar'}}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) + .to(must: [{foo: 'bar'}, + {foobar: {foo: 'bar'}}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) end specify do @@ -279,7 +323,8 @@ expect { subject.merge!(described_class.new(moo: 'baz')) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, {moo: 'baz'}], should: [], must_not: [], minimum_should_match: nil) + .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, + {moo: 'baz'}], should: [], must_not: [], minimum_should_match: nil) end specify do @@ -292,7 +337,8 @@ expect { subject.merge!(described_class.new(should: {foo: 'bar'})) } .to change { subject.value.to_h } .from(must: [{foo: 'bar'}], should: [{moo: 'baz'}], must_not: [], minimum_should_match: nil) - .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, {bool: {should: {foo: 'bar'}}}], should: [], must_not: [], minimum_should_match: nil) + .to(must: [{bool: {must: {foo: 'bar'}, should: {moo: 'baz'}}}, + {bool: {should: {foo: 'bar'}}}], should: [], must_not: [], minimum_should_match: nil) end context do diff --git a/spec/chewy/search/parameters/search_after_spec.rb b/spec/chewy/search/parameters/search_after_spec.rb index 5461808d0..602af6e1e 100644 --- a/spec/chewy/search/parameters/search_after_spec.rb +++ b/spec/chewy/search/parameters/search_after_spec.rb @@ -20,7 +20,10 @@ end describe '#merge!' do - specify { expect { subject.merge!(described_class.new(:baz)) }.to change { subject.value }.from([:foo, 42]).to([:baz]) } + specify do + expect { subject.merge!(described_class.new(:baz)) } + .to change { subject.value }.from([:foo, 42]).to([:baz]) + end specify { expect { subject.merge!(described_class.new) }.not_to change { subject.value }.from([:foo, 42]) } end diff --git a/spec/chewy/search/parameters/source_spec.rb b/spec/chewy/search/parameters/source_spec.rb index 7232b1106..c2550a216 100644 --- a/spec/chewy/search/parameters/source_spec.rb +++ b/spec/chewy/search/parameters/source_spec.rb @@ -12,8 +12,14 @@ specify { expect(described_class.new(true).value).to eq(includes: [], excludes: [], enabled: true) } specify { expect(described_class.new(a: 1).value).to eq(includes: [], excludes: [], enabled: true) } specify { expect(described_class.new(includes: :foo).value).to eq(includes: %w[foo], excludes: [], enabled: true) } - specify { expect(described_class.new(includes: :foo, excludes: 42).value).to eq(includes: %w[foo], excludes: %w[42], enabled: true) } - specify { expect(described_class.new(includes: :foo, excludes: 42, enabled: false).value).to eq(includes: %w[foo], excludes: %w[42], enabled: true) } + specify do + expect(described_class.new(includes: :foo, excludes: 42).value) + .to eq(includes: %w[foo], excludes: %w[42], enabled: true) + end + specify do + expect(described_class.new(includes: :foo, excludes: 42, enabled: false).value) + .to eq(includes: %w[foo], excludes: %w[42], enabled: true) + end end describe '#replace!' do diff --git a/spec/chewy/search/parameters_spec.rb b/spec/chewy/search/parameters_spec.rb index 8c9a0d5af..f14fcf9b2 100644 --- a/spec/chewy/search/parameters_spec.rb +++ b/spec/chewy/search/parameters_spec.rb @@ -55,7 +55,10 @@ subject { described_class.new(limit: 10, offset: 20, order: :foo) } specify { expect { subject.only!([:limit]) }.to change { subject.clone }.to(described_class.new(limit: 10)) } - specify { expect { subject.only!(%i[offset order]) }.to change { subject.clone }.to(described_class.new(offset: 20, order: :foo)) } + specify do + expect { subject.only!(%i[offset order]) } + .to change { subject.clone }.to(described_class.new(offset: 20, order: :foo)) + end specify { expect { subject.only!(%i[limit something]) }.to raise_error NameError } specify { expect { subject.only!([]) }.to raise_error ArgumentError } end @@ -63,8 +66,14 @@ describe '#except!' do subject { described_class.new(limit: 10, offset: 20, order: :foo) } - specify { expect { subject.except!([:limit]) }.to change { subject.clone }.to(described_class.new(offset: 20, order: :foo)) } - specify { expect { subject.except!(%i[offset order]) }.to change { subject.clone }.to(described_class.new(limit: 10)) } + specify do + expect { subject.except!([:limit]) } + .to change { subject.clone }.to(described_class.new(offset: 20, order: :foo)) + end + specify do + expect { subject.except!(%i[offset order]) } + .to change { subject.clone }.to(described_class.new(limit: 10)) + end specify { expect { subject.except!(%i[limit something]) }.to raise_error NameError } specify { expect { subject.except!([]) }.to raise_error ArgumentError } end diff --git a/spec/chewy/search/query_proxy_spec.rb b/spec/chewy/search/query_proxy_spec.rb index d396950be..f02ba24b1 100644 --- a/spec/chewy/search/query_proxy_spec.rb +++ b/spec/chewy/search/query_proxy_spec.rb @@ -8,41 +8,86 @@ describe '#must' do specify { expect { subject.must }.to raise_error ArgumentError } - specify { expect(subject.must(multi_match: {foo: 'bar'}).render[:body]).to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) } - specify { expect(subject.must { multi_match foo: 'bar' }.render[:body]).to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) } + specify do + expect(subject.must(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) + end + specify do + expect(subject.must(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) + end end describe '#should' do specify { expect { subject.should }.to raise_error ArgumentError } - specify { expect(subject.should(multi_match: {foo: 'bar'}).render[:body]).to eq(query: {bool: {must: {match: {foo: 'bar'}}, should: {multi_match: {foo: 'bar'}}}}) } - specify { expect(subject.should { multi_match foo: 'bar' }.render[:body]).to eq(query: {bool: {must: {match: {foo: 'bar'}}, should: {multi_match: {foo: 'bar'}}}}) } + specify do + expect(subject.should(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: {match: {foo: 'bar'}}, should: {multi_match: {foo: 'bar'}}}}) + end + specify do + expect(subject.should(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: {match: {foo: 'bar'}}, should: {multi_match: {foo: 'bar'}}}}) + end end describe '#must_not' do specify { expect { subject.must_not }.to raise_error ArgumentError } - specify { expect(subject.must_not(multi_match: {foo: 'bar'}).render[:body]).to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) } - specify { expect(subject.must_not { multi_match foo: 'bar' }.render[:body]).to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) } + specify do + expect(subject.must_not(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) + end + specify do + expect(subject.must_not(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) + end end describe '#and' do specify { expect { subject.and }.to raise_error ArgumentError } - specify { expect(subject.and(multi_match: {foo: 'bar'}).render[:body]).to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) } - specify { expect(subject.and { multi_match foo: 'bar' }.render[:body]).to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) } - specify { expect(subject.and(scope).render[:body]).to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {bool: {must_not: {match: {foo: 'bar'}}}}]}}) } + specify do + expect(subject.and(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) + end + specify do + expect(subject.and(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) + end + specify do + expect(subject.and(scope).render[:body]) + .to eq(query: {bool: {must: [{match: {foo: 'bar'}}, {bool: {must_not: {match: {foo: 'bar'}}}}]}}) + end end describe '#or' do specify { expect { subject.or }.to raise_error ArgumentError } - specify { expect(subject.or(multi_match: {foo: 'bar'}).render[:body]).to eq(query: {bool: {should: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) } - specify { expect(subject.or { multi_match foo: 'bar' }.render[:body]).to eq(query: {bool: {should: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) } - specify { expect(subject.or(scope).render[:body]).to eq(query: {bool: {should: [{match: {foo: 'bar'}}, {bool: {must_not: {match: {foo: 'bar'}}}}]}}) } + specify do + expect(subject.or(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {should: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) + end + specify do + expect(subject.or(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {should: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) + end + specify do + expect(subject.or(scope).render[:body]) + .to eq(query: {bool: {should: [{match: {foo: 'bar'}}, {bool: {must_not: {match: {foo: 'bar'}}}}]}}) + end end describe '#not' do specify { expect { subject.not }.to raise_error ArgumentError } - specify { expect(subject.not(multi_match: {foo: 'bar'}).render[:body]).to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) } - specify { expect(subject.not { multi_match foo: 'bar' }.render[:body]).to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) } - specify { expect(subject.not(scope).render[:body]).to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {bool: {must_not: {match: {foo: 'bar'}}}}}}) } + specify do + expect(subject.not(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) + end + specify do + expect(subject.not(multi_match: {foo: 'bar'}).render[:body]) + .to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) + end + specify do + expect(subject.not(scope).render[:body]) + .to eq(query: {bool: {must: {match: {foo: 'bar'}}, must_not: {bool: {must_not: {match: {foo: 'bar'}}}}}}) + end end describe '#minimum_should_match' do @@ -53,7 +98,10 @@ Chewy::Search::Request.new(ProductsIndex) .query.should(match: {foo: 'bar'}) end - specify { expect(subject.minimum_should_match('100%').render[:body]).to eq(query: {bool: {should: {match: {foo: 'bar'}}, minimum_should_match: '100%'}}) } + specify do + expect(subject.minimum_should_match('100%').render[:body]) + .to eq(query: {bool: {should: {match: {foo: 'bar'}}, minimum_should_match: '100%'}}) + end end context do @@ -62,7 +110,10 @@ .query.should(match: {foo: 'bar'}) .query.minimum_should_match(2) end - specify { expect(subject.minimum_should_match(nil).render[:body]).to eq(query: {bool: {should: {match: {foo: 'bar'}}}}) } + specify do + expect(subject.minimum_should_match(nil).render[:body]) + .to eq(query: {bool: {should: {match: {foo: 'bar'}}}}) + end end end end diff --git a/spec/chewy/search/request_spec.rb b/spec/chewy/search/request_spec.rb index d84a6239d..d46dc9759 100644 --- a/spec/chewy/search/request_spec.rb +++ b/spec/chewy/search/request_spec.rb @@ -31,11 +31,17 @@ specify { expect(described_class.new(ProductsIndex)).to eq(described_class.new(ProductsIndex)) } specify { expect(described_class.new(ProductsIndex)).not_to eq(described_class.new(CitiesIndex)) } specify { expect(described_class.new(ProductsIndex)).not_to eq(described_class.new(ProductsIndex, CitiesIndex)) } - specify { expect(described_class.new(CitiesIndex, ProductsIndex)).to eq(described_class.new(ProductsIndex, CitiesIndex)) } - specify { expect(described_class.new(ProductsIndex, CitiesIndex)).to eq(described_class.new(CitiesIndex, ProductsIndex)) } + specify do + expect(described_class.new(CitiesIndex, ProductsIndex)).to eq(described_class.new(ProductsIndex, CitiesIndex)) + end + specify do + expect(described_class.new(ProductsIndex, CitiesIndex)).to eq(described_class.new(CitiesIndex, ProductsIndex)) + end specify { expect(described_class.new(ProductsIndex).limit(10)).to eq(described_class.new(ProductsIndex).limit(10)) } - specify { expect(described_class.new(ProductsIndex).limit(10)).not_to eq(described_class.new(ProductsIndex).limit(20)) } + specify do + expect(described_class.new(ProductsIndex).limit(10)).not_to eq(described_class.new(ProductsIndex).limit(20)) + end specify { expect(ProductsIndex.limit(10)).to eq(ProductsIndex.limit(10)) } specify { expect(ProductsIndex.limit(10)).not_to eq(CitiesIndex.limit(10)) } @@ -64,50 +70,103 @@ %i[query post_filter].each do |name| describe "##{name}" do - specify { expect(subject.send(name, match: {foo: 'bar'}).render[:body]).to include(name => {match: {foo: 'bar'}}) } + specify do + expect(subject.send(name, match: {foo: 'bar'}).render[:body]) + .to include(name => {match: {foo: 'bar'}}) + end specify { expect(subject.send(name, nil)).to be_a described_class } - specify { expect(subject.send(name) { match foo: 'bar' }.render[:body]).to include(name => {match: {foo: 'bar'}}) } + specify do + expect(subject.send(name) { match foo: 'bar' }.render[:body]) + .to include(name => {match: {foo: 'bar'}}) + end specify do expect(subject.send(name, match: {foo: 'bar'}).send(name) { multi_match foo: 'bar' }.render[:body]) .to include(name => {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) end specify { expect { subject.send(name, match: {foo: 'bar'}) }.not_to change { subject.render } } specify do - expect(subject.send(name).should(match: {foo: 'bar'}).send(name).must_not { multi_match foo: 'bar' }.render[:body]) - .to include(name => {bool: {should: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) + expect( + subject.send(name).should(match: {foo: 'bar'}).send(name).must_not { multi_match foo: 'bar' }.render[:body] + ).to include(name => {bool: {should: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}) end context do let(:other_scope) { subject.send(name).should { multi_match foo: 'bar' }.send(name) { match foo: 'bar' } } specify do - expect(subject.send(name).not(other_scope).render[:body]) - .to include(name => {bool: {must_not: {bool: {must: {match: {foo: 'bar'}}, should: {multi_match: {foo: 'bar'}}}}}}) + expect( + subject.send(name).not(other_scope).render[:body] + ).to include( + name => { + bool: { + must_not: { + bool: { + must: {match: {foo: 'bar'}}, + should: {multi_match: {foo: 'bar'}} + } + } + } + } + ) end end end end describe '#filter' do - specify { expect(subject.filter(match: {foo: 'bar'}).render[:body]).to include(query: {bool: {filter: {match: {foo: 'bar'}}}}) } + specify do + expect(subject.filter(match: {foo: 'bar'}).render[:body]) + .to include(query: {bool: {filter: {match: {foo: 'bar'}}}}) + end specify { expect(subject.filter(nil)).to be_a described_class } - specify { expect(subject.filter { match foo: 'bar' }.render[:body]).to include(query: {bool: {filter: {match: {foo: 'bar'}}}}) } + specify do + expect(subject.filter(match: {foo: 'bar'}).render[:body]) + .to include(query: {bool: {filter: {match: {foo: 'bar'}}}}) + end specify do expect(subject.filter(match: {foo: 'bar'}).filter { multi_match foo: 'bar' }.render[:body]) .to include(query: {bool: {filter: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}}) end specify { expect { subject.filter(match: {foo: 'bar'}) }.not_to change { subject.render } } specify do - expect(subject.filter.should(match: {foo: 'bar'}).filter.must_not { multi_match foo: 'bar' }.render[:body]) - .to include(query: {bool: {filter: {bool: {should: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}}}) + expect( + subject.filter.should(match: {foo: 'bar'}).filter.must_not { multi_match foo: 'bar' }.render[:body] + ).to include( + query: { + bool: { + filter: { + bool: { + should: {match: {foo: 'bar'}}, + must_not: {multi_match: {foo: 'bar'}} + } + } + } + } + ) end context do let(:other_scope) { subject.filter.should { multi_match foo: 'bar' }.filter { match foo: 'bar' } } specify do - expect(subject.filter.not(other_scope).render[:body]) - .to include(query: {bool: {filter: {bool: {must_not: {bool: {must: {match: {foo: 'bar'}}, should: {multi_match: {foo: 'bar'}}}}}}}}) + expect( + subject.filter.not(other_scope).render[:body] + ).to include( + query: { + bool: { + filter: { + bool: { + must_not: { + bool: { + must: {match: {foo: 'bar'}}, + should: {multi_match: {foo: 'bar'}} + } + } + } + } + } + } + ) end end end @@ -175,23 +234,53 @@ specify { expect(subject.source(:foo, :bar).source(nil).render[:body]).to include(_source: %w[foo bar]) } specify { expect(subject.source(%i[foo bar]).source(nil).render[:body]).to include(_source: %w[foo bar]) } specify { expect(subject.source(excludes: :foo).render[:body]).to include(_source: {excludes: %w[foo]}) } - specify { expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body]).to include(_source: {excludes: %w[foo bar]}) } - specify { expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body]).to include(_source: {excludes: %w[foo bar]}) } - specify { expect(subject.source(excludes: :foo).source(:bar).render[:body]).to include(_source: {includes: %w[bar], excludes: %w[foo]}) } + specify do + expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body]) + .to include(_source: {excludes: %w[foo bar]}) + end + specify do + expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body]) + .to include(_source: {excludes: %w[foo bar]}) + end + specify do + expect(subject.source(excludes: :foo).source(:bar).render[:body]) + .to include(_source: {includes: %w[bar], excludes: %w[foo]}) + end specify { expect(subject.source(excludes: :foo).source(false).render[:body]).to include(_source: false) } - specify { expect(subject.source(excludes: :foo).source(false).source(excludes: :bar).render[:body]).to include(_source: {excludes: %w[foo bar]}) } - specify { expect(subject.source(excludes: :foo).source(false).source(true).render[:body]).to include(_source: {excludes: %w[foo]}) } + specify do + expect(subject.source(excludes: :foo).source(false).source(excludes: :bar).render[:body]) + .to include(_source: {excludes: %w[foo bar]}) + end + specify do + expect(subject.source(excludes: :foo).source(false).source(true).render[:body]) + .to include(_source: {excludes: %w[foo]}) + end specify { expect(subject.source(nil).render[:body]).to be_blank } specify { expect { subject.source(:foo) }.not_to change { subject.render } } end describe '#stored_fields' do specify { expect(subject.stored_fields(:foo).render[:body]).to include(stored_fields: ['foo']) } - specify { expect(subject.stored_fields(%i[foo bar]).stored_fields(nil).render[:body]).to include(stored_fields: %w[foo bar]) } - specify { expect(subject.stored_fields(:foo).stored_fields(:foo, :bar).render[:body]).to include(stored_fields: %w[foo bar]) } - specify { expect(subject.stored_fields(:foo).stored_fields(false).render[:body]).to include(stored_fields: '_none_') } - specify { expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(:bar).render[:body]).to include(stored_fields: %w[foo bar]) } - specify { expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(true).render[:body]).to include(stored_fields: %w[foo]) } + specify do + expect(subject.stored_fields(%i[foo bar]).stored_fields(nil).render[:body]) + .to include(stored_fields: %w[foo bar]) + end + specify do + expect(subject.stored_fields(:foo).stored_fields(:foo, :bar).render[:body]) + .to include(stored_fields: %w[foo bar]) + end + specify do + expect(subject.stored_fields(:foo).stored_fields(false).render[:body]) + .to include(stored_fields: '_none_') + end + specify do + expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(:bar).render[:body]) + .to include(stored_fields: %w[foo bar]) + end + specify do + expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(true).render[:body]) + .to include(stored_fields: %w[foo]) + end specify { expect(subject.stored_fields(nil).render[:body]).to be_blank } specify { expect { subject.stored_fields(:foo) }.not_to change { subject.render } } end @@ -199,8 +288,14 @@ %i[script_fields highlight].each do |name| describe "##{name}" do specify { expect(subject.send(name, foo: {bar: 42}).render[:body]).to include(name => {'foo' => {bar: 42}}) } - specify { expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body]).to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}}) } - specify { expect(subject.send(name, foo: {bar: 42}).send(name, nil).render[:body]).to include(name => {'foo' => {bar: 42}}) } + specify do + expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body]) + .to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}}) + end + specify do + expect(subject.send(name, foo: {bar: 42}).send(name, nil).render[:body]) + .to include(name => {'foo' => {bar: 42}}) + end specify { expect { subject.send(name, foo: {bar: 42}) }.not_to change { subject.render } } end end @@ -208,16 +303,28 @@ %i[suggest aggs].each do |name| describe "##{name}" do specify { expect(subject.send(name, foo: {bar: 42}).render[:body]).to include(name => {'foo' => {bar: 42}}) } - specify { expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body]).to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}}) } - specify { expect(subject.send(name, foo: {bar: 42}).send(name, nil).render[:body]).to include(name => {'foo' => {bar: 42}}) } + specify do + expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body]) + .to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}}) + end + specify do + expect(subject.send(name, foo: {bar: 42}).send(name, nil).render[:body]) + .to include(name => {'foo' => {bar: 42}}) + end specify { expect { subject.send(name, foo: {bar: 42}) }.not_to change { subject.render } } end end describe '#docvalue_fields' do specify { expect(subject.docvalue_fields(:foo).render[:body]).to include(docvalue_fields: ['foo']) } - specify { expect(subject.docvalue_fields(%i[foo bar]).docvalue_fields(nil).render[:body]).to include(docvalue_fields: %w[foo bar]) } - specify { expect(subject.docvalue_fields(:foo).docvalue_fields(:foo, :bar).render[:body]).to include(docvalue_fields: %w[foo bar]) } + specify do + expect(subject.docvalue_fields(%i[foo bar]).docvalue_fields(nil).render[:body]) + .to include(docvalue_fields: %w[foo bar]) + end + specify do + expect(subject.docvalue_fields(:foo).docvalue_fields(:foo, :bar).render[:body]) + .to include(docvalue_fields: %w[foo bar]) + end specify { expect(subject.docvalue_fields(nil).render[:body]).to be_blank } specify { expect { subject.docvalue_fields(:foo) }.not_to change { subject.render } } end @@ -232,14 +339,23 @@ describe '#indices_boost' do specify { expect(subject.indices_boost(foo: 1.2).render[:body]).to include(indices_boost: [{'foo' => 1.2}]) } - specify { expect(subject.indices_boost(foo: 1.2).indices_boost(moo: 1.3).render[:body]).to include(indices_boost: [{'foo' => 1.2}, {'moo' => 1.3}]) } - specify { expect(subject.indices_boost(foo: 1.2).indices_boost(nil).render[:body]).to include(indices_boost: [{'foo' => 1.2}]) } + specify do + expect(subject.indices_boost(foo: 1.2).indices_boost(moo: 1.3).render[:body]) + .to include(indices_boost: [{'foo' => 1.2}, {'moo' => 1.3}]) + end + specify do + expect(subject.indices_boost(foo: 1.2).indices_boost(nil).render[:body]) + .to include(indices_boost: [{'foo' => 1.2}]) + end specify { expect { subject.indices_boost(foo: 1.2) }.not_to change { subject.render } } end describe '#rescore' do specify { expect(subject.rescore(foo: 42).render[:body]).to include(rescore: [{foo: 42}]) } - specify { expect(subject.rescore(foo: 42).rescore(moo: 43).render[:body]).to include(rescore: [{foo: 42}, {moo: 43}]) } + specify do + expect(subject.rescore(foo: 42).rescore(moo: 43).render[:body]) + .to include(rescore: [{foo: 42}, {moo: 43}]) + end specify { expect(subject.rescore(foo: 42).rescore(nil).render[:body]).to include(rescore: [{foo: 42}]) } specify { expect { subject.rescore(foo: 42) }.not_to change { subject.render } } end @@ -253,7 +369,10 @@ describe '#search_after' do specify { expect(subject.search_after(:foo, :bar).render[:body]).to include(search_after: %i[foo bar]) } - specify { expect(subject.search_after(%i[foo bar]).search_after(:baz).render[:body]).to include(search_after: [:baz]) } + specify do + expect(subject.search_after(%i[foo bar]).search_after(:baz).render[:body]) + .to include(search_after: [:baz]) + end specify { expect(subject.search_after(:foo).search_after(nil).render[:body]).to be_blank } specify { expect { subject.search_after(:foo) }.not_to change { subject.render } } end @@ -310,7 +429,9 @@ context do let(:first_scope) { subject.query(foo: 'bar').filter.should(moo: 'baz').post_filter.must_not(boo: 'baf').limit(10) } - let(:second_scope) { subject.filter(foo: 'bar').post_filter.should(moo: 'baz').query.must_not(boo: 'baf').limit(20) } + let(:second_scope) do + subject.filter(foo: 'bar').post_filter.should(moo: 'baz').query.must_not(boo: 'baf').limit(20) + end describe '#and' do specify do @@ -379,7 +500,11 @@ context 'integration' do let(:products_count) { 9 } - let(:products) { Array.new(products_count) { |i| {id: i.next.to_i, name: "Name#{i.next}", age: 10 * i.next}.stringify_keys! } } + let(:products) do + Array.new(products_count) do |i| + {id: i.next.to_i, name: "Name#{i.next}", age: 10 * i.next}.stringify_keys! + end + end let(:cities) { Array.new(3) { |i| {id: (i.next + 9).to_i}.stringify_keys! } } let(:countries) { Array.new(3) { |i| {id: (i.next + 12).to_i}.stringify_keys! } } before do @@ -425,9 +550,18 @@ describe '#highlight' do specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name).to eq('Name3') } - specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name_highlight).to eq('Name3') } - specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name_highlights).to eq(['Name3']) } - specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first._data['_source']['name']).to eq('Name3') } + specify do + expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name_highlight) + .to eq('Name3') + end + specify do + expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name_highlights) + .to eq(['Name3']) + end + specify do + expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first._data['_source']['name']) + .to eq('Name3') + end end describe '#suggest' do @@ -551,12 +685,30 @@ specify { expect(subject.find { |w| w.id == 2 }).to be_a(ProductsIndex::Product).and have_attributes(id: 2) } specify { expect(subject.limit(2).find('1', '3', '7').map(&:id)).to contain_exactly(1, 3, 7) } specify { expect(subject.find(1, 3, 7).map(&:id)).to contain_exactly(1, 3, 7) } - specify { expect { subject.find('1', '3', '42') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42' } - specify { expect { subject.find(1, 3, 42) }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42' } - specify { expect { subject.query(match: {name: 'name3'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1' } - specify { expect { subject.query(match: {name: 'name2'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' } - specify { expect { subject.filter(match: {name: 'name2'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' } - specify { expect { subject.post_filter(match: {name: 'name2'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' } + specify do + expect { subject.find('1', '3', '42') } + .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42' + end + specify do + expect { subject.find(1, 3, 42) } + .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42' + end + specify do + expect { subject.query(match: {name: 'name3'}).find('1', '3') } + .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1' + end + specify do + expect { subject.query(match: {name: 'name2'}).find('1', '3') } + .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' + end + specify do + expect { subject.filter(match: {name: 'name2'}).find('1', '3') } + .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' + end + specify do + expect { subject.post_filter(match: {name: 'name2'}).find('1', '3') } + .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' + end context 'make sure it returns everything' do let(:products_count) { 12 } @@ -576,8 +728,12 @@ describe '#pluck' do specify { expect(subject.limit(5).pluck(:_id)).to eq(%w[1 2 3 4 5]) } - specify { expect(subject.limit(5).pluck(:_id, :age)).to eq([['1', 10], ['2', 20], ['3', 30], ['4', 40], ['5', 50]]) } - specify { expect(subject.limit(5).source(:name).pluck(:id, :age)).to eq([[1, 10], [2, 20], [3, 30], [4, 40], [5, 50]]) } + specify do + expect(subject.limit(5).pluck(:_id, :age)).to eq([['1', 10], ['2', 20], ['3', 30], ['4', 40], ['5', 50]]) + end + specify do + expect(subject.limit(5).source(:name).pluck(:id, :age)).to eq([[1, 10], [2, 20], [3, 30], [4, 40], [5, 50]]) + end specify do expect(subject.limit(5).pluck(:_index, :name)).to eq([ %w[products Name1], diff --git a/spec/chewy/search/response_spec.rb b/spec/chewy/search/response_spec.rb index ca7f3ad52..ae5721c2f 100644 --- a/spec/chewy/search/response_spec.rb +++ b/spec/chewy/search/response_spec.rb @@ -127,7 +127,9 @@ specify { expect(subject.aggs).to eq({}) } context do - let(:request) { Chewy::Search::Request.new(CitiesIndex, CountriesIndex).aggs(avg_rating: {avg: {field: :rating}}) } + let(:request) do + Chewy::Search::Request.new(CitiesIndex, CountriesIndex).aggs(avg_rating: {avg: {field: :rating}}) + end specify { expect(subject.aggs).to eq('avg_rating' => {'value' => 1.5}) } end end diff --git a/spec/chewy/search_spec.rb b/spec/chewy/search_spec.rb index f8e52faf6..de87a7b67 100644 --- a/spec/chewy/search_spec.rb +++ b/spec/chewy/search_spec.rb @@ -92,13 +92,25 @@ def self.by_name(index) end specify { expect(CitiesIndex.indices(CountriesIndex).by_rating(1).map(&:rating)).to eq([1, 1]) } - specify { expect(CitiesIndex.indices(CountriesIndex).by_rating(1).map(&:class)).to match_array([CitiesIndex::City, CountriesIndex::Country]) } + specify do + expect(CitiesIndex.indices(CountriesIndex).by_rating(1).map(&:class)) + .to match_array([CitiesIndex::City, CountriesIndex::Country]) + end specify { expect(CitiesIndex.indices(CountriesIndex).by_rating(1).by_name(2).map(&:rating)).to eq([1]) } - specify { expect(CitiesIndex.indices(CountriesIndex).by_rating(1).by_name(2).map(&:class)).to eq([CitiesIndex::City]) } + specify do + expect(CitiesIndex.indices(CountriesIndex).by_rating(1).by_name(2).map(&:class)) + .to eq([CitiesIndex::City]) + end specify { expect(CitiesIndex.indices(CountriesIndex).by_name(3).map(&:rating)).to eq([2, 1]) } - specify { expect(CitiesIndex.indices(CountriesIndex).by_name(3).map(&:class)).to eq([CitiesIndex::City, CountriesIndex::Country]) } + specify do + expect(CitiesIndex.indices(CountriesIndex).by_name(3).map(&:class)) + .to eq([CitiesIndex::City, CountriesIndex::Country]) + end specify { expect(CitiesIndex.indices(CountriesIndex).order(:name).by_rating(1).map(&:rating)).to eq([1, 1]) } - specify { expect(CitiesIndex.indices(CountriesIndex).order(:name).by_rating(1).map(&:class)).to match_array([CitiesIndex::City, CountriesIndex::Country]) } + specify do + expect(CitiesIndex.indices(CountriesIndex).order(:name).by_rating(1).map(&:class)) + .to match_array([CitiesIndex::City, CountriesIndex::Country]) + end specify { expect(CitiesIndex.by_rating(2).map(&:rating)).to eq([2]) } specify { expect(CitiesIndex.by_rating(2).map(&:class)).to eq([CitiesIndex::City]) } diff --git a/spec/chewy/stash_spec.rb b/spec/chewy/stash_spec.rb index 68a574343..e1198a5c4 100644 --- a/spec/chewy/stash_spec.rb +++ b/spec/chewy/stash_spec.rb @@ -72,14 +72,20 @@ def fetch_deleted_number(response) specify { expect(fetch_deleted_number(described_class.clean(only: UsersIndex))).to eq(1) } specify { expect(fetch_deleted_number(described_class.clean(only: [CitiesIndex, UsersIndex]))).to eq(2) } - specify { expect(fetch_deleted_number(described_class.clean(Time.now + 30.seconds, only: CountriesIndex))).to eq(0) } + specify do + expect(fetch_deleted_number(described_class.clean(Time.now + 30.seconds, only: CountriesIndex))).to eq(0) + end specify { expect(fetch_deleted_number(described_class.clean(Time.now + 30.seconds, only: CitiesIndex))).to eq(1) } end describe '.for' do specify { expect(described_class.for(UsersIndex).map(&:index_name)).to eq(['users']) } - specify { expect(described_class.for(CitiesIndex, CountriesIndex).map(&:type_name)).to contain_exactly('city', 'country') } - specify { expect(described_class.for(CitiesIndex, UsersIndex).map(&:index_name)).to contain_exactly('cities', 'users') } + specify do + expect(described_class.for(CitiesIndex, CountriesIndex).map(&:type_name)).to contain_exactly('city', 'country') + end + specify do + expect(described_class.for(CitiesIndex, UsersIndex).map(&:index_name)).to contain_exactly('cities', 'users') + end end describe '#type' do diff --git a/spec/chewy/strategy_spec.rb b/spec/chewy/strategy_spec.rb index 21f9fcfbb..64c5c3399 100644 --- a/spec/chewy/strategy_spec.rb +++ b/spec/chewy/strategy_spec.rb @@ -14,7 +14,10 @@ end describe '#push' do - specify { expect { strategy.push(:unexistant) }.to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`") } + specify do + expect { strategy.push(:unexistant) } + .to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`") + end specify do expect { strategy.push(:atomic) } @@ -35,7 +38,10 @@ end describe '#wrap' do - specify { expect { strategy.wrap(:unexistant) {} }.to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`") } + specify do + expect { strategy.wrap(:unexistant) {} } + .to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`") + end specify do expect do diff --git a/spec/chewy/type/adapter/active_record_spec.rb b/spec/chewy/type/adapter/active_record_spec.rb index 17cf4a8c4..f53953516 100644 --- a/spec/chewy/type/adapter/active_record_spec.rb +++ b/spec/chewy/type/adapter/active_record_spec.rb @@ -381,11 +381,21 @@ def delete_already? context 'objects' do specify { expect(subject.import(cities + deleted) { |_data| true }).to eq(true) } specify { expect(subject.import(cities + deleted) { |_data| false }).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[0].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[1].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[2].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[deleted[0].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[deleted[1].id])).to eq(false) } + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[0].id])).to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[1].id])).to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[2].id])).to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[deleted[0].id])).to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[deleted[1].id])).to eq(false) + end end context 'ids' do @@ -427,7 +437,10 @@ def delete_already? subject { described_class.new(Country.joins(:cities)) } specify { expect(subject.import_fields(Country.where('rating < 2'))).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(Country.where('rating < 2'), fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(Country.where('rating < 2'), fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end end end @@ -436,21 +449,36 @@ def delete_already? specify { expect(subject.import_fields(1, 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } specify { expect(subject.import_fields(countries.first(2))).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(countries.first(2), fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(countries.first(2), fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end end context 'batch_size' do specify { expect(subject.import_fields(batch_size: 2)).to match([contain_exactly(1, 2), [3]]) } - specify { expect(subject.import_fields(batch_size: 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1]), [[3, 2]]]) } + specify do + expect(subject.import_fields(batch_size: 2, fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1]), [[3, 2]]]) + end - specify { expect(subject.import_fields(Country.where('rating < 2'), batch_size: 2)).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(Country.where('rating < 2'), batch_size: 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(Country.where('rating < 2'), batch_size: 2)) + .to match([contain_exactly(1, 2)]) + end + specify do + expect(subject.import_fields(Country.where('rating < 2'), batch_size: 2, fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end specify { expect(subject.import_fields(1, 2, batch_size: 1)).to match([[1], [2]]) } specify { expect(subject.import_fields(1, 2, batch_size: 1, fields: [:rating])).to match([[[1, 0]], [[2, 1]]]) } specify { expect(subject.import_fields(countries.first(2), batch_size: 1)).to match([[1], [2]]) } - specify { expect(subject.import_fields(countries.first(2), batch_size: 1, fields: [:rating])).to match([[[1, 0]], [[2, 1]]]) } + specify do + expect(subject.import_fields(countries.first(2), batch_size: 1, fields: [:rating])) + .to match([[[1, 0]], [[2, 1]]]) + end end context 'typecast' do @@ -494,18 +522,18 @@ def delete_already? .to eq(cities.first(2) + [nil]) end specify do - expect(subject.load(city_ids, - _type: type, scope: -> { where(rating: 0) }, user: {scope: -> { where(rating: 1) }})) - .to eq([nil, nil] + cities.last(1)) + expect( + subject.load(city_ids, _type: type, scope: -> { where(rating: 0) }, user: {scope: -> { where(rating: 1) }}) + ).to eq([nil, nil] + cities.last(1)) end specify do expect(subject.load(city_ids, _type: type, scope: City.where(rating: 1))) .to eq([nil, nil] + cities.last(1)) end specify do - expect(subject.load(city_ids, - _type: type, scope: City.where(rating: 1), user: {scope: -> { where(rating: 0) }})) - .to eq(cities.first(2) + [nil]) + expect( + subject.load(city_ids, _type: type, scope: City.where(rating: 1), user: {scope: -> { where(rating: 0) }}) + ).to eq(cities.first(2) + [nil]) end end @@ -529,18 +557,22 @@ def delete_already? .to eq(cities.first(2) + [nil]) end specify do - expect(subject.load(city_ids, - _type: type, scope: -> { where(country_id: 0) }, user: {scope: -> { where(country_id: 1) }})) - .to eq([nil, nil] + cities.last(1)) + expect( + subject.load( + city_ids, _type: type, scope: -> { where(country_id: 0) }, user: {scope: -> { where(country_id: 1) }} + ) + ).to eq([nil, nil] + cities.last(1)) end specify do expect(subject.load(city_ids, _type: type, scope: City.where(country_id: 1))) .to eq([nil, nil] + cities.last(1)) end specify do - expect(subject.load(city_ids, - _type: type, scope: City.where(country_id: 1), user: {scope: -> { where(country_id: 0) }})) - .to eq(cities.first(2) + [nil]) + expect( + subject.load( + city_ids, _type: type, scope: City.where(country_id: 1), user: {scope: -> { where(country_id: 0) }} + ) + ).to eq(cities.first(2) + [nil]) end end end diff --git a/spec/chewy/type/adapter/mongoid_spec.rb b/spec/chewy/type/adapter/mongoid_spec.rb index 664516282..b7c1a9c77 100644 --- a/spec/chewy/type/adapter/mongoid_spec.rb +++ b/spec/chewy/type/adapter/mongoid_spec.rb @@ -268,11 +268,26 @@ def delete_already? context 'objects' do specify { expect(subject.import(cities + deleted) { |_data| true }).to eq(true) } specify { expect(subject.import(cities + deleted) { |_data| false }).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[cities[0].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[cities[2].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[cities[4].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[deleted[0].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[deleted[2].id])).to eq(false) } + specify do + expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[cities[0].id])) + .to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[cities[2].id])) + .to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[cities[4].id])) + .to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[deleted[0].id])) + .to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 2, &data_comparer.curry[deleted[2].id])) + .to eq(false) + end end context 'ids' do @@ -293,21 +308,30 @@ def delete_already? let!(:cities) { Array.new(6) { |i| City.create!(rating: i + 3, country_id: (i + 4) / 2) { |c| c.id = i + 3 } } } specify { expect(subject.import_fields).to match([contain_exactly(1, 2, 3, 4)]) } - specify { expect(subject.import_fields(fields: [:rating])).to match([contain_exactly([1, 0], [2, 1], [3, 2], [4, 3])]) } + specify do + expect(subject.import_fields(fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1], [3, 2], [4, 3])]) + end context 'scopes' do context do subject { described_class.new(Country.includes(:cities)) } specify { expect(subject.import_fields).to match([contain_exactly(1, 2, 3, 4)]) } - specify { expect(subject.import_fields(fields: [:rating])).to match([contain_exactly([1, 0], [2, 1], [3, 2], [4, 3])]) } + specify do + expect(subject.import_fields(fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1], [3, 2], [4, 3])]) + end end context 'ignores default scope if another scope is passed' do subject { described_class.new(Country.where(:rating.gt => 2)) } specify { expect(subject.import_fields(Country.where(:rating.lt => 2))).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(Country.where(:rating.lt => 2), fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(Country.where(:rating.lt => 2), fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end end end @@ -316,21 +340,41 @@ def delete_already? specify { expect(subject.import_fields(1, 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } specify { expect(subject.import_fields(countries.first(2))).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(countries.first(2), fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(countries.first(2), fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end end context 'batch_size' do specify { expect(subject.import_fields(batch_size: 2)).to match([contain_exactly(1, 2), contain_exactly(3, 4)]) } - specify { expect(subject.import_fields(batch_size: 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1]), contain_exactly([3, 2], [4, 3])]) } + specify do + expect(subject.import_fields(batch_size: 2, fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1]), contain_exactly([3, 2], [4, 3])]) + end - specify { expect(subject.import_fields(Country.where(:rating.lt => 2), batch_size: 2)).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(Country.where(:rating.lt => 2), batch_size: 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(Country.where(:rating.lt => 2), batch_size: 2)) + .to match([contain_exactly(1, 2)]) + end + specify do + expect(subject.import_fields(Country.where(:rating.lt => 2), batch_size: 2, fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end specify { expect(subject.import_fields(1, 2, 3, batch_size: 2)).to match([contain_exactly(1, 2), [3]]) } - specify { expect(subject.import_fields(1, 2, 3, batch_size: 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1]), [[3, 2]]]) } + specify do + expect(subject.import_fields(1, 2, 3, batch_size: 2, fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1]), [[3, 2]]]) + end - specify { expect(subject.import_fields(countries.first(3), batch_size: 2)).to match([contain_exactly(1, 2), [3]]) } - specify { expect(subject.import_fields(countries.first(3), batch_size: 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1]), [[3, 2]]]) } + specify do + expect(subject.import_fields(countries.first(3), batch_size: 2)).to match([contain_exactly(1, 2), [3]]) + end + specify do + expect(subject.import_fields(countries.first(3), batch_size: 2, fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1]), [[3, 2]]]) + end end end @@ -354,18 +398,18 @@ def delete_already? .to eq(cities.first(2) + [nil]) end specify do - expect(subject.load(city_ids, - _type: type, scope: -> { where(rating: 0) }, user: {scope: -> { where(rating: 1) }})) - .to eq([nil, nil] + cities.last(1)) + expect( + subject.load(city_ids, _type: type, scope: -> { where(rating: 0) }, user: {scope: -> { where(rating: 1) }}) + ).to eq([nil, nil] + cities.last(1)) end specify do expect(subject.load(city_ids, _type: type, scope: City.where(rating: 1))) .to eq([nil, nil] + cities.last(1)) end specify do - expect(subject.load(city_ids, - _type: type, scope: City.where(rating: 1), user: {scope: -> { where(rating: 0) }})) - .to eq(cities.first(2) + [nil]) + expect( + subject.load(city_ids, _type: type, scope: City.where(rating: 1), user: {scope: -> { where(rating: 0) }}) + ).to eq(cities.first(2) + [nil]) end end end diff --git a/spec/chewy/type/adapter/object_spec.rb b/spec/chewy/type/adapter/object_spec.rb index 51ddb56ae..6c59140ba 100644 --- a/spec/chewy/type/adapter/object_spec.rb +++ b/spec/chewy/type/adapter/object_spec.rb @@ -104,7 +104,13 @@ def import(*args) end context 'error handling' do - let(:products) { Array.new(3) { |i| double.tap { |product| allow(product).to receive_messages(rating: i.next) } } } + let(:products) do + Array.new(3) do |i| + double.tap do |product| + allow(product).to receive_messages(rating: i.next) + end + end + end let(:deleted) { Array.new(2) { |i| double(destroyed?: true, rating: i + 4) } } subject { described_class.new('product') } @@ -135,13 +141,18 @@ def import(*args) context do subject { described_class.new(-> { objects }) } specify { expect(subject.import_fields(batch_size: 2)).to match([[1, 2], [3]]) } - specify { expect(subject.import_fields(fields: [:name], batch_size: 2)).to match([[[1, 'Name0'], [2, 'Name1']], [[3, 'Name2']]]) } + specify do + expect(subject.import_fields(fields: [:name], batch_size: 2)) + .to match([[[1, 'Name0'], [2, 'Name1']], [[3, 'Name2']]]) + end end context do subject { described_class.new(-> { objects }) } specify { expect(subject.import_fields(objects.first(2))).to match([[1, 2]]) } - specify { expect(subject.import_fields(objects.first(2), fields: [:name])).to match([[[1, 'Name0'], [2, 'Name1']]]) } + specify do + expect(subject.import_fields(objects.first(2), fields: [:name])).to match([[[1, 'Name0'], [2, 'Name1']]]) + end end context do @@ -178,7 +189,9 @@ def self.pluck(*fields) context do subject { described_class.new(Product) } specify { expect(subject.import_fields(objects.first(2))).to match([[1, 2]]) } - specify { expect(subject.import_fields(objects.first(2), fields: [:name])).to match([[[1, 'Name0'], [2, 'Name1']]]) } + specify do + expect(subject.import_fields(objects.first(2), fields: [:name])).to match([[[1, 'Name0'], [2, 'Name1']]]) + end end context 'batch_size' do @@ -196,7 +209,9 @@ def self.pluck(*fields) specify { expect(subject.import_references).to match([objects]) } specify { expect(subject.import_references(batch_size: 2)).to match([objects.first(2), objects.last(1)]) } specify { expect(subject.import_references(objects.first(2))).to match([objects.first(2)]) } - specify { expect(subject.import_references(objects.first(2), batch_size: 1)).to match([objects.first(1), [objects[1]]]) } + specify do + expect(subject.import_references(objects.first(2), batch_size: 1)).to match([objects.first(1), [objects[1]]]) + end end describe '#load' do diff --git a/spec/chewy/type/adapter/sequel_spec.rb b/spec/chewy/type/adapter/sequel_spec.rb index 56946451d..a0905760a 100644 --- a/spec/chewy/type/adapter/sequel_spec.rb +++ b/spec/chewy/type/adapter/sequel_spec.rb @@ -319,11 +319,21 @@ def delete_already? context 'objects' do specify { expect(subject.import(cities + deleted) { |_data| true }).to eq(true) } specify { expect(subject.import(cities + deleted) { |_data| false }).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[0].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[1].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[2].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[deleted[0].id])).to eq(false) } - specify { expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[deleted[1].id])).to eq(false) } + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[0].id])).to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[1].id])).to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[cities[2].id])).to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[deleted[0].id])).to eq(false) + end + specify do + expect(subject.import(cities + deleted, batch_size: 1, &data_comparer.curry[deleted[1].id])).to eq(false) + end end context 'ids' do @@ -372,7 +382,10 @@ def delete_already? subject { described_class.new(Country.join(:cities, country_id: :id)) } specify { expect(subject.import_fields(Country.where('rating < 2'))).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(Country.where('rating < 2'), fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(Country.where('rating < 2'), fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end end end @@ -381,21 +394,36 @@ def delete_already? specify { expect(subject.import_fields(1, 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } specify { expect(subject.import_fields(countries.first(2))).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(countries.first(2), fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(countries.first(2), fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end end context 'batch_size' do specify { expect(subject.import_fields(batch_size: 2)).to match([contain_exactly(1, 2), [3]]) } - specify { expect(subject.import_fields(batch_size: 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1]), [[3, 2]]]) } + specify do + expect(subject.import_fields(batch_size: 2, fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1]), [[3, 2]]]) + end - specify { expect(subject.import_fields(Country.where('rating < 2'), batch_size: 2)).to match([contain_exactly(1, 2)]) } - specify { expect(subject.import_fields(Country.where('rating < 2'), batch_size: 2, fields: [:rating])).to match([contain_exactly([1, 0], [2, 1])]) } + specify do + expect(subject.import_fields(Country.where('rating < 2'), batch_size: 2)) + .to match([contain_exactly(1, 2)]) + end + specify do + expect(subject.import_fields(Country.where('rating < 2'), batch_size: 2, fields: [:rating])) + .to match([contain_exactly([1, 0], [2, 1])]) + end specify { expect(subject.import_fields(1, 2, batch_size: 1)).to match([[1], [2]]) } specify { expect(subject.import_fields(1, 2, batch_size: 1, fields: [:rating])).to match([[[1, 0]], [[2, 1]]]) } specify { expect(subject.import_fields(countries.first(2), batch_size: 1)).to match([[1], [2]]) } - specify { expect(subject.import_fields(countries.first(2), batch_size: 1, fields: [:rating])).to match([[[1, 0]], [[2, 1]]]) } + specify do + expect(subject.import_fields(countries.first(2), batch_size: 1, fields: [:rating])) + .to match([[[1, 0]], [[2, 1]]]) + end end end @@ -419,18 +447,18 @@ def delete_already? .to eq(cities.first(2) + [nil]) end specify do - expect(subject.load(city_ids, - _type: type, scope: -> { where(rating: 0) }, user: {scope: -> { where(rating: 1) }})) - .to eq([nil, nil] + cities.last(1)) + expect( + subject.load(city_ids, _type: type, scope: -> { where(rating: 0) }, user: {scope: -> { where(rating: 1) }}) + ).to eq([nil, nil] + cities.last(1)) end xspecify 'sequel does not support scopes merge' do expect(subject.load(city_ids, _type: type, scope: City.where(rating: 1))) .to eq([nil, nil] + cities.last(1)) end specify do - expect(subject.load(city_ids, - _type: type, scope: City.where(rating: 1), user: {scope: -> { where(rating: 0) }})) - .to eq(cities.first(2) + [nil]) + expect( + subject.load(city_ids, _type: type, scope: City.where(rating: 1), user: {scope: -> { where(rating: 0) }}) + ).to eq(cities.first(2) + [nil]) end end @@ -454,18 +482,22 @@ def delete_already? .to eq(cities.first(2) + [nil]) end specify do - expect(subject.load(city_ids, - _type: type, scope: -> { where(country_id: 0) }, user: {scope: -> { where(country_id: 1) }})) - .to eq([nil, nil] + cities.last(1)) + expect( + subject.load( + city_ids, _type: type, scope: -> { where(country_id: 0) }, user: {scope: -> { where(country_id: 1) }} + ) + ).to eq([nil, nil] + cities.last(1)) end xspecify 'sequel does not support scopes merge' do expect(subject.load(city_ids, _type: type, scope: City.where(country_id: 1))) .to eq([nil, nil] + cities.last(1)) end specify do - expect(subject.load(city_ids, - _type: type, scope: City.where(country_id: 1), user: {scope: -> { where(country_id: 0) }})) - .to eq(cities.first(2) + [nil]) + expect( + subject.load( + city_ids, _type: type, scope: City.where(country_id: 1), user: {scope: -> { where(country_id: 0) }} + ) + ).to eq(cities.first(2) + [nil]) end end end diff --git a/spec/chewy/type/import/routine_spec.rb b/spec/chewy/type/import/routine_spec.rb index ef15e8bba..ba5f4778a 100644 --- a/spec/chewy/type/import/routine_spec.rb +++ b/spec/chewy/type/import/routine_spec.rb @@ -68,7 +68,9 @@ specify { expect(described_class.new(CitiesIndex::City).parallel_options).to be_nil } specify { expect(described_class.new(CitiesIndex::City, parallel: true).parallel_options).to eq({}) } specify { expect(described_class.new(CitiesIndex::City, parallel: 3).parallel_options).to eq(in_processes: 3) } - specify { expect(described_class.new(CitiesIndex::City, parallel: {in_threads: 2}).parallel_options).to eq(in_threads: 2) } + specify do + expect(described_class.new(CitiesIndex::City, parallel: {in_threads: 2}).parallel_options).to eq(in_threads: 2) + end end describe '#stats' do diff --git a/spec/chewy/type/import_spec.rb b/spec/chewy/type/import_spec.rb index ad3f77f47..a6c295bb2 100644 --- a/spec/chewy/type/import_spec.rb +++ b/spec/chewy/type/import_spec.rb @@ -78,13 +78,25 @@ def subscribe_notification let(:names) { %w[name0 name1] } context 'mongoid', :mongoid do - specify { expect { import(City.where(:name.in => names)) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) } - specify { expect { import(City.where(:name.in => names).map(&:id)) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) } + specify do + expect { import(City.where(:name.in => names)) } + .to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) + end + specify do + expect { import(City.where(:name.in => names).map(&:id)) } + .to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) + end end context 'active record', :active_record do - specify { expect { import(City.where(name: names)) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) } - specify { expect { import(City.where(name: names).map(&:id)) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) } + specify do + expect { import(City.where(name: names)) } + .to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) + end + specify do + expect { import(City.where(name: names).map(&:id)) } + .to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) + end end end @@ -120,7 +132,10 @@ def subscribe_notification context ':bulk_size' do let!(:dummy_cities) { Array.new(3) { |i| City.create(id: i + 1, name: "name#{i}" * 20) } } - specify { expect { import(dummy_cities, bulk_size: 1.2.kilobyte) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities) } + specify do + expect { import(dummy_cities, bulk_size: 1.2.kilobyte) } + .to update_index(CitiesIndex::City).and_reindex(dummy_cities) + end context do before { expect(Chewy.client).to receive(:bulk).exactly(3).times.and_call_original } @@ -150,13 +165,15 @@ def subscribe_notification context 'mongoid', :mongoid do specify do - expect { import City.where(_id: dummy_cities.first.id) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first).only + expect { import City.where(_id: dummy_cities.first.id) } + .to update_index(CitiesIndex::City).and_reindex(dummy_cities.first).only end end context 'active record', :active_record do specify do - expect { import City.where(id: dummy_cities.first.id) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first).only + expect { import City.where(id: dummy_cities.first.id) } + .to update_index(CitiesIndex::City).and_reindex(dummy_cities.first).only end specify do @@ -266,7 +283,12 @@ def subscribe_notification import(objects, update_fields: %i[name]) expect(payload).to eq( - errors: {index: {{'type' => 'mapper_parsing_exception', 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'} => %w[2 4]}}, + errors: { + index: {{ + 'type' => 'mapper_parsing_exception', + 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value' + } => %w[2 4]} + }, import: {index: 6}, type: CitiesIndex::City ) @@ -284,7 +306,12 @@ def subscribe_notification import(objects, batch_size: 2, update_fields: %i[name]) expect(payload).to eq( - errors: {index: {{'type' => 'mapper_parsing_exception', 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'} => %w[2 4]}}, + errors: { + index: {{ + 'type' => 'mapper_parsing_exception', + 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value' + } => %w[2 4]} + }, import: {index: 6}, type: CitiesIndex::City ) @@ -305,7 +332,12 @@ def subscribe_notification import(objects, batch_size: 2, update_fields: %i[name]) expect(payload).to eq( - errors: {index: {{'type' => 'mapper_parsing_exception', 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'} => %w[2 4]}}, + errors: { + index: {{ + 'type' => 'mapper_parsing_exception', + 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value' + } => %w[2 4]} + }, import: {index: 6}, type: CitiesIndex::City ) @@ -412,7 +444,12 @@ def subscribe_notification import(objects, update_fields: %i[object]) expect(payload).to eq( - errors: {update: {{'type' => 'mapper_parsing_exception', 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'} => %w[2 4]}}, + errors: { + update: {{ + 'type' => 'mapper_parsing_exception', + 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value' + } => %w[2 4]} + }, import: {index: 6}, type: CitiesIndex::City ) @@ -509,7 +546,7 @@ def import(*args) stub_index(:cities) do define_type :city do crutch :names do |collection| - collection.map { |o| [o.name, o.name + '42'] }.to_h + collection.map { |o| [o.name, "#{o.name}42"] }.to_h end field :name, value: ->(o, c) { c.names[o.name] } field :rating diff --git a/spec/chewy/type/observe_spec.rb b/spec/chewy/type/observe_spec.rb index d8afd05a3..da2691eb0 100644 --- a/spec/chewy/type/observe_spec.rb +++ b/spec/chewy/type/observe_spec.rb @@ -79,7 +79,10 @@ specify { expect { city.update!(country: nil) }.to update_index('countries#country').and_reindex(country1).only } specify { expect { city.update!(country: country2) }.to update_index('cities#city').and_reindex(city).only } - specify { expect { city.update!(country: country2) }.to update_index('countries#country').and_reindex(country1, country2).only } + specify do + expect { city.update!(country: country2) } + .to update_index('countries#country').and_reindex(country1, country2).only + end end context do diff --git a/spec/chewy/type_spec.rb b/spec/chewy/type_spec.rb index 9e11c81b9..b51831d68 100644 --- a/spec/chewy/type_spec.rb +++ b/spec/chewy/type_spec.rb @@ -43,7 +43,10 @@ def self.by_name; end specify { expect { PlacesIndex::City.non_existing_method_call }.to raise_error(NoMethodError) } specify { expect(PlacesIndex::City._default_import_options).to eq({}) } - specify { expect { PlacesIndex::City.default_import_options(invalid_option: 'Yeah!') }.to raise_error(ArgumentError) } + specify do + expect { PlacesIndex::City.default_import_options(invalid_option: 'Yeah!') } + .to raise_error(ArgumentError) + end context 'default_import_options is set' do let(:converter) { -> {} } diff --git a/spec/chewy_spec.rb b/spec/chewy_spec.rb index 481dc1f02..1f9637535 100644 --- a/spec/chewy_spec.rb +++ b/spec/chewy_spec.rb @@ -18,15 +18,27 @@ end end - specify { expect { described_class.derive_type('some#developers') }.to raise_error(Chewy::UnderivableType, /SomeIndex/) } - specify { expect { described_class.derive_type('borogoves#developers') }.to raise_error(Chewy::UnderivableType, /Borogoves/) } - specify { expect { described_class.derive_type('developers#borogoves') }.to raise_error(Chewy::UnderivableType, /DevelopersIndex.*borogoves/) } + specify do + expect { described_class.derive_type('some#developers') } + .to raise_error(Chewy::UnderivableType, /SomeIndex/) + end + specify do + expect { described_class.derive_type('borogoves#developers') } + .to raise_error(Chewy::UnderivableType, /Borogoves/) + end + specify do + expect { described_class.derive_type('developers#borogoves') } + .to raise_error(Chewy::UnderivableType, /DevelopersIndex.*borogoves/) + end specify { expect(described_class.derive_type(DevelopersIndex::Developer)).to eq(DevelopersIndex::Developer) } specify { expect(described_class.derive_type('developers_index')).to eq(DevelopersIndex::Developer) } specify { expect(described_class.derive_type('developers')).to eq(DevelopersIndex::Developer) } specify { expect(described_class.derive_type('developers#developer')).to eq(DevelopersIndex::Developer) } - specify { expect(described_class.derive_type('namespace/autocomplete#developer')).to eq(Namespace::AutocompleteIndex::Developer) } + specify do + expect(described_class.derive_type('namespace/autocomplete#developer')) + .to eq(Namespace::AutocompleteIndex::Developer) + end end describe '.derive_types' do @@ -42,18 +54,35 @@ end end - specify { expect { described_class.derive_types('some#developers') }.to raise_error(Chewy::UnderivableType, /SomeIndex/) } - specify { expect { described_class.derive_types('borogoves#developers') }.to raise_error(Chewy::UnderivableType, /Borogoves/) } - specify { expect { described_class.derive_types('developers#borogoves') }.to raise_error(Chewy::UnderivableType, /DevelopersIndex.*borogoves/) } + specify do + expect { described_class.derive_types('some#developers') } + .to raise_error(Chewy::UnderivableType, /SomeIndex/) + end + specify do + expect { described_class.derive_types('borogoves#developers') } + .to raise_error(Chewy::UnderivableType, /Borogoves/) + end + specify do + expect { described_class.derive_types('developers#borogoves') } + .to raise_error(Chewy::UnderivableType, /DevelopersIndex.*borogoves/) + end - specify { expect(described_class.derive_types(Namespace::AutocompleteIndex)).to match_array(Namespace::AutocompleteIndex.types) } + specify do + expect(described_class.derive_types(Namespace::AutocompleteIndex)) + .to match_array(Namespace::AutocompleteIndex.types) + end specify { expect(described_class.derive_types(DevelopersIndex::Developer)).to eq([DevelopersIndex::Developer]) } specify { expect(described_class.derive_types('developers_index')).to eq([DevelopersIndex::Developer]) } specify { expect(described_class.derive_types('developers')).to eq([DevelopersIndex::Developer]) } specify { expect(described_class.derive_types('developers#developer')).to eq([DevelopersIndex::Developer]) } - specify { expect(described_class.derive_types('namespace/autocomplete')).to match_array(Namespace::AutocompleteIndex.types) } - specify { expect(described_class.derive_types('namespace/autocomplete#developer')).to eq([Namespace::AutocompleteIndex::Developer]) } + specify do + expect(described_class.derive_types('namespace/autocomplete')).to match_array(Namespace::AutocompleteIndex.types) + end + specify do + expect(described_class.derive_types('namespace/autocomplete#developer')) + .to eq([Namespace::AutocompleteIndex::Developer]) + end end describe '.create_type' do diff --git a/spec/support/active_record.rb b/spec/support/active_record.rb index 5bc56eb97..78c964e00 100644 --- a/spec/support/active_record.rb +++ b/spec/support/active_record.rb @@ -2,7 +2,9 @@ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'file::memory:?cache=shared', pool: 10) ActiveRecord::Base.logger = Logger.new('/dev/null') -ActiveRecord::Base.raise_in_transactional_callbacks = true if ActiveRecord::Base.respond_to?(:raise_in_transactional_callbacks) +if ActiveRecord::Base.respond_to?(:raise_in_transactional_callbacks) + ActiveRecord::Base.raise_in_transactional_callbacks = true +end ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'countries'") ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'cities'") @@ -47,7 +49,9 @@ def expects_no_query(except: nil, &block) &block ) ofending_queries = except ? queries.find_all { |query| !query.match(except) } : queries - raise "Expected no DB queries, but the following ones were made: #{ofending_queries.join(', ')}" if ofending_queries.present? + if ofending_queries.present? + raise "Expected no DB queries, but the following ones were made: #{ofending_queries.join(', ')}" + end end def stub_model(name, superclass = nil, &block)