diff --git a/lib/chewy/query.rb b/lib/chewy/query.rb index db3f7bcf3..d4d14ae0b 100644 --- a/lib/chewy/query.rb +++ b/lib/chewy/query.rb @@ -40,6 +40,11 @@ def initialize(*indexes_or_types_and_options) @criteria = Criteria.new end + # A compatibility layer with the new request DSL. + def render + _request + end + # Comparation with other query or collection # If other is collection - search request is executed and # result is used for comparation diff --git a/lib/chewy/search.rb b/lib/chewy/search.rb index 1d93574bb..8bcc095a0 100644 --- a/lib/chewy/search.rb +++ b/lib/chewy/search.rb @@ -58,11 +58,7 @@ def all # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html # @return [Hash] the request result def search_string(query, options = {}) - options = options.merge( - index: all._indexes.map(&:index_name), - type: all._types.map(&:type_name), - q: query - ) + options = options.merge(all.render.slice(:index, :type).merge(q: query)) Chewy.client.search(options) end diff --git a/lib/chewy/search/parameters.rb b/lib/chewy/search/parameters.rb index cf845ac3e..fbf9194a7 100644 --- a/lib/chewy/search/parameters.rb +++ b/lib/chewy/search/parameters.rb @@ -10,7 +10,8 @@ module Search # @see Chewy::Search::Request#parameters # @see Chewy::Search::Parameters::Storage class Parameters - QUERY_STRING_PARAMS = %i[search_type request_cache allow_partial_search_results].freeze + QUERY_STRING_STORAGES = %i[indices search_type request_cache allow_partial_search_results].freeze + # Default storage classes warehouse. It is probably possible to # add your own classes here if necessary, but I'm not sure it will work. # @@ -102,7 +103,7 @@ def merge!(other) # # @return [Hash] request body def render - {}.merge(render_body).merge(render_query_string_params) + render_query_string_params.merge(render_body) end protected @@ -124,19 +125,22 @@ def assert_storages(names) end def render_query_string_params - stores = @storages.select { |storage_name, _| QUERY_STRING_PARAMS.include?(storage_name) } - stores.values.inject({}) do |result, storage| + query_string_storages = @storages.select do |storage_name, _| + QUERY_STRING_STORAGES.include?(storage_name) + end + + query_string_storages.values.inject({}) do |result, storage| result.merge!(storage.render || {}) end end def render_body - exceptions = %i[filter query none] + QUERY_STRING_PARAMS + exceptions = %i[filter query none] + QUERY_STRING_STORAGES body = @storages.except(*exceptions).values.inject({}) do |result, storage| result.merge!(storage.render || {}) end body.merge!(render_query || {}) - body.present? ? {body: body} : {} + {body: body} end def render_query diff --git a/lib/chewy/search/parameters/indices.rb b/lib/chewy/search/parameters/indices.rb new file mode 100644 index 000000000..8d0fd1d7f --- /dev/null +++ b/lib/chewy/search/parameters/indices.rb @@ -0,0 +1,123 @@ +require 'chewy/search/parameters/storage' + +module Chewy + module Search + class Parameters + # Stores indices and/or types to query. + # Renders it to lists of string accepted by ElasticSearch + # API. + # + # The semantics behind it can be described in the + # following statements: + # 1. If index is added to the storage, no matter, a class + # or a string/symbol, it gets appended to the list. + # 2. If type is added to the storage, it filters out types + # assigned via indices. + # 3. But when a type class with non-existing index is added, + # this index got also added to the list if indices. + # 4. In cases when of an index identifier added, type + # indetifiers also got appended instead of filtering. + class Indices < Storage + # Two index storages are equal if they produce the + # same output on render. + # + # @see Chewy::Search::Parameters::Storage#== + # @param other [Chewy::Search::Parameters::Storage] any storage instance + # @return [true, false] the result of comparision + def ==(other) + super || other.class == self.class && other.render == render + end + + # Just adds types to types and indices to indices. + # + # @see Chewy::Search::Parameters::Storage#update! + # @param other_value [{Symbol => Array}] any acceptable storage value + # @return [{Symbol => Array}] updated value + def update!(other_value) + new_value = normalize(other_value) + + @value = { + indices: value[:indices] | new_value[:indices], + types: value[:types] | new_value[:types] + } + end + + # Returns desired index and type names. + # + # @see Chewy::Search::Parameters::Storage#render + # @return [{Symbol => Array}] rendered value with the parameter name + def render + { + index: index_names.uniq.sort, + type: type_names.uniq.sort + }.reject { |_, v| v.blank? } + end + + # Returns index classes used for the request. + # No strings/symbos included. + # + # @return [Array] a list of index classes + def indices + index_classes | type_classes.map(&:index) + end + + # Returns type classes used for the request. + # No strings/symbos included. + # + # @return [Array] a list of types classes + def types + type_classes | (index_classes - type_classes.map(&:index)).flat_map(&:types) + end + + private + + def initialize_clone(origin) + @value = origin.value.dup + end + + def normalize(value) + value ||= {} + + { + indices: Array.wrap(value[:indices]).flatten.compact, + types: Array.wrap(value[:types]).flatten.compact + } + end + + def index_classes + value[:indices].select do |klass| + klass.is_a?(Class) && klass < Chewy::Index + end + end + + def index_identifiers + value[:indices] - index_classes + end + + def index_names + indices.map(&:index_name) | index_identifiers.map(&:to_s) + end + + def type_classes + value[:types].select do |klass| + klass.is_a?(Class) && klass < Chewy::Type + end + end + + def type_identifiers + value[:types] - type_classes + end + + def type_names + type_names = types.map(&:type_name) + + if index_identifiers.blank? && type_identifiers.present? + (type_names & type_identifiers.map(&:to_s)).presence || type_names + else + type_names | type_identifiers.map(&:to_s) + end + end + end + end + end +end diff --git a/lib/chewy/search/request.rb b/lib/chewy/search/request.rb index a9e0adfd8..fcc22298b 100644 --- a/lib/chewy/search/request.rb +++ b/lib/chewy/search/request.rb @@ -26,8 +26,9 @@ class Request timeout min_score source stored_fields search_after load script_fields suggest aggs aggregations none indices_boost rescore highlight total total_count - total_entries types delete_all count exists? exist? find pluck - scroll_batches scroll_hits scroll_results scroll_wrappers + total_entries indices types delete_all count exists? + exist? find pluck scroll_batches scroll_hits + scroll_results scroll_wrappers ].to_set.freeze DEFAULT_BATCH_SIZE = 1000 DEFAULT_PLUCK_BATCH_SIZE = 10_000 @@ -51,24 +52,32 @@ class Request alias_method :total_count, :total alias_method :total_entries, :total - attr_reader :_indexes, :_types - # The class is initialized with the list of chewy indexes and/or # types, which are later used to compose requests. + # Any symbol/string passed is treated as an index identifier. # # @example + # Chewy::Search::Request.new(:places) + # # => ["places"]}> # Chewy::Search::Request.new(PlacesIndex) # # => ["places"], :type=>["city", "country"]}> # Chewy::Search::Request.new(PlacesIndex::City) # # => ["places"], :type=>["city"]}> # Chewy::Search::Request.new(UsersIndex, PlacesIndex::City) # # => ["users", "places"], :type=>["city", "user"]}> - # @param indexes_or_types [Array] indexes and types in any combinations - def initialize(*indexes_or_types) - @_types = indexes_or_types.select { |klass| klass < Chewy::Type } - @_indexes = indexes_or_types.select { |klass| klass < Chewy::Index } - @_types |= @_indexes.flat_map(&:types) - @_indexes |= @_types.map(&:index) + # @param indexes_or_types [Array] indices and types in any combinations + def initialize(*indices_or_types) + indices = indices_or_types.reject do |klass| + klass.is_a?(Class) && klass < Chewy::Type + end + + types = indices_or_types.select do |klass| + klass.is_a?(Class) && klass < Chewy::Type + end + + parameters.modify!(:indices) do + replace!(indices: indices, types: types) + end end # Underlying parameter storage collection. @@ -110,7 +119,7 @@ def response # # @return [Hash] request body def render - @render ||= render_base.merge(parameters.render) + @render ||= parameters.render end # Includes the class name and the result of rendering. @@ -281,21 +290,39 @@ def inspect # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-docvalue-fields.html # @param values [Array] field names # @return [Chewy::Search::Request] + %i[order docvalue_fields].each do |name| + define_method name do |value, *values| + modify(name) { update!([value, *values]) } + end + end + + # @!method indices(*values) + # Modifies `index` request parameter. Updates the storage on every call. + # Added passed indexes to the parameter list. + # + # @example + # UsersIndex.indices(CitiesIndex).indices(:another) + # # => ["another", "cities", "users"], :type=>["city", "user"]}> + # @see Chewy::Search::Parameters::Indices + # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html + # @param values [Array] index names + # @return [Chewy::Search::Request] # # @!method types(*values) - # Modifies `types` request parameter. Updates the storage on every call. - # Constrains types passed on the request initialization. + # Modifies `type` request parameter. Updates the storage on every call. + # Constrains types passed on the request initialization or adds them + # to the list depending on circumstances. # # @example - # PlacesIndex.types(:city).types(:unexistent) - # # => ["places"], :type=>["city"]}> - # @see Chewy::Search::Parameters::Types + # UsersIndex.types(CitiesIndex::City).types(:unexistent) + # # => ["cities", "users"], :type=>["city", "user"]}> + # @see Chewy::Search::Parameters::Indices # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html - # @param values [Array] type names + # @param values [Array] type names # @return [Chewy::Search::Request] - %i[order docvalue_fields types].each do |name| + %i[indices types].each do |name| define_method name do |value, *values| - modify(name) { update!([value, *values]) } + modify(:indices) { update!(name => [value, *values]) } end end @@ -759,7 +786,7 @@ def merge(other) # @param values [Array] # @return [Chewy::Search::Request] new scope def only(*values) - chain { parameters.only!(values.flatten(1)) } + chain { parameters.only!(values.flatten(1) + [:indices]) } end # Returns a new scope containing all the storages except specified. @@ -912,9 +939,7 @@ def pluck(*fields) def delete_all(refresh: true) request_body = only(WHERE_STORAGES).render.merge(refresh: refresh) ActiveSupport::Notifications.instrument 'delete_query.chewy', - request: request_body, indexes: _indexes, types: _types, - index: _indexes.one? ? _indexes.first : _indexes, - type: _types.one? ? _types.first : _types do + notification_payload(request: request_body) do if Runtime.version < '5.0' delete_by_query_plugin(request_body) else @@ -933,9 +958,7 @@ def initialize_clone(origin) private def compare_internals(other) - _indexes.sort_by(&:derivable_name) == other._indexes.sort_by(&:derivable_name) && - _types.sort_by(&:derivable_name) == other._types.sort_by(&:derivable_name) && - parameters == other.parameters + parameters == other.parameters end def modify(name, &block) @@ -947,45 +970,43 @@ def chain(&block) end def reset - @response, @render, @render_base, @type_names, @index_names, @loader = nil + @response, @render, @loader = nil end def perform(additional = {}) request_body = render.merge(additional) ActiveSupport::Notifications.instrument 'search_query.chewy', - request: request_body, indexes: _indexes, types: _types, - index: _indexes.one? ? _indexes.first : _indexes, - type: _types.one? ? _types.first : _types do - begin - Chewy.client.search(request_body) - rescue Elasticsearch::Transport::Transport::Errors::NotFound - {} + notification_payload(request: request_body) do + begin + Chewy.client.search(request_body) + rescue Elasticsearch::Transport::Transport::Errors::NotFound + {} + end end - end end - def raw_limit_value - parameters[:limit].value + def notification_payload(additional) + { + indexes: _indices, types: _types, + index: _indices.one? ? _indices.first : _indices, + type: _types.one? ? _types.first : _types + }.merge(additional) end - def raw_offset_value - parameters[:offset].value + def _indices + parameters[:indices].indices end - def index_names - @index_names ||= _indexes.map(&:index_name).uniq + def _types + parameters[:indices].types end - def type_names - @type_names ||= if parameters[:types].value.present? - _types.map(&:type_name).uniq & parameters[:types].value - else - _types.map(&:type_name).uniq - end + def raw_limit_value + parameters[:limit].value end - def render_base - @render_base ||= {index: index_names, type: type_names, body: {}} + def raw_offset_value + parameters[:offset].value end def delete_by_query_plugin(request) @@ -998,7 +1019,10 @@ def delete_by_query_plugin(request) end def loader - @loader ||= Loader.new(indexes: @_indexes, **parameters[:load].value) + @loader ||= Loader.new( + indexes: parameters[:indices].indices, + **parameters[:load].value + ) end def fetch_field(hit, field) diff --git a/lib/chewy/search/scrolling.rb b/lib/chewy/search/scrolling.rb index 733f946a7..b9d1518e6 100644 --- a/lib/chewy/search/scrolling.rb +++ b/lib/chewy/search/scrolling.rb @@ -125,11 +125,9 @@ def scroll_objects(**options) def perform_scroll(body) ActiveSupport::Notifications.instrument 'search_query.chewy', - request: body, indexes: _indexes, types: _types, - index: _indexes.one? ? _indexes.first : _indexes, - type: _types.one? ? _types.first : _types do - Chewy.client.scroll(body) - end + notification_payload(request: body) do + Chewy.client.scroll(body) + end end end end diff --git a/spec/chewy/search/parameters/indices_boost_spec.rb b/spec/chewy/search/parameters/indices_boost_spec.rb deleted file mode 100644 index a96cfe54f..000000000 --- a/spec/chewy/search/parameters/indices_boost_spec.rb +++ /dev/null @@ -1,83 +0,0 @@ -require 'spec_helper' - -describe Chewy::Search::Parameters::IndicesBoost do - subject { described_class.new(index: 1.2) } - - describe '#initialize' do - specify { expect(described_class.new.value).to eq({}) } - specify { expect(described_class.new(nil).value).to eq({}) } - specify { expect(subject.value).to eq('index' => 1.2) } - specify { expect(described_class.new(index: '1.2', other: 2).value).to eq('index' => 1.2, 'other' => 2.0) } - end - - describe '#replace!' do - specify do - expect { subject.replace!(nil) } - .to change { subject.value }.from('index' => 1.2).to({}) - end - - specify do - expect { subject.replace!(other: 3.1) } - .to change { subject.value } - .from('index' => 1.2).to('other' => 3.1) - end - end - - describe '#update!' do - specify do - expect { subject.update!(nil) } - .not_to change { subject.value } - end - - specify do - expect { subject.update!(other: 3.1) } - .to change { subject.value } - .from('index' => 1.2).to('index' => 1.2, 'other' => 3.1) - end - - context do - before { subject.update!(other: 3.1) } - - specify do - expect { subject.update!(index: 1.5) } - .to change { subject.value } - .from('index' => 1.2, 'other' => 3.1).to('index' => 1.5, 'other' => 3.1) - end - - specify do - expect { subject.update!(index: 1.5) } - .to change { subject.value.keys } - .from(%w[index other]).to(%w[other index]) - end - end - end - - describe '#merge!' do - specify do - expect { subject.merge!(described_class.new) } - .not_to change { subject.value } - end - - specify do - expect { subject.merge!(described_class.new(other: 3.1)) } - .to change { subject.value } - .from('index' => 1.2) - .to('index' => 1.2, 'other' => 3.1) - end - end - - describe '#render' do - specify { expect(described_class.new.render).to be_nil } - specify { expect(described_class.new(index: 1.2).render).to eq(indices_boost: [{'index' => 1.2}]) } - specify { expect(described_class.new(index: 1.2, other: 1.3).render).to eq(indices_boost: [{'index' => 1.2}, {'other' => 1.3}]) } - specify { expect(described_class.new(index: 1.2, other: 1.3).tap { |i| i.update!(index: '1.5') }.render).to eq(indices_boost: [{'other' => 1.3}, {'index' => 1.5}]) } - end - - describe '#==' do - specify { expect(described_class.new).to eq(described_class.new) } - specify { expect(described_class.new(index: 1.2)).to eq(described_class.new(index: 1.2)) } - specify { expect(described_class.new(index: 1.2)).not_to eq(described_class.new(other: 1.3)) } - specify { expect(described_class.new(index: 1.2, other: 1.3)).to eq(described_class.new(index: 1.2, other: 1.3)) } - specify { expect(described_class.new(index: 1.2, other: 1.3)).not_to eq(described_class.new(other: 1.3, index: 1.2)) } - end -end diff --git a/spec/chewy/search/parameters/indices_spec.rb b/spec/chewy/search/parameters/indices_spec.rb new file mode 100644 index 000000000..6c47ccc5a --- /dev/null +++ b/spec/chewy/search/parameters/indices_spec.rb @@ -0,0 +1,191 @@ +require 'spec_helper' + +describe Chewy::Search::Parameters::Indices do + before do + stub_index(:first) do + define_type :one + define_type :two + end + + stub_index(:second) do + define_type :three + end + end + + subject { described_class.new(indices: FirstIndex, types: SecondIndex::Three) } + + describe '#initialize' do + specify { expect(described_class.new.value).to eq(indices: [], types: []) } + specify { expect(described_class.new(nil).value).to eq(indices: [], types: []) } + specify { expect(described_class.new(foo: :whatever).value).to eq(indices: [], types: []) } + specify { expect(subject.value).to eq(indices: [FirstIndex], types: [SecondIndex::Three]) } + end + + describe '#replace!' do + specify do + expect { subject.replace!(nil) } + .to change { subject.value } + .from(indices: [FirstIndex], types: [SecondIndex::Three]) + .to(indices: [], types: []) + end + + specify do + expect { subject.replace!(indices: SecondIndex, types: FirstIndex::One) } + .to change { subject.value } + .from(indices: [FirstIndex], types: [SecondIndex::Three]) + .to(indices: [SecondIndex], types: [FirstIndex::One]) + end + end + + describe '#update!' do + specify do + expect { subject.update!(nil) } + .not_to change { subject.value } + end + + specify do + expect { subject.update!(indices: SecondIndex, types: [FirstIndex::One, SecondIndex::Three]) } + .to change { subject.value } + .from(indices: [FirstIndex], types: [SecondIndex::Three]) + .to(indices: [FirstIndex, SecondIndex], types: [SecondIndex::Three, FirstIndex::One]) + end + end + + describe '#merge!' do + specify do + expect { subject.merge!(described_class.new) } + .not_to change { subject.value } + end + + specify do + expect { subject.merge!(described_class.new(indices: SecondIndex, types: [FirstIndex::One, SecondIndex::Three])) } + .to change { subject.value } + .from(indices: [FirstIndex], types: [SecondIndex::Three]) + .to(indices: [FirstIndex, SecondIndex], types: [SecondIndex::Three, FirstIndex::One]) + end + end + + describe '#render' do + specify { expect(described_class.new.render).to eq({}) } + specify do + expect(described_class.new( + indices: FirstIndex + ).render).to eq(index: %w[first], type: %w[one two]) + end + specify do + expect(described_class.new( + indices: :whatever + ).render).to eq(index: %w[whatever]) + end + specify do + expect(described_class.new( + types: FirstIndex::One + ).render).to eq(index: %w[first], type: %w[one]) + end + specify do + expect(described_class.new( + types: :whatever + ).render).to eq({}) + end + specify do + expect(described_class.new( + indices: FirstIndex, types: SecondIndex::Three + ).render).to eq(index: %w[first second], type: %w[one three two]) + end + specify do + expect(described_class.new( + indices: FirstIndex, types: :one + ).render).to eq(index: %w[first], type: %w[one]) + end + specify do + expect(described_class.new( + indices: FirstIndex, types: :whatever + ).render).to eq(index: %w[first], type: %w[one two]) + end + specify do + expect(described_class.new( + indices: FirstIndex, types: %i[one whatever] + ).render).to eq(index: %w[first], type: %w[one]) + end + specify do + expect(described_class.new( + indices: :whatever, types: SecondIndex::Three + ).render).to eq(index: %w[second whatever], type: %w[three]) + end + specify do + expect(described_class.new( + indices: :whatever, types: [SecondIndex::Three, :whatever] + ).render).to eq(index: %w[second whatever], type: %w[three whatever]) + end + specify do + expect(described_class.new( + indices: [FirstIndex, :whatever], types: FirstIndex::One + ).render).to eq(index: %w[first whatever], type: %w[one]) + end + specify do + expect(described_class.new( + indices: FirstIndex, types: [FirstIndex::One, :whatever] + ).render).to eq(index: %w[first], type: %w[one]) + end + specify do + expect(described_class.new( + indices: FirstIndex, types: [SecondIndex::Three, :whatever] + ).render).to eq(index: %w[first second], type: %w[one three two]) + end + specify do + expect(described_class.new( + indices: [FirstIndex, :whatever], types: [FirstIndex::One, :whatever] + ).render).to eq(index: %w[first whatever], type: %w[one whatever]) + end + specify do + expect(described_class.new( + indices: [FirstIndex, :whatever], types: [SecondIndex::Three, FirstIndex::One] + ).render).to eq(index: %w[first second whatever], type: %w[one three]) + end + end + + describe '#==' do + specify { expect(described_class.new).to eq(described_class.new) } + specify do + expect(described_class.new(indices: SecondIndex, types: [SecondIndex::Three, :whatever])) + .to eq(described_class.new(indices: SecondIndex, types: :whatever)) + end + specify do + expect(described_class.new(indices: :first, types: %w[one two])) + .to eq(described_class.new(indices: FirstIndex)) + end + specify do + expect(described_class.new(indices: FirstIndex, types: SecondIndex::Three)) + .not_to eq(described_class.new(indices: FirstIndex)) + end + end + + describe '#indices' do + specify do + expect(described_class.new( + indices: [FirstIndex, :whatever], + types: [SecondIndex::Three, :whatever] + ).indices).to contain_exactly(FirstIndex, SecondIndex) + end + end + + describe '#types' do + specify do + expect(described_class.new( + indices: [FirstIndex, :whatever], + types: [SecondIndex::Three, :whatever] + ).types).to contain_exactly( + FirstIndex::One, FirstIndex::Two, SecondIndex::Three + ) + end + + specify do + expect(described_class.new( + indices: [FirstIndex, :whatever], + types: [FirstIndex::One, SecondIndex::Three, :whatever] + ).types).to contain_exactly( + FirstIndex::One, SecondIndex::Three + ) + end + end +end diff --git a/spec/chewy/search/parameters_spec.rb b/spec/chewy/search/parameters_spec.rb index 1b7859a21..6700b3023 100644 --- a/spec/chewy/search/parameters_spec.rb +++ b/spec/chewy/search/parameters_spec.rb @@ -100,21 +100,21 @@ def storage_object_ids(params) subject { described_class.new(offset: 10, order: 'foo') } specify { expect(subject.render).to eq(body: {from: 10, sort: ['foo']}) } - specify { expect(described_class.new.render).to eq({}) } + specify { expect(described_class.new.render).to eq(body: {}) } context do subject { described_class.new(request_cache: true) } - specify { expect(subject.render).to eq(request_cache: true) } + specify { expect(subject.render).to eq(body: {}, request_cache: true) } end context do subject { described_class.new(search_type: 'query_then_fetch') } - specify { expect(subject.render).to eq(search_type: 'query_then_fetch') } + specify { expect(subject.render).to eq(body: {}, search_type: 'query_then_fetch') } end context do subject { described_class.new(allow_partial_search_results: true) } - specify { expect(subject.render).to eq(allow_partial_search_results: true) } + specify { expect(subject.render).to eq(body: {}, allow_partial_search_results: true) } end context do diff --git a/spec/chewy/search/request_spec.rb b/spec/chewy/search/request_spec.rb index 7d1b0379a..518275034 100644 --- a/spec/chewy/search/request_spec.rb +++ b/spec/chewy/search/request_spec.rb @@ -57,11 +57,11 @@ describe '#inspect' do specify do expect(described_class.new(ProductsIndex).inspect) - .to eq('["products"], :type=>["product", "city", "country"], :body=>{}}>') + .to eq('["products"], :type=>["city", "country", "product"], :body=>{}}>') end specify do expect(ProductsIndex.limit(10).inspect) - .to eq('["products"], :type=>["product", "city", "country"], :body=>{:size=>10}}>') + .to eq('["products"], :type=>["city", "country", "product"], :body=>{:size=>10}}>') end end @@ -225,8 +225,17 @@ specify { expect { subject.docvalue_fields(:foo) }.not_to change { subject.render } } end + describe '#indices' do + specify { expect(described_class.new(:products).render[:index]).to eq(%w[products]) } + specify { expect(subject.indices(:cities).render[:index]).to eq(%w[cities products]) } + specify { expect(subject.indices(CitiesIndex, :whatever).render[:index]).to eq(%w[cities products whatever]) } + specify { expect(subject.indices([CitiesIndex, :products]).render[:index]).to eq(%w[cities products]) } + specify { expect { subject.indices(:cities) }.not_to change { subject.render } } + end + describe '#types' do specify { expect(subject.types(:product).render[:type]).to contain_exactly('product') } + specify { expect(described_class.new(ProductsIndex::City).types(ProductsIndex::Country).render[:type]).to match_array(%w[city country]) } specify { expect(subject.types(%i[product city]).types(nil).render[:type]).to match_array(%w[product city]) } specify { expect(subject.types(:product).types(:product, :city, :something).render[:type]).to match_array(%w[product city]) } specify { expect(subject.types(nil).render[:body]).to be_blank } @@ -422,7 +431,7 @@ expect(outer_payload).to eq( index: ProductsIndex, indexes: [ProductsIndex], - request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}}, + request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}}, type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country], types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country] ) @@ -651,7 +660,7 @@ expect(outer_payload).to eq( index: ProductsIndex, indexes: [ProductsIndex], - request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}, refresh: true}, + request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}, refresh: true}, type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country], types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country] ) @@ -666,7 +675,7 @@ expect(outer_payload).to eq( index: ProductsIndex, indexes: [ProductsIndex], - request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}, refresh: false}, + request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}, refresh: false}, type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country], types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country] )