chewy 0.10.1 → 7.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. checksums.yaml +5 -5
  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 +74 -0
  7. data/.rubocop.yml +28 -23
  8. data/.rubocop_todo.yml +110 -22
  9. data/CHANGELOG.md +480 -298
  10. data/CODE_OF_CONDUCT.md +14 -0
  11. data/CONTRIBUTING.md +63 -0
  12. data/Gemfile +3 -5
  13. data/Guardfile +3 -1
  14. data/LICENSE.txt +1 -1
  15. data/README.md +571 -333
  16. data/chewy.gemspec +12 -15
  17. data/gemfiles/rails.5.2.activerecord.gemfile +11 -0
  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 +48 -77
  22. data/lib/chewy/errors.rb +4 -10
  23. data/lib/chewy/fields/base.rb +88 -16
  24. data/lib/chewy/fields/root.rb +15 -21
  25. data/lib/chewy/index/actions.rb +67 -38
  26. data/lib/chewy/{type → index}/adapter/active_record.rb +18 -4
  27. data/lib/chewy/{type → index}/adapter/base.rb +11 -12
  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/index/crutch.rb +40 -0
  32. data/lib/chewy/index/import/bulk_builder.rb +311 -0
  33. data/lib/chewy/{type → index}/import/bulk_request.rb +10 -9
  34. data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
  35. data/lib/chewy/{type → index}/import/routine.rb +19 -18
  36. data/lib/chewy/{type → index}/import.rb +82 -36
  37. data/lib/chewy/{type → index}/mapping.rb +63 -62
  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/settings.rb +2 -0
  42. data/lib/chewy/index/specification.rb +13 -10
  43. data/lib/chewy/{type → index}/syncer.rb +62 -63
  44. data/lib/chewy/{type → index}/witchcraft.rb +15 -9
  45. data/lib/chewy/{type → index}/wrapper.rb +16 -6
  46. data/lib/chewy/index.rb +68 -93
  47. data/lib/chewy/journal.rb +25 -14
  48. data/lib/chewy/minitest/helpers.rb +91 -18
  49. data/lib/chewy/minitest/search_index_receiver.rb +29 -33
  50. data/lib/chewy/multi_search.rb +62 -0
  51. data/lib/chewy/railtie.rb +8 -24
  52. data/lib/chewy/rake_helper.rb +141 -112
  53. data/lib/chewy/rspec/build_query.rb +12 -0
  54. data/lib/chewy/rspec/helpers.rb +55 -0
  55. data/lib/chewy/rspec/update_index.rb +58 -49
  56. data/lib/chewy/rspec.rb +2 -0
  57. data/lib/chewy/runtime.rb +1 -1
  58. data/lib/chewy/search/loader.rb +19 -41
  59. data/lib/chewy/search/parameters/allow_partial_search_results.rb +27 -0
  60. data/lib/chewy/search/parameters/collapse.rb +16 -0
  61. data/lib/chewy/search/parameters/concerns/query_storage.rb +6 -5
  62. data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
  63. data/lib/chewy/search/parameters/indices.rb +78 -0
  64. data/lib/chewy/search/parameters/none.rb +1 -3
  65. data/lib/chewy/search/parameters/order.rb +6 -19
  66. data/lib/chewy/search/parameters/source.rb +5 -1
  67. data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
  68. data/lib/chewy/search/parameters.rb +28 -8
  69. data/lib/chewy/search/query_proxy.rb +9 -2
  70. data/lib/chewy/search/request.rb +207 -157
  71. data/lib/chewy/search/response.rb +5 -5
  72. data/lib/chewy/search/scoping.rb +7 -8
  73. data/lib/chewy/search/scrolling.rb +14 -13
  74. data/lib/chewy/search.rb +7 -26
  75. data/lib/chewy/stash.rb +27 -29
  76. data/lib/chewy/strategy/active_job.rb +2 -2
  77. data/lib/chewy/strategy/atomic.rb +1 -1
  78. data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
  79. data/lib/chewy/strategy/base.rb +10 -0
  80. data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +148 -0
  81. data/lib/chewy/strategy/delayed_sidekiq/worker.rb +52 -0
  82. data/lib/chewy/strategy/delayed_sidekiq.rb +17 -0
  83. data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
  84. data/lib/chewy/strategy/sidekiq.rb +3 -2
  85. data/lib/chewy/strategy.rb +6 -19
  86. data/lib/chewy/version.rb +1 -1
  87. data/lib/chewy.rb +37 -80
  88. data/lib/generators/chewy/install_generator.rb +1 -1
  89. data/lib/tasks/chewy.rake +26 -32
  90. data/migration_guide.md +56 -0
  91. data/spec/chewy/config_spec.rb +27 -57
  92. data/spec/chewy/fields/base_spec.rb +457 -174
  93. data/spec/chewy/fields/root_spec.rb +24 -32
  94. data/spec/chewy/fields/time_fields_spec.rb +5 -5
  95. data/spec/chewy/index/actions_spec.rb +425 -60
  96. data/spec/chewy/{type → index}/adapter/active_record_spec.rb +110 -44
  97. data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
  98. data/spec/chewy/index/aliases_spec.rb +3 -3
  99. data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
  100. data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
  101. data/spec/chewy/{type → index}/import/journal_builder_spec.rb +22 -30
  102. data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
  103. data/spec/chewy/{type → index}/import_spec.rb +154 -95
  104. data/spec/chewy/index/mapping_spec.rb +135 -0
  105. data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
  106. data/spec/chewy/index/observe/callback_spec.rb +139 -0
  107. data/spec/chewy/index/observe_spec.rb +143 -0
  108. data/spec/chewy/index/settings_spec.rb +3 -1
  109. data/spec/chewy/index/specification_spec.rb +32 -33
  110. data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
  111. data/spec/chewy/{type → index}/witchcraft_spec.rb +34 -21
  112. data/spec/chewy/index/wrapper_spec.rb +100 -0
  113. data/spec/chewy/index_spec.rb +99 -114
  114. data/spec/chewy/journal_spec.rb +56 -101
  115. data/spec/chewy/minitest/helpers_spec.rb +122 -14
  116. data/spec/chewy/minitest/search_index_receiver_spec.rb +24 -26
  117. data/spec/chewy/multi_search_spec.rb +84 -0
  118. data/spec/chewy/rake_helper_spec.rb +325 -101
  119. data/spec/chewy/rspec/build_query_spec.rb +34 -0
  120. data/spec/chewy/rspec/helpers_spec.rb +61 -0
  121. data/spec/chewy/rspec/update_index_spec.rb +106 -102
  122. data/spec/chewy/runtime_spec.rb +2 -2
  123. data/spec/chewy/search/loader_spec.rb +19 -53
  124. data/spec/chewy/search/pagination/kaminari_examples.rb +3 -5
  125. data/spec/chewy/search/pagination/kaminari_spec.rb +1 -1
  126. data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
  127. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
  128. data/spec/chewy/search/parameters/indices_spec.rb +99 -0
  129. data/spec/chewy/search/parameters/none_spec.rb +1 -1
  130. data/spec/chewy/search/parameters/order_spec.rb +18 -11
  131. data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
  132. data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
  133. data/spec/chewy/search/parameters/source_spec.rb +8 -2
  134. data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
  135. data/spec/chewy/search/parameters_spec.rb +39 -8
  136. data/spec/chewy/search/query_proxy_spec.rb +68 -17
  137. data/spec/chewy/search/request_spec.rb +360 -149
  138. data/spec/chewy/search/response_spec.rb +35 -25
  139. data/spec/chewy/search/scrolling_spec.rb +28 -26
  140. data/spec/chewy/search_spec.rb +73 -53
  141. data/spec/chewy/stash_spec.rb +16 -26
  142. data/spec/chewy/strategy/active_job_spec.rb +23 -10
  143. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
  144. data/spec/chewy/strategy/atomic_spec.rb +9 -10
  145. data/spec/chewy/strategy/delayed_sidekiq_spec.rb +190 -0
  146. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
  147. data/spec/chewy/strategy/sidekiq_spec.rb +14 -10
  148. data/spec/chewy/strategy_spec.rb +19 -15
  149. data/spec/chewy_spec.rb +17 -110
  150. data/spec/spec_helper.rb +7 -22
  151. data/spec/support/active_record.rb +43 -5
  152. metadata +123 -198
  153. data/.travis.yml +0 -53
  154. data/Appraisals +0 -79
  155. data/LEGACY_DSL.md +0 -497
  156. data/gemfiles/rails.4.0.activerecord.gemfile +0 -14
  157. data/gemfiles/rails.4.1.activerecord.gemfile +0 -14
  158. data/gemfiles/rails.4.2.activerecord.gemfile +0 -15
  159. data/gemfiles/rails.4.2.mongoid.5.1.gemfile +0 -15
  160. data/gemfiles/rails.5.0.activerecord.gemfile +0 -15
  161. data/gemfiles/rails.5.0.mongoid.6.0.gemfile +0 -15
  162. data/gemfiles/rails.5.1.activerecord.gemfile +0 -15
  163. data/gemfiles/rails.5.1.mongoid.6.1.gemfile +0 -15
  164. data/gemfiles/sequel.4.45.gemfile +0 -11
  165. data/lib/chewy/backports/deep_dup.rb +0 -46
  166. data/lib/chewy/backports/duplicable.rb +0 -91
  167. data/lib/chewy/query/compose.rb +0 -68
  168. data/lib/chewy/query/criteria.rb +0 -191
  169. data/lib/chewy/query/filters.rb +0 -227
  170. data/lib/chewy/query/loading.rb +0 -111
  171. data/lib/chewy/query/nodes/and.rb +0 -25
  172. data/lib/chewy/query/nodes/base.rb +0 -17
  173. data/lib/chewy/query/nodes/bool.rb +0 -34
  174. data/lib/chewy/query/nodes/equal.rb +0 -34
  175. data/lib/chewy/query/nodes/exists.rb +0 -20
  176. data/lib/chewy/query/nodes/expr.rb +0 -28
  177. data/lib/chewy/query/nodes/field.rb +0 -110
  178. data/lib/chewy/query/nodes/has_child.rb +0 -15
  179. data/lib/chewy/query/nodes/has_parent.rb +0 -15
  180. data/lib/chewy/query/nodes/has_relation.rb +0 -59
  181. data/lib/chewy/query/nodes/match_all.rb +0 -11
  182. data/lib/chewy/query/nodes/missing.rb +0 -20
  183. data/lib/chewy/query/nodes/not.rb +0 -25
  184. data/lib/chewy/query/nodes/or.rb +0 -25
  185. data/lib/chewy/query/nodes/prefix.rb +0 -19
  186. data/lib/chewy/query/nodes/query.rb +0 -20
  187. data/lib/chewy/query/nodes/range.rb +0 -63
  188. data/lib/chewy/query/nodes/raw.rb +0 -15
  189. data/lib/chewy/query/nodes/regexp.rb +0 -35
  190. data/lib/chewy/query/nodes/script.rb +0 -20
  191. data/lib/chewy/query/pagination.rb +0 -25
  192. data/lib/chewy/query.rb +0 -1098
  193. data/lib/chewy/search/pagination/will_paginate.rb +0 -43
  194. data/lib/chewy/search/parameters/types.rb +0 -20
  195. data/lib/chewy/strategy/resque.rb +0 -27
  196. data/lib/chewy/strategy/shoryuken.rb +0 -40
  197. data/lib/chewy/type/actions.rb +0 -43
  198. data/lib/chewy/type/adapter/mongoid.rb +0 -69
  199. data/lib/chewy/type/adapter/sequel.rb +0 -95
  200. data/lib/chewy/type/crutch.rb +0 -32
  201. data/lib/chewy/type/import/bulk_builder.rb +0 -122
  202. data/lib/chewy/type/observe.rb +0 -78
  203. data/lib/chewy/type.rb +0 -117
  204. data/lib/sequel/plugins/chewy_observe.rb +0 -78
  205. data/spec/chewy/query/criteria_spec.rb +0 -700
  206. data/spec/chewy/query/filters_spec.rb +0 -201
  207. data/spec/chewy/query/loading_spec.rb +0 -124
  208. data/spec/chewy/query/nodes/and_spec.rb +0 -12
  209. data/spec/chewy/query/nodes/bool_spec.rb +0 -14
  210. data/spec/chewy/query/nodes/equal_spec.rb +0 -32
  211. data/spec/chewy/query/nodes/exists_spec.rb +0 -18
  212. data/spec/chewy/query/nodes/has_child_spec.rb +0 -59
  213. data/spec/chewy/query/nodes/has_parent_spec.rb +0 -59
  214. data/spec/chewy/query/nodes/match_all_spec.rb +0 -11
  215. data/spec/chewy/query/nodes/missing_spec.rb +0 -16
  216. data/spec/chewy/query/nodes/not_spec.rb +0 -13
  217. data/spec/chewy/query/nodes/or_spec.rb +0 -12
  218. data/spec/chewy/query/nodes/prefix_spec.rb +0 -16
  219. data/spec/chewy/query/nodes/query_spec.rb +0 -12
  220. data/spec/chewy/query/nodes/range_spec.rb +0 -32
  221. data/spec/chewy/query/nodes/raw_spec.rb +0 -11
  222. data/spec/chewy/query/nodes/regexp_spec.rb +0 -43
  223. data/spec/chewy/query/nodes/script_spec.rb +0 -15
  224. data/spec/chewy/query/pagination/kaminari_spec.rb +0 -5
  225. data/spec/chewy/query/pagination/will_paginate_spec.rb +0 -5
  226. data/spec/chewy/query/pagination_spec.rb +0 -39
  227. data/spec/chewy/query_spec.rb +0 -636
  228. data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
  229. data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
  230. data/spec/chewy/search/parameters/indices_boost_spec.rb +0 -83
  231. data/spec/chewy/search/parameters/types_spec.rb +0 -5
  232. data/spec/chewy/strategy/resque_spec.rb +0 -46
  233. data/spec/chewy/strategy/shoryuken_spec.rb +0 -64
  234. data/spec/chewy/type/actions_spec.rb +0 -50
  235. data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
  236. data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
  237. data/spec/chewy/type/import/bulk_builder_spec.rb +0 -279
  238. data/spec/chewy/type/mapping_spec.rb +0 -142
  239. data/spec/chewy/type/observe_spec.rb +0 -137
  240. data/spec/chewy/type/wrapper_spec.rb +0 -98
  241. data/spec/chewy/type_spec.rb +0 -55
  242. data/spec/support/mongoid.rb +0 -93
  243. data/spec/support/sequel.rb +0 -80
@@ -5,21 +5,17 @@ describe Chewy::Search::Request do
5
5
 
6
6
  before do
7
7
  stub_index(:products) do
8
- define_type :product do
9
- field :id, type: :integer
10
- field :name
11
- field :age, type: :integer
12
- end
13
- define_type :city do
14
- field :id, type: :integer
15
- end
16
- define_type :country do
17
- field :id, type: :integer
18
- end
8
+ field :id, type: :integer
9
+ field :name
10
+ field :age, type: :integer
19
11
  end
20
12
 
21
13
  stub_index(:cities) do
22
- define_type :city
14
+ field :id, type: :integer
15
+ end
16
+
17
+ stub_index(:countries) do
18
+ field :id, type: :integer
23
19
  end
24
20
  end
25
21
 
@@ -29,15 +25,17 @@ describe Chewy::Search::Request do
29
25
  specify { expect(described_class.new(ProductsIndex)).to eq(described_class.new(ProductsIndex)) }
30
26
  specify { expect(described_class.new(ProductsIndex)).not_to eq(described_class.new(CitiesIndex)) }
31
27
  specify { expect(described_class.new(ProductsIndex)).not_to eq(described_class.new(ProductsIndex, CitiesIndex)) }
32
- specify { expect(described_class.new(CitiesIndex, ProductsIndex)).to eq(described_class.new(ProductsIndex, CitiesIndex)) }
33
- specify { expect(described_class.new(ProductsIndex::Product)).to eq(described_class.new(ProductsIndex::Product)) }
34
- specify { expect(described_class.new(ProductsIndex::Product)).not_to eq(described_class.new(ProductsIndex::City)) }
35
- specify { expect(described_class.new(ProductsIndex::Product)).not_to eq(described_class.new(ProductsIndex::Product, ProductsIndex::City)) }
36
- specify { expect(described_class.new(ProductsIndex::City, ProductsIndex::Product)).to eq(described_class.new(ProductsIndex::Product, ProductsIndex::City)) }
37
- specify { expect(described_class.new(ProductsIndex::City, CitiesIndex::City)).to eq(described_class.new(CitiesIndex::City, ProductsIndex::City)) }
28
+ specify do
29
+ expect(described_class.new(CitiesIndex, ProductsIndex)).to eq(described_class.new(ProductsIndex, CitiesIndex))
30
+ end
31
+ specify do
32
+ expect(described_class.new(ProductsIndex, CitiesIndex)).to eq(described_class.new(CitiesIndex, ProductsIndex))
33
+ end
38
34
 
39
35
  specify { expect(described_class.new(ProductsIndex).limit(10)).to eq(described_class.new(ProductsIndex).limit(10)) }
40
- specify { expect(described_class.new(ProductsIndex).limit(10)).not_to eq(described_class.new(ProductsIndex).limit(20)) }
36
+ specify do
37
+ expect(described_class.new(ProductsIndex).limit(10)).not_to eq(described_class.new(ProductsIndex).limit(20))
38
+ end
41
39
 
42
40
  specify { expect(ProductsIndex.limit(10)).to eq(ProductsIndex.limit(10)) }
43
41
  specify { expect(ProductsIndex.limit(10)).not_to eq(CitiesIndex.limit(10)) }
@@ -48,7 +46,6 @@ describe Chewy::Search::Request do
48
46
  expect(subject.render)
49
47
  .to match(
50
48
  index: %w[products],
51
- type: array_including(%w[product city country]),
52
49
  body: {}
53
50
  )
54
51
  end
@@ -57,60 +54,113 @@ describe Chewy::Search::Request do
57
54
  describe '#inspect' do
58
55
  specify do
59
56
  expect(described_class.new(ProductsIndex).inspect)
60
- .to eq('<Chewy::Search::Request {:index=>["products"], :type=>["product", "city", "country"], :body=>{}}>')
57
+ .to eq('<Chewy::Search::Request {:index=>["products"], :body=>{}}>')
61
58
  end
62
59
  specify do
63
60
  expect(ProductsIndex.limit(10).inspect)
64
- .to eq('<ProductsIndex::Query {:index=>["products"], :type=>["product", "city", "country"], :body=>{:size=>10}}>')
61
+ .to eq('<ProductsIndex::Query {:index=>["products"], :body=>{:size=>10}}>')
65
62
  end
66
63
  end
67
64
 
68
65
  %i[query post_filter].each do |name|
69
66
  describe "##{name}" do
70
- specify { expect(subject.send(name, match: {foo: 'bar'}).render[:body]).to include(name => {match: {foo: 'bar'}}) }
67
+ specify do
68
+ expect(subject.send(name, match: {foo: 'bar'}).render[:body])
69
+ .to include(name => {match: {foo: 'bar'}})
70
+ end
71
71
  specify { expect(subject.send(name, nil)).to be_a described_class }
72
- specify { expect(subject.send(name) { match foo: 'bar' }.render[:body]).to include(name => {match: {foo: 'bar'}}) }
72
+ specify do
73
+ expect(subject.send(name) { match foo: 'bar' }.render[:body])
74
+ .to include(name => {match: {foo: 'bar'}})
75
+ end
73
76
  specify do
74
77
  expect(subject.send(name, match: {foo: 'bar'}).send(name) { multi_match foo: 'bar' }.render[:body])
75
78
  .to include(name => {bool: {must: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}})
76
79
  end
77
80
  specify { expect { subject.send(name, match: {foo: 'bar'}) }.not_to change { subject.render } }
78
81
  specify do
79
- expect(subject.send(name).should(match: {foo: 'bar'}).send(name).must_not { multi_match foo: 'bar' }.render[:body])
80
- .to include(name => {bool: {should: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}})
82
+ expect(
83
+ subject.send(name).should(match: {foo: 'bar'}).send(name).must_not { multi_match foo: 'bar' }.render[:body]
84
+ ).to include(name => {bool: {should: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}})
81
85
  end
82
86
 
83
87
  context do
84
88
  let(:other_scope) { subject.send(name).should { multi_match foo: 'bar' }.send(name) { match foo: 'bar' } }
85
89
 
86
90
  specify do
87
- expect(subject.send(name).not(other_scope).render[:body])
88
- .to include(name => {bool: {must_not: {bool: {must: {match: {foo: 'bar'}}, should: {multi_match: {foo: 'bar'}}}}}})
91
+ expect(
92
+ subject.send(name).not(other_scope).render[:body]
93
+ ).to include(
94
+ name => {
95
+ bool: {
96
+ must_not: {
97
+ bool: {
98
+ must: {match: {foo: 'bar'}},
99
+ should: {multi_match: {foo: 'bar'}}
100
+ }
101
+ }
102
+ }
103
+ }
104
+ )
89
105
  end
90
106
  end
91
107
  end
92
108
  end
93
109
 
94
110
  describe '#filter' do
95
- specify { expect(subject.filter(match: {foo: 'bar'}).render[:body]).to include(query: {bool: {filter: {match: {foo: 'bar'}}}}) }
111
+ specify do
112
+ expect(subject.filter(match: {foo: 'bar'}).render[:body])
113
+ .to include(query: {bool: {filter: {match: {foo: 'bar'}}}})
114
+ end
96
115
  specify { expect(subject.filter(nil)).to be_a described_class }
97
- specify { expect(subject.filter { match foo: 'bar' }.render[:body]).to include(query: {bool: {filter: {match: {foo: 'bar'}}}}) }
116
+ specify do
117
+ expect(subject.filter(match: {foo: 'bar'}).render[:body])
118
+ .to include(query: {bool: {filter: {match: {foo: 'bar'}}}})
119
+ end
98
120
  specify do
99
121
  expect(subject.filter(match: {foo: 'bar'}).filter { multi_match foo: 'bar' }.render[:body])
100
122
  .to include(query: {bool: {filter: [{match: {foo: 'bar'}}, {multi_match: {foo: 'bar'}}]}})
101
123
  end
102
124
  specify { expect { subject.filter(match: {foo: 'bar'}) }.not_to change { subject.render } }
103
125
  specify do
104
- expect(subject.filter.should(match: {foo: 'bar'}).filter.must_not { multi_match foo: 'bar' }.render[:body])
105
- .to include(query: {bool: {filter: {bool: {should: {match: {foo: 'bar'}}, must_not: {multi_match: {foo: 'bar'}}}}}})
126
+ expect(
127
+ subject.filter.should(match: {foo: 'bar'}).filter.must_not { multi_match foo: 'bar' }.render[:body]
128
+ ).to include(
129
+ query: {
130
+ bool: {
131
+ filter: {
132
+ bool: {
133
+ should: {match: {foo: 'bar'}},
134
+ must_not: {multi_match: {foo: 'bar'}}
135
+ }
136
+ }
137
+ }
138
+ }
139
+ )
106
140
  end
107
141
 
108
142
  context do
109
143
  let(:other_scope) { subject.filter.should { multi_match foo: 'bar' }.filter { match foo: 'bar' } }
110
144
 
111
145
  specify do
112
- expect(subject.filter.not(other_scope).render[:body])
113
- .to include(query: {bool: {filter: {bool: {must_not: {bool: {must: {match: {foo: 'bar'}}, should: {multi_match: {foo: 'bar'}}}}}}}})
146
+ expect(
147
+ subject.filter.not(other_scope).render[:body]
148
+ ).to include(
149
+ query: {
150
+ bool: {
151
+ filter: {
152
+ bool: {
153
+ must_not: {
154
+ bool: {
155
+ must: {match: {foo: 'bar'}},
156
+ should: {multi_match: {foo: 'bar'}}
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ )
114
164
  end
115
165
  end
116
166
  end
@@ -127,7 +177,7 @@ describe Chewy::Search::Request do
127
177
  describe '#order' do
128
178
  specify { expect(subject.order(:foo).render[:body]).to include(sort: ['foo']) }
129
179
  specify { expect(subject.order(foo: 42).order(nil).render[:body]).to include(sort: ['foo' => 42]) }
130
- specify { expect(subject.order(foo: 42).order(foo: 43).render[:body]).to include(sort: ['foo' => 43]) }
180
+ specify { expect(subject.order(foo: 42).order(foo: 43).render[:body]).to include(sort: [{'foo' => 42}, {'foo' => 43}]) }
131
181
  specify { expect(subject.order(:foo).order(:bar, :baz).render[:body]).to include(sort: %w[foo bar baz]) }
132
182
  specify { expect(subject.order(nil).render[:body]).to be_blank }
133
183
  specify { expect { subject.order(:foo) }.not_to change { subject.render } }
@@ -142,7 +192,7 @@ describe Chewy::Search::Request do
142
192
  specify { expect { subject.reorder(:foo) }.not_to change { subject.render } }
143
193
  end
144
194
 
145
- %i[track_scores explain version profile].each do |name|
195
+ %i[track_scores track_total_hits explain version profile].each do |name|
146
196
  describe "##{name}" do
147
197
  specify { expect(subject.send(name).render[:body]).to include(name => true) }
148
198
  specify { expect(subject.send(name).send(name, false).render[:body]).to be_blank }
@@ -151,19 +201,31 @@ describe Chewy::Search::Request do
151
201
  end
152
202
 
153
203
  describe '#request_cache' do
154
- specify { expect(subject.request_cache(true).render[:body]).to include(request_cache: true) }
155
- specify { expect(subject.request_cache(true).request_cache(false).render[:body]).to include(request_cache: false) }
156
- specify { expect(subject.request_cache(true).request_cache(nil).render[:body]).to be_blank }
204
+ specify { expect(subject.request_cache(true).render).to include(request_cache: true) }
205
+ specify { expect(subject.request_cache(true).request_cache(false).render).to include(request_cache: false) }
206
+ specify { expect(subject.request_cache(true).request_cache(nil).render[:request_cache]).to be_blank }
157
207
  specify { expect { subject.request_cache(true) }.not_to change { subject.render } }
158
208
  end
159
209
 
160
- %i[search_type preference timeout].each do |name|
161
- describe "##{name}" do
162
- specify { expect(subject.send(name, :foo).render[:body]).to include(name => 'foo') }
163
- specify { expect(subject.send(name, :foo).send(name, :bar).render[:body]).to include(name => 'bar') }
164
- specify { expect(subject.send(name, :foo).send(name, nil).render[:body]).to be_blank }
165
- specify { expect { subject.send(name, :foo) }.not_to change { subject.render } }
166
- end
210
+ describe '#search_type' do
211
+ specify { expect(subject.search_type('foo').render).to include(search_type: 'foo') }
212
+ specify { expect(subject.search_type('foo').search_type('bar').render).to include(search_type: 'bar') }
213
+ specify { expect(subject.search_type('foo').search_type(nil).render[:search_type]).to be_blank }
214
+ specify { expect { subject.search_type('foo') }.not_to change { subject.render } }
215
+ end
216
+
217
+ describe '#preference' do
218
+ specify { expect(subject.preference('foo').render).to include(preference: 'foo') }
219
+ specify { expect(subject.preference('foo').preference('bar').render).to include(preference: 'bar') }
220
+ specify { expect(subject.preference('foo').preference(nil).render[:preference]).to be_blank }
221
+ specify { expect { subject.preference('foo') }.not_to change { subject.render } }
222
+ end
223
+
224
+ describe '#timeout' do
225
+ specify { expect(subject.timeout(:foo).render[:body]).to include(timeout: 'foo') }
226
+ specify { expect(subject.timeout(:foo).timeout(:bar).render[:body]).to include(timeout: 'bar') }
227
+ specify { expect(subject.timeout(:foo).timeout(nil).render[:body]).to be_blank }
228
+ specify { expect { subject.timeout(:foo) }.not_to change { subject.render } }
167
229
  end
168
230
 
169
231
  describe '#source' do
@@ -171,23 +233,53 @@ describe Chewy::Search::Request do
171
233
  specify { expect(subject.source(:foo, :bar).source(nil).render[:body]).to include(_source: %w[foo bar]) }
172
234
  specify { expect(subject.source(%i[foo bar]).source(nil).render[:body]).to include(_source: %w[foo bar]) }
173
235
  specify { expect(subject.source(excludes: :foo).render[:body]).to include(_source: {excludes: %w[foo]}) }
174
- specify { expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body]).to include(_source: {excludes: %w[foo bar]}) }
175
- specify { expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body]).to include(_source: {excludes: %w[foo bar]}) }
176
- specify { expect(subject.source(excludes: :foo).source(:bar).render[:body]).to include(_source: {includes: %w[bar], excludes: %w[foo]}) }
236
+ specify do
237
+ expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body])
238
+ .to include(_source: {excludes: %w[foo bar]})
239
+ end
240
+ specify do
241
+ expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body])
242
+ .to include(_source: {excludes: %w[foo bar]})
243
+ end
244
+ specify do
245
+ expect(subject.source(excludes: :foo).source(:bar).render[:body])
246
+ .to include(_source: {includes: %w[bar], excludes: %w[foo]})
247
+ end
177
248
  specify { expect(subject.source(excludes: :foo).source(false).render[:body]).to include(_source: false) }
178
- specify { expect(subject.source(excludes: :foo).source(false).source(excludes: :bar).render[:body]).to include(_source: {excludes: %w[foo bar]}) }
179
- specify { expect(subject.source(excludes: :foo).source(false).source(true).render[:body]).to include(_source: {excludes: %w[foo]}) }
249
+ specify do
250
+ expect(subject.source(excludes: :foo).source(false).source(excludes: :bar).render[:body])
251
+ .to include(_source: {excludes: %w[foo bar]})
252
+ end
253
+ specify do
254
+ expect(subject.source(excludes: :foo).source(false).source(true).render[:body])
255
+ .to include(_source: {excludes: %w[foo]})
256
+ end
180
257
  specify { expect(subject.source(nil).render[:body]).to be_blank }
181
258
  specify { expect { subject.source(:foo) }.not_to change { subject.render } }
182
259
  end
183
260
 
184
261
  describe '#stored_fields' do
185
262
  specify { expect(subject.stored_fields(:foo).render[:body]).to include(stored_fields: ['foo']) }
186
- specify { expect(subject.stored_fields(%i[foo bar]).stored_fields(nil).render[:body]).to include(stored_fields: %w[foo bar]) }
187
- specify { expect(subject.stored_fields(:foo).stored_fields(:foo, :bar).render[:body]).to include(stored_fields: %w[foo bar]) }
188
- specify { expect(subject.stored_fields(:foo).stored_fields(false).render[:body]).to include(stored_fields: '_none_') }
189
- specify { expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(:bar).render[:body]).to include(stored_fields: %w[foo bar]) }
190
- specify { expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(true).render[:body]).to include(stored_fields: %w[foo]) }
263
+ specify do
264
+ expect(subject.stored_fields(%i[foo bar]).stored_fields(nil).render[:body])
265
+ .to include(stored_fields: %w[foo bar])
266
+ end
267
+ specify do
268
+ expect(subject.stored_fields(:foo).stored_fields(:foo, :bar).render[:body])
269
+ .to include(stored_fields: %w[foo bar])
270
+ end
271
+ specify do
272
+ expect(subject.stored_fields(:foo).stored_fields(false).render[:body])
273
+ .to include(stored_fields: '_none_')
274
+ end
275
+ specify do
276
+ expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(:bar).render[:body])
277
+ .to include(stored_fields: %w[foo bar])
278
+ end
279
+ specify do
280
+ expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(true).render[:body])
281
+ .to include(stored_fields: %w[foo])
282
+ end
191
283
  specify { expect(subject.stored_fields(nil).render[:body]).to be_blank }
192
284
  specify { expect { subject.stored_fields(:foo) }.not_to change { subject.render } }
193
285
  end
@@ -195,8 +287,14 @@ describe Chewy::Search::Request do
195
287
  %i[script_fields highlight].each do |name|
196
288
  describe "##{name}" do
197
289
  specify { expect(subject.send(name, foo: {bar: 42}).render[:body]).to include(name => {'foo' => {bar: 42}}) }
198
- specify { expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body]).to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}}) }
199
- specify { expect(subject.send(name, foo: {bar: 42}).send(name, nil).render[:body]).to include(name => {'foo' => {bar: 42}}) }
290
+ specify do
291
+ expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body])
292
+ .to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}})
293
+ end
294
+ specify do
295
+ expect(subject.send(name, foo: {bar: 42}).send(name, nil).render[:body])
296
+ .to include(name => {'foo' => {bar: 42}})
297
+ end
200
298
  specify { expect { subject.send(name, foo: {bar: 42}) }.not_to change { subject.render } }
201
299
  end
202
300
  end
@@ -204,38 +302,69 @@ describe Chewy::Search::Request do
204
302
  %i[suggest aggs].each do |name|
205
303
  describe "##{name}" do
206
304
  specify { expect(subject.send(name, foo: {bar: 42}).render[:body]).to include(name => {'foo' => {bar: 42}}) }
207
- specify { expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body]).to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}}) }
208
- specify { expect(subject.send(name, foo: {bar: 42}).send(name, nil).render[:body]).to include(name => {'foo' => {bar: 42}}) }
305
+ specify do
306
+ expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body])
307
+ .to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}})
308
+ end
309
+ specify do
310
+ expect(subject.send(name, foo: {bar: 42}).send(name, nil).render[:body])
311
+ .to include(name => {'foo' => {bar: 42}})
312
+ end
209
313
  specify { expect { subject.send(name, foo: {bar: 42}) }.not_to change { subject.render } }
210
314
  end
211
315
  end
212
316
 
317
+ describe '#collapse' do
318
+ specify { expect(subject.collapse(foo: {bar: 42}).render[:body]).to include(collapse: {'foo' => {bar: 42}}) }
319
+ specify do
320
+ expect(subject.collapse(foo: {bar: 42}).collapse(moo: {baz: 43}).render[:body])
321
+ .to include(collapse: {'moo' => {baz: 43}})
322
+ end
323
+ specify { expect(subject.collapse(foo: {bar: 42}).collapse(nil).render[:body]).to be_blank }
324
+ specify { expect { subject.collapse(foo: {bar: 42}) }.not_to change { subject.render } }
325
+ end
326
+
213
327
  describe '#docvalue_fields' do
214
328
  specify { expect(subject.docvalue_fields(:foo).render[:body]).to include(docvalue_fields: ['foo']) }
215
- specify { expect(subject.docvalue_fields(%i[foo bar]).docvalue_fields(nil).render[:body]).to include(docvalue_fields: %w[foo bar]) }
216
- specify { expect(subject.docvalue_fields(:foo).docvalue_fields(:foo, :bar).render[:body]).to include(docvalue_fields: %w[foo bar]) }
329
+ specify do
330
+ expect(subject.docvalue_fields(%i[foo bar]).docvalue_fields(nil).render[:body])
331
+ .to include(docvalue_fields: %w[foo bar])
332
+ end
333
+ specify do
334
+ expect(subject.docvalue_fields(:foo).docvalue_fields(:foo, :bar).render[:body])
335
+ .to include(docvalue_fields: %w[foo bar])
336
+ end
217
337
  specify { expect(subject.docvalue_fields(nil).render[:body]).to be_blank }
218
338
  specify { expect { subject.docvalue_fields(:foo) }.not_to change { subject.render } }
219
339
  end
220
340
 
221
- describe '#types' do
222
- specify { expect(subject.types(:product).render[:type]).to contain_exactly('product') }
223
- specify { expect(subject.types(%i[product city]).types(nil).render[:type]).to match_array(%w[product city]) }
224
- specify { expect(subject.types(:product).types(:product, :city, :something).render[:type]).to match_array(%w[product city]) }
225
- specify { expect(subject.types(nil).render[:body]).to be_blank }
226
- specify { expect { subject.types(:product) }.not_to change { subject.render } }
341
+ describe '#indices' do
342
+ specify { expect(described_class.new(:products).render[:index]).to eq(%w[products]) }
343
+ specify { expect(subject.indices(:cities).render[:index]).to eq(%w[cities products]) }
344
+ specify { expect(subject.indices(CitiesIndex, :whatever).render[:index]).to eq(%w[cities products whatever]) }
345
+ specify { expect(subject.indices([CitiesIndex, :products]).render[:index]).to eq(%w[cities products]) }
346
+ specify { expect { subject.indices(:cities) }.not_to change { subject.render } }
227
347
  end
228
348
 
229
349
  describe '#indices_boost' do
230
350
  specify { expect(subject.indices_boost(foo: 1.2).render[:body]).to include(indices_boost: [{'foo' => 1.2}]) }
231
- specify { expect(subject.indices_boost(foo: 1.2).indices_boost(moo: 1.3).render[:body]).to include(indices_boost: [{'foo' => 1.2}, {'moo' => 1.3}]) }
232
- specify { expect(subject.indices_boost(foo: 1.2).indices_boost(nil).render[:body]).to include(indices_boost: [{'foo' => 1.2}]) }
351
+ specify do
352
+ expect(subject.indices_boost(foo: 1.2).indices_boost(moo: 1.3).render[:body])
353
+ .to include(indices_boost: [{'foo' => 1.2}, {'moo' => 1.3}])
354
+ end
355
+ specify do
356
+ expect(subject.indices_boost(foo: 1.2).indices_boost(nil).render[:body])
357
+ .to include(indices_boost: [{'foo' => 1.2}])
358
+ end
233
359
  specify { expect { subject.indices_boost(foo: 1.2) }.not_to change { subject.render } }
234
360
  end
235
361
 
236
362
  describe '#rescore' do
237
363
  specify { expect(subject.rescore(foo: 42).render[:body]).to include(rescore: [{foo: 42}]) }
238
- specify { expect(subject.rescore(foo: 42).rescore(moo: 43).render[:body]).to include(rescore: [{foo: 42}, {moo: 43}]) }
364
+ specify do
365
+ expect(subject.rescore(foo: 42).rescore(moo: 43).render[:body])
366
+ .to include(rescore: [{foo: 42}, {moo: 43}])
367
+ end
239
368
  specify { expect(subject.rescore(foo: 42).rescore(nil).render[:body]).to include(rescore: [{foo: 42}]) }
240
369
  specify { expect { subject.rescore(foo: 42) }.not_to change { subject.render } }
241
370
  end
@@ -247,9 +376,19 @@ describe Chewy::Search::Request do
247
376
  specify { expect { subject.min_score(1.2) }.not_to change { subject.render } }
248
377
  end
249
378
 
379
+ describe '#ignore_unavailable' do
380
+ specify { expect(subject.ignore_unavailable(true).render).to include(ignore_unavailable: true) }
381
+ specify { expect(subject.ignore_unavailable(true).ignore_unavailable(false).render).to include(ignore_unavailable: false) }
382
+ specify { expect(subject.ignore_unavailable(true).ignore_unavailable(nil).render[:ignore_unavailable]).to be_blank }
383
+ specify { expect { subject.ignore_unavailable(true) }.not_to change { subject.render } }
384
+ end
385
+
250
386
  describe '#search_after' do
251
387
  specify { expect(subject.search_after(:foo, :bar).render[:body]).to include(search_after: %i[foo bar]) }
252
- specify { expect(subject.search_after(%i[foo bar]).search_after(:baz).render[:body]).to include(search_after: [:baz]) }
388
+ specify do
389
+ expect(subject.search_after(%i[foo bar]).search_after(:baz).render[:body])
390
+ .to include(search_after: [:baz])
391
+ end
253
392
  specify { expect(subject.search_after(:foo).search_after(nil).render[:body]).to be_blank }
254
393
  specify { expect { subject.search_after(:foo) }.not_to change { subject.render } }
255
394
  end
@@ -260,17 +399,17 @@ describe Chewy::Search::Request do
260
399
  stub_model(:country)
261
400
 
262
401
  stub_index(:places) do
263
- define_type City do
264
- field :rating, type: 'integer'
265
- end
402
+ index_scope City
403
+ field :rating, type: 'integer'
404
+ end
266
405
 
267
- define_type Country do
268
- field :rating, type: 'integer'
269
- end
406
+ stub_index(:countries) do
407
+ index_scope Country
408
+ field :rating, type: 'integer'
270
409
  end
271
410
  end
272
411
 
273
- before { PlacesIndex.import!(cities: cities, countries: countries) }
412
+ before { PlacesIndex.import!(cities) }
274
413
 
275
414
  let(:cities) { Array.new(2) { |i| City.create!(rating: i) } }
276
415
  let(:countries) { Array.new(2) { |i| Country.create!(rating: i + 2) } }
@@ -278,14 +417,14 @@ describe Chewy::Search::Request do
278
417
  subject { described_class.new(PlacesIndex).order(:rating) }
279
418
 
280
419
  describe '#objects' do
281
- specify { expect(subject.objects).to eq([*cities, *countries]) }
420
+ specify { expect(subject.objects).to eq([*cities]) }
282
421
  specify { expect(subject.objects.class).to eq(Array) }
283
422
  end
284
423
 
285
424
  describe '#load' do
286
- specify { expect(subject.load(only: 'city')).to eq([*cities, *countries]) }
287
- specify { expect(subject.load(only: 'city').map(&:class).uniq).to eq([PlacesIndex::City, PlacesIndex::Country]) }
288
- specify { expect(subject.load(only: 'city').objects).to eq([*cities, nil, nil]) }
425
+ specify { expect(subject.load(only: 'city')).to eq([*cities]) }
426
+ specify { expect(subject.load(only: 'city').map(&:class).uniq).to eq([PlacesIndex]) }
427
+ specify { expect(subject.load(only: 'city').objects).to eq([*cities]) }
289
428
  end
290
429
  end
291
430
 
@@ -304,7 +443,9 @@ describe Chewy::Search::Request do
304
443
 
305
444
  context do
306
445
  let(:first_scope) { subject.query(foo: 'bar').filter.should(moo: 'baz').post_filter.must_not(boo: 'baf').limit(10) }
307
- let(:second_scope) { subject.filter(foo: 'bar').post_filter.should(moo: 'baz').query.must_not(boo: 'baf').limit(20) }
446
+ let(:second_scope) do
447
+ subject.filter(foo: 'bar').post_filter.should(moo: 'baz').query.must_not(boo: 'baf').limit(20)
448
+ end
308
449
 
309
450
  describe '#and' do
310
451
  specify do
@@ -372,14 +513,18 @@ describe Chewy::Search::Request do
372
513
  end
373
514
 
374
515
  context 'integration' do
375
- let(:products) { Array.new(3) { |i| {id: i.next.to_i, name: "Name#{i.next}", age: 10 * i.next}.stringify_keys! } }
376
- let(:cities) { Array.new(3) { |i| {id: (i.next + 3).to_i}.stringify_keys! } }
377
- let(:countries) { Array.new(3) { |i| {id: (i.next + 6).to_i}.stringify_keys! } }
516
+ let(:products_count) { 9 }
517
+ let(:products) do
518
+ Array.new(products_count) do |i|
519
+ {id: i.next.to_i, name: "Name#{i.next}", age: 10 * i.next}.stringify_keys!
520
+ end
521
+ end
522
+ let(:cities) { Array.new(3) { |i| {id: (i.next + 9).to_i}.stringify_keys! } }
523
+ let(:countries) { Array.new(3) { |i| {id: (i.next + 12).to_i}.stringify_keys! } }
378
524
  before do
379
- ProductsIndex::Product.import!(products.map { |h| double(h) })
380
- ProductsIndex::City.import!(cities.map { |h| double(h) })
381
- ProductsIndex::Country.import!(countries.map { |h| double(h) })
382
- CitiesIndex::City.import!(cities.map { |h| double(h) })
525
+ ProductsIndex.import!(products.map { |h| double(h) })
526
+ CountriesIndex.import!(countries.map { |h| double(h) })
527
+ CitiesIndex.import!(cities.map { |h| double(h) })
383
528
  end
384
529
 
385
530
  specify { expect(subject[0]._data).to be_a Hash }
@@ -391,18 +536,11 @@ describe Chewy::Search::Request do
391
536
  specify { expect(subject.size).to eq(3) }
392
537
  end
393
538
 
394
- context 'limited types' do
395
- subject { described_class.new(ProductsIndex::City, ProductsIndex::Country) }
396
-
397
- specify { expect(subject.count).to eq(6) }
398
- specify { expect(subject.size).to eq(6) }
399
- end
400
-
401
- context 'mixed types' do
402
- subject { described_class.new(CitiesIndex, ProductsIndex::Product) }
539
+ context 'mixed indexes' do
540
+ subject { described_class.new(CitiesIndex, ProductsIndex) }
403
541
 
404
- specify { expect(subject.count).to eq(9) }
405
- specify { expect(subject.size).to eq(9) }
542
+ specify { expect(subject.count).to eq(12) }
543
+ specify { expect(subject.size).to eq(10) } # pagination limit
406
544
  end
407
545
 
408
546
  context 'instrumentation' do
@@ -415,9 +553,7 @@ describe Chewy::Search::Request do
415
553
  expect(outer_payload).to eq(
416
554
  index: ProductsIndex,
417
555
  indexes: [ProductsIndex],
418
- request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}},
419
- type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
420
- types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
556
+ request: {index: ['products'], body: {query: {match: {name: 'name3'}}}}
421
557
  )
422
558
  end
423
559
  end
@@ -428,11 +564,23 @@ describe Chewy::Search::Request do
428
564
 
429
565
  describe '#highlight' do
430
566
  specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name).to eq('Name3') }
431
- specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name_highlight).to eq('<em>Name3</em>') }
432
- specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first._data['_source']['name']).to eq('Name3') }
567
+ specify do
568
+ expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name_highlight)
569
+ .to eq('<em>Name3</em>')
570
+ end
571
+ specify do
572
+ expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name_highlights)
573
+ .to eq(['<em>Name3</em>'])
574
+ end
575
+ specify do
576
+ expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first._data['_source']['name'])
577
+ .to eq('Name3')
578
+ end
433
579
  end
434
580
 
435
581
  describe '#suggest' do
582
+ let(:products_count) { 3 }
583
+
436
584
  specify do
437
585
  expect(subject.suggest(
438
586
  foo: {
@@ -454,7 +602,7 @@ describe Chewy::Search::Request do
454
602
  describe '#aggs' do
455
603
  specify do
456
604
  expect(subject.aggs(avg_age: {avg: {field: :age}}).aggs)
457
- .to eq('avg_age' => {'value' => 20.0})
605
+ .to eq('avg_age' => {'value' => 50.0})
458
606
  end
459
607
  end
460
608
 
@@ -474,8 +622,7 @@ describe Chewy::Search::Request do
474
622
  specify { expect(subject.count).to eq(9) }
475
623
  specify { expect(subject.limit(6).count).to eq(9) }
476
624
  specify { expect(subject.offset(6).count).to eq(9) }
477
- specify { expect(subject.types(:product, :something).count).to eq(3) }
478
- specify { expect(subject.types(:product, :country).count).to eq(6) }
625
+ specify { expect(subject.indices(:products, CountriesIndex).count).to eq(12) }
479
626
  specify { expect(subject.filter(term: {age: 10}).count).to eq(1) }
480
627
  specify { expect(subject.query(term: {age: 10}).count).to eq(1) }
481
628
  specify { expect(subject.order(nil).count).to eq(9) }
@@ -514,7 +661,7 @@ describe Chewy::Search::Request do
514
661
  context do
515
662
  before { expect(Chewy.client).to receive(:search).once.and_call_original }
516
663
 
517
- specify { expect(subject.first).to be_a(ProductsIndex::Country).and have_attributes(id: 9) }
664
+ specify { expect(subject.first).to be_a(ProductsIndex).and have_attributes(id: 9) }
518
665
  specify { expect(subject.first(3).map(&:id)).to eq([9, 8, 7]) }
519
666
  specify { expect(subject.first(10).map(&:id)).to have(9).items }
520
667
  specify { expect(subject.limit(5).first(10).map(&:id)).to have(9).items }
@@ -527,7 +674,7 @@ describe Chewy::Search::Request do
527
674
  expect(Chewy.client).not_to receive(:search)
528
675
  end
529
676
 
530
- specify { expect(subject.first).to be_a(ProductsIndex::Country).and have_attributes(id: 9) }
677
+ specify { expect(subject.first).to be_a(ProductsIndex).and have_attributes(id: 9) }
531
678
  specify { expect(subject.first(3).map(&:id)).to eq([9, 8, 7]) }
532
679
  specify { expect(subject.first(10).map(&:id)).to have(9).items }
533
680
 
@@ -548,19 +695,37 @@ describe Chewy::Search::Request do
548
695
  end
549
696
 
550
697
  describe '#find' do
551
- specify { expect(subject.find('1')).to be_a(ProductsIndex::Product).and have_attributes(id: 1) }
552
- specify { expect(subject.find { |w| w.id == 2 }).to be_a(ProductsIndex::Product).and have_attributes(id: 2) }
698
+ specify { expect(subject.find('1')).to be_a(ProductsIndex).and have_attributes(id: 1) }
699
+ specify { expect(subject.find { |w| w.id == 2 }).to be_a(ProductsIndex).and have_attributes(id: 2) }
553
700
  specify { expect(subject.limit(2).find('1', '3', '7').map(&:id)).to contain_exactly(1, 3, 7) }
554
701
  specify { expect(subject.find(1, 3, 7).map(&:id)).to contain_exactly(1, 3, 7) }
555
- specify { expect { subject.find('1', '3', '42') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42' }
556
- specify { expect { subject.find(1, 3, 42) }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42' }
557
- specify { expect { subject.query(match: {name: 'name3'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1' }
558
- specify { expect { subject.query(match: {name: 'name2'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' }
559
- specify { expect { subject.filter(match: {name: 'name2'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' }
560
- specify { expect { subject.post_filter(match: {name: 'name2'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' }
702
+ specify do
703
+ expect { subject.find('1', '3', '42') }
704
+ .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42'
705
+ end
706
+ specify do
707
+ expect { subject.find(1, 3, 42) }
708
+ .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42'
709
+ end
710
+ specify do
711
+ expect { subject.query(match: {name: 'name3'}).find('1', '3') }
712
+ .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1'
713
+ end
714
+ specify do
715
+ expect { subject.query(match: {name: 'name2'}).find('1', '3') }
716
+ .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3'
717
+ end
718
+ specify do
719
+ expect { subject.filter(match: {name: 'name2'}).find('1', '3') }
720
+ .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3'
721
+ end
722
+ specify do
723
+ expect { subject.post_filter(match: {name: 'name2'}).find('1', '3') }
724
+ .to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3'
725
+ end
561
726
 
562
727
  context 'make sure it returns everything' do
563
- let(:countries) { Array.new(6) { |i| {id: (i.next + 6).to_i}.stringify_keys! } }
728
+ let(:products_count) { 12 }
564
729
  before { expect(Chewy.client).not_to receive(:scroll) }
565
730
 
566
731
  specify { expect(subject.find((1..12).to_a)).to have(12).items }
@@ -571,21 +736,25 @@ describe Chewy::Search::Request do
571
736
  before { expect(Chewy.client).to receive(:scroll).once.and_call_original }
572
737
 
573
738
  specify { expect(subject.find((1..9).to_a)).to have(9).items }
574
- specify { expect(subject.find((1..9).to_a)).to all be_a(Chewy::Type) }
739
+ specify { expect(subject.find((1..9).to_a)).to all be_a(Chewy::Index) }
575
740
  end
576
741
  end
577
742
 
578
743
  describe '#pluck' do
579
744
  specify { expect(subject.limit(5).pluck(:_id)).to eq(%w[1 2 3 4 5]) }
580
- specify { expect(subject.limit(5).pluck(:_id, :age)).to eq([['1', 10], ['2', 20], ['3', 30], ['4', nil], ['5', nil]]) }
581
- specify { expect(subject.limit(5).source(:name).pluck(:id, :age)).to eq([[1, 10], [2, 20], [3, 30], [4, nil], [5, nil]]) }
582
- specify do
583
- expect(subject.limit(5).pluck(:_index, :_type, :name)).to eq([
584
- %w[products product Name1],
585
- %w[products product Name2],
586
- %w[products product Name3],
587
- ['products', 'city', nil],
588
- ['products', 'city', nil]
745
+ specify do
746
+ expect(subject.limit(5).pluck(:_id, :age)).to eq([['1', 10], ['2', 20], ['3', 30], ['4', 40], ['5', 50]])
747
+ end
748
+ specify do
749
+ expect(subject.limit(5).source(:name).pluck(:id, :age)).to eq([[1, 10], [2, 20], [3, 30], [4, 40], [5, 50]])
750
+ end
751
+ specify do
752
+ expect(subject.limit(5).pluck(:_index, :name)).to eq([
753
+ %w[products Name1],
754
+ %w[products Name2],
755
+ %w[products Name3],
756
+ %w[products Name4],
757
+ %w[products Name5]
589
758
  ])
590
759
  end
591
760
 
@@ -616,24 +785,12 @@ describe Chewy::Search::Request do
616
785
  Chewy.client.indices.refresh(index: 'products')
617
786
  end.to change { described_class.new(ProductsIndex).total_count }.from(9).to(7)
618
787
  end
619
- specify do
620
- expect do
621
- subject.types(:product).delete_all
622
- Chewy.client.indices.refresh(index: 'products')
623
- end.to change { described_class.new(ProductsIndex::Product).total_entries }.from(3).to(0)
624
- end
625
788
  specify do
626
789
  expect do
627
790
  subject.delete_all
628
791
  Chewy.client.indices.refresh(index: 'products')
629
792
  end.to change { described_class.new(ProductsIndex).total }.from(9).to(0)
630
793
  end
631
- specify do
632
- expect do
633
- described_class.new(ProductsIndex::City).delete_all
634
- Chewy.client.indices.refresh(index: 'products')
635
- end.to change { described_class.new(ProductsIndex).total }.from(9).to(6)
636
- end
637
794
 
638
795
  specify do
639
796
  outer_payload = nil
@@ -644,9 +801,7 @@ describe Chewy::Search::Request do
644
801
  expect(outer_payload).to eq(
645
802
  index: ProductsIndex,
646
803
  indexes: [ProductsIndex],
647
- request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}, refresh: true},
648
- type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
649
- types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
804
+ request: {index: ['products'], body: {query: {match: {name: 'name3'}}}, refresh: true}
650
805
  )
651
806
  end
652
807
 
@@ -659,11 +814,67 @@ describe Chewy::Search::Request do
659
814
  expect(outer_payload).to eq(
660
815
  index: ProductsIndex,
661
816
  indexes: [ProductsIndex],
662
- request: {index: ['products'], type: %w[product city country], body: {query: {match: {name: 'name3'}}}, refresh: false},
663
- type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
664
- types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
817
+ request: {index: ['products'], body: {query: {match: {name: 'name3'}}}, refresh: false}
665
818
  )
666
819
  end
820
+
821
+ it 'delete records asynchronously' do
822
+ outer_payload = nil
823
+ ActiveSupport::Notifications.subscribe('delete_query.chewy') do |_name, _start, _finish, _id, payload|
824
+ outer_payload = payload
825
+ end
826
+ subject.query(match: {name: 'name3'}).delete_all(
827
+ refresh: false,
828
+ wait_for_completion: false,
829
+ requests_per_second: 10.0,
830
+ scroll_size: 2000
831
+ )
832
+ expect(outer_payload).to eq(
833
+ index: ProductsIndex,
834
+ indexes: [ProductsIndex],
835
+ request: {
836
+ index: ['products'],
837
+ body: {query: {match: {name: 'name3'}}},
838
+ refresh: false,
839
+ wait_for_completion: false,
840
+ requests_per_second: 10.0,
841
+ scroll_size: 2000
842
+ }
843
+ )
844
+ end
845
+ end
846
+
847
+ describe '#response=' do
848
+ let(:query) { ProductsIndex.limit(0) }
849
+ let(:raw_response) { Chewy.client.search(query.render) }
850
+
851
+ it 'wraps and assigns the raw response' do
852
+ query.response = raw_response
853
+ expect(query.response).to be_a(Chewy::Search::Response)
854
+ end
855
+ end
856
+
857
+ describe '#performed?' do
858
+ let(:query) { ProductsIndex.limit(0) }
859
+ let(:raw_response) { Chewy.client.search(query.render) }
860
+
861
+ it 'is false on a new query' do
862
+ expect(query.performed?).to eq(false)
863
+ end
864
+
865
+ it 'is true after the search request was issued' do
866
+ expect do
867
+ # The `response` method has a side effect of performing unperformed
868
+ # queries.
869
+ query.response
870
+ end.to change(query, :performed?).from(false).to(true)
871
+ end
872
+
873
+ it 'is true after assigning a raw response' do
874
+ expect do
875
+ query.response = raw_response
876
+ end.to change(query, :performed?).from(false).to(true)
877
+ end
667
878
  end
668
879
  end
669
880
  end