chewy 5.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2decd9fc56f1c1116f0470c5dfce2fb84b3dbbab25ed42bcc1813f2f91069292
4
- data.tar.gz: 969f6d74cff1f399ffa9752d2559a9affcaa2fe96a63e05cdfe4aa2b0add0af4
3
+ metadata.gz: 55ee493bcdd9f0f001572ffade6a8fef187fd9fd0a87176dd52f07b18db6ec39
4
+ data.tar.gz: 1ed5e0e4d39c7e8b2202051322c7c312078ba644c62f49c320153d6bd2054ee7
5
5
  SHA512:
6
- metadata.gz: e55c97184ed6f171f9383087b792b6261167687acad1add6ca2d5196e87676b1600c54277174e213fd07de6d6d811124a20130ac7ca7ccb5b7077a78a710fbbc
7
- data.tar.gz: b0ceb62da09eea3332e1d67bdca2ab56dfadae6366ca27a8009e502da01057891e7c6a33bfb67f81f4b35119eff550b4390d40e9860e2441065d72c4d30fca78
6
+ metadata.gz: 9fe7425716df8484306cee104f3b3365a9ae36d2e6496b0653b88dd9a13f8e78f48a6d4f579f0e9a2887fb2d36632a1bd970c901d3ba10c87f9fd6405b56327d
7
+ data.tar.gz: f1c81281f0343256c47b20e52bf9363df6bc1c86f3c53e031f4facdb93d223fe6685e74ea3b048b5869a8d0c09ba0a0672c100a303d8b6cabd358e71de141c03
@@ -31,7 +31,7 @@ matrix:
31
31
  - rvm: 2.3.6
32
32
  gemfile: gemfiles/rails.4.2.mongoid.5.2.gemfile
33
33
  env: ES_VERSION=2.4.6
34
- - rvm: 2.5.0
34
+ - rvm: 2.5.1
35
35
  gemfile: gemfiles/rails.5.2.activerecord.gemfile
36
36
  env: ES_VERSION=5.6.7
37
37
  before_install:
data/Appraisals CHANGED
@@ -16,7 +16,7 @@
16
16
  end
17
17
  end
18
18
 
19
- %w[5.0 5.1].each do |activesupport|
19
+ %w[5.0 5.1 5.2].each do |activesupport|
20
20
  appraise "rails.#{activesupport}.activerecord" do
21
21
  gem 'activerecord', "~> #{activesupport}.0"
22
22
  gem 'activesupport', "~> #{activesupport}.0"
@@ -34,22 +34,6 @@ end
34
34
  end
35
35
  end
36
36
 
37
- appraise 'rails.5.2.activerecord' do
38
- gem 'activerecord', '~> 5.2.0.rc1'
39
- gem 'activesupport', '~> 5.2.0.rc1'
40
-
41
- gem 'activejob', '~> 5.2.0.rc1'
42
- gem 'resque', require: false
43
- gem 'shoryuken', require: false
44
- gem 'aws-sdk-sqs', require: false
45
- gem 'sidekiq', require: false
46
-
47
- gem 'kaminari-core', '~> 1.1.0', require: false
48
- gem 'will_paginate', require: false
49
-
50
- gem 'parallel', require: false
51
- end
52
-
53
37
  appraise 'rails.4.2.mongoid.5.2' do
54
38
  gem 'mongoid', '~> 5.2.0'
55
39
  gem 'activesupport', '~> 4.2.0'
@@ -1,5 +1,19 @@
1
1
  # master
2
2
 
3
+ # Version 5.1.0
4
+
5
+ ## Breaking changes
6
+
7
+ * Add support for multiple indices in request (@pyromaniac, #657)
8
+
9
+ * Support `search_type`, `request_cache`, and `allow_partial_search_results` as query string parameters (@mattzollinhofer, #647)
10
+
11
+ ## Changes
12
+
13
+ * Speed up imports when `bulk_size` is specified (@yahooguntu, #606)
14
+
15
+ * Insert `RequestStrategy` middleware before `ActionDispatch::ShowExceptions` (@dck, #682)
16
+
3
17
  # Version 5.0.0
4
18
 
5
19
  ## Breaking changes
data/README.md CHANGED
@@ -34,7 +34,7 @@ Chewy is an ODM and wrapper for [the official Elasticsearch client](https://gith
34
34
  * [Non-block notation](#non-block-notation)
35
35
  * [Designing your own strategies](#designing-your-own-strategies)
36
36
  * [Rails application strategies integration](#rails-application-strategies-integration)
37
- * [ActiveSupport::Notifications support](#activesupport-notifications-support)
37
+ * [ActiveSupport::Notifications support](#activesupportnotifications-support)
38
38
  * [NewRelic integration](#newrelic-integration)
39
39
  * [Search requests](#search-requests)
40
40
  * [Composing requests](#composing-requests)
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec| # rubocop:disable BlockLength
22
22
  spec.add_development_dependency 'elasticsearch-extensions'
23
23
  spec.add_development_dependency 'rake'
24
24
  spec.add_development_dependency 'resque_spec'
25
- spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'rspec', '~> 3.7.0'
26
26
  spec.add_development_dependency 'rspec-collection_matchers'
27
27
  spec.add_development_dependency 'rspec-its'
28
28
  spec.add_development_dependency 'rubocop', '0.52.1'
@@ -2,9 +2,9 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 5.2.0.rc1"
6
- gem "activesupport", "~> 5.2.0.rc1"
7
- gem "activejob", "~> 5.2.0.rc1"
5
+ gem "activerecord", "~> 5.2.0"
6
+ gem "activesupport", "~> 5.2.0"
7
+ gem "activejob", "~> 5.2.0"
8
8
  gem "resque", require: false
9
9
  gem "shoryuken", require: false
10
10
  gem "aws-sdk-sqs", require: false
@@ -40,6 +40,11 @@ module Chewy
40
40
  @criteria = Criteria.new
41
41
  end
42
42
 
43
+ # A compatibility layer with the new request DSL.
44
+ def render
45
+ _request
46
+ end
47
+
43
48
  # Comparation with other query or collection
44
49
  # If other is collection - search request is executed and
45
50
  # result is used for comparation
@@ -68,7 +68,7 @@ module Chewy
68
68
  end
69
69
 
70
70
  initializer 'chewy.request_strategy' do |app|
71
- app.config.middleware.insert_after(Rails::Rack::Logger, RequestStrategy)
71
+ app.config.middleware.insert_before(ActionDispatch::ShowExceptions, RequestStrategy)
72
72
  end
73
73
 
74
74
  initializer 'chewy.add_indices_path' do |_app|
@@ -58,11 +58,7 @@ module Chewy
58
58
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
59
59
  # @return [Hash] the request result
60
60
  def search_string(query, options = {})
61
- options = options.merge(
62
- index: all._indexes.map(&:index_name),
63
- type: all._types.map(&:type_name),
64
- q: query
65
- )
61
+ options = options.merge(all.render.slice(:index, :type).merge(q: query))
66
62
  Chewy.client.search(options)
67
63
  end
68
64
 
@@ -10,6 +10,8 @@ module Chewy
10
10
  # @see Chewy::Search::Request#parameters
11
11
  # @see Chewy::Search::Parameters::Storage
12
12
  class Parameters
13
+ QUERY_STRING_STORAGES = %i[indices search_type request_cache allow_partial_search_results].freeze
14
+
13
15
  # Default storage classes warehouse. It is probably possible to
14
16
  # add your own classes here if necessary, but I'm not sure it will work.
15
17
  #
@@ -101,11 +103,7 @@ module Chewy
101
103
  #
102
104
  # @return [Hash] request body
103
105
  def render
104
- body = @storages.except(:filter, :query, :none).values.inject({}) do |result, storage|
105
- result.merge!(storage.render || {})
106
- end
107
- body.merge!(render_query || {})
108
- body.present? ? {body: body} : {}
106
+ render_query_string_params.merge(render_body)
109
107
  end
110
108
 
111
109
  protected
@@ -126,6 +124,25 @@ module Chewy
126
124
  names
127
125
  end
128
126
 
127
+ def render_query_string_params
128
+ query_string_storages = @storages.select do |storage_name, _|
129
+ QUERY_STRING_STORAGES.include?(storage_name)
130
+ end
131
+
132
+ query_string_storages.values.inject({}) do |result, storage|
133
+ result.merge!(storage.render || {})
134
+ end
135
+ end
136
+
137
+ def render_body
138
+ exceptions = %i[filter query none] + QUERY_STRING_STORAGES
139
+ body = @storages.except(*exceptions).values.inject({}) do |result, storage|
140
+ result.merge!(storage.render || {})
141
+ end
142
+ body.merge!(render_query || {})
143
+ {body: body}
144
+ end
145
+
129
146
  def render_query
130
147
  none = @storages[:none].render
131
148
 
@@ -0,0 +1,27 @@
1
+ require 'chewy/search/parameters/storage'
2
+
3
+ module Chewy
4
+ module Search
5
+ class Parameters
6
+ # Stores boolean value, but has 3 states: `true`, `false` and `nil`.
7
+ #
8
+ # @see Chewy::Search::Request#allow_partial_search_results
9
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/6.4/search-request-body.html#_parameters_4
10
+ class AllowPartialSearchResults < Storage
11
+ # We don't want to render `nil`, but render `true` and `false` values.
12
+ #
13
+ # @see Chewy::Search::Parameters::Storage#render
14
+ # @return [{Symbol => Object}, nil]
15
+ def render
16
+ {self.class.param_name => value} unless value.nil?
17
+ end
18
+
19
+ private
20
+
21
+ def normalize(value)
22
+ !!value unless value.nil?
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,123 @@
1
+ require 'chewy/search/parameters/storage'
2
+
3
+ module Chewy
4
+ module Search
5
+ class Parameters
6
+ # Stores indices and/or types to query.
7
+ # Renders it to lists of string accepted by ElasticSearch
8
+ # API.
9
+ #
10
+ # The semantics behind it can be described in the
11
+ # following statements:
12
+ # 1. If index is added to the storage, no matter, a class
13
+ # or a string/symbol, it gets appended to the list.
14
+ # 2. If type is added to the storage, it filters out types
15
+ # assigned via indices.
16
+ # 3. But when a type class with non-existing index is added,
17
+ # this index got also added to the list if indices.
18
+ # 4. In cases when of an index identifier added, type
19
+ # indetifiers also got appended instead of filtering.
20
+ class Indices < Storage
21
+ # Two index storages are equal if they produce the
22
+ # same output on render.
23
+ #
24
+ # @see Chewy::Search::Parameters::Storage#==
25
+ # @param other [Chewy::Search::Parameters::Storage] any storage instance
26
+ # @return [true, false] the result of comparision
27
+ def ==(other)
28
+ super || other.class == self.class && other.render == render
29
+ end
30
+
31
+ # Just adds types to types and indices to indices.
32
+ #
33
+ # @see Chewy::Search::Parameters::Storage#update!
34
+ # @param other_value [{Symbol => Array<Chewy::Index, Chewy::Type, String, Symbol>}] any acceptable storage value
35
+ # @return [{Symbol => Array<Chewy::Index, Chewy::Type, String, Symbol>}] updated value
36
+ def update!(other_value)
37
+ new_value = normalize(other_value)
38
+
39
+ @value = {
40
+ indices: value[:indices] | new_value[:indices],
41
+ types: value[:types] | new_value[:types]
42
+ }
43
+ end
44
+
45
+ # Returns desired index and type names.
46
+ #
47
+ # @see Chewy::Search::Parameters::Storage#render
48
+ # @return [{Symbol => Array<String>}] rendered value with the parameter name
49
+ def render
50
+ {
51
+ index: index_names.uniq.sort,
52
+ type: type_names.uniq.sort
53
+ }.reject { |_, v| v.blank? }
54
+ end
55
+
56
+ # Returns index classes used for the request.
57
+ # No strings/symbos included.
58
+ #
59
+ # @return [Array<Chewy::Index>] a list of index classes
60
+ def indices
61
+ index_classes | type_classes.map(&:index)
62
+ end
63
+
64
+ # Returns type classes used for the request.
65
+ # No strings/symbos included.
66
+ #
67
+ # @return [Array<Chewy::Type>] a list of types classes
68
+ def types
69
+ type_classes | (index_classes - type_classes.map(&:index)).flat_map(&:types)
70
+ end
71
+
72
+ private
73
+
74
+ def initialize_clone(origin)
75
+ @value = origin.value.dup
76
+ end
77
+
78
+ def normalize(value)
79
+ value ||= {}
80
+
81
+ {
82
+ indices: Array.wrap(value[:indices]).flatten.compact,
83
+ types: Array.wrap(value[:types]).flatten.compact
84
+ }
85
+ end
86
+
87
+ def index_classes
88
+ value[:indices].select do |klass|
89
+ klass.is_a?(Class) && klass < Chewy::Index
90
+ end
91
+ end
92
+
93
+ def index_identifiers
94
+ value[:indices] - index_classes
95
+ end
96
+
97
+ def index_names
98
+ indices.map(&:index_name) | index_identifiers.map(&:to_s)
99
+ end
100
+
101
+ def type_classes
102
+ value[:types].select do |klass|
103
+ klass.is_a?(Class) && klass < Chewy::Type
104
+ end
105
+ end
106
+
107
+ def type_identifiers
108
+ value[:types] - type_classes
109
+ end
110
+
111
+ def type_names
112
+ type_names = types.map(&:type_name)
113
+
114
+ if index_identifiers.blank? && type_identifiers.present?
115
+ (type_names & type_identifiers.map(&:to_s)).presence || type_names
116
+ else
117
+ type_names | type_identifiers.map(&:to_s)
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -1,6 +1,6 @@
1
1
  module Chewy
2
2
  module Search
3
- # The main requset DSL class. Supports multiple index requests.
3
+ # The main request DSL class. Supports multiple index requests.
4
4
  # Supports ES2 and ES5 search API and query DSL.
5
5
  #
6
6
  # @note The class tries to be as immutable as possible,
@@ -26,8 +26,9 @@ module Chewy
26
26
  timeout min_score source stored_fields search_after
27
27
  load script_fields suggest aggs aggregations none
28
28
  indices_boost rescore highlight total total_count
29
- total_entries types delete_all count exists? exist? find pluck
30
- scroll_batches scroll_hits scroll_results scroll_wrappers
29
+ total_entries indices types delete_all count exists?
30
+ exist? find pluck scroll_batches scroll_hits
31
+ scroll_results scroll_wrappers
31
32
  ].to_set.freeze
32
33
  DEFAULT_BATCH_SIZE = 1000
33
34
  DEFAULT_PLUCK_BATCH_SIZE = 10_000
@@ -51,24 +52,32 @@ module Chewy
51
52
  alias_method :total_count, :total
52
53
  alias_method :total_entries, :total
53
54
 
54
- attr_reader :_indexes, :_types
55
-
56
55
  # The class is initialized with the list of chewy indexes and/or
57
56
  # types, which are later used to compose requests.
57
+ # Any symbol/string passed is treated as an index identifier.
58
58
  #
59
59
  # @example
60
+ # Chewy::Search::Request.new(:places)
61
+ # # => <Chewy::Search::Request {:index=>["places"]}>
60
62
  # Chewy::Search::Request.new(PlacesIndex)
61
63
  # # => <Chewy::Search::Request {:index=>["places"], :type=>["city", "country"]}>
62
64
  # Chewy::Search::Request.new(PlacesIndex::City)
63
65
  # # => <Chewy::Search::Request {:index=>["places"], :type=>["city"]}>
64
66
  # Chewy::Search::Request.new(UsersIndex, PlacesIndex::City)
65
67
  # # => <Chewy::Search::Request {:index=>["users", "places"], :type=>["city", "user"]}>
66
- # @param indexes_or_types [Array<Chewy::Index, Chewy::Type>] indexes and types in any combinations
67
- def initialize(*indexes_or_types)
68
- @_types = indexes_or_types.select { |klass| klass < Chewy::Type }
69
- @_indexes = indexes_or_types.select { |klass| klass < Chewy::Index }
70
- @_types |= @_indexes.flat_map(&:types)
71
- @_indexes |= @_types.map(&:index)
68
+ # @param indexes_or_types [Array<Chewy::Index, Chewy::Type, String, Symbol>] indices and types in any combinations
69
+ def initialize(*indices_or_types)
70
+ indices = indices_or_types.reject do |klass|
71
+ klass.is_a?(Class) && klass < Chewy::Type
72
+ end
73
+
74
+ types = indices_or_types.select do |klass|
75
+ klass.is_a?(Class) && klass < Chewy::Type
76
+ end
77
+
78
+ parameters.modify!(:indices) do
79
+ replace!(indices: indices, types: types)
80
+ end
72
81
  end
73
82
 
74
83
  # Underlying parameter storage collection.
@@ -110,7 +119,7 @@ module Chewy
110
119
  #
111
120
  # @return [Hash] request body
112
121
  def render
113
- @render ||= render_base.merge(parameters.render)
122
+ @render ||= parameters.render
114
123
  end
115
124
 
116
125
  # Includes the class name and the result of rendering.
@@ -281,21 +290,39 @@ module Chewy
281
290
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-docvalue-fields.html
282
291
  # @param values [Array<String, Symbol>] field names
283
292
  # @return [Chewy::Search::Request]
293
+ %i[order docvalue_fields].each do |name|
294
+ define_method name do |value, *values|
295
+ modify(name) { update!([value, *values]) }
296
+ end
297
+ end
298
+
299
+ # @!method indices(*values)
300
+ # Modifies `index` request parameter. Updates the storage on every call.
301
+ # Added passed indexes to the parameter list.
302
+ #
303
+ # @example
304
+ # UsersIndex.indices(CitiesIndex).indices(:another)
305
+ # # => <UsersIndex::Query {:index=>["another", "cities", "users"], :type=>["city", "user"]}>
306
+ # @see Chewy::Search::Parameters::Indices
307
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
308
+ # @param values [Array<Chewy::Index, String, Symbol>] index names
309
+ # @return [Chewy::Search::Request]
284
310
  #
285
311
  # @!method types(*values)
286
- # Modifies `types` request parameter. Updates the storage on every call.
287
- # Constrains types passed on the request initialization.
312
+ # Modifies `type` request parameter. Updates the storage on every call.
313
+ # Constrains types passed on the request initialization or adds them
314
+ # to the list depending on circumstances.
288
315
  #
289
316
  # @example
290
- # PlacesIndex.types(:city).types(:unexistent)
291
- # # => <PlacesIndex::Query {:index=>["places"], :type=>["city"]}>
292
- # @see Chewy::Search::Parameters::Types
317
+ # UsersIndex.types(CitiesIndex::City).types(:unexistent)
318
+ # # => <UsersIndex::Query {:index=>["cities", "users"], :type=>["city", "user"]}>
319
+ # @see Chewy::Search::Parameters::Indices
293
320
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
294
- # @param values [Array<String, Symbol>] type names
321
+ # @param values [Array<Chewy::Type, String, Symbol>] type names
295
322
  # @return [Chewy::Search::Request]
296
- %i[order docvalue_fields types].each do |name|
323
+ %i[indices types].each do |name|
297
324
  define_method name do |value, *values|
298
- modify(name) { update!([value, *values]) }
325
+ modify(:indices) { update!(name => [value, *values]) }
299
326
  end
300
327
  end
301
328
 
@@ -759,7 +786,7 @@ module Chewy
759
786
  # @param values [Array<String, Symbol>]
760
787
  # @return [Chewy::Search::Request] new scope
761
788
  def only(*values)
762
- chain { parameters.only!(values.flatten(1)) }
789
+ chain { parameters.only!(values.flatten(1) + [:indices]) }
763
790
  end
764
791
 
765
792
  # Returns a new scope containing all the storages except specified.
@@ -912,9 +939,7 @@ module Chewy
912
939
  def delete_all(refresh: true)
913
940
  request_body = only(WHERE_STORAGES).render.merge(refresh: refresh)
914
941
  ActiveSupport::Notifications.instrument 'delete_query.chewy',
915
- request: request_body, indexes: _indexes, types: _types,
916
- index: _indexes.one? ? _indexes.first : _indexes,
917
- type: _types.one? ? _types.first : _types do
942
+ notification_payload(request: request_body) do
918
943
  if Runtime.version < '5.0'
919
944
  delete_by_query_plugin(request_body)
920
945
  else
@@ -933,9 +958,7 @@ module Chewy
933
958
  private
934
959
 
935
960
  def compare_internals(other)
936
- _indexes.sort_by(&:derivable_name) == other._indexes.sort_by(&:derivable_name) &&
937
- _types.sort_by(&:derivable_name) == other._types.sort_by(&:derivable_name) &&
938
- parameters == other.parameters
961
+ parameters == other.parameters
939
962
  end
940
963
 
941
964
  def modify(name, &block)
@@ -947,45 +970,43 @@ module Chewy
947
970
  end
948
971
 
949
972
  def reset
950
- @response, @render, @render_base, @type_names, @index_names, @loader = nil
973
+ @response, @render, @loader = nil
951
974
  end
952
975
 
953
976
  def perform(additional = {})
954
977
  request_body = render.merge(additional)
955
978
  ActiveSupport::Notifications.instrument 'search_query.chewy',
956
- request: request_body, indexes: _indexes, types: _types,
957
- index: _indexes.one? ? _indexes.first : _indexes,
958
- type: _types.one? ? _types.first : _types do
959
- begin
960
- Chewy.client.search(request_body)
961
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
962
- {}
979
+ notification_payload(request: request_body) do
980
+ begin
981
+ Chewy.client.search(request_body)
982
+ rescue Elasticsearch::Transport::Transport::Errors::NotFound
983
+ {}
984
+ end
963
985
  end
964
- end
965
986
  end
966
987
 
967
- def raw_limit_value
968
- parameters[:limit].value
988
+ def notification_payload(additional)
989
+ {
990
+ indexes: _indices, types: _types,
991
+ index: _indices.one? ? _indices.first : _indices,
992
+ type: _types.one? ? _types.first : _types
993
+ }.merge(additional)
969
994
  end
970
995
 
971
- def raw_offset_value
972
- parameters[:offset].value
996
+ def _indices
997
+ parameters[:indices].indices
973
998
  end
974
999
 
975
- def index_names
976
- @index_names ||= _indexes.map(&:index_name).uniq
1000
+ def _types
1001
+ parameters[:indices].types
977
1002
  end
978
1003
 
979
- def type_names
980
- @type_names ||= if parameters[:types].value.present?
981
- _types.map(&:type_name).uniq & parameters[:types].value
982
- else
983
- _types.map(&:type_name).uniq
984
- end
1004
+ def raw_limit_value
1005
+ parameters[:limit].value
985
1006
  end
986
1007
 
987
- def render_base
988
- @render_base ||= {index: index_names, type: type_names, body: {}}
1008
+ def raw_offset_value
1009
+ parameters[:offset].value
989
1010
  end
990
1011
 
991
1012
  def delete_by_query_plugin(request)
@@ -998,7 +1019,10 @@ module Chewy
998
1019
  end
999
1020
 
1000
1021
  def loader
1001
- @loader ||= Loader.new(indexes: @_indexes, **parameters[:load].value)
1022
+ @loader ||= Loader.new(
1023
+ indexes: parameters[:indices].indices,
1024
+ **parameters[:load].value
1025
+ )
1002
1026
  end
1003
1027
 
1004
1028
  def fetch_field(hit, field)
@@ -125,11 +125,9 @@ module Chewy
125
125
 
126
126
  def perform_scroll(body)
127
127
  ActiveSupport::Notifications.instrument 'search_query.chewy',
128
- request: body, indexes: _indexes, types: _types,
129
- index: _indexes.one? ? _indexes.first : _indexes,
130
- type: _types.one? ? _types.first : _types do
131
- Chewy.client.scroll(body)
132
- end
128
+ notification_payload(request: body) do
129
+ Chewy.client.scroll(body)
130
+ end
133
131
  end
134
132
  end
135
133
  end
@@ -54,15 +54,17 @@ module Chewy
54
54
 
55
55
  def request_bodies(body)
56
56
  if @bulk_size
57
+ serializer = ::Elasticsearch::API.serializer
57
58
  pieces = body.each_with_object(['']) do |piece, result|
58
59
  operation, meta = piece.to_a.first
59
60
  data = meta.delete(:data)
60
- piece = [{operation => meta}, data].compact.map(&:to_json).join("\n")
61
+ piece = serializer.dump(operation => meta)
62
+ piece << "\n" << serializer.dump(data) if data.present?
61
63
 
62
64
  if result.last.bytesize + piece.bytesize > @bulk_size
63
65
  result.push(piece)
64
66
  else
65
- result[-1] = [result[-1], piece].reject(&:blank?).join("\n")
67
+ result[-1].blank? ? (result[-1] = piece) : (result[-1] << "\n" << piece)
66
68
  end
67
69
  end
68
70
  pieces.each { |piece| piece << "\n" }
@@ -31,7 +31,7 @@ module Chewy
31
31
  index_name: @type.index.derivable_name,
32
32
  type_name: @type.type_name,
33
33
  action: action,
34
- references: identify(objects).map(&:to_json).map(&Base64.method(:encode64)),
34
+ references: identify(objects).map { |item| Base64.encode64(::Elasticsearch::API.serializer.dump(item)) },
35
35
  created_at: Time.now.utc
36
36
  }
37
37
  end
@@ -41,7 +41,7 @@ module Chewy
41
41
 
42
42
  %w[_id _type _index].each do |name|
43
43
  define_method name do
44
- data[name]
44
+ _data[name]
45
45
  end
46
46
  end
47
47
 
@@ -1,3 +1,3 @@
1
1
  module Chewy
2
- VERSION = '5.0.0'.freeze
2
+ VERSION = '5.1.0'.freeze
3
3
  end
@@ -0,0 +1,191 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Search::Parameters::Indices do
4
+ before do
5
+ stub_index(:first) do
6
+ define_type :one
7
+ define_type :two
8
+ end
9
+
10
+ stub_index(:second) do
11
+ define_type :three
12
+ end
13
+ end
14
+
15
+ subject { described_class.new(indices: FirstIndex, types: SecondIndex::Three) }
16
+
17
+ describe '#initialize' do
18
+ specify { expect(described_class.new.value).to eq(indices: [], types: []) }
19
+ specify { expect(described_class.new(nil).value).to eq(indices: [], types: []) }
20
+ specify { expect(described_class.new(foo: :whatever).value).to eq(indices: [], types: []) }
21
+ specify { expect(subject.value).to eq(indices: [FirstIndex], types: [SecondIndex::Three]) }
22
+ end
23
+
24
+ describe '#replace!' do
25
+ specify do
26
+ expect { subject.replace!(nil) }
27
+ .to change { subject.value }
28
+ .from(indices: [FirstIndex], types: [SecondIndex::Three])
29
+ .to(indices: [], types: [])
30
+ end
31
+
32
+ specify do
33
+ expect { subject.replace!(indices: SecondIndex, types: FirstIndex::One) }
34
+ .to change { subject.value }
35
+ .from(indices: [FirstIndex], types: [SecondIndex::Three])
36
+ .to(indices: [SecondIndex], types: [FirstIndex::One])
37
+ end
38
+ end
39
+
40
+ describe '#update!' do
41
+ specify do
42
+ expect { subject.update!(nil) }
43
+ .not_to change { subject.value }
44
+ end
45
+
46
+ specify do
47
+ expect { subject.update!(indices: SecondIndex, types: [FirstIndex::One, SecondIndex::Three]) }
48
+ .to change { subject.value }
49
+ .from(indices: [FirstIndex], types: [SecondIndex::Three])
50
+ .to(indices: [FirstIndex, SecondIndex], types: [SecondIndex::Three, FirstIndex::One])
51
+ end
52
+ end
53
+
54
+ describe '#merge!' do
55
+ specify do
56
+ expect { subject.merge!(described_class.new) }
57
+ .not_to change { subject.value }
58
+ end
59
+
60
+ specify do
61
+ expect { subject.merge!(described_class.new(indices: SecondIndex, types: [FirstIndex::One, SecondIndex::Three])) }
62
+ .to change { subject.value }
63
+ .from(indices: [FirstIndex], types: [SecondIndex::Three])
64
+ .to(indices: [FirstIndex, SecondIndex], types: [SecondIndex::Three, FirstIndex::One])
65
+ end
66
+ end
67
+
68
+ describe '#render' do
69
+ specify { expect(described_class.new.render).to eq({}) }
70
+ specify do
71
+ expect(described_class.new(
72
+ indices: FirstIndex
73
+ ).render).to eq(index: %w[first], type: %w[one two])
74
+ end
75
+ specify do
76
+ expect(described_class.new(
77
+ indices: :whatever
78
+ ).render).to eq(index: %w[whatever])
79
+ end
80
+ specify do
81
+ expect(described_class.new(
82
+ types: FirstIndex::One
83
+ ).render).to eq(index: %w[first], type: %w[one])
84
+ end
85
+ specify do
86
+ expect(described_class.new(
87
+ types: :whatever
88
+ ).render).to eq({})
89
+ end
90
+ specify do
91
+ expect(described_class.new(
92
+ indices: FirstIndex, types: SecondIndex::Three
93
+ ).render).to eq(index: %w[first second], type: %w[one three two])
94
+ end
95
+ specify do
96
+ expect(described_class.new(
97
+ indices: FirstIndex, types: :one
98
+ ).render).to eq(index: %w[first], type: %w[one])
99
+ end
100
+ specify do
101
+ expect(described_class.new(
102
+ indices: FirstIndex, types: :whatever
103
+ ).render).to eq(index: %w[first], type: %w[one two])
104
+ end
105
+ specify do
106
+ expect(described_class.new(
107
+ indices: FirstIndex, types: %i[one whatever]
108
+ ).render).to eq(index: %w[first], type: %w[one])
109
+ end
110
+ specify do
111
+ expect(described_class.new(
112
+ indices: :whatever, types: SecondIndex::Three
113
+ ).render).to eq(index: %w[second whatever], type: %w[three])
114
+ end
115
+ specify do
116
+ expect(described_class.new(
117
+ indices: :whatever, types: [SecondIndex::Three, :whatever]
118
+ ).render).to eq(index: %w[second whatever], type: %w[three whatever])
119
+ end
120
+ specify do
121
+ expect(described_class.new(
122
+ indices: [FirstIndex, :whatever], types: FirstIndex::One
123
+ ).render).to eq(index: %w[first whatever], type: %w[one])
124
+ end
125
+ specify do
126
+ expect(described_class.new(
127
+ indices: FirstIndex, types: [FirstIndex::One, :whatever]
128
+ ).render).to eq(index: %w[first], type: %w[one])
129
+ end
130
+ specify do
131
+ expect(described_class.new(
132
+ indices: FirstIndex, types: [SecondIndex::Three, :whatever]
133
+ ).render).to eq(index: %w[first second], type: %w[one three two])
134
+ end
135
+ specify do
136
+ expect(described_class.new(
137
+ indices: [FirstIndex, :whatever], types: [FirstIndex::One, :whatever]
138
+ ).render).to eq(index: %w[first whatever], type: %w[one whatever])
139
+ end
140
+ specify do
141
+ expect(described_class.new(
142
+ indices: [FirstIndex, :whatever], types: [SecondIndex::Three, FirstIndex::One]
143
+ ).render).to eq(index: %w[first second whatever], type: %w[one three])
144
+ end
145
+ end
146
+
147
+ describe '#==' do
148
+ specify { expect(described_class.new).to eq(described_class.new) }
149
+ specify do
150
+ expect(described_class.new(indices: SecondIndex, types: [SecondIndex::Three, :whatever]))
151
+ .to eq(described_class.new(indices: SecondIndex, types: :whatever))
152
+ end
153
+ specify do
154
+ expect(described_class.new(indices: :first, types: %w[one two]))
155
+ .to eq(described_class.new(indices: FirstIndex))
156
+ end
157
+ specify do
158
+ expect(described_class.new(indices: FirstIndex, types: SecondIndex::Three))
159
+ .not_to eq(described_class.new(indices: FirstIndex))
160
+ end
161
+ end
162
+
163
+ describe '#indices' do
164
+ specify do
165
+ expect(described_class.new(
166
+ indices: [FirstIndex, :whatever],
167
+ types: [SecondIndex::Three, :whatever]
168
+ ).indices).to contain_exactly(FirstIndex, SecondIndex)
169
+ end
170
+ end
171
+
172
+ describe '#types' do
173
+ specify do
174
+ expect(described_class.new(
175
+ indices: [FirstIndex, :whatever],
176
+ types: [SecondIndex::Three, :whatever]
177
+ ).types).to contain_exactly(
178
+ FirstIndex::One, FirstIndex::Two, SecondIndex::Three
179
+ )
180
+ end
181
+
182
+ specify do
183
+ expect(described_class.new(
184
+ indices: [FirstIndex, :whatever],
185
+ types: [FirstIndex::One, SecondIndex::Three, :whatever]
186
+ ).types).to contain_exactly(
187
+ FirstIndex::One, SecondIndex::Three
188
+ )
189
+ end
190
+ end
191
+ end
@@ -100,7 +100,22 @@ describe Chewy::Search::Parameters do
100
100
  subject { described_class.new(offset: 10, order: 'foo') }
101
101
 
102
102
  specify { expect(subject.render).to eq(body: {from: 10, sort: ['foo']}) }
103
- specify { expect(described_class.new.render).to eq({}) }
103
+ specify { expect(described_class.new.render).to eq(body: {}) }
104
+
105
+ context do
106
+ subject { described_class.new(request_cache: true) }
107
+ specify { expect(subject.render).to eq(body: {}, request_cache: true) }
108
+ end
109
+
110
+ context do
111
+ subject { described_class.new(search_type: 'query_then_fetch') }
112
+ specify { expect(subject.render).to eq(body: {}, search_type: 'query_then_fetch') }
113
+ end
114
+
115
+ context do
116
+ subject { described_class.new(allow_partial_search_results: true) }
117
+ specify { expect(subject.render).to eq(body: {}, allow_partial_search_results: true) }
118
+ end
104
119
 
105
120
  context do
106
121
  subject { described_class.new(query: {foo: 'bar'}, filter: {moo: 'baz'}) }
@@ -57,11 +57,11 @@ describe Chewy::Search::Request do
57
57
  describe '#inspect' do
58
58
  specify do
59
59
  expect(described_class.new(ProductsIndex).inspect)
60
- .to eq('<Chewy::Search::Request {:index=>["products"], :type=>["product", "city", "country"], :body=>{}}>')
60
+ .to eq('<Chewy::Search::Request {:index=>["products"], :type=>["city", "country", "product"], :body=>{}}>')
61
61
  end
62
62
  specify do
63
63
  expect(ProductsIndex.limit(10).inspect)
64
- .to eq('<ProductsIndex::Query {:index=>["products"], :type=>["product", "city", "country"], :body=>{:size=>10}}>')
64
+ .to eq('<ProductsIndex::Query {:index=>["products"], :type=>["city", "country", "product"], :body=>{:size=>10}}>')
65
65
  end
66
66
  end
67
67
 
@@ -151,13 +151,20 @@ describe Chewy::Search::Request do
151
151
  end
152
152
 
153
153
  describe '#request_cache' do
154
- specify { expect(subject.request_cache(true).render[:body]).to include(request_cache: true) }
155
- specify { expect(subject.request_cache(true).request_cache(false).render[:body]).to include(request_cache: false) }
156
- specify { expect(subject.request_cache(true).request_cache(nil).render[:body]).to be_blank }
154
+ specify { expect(subject.request_cache(true).render).to include(request_cache: true) }
155
+ specify { expect(subject.request_cache(true).request_cache(false).render).to include(request_cache: false) }
156
+ specify { expect(subject.request_cache(true).request_cache(nil).render[:request_cache]).to be_blank }
157
157
  specify { expect { subject.request_cache(true) }.not_to change { subject.render } }
158
158
  end
159
159
 
160
- %i[search_type preference timeout].each do |name|
160
+ describe '#search_type' do
161
+ specify { expect(subject.search_type('foo').render).to include(search_type: 'foo') }
162
+ specify { expect(subject.search_type('foo').search_type('bar').render).to include(search_type: 'bar') }
163
+ specify { expect(subject.search_type('foo').search_type(nil).render[:search_type]).to be_blank }
164
+ specify { expect { subject.search_type('foo') }.not_to change { subject.render } }
165
+ end
166
+
167
+ %i[preference timeout].each do |name|
161
168
  describe "##{name}" do
162
169
  specify { expect(subject.send(name, :foo).render[:body]).to include(name => 'foo') }
163
170
  specify { expect(subject.send(name, :foo).send(name, :bar).render[:body]).to include(name => 'bar') }
@@ -218,8 +225,17 @@ describe Chewy::Search::Request do
218
225
  specify { expect { subject.docvalue_fields(:foo) }.not_to change { subject.render } }
219
226
  end
220
227
 
228
+ describe '#indices' do
229
+ specify { expect(described_class.new(:products).render[:index]).to eq(%w[products]) }
230
+ specify { expect(subject.indices(:cities).render[:index]).to eq(%w[cities products]) }
231
+ specify { expect(subject.indices(CitiesIndex, :whatever).render[:index]).to eq(%w[cities products whatever]) }
232
+ specify { expect(subject.indices([CitiesIndex, :products]).render[:index]).to eq(%w[cities products]) }
233
+ specify { expect { subject.indices(:cities) }.not_to change { subject.render } }
234
+ end
235
+
221
236
  describe '#types' do
222
237
  specify { expect(subject.types(:product).render[:type]).to contain_exactly('product') }
238
+ specify { expect(described_class.new(ProductsIndex::City).types(ProductsIndex::Country).render[:type]).to match_array(%w[city country]) }
223
239
  specify { expect(subject.types(%i[product city]).types(nil).render[:type]).to match_array(%w[product city]) }
224
240
  specify { expect(subject.types(:product).types(:product, :city, :something).render[:type]).to match_array(%w[product city]) }
225
241
  specify { expect(subject.types(nil).render[:body]).to be_blank }
@@ -415,7 +431,7 @@ describe Chewy::Search::Request do
415
431
  expect(outer_payload).to eq(
416
432
  index: ProductsIndex,
417
433
  indexes: [ProductsIndex],
418
- request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}},
434
+ request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}},
419
435
  type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
420
436
  types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
421
437
  )
@@ -644,7 +660,7 @@ describe Chewy::Search::Request do
644
660
  expect(outer_payload).to eq(
645
661
  index: ProductsIndex,
646
662
  indexes: [ProductsIndex],
647
- request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}, refresh: true},
663
+ request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}, refresh: true},
648
664
  type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
649
665
  types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
650
666
  )
@@ -659,7 +675,7 @@ describe Chewy::Search::Request do
659
675
  expect(outer_payload).to eq(
660
676
  index: ProductsIndex,
661
677
  indexes: [ProductsIndex],
662
- request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}, refresh: false},
678
+ request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}, refresh: false},
663
679
  type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
664
680
  types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
665
681
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chewy
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pyromaniac
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-13 00:00:00.000000000 Z
11
+ date: 2019-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -84,16 +84,16 @@ dependencies:
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 3.7.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: 3.7.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec-collection_matchers
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -324,6 +324,7 @@ files:
324
324
  - lib/chewy/search/pagination/will_paginate.rb
325
325
  - lib/chewy/search/parameters.rb
326
326
  - lib/chewy/search/parameters/aggs.rb
327
+ - lib/chewy/search/parameters/allow_partial_search_results.rb
327
328
  - lib/chewy/search/parameters/concerns/bool_storage.rb
328
329
  - lib/chewy/search/parameters/concerns/hash_storage.rb
329
330
  - lib/chewy/search/parameters/concerns/integer_storage.rb
@@ -334,6 +335,7 @@ files:
334
335
  - lib/chewy/search/parameters/explain.rb
335
336
  - lib/chewy/search/parameters/filter.rb
336
337
  - lib/chewy/search/parameters/highlight.rb
338
+ - lib/chewy/search/parameters/indices.rb
337
339
  - lib/chewy/search/parameters/indices_boost.rb
338
340
  - lib/chewy/search/parameters/limit.rb
339
341
  - lib/chewy/search/parameters/load.rb
@@ -450,7 +452,7 @@ files:
450
452
  - spec/chewy/search/parameters/filter_spec.rb
451
453
  - spec/chewy/search/parameters/hash_storage_examples.rb
452
454
  - spec/chewy/search/parameters/highlight_spec.rb
453
- - spec/chewy/search/parameters/indices_boost_spec.rb
455
+ - spec/chewy/search/parameters/indices_spec.rb
454
456
  - spec/chewy/search/parameters/integer_storage_examples.rb
455
457
  - spec/chewy/search/parameters/limit_spec.rb
456
458
  - spec/chewy/search/parameters/load_spec.rb
@@ -534,8 +536,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
534
536
  - !ruby/object:Gem::Version
535
537
  version: '0'
536
538
  requirements: []
537
- rubyforge_project:
538
- rubygems_version: 2.7.4
539
+ rubygems_version: 3.0.6
539
540
  signing_key:
540
541
  specification_version: 4
541
542
  summary: Elasticsearch ODM client wrapper
@@ -592,7 +593,7 @@ test_files:
592
593
  - spec/chewy/search/parameters/filter_spec.rb
593
594
  - spec/chewy/search/parameters/hash_storage_examples.rb
594
595
  - spec/chewy/search/parameters/highlight_spec.rb
595
- - spec/chewy/search/parameters/indices_boost_spec.rb
596
+ - spec/chewy/search/parameters/indices_spec.rb
596
597
  - spec/chewy/search/parameters/integer_storage_examples.rb
597
598
  - spec/chewy/search/parameters/limit_spec.rb
598
599
  - spec/chewy/search/parameters/load_spec.rb
@@ -1,83 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Chewy::Search::Parameters::IndicesBoost do
4
- subject { described_class.new(index: 1.2) }
5
-
6
- describe '#initialize' do
7
- specify { expect(described_class.new.value).to eq({}) }
8
- specify { expect(described_class.new(nil).value).to eq({}) }
9
- specify { expect(subject.value).to eq('index' => 1.2) }
10
- specify { expect(described_class.new(index: '1.2', other: 2).value).to eq('index' => 1.2, 'other' => 2.0) }
11
- end
12
-
13
- describe '#replace!' do
14
- specify do
15
- expect { subject.replace!(nil) }
16
- .to change { subject.value }.from('index' => 1.2).to({})
17
- end
18
-
19
- specify do
20
- expect { subject.replace!(other: 3.1) }
21
- .to change { subject.value }
22
- .from('index' => 1.2).to('other' => 3.1)
23
- end
24
- end
25
-
26
- describe '#update!' do
27
- specify do
28
- expect { subject.update!(nil) }
29
- .not_to change { subject.value }
30
- end
31
-
32
- specify do
33
- expect { subject.update!(other: 3.1) }
34
- .to change { subject.value }
35
- .from('index' => 1.2).to('index' => 1.2, 'other' => 3.1)
36
- end
37
-
38
- context do
39
- before { subject.update!(other: 3.1) }
40
-
41
- specify do
42
- expect { subject.update!(index: 1.5) }
43
- .to change { subject.value }
44
- .from('index' => 1.2, 'other' => 3.1).to('index' => 1.5, 'other' => 3.1)
45
- end
46
-
47
- specify do
48
- expect { subject.update!(index: 1.5) }
49
- .to change { subject.value.keys }
50
- .from(%w[index other]).to(%w[other index])
51
- end
52
- end
53
- end
54
-
55
- describe '#merge!' do
56
- specify do
57
- expect { subject.merge!(described_class.new) }
58
- .not_to change { subject.value }
59
- end
60
-
61
- specify do
62
- expect { subject.merge!(described_class.new(other: 3.1)) }
63
- .to change { subject.value }
64
- .from('index' => 1.2)
65
- .to('index' => 1.2, 'other' => 3.1)
66
- end
67
- end
68
-
69
- describe '#render' do
70
- specify { expect(described_class.new.render).to be_nil }
71
- specify { expect(described_class.new(index: 1.2).render).to eq(indices_boost: [{'index' => 1.2}]) }
72
- specify { expect(described_class.new(index: 1.2, other: 1.3).render).to eq(indices_boost: [{'index' => 1.2}, {'other' => 1.3}]) }
73
- 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}]) }
74
- end
75
-
76
- describe '#==' do
77
- specify { expect(described_class.new).to eq(described_class.new) }
78
- specify { expect(described_class.new(index: 1.2)).to eq(described_class.new(index: 1.2)) }
79
- specify { expect(described_class.new(index: 1.2)).not_to eq(described_class.new(other: 1.3)) }
80
- specify { expect(described_class.new(index: 1.2, other: 1.3)).to eq(described_class.new(index: 1.2, other: 1.3)) }
81
- specify { expect(described_class.new(index: 1.2, other: 1.3)).not_to eq(described_class.new(other: 1.3, index: 1.2)) }
82
- end
83
- end