chewy 8.0.0 → 8.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.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +30 -16
  4. data/lib/chewy/errors.rb +3 -0
  5. data/lib/chewy/fields/root.rb +3 -3
  6. data/lib/chewy/index/crutch.rb +12 -2
  7. data/lib/chewy/index/import/bulk_builder.rb +4 -3
  8. data/lib/chewy/index/import/routine.rb +2 -1
  9. data/lib/chewy/index/import.rb +4 -4
  10. data/lib/chewy/index/witchcraft.rb +24 -8
  11. data/lib/chewy/multi_search.rb +1 -1
  12. data/lib/chewy/search/parameters/runtime_mappings.rb +14 -0
  13. data/lib/chewy/search/request.rb +18 -2
  14. data/lib/chewy/search/scrolling.rb +14 -6
  15. data/lib/chewy/stash.rb +10 -6
  16. data/lib/chewy/version.rb +1 -1
  17. metadata +5 -131
  18. data/.github/CODEOWNERS +0 -1
  19. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -39
  20. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  21. data/.github/PULL_REQUEST_TEMPLATE.md +0 -16
  22. data/.github/dependabot.yml +0 -42
  23. data/.github/workflows/ruby.yml +0 -61
  24. data/.gitignore +0 -22
  25. data/.rspec +0 -2
  26. data/.rubocop.yml +0 -64
  27. data/.rubocop_todo.yml +0 -225
  28. data/.yardopts +0 -5
  29. data/CODE_OF_CONDUCT.md +0 -14
  30. data/CONTRIBUTING.md +0 -63
  31. data/Gemfile +0 -22
  32. data/Guardfile +0 -25
  33. data/Rakefile +0 -17
  34. data/chewy.gemspec +0 -24
  35. data/docker-compose.yml +0 -14
  36. data/docs/README.md +0 -16
  37. data/docs/configuration.md +0 -440
  38. data/docs/import.md +0 -122
  39. data/docs/indexing.md +0 -329
  40. data/docs/querying.md +0 -72
  41. data/docs/rake_tasks.md +0 -108
  42. data/docs/testing.md +0 -41
  43. data/docs/troubleshooting.md +0 -101
  44. data/filters +0 -78
  45. data/gemfiles/base.gemfile +0 -12
  46. data/gemfiles/rails.7.2.activerecord.gemfile +0 -14
  47. data/gemfiles/rails.8.0.activerecord.gemfile +0 -14
  48. data/migration_guide.md +0 -56
  49. data/spec/chewy/config_spec.rb +0 -110
  50. data/spec/chewy/elastic_client_spec.rb +0 -26
  51. data/spec/chewy/fields/base_spec.rb +0 -700
  52. data/spec/chewy/fields/root_spec.rb +0 -142
  53. data/spec/chewy/fields/time_fields_spec.rb +0 -28
  54. data/spec/chewy/index/actions_spec.rb +0 -851
  55. data/spec/chewy/index/adapter/active_record_spec.rb +0 -663
  56. data/spec/chewy/index/adapter/object_spec.rb +0 -243
  57. data/spec/chewy/index/aliases_spec.rb +0 -49
  58. data/spec/chewy/index/import/bulk_builder_spec.rb +0 -494
  59. data/spec/chewy/index/import/bulk_request_spec.rb +0 -95
  60. data/spec/chewy/index/import/journal_builder_spec.rb +0 -87
  61. data/spec/chewy/index/import/routine_spec.rb +0 -110
  62. data/spec/chewy/index/import_spec.rb +0 -615
  63. data/spec/chewy/index/mapping_spec.rb +0 -135
  64. data/spec/chewy/index/observe/active_record_methods_spec.rb +0 -68
  65. data/spec/chewy/index/observe/callback_spec.rb +0 -139
  66. data/spec/chewy/index/observe_spec.rb +0 -143
  67. data/spec/chewy/index/settings_spec.rb +0 -136
  68. data/spec/chewy/index/specification_spec.rb +0 -156
  69. data/spec/chewy/index/syncer_spec.rb +0 -118
  70. data/spec/chewy/index/witchcraft_spec.rb +0 -245
  71. data/spec/chewy/index/wrapper_spec.rb +0 -100
  72. data/spec/chewy/index_spec.rb +0 -269
  73. data/spec/chewy/journal_spec.rb +0 -223
  74. data/spec/chewy/minitest/helpers_spec.rb +0 -194
  75. data/spec/chewy/minitest/search_index_receiver_spec.rb +0 -120
  76. data/spec/chewy/multi_search_spec.rb +0 -84
  77. data/spec/chewy/rake_helper_spec.rb +0 -656
  78. data/spec/chewy/repository_spec.rb +0 -50
  79. data/spec/chewy/rspec/build_query_spec.rb +0 -34
  80. data/spec/chewy/rspec/helpers_spec.rb +0 -61
  81. data/spec/chewy/rspec/update_index_spec.rb +0 -313
  82. data/spec/chewy/runtime/version_spec.rb +0 -48
  83. data/spec/chewy/runtime_spec.rb +0 -9
  84. data/spec/chewy/search/loader_spec.rb +0 -83
  85. data/spec/chewy/search/pagination/kaminari_examples.rb +0 -69
  86. data/spec/chewy/search/pagination/kaminari_spec.rb +0 -21
  87. data/spec/chewy/search/parameters/aggs_spec.rb +0 -5
  88. data/spec/chewy/search/parameters/bool_storage_examples.rb +0 -53
  89. data/spec/chewy/search/parameters/collapse_spec.rb +0 -5
  90. data/spec/chewy/search/parameters/docvalue_fields_spec.rb +0 -5
  91. data/spec/chewy/search/parameters/explain_spec.rb +0 -5
  92. data/spec/chewy/search/parameters/filter_spec.rb +0 -5
  93. data/spec/chewy/search/parameters/hash_storage_examples.rb +0 -59
  94. data/spec/chewy/search/parameters/highlight_spec.rb +0 -5
  95. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +0 -67
  96. data/spec/chewy/search/parameters/indices_spec.rb +0 -99
  97. data/spec/chewy/search/parameters/integer_storage_examples.rb +0 -32
  98. data/spec/chewy/search/parameters/knn_spec.rb +0 -5
  99. data/spec/chewy/search/parameters/limit_spec.rb +0 -5
  100. data/spec/chewy/search/parameters/load_spec.rb +0 -60
  101. data/spec/chewy/search/parameters/min_score_spec.rb +0 -32
  102. data/spec/chewy/search/parameters/none_spec.rb +0 -5
  103. data/spec/chewy/search/parameters/offset_spec.rb +0 -5
  104. data/spec/chewy/search/parameters/order_spec.rb +0 -72
  105. data/spec/chewy/search/parameters/post_filter_spec.rb +0 -5
  106. data/spec/chewy/search/parameters/preference_spec.rb +0 -5
  107. data/spec/chewy/search/parameters/profile_spec.rb +0 -5
  108. data/spec/chewy/search/parameters/query_spec.rb +0 -5
  109. data/spec/chewy/search/parameters/query_storage_examples.rb +0 -434
  110. data/spec/chewy/search/parameters/request_cache_spec.rb +0 -67
  111. data/spec/chewy/search/parameters/rescore_spec.rb +0 -62
  112. data/spec/chewy/search/parameters/script_fields_spec.rb +0 -5
  113. data/spec/chewy/search/parameters/search_after_spec.rb +0 -35
  114. data/spec/chewy/search/parameters/search_type_spec.rb +0 -5
  115. data/spec/chewy/search/parameters/source_spec.rb +0 -162
  116. data/spec/chewy/search/parameters/storage_spec.rb +0 -60
  117. data/spec/chewy/search/parameters/stored_fields_spec.rb +0 -126
  118. data/spec/chewy/search/parameters/string_array_storage_examples.rb +0 -63
  119. data/spec/chewy/search/parameters/string_storage_examples.rb +0 -32
  120. data/spec/chewy/search/parameters/suggest_spec.rb +0 -5
  121. data/spec/chewy/search/parameters/terminate_after_spec.rb +0 -5
  122. data/spec/chewy/search/parameters/timeout_spec.rb +0 -5
  123. data/spec/chewy/search/parameters/track_scores_spec.rb +0 -5
  124. data/spec/chewy/search/parameters/track_total_hits_spec.rb +0 -5
  125. data/spec/chewy/search/parameters/version_spec.rb +0 -5
  126. data/spec/chewy/search/parameters_spec.rb +0 -161
  127. data/spec/chewy/search/query_proxy_spec.rb +0 -95
  128. data/spec/chewy/search/request_spec.rb +0 -886
  129. data/spec/chewy/search/response_spec.rb +0 -180
  130. data/spec/chewy/search/scrolling_spec.rb +0 -171
  131. data/spec/chewy/search_spec.rb +0 -127
  132. data/spec/chewy/stash_spec.rb +0 -85
  133. data/spec/chewy/strategy/active_job_spec.rb +0 -73
  134. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +0 -60
  135. data/spec/chewy/strategy/atomic_spec.rb +0 -61
  136. data/spec/chewy/strategy/delayed_sidekiq_spec.rb +0 -225
  137. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +0 -214
  138. data/spec/chewy/strategy/sidekiq_spec.rb +0 -52
  139. data/spec/chewy/strategy_spec.rb +0 -125
  140. data/spec/chewy_spec.rb +0 -100
  141. data/spec/spec_helper.rb +0 -69
  142. data/spec/support/active_record.rb +0 -124
  143. data/spec/support/class_helpers.rb +0 -16
  144. data/spec/support/fail_helpers.rb +0 -13
@@ -1,615 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Chewy::Index::Import do
4
- before { drop_indices }
5
-
6
- before do
7
- stub_model(:city)
8
- end
9
-
10
- before do
11
- stub_index(:cities) do
12
- index_scope City
13
- field :name
14
- end
15
- end
16
-
17
- def imported_cities
18
- CitiesIndex.all.map do |city|
19
- city.attributes.except('_score', '_explanation')
20
- end
21
- end
22
-
23
- def subscribe_notification
24
- outer_payload = {}
25
- ActiveSupport::Notifications.subscribe('import_objects.chewy') do |_name, _start, _finish, _id, payload|
26
- outer_payload.merge!(payload)
27
- end
28
- outer_payload
29
- end
30
-
31
- let!(:dummy_cities) { Array.new(3) { |i| City.create(id: i + 1, name: "name#{i}") } }
32
-
33
- describe 'index creation on import' do
34
- let(:dummy_city) { City.create }
35
-
36
- specify 'lazy (default)' do
37
- expect(CitiesIndex).to receive(:exists?).and_call_original
38
- expect(CitiesIndex).to receive(:create!).and_call_original
39
- CitiesIndex.import(dummy_city)
40
- end
41
-
42
- specify 'lazy without objects' do
43
- expect(CitiesIndex).not_to receive(:exists?)
44
- expect(CitiesIndex).not_to receive(:create!)
45
- CitiesIndex.import([])
46
- end
47
-
48
- context 'skip' do
49
- before do
50
- # To avoid flaky issues when previous specs were run
51
- expect(Chewy::Index).to receive(:descendants).and_return([CitiesIndex])
52
- Chewy.create_indices
53
- Chewy.config.settings[:skip_index_creation_on_import] = true
54
- end
55
- after { Chewy.config.settings[:skip_index_creation_on_import] = nil }
56
-
57
- specify do
58
- expect(CitiesIndex).not_to receive(:exists?)
59
- expect(CitiesIndex).not_to receive(:create!)
60
- CitiesIndex.import(dummy_city)
61
- end
62
- end
63
-
64
- context 'skip journal creation on import' do
65
- before do
66
- Chewy::Stash::Journal.create!
67
- Chewy.config.settings[:skip_journal_creation_on_import] = true
68
- end
69
- after { Chewy.config.settings[:skip_journal_creation_on_import] = nil }
70
-
71
- specify do
72
- expect(Chewy::Stash::Journal).not_to receive(:create!)
73
- CitiesIndex.import(dummy_city, journal: true)
74
- end
75
- end
76
- end
77
-
78
- shared_examples 'importing' do
79
- specify { expect(import).to eq(true) }
80
- specify { expect(import([])).to eq(true) }
81
- specify { expect(import(dummy_cities)).to eq(true) }
82
- specify { expect(import(dummy_cities.map(&:id))).to eq(true) }
83
-
84
- specify { expect { import([]) }.not_to update_index(CitiesIndex) }
85
- specify { expect { import }.to update_index(CitiesIndex).and_reindex(dummy_cities) }
86
- specify { expect { import dummy_cities }.to update_index(CitiesIndex).and_reindex(dummy_cities) }
87
- specify { expect { import dummy_cities.map(&:id) }.to update_index(CitiesIndex).and_reindex(dummy_cities) }
88
-
89
- describe 'criteria-driven importing' do
90
- let(:names) { %w[name0 name1] }
91
-
92
- context 'active record', :active_record do
93
- specify do
94
- expect { import(City.where(name: names)) }
95
- .to update_index(CitiesIndex).and_reindex(dummy_cities.first(2))
96
- end
97
- specify do
98
- expect { import(City.where(name: names).map(&:id)) }
99
- .to update_index(CitiesIndex).and_reindex(dummy_cities.first(2))
100
- end
101
- end
102
- end
103
-
104
- specify do
105
- dummy_cities.first.destroy
106
- expect { import dummy_cities }
107
- .to update_index(CitiesIndex).and_reindex(dummy_cities.from(1)).and_delete(dummy_cities.first)
108
- end
109
-
110
- specify do
111
- dummy_cities.first.destroy
112
- expect { import dummy_cities.map(&:id) }
113
- .to update_index(CitiesIndex).and_reindex(dummy_cities.from(1)).and_delete(dummy_cities.first)
114
- end
115
-
116
- specify do
117
- dummy_cities.first.destroy
118
-
119
- imported = []
120
- allow(CitiesIndex.client).to receive(:bulk) { |params|
121
- imported << params[:body]
122
- nil
123
- }
124
-
125
- import dummy_cities.map(&:id), batch_size: 2
126
- expect(imported.flatten).to match_array([
127
- {index: {_id: 2, data: {'name' => 'name1'}}},
128
- {index: {_id: 3, data: {'name' => 'name2'}}},
129
- {delete: {_id: dummy_cities.first.id}}
130
- ])
131
- end
132
-
133
- context ':bulk_size' do
134
- let!(:dummy_cities) { Array.new(3) { |i| City.create(id: i + 1, name: "name#{i}" * 20) } }
135
-
136
- specify do
137
- expect { import(dummy_cities, bulk_size: 1.2.kilobyte) }
138
- .to update_index(CitiesIndex).and_reindex(dummy_cities)
139
- end
140
-
141
- context do
142
- before { expect(Chewy.client).to receive(:bulk).exactly(3).times.and_call_original }
143
- specify { expect(import(dummy_cities, bulk_size: 1.2.kilobyte)).to eq(true) }
144
- end
145
- end
146
-
147
- context 'scoped' do
148
- before do
149
- names = %w[name0 name1]
150
-
151
- criteria = {name: names}
152
-
153
- stub_index(:cities) do
154
- index_scope City.where(criteria)
155
- field :name
156
- end
157
- end
158
-
159
- specify { expect { import }.to update_index(CitiesIndex).and_reindex(dummy_cities.first(2)) }
160
-
161
- context 'active record', :active_record do
162
- specify do
163
- expect { import City.where(id: dummy_cities.first.id) }
164
- .to update_index(CitiesIndex).and_reindex(dummy_cities.first).only
165
- end
166
-
167
- specify do
168
- allow(CitiesIndex).to receive(:import_linear).and_return(double(present?: false))
169
- allow(CitiesIndex).to receive(:import_parallel).and_return(double(present?: false))
170
-
171
- expects_no_query(except: /SELECT\s+1\s+AS\s+one\s+FROM/) do
172
- import City.where(id: dummy_cities.first.id)
173
- end
174
- end
175
- end
176
- end
177
-
178
- context 'instrumentation payload' do
179
- specify do
180
- payload = subscribe_notification
181
- dummy_cities.first.destroy
182
- import dummy_cities
183
- expect(payload).to eq(index: CitiesIndex, import: {delete: 1, index: 2})
184
- end
185
-
186
- specify do
187
- payload = subscribe_notification
188
- dummy_cities.first.destroy
189
- import dummy_cities, batch_size: 2
190
- expect(payload).to eq(index: CitiesIndex, import: {delete: 1, index: 2})
191
- end
192
-
193
- specify do
194
- payload = subscribe_notification
195
- import dummy_cities, batch_size: 2
196
- expect(payload).to eq(index: CitiesIndex, import: {index: 3})
197
- end
198
-
199
- context do
200
- before do
201
- stub_index(:cities) do
202
- index_scope City
203
- field :name, type: 'object'
204
- end
205
- end
206
-
207
- let(:document_parsing_exception) do
208
- {
209
- 'type' => 'document_parsing_exception',
210
- 'reason' => '[1:9] object mapping for [name] tried to parse field [name] as object, but found a concrete value'
211
- }
212
- end
213
-
214
- specify do
215
- payload = subscribe_notification
216
- import dummy_cities, batch_size: 2
217
- expect(payload).to eq(index: CitiesIndex,
218
- errors: {index: {document_parsing_exception => %w[1 2 3]}},
219
- import: {index: 3})
220
- end
221
- end
222
- end
223
-
224
- context 'fields' do
225
- before { CitiesIndex.import!(dummy_cities.first(2)) }
226
-
227
- context do
228
- before { expect(Chewy.client).to receive(:bulk).twice.and_call_original }
229
- specify { expect(import(dummy_cities, update_fields: [:name])).to eq(true) }
230
- end
231
-
232
- context do
233
- before { CitiesIndex.import!(dummy_cities.last) }
234
- before { expect(Chewy.client).to receive(:bulk).once.and_call_original }
235
- specify { expect(import(dummy_cities, update_fields: [:name])).to eq(true) }
236
- end
237
- end
238
-
239
- context 'fields integrational' do
240
- before do
241
- stub_index(:cities) do
242
- field :name
243
- field :object, type: 'object'
244
- end
245
- end
246
-
247
- let(:objects) do
248
- [
249
- double('Name1', id: 1, name: 'Name11', object: {foo: 11}),
250
- double('Name2', id: 2, name: 'Name12', object: 'foo'),
251
- double('Name3', id: 3, name: 'Name13', object: {foo: 13}),
252
- double('Name4', id: 4, name: 'Name14', object: 'foo'),
253
- double('Name5', id: 5, name: 'Name15', object: {foo: 15}),
254
- double('Name6', id: '', name: 'Name16', object: {foo: 16})
255
- ]
256
- end
257
-
258
- let(:old_objects) do
259
- Array.new(6) do |i|
260
- double("Name#{i + 1}", id: i + 1, name: "Name#{i + 1}", object: {foo: i + 1})
261
- end
262
- end
263
-
264
- specify do
265
- payload = subscribe_notification
266
-
267
- expect(Chewy.client).to receive(:bulk).twice.and_call_original
268
- import(objects, update_fields: %i[name])
269
-
270
- expect(payload).to eq(
271
- errors: {
272
- index: {{
273
- 'type' => 'document_parsing_exception',
274
- 'reason' => '[1:27] object mapping for [object] tried to parse field [object] as object, but found a concrete value'
275
- } => %w[2 4]}
276
- },
277
- import: {index: 6},
278
- index: CitiesIndex
279
- )
280
- expect(imported_cities).to match_array([
281
- {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
282
- {'id' => '3', 'name' => 'Name13', 'object' => {'foo' => 13}},
283
- {'id' => '5', 'name' => 'Name15', 'object' => {'foo' => 15}}
284
- ])
285
- end
286
-
287
- specify do
288
- payload = subscribe_notification
289
-
290
- expect(Chewy.client).to receive(:bulk).at_least(4).at_most(6).times.and_call_original
291
- import(objects, batch_size: 2, update_fields: %i[name])
292
-
293
- expect(payload).to eq(
294
- errors: {
295
- index: {{
296
- 'type' => 'document_parsing_exception',
297
- 'reason' => '[1:27] object mapping for [object] tried to parse field [object] as object, but found a concrete value'
298
- } => %w[2 4]}
299
- },
300
- import: {index: 6},
301
- index: CitiesIndex
302
- )
303
- expect(imported_cities).to match_array([
304
- {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
305
- {'id' => '3', 'name' => 'Name13', 'object' => {'foo' => 13}},
306
- {'id' => '5', 'name' => 'Name15', 'object' => {'foo' => 15}}
307
- ])
308
- end
309
-
310
- context do
311
- before { CitiesIndex.import!(objects[4]) }
312
-
313
- specify do
314
- payload = subscribe_notification
315
-
316
- expect(Chewy.client).to receive(:bulk).at_least(3).at_most(5).times.and_call_original
317
- import(objects, batch_size: 2, update_fields: %i[name])
318
-
319
- expect(payload).to eq(
320
- errors: {
321
- index: {{
322
- 'type' => 'document_parsing_exception',
323
- 'reason' => '[1:27] object mapping for [object] tried to parse field [object] as object, but found a concrete value'
324
- } => %w[2 4]}
325
- },
326
- import: {index: 6},
327
- index: CitiesIndex
328
- )
329
- expect(imported_cities).to match_array([
330
- {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
331
- {'id' => '3', 'name' => 'Name13', 'object' => {'foo' => 13}},
332
- {'id' => '5', 'name' => 'Name15', 'object' => {'foo' => 15}}
333
- ])
334
- end
335
- end
336
-
337
- context do
338
- before { CitiesIndex.import!(old_objects[1], old_objects[3], objects[4]) }
339
-
340
- specify do
341
- payload = subscribe_notification
342
-
343
- expect(Chewy.client).to receive(:bulk).twice.and_call_original
344
- import(objects, update_fields: %i[name])
345
-
346
- expect(payload).to eq(
347
- import: {index: 6},
348
- index: CitiesIndex
349
- )
350
- expect(imported_cities).to match_array([
351
- {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
352
- {'id' => '2', 'name' => 'Name12', 'object' => {'foo' => 2}},
353
- {'id' => '3', 'name' => 'Name13', 'object' => {'foo' => 13}},
354
- {'id' => '4', 'name' => 'Name14', 'object' => {'foo' => 4}},
355
- {'id' => '5', 'name' => 'Name15', 'object' => {'foo' => 15}}
356
- ])
357
- end
358
-
359
- specify do
360
- payload = subscribe_notification
361
-
362
- expect(Chewy.client).to receive(:bulk).at_least(3).at_most(5).times.and_call_original
363
- import(objects, batch_size: 2, update_fields: %i[name])
364
-
365
- expect(payload).to eq(
366
- import: {index: 6},
367
- index: CitiesIndex
368
- )
369
- expect(imported_cities).to match_array([
370
- {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
371
- {'id' => '2', 'name' => 'Name12', 'object' => {'foo' => 2}},
372
- {'id' => '3', 'name' => 'Name13', 'object' => {'foo' => 13}},
373
- {'id' => '4', 'name' => 'Name14', 'object' => {'foo' => 4}},
374
- {'id' => '5', 'name' => 'Name15', 'object' => {'foo' => 15}}
375
- ])
376
- end
377
-
378
- specify do
379
- payload = subscribe_notification
380
-
381
- expect(Chewy.client).to receive(:bulk).once.and_call_original
382
- import(objects, update_fields: %i[name], update_failover: false)
383
-
384
- # Full match doesn't work here.
385
- expect(payload[:errors][:update].keys).to match([
386
- hash_including('type' => 'document_missing_exception', 'reason' => '[1]: document missing'),
387
- hash_including('type' => 'document_missing_exception', 'reason' => '[3]: document missing')
388
- ])
389
- expect(payload[:errors][:update].values).to eq([['1'], ['3']])
390
- expect(imported_cities).to match_array([
391
- {'id' => '2', 'name' => 'Name12', 'object' => {'foo' => 2}},
392
- {'id' => '4', 'name' => 'Name14', 'object' => {'foo' => 4}},
393
- {'id' => '5', 'name' => 'Name15', 'object' => {'foo' => 15}}
394
- ])
395
- end
396
- end
397
-
398
- context do
399
- before { CitiesIndex.import!(old_objects) }
400
-
401
- specify do
402
- payload = subscribe_notification
403
-
404
- expect(Chewy.client).to receive(:bulk).once.and_call_original
405
- import(objects, update_fields: %i[name])
406
-
407
- expect(payload).to eq(
408
- import: {index: 6},
409
- index: CitiesIndex
410
- )
411
- expect(imported_cities).to match_array([
412
- {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 1}},
413
- {'id' => '2', 'name' => 'Name12', 'object' => {'foo' => 2}},
414
- {'id' => '3', 'name' => 'Name13', 'object' => {'foo' => 3}},
415
- {'id' => '4', 'name' => 'Name14', 'object' => {'foo' => 4}},
416
- {'id' => '5', 'name' => 'Name15', 'object' => {'foo' => 5}},
417
- {'id' => '6', 'name' => 'Name6', 'object' => {'foo' => 6}}
418
- ])
419
- end
420
- end
421
-
422
- context do
423
- before { CitiesIndex.import!(old_objects) }
424
-
425
- specify do
426
- payload = subscribe_notification
427
-
428
- expect(Chewy.client).to receive(:bulk).once.and_call_original
429
- import(objects, update_fields: %i[object])
430
-
431
- expect(payload).to eq(
432
- errors: {
433
- update: {{
434
- 'type' => 'document_parsing_exception',
435
- 'reason' => '[1:26] object mapping for [object] tried to parse field [object] as object, but found a concrete value'
436
- } => %w[2 4]}
437
- },
438
- import: {index: 6},
439
- index: CitiesIndex
440
- )
441
- expect(imported_cities).to match_array([
442
- {'id' => '1', 'name' => 'Name1', 'object' => {'foo' => 11}},
443
- {'id' => '2', 'name' => 'Name2', 'object' => {'foo' => 2}},
444
- {'id' => '3', 'name' => 'Name3', 'object' => {'foo' => 13}},
445
- {'id' => '4', 'name' => 'Name4', 'object' => {'foo' => 4}},
446
- {'id' => '5', 'name' => 'Name5', 'object' => {'foo' => 15}},
447
- {'id' => '6', 'name' => 'Name6', 'object' => {'foo' => 6}}
448
- ])
449
- end
450
- end
451
- end
452
-
453
- context 'error handling' do
454
- context do
455
- before do
456
- stub_index(:cities) do
457
- index_scope City
458
- field :name, type: 'object'
459
- end
460
- end
461
-
462
- specify { expect(import(dummy_cities)).to eq(false) }
463
- specify { expect(import(dummy_cities.map(&:id))).to eq(false) }
464
- specify { expect(import(dummy_cities, batch_size: 1)).to eq(false) }
465
- end
466
-
467
- context do
468
- before do
469
- stub_index(:cities) do
470
- index_scope City
471
- field :name, type: 'object', value: -> { name == 'name1' ? name : {name: name} }
472
- end
473
- end
474
-
475
- specify { expect(import(dummy_cities)).to eq(false) }
476
- specify { expect(import(dummy_cities.map(&:id))).to eq(false) }
477
- specify { expect(import(dummy_cities, batch_size: 2)).to eq(false) }
478
- end
479
- end
480
-
481
- context 'default_import_options are set' do
482
- before do
483
- CitiesIndex.default_import_options(batch_size: 500)
484
- end
485
-
486
- specify do
487
- expect(CitiesIndex.adapter).to receive(:import).with(any_args, hash_including(batch_size: 500))
488
- CitiesIndex.import
489
- end
490
- end
491
- end
492
-
493
- describe '.import', :orm do
494
- def import(*args)
495
- CitiesIndex.import(*args)
496
- end
497
-
498
- it_behaves_like 'importing'
499
-
500
- context 'parallel' do
501
- def import(*args)
502
- options = args.extract_options!
503
- options[:parallel] = 0
504
- CitiesIndex.import(*args, options)
505
- end
506
-
507
- it_behaves_like 'importing'
508
- end
509
-
510
- context 'with parent-child relationship' do
511
- before do
512
- stub_model(:comment)
513
- stub_index(:comments) do
514
- index_scope Comment
515
- field :content
516
- field :comment_type, type: :join, relations: {question: %i[answer comment], answer: :vote}, join: {type: :comment_type, id: :commented_id}
517
- end
518
- end
519
-
520
- let!(:comments) do
521
- [
522
- Comment.create!(id: 1, content: 'Where is Nemo?', comment_type: :question),
523
- Comment.create!(id: 2, content: 'Here.', comment_type: :answer, commented_id: 1),
524
- Comment.create!(id: 3, content: 'There!', comment_type: :answer, commented_id: 1),
525
- Comment.create!(id: 4, content: 'Yes, he is here.', comment_type: :vote, commented_id: 2)
526
- ]
527
- end
528
-
529
- def imported_comments
530
- CommentsIndex.all.map do |comment|
531
- comment.attributes.except('_score', '_explanation')
532
- end
533
- end
534
-
535
- it 'imports parent and children' do
536
- CommentsIndex.import!(comments.map(&:id))
537
-
538
- expect(imported_comments).to match_array([
539
- {'id' => '1', 'content' => 'Where is Nemo?', 'comment_type' => 'question'},
540
- {'id' => '2', 'content' => 'Here.', 'comment_type' => {'name' => 'answer', 'parent' => 1}},
541
- {'id' => '3', 'content' => 'There!', 'comment_type' => {'name' => 'answer', 'parent' => 1}},
542
- {'id' => '4', 'content' => 'Yes, he is here.', 'comment_type' => {'name' => 'vote', 'parent' => 2}}
543
- ])
544
-
545
- answer_ids = CommentsIndex.query(has_parent: {parent_type: 'question', query: {match: {content: 'Where'}}}).pluck(:_id)
546
- expect(answer_ids).to match_array(%w[2 3])
547
- end
548
- end
549
- end
550
-
551
- describe '.import!', :orm do
552
- specify { expect { CitiesIndex.import! }.not_to raise_error }
553
-
554
- context do
555
- before do
556
- stub_index(:cities) do
557
- index_scope City
558
- field :name, type: 'object'
559
- end
560
- end
561
-
562
- specify { expect { CitiesIndex.import!(dummy_cities) }.to raise_error Chewy::ImportFailed }
563
- end
564
- end
565
-
566
- describe '.compose' do
567
- before do
568
- stub_index(:cities) do
569
- crutch :names do |collection|
570
- collection.to_h { |o| [o.name, "#{o.name}42"] }
571
- end
572
- field :name, value: ->(o, c) { c.names[o.name] }
573
- field :rating
574
- end
575
- end
576
-
577
- specify do
578
- expect(CitiesIndex.compose(double(name: 'Name', rating: 42)))
579
- .to eq('name' => 'Name42', 'rating' => 42)
580
- end
581
-
582
- specify do
583
- expect(CitiesIndex.compose(double(name: 'Name', rating: 42), fields: %i[name]))
584
- .to eq('name' => 'Name42')
585
- end
586
-
587
- context 'witchcraft' do
588
- before { CitiesIndex.witchcraft! }
589
-
590
- specify do
591
- expect(CitiesIndex.compose(double(name: 'Name', rating: 42)))
592
- .to eq('name' => 'Name42', 'rating' => 42)
593
- end
594
-
595
- specify do
596
- expect(CitiesIndex.compose(double(name: 'Name', rating: 42), fields: %i[name]))
597
- .to eq('name' => 'Name42')
598
- end
599
- end
600
-
601
- context 'custom crutches' do
602
- let(:crutches) { double(names: {'Name' => 'Name43'}) }
603
-
604
- specify do
605
- expect(CitiesIndex.compose(double(name: 'Name', rating: 42), crutches))
606
- .to eq('name' => 'Name43', 'rating' => 42)
607
- end
608
-
609
- specify do
610
- expect(CitiesIndex.compose(double(name: 'Name', rating: 42), crutches, fields: %i[name]))
611
- .to eq('name' => 'Name43')
612
- end
613
- end
614
- end
615
- end