chewy 0.8.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +34 -0
  3. data/.rubocop_todo.yml +44 -0
  4. data/.travis.yml +20 -60
  5. data/Appraisals +15 -40
  6. data/CHANGELOG.md +42 -0
  7. data/Gemfile +1 -0
  8. data/Guardfile +5 -5
  9. data/README.md +155 -6
  10. data/Rakefile +11 -1
  11. data/chewy.gemspec +5 -7
  12. data/gemfiles/rails.3.2.activerecord.gemfile +1 -0
  13. data/gemfiles/rails.3.2.activerecord.kaminari.gemfile +1 -0
  14. data/gemfiles/rails.3.2.activerecord.will_paginate.gemfile +1 -0
  15. data/gemfiles/rails.4.2.activerecord.gemfile +1 -0
  16. data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +1 -0
  17. data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +1 -0
  18. data/gemfiles/{rails.4.2.mongoid.4.0.0.gemfile → rails.4.2.mongoid.4.0.gemfile} +2 -1
  19. data/gemfiles/{rails.4.2.mongoid.4.0.0.kaminari.gemfile → rails.4.2.mongoid.4.0.kaminari.gemfile} +2 -1
  20. data/gemfiles/{rails.4.2.mongoid.4.0.0.will_paginate.gemfile → rails.4.2.mongoid.4.0.will_paginate.gemfile} +2 -1
  21. data/gemfiles/{rails.4.2.mongoid.5.1.0.gemfile → rails.4.2.mongoid.5.1.gemfile} +2 -1
  22. data/gemfiles/{rails.4.2.mongoid.5.1.0.kaminari.gemfile → rails.4.2.mongoid.5.1.kaminari.gemfile} +2 -1
  23. data/gemfiles/{rails.4.2.mongoid.5.1.0.will_paginate.gemfile → rails.4.2.mongoid.5.1.will_paginate.gemfile} +2 -1
  24. data/gemfiles/{rails.4.0.activerecord.gemfile → rails.5.0.activerecord.gemfile} +4 -2
  25. data/gemfiles/{rails.4.0.mongoid.4.0.0.kaminari.gemfile → rails.5.0.activerecord.kaminari.gemfile} +4 -2
  26. data/gemfiles/{rails.4.0.mongoid.4.0.0.will_paginate.gemfile → rails.5.0.activerecord.will_paginate.gemfile} +4 -2
  27. data/gemfiles/{sequel.4.31.gemfile → sequel.4.38.gemfile} +3 -2
  28. data/lib/chewy.rb +24 -16
  29. data/lib/chewy/backports/deep_dup.rb +1 -1
  30. data/lib/chewy/backports/duplicable.rb +1 -0
  31. data/lib/chewy/config.rb +13 -7
  32. data/lib/chewy/errors.rb +4 -4
  33. data/lib/chewy/fields/base.rb +19 -14
  34. data/lib/chewy/fields/root.rb +11 -9
  35. data/lib/chewy/index.rb +38 -25
  36. data/lib/chewy/index/actions.rb +17 -17
  37. data/lib/chewy/index/settings.rb +3 -4
  38. data/lib/chewy/journal.rb +107 -0
  39. data/lib/chewy/journal/apply.rb +31 -0
  40. data/lib/chewy/journal/clean.rb +24 -0
  41. data/lib/chewy/journal/entry.rb +83 -0
  42. data/lib/chewy/journal/query.rb +87 -0
  43. data/lib/chewy/log_subscriber.rb +8 -8
  44. data/lib/chewy/minitest.rb +1 -0
  45. data/lib/chewy/minitest/helpers.rb +77 -0
  46. data/lib/chewy/minitest/search_index_receiver.rb +80 -0
  47. data/lib/chewy/query.rb +116 -60
  48. data/lib/chewy/query/compose.rb +5 -6
  49. data/lib/chewy/query/criteria.rb +26 -16
  50. data/lib/chewy/query/filters.rb +9 -9
  51. data/lib/chewy/query/loading.rb +2 -2
  52. data/lib/chewy/query/nodes/and.rb +3 -3
  53. data/lib/chewy/query/nodes/base.rb +1 -1
  54. data/lib/chewy/query/nodes/bool.rb +6 -4
  55. data/lib/chewy/query/nodes/equal.rb +6 -6
  56. data/lib/chewy/query/nodes/exists.rb +2 -2
  57. data/lib/chewy/query/nodes/expr.rb +2 -2
  58. data/lib/chewy/query/nodes/field.rb +35 -31
  59. data/lib/chewy/query/nodes/has_child.rb +1 -0
  60. data/lib/chewy/query/nodes/has_parent.rb +1 -0
  61. data/lib/chewy/query/nodes/has_relation.rb +11 -13
  62. data/lib/chewy/query/nodes/match_all.rb +1 -1
  63. data/lib/chewy/query/nodes/missing.rb +2 -2
  64. data/lib/chewy/query/nodes/not.rb +3 -3
  65. data/lib/chewy/query/nodes/or.rb +3 -3
  66. data/lib/chewy/query/nodes/prefix.rb +4 -3
  67. data/lib/chewy/query/nodes/query.rb +3 -3
  68. data/lib/chewy/query/nodes/range.rb +11 -11
  69. data/lib/chewy/query/nodes/raw.rb +1 -1
  70. data/lib/chewy/query/nodes/regexp.rb +15 -11
  71. data/lib/chewy/query/nodes/script.rb +6 -6
  72. data/lib/chewy/query/pagination/will_paginate.rb +2 -2
  73. data/lib/chewy/railtie.rb +3 -3
  74. data/lib/chewy/rake_helper.rb +51 -30
  75. data/lib/chewy/repository.rb +2 -2
  76. data/lib/chewy/rspec.rb +1 -1
  77. data/lib/chewy/rspec/update_index.rb +46 -47
  78. data/lib/chewy/runtime/version.rb +4 -4
  79. data/lib/chewy/search.rb +7 -5
  80. data/lib/chewy/strategy.rb +10 -8
  81. data/lib/chewy/strategy/atomic.rb +2 -2
  82. data/lib/chewy/strategy/base.rb +4 -4
  83. data/lib/chewy/strategy/bypass.rb +1 -2
  84. data/lib/chewy/strategy/sidekiq.rb +2 -0
  85. data/lib/chewy/strategy/urgent.rb +1 -1
  86. data/lib/chewy/type.rb +51 -45
  87. data/lib/chewy/type/adapter/active_record.rb +23 -12
  88. data/lib/chewy/type/adapter/base.rb +4 -4
  89. data/lib/chewy/type/adapter/mongoid.rb +6 -6
  90. data/lib/chewy/type/adapter/object.rb +15 -12
  91. data/lib/chewy/type/adapter/orm.rb +24 -15
  92. data/lib/chewy/type/adapter/sequel.rb +11 -7
  93. data/lib/chewy/type/crutch.rb +4 -3
  94. data/lib/chewy/type/import.rb +51 -32
  95. data/lib/chewy/type/mapping.rb +17 -17
  96. data/lib/chewy/type/observe.rb +9 -7
  97. data/lib/chewy/type/witchcraft.rb +62 -23
  98. data/lib/chewy/type/wrapper.rb +20 -14
  99. data/lib/chewy/version.rb +1 -1
  100. data/lib/generators/chewy/install_generator.rb +3 -3
  101. data/lib/tasks/chewy.rake +28 -23
  102. data/spec/chewy/config_spec.rb +33 -12
  103. data/spec/chewy/fields/base_spec.rb +143 -154
  104. data/spec/chewy/fields/root_spec.rb +22 -20
  105. data/spec/chewy/fields/time_fields_spec.rb +11 -9
  106. data/spec/chewy/index/actions_spec.rb +27 -4
  107. data/spec/chewy/index/aliases_spec.rb +2 -2
  108. data/spec/chewy/index/settings_spec.rb +72 -50
  109. data/spec/chewy/index_spec.rb +95 -43
  110. data/spec/chewy/journal/apply_spec.rb +120 -0
  111. data/spec/chewy/journal/entry_spec.rb +237 -0
  112. data/spec/chewy/journal_spec.rb +173 -0
  113. data/spec/chewy/minitest/helpers_spec.rb +90 -0
  114. data/spec/chewy/minitest/search_index_receiver_spec.rb +120 -0
  115. data/spec/chewy/query/criteria_spec.rb +504 -237
  116. data/spec/chewy/query/filters_spec.rb +94 -66
  117. data/spec/chewy/query/loading_spec.rb +76 -40
  118. data/spec/chewy/query/nodes/and_spec.rb +3 -7
  119. data/spec/chewy/query/nodes/bool_spec.rb +5 -13
  120. data/spec/chewy/query/nodes/equal_spec.rb +20 -20
  121. data/spec/chewy/query/nodes/exists_spec.rb +7 -7
  122. data/spec/chewy/query/nodes/has_child_spec.rb +42 -23
  123. data/spec/chewy/query/nodes/has_parent_spec.rb +42 -23
  124. data/spec/chewy/query/nodes/match_all_spec.rb +2 -2
  125. data/spec/chewy/query/nodes/missing_spec.rb +6 -5
  126. data/spec/chewy/query/nodes/not_spec.rb +3 -7
  127. data/spec/chewy/query/nodes/or_spec.rb +3 -7
  128. data/spec/chewy/query/nodes/prefix_spec.rb +6 -6
  129. data/spec/chewy/query/nodes/query_spec.rb +3 -3
  130. data/spec/chewy/query/nodes/range_spec.rb +19 -19
  131. data/spec/chewy/query/nodes/raw_spec.rb +2 -2
  132. data/spec/chewy/query/nodes/regexp_spec.rb +31 -19
  133. data/spec/chewy/query/nodes/script_spec.rb +5 -5
  134. data/spec/chewy/query/pagination/kaminari_spec.rb +2 -2
  135. data/spec/chewy/query/pagination/will_paginage_spec.rb +6 -7
  136. data/spec/chewy/query/pagination_spec.rb +2 -3
  137. data/spec/chewy/query_spec.rb +208 -145
  138. data/spec/chewy/repository_spec.rb +8 -8
  139. data/spec/chewy/rspec/update_index_spec.rb +180 -111
  140. data/spec/chewy/search_spec.rb +8 -8
  141. data/spec/chewy/strategy/active_job_spec.rb +2 -2
  142. data/spec/chewy/strategy/atomic_spec.rb +4 -1
  143. data/spec/chewy/strategy/resque_spec.rb +2 -2
  144. data/spec/chewy/strategy/sidekiq_spec.rb +2 -2
  145. data/spec/chewy/type/actions_spec.rb +1 -1
  146. data/spec/chewy/type/adapter/active_record_spec.rb +255 -149
  147. data/spec/chewy/type/adapter/mongoid_spec.rb +169 -108
  148. data/spec/chewy/type/adapter/object_spec.rb +56 -40
  149. data/spec/chewy/type/adapter/sequel_spec.rb +248 -163
  150. data/spec/chewy/type/import_spec.rb +78 -47
  151. data/spec/chewy/type/mapping_spec.rb +6 -6
  152. data/spec/chewy/type/observe_spec.rb +20 -14
  153. data/spec/chewy/type/witchcraft_spec.rb +89 -43
  154. data/spec/chewy/type_spec.rb +4 -3
  155. data/spec/chewy_spec.rb +10 -8
  156. data/spec/spec_helper.rb +3 -0
  157. data/spec/support/active_record.rb +1 -1
  158. data/spec/support/class_helpers.rb +10 -11
  159. data/spec/support/mongoid.rb +2 -2
  160. data/spec/support/sequel.rb +1 -1
  161. metadata +65 -35
  162. data/gemfiles/rails.4.0.activerecord.kaminari.gemfile +0 -14
  163. data/gemfiles/rails.4.0.activerecord.will_paginate.gemfile +0 -14
  164. data/gemfiles/rails.4.0.mongoid.4.0.0.gemfile +0 -15
  165. data/gemfiles/rails.4.0.mongoid.5.1.0.gemfile +0 -15
  166. data/gemfiles/rails.4.0.mongoid.5.1.0.kaminari.gemfile +0 -14
  167. data/gemfiles/rails.4.0.mongoid.5.1.0.will_paginate.gemfile +0 -14
  168. data/gemfiles/rails.4.1.activerecord.gemfile +0 -15
  169. data/gemfiles/rails.4.1.activerecord.kaminari.gemfile +0 -14
  170. data/gemfiles/rails.4.1.activerecord.will_paginate.gemfile +0 -14
  171. data/gemfiles/rails.4.1.mongoid.4.0.0.gemfile +0 -15
  172. data/gemfiles/rails.4.1.mongoid.4.0.0.kaminari.gemfile +0 -14
  173. data/gemfiles/rails.4.1.mongoid.4.0.0.will_paginate.gemfile +0 -14
  174. data/gemfiles/rails.4.1.mongoid.5.1.0.gemfile +0 -15
  175. data/gemfiles/rails.4.1.mongoid.5.1.0.kaminari.gemfile +0 -14
  176. data/gemfiles/rails.4.1.mongoid.5.1.0.will_paginate.gemfile +0 -14
  177. data/gemfiles/rails.5.0.0.beta3.activerecord.gemfile +0 -16
  178. data/gemfiles/rails.5.0.0.beta3.activerecord.kaminari.gemfile +0 -16
  179. data/gemfiles/rails.5.0.0.beta3.activerecord.will_paginate.gemfile +0 -15
@@ -15,7 +15,7 @@ describe Chewy::Type::Import do
15
15
  end
16
16
  end
17
17
 
18
- let!(:dummy_cities) { 3.times.map { |i| City.create(id: i + 1, name: "name#{i}") } }
18
+ let!(:dummy_cities) { Array.new(3) { |i| City.create(id: i + 1, name: "name#{i}") } }
19
19
  let(:city) { CitiesIndex::City }
20
20
 
21
21
  describe '.import', :orm do
@@ -59,44 +59,57 @@ describe Chewy::Type::Import do
59
59
  dummy_cities.first.destroy
60
60
 
61
61
  imported = []
62
- allow(CitiesIndex.client).to receive(:bulk) { |params| imported << params[:body]; nil }
62
+ allow(CitiesIndex.client).to receive(:bulk) { |params|
63
+ imported << params[:body]
64
+ nil
65
+ }
63
66
 
64
67
  city.import dummy_cities.map(&:id), batch_size: 2
65
68
  expect(imported.flatten).to match_array([
66
- {index: {_id: 2, data: {'name' => 'name1'}}},
67
- {index: {_id: 3, data: {'name' => 'name2'}}},
68
- {delete: {_id: dummy_cities.first.id}}
69
+ { index: { _id: 2, data: { 'name' => 'name1' } } },
70
+ { index: { _id: 3, data: { 'name' => 'name2' } } },
71
+ { delete: { _id: dummy_cities.first.id } }
69
72
  ])
70
73
  end
71
74
 
72
75
  context ':bulk_size' do
76
+ specify { expect(city.import(dummy_cities.first, bulk_size: 1.2.kilobyte)).to eq(true) }
77
+ specify { expect(city.import(dummy_cities, bulk_size: 1.2.kilobyte)).to eq(true) }
78
+ specify { expect { city.import(dummy_cities, bulk_size: 1.2.kilobyte) }.to update_index(city).and_reindex(dummy_cities) }
79
+
73
80
  specify do
74
81
  dummy_cities.first.destroy
75
82
 
76
83
  imported = []
77
- allow(CitiesIndex.client).to receive(:bulk) { |params| imported << params[:body]; nil }
84
+ allow(CitiesIndex.client).to receive(:bulk) { |params|
85
+ imported << params[:body]
86
+ nil
87
+ }
78
88
 
79
89
  city.import dummy_cities.map(&:id), bulk_size: 1.2.kilobyte
80
90
  expect(imported.flatten).to match_array([
81
- %Q({"delete":{"_id":1}}),
82
- %Q({"index":{"_id":2}}\n{"name":"name1"}\n{"index":{"_id":3}}\n{"name":"name2"})
91
+ %({"delete":{"_id":1}}\n),
92
+ %({"index":{"_id":2}}\n{"name":"name1"}\n{"index":{"_id":3}}\n{"name":"name2"}\n)
83
93
  ])
84
94
  end
85
95
 
86
96
  context do
87
- let!(:dummy_cities) { 3.times.map { |i| City.create(id: i + 1, name: "name#{i}" * 20) } }
97
+ let!(:dummy_cities) { Array.new(3) { |i| City.create(id: i + 1, name: "name#{i}" * 20) } }
88
98
 
89
99
  specify do
90
100
  dummy_cities.first.destroy
91
101
 
92
102
  imported = []
93
- allow(CitiesIndex.client).to receive(:bulk) { |params| imported << params[:body]; nil }
103
+ allow(CitiesIndex.client).to receive(:bulk) { |params|
104
+ imported << params[:body]
105
+ nil
106
+ }
94
107
 
95
108
  city.import dummy_cities.map(&:id), bulk_size: 1.2.kilobyte
96
109
  expect(imported.flatten).to match_array([
97
- %Q({"delete":{"_id":1}}),
98
- %Q({"index":{"_id":2}}\n{"name":"#{'name1' * 20}"}),
99
- %Q({"index":{"_id":3}}\n{"name":"#{'name2' * 20}"})
110
+ %({"delete":{"_id":1}}\n),
111
+ %({"index":{"_id":2}}\n{"name":"#{'name1' * 20}"}\n),
112
+ %({"index":{"_id":3}}\n{"name":"#{'name2' * 20}"}\n)
100
113
  ])
101
114
  end
102
115
 
@@ -152,34 +165,34 @@ describe Chewy::Type::Import do
152
165
  context 'instrumentation payload' do
153
166
  specify do
154
167
  outer_payload = nil
155
- ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
168
+ ActiveSupport::Notifications.subscribe('import_objects.chewy') do |_name, _start, _finish, _id, payload|
156
169
  outer_payload = payload
157
170
  end
158
171
 
159
172
  dummy_cities.first.destroy
160
173
  city.import dummy_cities
161
- expect(outer_payload).to eq({type: CitiesIndex::City, import: {delete: 1, index: 2}})
174
+ expect(outer_payload).to eq(type: CitiesIndex::City, import: { delete: 1, index: 2 })
162
175
  end
163
176
 
164
177
  specify do
165
178
  outer_payload = nil
166
- ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
179
+ ActiveSupport::Notifications.subscribe('import_objects.chewy') do |_name, _start, _finish, _id, payload|
167
180
  outer_payload = payload
168
181
  end
169
182
 
170
183
  dummy_cities.first.destroy
171
184
  city.import dummy_cities, batch_size: 2
172
- expect(outer_payload).to eq({type: CitiesIndex::City, import: {delete: 1, index: 2}})
185
+ expect(outer_payload).to eq(type: CitiesIndex::City, import: { delete: 1, index: 2 })
173
186
  end
174
187
 
175
188
  specify do
176
189
  outer_payload = nil
177
- ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
190
+ ActiveSupport::Notifications.subscribe('import_objects.chewy') do |_name, _start, _finish, _id, payload|
178
191
  outer_payload = payload
179
192
  end
180
193
 
181
194
  city.import dummy_cities, batch_size: 2
182
- expect(outer_payload).to eq({type: CitiesIndex::City, import: {index: 3}})
195
+ expect(outer_payload).to eq(type: CitiesIndex::City, import: { index: 3 })
183
196
  end
184
197
 
185
198
  context do
@@ -191,43 +204,51 @@ describe Chewy::Type::Import do
191
204
  end
192
205
  end
193
206
 
207
+ let(:write_failure_exception) do
208
+ 'WriteFailureException; nested: MapperParsingException[object mapping for [city] ' \
209
+ 'tried to parse field [name] as object, but got EOF, has a concrete value been provided to it?]; '
210
+ end
211
+ let(:mapper_parsing_exception) do
212
+ 'MapperParsingException[object mapping for [city] tried to parse field [name] ' \
213
+ 'as object, but got EOF, has a concrete value been provided to it?]'
214
+ end
215
+
194
216
  specify do
195
217
  skip_on_version_gte('2.0', 'format of exception changed in 2.x')
196
218
  outer_payload = nil
197
- ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
219
+ ActiveSupport::Notifications.subscribe('import_objects.chewy') do |_name, _start, _finish, _id, payload|
198
220
  outer_payload = payload
199
221
  end
200
222
 
201
223
  city.import dummy_cities, batch_size: 2
202
- expect(outer_payload).to eq({
203
- type: CitiesIndex::City,
224
+ expect(outer_payload).to eq(type: CitiesIndex::City,
204
225
  errors: {
205
226
  index: {
206
- "WriteFailureException; nested: MapperParsingException[object mapping for [city] tried to parse field [name] as object, but got EOF, has a concrete value been provided to it?]; " => ["1"],
207
- "MapperParsingException[object mapping for [city] tried to parse field [name] as object, but got EOF, has a concrete value been provided to it?]" => ["2", "3"]
227
+ write_failure_exception => ['1'],
228
+ mapper_parsing_exception => %w(2 3)
208
229
  }
209
230
  },
210
- import: {index: 3}
211
- })
231
+ import: { index: 3 })
212
232
  end
213
233
 
214
234
  specify do
215
235
  skip_on_version_lt('2.0', 'format of exception was changed')
216
236
  outer_payload = nil
217
- ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
237
+ ActiveSupport::Notifications.subscribe('import_objects.chewy') do |_name, _start, _finish, _id, payload|
218
238
  outer_payload = payload
219
239
  end
220
240
 
221
241
  city.import dummy_cities, batch_size: 2
222
- expect(outer_payload).to eq({
223
- type: CitiesIndex::City,
242
+ expect(outer_payload).to eq(type: CitiesIndex::City,
224
243
  errors: {
225
244
  index: {
226
- {"type"=>"mapper_parsing_exception", "reason"=>"object mapping for [name] tried to parse field [name] as object, but found a concrete value"} => ["1", "2", "3"]
245
+ {
246
+ 'type' => 'mapper_parsing_exception',
247
+ 'reason' => 'object mapping for [name] tried to parse field [name] as object, but found a concrete value'
248
+ } => %w(1 2 3)
227
249
  }
228
250
  },
229
- import: {index: 3}
230
- })
251
+ import: { index: 3 })
231
252
  end
232
253
  end
233
254
  end
@@ -251,7 +272,7 @@ describe Chewy::Type::Import do
251
272
  before do
252
273
  stub_index(:cities) do
253
274
  define_type City do
254
- field :name, type: 'object', value: ->{ name == 'name1' ? name : {name: name} }
275
+ field :name, type: 'object', value: -> { name == 'name1' ? name : { name: name } }
255
276
  end
256
277
  end
257
278
  end
@@ -291,12 +312,12 @@ describe Chewy::Type::Import do
291
312
  let(:child_city) { City.create(id: 4, country_id: country.id, name: 'city') }
292
313
  let(:city) { CountriesIndex::City }
293
314
 
294
- specify { expect(city.import(child_city)).to eq(true) }
315
+ specify { expect(city.import(child_city)).to eq(true) }
295
316
  specify { expect { city.import child_city }.to update_index(city).and_reindex(child_city) }
296
317
 
297
318
  specify do
298
319
  expect(CountriesIndex.client).to receive(:bulk).with(hash_including(
299
- body: [{ index: { _id: child_city.id, parent: country.id, data: { 'name' => 'city' } } }]
320
+ body: [{ index: { _id: child_city.id, parent: country.id, data: { 'name' => 'city' } } }]
300
321
  ))
301
322
 
302
323
  city.import child_city
@@ -309,10 +330,10 @@ describe Chewy::Type::Import do
309
330
  child_city.update_attributes(country_id: another_country.id)
310
331
 
311
332
  expect(CountriesIndex.client).to receive(:bulk).with(hash_including(
312
- body: [
313
- { delete: { _id: child_city.id, parent: country.id.to_s } },
314
- { index: { _id: child_city.id, parent: another_country.id, data: { 'name' => 'city' } } }
315
- ]
333
+ body: [
334
+ { delete: { _id: child_city.id, parent: country.id.to_s } },
335
+ { index: { _id: child_city.id, parent: another_country.id, data: { 'name' => 'city' } } }
336
+ ]
316
337
  ))
317
338
 
318
339
  city.import child_city
@@ -322,7 +343,7 @@ describe Chewy::Type::Import do
322
343
  child_city.destroy
323
344
 
324
345
  expect(CountriesIndex.client).to receive(:bulk).with(hash_including(
325
- body: [{ delete: { _id: child_city.id, parent: country.id.to_s } }]
346
+ body: [{ delete: { _id: child_city.id, parent: country.id.to_s } }]
326
347
  ))
327
348
 
328
349
  city.import child_city
@@ -332,11 +353,18 @@ describe Chewy::Type::Import do
332
353
  child_city.destroy
333
354
 
334
355
  expect(CountriesIndex.client).to receive(:bulk).with(hash_including(
335
- body: [{ delete: { _id: child_city.id, parent: country.id.to_s } }]
356
+ body: [{ delete: { _id: child_city.id, parent: country.id.to_s } }]
336
357
  ))
337
358
 
338
359
  city.import child_city.id
339
360
  end
361
+
362
+ specify do
363
+ child_city.destroy
364
+
365
+ expect(city.import(child_city)).to eq(true)
366
+ expect(city.import(child_city)).to eq(true)
367
+ end
340
368
  end
341
369
  end
342
370
 
@@ -359,12 +387,12 @@ describe Chewy::Type::Import do
359
387
  end
360
388
  end
361
389
 
362
- specify { expect(country.import(canada)).to eq(true) }
390
+ specify { expect(country.import(canada)).to eq(true) }
363
391
  specify { expect { country.import(canada) }.to update_index(country).and_reindex(canada.country_code) }
364
392
 
365
393
  specify do
366
394
  expect(CountriesIndex.client).to receive(:bulk).with(hash_including(
367
- body: [{ index: { _id: canada.country_code, data: { 'name' => 'Canada', 'rating' => 4 } } }]
395
+ body: [{ index: { _id: canada.country_code, data: { 'name' => 'Canada', 'rating' => 4 } } }]
368
396
  ))
369
397
 
370
398
  country.import canada
@@ -374,7 +402,7 @@ describe Chewy::Type::Import do
374
402
  canada.update_attributes(rating: 9)
375
403
 
376
404
  expect(CountriesIndex.client).to receive(:bulk).with(hash_including(
377
- body: [{ index: { _id: canada.country_code, data: { 'name' => 'Canada', 'rating' => 9 } } }]
405
+ body: [{ index: { _id: canada.country_code, data: { 'name' => 'Canada', 'rating' => 9 } } }]
378
406
  ))
379
407
 
380
408
  country.import canada
@@ -384,12 +412,11 @@ describe Chewy::Type::Import do
384
412
  canada.destroy
385
413
 
386
414
  expect(CountriesIndex.client).to receive(:bulk).with(hash_including(
387
- body: [{ delete: { _id: canada.country_code } }]
415
+ body: [{ delete: { _id: canada.country_code } }]
388
416
  ))
389
417
 
390
418
  country.import canada
391
419
  end
392
-
393
420
  end
394
421
 
395
422
  context 'default_import_options is set' do
@@ -426,7 +453,11 @@ describe Chewy::Type::Import do
426
453
 
427
454
  specify do
428
455
  expect(ActiveSupport::Notifications).to receive(:unsubscribe)
429
- city.import!(dummy_cities) rescue nil
456
+ begin
457
+ city.import!(dummy_cities)
458
+ rescue
459
+ nil
460
+ end
430
461
  end
431
462
  end
432
463
  end
@@ -34,8 +34,8 @@ describe Chewy::Type::Mapping do
34
34
  end
35
35
 
36
36
  describe '.agg' do
37
- specify { expect(product._agg_defs[:named_agg].call).to eq({ avg: { field: 'title.subfield1' } }) }
38
- specify { expect(review._agg_defs[:named_agg].call).to eq({ avg: { field: 'comments.rating' } }) }
37
+ specify { expect(product._agg_defs[:named_agg].call).to eq(avg: { field: 'title.subfield1' }) }
38
+ specify { expect(review._agg_defs[:named_agg].call).to eq(avg: { field: 'comments.rating' }) }
39
39
  end
40
40
 
41
41
  describe '.field' do
@@ -68,26 +68,26 @@ describe Chewy::Type::Mapping do
68
68
  end
69
69
  end
70
70
 
71
- specify { expect(product.mappings_hash[:product][:_parent]).to eq({ type: 'project' }) }
71
+ specify { expect(product.mappings_hash[:product][:_parent]).to eq(type: 'project') }
72
72
  end
73
73
 
74
74
  context do
75
75
  before do
76
76
  stub_index(:products) do
77
77
  define_type :product do
78
- root parent: {'type' => 'project'}, parent_id: -> { project_id } do
78
+ root parent: { 'type' => 'project' }, parent_id: -> { project_id } do
79
79
  field :name, 'surname'
80
80
  end
81
81
  end
82
82
  end
83
83
  end
84
84
 
85
- specify { expect(product.mappings_hash[:product][:_parent]).to eq({ type: 'project' }) }
85
+ specify { expect(product.mappings_hash[:product][:_parent]).to eq(type: 'project') }
86
86
  end
87
87
  end
88
88
  end
89
89
 
90
- context "no root element call" do
90
+ context 'no root element call' do
91
91
  before do
92
92
  stub_index(:products) do
93
93
  define_type :product do
@@ -8,14 +8,20 @@ describe Chewy::Type::Observe do
8
8
  end
9
9
  end
10
10
 
11
- let(:backreferenced) { 3.times.map { |i| double(id: i) } }
12
-
13
- specify { expect { DummiesIndex::Dummy.update_index(backreferenced) }
14
- .to raise_error Chewy::UndefinedUpdateStrategy }
15
- specify { expect { DummiesIndex::Dummy.update_index([]) }
16
- .not_to update_index('dummies#dummy') }
17
- specify { expect { DummiesIndex::Dummy.update_index(nil) }
18
- .not_to update_index('dummies#dummy') }
11
+ let(:backreferenced) { Array.new(3) { |i| double(id: i) } }
12
+
13
+ specify do
14
+ expect { DummiesIndex::Dummy.update_index(backreferenced) }
15
+ .to raise_error Chewy::UndefinedUpdateStrategy
16
+ end
17
+ specify do
18
+ expect { DummiesIndex::Dummy.update_index([]) }
19
+ .not_to update_index('dummies#dummy')
20
+ end
21
+ specify do
22
+ expect { DummiesIndex::Dummy.update_index(nil) }
23
+ .not_to update_index('dummies#dummy')
24
+ end
19
25
  end
20
26
 
21
27
  context 'integration', :orm do
@@ -23,10 +29,10 @@ describe Chewy::Type::Observe do
23
29
 
24
30
  before do
25
31
  city_countries_update_proc = if adapter == :sequel
26
- ->(*) { previous_changes.try(:[], :country_id) || country }
27
- else
28
- ->(*) { changes['country_id'] || previous_changes['country_id'] || country }
29
- end
32
+ ->(*) { previous_changes.try(:[], :country_id) || country }
33
+ else
34
+ ->(*) { changes['country_id'] || previous_changes['country_id'] || country }
35
+ end
30
36
 
31
37
  stub_model(:city) do
32
38
  update_index(->(city) { "cities##{city.class.name.underscore}" }) { self }
@@ -35,7 +41,7 @@ describe Chewy::Type::Observe do
35
41
 
36
42
  stub_model(:country) do
37
43
  update_index('cities#city', if: -> { update_condition }) { cities }
38
- update_index(->{ "countries##{self.class.name.underscore}" }, :self)
44
+ update_index(-> { "countries##{self.class.name.underscore}" }, :self)
39
45
  attr_accessor :update_condition
40
46
  end
41
47
 
@@ -75,7 +81,7 @@ describe Chewy::Type::Observe do
75
81
  context do
76
82
  let!(:country) do
77
83
  Chewy.strategy(:atomic) do
78
- cities = 2.times.map { |i| City.create!(id: i) }
84
+ cities = Array.new(2) { |i| City.create!(id: i) }
79
85
  if adapter == :sequel
80
86
  Country.create(id: 1, update_condition: update_condition).tap do |country|
81
87
  cities.each { |city| country.add_city(city) }
@@ -15,7 +15,7 @@ describe Chewy::Type::Witchcraft do
15
15
 
16
16
  describe '#cauldron' do
17
17
  let(:type) { ProductsIndex::Product }
18
- let(:object) { }
18
+ let(:object) {}
19
19
 
20
20
  context 'empty mapping' do
21
21
  mapping {}
@@ -28,7 +28,7 @@ describe Chewy::Type::Witchcraft do
28
28
  field :age
29
29
  field :tags
30
30
  end
31
- let(:attributes) { { name: 'Name', age: 13, tags: %w[Ruby RoR] } }
31
+ let(:attributes) { { name: 'Name', age: 13, tags: %w(Ruby RoR) } }
32
32
 
33
33
  context do
34
34
  let(:object) { double(attributes) }
@@ -44,12 +44,12 @@ describe Chewy::Type::Witchcraft do
44
44
  context 'simple lambdas' do
45
45
  mapping do
46
46
  field :name
47
- field :age, value: -> (obj) {
47
+ field :age, value: lambda { |obj|
48
48
  obj.age if obj
49
49
  }
50
50
  field :tags, value: -> { tags.map(&:to_sym) }
51
51
  end
52
- let(:attributes) { { name: 'Name', age: 13, tags: %w[Ruby RoR] } }
52
+ let(:attributes) { { name: 'Name', age: 13, tags: %w(Ruby RoR) } }
53
53
 
54
54
  context do
55
55
  let(:object) { double(attributes) }
@@ -59,14 +59,14 @@ describe Chewy::Type::Witchcraft do
59
59
 
60
60
  context 'crutches' do
61
61
  mapping do
62
- field :name, value: -> (o, c) { c.names[0] }
62
+ field :name, value: ->(_o, c) { c.names[0] }
63
63
  end
64
64
  let(:attributes) { { name: 'Name' } }
65
65
 
66
66
  context do
67
67
  let(:object) { double(attributes) }
68
68
  let(:crutches) { double(names: ['Other']) }
69
- specify { expect(type.cauldron.brew(object, crutches)).to eq({name: 'Other'}.as_json) }
69
+ specify { expect(type.cauldron.brew(object, crutches)).to eq({ name: 'Other' }.as_json) }
70
70
  end
71
71
  end
72
72
 
@@ -79,14 +79,18 @@ describe Chewy::Type::Witchcraft do
79
79
  end
80
80
  end
81
81
 
82
- let(:object) { double(queries: [
83
- {title: 'Title1', body: 'Body1'},
84
- {title: 'Title2', body: 'Body2'}
85
- ]) }
86
- specify { expect(type.cauldron.brew(object)).to eq({ queries: [
87
- {title: 'Title1', body: 'This Body1'},
88
- {title: 'Title2', body: 'This Body2'}
89
- ] }.as_json) }
82
+ let(:object) do
83
+ double(queries: [
84
+ { title: 'Title1', body: 'Body1' },
85
+ { title: 'Title2', body: 'Body2' }
86
+ ])
87
+ end
88
+ specify do
89
+ expect(type.cauldron.brew(object)).to eq({ queries: [
90
+ { title: 'Title1', body: 'This Body1' },
91
+ { title: 'Title2', body: 'This Body2' }
92
+ ] }.as_json)
93
+ end
90
94
  end
91
95
 
92
96
  context do
@@ -97,14 +101,18 @@ describe Chewy::Type::Witchcraft do
97
101
  end
98
102
  end
99
103
 
100
- let(:object) { double(queries: [
101
- double(title: 'Title1', body: 'Body1'),
102
- double(title: 'Title2', body: 'Body2')
103
- ]) }
104
- specify { expect(type.cauldron.brew(object)).to eq({ queries: [
105
- {title: 'Title1', body: 'This Body1'},
106
- {title: 'Title2', body: 'This Body2'}
107
- ] }.as_json) }
104
+ let(:object) do
105
+ double(queries: [
106
+ double(title: 'Title1', body: 'Body1'),
107
+ double(title: 'Title2', body: 'Body2')
108
+ ])
109
+ end
110
+ specify do
111
+ expect(type.cauldron.brew(object)).to eq({ queries: [
112
+ { title: 'Title1', body: 'This Body1' },
113
+ { title: 'Title2', body: 'This Body2' }
114
+ ] }.as_json)
115
+ end
108
116
  end
109
117
 
110
118
  context do
@@ -115,39 +123,77 @@ describe Chewy::Type::Witchcraft do
115
123
  end
116
124
  end
117
125
 
118
- let(:object) { double(queries: [
119
- double(title: 'Title1', body: 'Body1'),
120
- double(title: 'Title2', body: 'Body2')
121
- ]) }
122
- specify { expect(type.cauldron.brew(object)).to eq({ queries: [
123
- {title: 'Title1', body: 'This Body1'},
124
- {title: 'Title2', body: 'This Body2'}
125
- ] }.as_json) }
126
+ let(:object) do
127
+ double(queries: [
128
+ double(title: 'Title1', body: 'Body1'),
129
+ double(title: 'Title2', body: 'Body2')
130
+ ])
131
+ end
132
+ specify do
133
+ expect(type.cauldron.brew(object)).to eq({ queries: [
134
+ { title: 'Title1', body: 'This Body1' },
135
+ { title: 'Title2', body: 'This Body2' }
136
+ ] }.as_json)
137
+ end
126
138
  end
127
139
 
128
140
  context do
129
141
  mapping do
130
142
  field :queries do
131
- field :fields, value: -> (o, q) { q.fields } do
143
+ field :fields, value: ->(_o, q) { q.fields } do
132
144
  field :first
133
- field :second, value: -> (o, q, f, c) {
145
+ field :second, value: lambda { |_o, q, f, c|
134
146
  q.value + (f.respond_to?(:second) ? f.second : c.second)
135
147
  }
136
148
  end
137
149
  end
138
150
  end
139
151
 
140
- let(:object) { double(queries: [
141
- double(value: 'Value1', fields: [double(first: 'First1', second: 'Second1'), {first: 'First2'}]),
142
- double(value: 'Value2', fields: double(first: 'First3', second: 'Second2', third: 'Third'))
143
- ]) }
144
- specify { expect(type.cauldron.brew(object, double(second: 'Crutch'))).to eq({queries: [
145
- {fields: [
146
- {first: 'First1', second: 'Value1Second1'},
147
- {first: 'First2', second: 'Value1Crutch'}
148
- ]},
149
- {fields: {first: 'First3', second: 'Value2Second2'}}
150
- ]}.as_json) }
152
+ let(:object) do
153
+ double(queries: [
154
+ double(value: 'Value1', fields: [double(first: 'First1', second: 'Second1'), { first: 'First2' }]),
155
+ double(value: 'Value2', fields: double(first: 'First3', second: 'Second2', third: 'Third'))
156
+ ])
157
+ end
158
+ specify do
159
+ expect(type.cauldron.brew(object, double(second: 'Crutch'))).to eq({ queries: [
160
+ { fields: [
161
+ { first: 'First1', second: 'Value1Second1' },
162
+ { first: 'First2', second: 'Value1Crutch' }
163
+ ] },
164
+ { fields: { first: 'First3', second: 'Value2Second2' } }
165
+ ] }.as_json)
166
+ end
167
+ end
168
+ end
169
+
170
+ context 'dynamic fields' do
171
+ mapping do
172
+ [[:name], [:age]].each do |param|
173
+ field param.first, value: ->(o) { o.send(param[0]) if param[0] }
174
+ end
175
+ end
176
+ let(:attributes) { { name: 'Name', age: 13 } }
177
+
178
+ context do
179
+ let(:object) { double(attributes) }
180
+ specify { expect(type.cauldron.brew(object)).to eq(attributes.as_json) }
181
+ end
182
+ end
183
+
184
+ context 'dynamic fields' do
185
+ mapping do
186
+ def self.custom_value(field)
187
+ ->(o) { o.send(field) }
188
+ end
189
+
190
+ field :name, value: custom_value(:name)
191
+ end
192
+ let(:attributes) { { name: 'Name' } }
193
+
194
+ context do
195
+ let(:object) { double(attributes) }
196
+ specify { expect(type.cauldron.brew(object)).to eq(attributes.as_json) }
151
197
  end
152
198
  end
153
199
  end