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
@@ -5,11 +5,11 @@ describe Chewy::Strategy::Atomic, :orm do
5
5
 
6
6
  before do
7
7
  stub_model(:country) do
8
- update_index('countries#country') { self }
8
+ update_index('countries') { self }
9
9
  end
10
10
 
11
11
  stub_index(:countries) do
12
- define_type Country
12
+ index_scope Country
13
13
  end
14
14
  end
15
15
 
@@ -18,35 +18,34 @@ describe Chewy::Strategy::Atomic, :orm do
18
18
 
19
19
  specify do
20
20
  expect { [country, other_country].map(&:save!) }
21
- .to update_index(CountriesIndex::Country, strategy: :atomic)
21
+ .to update_index(CountriesIndex, strategy: :atomic)
22
22
  .and_reindex(country, other_country).only
23
23
  end
24
24
 
25
25
  specify do
26
26
  expect { [country, other_country].map(&:destroy) }
27
- .to update_index(CountriesIndex::Country, strategy: :atomic)
27
+ .to update_index(CountriesIndex, strategy: :atomic)
28
28
  .and_delete(country, other_country).only
29
29
  end
30
30
 
31
31
  context do
32
32
  before do
33
33
  stub_index(:countries) do
34
- define_type Country do
35
- root id: -> { country_code } do
36
- end
34
+ index_scope Country
35
+ root id: -> { country_code } do
37
36
  end
38
37
  end
39
38
  end
40
39
 
41
40
  specify do
42
41
  expect { [country, other_country].map(&:save!) }
43
- .to update_index(CountriesIndex::Country, strategy: :atomic)
42
+ .to update_index(CountriesIndex, strategy: :atomic)
44
43
  .and_reindex('HL', 'WD').only
45
44
  end
46
45
 
47
46
  specify do
48
47
  expect { [country, other_country].map(&:destroy) }
49
- .to update_index(CountriesIndex::Country, strategy: :atomic)
48
+ .to update_index(CountriesIndex, strategy: :atomic)
50
49
  .and_delete('HL', 'WD').only
51
50
  end
52
51
 
@@ -55,7 +54,7 @@ describe Chewy::Strategy::Atomic, :orm do
55
54
  country.save!
56
55
  other_country.destroy
57
56
  end
58
- .to update_index(CountriesIndex::Country, strategy: :atomic)
57
+ .to update_index(CountriesIndex, strategy: :atomic)
59
58
  .and_reindex('HL').and_delete('WD').only
60
59
  end
61
60
  end
@@ -0,0 +1,214 @@
1
+ require 'spec_helper'
2
+
3
+ if defined?(::Sidekiq)
4
+ require 'sidekiq/testing'
5
+
6
+ describe Chewy::Strategy::LazySidekiq do
7
+ around do |example|
8
+ sidekiq_settings = Chewy.settings[:sidekiq]
9
+ Chewy.settings[:sidekiq] = {queue: 'low'}
10
+ Chewy.strategy(:bypass) { example.run }
11
+ Chewy.settings[:sidekiq] = sidekiq_settings
12
+ end
13
+ before { ::Sidekiq::Worker.clear_all }
14
+
15
+ context 'strategy' do
16
+ before do
17
+ stub_model(:city) do
18
+ update_index('cities') { self }
19
+ end
20
+
21
+ stub_index(:cities) do
22
+ index_scope City
23
+ end
24
+ end
25
+
26
+ let(:city) { City.create!(name: 'hello') }
27
+ let(:other_city) { City.create!(name: 'world') }
28
+
29
+ it 'does not update indices synchronously' do
30
+ expect { [city, other_city].map(&:save!) }
31
+ .not_to update_index(CitiesIndex, strategy: :lazy_sidekiq)
32
+ end
33
+
34
+ it 'updates indices asynchronously on record save' do
35
+ expect(::Sidekiq::Client).to receive(:push)
36
+ .with(hash_including(
37
+ 'class' => Chewy::Strategy::LazySidekiq::IndicesUpdateWorker,
38
+ 'queue' => 'low'
39
+ ))
40
+ .and_call_original
41
+ .once
42
+ ::Sidekiq::Testing.inline! do
43
+ expect { [city, other_city].map(&:save!) }
44
+ .to update_index(CitiesIndex, strategy: :lazy_sidekiq)
45
+ .and_reindex(city, other_city).only
46
+ end
47
+ end
48
+
49
+ it 'updates indices asynchronously with falling back to sidekiq strategy on record destroy' do
50
+ expect(::Sidekiq::Client).not_to receive(:push)
51
+ .with(hash_including(
52
+ 'class' => Chewy::Strategy::LazySidekiq::IndicesUpdateWorker,
53
+ 'queue' => 'low'
54
+ ))
55
+ expect(::Sidekiq::Client).to receive(:push)
56
+ .with(hash_including(
57
+ 'class' => Chewy::Strategy::Sidekiq::Worker,
58
+ 'queue' => 'low',
59
+ 'args' => ['CitiesIndex', [city.id, other_city.id]]
60
+ ))
61
+ .and_call_original
62
+ .once
63
+ ::Sidekiq::Testing.inline! do
64
+ expect { [city, other_city].map(&:destroy) }.to update_index(CitiesIndex, strategy: :sidekiq)
65
+ end
66
+ end
67
+
68
+ it 'calls Index#import!' do
69
+ allow(City).to receive(:where).with(id: [city.id, other_city.id]).and_return([city, other_city])
70
+ expect(city).to receive(:run_chewy_callbacks).and_call_original
71
+ expect(other_city).to receive(:run_chewy_callbacks).and_call_original
72
+
73
+ expect do
74
+ ::Sidekiq::Testing.inline! do
75
+ Chewy::Strategy::LazySidekiq::IndicesUpdateWorker.new.perform({'City' => [city.id, other_city.id]})
76
+ end
77
+ end.to update_index(CitiesIndex).and_reindex(city, other_city).only
78
+ end
79
+
80
+ context 'when Chewy.disable_refresh_async is true' do
81
+ before do
82
+ allow(Chewy).to receive(:disable_refresh_async).and_return(true)
83
+ end
84
+
85
+ it 'calls Index#import! with refresh false' do
86
+ allow(City).to receive(:where).with(id: [city.id, other_city.id]).and_return([city, other_city])
87
+ expect(city).to receive(:run_chewy_callbacks).and_call_original
88
+ expect(other_city).to receive(:run_chewy_callbacks).and_call_original
89
+
90
+ expect do
91
+ ::Sidekiq::Testing.inline! do
92
+ Chewy::Strategy::LazySidekiq::IndicesUpdateWorker.new.perform({'City' => [city.id, other_city.id]})
93
+ end
94
+ end.to update_index(CitiesIndex).and_reindex(city, other_city).only.no_refresh
95
+ end
96
+ end
97
+ end
98
+
99
+ context 'integration' do
100
+ around { |example| ::Sidekiq::Testing.inline! { example.run } }
101
+
102
+ let(:update_condition) { true }
103
+
104
+ before do
105
+ city_model
106
+ country_model
107
+
108
+ City.belongs_to :country
109
+ Country.has_many :cities
110
+
111
+ stub_index(:cities) do
112
+ index_scope City
113
+ end
114
+
115
+ stub_index(:countries) do
116
+ index_scope Country
117
+ end
118
+ end
119
+
120
+ context 'state dependent' do
121
+ let(:city_model) do
122
+ stub_model(:city) do
123
+ update_index(-> { 'cities' }, :self)
124
+ update_index('countries') { changes['country_id'] || previous_changes['country_id'] || country }
125
+ end
126
+ end
127
+
128
+ let(:country_model) do
129
+ stub_model(:country) do
130
+ update_index('cities', if: -> { state_dependent_update_condition }) { cities }
131
+ update_index(-> { 'countries' }, :self)
132
+ attr_accessor :state_dependent_update_condition
133
+ end
134
+ end
135
+
136
+ context 'city updates' do
137
+ let!(:country1) { Country.create!(id: 1) }
138
+ let!(:country2) { Country.create!(id: 2) }
139
+ let!(:city) { City.create!(id: 1, country: country1) }
140
+
141
+ it 'does not update index of removed entity because model state on the moment of save cannot be fetched' do
142
+ expect { city.update!(country: nil) }.not_to update_index('countries', strategy: :lazy_sidekiq)
143
+ end
144
+ it 'does not update index of removed entity because model state on the moment of save cannot be fetched' do
145
+ expect { city.update!(country: country2) }.to update_index('countries', strategy: :lazy_sidekiq).and_reindex(country2).only
146
+ end
147
+ end
148
+
149
+ context 'country updates' do
150
+ let!(:country) do
151
+ cities = Array.new(2) { |i| City.create!(id: i) }
152
+ Country.create!(id: 1, cities: cities, state_dependent_update_condition: update_condition)
153
+ end
154
+
155
+ it 'does not update index because state of attribute cannot be fetched' do
156
+ expect { country.save! }.not_to update_index('cities', strategy: :lazy_sidekiq)
157
+ end
158
+ end
159
+ end
160
+
161
+ context 'state independent' do
162
+ let(:city_model) do
163
+ stub_model(:city) do
164
+ update_index(-> { 'cities' }, :self)
165
+ update_index('countries') { country }
166
+ end
167
+ end
168
+
169
+ let(:country_model) do
170
+ stub_model(:country) do
171
+ update_index('cities', if: -> { state_independent_update_condition }) { cities }
172
+ update_index(-> { 'countries' }, :self)
173
+ end
174
+ end
175
+
176
+ before do
177
+ allow_any_instance_of(Country).to receive(:state_independent_update_condition).and_return(update_condition)
178
+ end
179
+
180
+ context 'when city updates' do
181
+ let!(:country1) { Country.create!(id: 1) }
182
+ let!(:country2) { Country.create!(id: 2) }
183
+ let!(:city) { City.create!(id: 1, country: country1) }
184
+
185
+ specify { expect { city.save! }.to update_index('cities', strategy: :lazy_sidekiq).and_reindex(city).only }
186
+ specify { expect { city.save! }.to update_index('countries', strategy: :lazy_sidekiq).and_reindex(country1).only }
187
+
188
+ specify { expect { city.destroy }.not_to update_index('cities').and_reindex(city).only }
189
+ specify { expect { city.destroy }.to update_index('countries', strategy: :sidekiq).and_reindex(country1).only }
190
+
191
+ specify { expect { city.update!(country: nil) }.to update_index('cities', strategy: :lazy_sidekiq).and_reindex(city).only }
192
+ specify { expect { city.update!(country: country2) }.to update_index('cities', strategy: :lazy_sidekiq).and_reindex(city).only }
193
+ end
194
+
195
+ context 'when country updates' do
196
+ let!(:country) do
197
+ cities = Array.new(2) { |i| City.create!(id: i) }
198
+ Country.create!(id: 1, cities: cities)
199
+ end
200
+ specify { expect { country.save! }.to update_index('cities', strategy: :lazy_sidekiq).and_reindex(country.cities).only }
201
+ specify { expect { country.save! }.to update_index('countries', strategy: :lazy_sidekiq).and_reindex(country).only }
202
+
203
+ specify { expect { country.destroy }.to update_index('cities', strategy: :sidekiq).and_reindex(country.cities).only }
204
+ specify { expect { country.destroy }.not_to update_index('countries').and_reindex(country).only }
205
+
206
+ context 'when update condition is false' do
207
+ let(:update_condition) { false }
208
+ specify { expect { country.save! }.not_to update_index('cities', strategy: :lazy_sidekiq) }
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
@@ -4,15 +4,20 @@ if defined?(::Sidekiq)
4
4
  require 'sidekiq/testing'
5
5
 
6
6
  describe Chewy::Strategy::Sidekiq do
7
- around { |example| Chewy.strategy(:bypass) { example.run } }
7
+ around do |example|
8
+ sidekiq_settings = Chewy.settings[:sidekiq]
9
+ Chewy.settings[:sidekiq] = {queue: 'low'}
10
+ Chewy.strategy(:bypass) { example.run }
11
+ Chewy.settings[:sidekiq] = sidekiq_settings
12
+ end
8
13
  before { ::Sidekiq::Worker.clear_all }
9
14
  before do
10
15
  stub_model(:city) do
11
- update_index('cities#city') { self }
16
+ update_index('cities') { self }
12
17
  end
13
18
 
14
19
  stub_index(:cities) do
15
- define_type City
20
+ index_scope City
16
21
  end
17
22
  end
18
23
 
@@ -21,28 +26,27 @@ if defined?(::Sidekiq)
21
26
 
22
27
  specify do
23
28
  expect { [city, other_city].map(&:save!) }
24
- .not_to update_index(CitiesIndex::City, strategy: :sidekiq)
29
+ .not_to update_index(CitiesIndex, strategy: :sidekiq)
25
30
  end
26
31
 
27
32
  specify do
28
- Chewy.settings[:sidekiq] = {queue: 'low'}
29
33
  expect(::Sidekiq::Client).to receive(:push).with(hash_including('queue' => 'low')).and_call_original
30
34
  ::Sidekiq::Testing.inline! do
31
35
  expect { [city, other_city].map(&:save!) }
32
- .to update_index(CitiesIndex::City, strategy: :sidekiq)
36
+ .to update_index(CitiesIndex, strategy: :sidekiq)
33
37
  .and_reindex(city, other_city).only
34
38
  end
35
39
  end
36
40
 
37
41
  specify do
38
- expect(CitiesIndex::City).to receive(:import!).with([city.id, other_city.id], suffix: '201601')
39
- Chewy::Strategy::Sidekiq::Worker.new.perform('CitiesIndex::City', [city.id, other_city.id], suffix: '201601')
42
+ expect(CitiesIndex).to receive(:import!).with([city.id, other_city.id], suffix: '201601')
43
+ Chewy::Strategy::Sidekiq::Worker.new.perform('CitiesIndex', [city.id, other_city.id], suffix: '201601')
40
44
  end
41
45
 
42
46
  specify do
43
47
  allow(Chewy).to receive(:disable_refresh_async).and_return(true)
44
- expect(CitiesIndex::City).to receive(:import!).with([city.id, other_city.id], suffix: '201601', refresh: false)
45
- Chewy::Strategy::Sidekiq::Worker.new.perform('CitiesIndex::City', [city.id, other_city.id], suffix: '201601')
48
+ expect(CitiesIndex).to receive(:import!).with([city.id, other_city.id], suffix: '201601', refresh: false)
49
+ Chewy::Strategy::Sidekiq::Worker.new.perform('CitiesIndex', [city.id, other_city.id], suffix: '201601')
46
50
  end
47
51
  end
48
52
  end
@@ -14,7 +14,10 @@ describe Chewy::Strategy do
14
14
  end
15
15
 
16
16
  describe '#push' do
17
- specify { expect { strategy.push(:unexistant) }.to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`") }
17
+ specify do
18
+ expect { strategy.push(:unexistant) }
19
+ .to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`")
20
+ end
18
21
 
19
22
  specify do
20
23
  expect { strategy.push(:atomic) }
@@ -35,7 +38,10 @@ describe Chewy::Strategy do
35
38
  end
36
39
 
37
40
  describe '#wrap' do
38
- specify { expect { strategy.wrap(:unexistant) {} }.to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`") }
41
+ specify do
42
+ expect { strategy.wrap(:unexistant) {} }
43
+ .to raise_error(RuntimeError).with_message("Can't find update strategy `unexistant`")
44
+ end
39
45
 
40
46
  specify do
41
47
  expect do
@@ -49,11 +55,11 @@ describe Chewy::Strategy do
49
55
  context 'nesting', :orm do
50
56
  before do
51
57
  stub_model(:city) do
52
- update_index('cities#city') { self }
58
+ update_index('cities') { self }
53
59
  end
54
60
 
55
61
  stub_index(:cities) do
56
- define_type City
62
+ index_scope City
57
63
  end
58
64
  end
59
65
 
@@ -64,12 +70,12 @@ describe Chewy::Strategy do
64
70
  around { |example| Chewy.strategy(:bypass) { example.run } }
65
71
 
66
72
  specify do
67
- expect(CitiesIndex::City).not_to receive(:import!)
73
+ expect(CitiesIndex).not_to receive(:import!)
68
74
  [city, other_city].map(&:save!)
69
75
  end
70
76
 
71
77
  specify do
72
- expect(CitiesIndex::City).to receive(:import!).with([city.id, other_city.id]).once
78
+ expect(CitiesIndex).to receive(:import!).with([city.id, other_city.id]).once
73
79
  Chewy.strategy(:atomic) { [city, other_city].map(&:save!) }
74
80
  end
75
81
  end
@@ -78,41 +84,39 @@ describe Chewy::Strategy do
78
84
  around { |example| Chewy.strategy(:urgent) { example.run } }
79
85
 
80
86
  specify do
81
- expect(CitiesIndex::City).to receive(:import!).at_least(2).times
87
+ expect(CitiesIndex).to receive(:import!).at_least(2).times
82
88
  [city, other_city].map(&:save!)
83
89
  end
84
90
 
85
91
  specify do
86
- expect(CitiesIndex::City).to receive(:import!).with([city.id, other_city.id]).once
92
+ expect(CitiesIndex).to receive(:import!).with([city.id, other_city.id]).once
87
93
  Chewy.strategy(:atomic) { [city, other_city].map(&:save!) }
88
94
  end
89
95
 
90
96
  context 'hash passed to urgent' do
91
97
  before do
92
- stub_index(:cities) do
93
- define_type :city
94
- end
98
+ stub_index(:cities)
95
99
 
96
100
  stub_model(:city) do
97
- update_index('cities#city') { {name: name} }
101
+ update_index('cities') { {name: name} }
98
102
  end
99
103
  end
100
104
 
101
105
  specify do
102
106
  [city, other_city].map(&:save!)
103
- expect(CitiesIndex::City.total_count).to eq(4)
107
+ expect(CitiesIndex.total_count).to eq(4)
104
108
  end
105
109
 
106
110
  context do
107
111
  before do
108
112
  stub_model(:city) do
109
- update_index('cities#city') { {id: id.to_s, name: name} }
113
+ update_index('cities') { {id: id.to_s, name: name} }
110
114
  end
111
115
  end
112
116
 
113
117
  specify do
114
118
  [city, other_city].map(&:save!)
115
- expect(CitiesIndex::City.total_count).to eq(2)
119
+ expect(CitiesIndex.total_count).to eq(2)
116
120
  end
117
121
  end
118
122
  end
data/spec/chewy_spec.rb CHANGED
@@ -5,120 +5,29 @@ describe Chewy do
5
5
  expect(Chewy::VERSION).not_to be nil
6
6
  end
7
7
 
8
- describe '.derive_type' do
8
+ describe '.derive_name' do
9
9
  before do
10
10
  stub_const('SomeIndex', Class.new)
11
11
 
12
- stub_index(:developers) do
13
- define_type :developer
14
- end
15
-
16
- stub_index('namespace/autocomplete') do
17
- define_type :developer
18
- define_type :company
19
- end
20
- end
21
-
22
- specify { expect { described_class.derive_type('some#developers') }.to raise_error(Chewy::UnderivableType, /SomeIndex/) }
23
- specify { expect { described_class.derive_type('borogoves#developers') }.to raise_error(Chewy::UnderivableType, /Borogoves/) }
24
- specify { expect { described_class.derive_type('developers#borogoves') }.to raise_error(Chewy::UnderivableType, /DevelopersIndex.*borogoves/) }
25
- specify { expect { described_class.derive_type('namespace/autocomplete') }.to raise_error(Chewy::UnderivableType, %r{AutocompleteIndex.*namespace/autocomplete#type_name}) }
26
-
27
- specify { expect(described_class.derive_type(DevelopersIndex::Developer)).to eq(DevelopersIndex::Developer) }
28
- specify { expect(described_class.derive_type('developers_index')).to eq(DevelopersIndex::Developer) }
29
- specify { expect(described_class.derive_type('developers')).to eq(DevelopersIndex::Developer) }
30
- specify { expect(described_class.derive_type('developers#developer')).to eq(DevelopersIndex::Developer) }
31
- specify { expect(described_class.derive_type('namespace/autocomplete#developer')).to eq(Namespace::AutocompleteIndex::Developer) }
32
- specify { expect(described_class.derive_type('namespace/autocomplete#company')).to eq(Namespace::AutocompleteIndex::Company) }
33
- end
34
-
35
- describe '.derive_types' do
36
- before do
37
- stub_const('SomeIndex', Class.new)
38
-
39
- stub_index(:developers) do
40
- define_type :developer
41
- end
42
-
43
- stub_index('namespace/autocomplete') do
44
- define_type :developer
45
- define_type :company
46
- end
47
- end
48
-
49
- specify { expect { described_class.derive_types('some#developers') }.to raise_error(Chewy::UnderivableType, /SomeIndex/) }
50
- specify { expect { described_class.derive_types('borogoves#developers') }.to raise_error(Chewy::UnderivableType, /Borogoves/) }
51
- specify { expect { described_class.derive_types('developers#borogoves') }.to raise_error(Chewy::UnderivableType, /DevelopersIndex.*borogoves/) }
52
-
53
- specify { expect(described_class.derive_types(Namespace::AutocompleteIndex)).to match_array(Namespace::AutocompleteIndex.types) }
54
- specify { expect(described_class.derive_types(DevelopersIndex::Developer)).to eq([DevelopersIndex::Developer]) }
12
+ stub_index(:developers)
55
13
 
56
- specify { expect(described_class.derive_types('developers_index')).to eq([DevelopersIndex::Developer]) }
57
- specify { expect(described_class.derive_types('developers')).to eq([DevelopersIndex::Developer]) }
58
- specify { expect(described_class.derive_types('developers#developer')).to eq([DevelopersIndex::Developer]) }
59
- specify { expect(described_class.derive_types('namespace/autocomplete')).to match_array(Namespace::AutocompleteIndex.types) }
60
- specify { expect(described_class.derive_types('namespace/autocomplete#developer')).to eq([Namespace::AutocompleteIndex::Developer]) }
61
- specify { expect(described_class.derive_types('namespace/autocomplete#company')).to eq([Namespace::AutocompleteIndex::Company]) }
62
- end
63
-
64
- describe '.create_type' do
65
- before { stub_index(:cities) }
66
-
67
- context 'Symbol' do
68
- subject { described_class.create_type(CitiesIndex, :city) }
69
-
70
- it { is_expected.to be_a Class }
71
- it { is_expected.to be < Chewy::Type }
72
- its(:name) { should == 'CitiesIndex::City' }
73
- its(:index) { should == CitiesIndex }
74
- its(:type_name) { should == 'city' }
14
+ stub_index('namespace/autocomplete')
75
15
  end
76
16
 
77
- context 'simple model' do
78
- before { stub_class(:city) }
79
- subject { described_class.create_type(CitiesIndex, City) }
80
-
81
- it { is_expected.to be_a Class }
82
- it { is_expected.to be < Chewy::Type }
83
- its(:name) { should == 'CitiesIndex::City' }
84
- its(:index) { should == CitiesIndex }
85
- its(:type_name) { should == 'city' }
86
- end
87
-
88
- context 'model scope', :orm do
89
- before { stub_model(:city) }
90
- subject { described_class.create_type(CitiesIndex, City.where(rating: 1)) }
91
-
92
- it { is_expected.to be_a Class }
93
- it { is_expected.to be < Chewy::Type }
94
- its(:name) { should == 'CitiesIndex::City' }
95
- its(:index) { should == CitiesIndex }
96
- its(:type_name) { should == 'city' }
17
+ specify do
18
+ expect { described_class.derive_name('some') }
19
+ .to raise_error(Chewy::UndefinedIndex, /SomeIndex/)
97
20
  end
98
-
99
- context 'Namespaced index' do
100
- before { stub_class(:city) }
101
- before { stub_index('namespace/cities') }
102
-
103
- subject { described_class.create_type(Namespace::CitiesIndex, City) }
104
-
105
- it { is_expected.to be_a Class }
106
- it { is_expected.to be < Chewy::Type }
107
- its(:name) { should == 'Namespace::CitiesIndex::City' }
108
- its(:index) { should == Namespace::CitiesIndex }
109
- its(:type_name) { should == 'city' }
21
+ specify do
22
+ expect { described_class.derive_name('borogoves') }
23
+ .to raise_error(Chewy::UndefinedIndex, /Borogoves/)
110
24
  end
111
25
 
112
- context 'Namespaced model' do
113
- before { stub_class('namespace/city') }
114
-
115
- subject { described_class.create_type(CitiesIndex, Namespace::City) }
116
-
117
- it { is_expected.to be_a Class }
118
- it { is_expected.to be < Chewy::Type }
119
- its(:name) { should == 'CitiesIndex::City' }
120
- its(:index) { should == CitiesIndex }
121
- its(:type_name) { should == 'city' }
26
+ specify { expect(described_class.derive_name(DevelopersIndex)).to eq(DevelopersIndex) }
27
+ specify { expect(described_class.derive_name('developers_index')).to eq(DevelopersIndex) }
28
+ specify { expect(described_class.derive_name('developers')).to eq(DevelopersIndex) }
29
+ specify do
30
+ expect(described_class.derive_name('namespace/autocomplete')).to eq(Namespace::AutocompleteIndex)
122
31
  end
123
32
  end
124
33
 
@@ -130,7 +39,6 @@ describe Chewy do
130
39
  stub_index(:admins).create!
131
40
  allow(Chewy).to receive_messages(configuration: Chewy.configuration.merge(prefix: 'prefix2'))
132
41
  stub_index(:developers).create!
133
- stub_index(:companies).create!
134
42
 
135
43
  Chewy.massacre
136
44
 
@@ -139,17 +47,16 @@ describe Chewy do
139
47
 
140
48
  specify { expect(AdminsIndex.exists?).to eq(true) }
141
49
  specify { expect(DevelopersIndex.exists?).to eq(false) }
142
- specify { expect(CompaniesIndex.exists?).to eq(false) }
143
50
  end
144
51
 
145
52
  describe '.client' do
146
- let!(:initial_client) { Thread.current[:chewy_client] }
53
+ let!(:initial_client) { Chewy.current[:chewy_client] }
147
54
  let(:faraday_block) { proc {} }
148
55
  let(:mock_client) { double(:client) }
149
56
  let(:expected_client_config) { {transport_options: {}} }
150
57
 
151
58
  before do
152
- Thread.current[:chewy_client] = nil
59
+ Chewy.current[:chewy_client] = nil
153
60
  allow(Chewy).to receive_messages(configuration: {transport_options: {proc: faraday_block}})
154
61
 
155
62
  allow(::Elasticsearch::Client).to receive(:new).with(expected_client_config) do |*_args, &passed_block|
@@ -163,7 +70,7 @@ describe Chewy do
163
70
 
164
71
  its(:client) { is_expected.to eq(mock_client) }
165
72
 
166
- after { Thread.current[:chewy_client] = initial_client }
73
+ after { Chewy.current[:chewy_client] = initial_client }
167
74
  end
168
75
 
169
76
  describe '.create_indices' do
data/spec/spec_helper.rb CHANGED
@@ -2,12 +2,7 @@ require 'bundler'
2
2
 
3
3
  Bundler.require
4
4
 
5
- begin
6
- require 'active_record'
7
- require 'sequel'
8
- rescue LoadError
9
- nil
10
- end
5
+ require 'active_record'
11
6
 
12
7
  require 'rspec/its'
13
8
  require 'rspec/collection_matchers'
@@ -21,8 +16,11 @@ require 'support/class_helpers'
21
16
 
22
17
  require 'chewy/rspec'
23
18
 
19
+ host = ENV['ES_HOST'] || 'localhost'
20
+ port = ENV['ES_PORT'] || 9250
21
+
24
22
  Chewy.settings = {
25
- host: 'localhost:9250',
23
+ host: "#{host}:#{port}",
26
24
  wait_for_status: 'green',
27
25
  index: {
28
26
  number_of_shards: 1,
@@ -30,15 +28,8 @@ Chewy.settings = {
30
28
  }
31
29
  }
32
30
 
33
- Chewy.default_field_type = 'string' if Chewy::Runtime.version < '5.0'
34
31
  # Chewy.transport_logger = Logger.new(STDERR)
35
32
 
36
- KEYWORD_FIELD = if Chewy::Runtime.version < '5.0'
37
- {type: 'string', index: 'not_analyzed'}
38
- else
39
- {type: 'keyword'}
40
- end
41
-
42
33
  RSpec.configure do |config|
43
34
  config.mock_with :rspec
44
35
  config.order = :random
@@ -47,20 +38,6 @@ RSpec.configure do |config|
47
38
 
48
39
  config.include FailHelpers
49
40
  config.include ClassHelpers
50
-
51
- Aws.config.update(stub_responses: true) if defined?(::Aws)
52
41
  end
53
42
 
54
- if defined?(::ActiveRecord)
55
- require 'support/active_record'
56
- elsif defined?(::Mongoid)
57
- require 'support/mongoid'
58
- elsif defined?(::Sequel)
59
- require 'support/sequel'
60
- else
61
- RSpec.configure do |config|
62
- %i[orm mongoid active_record sequel].each do |group|
63
- config.filter_run_excluding(group)
64
- end
65
- end
66
- end
43
+ require 'support/active_record'