chewy 5.1.0 → 7.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (234) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
  6. data/.github/workflows/ruby.yml +73 -0
  7. data/.rubocop.yml +13 -8
  8. data/.rubocop_todo.yml +110 -22
  9. data/CHANGELOG.md +449 -347
  10. data/CODE_OF_CONDUCT.md +14 -0
  11. data/CONTRIBUTING.md +63 -0
  12. data/Gemfile +3 -7
  13. data/Guardfile +3 -1
  14. data/LICENSE.txt +1 -1
  15. data/README.md +423 -311
  16. data/chewy.gemspec +8 -10
  17. data/gemfiles/rails.5.2.activerecord.gemfile +9 -14
  18. data/gemfiles/rails.6.0.activerecord.gemfile +11 -0
  19. data/gemfiles/rails.6.1.activerecord.gemfile +13 -0
  20. data/gemfiles/rails.7.0.activerecord.gemfile +13 -0
  21. data/lib/chewy/config.rb +42 -60
  22. data/lib/chewy/errors.rb +4 -10
  23. data/lib/chewy/fields/base.rb +80 -20
  24. data/lib/chewy/fields/root.rb +7 -17
  25. data/lib/chewy/index/actions.rb +62 -35
  26. data/lib/chewy/{type → index}/adapter/active_record.rb +18 -4
  27. data/lib/chewy/{type → index}/adapter/base.rb +2 -3
  28. data/lib/chewy/{type → index}/adapter/object.rb +28 -32
  29. data/lib/chewy/{type → index}/adapter/orm.rb +26 -24
  30. data/lib/chewy/index/aliases.rb +14 -5
  31. data/lib/chewy/{type → index}/crutch.rb +5 -5
  32. data/lib/chewy/index/import/bulk_builder.rb +311 -0
  33. data/lib/chewy/{type → index}/import/bulk_request.rb +6 -7
  34. data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
  35. data/lib/chewy/{type → index}/import/routine.rb +17 -16
  36. data/lib/chewy/{type → index}/import.rb +51 -33
  37. data/lib/chewy/{type → index}/mapping.rb +32 -37
  38. data/lib/chewy/index/observe/active_record_methods.rb +87 -0
  39. data/lib/chewy/index/observe/callback.rb +34 -0
  40. data/lib/chewy/index/observe.rb +17 -0
  41. data/lib/chewy/index/specification.rb +1 -0
  42. data/lib/chewy/{type → index}/syncer.rb +61 -62
  43. data/lib/chewy/{type → index}/witchcraft.rb +15 -9
  44. data/lib/chewy/{type → index}/wrapper.rb +13 -3
  45. data/lib/chewy/index.rb +46 -96
  46. data/lib/chewy/journal.rb +25 -14
  47. data/lib/chewy/minitest/helpers.rb +86 -13
  48. data/lib/chewy/minitest/search_index_receiver.rb +22 -26
  49. data/lib/chewy/multi_search.rb +62 -0
  50. data/lib/chewy/railtie.rb +6 -20
  51. data/lib/chewy/rake_helper.rb +136 -108
  52. data/lib/chewy/rspec/build_query.rb +12 -0
  53. data/lib/chewy/rspec/helpers.rb +55 -0
  54. data/lib/chewy/rspec/update_index.rb +55 -44
  55. data/lib/chewy/rspec.rb +2 -0
  56. data/lib/chewy/runtime.rb +1 -1
  57. data/lib/chewy/search/loader.rb +19 -41
  58. data/lib/chewy/search/parameters/collapse.rb +16 -0
  59. data/lib/chewy/search/parameters/concerns/query_storage.rb +2 -2
  60. data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
  61. data/lib/chewy/search/parameters/indices.rb +12 -57
  62. data/lib/chewy/search/parameters/none.rb +1 -3
  63. data/lib/chewy/search/parameters/order.rb +6 -19
  64. data/lib/chewy/search/parameters/source.rb +5 -1
  65. data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
  66. data/lib/chewy/search/parameters.rb +7 -4
  67. data/lib/chewy/search/query_proxy.rb +9 -2
  68. data/lib/chewy/search/request.rb +180 -154
  69. data/lib/chewy/search/response.rb +5 -5
  70. data/lib/chewy/search/scoping.rb +7 -8
  71. data/lib/chewy/search/scrolling.rb +16 -13
  72. data/lib/chewy/search.rb +7 -22
  73. data/lib/chewy/stash.rb +19 -30
  74. data/lib/chewy/strategy/active_job.rb +2 -2
  75. data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
  76. data/lib/chewy/strategy/base.rb +10 -0
  77. data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
  78. data/lib/chewy/strategy/sidekiq.rb +3 -2
  79. data/lib/chewy/strategy.rb +5 -19
  80. data/lib/chewy/version.rb +1 -1
  81. data/lib/chewy.rb +36 -80
  82. data/lib/generators/chewy/install_generator.rb +1 -1
  83. data/lib/tasks/chewy.rake +26 -32
  84. data/migration_guide.md +56 -0
  85. data/spec/chewy/config_spec.rb +15 -61
  86. data/spec/chewy/fields/base_spec.rb +432 -145
  87. data/spec/chewy/fields/root_spec.rb +20 -28
  88. data/spec/chewy/fields/time_fields_spec.rb +5 -5
  89. data/spec/chewy/index/actions_spec.rb +388 -55
  90. data/spec/chewy/{type → index}/adapter/active_record_spec.rb +110 -44
  91. data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
  92. data/spec/chewy/index/aliases_spec.rb +3 -3
  93. data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
  94. data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
  95. data/spec/chewy/{type → index}/import/journal_builder_spec.rb +14 -22
  96. data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
  97. data/spec/chewy/{type → index}/import_spec.rb +149 -96
  98. data/spec/chewy/index/mapping_spec.rb +135 -0
  99. data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
  100. data/spec/chewy/index/observe/callback_spec.rb +139 -0
  101. data/spec/chewy/index/observe_spec.rb +143 -0
  102. data/spec/chewy/index/settings_spec.rb +3 -1
  103. data/spec/chewy/index/specification_spec.rb +20 -30
  104. data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
  105. data/spec/chewy/{type → index}/witchcraft_spec.rb +34 -21
  106. data/spec/chewy/index/wrapper_spec.rb +100 -0
  107. data/spec/chewy/index_spec.rb +69 -137
  108. data/spec/chewy/journal_spec.rb +46 -91
  109. data/spec/chewy/minitest/helpers_spec.rb +122 -14
  110. data/spec/chewy/minitest/search_index_receiver_spec.rb +24 -26
  111. data/spec/chewy/multi_search_spec.rb +84 -0
  112. data/spec/chewy/rake_helper_spec.rb +293 -101
  113. data/spec/chewy/rspec/build_query_spec.rb +34 -0
  114. data/spec/chewy/rspec/helpers_spec.rb +61 -0
  115. data/spec/chewy/rspec/update_index_spec.rb +106 -102
  116. data/spec/chewy/runtime_spec.rb +2 -2
  117. data/spec/chewy/search/loader_spec.rb +19 -53
  118. data/spec/chewy/search/pagination/kaminari_examples.rb +3 -5
  119. data/spec/chewy/search/pagination/kaminari_spec.rb +1 -1
  120. data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
  121. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
  122. data/spec/chewy/search/parameters/indices_spec.rb +26 -118
  123. data/spec/chewy/search/parameters/none_spec.rb +1 -1
  124. data/spec/chewy/search/parameters/order_spec.rb +18 -11
  125. data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
  126. data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
  127. data/spec/chewy/search/parameters/source_spec.rb +8 -2
  128. data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
  129. data/spec/chewy/search/parameters_spec.rb +23 -7
  130. data/spec/chewy/search/query_proxy_spec.rb +68 -17
  131. data/spec/chewy/search/request_spec.rb +344 -149
  132. data/spec/chewy/search/response_spec.rb +35 -25
  133. data/spec/chewy/search/scrolling_spec.rb +28 -26
  134. data/spec/chewy/search_spec.rb +69 -59
  135. data/spec/chewy/stash_spec.rb +16 -26
  136. data/spec/chewy/strategy/active_job_spec.rb +23 -10
  137. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
  138. data/spec/chewy/strategy/atomic_spec.rb +9 -10
  139. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
  140. data/spec/chewy/strategy/sidekiq_spec.rb +14 -10
  141. data/spec/chewy/strategy_spec.rb +19 -15
  142. data/spec/chewy_spec.rb +17 -110
  143. data/spec/spec_helper.rb +6 -29
  144. data/spec/support/active_record.rb +43 -5
  145. metadata +102 -198
  146. data/.travis.yml +0 -45
  147. data/Appraisals +0 -81
  148. data/LEGACY_DSL.md +0 -497
  149. data/gemfiles/rails.4.0.activerecord.gemfile +0 -15
  150. data/gemfiles/rails.4.1.activerecord.gemfile +0 -15
  151. data/gemfiles/rails.4.2.activerecord.gemfile +0 -16
  152. data/gemfiles/rails.4.2.mongoid.5.2.gemfile +0 -16
  153. data/gemfiles/rails.5.0.activerecord.gemfile +0 -16
  154. data/gemfiles/rails.5.0.mongoid.6.1.gemfile +0 -16
  155. data/gemfiles/rails.5.1.activerecord.gemfile +0 -16
  156. data/gemfiles/rails.5.1.mongoid.6.3.gemfile +0 -16
  157. data/gemfiles/sequel.4.45.gemfile +0 -11
  158. data/lib/chewy/backports/deep_dup.rb +0 -46
  159. data/lib/chewy/backports/duplicable.rb +0 -91
  160. data/lib/chewy/query/compose.rb +0 -68
  161. data/lib/chewy/query/criteria.rb +0 -191
  162. data/lib/chewy/query/filters.rb +0 -244
  163. data/lib/chewy/query/loading.rb +0 -110
  164. data/lib/chewy/query/nodes/and.rb +0 -25
  165. data/lib/chewy/query/nodes/base.rb +0 -17
  166. data/lib/chewy/query/nodes/bool.rb +0 -34
  167. data/lib/chewy/query/nodes/equal.rb +0 -34
  168. data/lib/chewy/query/nodes/exists.rb +0 -20
  169. data/lib/chewy/query/nodes/expr.rb +0 -28
  170. data/lib/chewy/query/nodes/field.rb +0 -110
  171. data/lib/chewy/query/nodes/has_child.rb +0 -15
  172. data/lib/chewy/query/nodes/has_parent.rb +0 -15
  173. data/lib/chewy/query/nodes/has_relation.rb +0 -59
  174. data/lib/chewy/query/nodes/match_all.rb +0 -11
  175. data/lib/chewy/query/nodes/missing.rb +0 -20
  176. data/lib/chewy/query/nodes/not.rb +0 -25
  177. data/lib/chewy/query/nodes/or.rb +0 -25
  178. data/lib/chewy/query/nodes/prefix.rb +0 -19
  179. data/lib/chewy/query/nodes/query.rb +0 -20
  180. data/lib/chewy/query/nodes/range.rb +0 -63
  181. data/lib/chewy/query/nodes/raw.rb +0 -15
  182. data/lib/chewy/query/nodes/regexp.rb +0 -35
  183. data/lib/chewy/query/nodes/script.rb +0 -20
  184. data/lib/chewy/query/pagination.rb +0 -25
  185. data/lib/chewy/query.rb +0 -1142
  186. data/lib/chewy/search/pagination/will_paginate.rb +0 -43
  187. data/lib/chewy/search/parameters/types.rb +0 -20
  188. data/lib/chewy/strategy/resque.rb +0 -27
  189. data/lib/chewy/strategy/shoryuken.rb +0 -40
  190. data/lib/chewy/type/actions.rb +0 -43
  191. data/lib/chewy/type/adapter/mongoid.rb +0 -67
  192. data/lib/chewy/type/adapter/sequel.rb +0 -93
  193. data/lib/chewy/type/import/bulk_builder.rb +0 -122
  194. data/lib/chewy/type/observe.rb +0 -82
  195. data/lib/chewy/type.rb +0 -117
  196. data/lib/sequel/plugins/chewy_observe.rb +0 -63
  197. data/spec/chewy/query/criteria_spec.rb +0 -700
  198. data/spec/chewy/query/filters_spec.rb +0 -201
  199. data/spec/chewy/query/loading_spec.rb +0 -124
  200. data/spec/chewy/query/nodes/and_spec.rb +0 -12
  201. data/spec/chewy/query/nodes/bool_spec.rb +0 -14
  202. data/spec/chewy/query/nodes/equal_spec.rb +0 -32
  203. data/spec/chewy/query/nodes/exists_spec.rb +0 -18
  204. data/spec/chewy/query/nodes/has_child_spec.rb +0 -59
  205. data/spec/chewy/query/nodes/has_parent_spec.rb +0 -59
  206. data/spec/chewy/query/nodes/match_all_spec.rb +0 -11
  207. data/spec/chewy/query/nodes/missing_spec.rb +0 -16
  208. data/spec/chewy/query/nodes/not_spec.rb +0 -14
  209. data/spec/chewy/query/nodes/or_spec.rb +0 -12
  210. data/spec/chewy/query/nodes/prefix_spec.rb +0 -16
  211. data/spec/chewy/query/nodes/query_spec.rb +0 -12
  212. data/spec/chewy/query/nodes/range_spec.rb +0 -32
  213. data/spec/chewy/query/nodes/raw_spec.rb +0 -11
  214. data/spec/chewy/query/nodes/regexp_spec.rb +0 -43
  215. data/spec/chewy/query/nodes/script_spec.rb +0 -15
  216. data/spec/chewy/query/pagination/kaminari_spec.rb +0 -5
  217. data/spec/chewy/query/pagination/will_paginate_spec.rb +0 -5
  218. data/spec/chewy/query/pagination_spec.rb +0 -39
  219. data/spec/chewy/query_spec.rb +0 -637
  220. data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
  221. data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
  222. data/spec/chewy/search/parameters/types_spec.rb +0 -5
  223. data/spec/chewy/strategy/resque_spec.rb +0 -46
  224. data/spec/chewy/strategy/shoryuken_spec.rb +0 -66
  225. data/spec/chewy/type/actions_spec.rb +0 -50
  226. data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
  227. data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
  228. data/spec/chewy/type/import/bulk_builder_spec.rb +0 -279
  229. data/spec/chewy/type/mapping_spec.rb +0 -173
  230. data/spec/chewy/type/observe_spec.rb +0 -137
  231. data/spec/chewy/type/wrapper_spec.rb +0 -98
  232. data/spec/chewy/type_spec.rb +0 -55
  233. data/spec/support/mongoid.rb +0 -93
  234. data/spec/support/sequel.rb +0 -80
@@ -5,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=>["city", "country", "product"], :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=>["city", "country", "product"], :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 }
@@ -164,13 +214,18 @@ describe Chewy::Search::Request do
164
214
  specify { expect { subject.search_type('foo') }.not_to change { subject.render } }
165
215
  end
166
216
 
167
- %i[preference timeout].each do |name|
168
- describe "##{name}" do
169
- specify { expect(subject.send(name, :foo).render[:body]).to include(name => 'foo') }
170
- specify { expect(subject.send(name, :foo).send(name, :bar).render[:body]).to include(name => 'bar') }
171
- specify { expect(subject.send(name, :foo).send(name, nil).render[:body]).to be_blank }
172
- specify { expect { subject.send(name, :foo) }.not_to change { subject.render } }
173
- end
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 } }
174
229
  end
175
230
 
176
231
  describe '#source' do
@@ -178,23 +233,53 @@ describe Chewy::Search::Request do
178
233
  specify { expect(subject.source(:foo, :bar).source(nil).render[:body]).to include(_source: %w[foo bar]) }
179
234
  specify { expect(subject.source(%i[foo bar]).source(nil).render[:body]).to include(_source: %w[foo bar]) }
180
235
  specify { expect(subject.source(excludes: :foo).render[:body]).to include(_source: {excludes: %w[foo]}) }
181
- specify { expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body]).to include(_source: {excludes: %w[foo bar]}) }
182
- specify { expect(subject.source(excludes: :foo).source(excludes: %i[foo bar]).render[:body]).to include(_source: {excludes: %w[foo bar]}) }
183
- 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
184
248
  specify { expect(subject.source(excludes: :foo).source(false).render[:body]).to include(_source: false) }
185
- specify { expect(subject.source(excludes: :foo).source(false).source(excludes: :bar).render[:body]).to include(_source: {excludes: %w[foo bar]}) }
186
- 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
187
257
  specify { expect(subject.source(nil).render[:body]).to be_blank }
188
258
  specify { expect { subject.source(:foo) }.not_to change { subject.render } }
189
259
  end
190
260
 
191
261
  describe '#stored_fields' do
192
262
  specify { expect(subject.stored_fields(:foo).render[:body]).to include(stored_fields: ['foo']) }
193
- specify { expect(subject.stored_fields(%i[foo bar]).stored_fields(nil).render[:body]).to include(stored_fields: %w[foo bar]) }
194
- specify { expect(subject.stored_fields(:foo).stored_fields(:foo, :bar).render[:body]).to include(stored_fields: %w[foo bar]) }
195
- specify { expect(subject.stored_fields(:foo).stored_fields(false).render[:body]).to include(stored_fields: '_none_') }
196
- specify { expect(subject.stored_fields(:foo).stored_fields(false).stored_fields(:bar).render[:body]).to include(stored_fields: %w[foo bar]) }
197
- 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
198
283
  specify { expect(subject.stored_fields(nil).render[:body]).to be_blank }
199
284
  specify { expect { subject.stored_fields(:foo) }.not_to change { subject.render } }
200
285
  end
@@ -202,8 +287,14 @@ describe Chewy::Search::Request do
202
287
  %i[script_fields highlight].each do |name|
203
288
  describe "##{name}" do
204
289
  specify { expect(subject.send(name, foo: {bar: 42}).render[:body]).to include(name => {'foo' => {bar: 42}}) }
205
- specify { expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body]).to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}}) }
206
- 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
207
298
  specify { expect { subject.send(name, foo: {bar: 42}) }.not_to change { subject.render } }
208
299
  end
209
300
  end
@@ -211,16 +302,38 @@ describe Chewy::Search::Request do
211
302
  %i[suggest aggs].each do |name|
212
303
  describe "##{name}" do
213
304
  specify { expect(subject.send(name, foo: {bar: 42}).render[:body]).to include(name => {'foo' => {bar: 42}}) }
214
- specify { expect(subject.send(name, foo: {bar: 42}).send(name, moo: {baz: 43}).render[:body]).to include(name => {'foo' => {bar: 42}, 'moo' => {baz: 43}}) }
215
- 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
216
313
  specify { expect { subject.send(name, foo: {bar: 42}) }.not_to change { subject.render } }
217
314
  end
218
315
  end
219
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
+
220
327
  describe '#docvalue_fields' do
221
328
  specify { expect(subject.docvalue_fields(:foo).render[:body]).to include(docvalue_fields: ['foo']) }
222
- specify { expect(subject.docvalue_fields(%i[foo bar]).docvalue_fields(nil).render[:body]).to include(docvalue_fields: %w[foo bar]) }
223
- 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
224
337
  specify { expect(subject.docvalue_fields(nil).render[:body]).to be_blank }
225
338
  specify { expect { subject.docvalue_fields(:foo) }.not_to change { subject.render } }
226
339
  end
@@ -233,25 +346,25 @@ describe Chewy::Search::Request do
233
346
  specify { expect { subject.indices(:cities) }.not_to change { subject.render } }
234
347
  end
235
348
 
236
- describe '#types' do
237
- specify { expect(subject.types(:product).render[:type]).to contain_exactly('product') }
238
- specify { expect(described_class.new(ProductsIndex::City).types(ProductsIndex::Country).render[:type]).to match_array(%w[city country]) }
239
- specify { expect(subject.types(%i[product city]).types(nil).render[:type]).to match_array(%w[product city]) }
240
- specify { expect(subject.types(:product).types(:product, :city, :something).render[:type]).to match_array(%w[product city]) }
241
- specify { expect(subject.types(nil).render[:body]).to be_blank }
242
- specify { expect { subject.types(:product) }.not_to change { subject.render } }
243
- end
244
-
245
349
  describe '#indices_boost' do
246
350
  specify { expect(subject.indices_boost(foo: 1.2).render[:body]).to include(indices_boost: [{'foo' => 1.2}]) }
247
- 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}]) }
248
- 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
249
359
  specify { expect { subject.indices_boost(foo: 1.2) }.not_to change { subject.render } }
250
360
  end
251
361
 
252
362
  describe '#rescore' do
253
363
  specify { expect(subject.rescore(foo: 42).render[:body]).to include(rescore: [{foo: 42}]) }
254
- 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
255
368
  specify { expect(subject.rescore(foo: 42).rescore(nil).render[:body]).to include(rescore: [{foo: 42}]) }
256
369
  specify { expect { subject.rescore(foo: 42) }.not_to change { subject.render } }
257
370
  end
@@ -263,9 +376,19 @@ describe Chewy::Search::Request do
263
376
  specify { expect { subject.min_score(1.2) }.not_to change { subject.render } }
264
377
  end
265
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
+
266
386
  describe '#search_after' do
267
387
  specify { expect(subject.search_after(:foo, :bar).render[:body]).to include(search_after: %i[foo bar]) }
268
- 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
269
392
  specify { expect(subject.search_after(:foo).search_after(nil).render[:body]).to be_blank }
270
393
  specify { expect { subject.search_after(:foo) }.not_to change { subject.render } }
271
394
  end
@@ -276,17 +399,17 @@ describe Chewy::Search::Request do
276
399
  stub_model(:country)
277
400
 
278
401
  stub_index(:places) do
279
- define_type City do
280
- field :rating, type: 'integer'
281
- end
402
+ index_scope City
403
+ field :rating, type: 'integer'
404
+ end
282
405
 
283
- define_type Country do
284
- field :rating, type: 'integer'
285
- end
406
+ stub_index(:countries) do
407
+ index_scope Country
408
+ field :rating, type: 'integer'
286
409
  end
287
410
  end
288
411
 
289
- before { PlacesIndex.import!(cities: cities, countries: countries) }
412
+ before { PlacesIndex.import!(cities) }
290
413
 
291
414
  let(:cities) { Array.new(2) { |i| City.create!(rating: i) } }
292
415
  let(:countries) { Array.new(2) { |i| Country.create!(rating: i + 2) } }
@@ -294,14 +417,14 @@ describe Chewy::Search::Request do
294
417
  subject { described_class.new(PlacesIndex).order(:rating) }
295
418
 
296
419
  describe '#objects' do
297
- specify { expect(subject.objects).to eq([*cities, *countries]) }
420
+ specify { expect(subject.objects).to eq([*cities]) }
298
421
  specify { expect(subject.objects.class).to eq(Array) }
299
422
  end
300
423
 
301
424
  describe '#load' do
302
- specify { expect(subject.load(only: 'city')).to eq([*cities, *countries]) }
303
- specify { expect(subject.load(only: 'city').map(&:class).uniq).to eq([PlacesIndex::City, PlacesIndex::Country]) }
304
- 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]) }
305
428
  end
306
429
  end
307
430
 
@@ -320,7 +443,9 @@ describe Chewy::Search::Request do
320
443
 
321
444
  context do
322
445
  let(:first_scope) { subject.query(foo: 'bar').filter.should(moo: 'baz').post_filter.must_not(boo: 'baf').limit(10) }
323
- 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
324
449
 
325
450
  describe '#and' do
326
451
  specify do
@@ -388,14 +513,18 @@ describe Chewy::Search::Request do
388
513
  end
389
514
 
390
515
  context 'integration' do
391
- let(:products) { Array.new(3) { |i| {id: i.next.to_i, name: "Name#{i.next}", age: 10 * i.next}.stringify_keys! } }
392
- let(:cities) { Array.new(3) { |i| {id: (i.next + 3).to_i}.stringify_keys! } }
393
- 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! } }
394
524
  before do
395
- ProductsIndex::Product.import!(products.map { |h| double(h) })
396
- ProductsIndex::City.import!(cities.map { |h| double(h) })
397
- ProductsIndex::Country.import!(countries.map { |h| double(h) })
398
- 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) })
399
528
  end
400
529
 
401
530
  specify { expect(subject[0]._data).to be_a Hash }
@@ -407,18 +536,11 @@ describe Chewy::Search::Request do
407
536
  specify { expect(subject.size).to eq(3) }
408
537
  end
409
538
 
410
- context 'limited types' do
411
- subject { described_class.new(ProductsIndex::City, ProductsIndex::Country) }
412
-
413
- specify { expect(subject.count).to eq(6) }
414
- specify { expect(subject.size).to eq(6) }
415
- end
416
-
417
- context 'mixed types' do
418
- subject { described_class.new(CitiesIndex, ProductsIndex::Product) }
539
+ context 'mixed indexes' do
540
+ subject { described_class.new(CitiesIndex, ProductsIndex) }
419
541
 
420
- specify { expect(subject.count).to eq(9) }
421
- 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
422
544
  end
423
545
 
424
546
  context 'instrumentation' do
@@ -431,9 +553,7 @@ describe Chewy::Search::Request do
431
553
  expect(outer_payload).to eq(
432
554
  index: ProductsIndex,
433
555
  indexes: [ProductsIndex],
434
- request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}},
435
- type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
436
- types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
556
+ request: {index: ['products'], body: {query: {match: {name: 'name3'}}}}
437
557
  )
438
558
  end
439
559
  end
@@ -444,11 +564,23 @@ describe Chewy::Search::Request do
444
564
 
445
565
  describe '#highlight' do
446
566
  specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name).to eq('Name3') }
447
- specify { expect(subject.query(match: {name: 'name3'}).highlight(fields: {name: {}}).first.name_highlight).to eq('<em>Name3</em>') }
448
- 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
449
579
  end
450
580
 
451
581
  describe '#suggest' do
582
+ let(:products_count) { 3 }
583
+
452
584
  specify do
453
585
  expect(subject.suggest(
454
586
  foo: {
@@ -470,7 +602,7 @@ describe Chewy::Search::Request do
470
602
  describe '#aggs' do
471
603
  specify do
472
604
  expect(subject.aggs(avg_age: {avg: {field: :age}}).aggs)
473
- .to eq('avg_age' => {'value' => 20.0})
605
+ .to eq('avg_age' => {'value' => 50.0})
474
606
  end
475
607
  end
476
608
 
@@ -490,8 +622,7 @@ describe Chewy::Search::Request do
490
622
  specify { expect(subject.count).to eq(9) }
491
623
  specify { expect(subject.limit(6).count).to eq(9) }
492
624
  specify { expect(subject.offset(6).count).to eq(9) }
493
- specify { expect(subject.types(:product, :something).count).to eq(3) }
494
- specify { expect(subject.types(:product, :country).count).to eq(6) }
625
+ specify { expect(subject.indices(:products, CountriesIndex).count).to eq(12) }
495
626
  specify { expect(subject.filter(term: {age: 10}).count).to eq(1) }
496
627
  specify { expect(subject.query(term: {age: 10}).count).to eq(1) }
497
628
  specify { expect(subject.order(nil).count).to eq(9) }
@@ -530,7 +661,7 @@ describe Chewy::Search::Request do
530
661
  context do
531
662
  before { expect(Chewy.client).to receive(:search).once.and_call_original }
532
663
 
533
- 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) }
534
665
  specify { expect(subject.first(3).map(&:id)).to eq([9, 8, 7]) }
535
666
  specify { expect(subject.first(10).map(&:id)).to have(9).items }
536
667
  specify { expect(subject.limit(5).first(10).map(&:id)).to have(9).items }
@@ -543,7 +674,7 @@ describe Chewy::Search::Request do
543
674
  expect(Chewy.client).not_to receive(:search)
544
675
  end
545
676
 
546
- 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) }
547
678
  specify { expect(subject.first(3).map(&:id)).to eq([9, 8, 7]) }
548
679
  specify { expect(subject.first(10).map(&:id)).to have(9).items }
549
680
 
@@ -564,19 +695,37 @@ describe Chewy::Search::Request do
564
695
  end
565
696
 
566
697
  describe '#find' do
567
- specify { expect(subject.find('1')).to be_a(ProductsIndex::Product).and have_attributes(id: 1) }
568
- 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) }
569
700
  specify { expect(subject.limit(2).find('1', '3', '7').map(&:id)).to contain_exactly(1, 3, 7) }
570
701
  specify { expect(subject.find(1, 3, 7).map(&:id)).to contain_exactly(1, 3, 7) }
571
- specify { expect { subject.find('1', '3', '42') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42' }
572
- specify { expect { subject.find(1, 3, 42) }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 42' }
573
- specify { expect { subject.query(match: {name: 'name3'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1' }
574
- specify { expect { subject.query(match: {name: 'name2'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' }
575
- specify { expect { subject.filter(match: {name: 'name2'}).find('1', '3') }.to raise_error Chewy::DocumentNotFound, 'Could not find documents for ids: 1 and 3' }
576
- 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
577
726
 
578
727
  context 'make sure it returns everything' do
579
- let(:countries) { Array.new(6) { |i| {id: (i.next + 6).to_i}.stringify_keys! } }
728
+ let(:products_count) { 12 }
580
729
  before { expect(Chewy.client).not_to receive(:scroll) }
581
730
 
582
731
  specify { expect(subject.find((1..12).to_a)).to have(12).items }
@@ -587,21 +736,25 @@ describe Chewy::Search::Request do
587
736
  before { expect(Chewy.client).to receive(:scroll).once.and_call_original }
588
737
 
589
738
  specify { expect(subject.find((1..9).to_a)).to have(9).items }
590
- 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) }
591
740
  end
592
741
  end
593
742
 
594
743
  describe '#pluck' do
595
744
  specify { expect(subject.limit(5).pluck(:_id)).to eq(%w[1 2 3 4 5]) }
596
- specify { expect(subject.limit(5).pluck(:_id, :age)).to eq([['1', 10], ['2', 20], ['3', 30], ['4', nil], ['5', nil]]) }
597
- specify { expect(subject.limit(5).source(:name).pluck(:id, :age)).to eq([[1, 10], [2, 20], [3, 30], [4, nil], [5, nil]]) }
598
- specify do
599
- expect(subject.limit(5).pluck(:_index, :_type, :name)).to eq([
600
- %w[products product Name1],
601
- %w[products product Name2],
602
- %w[products product Name3],
603
- ['products', 'city', nil],
604
- ['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]
605
758
  ])
606
759
  end
607
760
 
@@ -632,24 +785,12 @@ describe Chewy::Search::Request do
632
785
  Chewy.client.indices.refresh(index: 'products')
633
786
  end.to change { described_class.new(ProductsIndex).total_count }.from(9).to(7)
634
787
  end
635
- specify do
636
- expect do
637
- subject.types(:product).delete_all
638
- Chewy.client.indices.refresh(index: 'products')
639
- end.to change { described_class.new(ProductsIndex::Product).total_entries }.from(3).to(0)
640
- end
641
788
  specify do
642
789
  expect do
643
790
  subject.delete_all
644
791
  Chewy.client.indices.refresh(index: 'products')
645
792
  end.to change { described_class.new(ProductsIndex).total }.from(9).to(0)
646
793
  end
647
- specify do
648
- expect do
649
- described_class.new(ProductsIndex::City).delete_all
650
- Chewy.client.indices.refresh(index: 'products')
651
- end.to change { described_class.new(ProductsIndex).total }.from(9).to(6)
652
- end
653
794
 
654
795
  specify do
655
796
  outer_payload = nil
@@ -660,9 +801,7 @@ describe Chewy::Search::Request do
660
801
  expect(outer_payload).to eq(
661
802
  index: ProductsIndex,
662
803
  indexes: [ProductsIndex],
663
- request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}, refresh: true},
664
- type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
665
- types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
804
+ request: {index: ['products'], body: {query: {match: {name: 'name3'}}}, refresh: true}
666
805
  )
667
806
  end
668
807
 
@@ -675,11 +814,67 @@ describe Chewy::Search::Request do
675
814
  expect(outer_payload).to eq(
676
815
  index: ProductsIndex,
677
816
  indexes: [ProductsIndex],
678
- request: {index: ['products'], type: %w[city country product], body: {query: {match: {name: 'name3'}}}, refresh: false},
679
- type: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country],
680
- types: [ProductsIndex::Product, ProductsIndex::City, ProductsIndex::Country]
817
+ request: {index: ['products'], body: {query: {match: {name: 'name3'}}}, refresh: false}
681
818
  )
682
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
683
878
  end
684
879
  end
685
880
  end