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
@@ -7,28 +7,30 @@ describe Chewy::Search::Response, :orm do
7
7
  stub_model(:city)
8
8
  stub_model(:country)
9
9
 
10
- stub_index(:places) do
11
- define_type City do
12
- field :name
13
- field :rating, type: 'integer'
14
- end
15
-
16
- define_type Country do
17
- field :name
18
- field :rating, type: 'integer'
19
- end
10
+ stub_index(:cities) do
11
+ index_scope City
12
+ field :name
13
+ field :rating, type: 'integer'
14
+ end
15
+ stub_index(:countries) do
16
+ index_scope Country
17
+ field :name
18
+ field :rating, type: 'integer'
20
19
  end
21
20
  end
22
21
 
23
- before { PlacesIndex.import!(cities: cities, countries: countries) }
22
+ before do
23
+ CitiesIndex.import!(cities: cities)
24
+ CountriesIndex.import!(countries)
25
+ end
24
26
 
25
27
  let(:cities) { Array.new(2) { |i| City.create!(rating: i, name: "city #{i}") } }
26
28
  let(:countries) { Array.new(2) { |i| Country.create!(rating: i + 2, name: "country #{i}") } }
27
29
 
28
- let(:request) { Chewy::Search::Request.new(PlacesIndex).order(:rating) }
30
+ let(:request) { Chewy::Search::Request.new(CitiesIndex, CountriesIndex).order(:rating) }
29
31
  let(:raw_response) { request.send(:perform) }
30
32
  let(:load_options) { {} }
31
- let(:loader) { Chewy::Search::Loader.new(indexes: [PlacesIndex], **load_options) }
33
+ let(:loader) { Chewy::Search::Loader.new(indexes: [CitiesIndex, CountriesIndex], **load_options) }
32
34
  subject { described_class.new(raw_response, loader) }
33
35
 
34
36
  describe '#hits' do
@@ -59,7 +61,7 @@ describe Chewy::Search::Response, :orm do
59
61
  specify { expect(subject.max_score).to be_nil }
60
62
 
61
63
  context do
62
- let(:request) { Chewy::Search::Request.new(PlacesIndex).query(range: {rating: {lte: 42}}) }
64
+ let(:request) { Chewy::Search::Request.new(CitiesIndex).query(range: {rating: {lte: 42}}) }
63
65
  specify { expect(subject.max_score).to eq(1.0) }
64
66
  end
65
67
  end
@@ -69,10 +71,13 @@ describe Chewy::Search::Response, :orm do
69
71
 
70
72
  context do
71
73
  let(:request) do
72
- Chewy::Search::Request.new(PlacesIndex)
74
+ Chewy::Search::Request.new(CitiesIndex)
73
75
  .query(script: {script: {inline: 'sleep(100); true', lang: 'groovy'}})
74
76
  end
75
- specify { expect(subject.took).to be > 100 }
77
+ specify do
78
+ pending
79
+ expect(subject.took).to be > 100
80
+ end
76
81
  end
77
82
  end
78
83
 
@@ -81,10 +86,13 @@ describe Chewy::Search::Response, :orm do
81
86
 
82
87
  context do
83
88
  let(:request) do
84
- Chewy::Search::Request.new(PlacesIndex)
89
+ Chewy::Search::Request.new(CitiesIndex)
85
90
  .query(script: {script: {inline: 'sleep(100); true', lang: 'groovy'}}).timeout('10ms')
86
91
  end
87
- specify { expect(subject.timed_out?).to eq(true) }
92
+ specify do
93
+ pending
94
+ expect(subject.timed_out?).to eq(true)
95
+ end
88
96
  end
89
97
  end
90
98
 
@@ -93,7 +101,7 @@ describe Chewy::Search::Response, :orm do
93
101
 
94
102
  context do
95
103
  let(:request) do
96
- Chewy::Search::Request.new(PlacesIndex).suggest(
104
+ Chewy::Search::Request.new(CitiesIndex).suggest(
97
105
  my_suggestion: {
98
106
  text: 'city country',
99
107
  term: {
@@ -117,7 +125,9 @@ describe Chewy::Search::Response, :orm do
117
125
  specify { expect(subject.aggs).to eq({}) }
118
126
 
119
127
  context do
120
- let(:request) { Chewy::Search::Request.new(PlacesIndex).aggs(avg_rating: {avg: {field: :rating}}) }
128
+ let(:request) do
129
+ Chewy::Search::Request.new(CitiesIndex, CountriesIndex).aggs(avg_rating: {avg: {field: :rating}})
130
+ end
121
131
  specify { expect(subject.aggs).to eq('avg_rating' => {'value' => 1.5}) }
122
132
  end
123
133
  end
@@ -127,7 +137,7 @@ describe Chewy::Search::Response, :orm do
127
137
  specify { expect(subject.wrappers).to have(4).items }
128
138
  specify do
129
139
  expect(subject.wrappers.map(&:class).uniq)
130
- .to contain_exactly(PlacesIndex::City, PlacesIndex::Country)
140
+ .to contain_exactly(CitiesIndex, CountriesIndex)
131
141
  end
132
142
  specify { expect(subject.wrappers.map(&:_data)).to eq(subject.hits) }
133
143
 
@@ -149,14 +159,14 @@ describe Chewy::Search::Response, :orm do
149
159
  context do
150
160
  let(:raw_response) do
151
161
  {'hits' => {'hits' => [
152
- {'_index' => 'places',
162
+ {'_index' => 'cities',
153
163
  '_type' => 'city',
154
164
  '_id' => '1',
155
165
  '_score' => 1.3,
156
166
  '_source' => {'id' => 2, 'rating' => 0}}
157
167
  ]}}
158
168
  end
159
- specify { expect(subject.wrappers.first).to be_a(PlacesIndex::City) }
169
+ specify { expect(subject.wrappers.first).to be_a(CitiesIndex) }
160
170
  specify { expect(subject.wrappers.first.id).to eq(2) }
161
171
  specify { expect(subject.wrappers.first.rating).to eq(0) }
162
172
  specify { expect(subject.wrappers.first._score).to eq(1.3) }
@@ -166,14 +176,14 @@ describe Chewy::Search::Response, :orm do
166
176
  context do
167
177
  let(:raw_response) do
168
178
  {'hits' => {'hits' => [
169
- {'_index' => 'places',
179
+ {'_index' => 'countries',
170
180
  '_type' => 'country',
171
181
  '_id' => '2',
172
182
  '_score' => 1.2,
173
183
  '_explanation' => {foo: 'bar'}}
174
184
  ]}}
175
185
  end
176
- specify { expect(subject.wrappers.first).to be_a(PlacesIndex::Country) }
186
+ specify { expect(subject.wrappers.first).to be_a(CountriesIndex) }
177
187
  specify { expect(subject.wrappers.first.id).to eq('2') }
178
188
  specify { expect(subject.wrappers.first.rating).to be_nil }
179
189
  specify { expect(subject.wrappers.first._score).to eq(1.2) }
@@ -7,25 +7,27 @@ describe Chewy::Search::Scrolling, :orm do
7
7
  stub_model(:city)
8
8
  stub_model(:country)
9
9
 
10
- stub_index(:places) do
11
- define_type City do
12
- field :name
13
- field :rating, type: 'integer'
14
- end
15
-
16
- define_type Country do
17
- field :name
18
- field :rating, type: 'integer'
19
- end
10
+ stub_index(:cities) do
11
+ index_scope City
12
+ field :name
13
+ field :rating, type: 'integer'
14
+ end
15
+ stub_index(:countries) do
16
+ index_scope Country
17
+ field :name
18
+ field :rating, type: 'integer'
20
19
  end
21
20
  end
22
21
 
23
- let(:request) { Chewy::Search::Request.new(PlacesIndex).order(:rating) }
22
+ let(:request) { Chewy::Search::Request.new(CitiesIndex, CountriesIndex).order(:rating) }
24
23
 
25
24
  specify { expect(request.scroll_batches.to_a).to eq([]) }
26
25
 
27
26
  context do
28
- before { PlacesIndex.import!(cities: cities, countries: countries) }
27
+ before do
28
+ CitiesIndex.import!(cities)
29
+ CountriesIndex.import!(countries: countries)
30
+ end
29
31
 
30
32
  let(:cities) { Array.new(2) { |i| City.create!(rating: i, name: "city #{i}") } }
31
33
  let(:countries) { Array.new(3) { |i| Country.create!(rating: i + 2, name: "country #{i}") } }
@@ -61,9 +63,9 @@ describe Chewy::Search::Scrolling, :orm do
61
63
  context do
62
64
  before { expect(Chewy.client).not_to receive(:scroll) }
63
65
  it 'respects limit and terminate_after' do
64
- expect(request.terminate_after(2).limit(4).scroll_batches(batch_size: 3).map do |batch|
66
+ expect(request.terminate_after(1).limit(4).scroll_batches(batch_size: 3).map do |batch|
65
67
  batch.map { |hit| hit['_source']['rating'] }
66
- end).to eq([[0, 1]])
68
+ end).to eq([[0, 2]])
67
69
  end
68
70
  end
69
71
 
@@ -103,6 +105,11 @@ describe Chewy::Search::Scrolling, :orm do
103
105
  end
104
106
  end
105
107
 
108
+ it 'clears the scroll after completion' do
109
+ expect(Chewy.client).to receive(:clear_scroll).with(body: {scroll_id: anything}).once.and_call_original
110
+ request.scroll_batches(batch_size: 3) {}
111
+ end
112
+
106
113
  context 'instrumentation' do
107
114
  specify do
108
115
  outer_payload = []
@@ -110,21 +117,16 @@ describe Chewy::Search::Scrolling, :orm do
110
117
  outer_payload << payload
111
118
  end
112
119
  request.scroll_batches(batch_size: 3).to_a
113
-
114
120
  expect(outer_payload).to match_array([
115
121
  hash_including(
116
- index: PlacesIndex,
117
- indexes: [PlacesIndex],
118
- request: {index: ['places'], type: %w[city country], body: {sort: ['rating']}, size: 3, scroll: '1m'},
119
- type: [PlacesIndex::City, PlacesIndex::Country],
120
- types: [PlacesIndex::City, PlacesIndex::Country]
122
+ index: [CitiesIndex, CountriesIndex],
123
+ indexes: [CitiesIndex, CountriesIndex],
124
+ request: {index: %w[cities countries], body: {sort: ['rating']}, size: 3, scroll: '1m'}
121
125
  ),
122
126
  hash_including(
123
- index: PlacesIndex,
124
- indexes: [PlacesIndex],
125
- request: {scroll: '1m', scroll_id: an_instance_of(String)},
126
- type: [PlacesIndex::City, PlacesIndex::Country],
127
- types: [PlacesIndex::City, PlacesIndex::Country]
127
+ index: [CitiesIndex, CountriesIndex],
128
+ indexes: [CitiesIndex, CountriesIndex],
129
+ request: {scroll: '1m', scroll_id: an_instance_of(String)}
128
130
  )
129
131
  ])
130
132
  end
@@ -149,7 +151,7 @@ describe Chewy::Search::Scrolling, :orm do
149
151
  end
150
152
  specify do
151
153
  expect(request.scroll_wrappers(batch_size: 2).map(&:class).uniq)
152
- .to eq([PlacesIndex::City, PlacesIndex::Country])
154
+ .to eq([CitiesIndex, CountriesIndex])
153
155
  end
154
156
  end
155
157
 
@@ -4,48 +4,34 @@ describe Chewy::Search do
4
4
  before { Chewy.massacre }
5
5
 
6
6
  before do
7
- stub_index(:products) do
8
- define_type :product
9
- define_type :product2
10
- end
7
+ stub_index(:products)
11
8
  end
12
9
 
13
- let(:product) { ProductsIndex::Product }
14
-
15
10
  describe '.all' do
16
11
  specify { expect(ProductsIndex.all).to be_a(Chewy::Search::Request) }
17
- specify { expect(product.all).to be_a(Chewy::Search::Request) }
18
12
 
19
13
  context do
20
14
  before { allow(Chewy).to receive_messages(search_class: Chewy::Search::Request) }
21
15
 
22
16
  specify { expect(ProductsIndex.all).to be_a(Chewy::Search::Request) }
23
- specify { expect(product.all).to be_a(Chewy::Search::Request) }
24
17
  end
25
18
  end
26
19
 
27
20
  describe '.search_string' do
28
21
  specify do
29
- expect(ProductsIndex.client).to receive(:search).with(hash_including(q: 'hello')).twice
22
+ expect(ProductsIndex.client).to receive(:search).with(hash_including(q: 'hello')).once
30
23
  ProductsIndex.search_string('hello')
31
- product.search_string('hello')
32
24
  end
33
25
 
34
26
  specify do
35
- expect(ProductsIndex.client).to receive(:search).with(hash_including(explain: true)).twice
27
+ expect(ProductsIndex.client).to receive(:search).with(hash_including(explain: true)).once
36
28
  ProductsIndex.search_string('hello', explain: true)
37
- product.search_string('hello', explain: true)
38
29
  end
39
30
 
40
31
  specify do
41
- expect(ProductsIndex.client).to receive(:search).with(hash_including(index: ['products'], type: %w[product product2]))
32
+ expect(ProductsIndex.client).to receive(:search).with(hash_including(index: ['products'])).once
42
33
  ProductsIndex.search_string('hello')
43
34
  end
44
-
45
- specify do
46
- expect(ProductsIndex.client).to receive(:search).with(hash_including(index: ['products'], type: ['product']))
47
- product.search_string('hello')
48
- end
49
35
  end
50
36
 
51
37
  context 'named scopes' do
@@ -53,7 +39,7 @@ describe Chewy::Search do
53
39
  stub_model(:city)
54
40
  stub_model(:country)
55
41
 
56
- stub_index(:places) do
42
+ stub_index(:cities) do
57
43
  def self.by_rating(value)
58
44
  filter { match rating: value }
59
45
  end
@@ -62,56 +48,80 @@ describe Chewy::Search do
62
48
  filter { match name: "Name#{index}" }
63
49
  end
64
50
 
65
- define_type City do
66
- def self.by_rating
67
- filter { match rating: yield }
68
- end
51
+ def self.by_rating_with_kwargs(value, options:) # rubocop:disable Lint/UnusedMethodArgument
52
+ filter { match rating: value }
53
+ end
69
54
 
70
- def self.by_index(index)
71
- filter { match name: "Name#{index}" }
72
- end
55
+ index_scope City
56
+ field :name, type: 'keyword'
57
+ field :rating, type: :integer
58
+ end
73
59
 
74
- field :name, KEYWORD_FIELD
75
- field :rating, type: :integer
60
+ stub_index(:countries) do
61
+ def self.by_rating(value)
62
+ filter { match rating: value }
76
63
  end
77
64
 
78
- define_type Country do
79
- field :name, KEYWORD_FIELD
80
- field :rating, type: :integer
65
+ def self.by_name(index)
66
+ filter { match name: "Name#{index}" }
81
67
  end
68
+
69
+ index_scope Country
70
+ field :name, type: 'keyword'
71
+ field :rating, type: :integer
82
72
  end
83
73
  end
84
74
 
85
75
  let!(:cities) { Array.new(3) { |i| City.create! rating: i + 1, name: "Name#{i + 2}" } }
86
76
  let!(:countries) { Array.new(3) { |i| Country.create! rating: i + 1, name: "Name#{i + 3}" } }
87
77
 
88
- before { PlacesIndex.import! city: cities, country: countries }
89
-
90
- specify { expect(PlacesIndex.by_rating(1).map(&:rating)).to eq([1, 1]) }
91
- specify { expect(PlacesIndex.by_rating(1).map(&:class)).to match_array([PlacesIndex::City, PlacesIndex::Country]) }
92
- specify { expect(PlacesIndex.by_rating(1).by_name(2).map(&:rating)).to eq([1]) }
93
- specify { expect(PlacesIndex.by_rating(1).by_name(2).map(&:class)).to eq([PlacesIndex::City]) }
94
- specify { expect(PlacesIndex.by_name(3).map(&:rating)).to eq([2, 1]) }
95
- specify { expect(PlacesIndex.by_name(3).map(&:class)).to eq([PlacesIndex::City, PlacesIndex::Country]) }
96
- specify { expect(PlacesIndex.order(:name).by_rating(1).map(&:rating)).to eq([1, 1]) }
97
- specify { expect(PlacesIndex.order(:name).by_rating(1).map(&:class)).to match_array([PlacesIndex::City, PlacesIndex::Country]) }
98
-
99
- specify { expect(PlacesIndex::City.by_rating { 2 }.map(&:rating)).to eq([2]) }
100
- specify { expect(PlacesIndex::City.by_rating { 2 }.map(&:class)).to eq([PlacesIndex::City]) }
101
- specify { expect(PlacesIndex::City.by_rating { 2 }.by_name(3).map(&:rating)).to eq([2]) }
102
- specify { expect(PlacesIndex::City.by_rating { 2 }.by_name(3).map(&:class)).to eq([PlacesIndex::City]) }
103
- specify { expect(PlacesIndex::City.by_name(3).map(&:rating)).to eq([2]) }
104
- specify { expect(PlacesIndex::City.by_index(3).map(&:rating)).to eq([2]) }
105
- specify { expect(PlacesIndex::City.order(:name).by_name(3).map(&:rating)).to eq([2]) }
106
- specify { expect(PlacesIndex::City.order(:name).by_index(3).map(&:rating)).to eq([2]) }
107
- specify { expect(PlacesIndex::City.order(:name).by_rating { 2 }.map(&:rating)).to eq([2]) }
108
- specify { expect(PlacesIndex::City.order(:name).by_rating { 2 }.map(&:class)).to eq([PlacesIndex::City]) }
109
-
110
- specify { expect(PlacesIndex::Country.by_rating(3).map(&:rating)).to eq([3]) }
111
- specify { expect(PlacesIndex::Country.by_rating(3).map(&:class)).to eq([PlacesIndex::Country]) }
112
- specify { expect(PlacesIndex::Country.by_rating(3).by_name(5).map(&:rating)).to eq([3]) }
113
- specify { expect(PlacesIndex::Country.by_rating(3).by_name(5).map(&:class)).to eq([PlacesIndex::Country]) }
114
- specify { expect(PlacesIndex::Country.order(:name).by_rating(3).map(&:rating)).to eq([3]) }
115
- specify { expect(PlacesIndex::Country.order(:name).by_rating(3).map(&:class)).to eq([PlacesIndex::Country]) }
78
+ before do
79
+ CitiesIndex.import!(cities)
80
+ CountriesIndex.import!(country: countries)
81
+ end
82
+
83
+ specify { expect(CitiesIndex.indices(CountriesIndex).by_rating(1).map(&:rating)).to eq([1, 1]) }
84
+ specify do
85
+ expect(CitiesIndex.indices(CountriesIndex).by_rating(1).map(&:class))
86
+ .to match_array([CitiesIndex, CountriesIndex])
87
+ end
88
+ specify { expect(CitiesIndex.indices(CountriesIndex).by_rating(1).by_name(2).map(&:rating)).to eq([1]) }
89
+ specify do
90
+ expect(CitiesIndex.indices(CountriesIndex).by_rating(1).by_name(2).map(&:class))
91
+ .to eq([CitiesIndex])
92
+ end
93
+ specify { expect(CitiesIndex.indices(CountriesIndex).by_name(3).map(&:rating)).to eq([2, 1]) }
94
+ specify do
95
+ expect(CitiesIndex.indices(CountriesIndex).by_name(3).map(&:class))
96
+ .to eq([CitiesIndex, CountriesIndex])
97
+ end
98
+ specify { expect(CitiesIndex.indices(CountriesIndex).order(:name).by_rating(1).map(&:rating)).to eq([1, 1]) }
99
+ specify do
100
+ expect(CitiesIndex.indices(CountriesIndex).order(:name).by_rating(1).map(&:class))
101
+ .to match_array([CitiesIndex, CountriesIndex])
102
+ end
103
+
104
+ specify { expect(CitiesIndex.by_rating(2).map(&:rating)).to eq([2]) }
105
+ specify { expect(CitiesIndex.by_rating(2).map(&:class)).to eq([CitiesIndex]) }
106
+ specify { expect(CitiesIndex.by_rating(2).by_name(3).map(&:rating)).to eq([2]) }
107
+ specify { expect(CitiesIndex.by_rating(2).by_name(3).map(&:class)).to eq([CitiesIndex]) }
108
+ specify { expect(CitiesIndex.by_name(3).map(&:rating)).to eq([2]) }
109
+ specify { expect(CitiesIndex.by_name(3).map(&:rating)).to eq([2]) }
110
+ specify { expect(CitiesIndex.order(:name).by_name(3).map(&:rating)).to eq([2]) }
111
+ specify { expect(CitiesIndex.order(:name).by_name(3).map(&:rating)).to eq([2]) }
112
+ specify { expect(CitiesIndex.order(:name).by_rating(2).map(&:rating)).to eq([2]) }
113
+ specify { expect(CitiesIndex.order(:name).by_rating(2).map(&:class)).to eq([CitiesIndex]) }
114
+
115
+ specify { expect(CountriesIndex.by_rating(3).map(&:rating)).to eq([3]) }
116
+ specify { expect(CountriesIndex.by_rating(3).map(&:class)).to eq([CountriesIndex]) }
117
+ specify { expect(CountriesIndex.by_rating(3).by_name(5).map(&:rating)).to eq([3]) }
118
+ specify { expect(CountriesIndex.by_rating(3).by_name(5).map(&:class)).to eq([CountriesIndex]) }
119
+ specify { expect(CountriesIndex.order(:name).by_rating(3).map(&:rating)).to eq([3]) }
120
+ specify { expect(CountriesIndex.order(:name).by_rating(3).map(&:class)).to eq([CountriesIndex]) }
121
+
122
+ specify 'supports keyword arguments' do
123
+ expect(CitiesIndex.by_rating_with_kwargs(3, options: 'blah blah blah').map(&:rating)).to eq([3])
124
+ expect(CitiesIndex.order(:name).by_rating_with_kwargs(3, options: 'blah blah blah').map(&:rating)).to eq([3])
125
+ end
116
126
  end
117
127
  end
@@ -9,11 +9,11 @@ describe Chewy::Stash::Journal, :orm do
9
9
 
10
10
  before do
11
11
  stub_model(:city)
12
- stub_index(:places) do
13
- define_type City
14
- define_type :country
12
+ stub_index(:cities) do
13
+ index_scope City
15
14
  end
16
- stub_index(:users) { define_type :user }
15
+ stub_index(:countries)
16
+ stub_index(:users)
17
17
  stub_index(:borogoves)
18
18
  end
19
19
 
@@ -21,12 +21,12 @@ describe Chewy::Stash::Journal, :orm do
21
21
  after { Timecop.return }
22
22
 
23
23
  before do
24
- PlacesIndex::City.import!(City.new(id: 1, name: 'City'), journal: true)
24
+ CitiesIndex.import!(City.new(id: 1, name: 'City'), journal: true)
25
25
  Timecop.travel(Time.now + 1.minute) do
26
- PlacesIndex::Country.import!([id: 2, name: 'Country'], journal: true)
26
+ CountriesIndex.import!([id: 2, name: 'Country'], journal: true)
27
27
  end
28
28
  Timecop.travel(Time.now + 2.minutes) do
29
- UsersIndex::User.import!([id: 3, name: 'User'], journal: true)
29
+ UsersIndex.import!([id: 3, name: 'User'], journal: true)
30
30
  end
31
31
  end
32
32
 
@@ -49,11 +49,11 @@ describe Chewy::Stash::Journal, :orm do
49
49
  .to contain_exactly([{'id' => 3, 'name' => 'User'}])
50
50
  end
51
51
  specify do
52
- expect(described_class.entries(Time.now - 30.seconds, only: [PlacesIndex::City, UsersIndex]).map(&:references))
52
+ expect(described_class.entries(Time.now - 30.seconds, only: [CitiesIndex, UsersIndex]).map(&:references))
53
53
  .to contain_exactly([1], [{'id' => 3, 'name' => 'User'}])
54
54
  end
55
55
  specify do
56
- expect(described_class.entries(Time.now + 30.seconds, only: [PlacesIndex::City, UsersIndex]).map(&:references))
56
+ expect(described_class.entries(Time.now + 30.seconds, only: [CitiesIndex, UsersIndex]).map(&:references))
57
57
  .to contain_exactly([{'id' => 3, 'name' => 'User'}])
58
58
  end
59
59
  specify do
@@ -68,28 +68,18 @@ describe Chewy::Stash::Journal, :orm do
68
68
  specify { expect(fetch_deleted_number(described_class.clean(Time.now + 90.seconds))).to eq(2) }
69
69
  specify { expect(fetch_deleted_number(described_class.clean(only: BorogovesIndex))).to eq(0) }
70
70
  specify { expect(fetch_deleted_number(described_class.clean(only: UsersIndex))).to eq(1) }
71
- specify { expect(fetch_deleted_number(described_class.clean(only: [PlacesIndex::City, UsersIndex]))).to eq(2) }
71
+ specify { expect(fetch_deleted_number(described_class.clean(only: [CitiesIndex, UsersIndex]))).to eq(2) }
72
72
 
73
- specify { expect(fetch_deleted_number(described_class.clean(Time.now + 30.seconds, only: PlacesIndex::Country))).to eq(0) }
74
- specify { expect(fetch_deleted_number(described_class.clean(Time.now + 30.seconds, only: PlacesIndex::City))).to eq(1) }
73
+ specify do
74
+ expect(fetch_deleted_number(described_class.clean(Time.now + 30.seconds, only: CountriesIndex))).to eq(0)
75
+ end
76
+ specify { expect(fetch_deleted_number(described_class.clean(Time.now + 30.seconds, only: CitiesIndex))).to eq(1) }
75
77
  end
76
78
 
77
79
  describe '.for' do
78
80
  specify { expect(described_class.for(UsersIndex).map(&:index_name)).to eq(['users']) }
79
- specify { expect(described_class.for(PlacesIndex).map(&:type_name)).to contain_exactly('city', 'country') }
80
- specify { expect(described_class.for(PlacesIndex::City, UsersIndex).map(&:index_name)).to contain_exactly('places', 'users') }
81
- end
82
-
83
- describe '#type' do
84
- let(:index_name) { 'users' }
85
- let(:type_name) { 'city' }
86
- subject { described_class::Journal.new('index_name' => index_name, 'type_name' => type_name).type }
87
-
88
- specify { expect { subject }.to raise_error(Chewy::UnderivableType) }
89
-
90
- context do
91
- let(:index_name) { 'places' }
92
- it { is_expected.to eq(PlacesIndex::City) }
81
+ specify do
82
+ expect(described_class.for(CitiesIndex, UsersIndex).map(&:index_name)).to contain_exactly('cities', 'users')
93
83
  end
94
84
  end
95
85
  end
@@ -2,7 +2,12 @@ require 'spec_helper'
2
2
 
3
3
  if defined?(::ActiveJob)
4
4
  describe Chewy::Strategy::ActiveJob do
5
- around { |example| Chewy.strategy(:bypass) { example.run } }
5
+ around do |example|
6
+ active_job_settings = Chewy.settings[:active_job]
7
+ Chewy.settings[:active_job] = {queue: 'low'}
8
+ Chewy.strategy(:bypass) { example.run }
9
+ Chewy.settings[:active_job] = active_job_settings
10
+ end
6
11
  before(:all) do
7
12
  ::ActiveJob::Base.logger = Chewy.logger
8
13
  end
@@ -14,11 +19,11 @@ if defined?(::ActiveJob)
14
19
 
15
20
  before do
16
21
  stub_model(:city) do
17
- update_index('cities#city') { self }
22
+ update_index('cities') { self }
18
23
  end
19
24
 
20
25
  stub_index(:cities) do
21
- define_type City
26
+ index_scope City
22
27
  end
23
28
  end
24
29
 
@@ -27,7 +32,7 @@ if defined?(::ActiveJob)
27
32
 
28
33
  specify do
29
34
  expect { [city, other_city].map(&:save!) }
30
- .not_to update_index(CitiesIndex::City, strategy: :active_job)
35
+ .not_to update_index(CitiesIndex, strategy: :active_job)
31
36
  end
32
37
 
33
38
  specify do
@@ -36,25 +41,33 @@ if defined?(::ActiveJob)
36
41
  end
37
42
  enqueued_job = ::ActiveJob::Base.queue_adapter.enqueued_jobs.first
38
43
  expect(enqueued_job[:job]).to eq(Chewy::Strategy::ActiveJob::Worker)
39
- expect(enqueued_job[:queue]).to eq('chewy')
44
+ expect(enqueued_job[:queue]).to eq('low')
45
+ end
46
+
47
+ specify do
48
+ Chewy.strategy(:active_job) do
49
+ [city, other_city].map(&:save!)
50
+ end
51
+ enqueued_job = ::ActiveJob::Base.queue_adapter.enqueued_jobs.first
52
+ expect(enqueued_job[:queue]).to eq('low')
40
53
  end
41
54
 
42
55
  specify do
43
56
  ::ActiveJob::Base.queue_adapter = :inline
44
57
  expect { [city, other_city].map(&:save!) }
45
- .to update_index(CitiesIndex::City, strategy: :active_job)
58
+ .to update_index(CitiesIndex, strategy: :active_job)
46
59
  .and_reindex(city, other_city).only
47
60
  end
48
61
 
49
62
  specify do
50
- expect(CitiesIndex::City).to receive(:import!).with([city.id, other_city.id], suffix: '201601')
51
- Chewy::Strategy::ActiveJob::Worker.new.perform('CitiesIndex::City', [city.id, other_city.id], suffix: '201601')
63
+ expect(CitiesIndex).to receive(:import!).with([city.id, other_city.id], suffix: '201601')
64
+ Chewy::Strategy::ActiveJob::Worker.new.perform('CitiesIndex', [city.id, other_city.id], suffix: '201601')
52
65
  end
53
66
 
54
67
  specify do
55
68
  allow(Chewy).to receive(:disable_refresh_async).and_return(true)
56
- expect(CitiesIndex::City).to receive(:import!).with([city.id, other_city.id], suffix: '201601', refresh: false)
57
- Chewy::Strategy::ActiveJob::Worker.new.perform('CitiesIndex::City', [city.id, other_city.id], suffix: '201601')
69
+ expect(CitiesIndex).to receive(:import!).with([city.id, other_city.id], suffix: '201601', refresh: false)
70
+ Chewy::Strategy::ActiveJob::Worker.new.perform('CitiesIndex', [city.id, other_city.id], suffix: '201601')
58
71
  end
59
72
  end
60
73
  end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Strategy::AtomicNoRefresh, :orm do
4
+ around { |example| Chewy.strategy(:bypass) { example.run } }
5
+
6
+ before do
7
+ stub_model(:country) do
8
+ update_index('countries') { self }
9
+ end
10
+
11
+ stub_index(:countries) do
12
+ index_scope Country
13
+ end
14
+ end
15
+
16
+ let(:country) { Country.create!(name: 'hello', country_code: 'HL') }
17
+ let(:other_country) { Country.create!(name: 'world', country_code: 'WD') }
18
+
19
+ specify do
20
+ expect { [country, other_country].map(&:save!) }
21
+ .to update_index(CountriesIndex, strategy: :atomic_no_refresh)
22
+ .and_reindex(country, other_country).only.no_refresh
23
+ end
24
+
25
+ specify do
26
+ expect { [country, other_country].map(&:destroy) }
27
+ .to update_index(CountriesIndex, strategy: :atomic_no_refresh)
28
+ .and_delete(country, other_country).only.no_refresh
29
+ end
30
+
31
+ context do
32
+ before do
33
+ stub_index(:countries) do
34
+ index_scope Country
35
+ root id: -> { country_code }
36
+ end
37
+ end
38
+
39
+ specify do
40
+ expect { [country, other_country].map(&:save!) }
41
+ .to update_index(CountriesIndex, strategy: :atomic_no_refresh)
42
+ .and_reindex('HL', 'WD').only.no_refresh
43
+ end
44
+
45
+ specify do
46
+ expect { [country, other_country].map(&:destroy) }
47
+ .to update_index(CountriesIndex, strategy: :atomic_no_refresh)
48
+ .and_delete('HL', 'WD').only.no_refresh
49
+ end
50
+
51
+ specify do
52
+ expect do
53
+ country.save!
54
+ other_country.destroy
55
+ end
56
+ .to update_index(CountriesIndex, strategy: :atomic_no_refresh)
57
+ .and_reindex('HL').and_delete('WD').only.no_refresh
58
+ end
59
+ end
60
+ end