chewy 6.0.0 → 7.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
- data/.github/dependabot.yml +42 -0
- data/.github/workflows/ruby.yml +48 -0
- data/.rubocop.yml +16 -8
- data/.rubocop_todo.yml +110 -22
- data/CHANGELOG.md +385 -105
- data/CODE_OF_CONDUCT.md +14 -0
- data/CONTRIBUTING.md +63 -0
- data/Gemfile +4 -10
- data/Guardfile +3 -1
- data/README.md +494 -275
- data/chewy.gemspec +5 -20
- data/gemfiles/base.gemfile +12 -0
- data/gemfiles/rails.6.1.activerecord.gemfile +10 -15
- data/gemfiles/rails.7.0.activerecord.gemfile +14 -0
- data/gemfiles/rails.7.1.activerecord.gemfile +14 -0
- data/lib/chewy/config.rb +58 -50
- data/lib/chewy/elastic_client.rb +31 -0
- data/lib/chewy/errors.rb +7 -10
- data/lib/chewy/fields/base.rb +79 -13
- data/lib/chewy/fields/root.rb +4 -14
- data/lib/chewy/index/actions.rb +54 -37
- data/lib/chewy/{type → index}/adapter/active_record.rb +30 -6
- data/lib/chewy/{type → index}/adapter/base.rb +2 -3
- data/lib/chewy/{type → index}/adapter/object.rb +27 -31
- data/lib/chewy/{type → index}/adapter/orm.rb +17 -18
- data/lib/chewy/index/aliases.rb +14 -5
- data/lib/chewy/index/crutch.rb +40 -0
- data/lib/chewy/index/import/bulk_builder.rb +311 -0
- data/lib/chewy/{type → index}/import/bulk_request.rb +6 -7
- data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
- data/lib/chewy/{type → index}/import/routine.rb +18 -17
- data/lib/chewy/{type → index}/import.rb +76 -32
- data/lib/chewy/{type → index}/mapping.rb +29 -34
- data/lib/chewy/index/observe/active_record_methods.rb +87 -0
- data/lib/chewy/index/observe/callback.rb +34 -0
- data/lib/chewy/index/observe.rb +17 -0
- data/lib/chewy/index/specification.rb +1 -0
- data/lib/chewy/{type → index}/syncer.rb +59 -59
- data/lib/chewy/{type → index}/witchcraft.rb +11 -7
- data/lib/chewy/{type → index}/wrapper.rb +2 -2
- data/lib/chewy/index.rb +67 -94
- data/lib/chewy/journal.rb +25 -14
- data/lib/chewy/log_subscriber.rb +5 -1
- data/lib/chewy/minitest/helpers.rb +86 -13
- data/lib/chewy/minitest/search_index_receiver.rb +24 -26
- data/lib/chewy/railtie.rb +6 -20
- data/lib/chewy/rake_helper.rb +169 -113
- data/lib/chewy/rspec/build_query.rb +12 -0
- data/lib/chewy/rspec/helpers.rb +55 -0
- data/lib/chewy/rspec/update_index.rb +55 -44
- data/lib/chewy/rspec.rb +2 -0
- data/lib/chewy/runtime/version.rb +1 -1
- data/lib/chewy/runtime.rb +1 -1
- data/lib/chewy/search/loader.rb +19 -41
- data/lib/chewy/search/parameters/collapse.rb +16 -0
- data/lib/chewy/search/parameters/concerns/query_storage.rb +2 -2
- data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
- data/lib/chewy/search/parameters/indices.rb +13 -58
- data/lib/chewy/search/parameters/knn.rb +16 -0
- data/lib/chewy/search/parameters/order.rb +6 -19
- data/lib/chewy/search/parameters/source.rb +5 -1
- data/lib/chewy/search/parameters/storage.rb +1 -1
- data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
- data/lib/chewy/search/parameters.rb +6 -4
- data/lib/chewy/search/query_proxy.rb +9 -2
- data/lib/chewy/search/request.rb +169 -134
- data/lib/chewy/search/response.rb +5 -5
- data/lib/chewy/search/scoping.rb +7 -8
- data/lib/chewy/search/scrolling.rb +13 -13
- data/lib/chewy/search.rb +9 -19
- data/lib/chewy/stash.rb +19 -30
- data/lib/chewy/strategy/active_job.rb +1 -1
- data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
- data/lib/chewy/strategy/base.rb +10 -0
- data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +151 -0
- data/lib/chewy/strategy/delayed_sidekiq/worker.rb +52 -0
- data/lib/chewy/strategy/delayed_sidekiq.rb +30 -0
- data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
- data/lib/chewy/strategy/sidekiq.rb +2 -1
- data/lib/chewy/strategy.rb +6 -19
- data/lib/chewy/version.rb +1 -1
- data/lib/chewy.rb +39 -86
- data/lib/generators/chewy/install_generator.rb +1 -1
- data/lib/tasks/chewy.rake +36 -32
- data/migration_guide.md +46 -8
- data/spec/chewy/config_spec.rb +14 -39
- data/spec/chewy/elastic_client_spec.rb +26 -0
- data/spec/chewy/fields/base_spec.rb +432 -147
- data/spec/chewy/fields/root_spec.rb +20 -28
- data/spec/chewy/fields/time_fields_spec.rb +5 -5
- data/spec/chewy/index/actions_spec.rb +368 -59
- data/spec/chewy/{type → index}/adapter/active_record_spec.rb +156 -40
- data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
- data/spec/chewy/index/aliases_spec.rb +3 -3
- data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
- data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
- data/spec/chewy/{type → index}/import/journal_builder_spec.rb +9 -19
- data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
- data/spec/chewy/{type → index}/import_spec.rb +164 -98
- data/spec/chewy/index/mapping_spec.rb +135 -0
- data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
- data/spec/chewy/index/observe/callback_spec.rb +139 -0
- data/spec/chewy/index/observe_spec.rb +143 -0
- data/spec/chewy/index/settings_spec.rb +3 -1
- data/spec/chewy/index/specification_spec.rb +20 -30
- data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
- data/spec/chewy/{type → index}/witchcraft_spec.rb +20 -22
- data/spec/chewy/index/wrapper_spec.rb +100 -0
- data/spec/chewy/index_spec.rb +60 -105
- data/spec/chewy/journal_spec.rb +25 -74
- data/spec/chewy/minitest/helpers_spec.rb +123 -15
- data/spec/chewy/minitest/search_index_receiver_spec.rb +28 -30
- data/spec/chewy/multi_search_spec.rb +4 -5
- data/spec/chewy/rake_helper_spec.rb +315 -55
- data/spec/chewy/rspec/build_query_spec.rb +34 -0
- data/spec/chewy/rspec/helpers_spec.rb +61 -0
- data/spec/chewy/rspec/update_index_spec.rb +74 -71
- data/spec/chewy/runtime_spec.rb +2 -2
- data/spec/chewy/search/loader_spec.rb +19 -53
- data/spec/chewy/search/pagination/kaminari_examples.rb +4 -6
- data/spec/chewy/search/pagination/kaminari_spec.rb +2 -2
- data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
- data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
- data/spec/chewy/search/parameters/indices_spec.rb +26 -117
- data/spec/chewy/search/parameters/knn_spec.rb +5 -0
- data/spec/chewy/search/parameters/order_spec.rb +18 -11
- data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
- data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
- data/spec/chewy/search/parameters/source_spec.rb +8 -2
- data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
- data/spec/chewy/search/parameters_spec.rb +18 -4
- data/spec/chewy/search/query_proxy_spec.rb +68 -17
- data/spec/chewy/search/request_spec.rb +292 -110
- data/spec/chewy/search/response_spec.rb +12 -12
- data/spec/chewy/search/scrolling_spec.rb +10 -17
- data/spec/chewy/search_spec.rb +40 -34
- data/spec/chewy/stash_spec.rb +9 -21
- data/spec/chewy/strategy/active_job_spec.rb +16 -16
- data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
- data/spec/chewy/strategy/atomic_spec.rb +9 -10
- data/spec/chewy/strategy/delayed_sidekiq_spec.rb +202 -0
- data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
- data/spec/chewy/strategy/sidekiq_spec.rb +12 -12
- data/spec/chewy/strategy_spec.rb +19 -15
- data/spec/chewy_spec.rb +24 -107
- data/spec/spec_helper.rb +3 -22
- data/spec/support/active_record.rb +25 -7
- metadata +78 -339
- data/.circleci/config.yml +0 -240
- data/Appraisals +0 -81
- data/gemfiles/rails.5.2.activerecord.gemfile +0 -17
- data/gemfiles/rails.5.2.mongoid.6.4.gemfile +0 -17
- data/gemfiles/rails.6.0.activerecord.gemfile +0 -17
- data/gemfiles/sequel.4.45.gemfile +0 -11
- data/lib/chewy/backports/deep_dup.rb +0 -46
- data/lib/chewy/backports/duplicable.rb +0 -91
- data/lib/chewy/search/pagination/will_paginate.rb +0 -43
- data/lib/chewy/search/parameters/types.rb +0 -20
- data/lib/chewy/strategy/resque.rb +0 -27
- data/lib/chewy/strategy/shoryuken.rb +0 -40
- data/lib/chewy/type/actions.rb +0 -43
- data/lib/chewy/type/adapter/mongoid.rb +0 -67
- data/lib/chewy/type/adapter/sequel.rb +0 -93
- data/lib/chewy/type/crutch.rb +0 -32
- data/lib/chewy/type/import/bulk_builder.rb +0 -122
- data/lib/chewy/type/observe.rb +0 -82
- data/lib/chewy/type.rb +0 -120
- data/lib/sequel/plugins/chewy_observe.rb +0 -63
- data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
- data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
- data/spec/chewy/search/parameters/types_spec.rb +0 -5
- data/spec/chewy/strategy/resque_spec.rb +0 -46
- data/spec/chewy/strategy/shoryuken_spec.rb +0 -70
- data/spec/chewy/type/actions_spec.rb +0 -50
- data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
- data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
- data/spec/chewy/type/import/bulk_builder_spec.rb +0 -194
- data/spec/chewy/type/mapping_spec.rb +0 -175
- data/spec/chewy/type/observe_spec.rb +0 -137
- data/spec/chewy/type/wrapper_spec.rb +0 -100
- data/spec/chewy/type_spec.rb +0 -55
- data/spec/support/mongoid.rb +0 -93
- data/spec/support/sequel.rb +0 -80
@@ -1,26 +1,26 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support/core_ext/hash/keys'
|
2
2
|
|
3
3
|
# Rspec matcher `update_index`
|
4
4
|
# To use it - add `require 'chewy/rspec'` to the `spec_helper.rb`
|
5
|
-
# Simple usage - just pass
|
5
|
+
# Simple usage - just pass index as argument.
|
6
6
|
#
|
7
|
-
# specify { expect { user.save! }.to update_index(UsersIndex
|
8
|
-
# specify { expect { user.save! }.to update_index('users
|
9
|
-
# specify { expect { user.save! }.not_to update_index('users
|
7
|
+
# specify { expect { user.save! }.to update_index(UsersIndex) }
|
8
|
+
# specify { expect { user.save! }.to update_index('users') }
|
9
|
+
# specify { expect { user.save! }.not_to update_index('users') }
|
10
10
|
#
|
11
11
|
# This example will pass as well because user1 was reindexed
|
12
12
|
# and nothing was said about user2:
|
13
13
|
#
|
14
14
|
# specify { expect { [user1, user2].map(&:save!) }
|
15
|
-
# .to update_index(UsersIndex
|
15
|
+
# .to update_index(UsersIndex).and_reindex(user1) }
|
16
16
|
#
|
17
17
|
# If you need to specify reindexed records strictly - use `only` chain.
|
18
18
|
# Combined matcher chain methods:
|
19
19
|
#
|
20
20
|
# specify { expect { user1.destroy!; user2.save! } }
|
21
|
-
# .to update_index(UsersIndex
|
21
|
+
# .to update_index(UsersIndex).and_reindex(user2).and_delete(user1) }
|
22
22
|
#
|
23
|
-
RSpec::Matchers.define :update_index do |
|
23
|
+
RSpec::Matchers.define :update_index do |index_name, options = {}| # rubocop:disable Metrics/BlockLength
|
24
24
|
if !respond_to?(:failure_message) && respond_to?(:failure_message_for_should)
|
25
25
|
alias_method :failure_message, :failure_message_for_should
|
26
26
|
alias_method :failure_message_when_negated, :failure_message_for_should_not
|
@@ -28,30 +28,30 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
28
28
|
|
29
29
|
# Specify indexed records by passing record itself or id.
|
30
30
|
#
|
31
|
-
# specify { expect { user.save! }.to update_index(UsersIndex
|
32
|
-
# specify { expect { user.save! }.to update_index(UsersIndex
|
31
|
+
# specify { expect { user.save! }.to update_index(UsersIndex).and_reindex(user)
|
32
|
+
# specify { expect { user.save! }.to update_index(UsersIndex).and_reindex(42)
|
33
33
|
# specify { expect { [user1, user2].map(&:save!) }
|
34
|
-
# .to update_index(UsersIndex
|
34
|
+
# .to update_index(UsersIndex).and_reindex(user1, user2) }
|
35
35
|
# specify { expect { [user1, user2].map(&:save!) }
|
36
|
-
# .to update_index(UsersIndex
|
36
|
+
# .to update_index(UsersIndex).and_reindex(user1).and_reindex(user2) }
|
37
37
|
#
|
38
38
|
# Specify indexing count for every particular record. Useful in case
|
39
39
|
# urgent index updates.
|
40
40
|
#
|
41
41
|
# specify { expect { 2.times { user.save! } }
|
42
|
-
# .to update_index(UsersIndex
|
42
|
+
# .to update_index(UsersIndex).and_reindex(user, times: 2) }
|
43
43
|
#
|
44
44
|
# Specify reindexed attributes. Note that arrays are
|
45
45
|
# compared position-independently.
|
46
46
|
#
|
47
47
|
# specify { expect { user.update_attributes!(name: 'Duke') }
|
48
|
-
# .to update_index(UsersIndex
|
48
|
+
# .to update_index(UsersIndex).and_reindex(user, with: {name: 'Duke'}) }
|
49
49
|
#
|
50
50
|
# You can combine all the options and chain `and_reindex` method to
|
51
51
|
# specify options for every indexed record:
|
52
52
|
#
|
53
53
|
# specify { expect { 2.times { [user1, user2].map { |u| u.update_attributes!(name: "Duke#{u.id}") } } }
|
54
|
-
# .to update_index(UsersIndex
|
54
|
+
# .to update_index(UsersIndex)
|
55
55
|
# .and_reindex(user1, with: {name: 'Duke42'}) }
|
56
56
|
# .and_reindex(user2, times: 1, with: {name: 'Duke43'}) }
|
57
57
|
#
|
@@ -62,8 +62,8 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
62
62
|
|
63
63
|
# Specify deleted records with record itself or id passed.
|
64
64
|
#
|
65
|
-
# specify { expect { user.destroy! }.to update_index(UsersIndex
|
66
|
-
# specify { expect { user.destroy! }.to update_index(UsersIndex
|
65
|
+
# specify { expect { user.destroy! }.to update_index(UsersIndex).and_delete(user) }
|
66
|
+
# specify { expect { user.destroy! }.to update_index(UsersIndex).and_delete(user.id) }
|
67
67
|
#
|
68
68
|
chain(:and_delete) do |*args|
|
69
69
|
@delete ||= {}
|
@@ -73,14 +73,14 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
73
73
|
# Used for specifying than no other records would be indexed or deleted:
|
74
74
|
#
|
75
75
|
# specify { expect { [user1, user2].map(&:save!) }
|
76
|
-
# .to update_index(UsersIndex
|
76
|
+
# .to update_index(UsersIndex).and_reindex(user1, user2).only }
|
77
77
|
# specify { expect { [user1, user2].map(&:destroy!) }
|
78
|
-
# .to update_index(UsersIndex
|
78
|
+
# .to update_index(UsersIndex).and_delete(user1, user2).only }
|
79
79
|
#
|
80
80
|
# This example will fail:
|
81
81
|
#
|
82
82
|
# specify { expect { [user1, user2].map(&:save!) }
|
83
|
-
# .to update_index(UsersIndex
|
83
|
+
# .to update_index(UsersIndex).and_reindex(user1).only }
|
84
84
|
#
|
85
85
|
chain(:only) do |*_args|
|
86
86
|
raise 'Use `only` in conjunction with `and_reindex` or `and_delete`' if @reindex.blank? && @delete.blank?
|
@@ -88,23 +88,30 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
88
88
|
@only = true
|
89
89
|
end
|
90
90
|
|
91
|
+
# Expect import to be called with refresh=false parameter
|
92
|
+
chain(:no_refresh) do
|
93
|
+
@no_refresh = true
|
94
|
+
end
|
95
|
+
|
91
96
|
def supports_block_expectations?
|
92
97
|
true
|
93
98
|
end
|
94
99
|
|
95
|
-
match do |block| # rubocop:disable BlockLength
|
100
|
+
match do |block| # rubocop:disable Metrics/BlockLength
|
96
101
|
@reindex ||= {}
|
97
102
|
@delete ||= {}
|
98
103
|
@missed_reindex = []
|
99
104
|
@missed_delete = []
|
100
105
|
|
101
|
-
|
106
|
+
index = Chewy.derive_name(index_name)
|
102
107
|
if defined?(Mocha) && RSpec.configuration.mock_framework.to_s == 'RSpec::Core::MockingAdapters::Mocha'
|
103
|
-
|
108
|
+
params_matcher = @no_refresh ? has_entry(refresh: false) : any_parameters
|
109
|
+
Chewy::Index::Import::BulkRequest.stubs(:new).with(index, params_matcher).returns(mock_bulk_request)
|
104
110
|
else
|
105
|
-
mocked_already =
|
106
|
-
allow(Chewy::
|
107
|
-
|
111
|
+
mocked_already = RSpec::Mocks.space.proxy_for(Chewy::Index::Import::BulkRequest).method_double_if_exists_for_message(:new)
|
112
|
+
allow(Chewy::Index::Import::BulkRequest).to receive(:new).and_call_original unless mocked_already
|
113
|
+
params_matcher = @no_refresh ? hash_including(refresh: false) : any_args
|
114
|
+
allow(Chewy::Index::Import::BulkRequest).to receive(:new).with(index, params_matcher).and_return(mock_bulk_request)
|
108
115
|
end
|
109
116
|
|
110
117
|
Chewy.strategy(options[:strategy] || :atomic) { block.call }
|
@@ -127,13 +134,13 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
127
134
|
end
|
128
135
|
|
129
136
|
@reindex.each_value do |document|
|
130
|
-
document[:match_count] = (!document[:expected_count] && document[:real_count]
|
137
|
+
document[:match_count] = (!document[:expected_count] && (document[:real_count]).positive?) ||
|
131
138
|
(document[:expected_count] && document[:expected_count] == document[:real_count])
|
132
139
|
document[:match_attributes] = document[:expected_attributes].blank? ||
|
133
140
|
compare_attributes(document[:expected_attributes], document[:real_attributes])
|
134
141
|
end
|
135
142
|
@delete.each_value do |document|
|
136
|
-
document[:match_count] = (!document[:expected_count] && document[:real_count]
|
143
|
+
document[:match_count] = (!document[:expected_count] && (document[:real_count]).positive?) ||
|
137
144
|
(document[:expected_count] && document[:expected_count] == document[:real_count])
|
138
145
|
end
|
139
146
|
|
@@ -142,13 +149,13 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
142
149
|
@delete.all? { |_, document| document[:match_count] }
|
143
150
|
end
|
144
151
|
|
145
|
-
failure_message do # rubocop:disable BlockLength
|
152
|
+
failure_message do # rubocop:disable Metrics/BlockLength
|
146
153
|
output = ''
|
147
154
|
|
148
155
|
if mock_bulk_request.updates.none?
|
149
|
-
output << "Expected index `#{
|
156
|
+
output << "Expected index `#{index_name}` to be updated#{' with no refresh' if @no_refresh}, but it was not\n"
|
150
157
|
elsif @missed_reindex.present? || @missed_delete.present?
|
151
|
-
message = "Expected index `#{
|
158
|
+
message = "Expected index `#{index_name}` "
|
152
159
|
message << [
|
153
160
|
("to update documents #{@reindex.keys}" if @reindex.present?),
|
154
161
|
("to delete documents #{@delete.keys}" if @delete.present?)
|
@@ -166,9 +173,13 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
166
173
|
output << @reindex.each.with_object('') do |(id, document), result|
|
167
174
|
unless document[:match_count] && document[:match_attributes]
|
168
175
|
result << "Expected document with id `#{id}` to be reindexed"
|
169
|
-
if document[:real_count]
|
170
|
-
|
171
|
-
|
176
|
+
if (document[:real_count]).positive?
|
177
|
+
if document[:expected_count] && !document[:match_count]
|
178
|
+
result << "\n #{document[:expected_count]} times, but was reindexed #{document[:real_count]} times"
|
179
|
+
end
|
180
|
+
if document[:expected_attributes].present? && !document[:match_attributes]
|
181
|
+
result << "\n with #{document[:expected_attributes]}, but it was reindexed with #{document[:real_attributes]}"
|
182
|
+
end
|
172
183
|
else
|
173
184
|
result << ', but it was not'
|
174
185
|
end
|
@@ -179,11 +190,11 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
179
190
|
output << @delete.each.with_object('') do |(id, document), result|
|
180
191
|
unless document[:match_count]
|
181
192
|
result << "Expected document with id `#{id}` to be deleted"
|
182
|
-
result << if document[:real_count]
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
193
|
+
result << if (document[:real_count]).positive? && document[:expected_count]
|
194
|
+
"\n #{document[:expected_count]} times, but was deleted #{document[:real_count]} times"
|
195
|
+
else
|
196
|
+
', but it was not'
|
197
|
+
end
|
187
198
|
result << "\n"
|
188
199
|
end
|
189
200
|
end
|
@@ -193,9 +204,9 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
193
204
|
|
194
205
|
failure_message_when_negated do
|
195
206
|
if mock_bulk_request.updates.present?
|
196
|
-
"Expected index `#{
|
197
|
-
|
198
|
-
|
207
|
+
"Expected index `#{index_name}` not to be updated, but it was with #{mock_bulk_request.updates.map(&:values).flatten.group_by { |documents| documents[:_id] }.map do |id, documents|
|
208
|
+
"\n document id `#{id}` (#{documents.count} times)"
|
209
|
+
end.join}\n"
|
199
210
|
end
|
200
211
|
end
|
201
212
|
|
@@ -209,7 +220,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
209
220
|
expected_count = options[:times] || options[:count]
|
210
221
|
expected_attributes = (options[:with] || options[:attributes] || {}).deep_symbolize_keys
|
211
222
|
|
212
|
-
|
223
|
+
args.flatten.to_h do |document|
|
213
224
|
id = document.respond_to?(:id) ? document.id.to_s : document.to_s
|
214
225
|
[id, {
|
215
226
|
document: document,
|
@@ -218,7 +229,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
|
|
218
229
|
real_count: 0,
|
219
230
|
real_attributes: {}
|
220
231
|
}]
|
221
|
-
end
|
232
|
+
end
|
222
233
|
end
|
223
234
|
|
224
235
|
def compare_attributes(expected, real)
|
data/lib/chewy/rspec.rb
CHANGED
@@ -5,7 +5,7 @@ module Chewy
|
|
5
5
|
attr_reader :major, :minor, :patch
|
6
6
|
|
7
7
|
def initialize(version)
|
8
|
-
@major, @minor, @patch = *(version.to_s.split('.', 3) + [0] * 3).first(3).map(&:to_i)
|
8
|
+
@major, @minor, @patch = *(version.to_s.split('.', 3) + ([0] * 3)).first(3).map(&:to_i)
|
9
9
|
end
|
10
10
|
|
11
11
|
def to_s
|
data/lib/chewy/runtime.rb
CHANGED
@@ -3,7 +3,7 @@ require 'chewy/runtime/version'
|
|
3
3
|
module Chewy
|
4
4
|
module Runtime
|
5
5
|
def self.version
|
6
|
-
|
6
|
+
Chewy.current[:chewy_runtime_version] ||= Version.new(Chewy.client.info['version']['number'])
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
data/lib/chewy/search/loader.rb
CHANGED
@@ -3,36 +3,28 @@ module Chewy
|
|
3
3
|
# This class is used for two different purposes: load ORM/ODM
|
4
4
|
# source objects.
|
5
5
|
#
|
6
|
-
# @see Chewy::
|
6
|
+
# @see Chewy::Index::Import
|
7
7
|
# @see Chewy::Search::Request#load
|
8
8
|
# @see Chewy::Search::Response#objects
|
9
9
|
# @see Chewy::Search::Scrolling#scroll_objects
|
10
10
|
class Loader
|
11
|
-
# @param indexes [Array<Chewy::Index>] list of indexes to lookup
|
12
|
-
# @param only [Array<String, Symbol>] list of selected type names to load
|
13
|
-
# @param except [Array<String, Symbol>] list of type names which will not be loaded
|
11
|
+
# @param indexes [Array<Chewy::Index>] list of indexes to lookup
|
14
12
|
# @param options [Hash] adapter-specific load options
|
15
|
-
# @see Chewy::
|
16
|
-
def initialize(indexes: [],
|
13
|
+
# @see Chewy::Index::Adapter::Base#load
|
14
|
+
def initialize(indexes: [], **options)
|
17
15
|
@indexes = indexes
|
18
|
-
@only = Array.wrap(only).map(&:to_s)
|
19
|
-
@except = Array.wrap(except).map(&:to_s)
|
20
16
|
@options = options
|
21
17
|
end
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
index_class = derive_index(index)
|
33
|
-
raise Chewy::UnderivableType, "Can not find index named `#{index}`" unless index_class
|
34
|
-
index_class.type_hash[type] or raise Chewy::UnderivableType, "Index `#{index}` doesn`t have type named `#{type}`"
|
35
|
-
end
|
19
|
+
def derive_index(index_name)
|
20
|
+
index = (@derive_index ||= {})[index_name] ||= indexes_hash[index_name] ||
|
21
|
+
indexes_hash[indexes_hash.keys.sort_by(&:length)
|
22
|
+
.reverse.detect do |name|
|
23
|
+
index_name.match(/#{name}(_.+|\z)/)
|
24
|
+
end]
|
25
|
+
raise Chewy::UndefinedIndex, "Can not find index named `#{index}`" unless index
|
26
|
+
|
27
|
+
index
|
36
28
|
end
|
37
29
|
|
38
30
|
# For each passed hit this method loads an ORM/ORD source object
|
@@ -41,19 +33,17 @@ module Chewy
|
|
41
33
|
# will be returned at the corresponding position in array.
|
42
34
|
#
|
43
35
|
# Records/documents are loaded in an efficient manner, performing
|
44
|
-
# a single query for each
|
36
|
+
# a single query for each index present.
|
45
37
|
#
|
46
38
|
# @param hits [Array<Hash>] ES hits array
|
47
39
|
# @return [Array<Object, nil>] the array of corresponding ORM/ODM objects
|
48
40
|
def load(hits)
|
49
|
-
hit_groups = hits.group_by { |hit|
|
50
|
-
loaded_objects = hit_groups.each_with_object({}) do |(
|
51
|
-
|
52
|
-
|
53
|
-
type = derive_type(index_name, type_name)
|
41
|
+
hit_groups = hits.group_by { |hit| hit['_index'] }
|
42
|
+
loaded_objects = hit_groups.each_with_object({}) do |(index_name, hit_group), result|
|
43
|
+
index = derive_index(index_name)
|
54
44
|
ids = hit_group.map { |hit| hit['_id'] }
|
55
|
-
loaded =
|
56
|
-
loaded ||= hit_group.map { |hit|
|
45
|
+
loaded = index.adapter.load(ids, **@options.merge(_index: index.base_name))
|
46
|
+
loaded ||= hit_group.map { |hit| index.build(hit) }
|
57
47
|
|
58
48
|
result.merge!(hit_group.zip(loaded).to_h)
|
59
49
|
end
|
@@ -63,21 +53,9 @@ module Chewy
|
|
63
53
|
|
64
54
|
private
|
65
55
|
|
66
|
-
def derive_index(index_name)
|
67
|
-
(@derive_index ||= {})[index_name] ||= indexes_hash[index_name] ||
|
68
|
-
indexes_hash[indexes_hash.keys.sort_by(&:length)
|
69
|
-
.reverse.detect do |name|
|
70
|
-
index_name.match(/#{name}(_.+|\z)/)
|
71
|
-
end]
|
72
|
-
end
|
73
|
-
|
74
56
|
def indexes_hash
|
75
57
|
@indexes_hash ||= @indexes.index_by(&:index_name)
|
76
58
|
end
|
77
|
-
|
78
|
-
def skip_type?(type_name)
|
79
|
-
@except.include?(type_name) || @only.present? && !@only.include?(type_name)
|
80
|
-
end
|
81
59
|
end
|
82
60
|
end
|
83
61
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'chewy/search/parameters/storage'
|
2
|
+
|
3
|
+
module Chewy
|
4
|
+
module Search
|
5
|
+
class Parameters
|
6
|
+
# Just a standard hash storage. Nothing to see here.
|
7
|
+
#
|
8
|
+
# @see Chewy::Search::Parameters::HashStorage
|
9
|
+
# @see Chewy::Search::Request#collapse
|
10
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html
|
11
|
+
class Collapse < Storage
|
12
|
+
include HashStorage
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -5,7 +5,7 @@ module Chewy
|
|
5
5
|
class Parameters
|
6
6
|
# This is a basic storage implementation for `query`, `filter`
|
7
7
|
# and `post_filter` storages. It uses `bool` query as a root
|
8
|
-
# structure for each of them. The `bool` root is
|
8
|
+
# structure for each of them. The `bool` root is omitted on
|
9
9
|
# rendering if there is only a single query in the `must` or
|
10
10
|
# `should` array. Besides the standard parameter storage
|
11
11
|
# capabilities, it provides specialized methods for the `bool`
|
@@ -86,7 +86,7 @@ module Chewy
|
|
86
86
|
def reduce
|
87
87
|
value = to_h
|
88
88
|
.reject { |_, v| v.blank? }
|
89
|
-
.
|
89
|
+
.transform_values { |v| v.is_a?(Array) && v.one? ? v.first : v }
|
90
90
|
value.delete(:minimum_should_match) if should.empty?
|
91
91
|
value
|
92
92
|
end
|
@@ -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#ignore_unavailable
|
9
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-index.html#multi-index
|
10
|
+
class IgnoreUnavailable < 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
|
@@ -3,70 +3,48 @@ require 'chewy/search/parameters/storage'
|
|
3
3
|
module Chewy
|
4
4
|
module Search
|
5
5
|
class Parameters
|
6
|
-
# Stores indices
|
6
|
+
# Stores indices to query.
|
7
7
|
# Renders it to lists of string accepted by ElasticSearch
|
8
8
|
# API.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
# following statements:
|
12
|
-
# 1. If index is added to the storage, no matter, a class
|
10
|
+
# If index is added to the storage, no matter, a class
|
13
11
|
# 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
12
|
class Indices < Storage
|
21
13
|
# Two index storages are equal if they produce the
|
22
14
|
# same output on render.
|
23
15
|
#
|
24
16
|
# @see Chewy::Search::Parameters::Storage#==
|
25
17
|
# @param other [Chewy::Search::Parameters::Storage] any storage instance
|
26
|
-
# @return [true, false] the result of
|
18
|
+
# @return [true, false] the result of comparison
|
27
19
|
def ==(other)
|
28
|
-
super || other.class == self.class && other.render == render
|
20
|
+
super || (other.class == self.class && other.render == render)
|
29
21
|
end
|
30
22
|
|
31
|
-
# Just adds
|
23
|
+
# Just adds indices to indices.
|
32
24
|
#
|
33
25
|
# @see Chewy::Search::Parameters::Storage#update!
|
34
|
-
# @param other_value [{Symbol => Array<Chewy::Index,
|
35
|
-
# @return [{Symbol => Array<Chewy::Index,
|
26
|
+
# @param other_value [{Symbol => Array<Chewy::Index, String, Symbol>}] any acceptable storage value
|
27
|
+
# @return [{Symbol => Array<Chewy::Index, String, Symbol>}] updated value
|
36
28
|
def update!(other_value)
|
37
29
|
new_value = normalize(other_value)
|
38
30
|
|
39
|
-
@value = {
|
40
|
-
indices: value[:indices] | new_value[:indices],
|
41
|
-
types: value[:types] | new_value[:types]
|
42
|
-
}
|
31
|
+
@value = {indices: value[:indices] | new_value[:indices]}
|
43
32
|
end
|
44
33
|
|
45
|
-
# Returns desired index
|
34
|
+
# Returns desired index names.
|
46
35
|
#
|
47
36
|
# @see Chewy::Search::Parameters::Storage#render
|
48
37
|
# @return [{Symbol => Array<String>}] rendered value with the parameter name
|
49
38
|
def render
|
50
|
-
{
|
51
|
-
index: index_names.uniq.sort,
|
52
|
-
type: type_names.uniq.sort
|
53
|
-
}.reject { |_, v| v.blank? }
|
39
|
+
{index: index_names.uniq.sort}.reject { |_, v| v.blank? }
|
54
40
|
end
|
55
41
|
|
56
42
|
# Returns index classes used for the request.
|
57
|
-
# No strings/
|
43
|
+
# No strings/symbols included.
|
58
44
|
#
|
59
45
|
# @return [Array<Chewy::Index>] a list of index classes
|
60
46
|
def indices
|
61
|
-
index_classes
|
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)
|
47
|
+
index_classes
|
70
48
|
end
|
71
49
|
|
72
50
|
private
|
@@ -78,10 +56,7 @@ module Chewy
|
|
78
56
|
def normalize(value)
|
79
57
|
value ||= {}
|
80
58
|
|
81
|
-
{
|
82
|
-
indices: Array.wrap(value[:indices]).flatten.compact,
|
83
|
-
types: Array.wrap(value[:types]).flatten.compact
|
84
|
-
}
|
59
|
+
{indices: Array.wrap(value[:indices]).flatten.compact}
|
85
60
|
end
|
86
61
|
|
87
62
|
def index_classes
|
@@ -97,26 +72,6 @@ module Chewy
|
|
97
72
|
def index_names
|
98
73
|
indices.map(&:index_name) | index_identifiers.map(&:to_s)
|
99
74
|
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
75
|
end
|
121
76
|
end
|
122
77
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'chewy/search/parameters/storage'
|
2
|
+
|
3
|
+
module Chewy
|
4
|
+
module Search
|
5
|
+
class Parameters
|
6
|
+
# Just a standard hash storage. Nothing to see here.
|
7
|
+
#
|
8
|
+
# @see Chewy::Search::Parameters::HashStorage
|
9
|
+
# @see Chewy::Search::Request#knn
|
10
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html
|
11
|
+
class Knn < Storage
|
12
|
+
include HashStorage
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -17,7 +17,7 @@ module Chewy
|
|
17
17
|
# @param other_value [Object] any acceptable storage value
|
18
18
|
# @return [Object] updated value
|
19
19
|
def update!(other_value)
|
20
|
-
value.
|
20
|
+
value.concat(normalize(other_value))
|
21
21
|
end
|
22
22
|
|
23
23
|
# Size requires specialized rendering logic, it should return
|
@@ -28,20 +28,7 @@ module Chewy
|
|
28
28
|
def render
|
29
29
|
return if value.blank?
|
30
30
|
|
31
|
-
sort
|
32
|
-
options ? {field => options} : field
|
33
|
-
end
|
34
|
-
{sort: sort}
|
35
|
-
end
|
36
|
-
|
37
|
-
# Comparison also reqires additional logic. Hashes are compared
|
38
|
-
# orderlessly, but for `sort` parameter oder is important, so we
|
39
|
-
# compare hash key collections additionally.
|
40
|
-
#
|
41
|
-
# @see Chewy::Search::Parameters::Storage#==
|
42
|
-
# @return [true, false]
|
43
|
-
def ==(other)
|
44
|
-
super && value.keys == other.value.keys
|
31
|
+
{sort: value}
|
45
32
|
end
|
46
33
|
|
47
34
|
private
|
@@ -49,13 +36,13 @@ module Chewy
|
|
49
36
|
def normalize(value)
|
50
37
|
case value
|
51
38
|
when Array
|
52
|
-
value.each_with_object(
|
53
|
-
res.
|
39
|
+
value.each_with_object([]) do |sv, res|
|
40
|
+
res.concat(normalize(sv))
|
54
41
|
end
|
55
42
|
when Hash
|
56
|
-
value.stringify_keys
|
43
|
+
[value.stringify_keys]
|
57
44
|
else
|
58
|
-
value.present? ?
|
45
|
+
value.present? ? [value.to_s] : []
|
59
46
|
end
|
60
47
|
end
|
61
48
|
end
|
@@ -17,7 +17,11 @@ module Chewy
|
|
17
17
|
# In case of hash, respective values are concatenated as well.
|
18
18
|
#
|
19
19
|
# @see Chewy::Search::Parameters::Storage#update!
|
20
|
-
# @param other_value
|
20
|
+
# @param other_value
|
21
|
+
# [true, false, {
|
22
|
+
# Symbol => Array<String, Symbol>, String, Symbol},
|
23
|
+
# Array<String, Symbol>, String, Symbol
|
24
|
+
# ] any acceptable storage value
|
21
25
|
# @return [{Symbol => Array<String>, true, false}] updated value
|
22
26
|
def update!(other_value)
|
23
27
|
new_value = normalize(other_value)
|
@@ -35,7 +35,7 @@ module Chewy
|
|
35
35
|
# @param other [Chewy::Search::Parameters::Storage] any storage instance
|
36
36
|
# @return [true, false] the result of comparision
|
37
37
|
def ==(other)
|
38
|
-
super || other.class == self.class && other.value == value
|
38
|
+
super || (other.class == self.class && other.value == value)
|
39
39
|
end
|
40
40
|
|
41
41
|
# Replaces current value with normalized provided one. Doesn't
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'chewy/search/parameters/storage'
|
2
|
+
|
3
|
+
module Chewy
|
4
|
+
module Search
|
5
|
+
class Parameters
|
6
|
+
# Just a standard boolean storage, nothing to see here.
|
7
|
+
#
|
8
|
+
# @see Chewy::Search::Parameters::BoolStorage
|
9
|
+
# @see Chewy::Search::Request#track_total_hits
|
10
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-your-data.html#track-total-hits
|
11
|
+
class TrackTotalHits < Storage
|
12
|
+
include BoolStorage
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|