chewy 5.1.0 → 7.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (234) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
  6. data/.github/workflows/ruby.yml +73 -0
  7. data/.rubocop.yml +13 -8
  8. data/.rubocop_todo.yml +110 -22
  9. data/CHANGELOG.md +449 -347
  10. data/CODE_OF_CONDUCT.md +14 -0
  11. data/CONTRIBUTING.md +63 -0
  12. data/Gemfile +3 -7
  13. data/Guardfile +3 -1
  14. data/LICENSE.txt +1 -1
  15. data/README.md +423 -311
  16. data/chewy.gemspec +8 -10
  17. data/gemfiles/rails.5.2.activerecord.gemfile +9 -14
  18. data/gemfiles/rails.6.0.activerecord.gemfile +11 -0
  19. data/gemfiles/rails.6.1.activerecord.gemfile +13 -0
  20. data/gemfiles/rails.7.0.activerecord.gemfile +13 -0
  21. data/lib/chewy/config.rb +42 -60
  22. data/lib/chewy/errors.rb +4 -10
  23. data/lib/chewy/fields/base.rb +80 -20
  24. data/lib/chewy/fields/root.rb +7 -17
  25. data/lib/chewy/index/actions.rb +62 -35
  26. data/lib/chewy/{type → index}/adapter/active_record.rb +18 -4
  27. data/lib/chewy/{type → index}/adapter/base.rb +2 -3
  28. data/lib/chewy/{type → index}/adapter/object.rb +28 -32
  29. data/lib/chewy/{type → index}/adapter/orm.rb +26 -24
  30. data/lib/chewy/index/aliases.rb +14 -5
  31. data/lib/chewy/{type → index}/crutch.rb +5 -5
  32. data/lib/chewy/index/import/bulk_builder.rb +311 -0
  33. data/lib/chewy/{type → index}/import/bulk_request.rb +6 -7
  34. data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
  35. data/lib/chewy/{type → index}/import/routine.rb +17 -16
  36. data/lib/chewy/{type → index}/import.rb +51 -33
  37. data/lib/chewy/{type → index}/mapping.rb +32 -37
  38. data/lib/chewy/index/observe/active_record_methods.rb +87 -0
  39. data/lib/chewy/index/observe/callback.rb +34 -0
  40. data/lib/chewy/index/observe.rb +17 -0
  41. data/lib/chewy/index/specification.rb +1 -0
  42. data/lib/chewy/{type → index}/syncer.rb +61 -62
  43. data/lib/chewy/{type → index}/witchcraft.rb +15 -9
  44. data/lib/chewy/{type → index}/wrapper.rb +13 -3
  45. data/lib/chewy/index.rb +46 -96
  46. data/lib/chewy/journal.rb +25 -14
  47. data/lib/chewy/minitest/helpers.rb +86 -13
  48. data/lib/chewy/minitest/search_index_receiver.rb +22 -26
  49. data/lib/chewy/multi_search.rb +62 -0
  50. data/lib/chewy/railtie.rb +6 -20
  51. data/lib/chewy/rake_helper.rb +136 -108
  52. data/lib/chewy/rspec/build_query.rb +12 -0
  53. data/lib/chewy/rspec/helpers.rb +55 -0
  54. data/lib/chewy/rspec/update_index.rb +55 -44
  55. data/lib/chewy/rspec.rb +2 -0
  56. data/lib/chewy/runtime.rb +1 -1
  57. data/lib/chewy/search/loader.rb +19 -41
  58. data/lib/chewy/search/parameters/collapse.rb +16 -0
  59. data/lib/chewy/search/parameters/concerns/query_storage.rb +2 -2
  60. data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
  61. data/lib/chewy/search/parameters/indices.rb +12 -57
  62. data/lib/chewy/search/parameters/none.rb +1 -3
  63. data/lib/chewy/search/parameters/order.rb +6 -19
  64. data/lib/chewy/search/parameters/source.rb +5 -1
  65. data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
  66. data/lib/chewy/search/parameters.rb +7 -4
  67. data/lib/chewy/search/query_proxy.rb +9 -2
  68. data/lib/chewy/search/request.rb +180 -154
  69. data/lib/chewy/search/response.rb +5 -5
  70. data/lib/chewy/search/scoping.rb +7 -8
  71. data/lib/chewy/search/scrolling.rb +16 -13
  72. data/lib/chewy/search.rb +7 -22
  73. data/lib/chewy/stash.rb +19 -30
  74. data/lib/chewy/strategy/active_job.rb +2 -2
  75. data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
  76. data/lib/chewy/strategy/base.rb +10 -0
  77. data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
  78. data/lib/chewy/strategy/sidekiq.rb +3 -2
  79. data/lib/chewy/strategy.rb +5 -19
  80. data/lib/chewy/version.rb +1 -1
  81. data/lib/chewy.rb +36 -80
  82. data/lib/generators/chewy/install_generator.rb +1 -1
  83. data/lib/tasks/chewy.rake +26 -32
  84. data/migration_guide.md +56 -0
  85. data/spec/chewy/config_spec.rb +15 -61
  86. data/spec/chewy/fields/base_spec.rb +432 -145
  87. data/spec/chewy/fields/root_spec.rb +20 -28
  88. data/spec/chewy/fields/time_fields_spec.rb +5 -5
  89. data/spec/chewy/index/actions_spec.rb +388 -55
  90. data/spec/chewy/{type → index}/adapter/active_record_spec.rb +110 -44
  91. data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
  92. data/spec/chewy/index/aliases_spec.rb +3 -3
  93. data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
  94. data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
  95. data/spec/chewy/{type → index}/import/journal_builder_spec.rb +14 -22
  96. data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
  97. data/spec/chewy/{type → index}/import_spec.rb +149 -96
  98. data/spec/chewy/index/mapping_spec.rb +135 -0
  99. data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
  100. data/spec/chewy/index/observe/callback_spec.rb +139 -0
  101. data/spec/chewy/index/observe_spec.rb +143 -0
  102. data/spec/chewy/index/settings_spec.rb +3 -1
  103. data/spec/chewy/index/specification_spec.rb +20 -30
  104. data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
  105. data/spec/chewy/{type → index}/witchcraft_spec.rb +34 -21
  106. data/spec/chewy/index/wrapper_spec.rb +100 -0
  107. data/spec/chewy/index_spec.rb +69 -137
  108. data/spec/chewy/journal_spec.rb +46 -91
  109. data/spec/chewy/minitest/helpers_spec.rb +122 -14
  110. data/spec/chewy/minitest/search_index_receiver_spec.rb +24 -26
  111. data/spec/chewy/multi_search_spec.rb +84 -0
  112. data/spec/chewy/rake_helper_spec.rb +293 -101
  113. data/spec/chewy/rspec/build_query_spec.rb +34 -0
  114. data/spec/chewy/rspec/helpers_spec.rb +61 -0
  115. data/spec/chewy/rspec/update_index_spec.rb +106 -102
  116. data/spec/chewy/runtime_spec.rb +2 -2
  117. data/spec/chewy/search/loader_spec.rb +19 -53
  118. data/spec/chewy/search/pagination/kaminari_examples.rb +3 -5
  119. data/spec/chewy/search/pagination/kaminari_spec.rb +1 -1
  120. data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
  121. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
  122. data/spec/chewy/search/parameters/indices_spec.rb +26 -118
  123. data/spec/chewy/search/parameters/none_spec.rb +1 -1
  124. data/spec/chewy/search/parameters/order_spec.rb +18 -11
  125. data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
  126. data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
  127. data/spec/chewy/search/parameters/source_spec.rb +8 -2
  128. data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
  129. data/spec/chewy/search/parameters_spec.rb +23 -7
  130. data/spec/chewy/search/query_proxy_spec.rb +68 -17
  131. data/spec/chewy/search/request_spec.rb +344 -149
  132. data/spec/chewy/search/response_spec.rb +35 -25
  133. data/spec/chewy/search/scrolling_spec.rb +28 -26
  134. data/spec/chewy/search_spec.rb +69 -59
  135. data/spec/chewy/stash_spec.rb +16 -26
  136. data/spec/chewy/strategy/active_job_spec.rb +23 -10
  137. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
  138. data/spec/chewy/strategy/atomic_spec.rb +9 -10
  139. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
  140. data/spec/chewy/strategy/sidekiq_spec.rb +14 -10
  141. data/spec/chewy/strategy_spec.rb +19 -15
  142. data/spec/chewy_spec.rb +17 -110
  143. data/spec/spec_helper.rb +6 -29
  144. data/spec/support/active_record.rb +43 -5
  145. metadata +102 -198
  146. data/.travis.yml +0 -45
  147. data/Appraisals +0 -81
  148. data/LEGACY_DSL.md +0 -497
  149. data/gemfiles/rails.4.0.activerecord.gemfile +0 -15
  150. data/gemfiles/rails.4.1.activerecord.gemfile +0 -15
  151. data/gemfiles/rails.4.2.activerecord.gemfile +0 -16
  152. data/gemfiles/rails.4.2.mongoid.5.2.gemfile +0 -16
  153. data/gemfiles/rails.5.0.activerecord.gemfile +0 -16
  154. data/gemfiles/rails.5.0.mongoid.6.1.gemfile +0 -16
  155. data/gemfiles/rails.5.1.activerecord.gemfile +0 -16
  156. data/gemfiles/rails.5.1.mongoid.6.3.gemfile +0 -16
  157. data/gemfiles/sequel.4.45.gemfile +0 -11
  158. data/lib/chewy/backports/deep_dup.rb +0 -46
  159. data/lib/chewy/backports/duplicable.rb +0 -91
  160. data/lib/chewy/query/compose.rb +0 -68
  161. data/lib/chewy/query/criteria.rb +0 -191
  162. data/lib/chewy/query/filters.rb +0 -244
  163. data/lib/chewy/query/loading.rb +0 -110
  164. data/lib/chewy/query/nodes/and.rb +0 -25
  165. data/lib/chewy/query/nodes/base.rb +0 -17
  166. data/lib/chewy/query/nodes/bool.rb +0 -34
  167. data/lib/chewy/query/nodes/equal.rb +0 -34
  168. data/lib/chewy/query/nodes/exists.rb +0 -20
  169. data/lib/chewy/query/nodes/expr.rb +0 -28
  170. data/lib/chewy/query/nodes/field.rb +0 -110
  171. data/lib/chewy/query/nodes/has_child.rb +0 -15
  172. data/lib/chewy/query/nodes/has_parent.rb +0 -15
  173. data/lib/chewy/query/nodes/has_relation.rb +0 -59
  174. data/lib/chewy/query/nodes/match_all.rb +0 -11
  175. data/lib/chewy/query/nodes/missing.rb +0 -20
  176. data/lib/chewy/query/nodes/not.rb +0 -25
  177. data/lib/chewy/query/nodes/or.rb +0 -25
  178. data/lib/chewy/query/nodes/prefix.rb +0 -19
  179. data/lib/chewy/query/nodes/query.rb +0 -20
  180. data/lib/chewy/query/nodes/range.rb +0 -63
  181. data/lib/chewy/query/nodes/raw.rb +0 -15
  182. data/lib/chewy/query/nodes/regexp.rb +0 -35
  183. data/lib/chewy/query/nodes/script.rb +0 -20
  184. data/lib/chewy/query/pagination.rb +0 -25
  185. data/lib/chewy/query.rb +0 -1142
  186. data/lib/chewy/search/pagination/will_paginate.rb +0 -43
  187. data/lib/chewy/search/parameters/types.rb +0 -20
  188. data/lib/chewy/strategy/resque.rb +0 -27
  189. data/lib/chewy/strategy/shoryuken.rb +0 -40
  190. data/lib/chewy/type/actions.rb +0 -43
  191. data/lib/chewy/type/adapter/mongoid.rb +0 -67
  192. data/lib/chewy/type/adapter/sequel.rb +0 -93
  193. data/lib/chewy/type/import/bulk_builder.rb +0 -122
  194. data/lib/chewy/type/observe.rb +0 -82
  195. data/lib/chewy/type.rb +0 -117
  196. data/lib/sequel/plugins/chewy_observe.rb +0 -63
  197. data/spec/chewy/query/criteria_spec.rb +0 -700
  198. data/spec/chewy/query/filters_spec.rb +0 -201
  199. data/spec/chewy/query/loading_spec.rb +0 -124
  200. data/spec/chewy/query/nodes/and_spec.rb +0 -12
  201. data/spec/chewy/query/nodes/bool_spec.rb +0 -14
  202. data/spec/chewy/query/nodes/equal_spec.rb +0 -32
  203. data/spec/chewy/query/nodes/exists_spec.rb +0 -18
  204. data/spec/chewy/query/nodes/has_child_spec.rb +0 -59
  205. data/spec/chewy/query/nodes/has_parent_spec.rb +0 -59
  206. data/spec/chewy/query/nodes/match_all_spec.rb +0 -11
  207. data/spec/chewy/query/nodes/missing_spec.rb +0 -16
  208. data/spec/chewy/query/nodes/not_spec.rb +0 -14
  209. data/spec/chewy/query/nodes/or_spec.rb +0 -12
  210. data/spec/chewy/query/nodes/prefix_spec.rb +0 -16
  211. data/spec/chewy/query/nodes/query_spec.rb +0 -12
  212. data/spec/chewy/query/nodes/range_spec.rb +0 -32
  213. data/spec/chewy/query/nodes/raw_spec.rb +0 -11
  214. data/spec/chewy/query/nodes/regexp_spec.rb +0 -43
  215. data/spec/chewy/query/nodes/script_spec.rb +0 -15
  216. data/spec/chewy/query/pagination/kaminari_spec.rb +0 -5
  217. data/spec/chewy/query/pagination/will_paginate_spec.rb +0 -5
  218. data/spec/chewy/query/pagination_spec.rb +0 -39
  219. data/spec/chewy/query_spec.rb +0 -637
  220. data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
  221. data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
  222. data/spec/chewy/search/parameters/types_spec.rb +0 -5
  223. data/spec/chewy/strategy/resque_spec.rb +0 -46
  224. data/spec/chewy/strategy/shoryuken_spec.rb +0 -66
  225. data/spec/chewy/type/actions_spec.rb +0 -50
  226. data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
  227. data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
  228. data/spec/chewy/type/import/bulk_builder_spec.rb +0 -279
  229. data/spec/chewy/type/mapping_spec.rb +0 -173
  230. data/spec/chewy/type/observe_spec.rb +0 -137
  231. data/spec/chewy/type/wrapper_spec.rb +0 -98
  232. data/spec/chewy/type_spec.rb +0 -55
  233. data/spec/support/mongoid.rb +0 -93
  234. data/spec/support/sequel.rb +0 -80
@@ -1,24 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  # TODO: add more specs here later
4
- describe Chewy::Type::Import::Routine do
4
+ describe Chewy::Index::Import::Routine do
5
5
  before { Chewy.massacre }
6
6
  before do
7
7
  stub_index(:cities) do
8
- define_type :city do
9
- field :name
10
- field :object, type: 'object'
11
- end
8
+ field :name
9
+ field :object, type: 'object'
12
10
  end
13
11
  CitiesIndex.create!
14
12
  end
15
13
 
16
- let(:index) { [double(id: 1, name: 'Name', object: {}), double(id: 2, name: 'Name', object: {})] }
17
- let(:delete) { [double(id: 3, name: 'Name')] }
14
+ let(:index) { [double('city_1', id: 1, name: 'Name', object: {}), double('city_2', id: 2, name: 'Name', object: {})] }
15
+ let(:delete) { [double('city_3', id: 3, name: 'Name', object: {})] }
18
16
 
19
17
  describe '#options' do
20
18
  specify do
21
- expect(described_class.new(CitiesIndex::City).options).to eq(
19
+ expect(described_class.new(CitiesIndex).options).to eq(
22
20
  journal: nil,
23
21
  refresh: true,
24
22
  update_failover: true,
@@ -29,7 +27,7 @@ describe Chewy::Type::Import::Routine do
29
27
 
30
28
  specify do
31
29
  expect(described_class.new(
32
- CitiesIndex::City, batch_size: 100, bulk_size: 1.megabyte, refresh: false
30
+ CitiesIndex, batch_size: 100, bulk_size: 1.megabyte, refresh: false
33
31
  ).options).to eq(
34
32
  journal: nil,
35
33
  refresh: false,
@@ -43,7 +41,7 @@ describe Chewy::Type::Import::Routine do
43
41
  context do
44
42
  before { allow(Chewy).to receive_messages(configuration: Chewy.configuration.merge(journal: true)) }
45
43
  specify do
46
- expect(described_class.new(CitiesIndex::City).options).to eq(
44
+ expect(described_class.new(CitiesIndex).options).to eq(
47
45
  journal: true,
48
46
  refresh: true,
49
47
  update_failover: true,
@@ -55,24 +53,26 @@ describe Chewy::Type::Import::Routine do
55
53
 
56
54
  specify do
57
55
  expect(CitiesIndex.client).to receive(:bulk).with(hash_including(refresh: true))
58
- described_class.new(CitiesIndex::City).process(index: index)
56
+ described_class.new(CitiesIndex).process(index: index)
59
57
  end
60
58
 
61
59
  specify do
62
60
  expect(CitiesIndex.client).to receive(:bulk).with(hash_including(refresh: false))
63
- described_class.new(CitiesIndex::City, refresh: false).process(index: index)
61
+ described_class.new(CitiesIndex, refresh: false).process(index: index)
64
62
  end
65
63
  end
66
64
 
67
65
  describe '#parallel_options' do
68
- specify { expect(described_class.new(CitiesIndex::City).parallel_options).to be_nil }
69
- specify { expect(described_class.new(CitiesIndex::City, parallel: true).parallel_options).to eq({}) }
70
- specify { expect(described_class.new(CitiesIndex::City, parallel: 3).parallel_options).to eq(in_processes: 3) }
71
- specify { expect(described_class.new(CitiesIndex::City, parallel: {in_threads: 2}).parallel_options).to eq(in_threads: 2) }
66
+ specify { expect(described_class.new(CitiesIndex).parallel_options).to be_nil }
67
+ specify { expect(described_class.new(CitiesIndex, parallel: true).parallel_options).to eq({}) }
68
+ specify { expect(described_class.new(CitiesIndex, parallel: 3).parallel_options).to eq(in_processes: 3) }
69
+ specify do
70
+ expect(described_class.new(CitiesIndex, parallel: {in_threads: 2}).parallel_options).to eq(in_threads: 2)
71
+ end
72
72
  end
73
73
 
74
74
  describe '#stats' do
75
- subject { described_class.new(CitiesIndex::City) }
75
+ subject { described_class.new(CitiesIndex) }
76
76
 
77
77
  specify { expect(subject.stats).to eq({}) }
78
78
  specify do
@@ -92,8 +92,8 @@ describe Chewy::Type::Import::Routine do
92
92
  end
93
93
 
94
94
  describe '#errors' do
95
- subject { described_class.new(CitiesIndex::City) }
96
- let(:index) { [double(id: 1, name: 'Name', object: ''), double(id: 2, name: 'Name', object: {})] }
95
+ subject { described_class.new(CitiesIndex) }
96
+ let(:index) { [double('city_1', id: 1, name: 'Name', object: ''), double('city_2', id: 2, name: 'Name', object: {})] }
97
97
 
98
98
  specify { expect(subject.errors).to eq([]) }
99
99
  specify do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Chewy::Type::Import do
3
+ describe Chewy::Index::Import do
4
4
  before { Chewy.massacre }
5
5
 
6
6
  before do
@@ -9,14 +9,13 @@ describe Chewy::Type::Import do
9
9
 
10
10
  before do
11
11
  stub_index(:cities) do
12
- define_type City do
13
- field :name
14
- end
12
+ index_scope City
13
+ field :name
15
14
  end
16
15
  end
17
16
 
18
17
  def imported_cities
19
- CitiesIndex::City.all.map do |city|
18
+ CitiesIndex.all.map do |city|
20
19
  city.attributes.except('_score', '_explanation')
21
20
  end
22
21
  end
@@ -37,13 +36,13 @@ describe Chewy::Type::Import do
37
36
  specify 'lazy (default)' do
38
37
  expect(CitiesIndex).to receive(:exists?).and_call_original
39
38
  expect(CitiesIndex).to receive(:create!).and_call_original
40
- CitiesIndex::City.import(dummy_city)
39
+ CitiesIndex.import(dummy_city)
41
40
  end
42
41
 
43
42
  specify 'lazy without objects' do
44
43
  expect(CitiesIndex).not_to receive(:exists?)
45
44
  expect(CitiesIndex).not_to receive(:create!)
46
- CitiesIndex::City.import([])
45
+ CitiesIndex.import([])
47
46
  end
48
47
 
49
48
  context 'skip' do
@@ -58,7 +57,7 @@ describe Chewy::Type::Import do
58
57
  specify do
59
58
  expect(CitiesIndex).not_to receive(:exists?)
60
59
  expect(CitiesIndex).not_to receive(:create!)
61
- CitiesIndex::City.import(dummy_city)
60
+ CitiesIndex.import(dummy_city)
62
61
  end
63
62
  end
64
63
  end
@@ -69,35 +68,36 @@ describe Chewy::Type::Import do
69
68
  specify { expect(import(dummy_cities)).to eq(true) }
70
69
  specify { expect(import(dummy_cities.map(&:id))).to eq(true) }
71
70
 
72
- specify { expect { import([]) }.not_to update_index(CitiesIndex::City) }
73
- specify { expect { import }.to update_index(CitiesIndex::City).and_reindex(dummy_cities) }
74
- specify { expect { import dummy_cities }.to update_index(CitiesIndex::City).and_reindex(dummy_cities) }
75
- specify { expect { import dummy_cities.map(&:id) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities) }
71
+ specify { expect { import([]) }.not_to update_index(CitiesIndex) }
72
+ specify { expect { import }.to update_index(CitiesIndex).and_reindex(dummy_cities) }
73
+ specify { expect { import dummy_cities }.to update_index(CitiesIndex).and_reindex(dummy_cities) }
74
+ specify { expect { import dummy_cities.map(&:id) }.to update_index(CitiesIndex).and_reindex(dummy_cities) }
76
75
 
77
76
  describe 'criteria-driven importing' do
78
77
  let(:names) { %w[name0 name1] }
79
78
 
80
- context 'mongoid', :mongoid do
81
- specify { expect { import(City.where(:name.in => names)) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) }
82
- specify { expect { import(City.where(:name.in => names).map(&:id)) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) }
83
- end
84
-
85
79
  context 'active record', :active_record do
86
- specify { expect { import(City.where(name: names)) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) }
87
- specify { expect { import(City.where(name: names).map(&:id)) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) }
80
+ specify do
81
+ expect { import(City.where(name: names)) }
82
+ .to update_index(CitiesIndex).and_reindex(dummy_cities.first(2))
83
+ end
84
+ specify do
85
+ expect { import(City.where(name: names).map(&:id)) }
86
+ .to update_index(CitiesIndex).and_reindex(dummy_cities.first(2))
87
+ end
88
88
  end
89
89
  end
90
90
 
91
91
  specify do
92
92
  dummy_cities.first.destroy
93
93
  expect { import dummy_cities }
94
- .to update_index(CitiesIndex::City).and_reindex(dummy_cities.from(1)).and_delete(dummy_cities.first)
94
+ .to update_index(CitiesIndex).and_reindex(dummy_cities.from(1)).and_delete(dummy_cities.first)
95
95
  end
96
96
 
97
97
  specify do
98
98
  dummy_cities.first.destroy
99
99
  expect { import dummy_cities.map(&:id) }
100
- .to update_index(CitiesIndex::City).and_reindex(dummy_cities.from(1)).and_delete(dummy_cities.first)
100
+ .to update_index(CitiesIndex).and_reindex(dummy_cities.from(1)).and_delete(dummy_cities.first)
101
101
  end
102
102
 
103
103
  specify do
@@ -120,7 +120,10 @@ describe Chewy::Type::Import do
120
120
  context ':bulk_size' do
121
121
  let!(:dummy_cities) { Array.new(3) { |i| City.create(id: i + 1, name: "name#{i}" * 20) } }
122
122
 
123
- specify { expect { import(dummy_cities, bulk_size: 1.2.kilobyte) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities) }
123
+ specify do
124
+ expect { import(dummy_cities, bulk_size: 1.2.kilobyte) }
125
+ .to update_index(CitiesIndex).and_reindex(dummy_cities)
126
+ end
124
127
 
125
128
  context do
126
129
  before { expect(Chewy.client).to receive(:bulk).exactly(3).times.and_call_original }
@@ -132,31 +135,29 @@ describe Chewy::Type::Import do
132
135
  before do
133
136
  names = %w[name0 name1]
134
137
 
135
- criteria = case adapter
136
- when :mongoid
137
- {:name.in => names}
138
- else
139
- {name: names}
140
- end
138
+ criteria = {name: names}
141
139
 
142
140
  stub_index(:cities) do
143
- define_type City.where(criteria) do
144
- field :name
145
- end
141
+ index_scope City.where(criteria)
142
+ field :name
146
143
  end
147
144
  end
148
145
 
149
- specify { expect { import }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first(2)) }
146
+ specify { expect { import }.to update_index(CitiesIndex).and_reindex(dummy_cities.first(2)) }
150
147
 
151
- context 'mongoid', :mongoid do
148
+ context 'active record', :active_record do
152
149
  specify do
153
- expect { import City.where(_id: dummy_cities.first.id) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first).only
150
+ expect { import City.where(id: dummy_cities.first.id) }
151
+ .to update_index(CitiesIndex).and_reindex(dummy_cities.first).only
154
152
  end
155
- end
156
153
 
157
- context 'active record', :active_record do
158
154
  specify do
159
- expect { import City.where(id: dummy_cities.first.id) }.to update_index(CitiesIndex::City).and_reindex(dummy_cities.first).only
155
+ allow(CitiesIndex).to receive(:import_linear).and_return(double(present?: false))
156
+ allow(CitiesIndex).to receive(:import_parallel).and_return(double(present?: false))
157
+
158
+ expects_no_query(except: /SELECT\s+1\s+AS\s+one\s+FROM/) do
159
+ import City.where(id: dummy_cities.first.id)
160
+ end
160
161
  end
161
162
  end
162
163
  end
@@ -166,28 +167,27 @@ describe Chewy::Type::Import do
166
167
  payload = subscribe_notification
167
168
  dummy_cities.first.destroy
168
169
  import dummy_cities
169
- expect(payload).to eq(type: CitiesIndex::City, import: {delete: 1, index: 2})
170
+ expect(payload).to eq(index: CitiesIndex, import: {delete: 1, index: 2})
170
171
  end
171
172
 
172
173
  specify do
173
174
  payload = subscribe_notification
174
175
  dummy_cities.first.destroy
175
176
  import dummy_cities, batch_size: 2
176
- expect(payload).to eq(type: CitiesIndex::City, import: {delete: 1, index: 2})
177
+ expect(payload).to eq(index: CitiesIndex, import: {delete: 1, index: 2})
177
178
  end
178
179
 
179
180
  specify do
180
181
  payload = subscribe_notification
181
182
  import dummy_cities, batch_size: 2
182
- expect(payload).to eq(type: CitiesIndex::City, import: {index: 3})
183
+ expect(payload).to eq(index: CitiesIndex, import: {index: 3})
183
184
  end
184
185
 
185
186
  context do
186
187
  before do
187
188
  stub_index(:cities) do
188
- define_type City do
189
- field :name, type: 'object'
190
- end
189
+ index_scope City
190
+ field :name, type: 'object'
191
191
  end
192
192
  end
193
193
 
@@ -201,7 +201,7 @@ describe Chewy::Type::Import do
201
201
  specify do
202
202
  payload = subscribe_notification
203
203
  import dummy_cities, batch_size: 2
204
- expect(payload).to eq(type: CitiesIndex::City,
204
+ expect(payload).to eq(index: CitiesIndex,
205
205
  errors: {index: {mapper_parsing_exception => %w[1 2 3]}},
206
206
  import: {index: 3})
207
207
  end
@@ -209,7 +209,7 @@ describe Chewy::Type::Import do
209
209
  end
210
210
 
211
211
  context 'fields' do
212
- before { CitiesIndex::City.import!(dummy_cities.first(2)) }
212
+ before { CitiesIndex.import!(dummy_cities.first(2)) }
213
213
 
214
214
  context do
215
215
  before { expect(Chewy.client).to receive(:bulk).twice.and_call_original }
@@ -217,7 +217,7 @@ describe Chewy::Type::Import do
217
217
  end
218
218
 
219
219
  context do
220
- before { CitiesIndex::City.import!(dummy_cities.last) }
220
+ before { CitiesIndex.import!(dummy_cities.last) }
221
221
  before { expect(Chewy.client).to receive(:bulk).once.and_call_original }
222
222
  specify { expect(import(dummy_cities, update_fields: [:name])).to eq(true) }
223
223
  end
@@ -226,10 +226,8 @@ describe Chewy::Type::Import do
226
226
  context 'fields integrational' do
227
227
  before do
228
228
  stub_index(:cities) do
229
- define_type :city do
230
- field :name
231
- field :object, type: 'object'
232
- end
229
+ field :name
230
+ field :object, type: 'object'
233
231
  end
234
232
  end
235
233
 
@@ -257,9 +255,14 @@ describe Chewy::Type::Import do
257
255
  import(objects, update_fields: %i[name])
258
256
 
259
257
  expect(payload).to eq(
260
- errors: {index: {{'type' => 'mapper_parsing_exception', 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'} => %w[2 4]}},
258
+ errors: {
259
+ index: {{
260
+ 'type' => 'mapper_parsing_exception',
261
+ 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'
262
+ } => %w[2 4]}
263
+ },
261
264
  import: {index: 6},
262
- type: CitiesIndex::City
265
+ index: CitiesIndex
263
266
  )
264
267
  expect(imported_cities).to match_array([
265
268
  {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
@@ -275,9 +278,14 @@ describe Chewy::Type::Import do
275
278
  import(objects, batch_size: 2, update_fields: %i[name])
276
279
 
277
280
  expect(payload).to eq(
278
- errors: {index: {{'type' => 'mapper_parsing_exception', 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'} => %w[2 4]}},
281
+ errors: {
282
+ index: {{
283
+ 'type' => 'mapper_parsing_exception',
284
+ 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'
285
+ } => %w[2 4]}
286
+ },
279
287
  import: {index: 6},
280
- type: CitiesIndex::City
288
+ index: CitiesIndex
281
289
  )
282
290
  expect(imported_cities).to match_array([
283
291
  {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
@@ -287,7 +295,7 @@ describe Chewy::Type::Import do
287
295
  end
288
296
 
289
297
  context do
290
- before { CitiesIndex::City.import!(objects[4]) }
298
+ before { CitiesIndex.import!(objects[4]) }
291
299
 
292
300
  specify do
293
301
  payload = subscribe_notification
@@ -296,9 +304,14 @@ describe Chewy::Type::Import do
296
304
  import(objects, batch_size: 2, update_fields: %i[name])
297
305
 
298
306
  expect(payload).to eq(
299
- errors: {index: {{'type' => 'mapper_parsing_exception', 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'} => %w[2 4]}},
307
+ errors: {
308
+ index: {{
309
+ 'type' => 'mapper_parsing_exception',
310
+ 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'
311
+ } => %w[2 4]}
312
+ },
300
313
  import: {index: 6},
301
- type: CitiesIndex::City
314
+ index: CitiesIndex
302
315
  )
303
316
  expect(imported_cities).to match_array([
304
317
  {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
@@ -309,7 +322,7 @@ describe Chewy::Type::Import do
309
322
  end
310
323
 
311
324
  context do
312
- before { CitiesIndex::City.import!(old_objects[1], old_objects[3], objects[4]) }
325
+ before { CitiesIndex.import!(old_objects[1], old_objects[3], objects[4]) }
313
326
 
314
327
  specify do
315
328
  payload = subscribe_notification
@@ -319,7 +332,7 @@ describe Chewy::Type::Import do
319
332
 
320
333
  expect(payload).to eq(
321
334
  import: {index: 6},
322
- type: CitiesIndex::City
335
+ index: CitiesIndex
323
336
  )
324
337
  expect(imported_cities).to match_array([
325
338
  {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
@@ -338,7 +351,7 @@ describe Chewy::Type::Import do
338
351
 
339
352
  expect(payload).to eq(
340
353
  import: {index: 6},
341
- type: CitiesIndex::City
354
+ index: CitiesIndex
342
355
  )
343
356
  expect(imported_cities).to match_array([
344
357
  {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 11}},
@@ -357,8 +370,8 @@ describe Chewy::Type::Import do
357
370
 
358
371
  # Full match doesn't work here.
359
372
  expect(payload[:errors][:update].keys).to match([
360
- hash_including('type' => 'document_missing_exception', 'reason' => '[city][1]: document missing'),
361
- hash_including('type' => 'document_missing_exception', 'reason' => '[city][3]: document missing')
373
+ hash_including('type' => 'document_missing_exception', 'reason' => '[_doc][1]: document missing'),
374
+ hash_including('type' => 'document_missing_exception', 'reason' => '[_doc][3]: document missing')
362
375
  ])
363
376
  expect(payload[:errors][:update].values).to eq([['1'], ['3']])
364
377
  expect(imported_cities).to match_array([
@@ -370,7 +383,7 @@ describe Chewy::Type::Import do
370
383
  end
371
384
 
372
385
  context do
373
- before { CitiesIndex::City.import!(old_objects) }
386
+ before { CitiesIndex.import!(old_objects) }
374
387
 
375
388
  specify do
376
389
  payload = subscribe_notification
@@ -380,7 +393,7 @@ describe Chewy::Type::Import do
380
393
 
381
394
  expect(payload).to eq(
382
395
  import: {index: 6},
383
- type: CitiesIndex::City
396
+ index: CitiesIndex
384
397
  )
385
398
  expect(imported_cities).to match_array([
386
399
  {'id' => '1', 'name' => 'Name11', 'object' => {'foo' => 1}},
@@ -394,7 +407,7 @@ describe Chewy::Type::Import do
394
407
  end
395
408
 
396
409
  context do
397
- before { CitiesIndex::City.import!(old_objects) }
410
+ before { CitiesIndex.import!(old_objects) }
398
411
 
399
412
  specify do
400
413
  payload = subscribe_notification
@@ -403,9 +416,14 @@ describe Chewy::Type::Import do
403
416
  import(objects, update_fields: %i[object])
404
417
 
405
418
  expect(payload).to eq(
406
- errors: {update: {{'type' => 'mapper_parsing_exception', 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'} => %w[2 4]}},
419
+ errors: {
420
+ update: {{
421
+ 'type' => 'mapper_parsing_exception',
422
+ 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'
423
+ } => %w[2 4]}
424
+ },
407
425
  import: {index: 6},
408
- type: CitiesIndex::City
426
+ index: CitiesIndex
409
427
  )
410
428
  expect(imported_cities).to match_array([
411
429
  {'id' => '1', 'name' => 'Name1', 'object' => {'foo' => 11}},
@@ -423,9 +441,8 @@ describe Chewy::Type::Import do
423
441
  context do
424
442
  before do
425
443
  stub_index(:cities) do
426
- define_type City do
427
- field :name, type: 'object'
428
- end
444
+ index_scope City
445
+ field :name, type: 'object'
429
446
  end
430
447
  end
431
448
 
@@ -437,9 +454,8 @@ describe Chewy::Type::Import do
437
454
  context do
438
455
  before do
439
456
  stub_index(:cities) do
440
- define_type City do
441
- field :name, type: 'object', value: -> { name == 'name1' ? name : {name: name} }
442
- end
457
+ index_scope City
458
+ field :name, type: 'object', value: -> { name == 'name1' ? name : {name: name} }
443
459
  end
444
460
  end
445
461
 
@@ -451,19 +467,19 @@ describe Chewy::Type::Import do
451
467
 
452
468
  context 'default_import_options are set' do
453
469
  before do
454
- CitiesIndex::City.default_import_options(batch_size: 500)
470
+ CitiesIndex.default_import_options(batch_size: 500)
455
471
  end
456
472
 
457
473
  specify do
458
- expect(CitiesIndex::City.adapter).to receive(:import).with(any_args, hash_including(batch_size: 500))
459
- CitiesIndex::City.import
474
+ expect(CitiesIndex.adapter).to receive(:import).with(any_args, hash_including(batch_size: 500))
475
+ CitiesIndex.import
460
476
  end
461
477
  end
462
478
  end
463
479
 
464
480
  describe '.import', :orm do
465
481
  def import(*args)
466
- CitiesIndex::City.import(*args)
482
+ CitiesIndex.import(*args)
467
483
  end
468
484
 
469
485
  it_behaves_like 'importing'
@@ -472,62 +488,99 @@ describe Chewy::Type::Import do
472
488
  def import(*args)
473
489
  options = args.extract_options!
474
490
  options[:parallel] = 0
475
- CitiesIndex::City.import(*args, options)
491
+ CitiesIndex.import(*args, options)
476
492
  end
477
493
 
478
494
  it_behaves_like 'importing'
479
495
  end
496
+
497
+ context 'with parent-child relationship' do
498
+ before do
499
+ stub_model(:comment)
500
+ stub_index(:comments) do
501
+ index_scope Comment
502
+ field :content
503
+ field :comment_type, type: :join, relations: {question: %i[answer comment], answer: :vote}, join: {type: :comment_type, id: :commented_id}
504
+ end
505
+ end
506
+
507
+ let!(:comments) do
508
+ [
509
+ Comment.create!(id: 1, content: 'Where is Nemo?', comment_type: :question),
510
+ Comment.create!(id: 2, content: 'Here.', comment_type: :answer, commented_id: 1),
511
+ Comment.create!(id: 3, content: 'There!', comment_type: :answer, commented_id: 1),
512
+ Comment.create!(id: 4, content: 'Yes, he is here.', comment_type: :vote, commented_id: 2)
513
+ ]
514
+ end
515
+
516
+ def imported_comments
517
+ CommentsIndex.all.map do |comment|
518
+ comment.attributes.except('_score', '_explanation')
519
+ end
520
+ end
521
+
522
+ it 'imports parent and children' do
523
+ CommentsIndex.import!(comments.map(&:id))
524
+
525
+ expect(imported_comments).to match_array([
526
+ {'id' => '1', 'content' => 'Where is Nemo?', 'comment_type' => 'question'},
527
+ {'id' => '2', 'content' => 'Here.', 'comment_type' => {'name' => 'answer', 'parent' => 1}},
528
+ {'id' => '3', 'content' => 'There!', 'comment_type' => {'name' => 'answer', 'parent' => 1}},
529
+ {'id' => '4', 'content' => 'Yes, he is here.', 'comment_type' => {'name' => 'vote', 'parent' => 2}}
530
+ ])
531
+
532
+ answer_ids = CommentsIndex.query(has_parent: {parent_type: 'question', query: {match: {content: 'Where'}}}).pluck(:_id)
533
+ expect(answer_ids).to match_array(%w[2 3])
534
+ end
535
+ end
480
536
  end
481
537
 
482
538
  describe '.import!', :orm do
483
- specify { expect { CitiesIndex::City.import! }.not_to raise_error }
539
+ specify { expect { CitiesIndex.import! }.not_to raise_error }
484
540
 
485
541
  context do
486
542
  before do
487
543
  stub_index(:cities) do
488
- define_type City do
489
- field :name, type: 'object'
490
- end
544
+ index_scope City
545
+ field :name, type: 'object'
491
546
  end
492
547
  end
493
548
 
494
- specify { expect { CitiesIndex::City.import!(dummy_cities) }.to raise_error Chewy::ImportFailed }
549
+ specify { expect { CitiesIndex.import!(dummy_cities) }.to raise_error Chewy::ImportFailed }
495
550
  end
496
551
  end
497
552
 
498
553
  describe '.compose' do
499
554
  before do
500
555
  stub_index(:cities) do
501
- define_type :city do
502
- crutch :names do |collection|
503
- collection.map { |o| [o.name, o.name + '42'] }.to_h
504
- end
505
- field :name, value: ->(o, c) { c.names[o.name] }
506
- field :rating
556
+ crutch :names do |collection|
557
+ collection.map { |o| [o.name, "#{o.name}42"] }.to_h
507
558
  end
559
+ field :name, value: ->(o, c) { c.names[o.name] }
560
+ field :rating
508
561
  end
509
562
  end
510
563
 
511
564
  specify do
512
- expect(CitiesIndex::City.compose(double(name: 'Name', rating: 42)))
565
+ expect(CitiesIndex.compose(double(name: 'Name', rating: 42)))
513
566
  .to eq('name' => 'Name42', 'rating' => 42)
514
567
  end
515
568
 
516
569
  specify do
517
- expect(CitiesIndex::City.compose(double(name: 'Name', rating: 42), fields: %i[name]))
570
+ expect(CitiesIndex.compose(double(name: 'Name', rating: 42), fields: %i[name]))
518
571
  .to eq('name' => 'Name42')
519
572
  end
520
573
 
521
574
  context 'witchcraft' do
522
- before { CitiesIndex::City.witchcraft! }
575
+ before { CitiesIndex.witchcraft! }
523
576
 
524
577
  specify do
525
- expect(CitiesIndex::City.compose(double(name: 'Name', rating: 42)))
578
+ expect(CitiesIndex.compose(double(name: 'Name', rating: 42)))
526
579
  .to eq('name' => 'Name42', 'rating' => 42)
527
580
  end
528
581
 
529
582
  specify do
530
- expect(CitiesIndex::City.compose(double(name: 'Name', rating: 42), fields: %i[name]))
583
+ expect(CitiesIndex.compose(double(name: 'Name', rating: 42), fields: %i[name]))
531
584
  .to eq('name' => 'Name42')
532
585
  end
533
586
  end
@@ -536,12 +589,12 @@ describe Chewy::Type::Import do
536
589
  let(:crutches) { double(names: {'Name' => 'Name43'}) }
537
590
 
538
591
  specify do
539
- expect(CitiesIndex::City.compose(double(name: 'Name', rating: 42), crutches))
592
+ expect(CitiesIndex.compose(double(name: 'Name', rating: 42), crutches))
540
593
  .to eq('name' => 'Name43', 'rating' => 42)
541
594
  end
542
595
 
543
596
  specify do
544
- expect(CitiesIndex::City.compose(double(name: 'Name', rating: 42), crutches, fields: %i[name]))
597
+ expect(CitiesIndex.compose(double(name: 'Name', rating: 42), crutches, fields: %i[name]))
545
598
  .to eq('name' => 'Name43')
546
599
  end
547
600
  end