Skip to content

Commit 9d110f8

Browse files
Merge #405
405: Support scopes in multi_search r=ellnix a=ellnix # Pull Request ## Related issue Fixes part of #397 - This makes multi_search, like the regular search, support relations and other collections that respond to `where`. - In favor of this new :collection option, :class_name is softly deprecated for a consistent user experience (since :collection does everything that :class_name did and more) Co-authored-by: ellnix <[email protected]>
2 parents 9d9ed17 + 0d7480a commit 9d110f8

File tree

4 files changed

+69
-14
lines changed

4 files changed

+69
-14
lines changed

README.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,14 @@ Use `#each_result` to loop through pairs of your provided keys and the results:
265265
</ul>
266266
```
267267

268-
Records are loaded when the keys are models, or when `:class_name` option is passed:
268+
Records are loaded when the keys are models, or when `:scope` option is passed:
269269

270270
```ruby
271271
multi_search_results = Meilisearch::Rails.multi_search(
272-
'books' => { q: 'Harry', class_name: 'Book' },
273-
'mangas' => { q: 'Attack', class_name: 'Manga' }
272+
# scope may be a relation
273+
'books' => { q: 'Harry', scope: Book.all },
274+
# or a model
275+
'mangas' => { q: 'Attack', scope: Manga }
274276
)
275277
```
276278

@@ -280,8 +282,8 @@ The index to search is inferred from the model if the key is a model, if the key
280282

281283
```ruby
282284
multi_search_results = Meilisearch::Rails.multi_search(
283-
'western' => { q: 'Harry', class_name: 'Book', index_uid: 'books_production' },
284-
'japanese' => { q: 'Attack', class_name: 'Manga', index_uid: 'mangas_production' }
285+
'western' => { q: 'Harry', scope: Book, index_uid: 'books_production' },
286+
'japanese' => { q: 'Attack', scope: Manga, index_uid: 'mangas_production' }
285287
)
286288
```
287289

@@ -291,10 +293,11 @@ You can search the same index multiple times by specifying `:index_uid`:
291293

292294
```ruby
293295
query = 'hero'
296+
294297
multi_search_results = Meilisearch::Rails.multi_search(
295-
'Isekai Manga' => { q: query, class_name: 'Manga', filters: 'genre:isekai', index_uid: 'mangas_production' }
296-
'Shounen Manga' => { q: query, class_name: 'Manga', filters: 'genre:shounen', index_uid: 'mangas_production' }
297-
'Steampunk Manga' => { q: query, class_name: 'Manga', filters: 'genre:steampunk', index_uid: 'mangas_production' }
298+
'Isekai Manga' => { q: query, scope: Manga, filters: 'genre:isekai', index_uid: 'mangas_production' }
299+
'Shounen Manga' => { q: query, scope: Manga, filters: 'genre:shounen', index_uid: 'mangas_production' }
300+
'Steampunk Manga' => { q: query, scope: Manga, filters: 'genre:steampunk', index_uid: 'mangas_production' }
298301
)
299302
```
300303

lib/meilisearch/rails/multi_search.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ module Rails
55
class << self
66
def multi_search(searches)
77
search_parameters = searches.map do |(index_target, options)|
8-
index_target = options.delete(:index_uid) || index_target
8+
model_class = options[:scope].respond_to?(:model) ? options[:scope].model : options[:scope]
9+
index_target = options.delete(:index_uid) || model_class || index_target
910

1011
paginate(options) if pagination_enabled?
1112
normalize(options, index_target)
@@ -18,7 +19,7 @@ def multi_search(searches)
1819

1920
def normalize(options, index_target)
2021
options
21-
.except(:class_name)
22+
.except(:class_name, :scope)
2223
.merge!(index_uid: index_uid_from_target(index_target))
2324
end
2425

lib/meilisearch/rails/multi_search/result.rb

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@ def initialize(searches, raw_results)
99

1010
searches.zip(raw_results['results']).each do |(target, search_options), result|
1111
results_class = if search_options[:class_name]
12+
Meilisearch::Rails.logger.warn(
13+
'[meilisearch-rails] The :class_name option in multi search is deprecated, please use :scope instead.'
14+
)
15+
1216
search_options[:class_name].constantize
1317
elsif target.instance_of?(Class)
1418
target
19+
elsif search_options[:scope]
20+
search_options[:scope]
1521
end
1622

17-
@results[target] = results_class ? load_results(results_class, result) : result['hits']
23+
@results[target] = results_class ? load_results(results_class, result, scope: search_options[:scope]) : result['hits']
1824

1925
@metadata[target] = result.except('hits')
2026
end
@@ -69,7 +75,9 @@ def to_h
6975

7076
private
7177

72-
def load_results(klass, result)
78+
def load_results(klass, result, scope:)
79+
scope ||= klass
80+
7381
pk_method = klass.ms_primary_key_method
7482
pk_method = pk_method.in if Utilities.mongo_model?(klass)
7583

@@ -78,7 +86,7 @@ def load_results(klass, result)
7886
hits_by_id =
7987
result['hits'].index_by { |hit| hit[condition_key.to_s] }
8088

81-
records = klass.where(condition_key => hits_by_id.keys)
89+
records = scope.where(condition_key => hits_by_id.keys)
8290

8391
if records.respond_to? :in_order_of
8492
records.in_order_of(condition_key, hits_by_id.keys).each do |record|

spec/multi_search_spec.rb

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@
9999

100100
context 'when :class_name is also present' do
101101
it 'loads results from the correct models' do
102+
allow(Meilisearch::Rails.logger).to receive(:warn).and_return(nil)
103+
102104
results = Meilisearch::Rails.multi_search(
103105
'books' => { q: 'Steve', index_uid: Book.index.uid, class_name: 'Book' },
104106
'products' => { q: 'palm', limit: 1, index_uid: Product.index.uid, class_name: 'Product' },
@@ -134,6 +136,18 @@
134136
end
135137

136138
context 'when class_name is specified' do
139+
let(:logger) { instance_double('Logger', warn: nil) }
140+
141+
before do
142+
allow(Meilisearch::Rails).to receive(:logger).and_return(logger)
143+
end
144+
145+
it 'warns about deprecation' do
146+
results = Meilisearch::Rails.multi_search(Book.index.uid => { q: 'Steve', class_name: 'Book' })
147+
expect(results.to_h[Book.index.uid]).to contain_exactly(steve_jobs)
148+
expect(logger).to have_received(:warn).with(a_string_matching(':class_name'))
149+
end
150+
137151
it 'returns ORM records' do
138152
results = Meilisearch::Rails.multi_search(
139153
Book.index.uid => { q: 'Steve', class_name: 'Book' },
@@ -164,7 +178,7 @@
164178
it 'returns a mixture of ORM records and hashes' do
165179
results = Meilisearch::Rails.multi_search(
166180
Book => { q: 'Steve' },
167-
Product.index.uid => { q: 'palm', limit: 1, class_name: 'Product' },
181+
Product.index.uid => { q: 'palm', limit: 1, scope: Product },
168182
Color.index.uid => { q: 'bl' }
169183
)
170184

@@ -200,4 +214,33 @@
200214
Meilisearch::Rails.configuration[:pagination_backend] = nil
201215
end
202216
end
217+
218+
context 'with scopes' do
219+
it 'fetches items from the given scope' do
220+
results = Meilisearch::Rails.multi_search(
221+
Product => { q: 'palm', scope: Product.where('tags LIKE "%terrible%"') },
222+
Color => { q: 'bl', scope: Color.where(short_name: 'bla') }
223+
)
224+
225+
expect(results).to contain_exactly(
226+
black, palm_pixi_plus
227+
)
228+
end
229+
230+
it 'infers the model' do
231+
results = Meilisearch::Rails.multi_search(
232+
'colors' => { q: 'bl', scope: Color.all, index_uid: Color.index.uid }
233+
)
234+
235+
expect(results.to_h['colors']).to contain_exactly(blue, black)
236+
end
237+
238+
it 'infers the index as well as the model' do
239+
results = Meilisearch::Rails.multi_search(
240+
'colors' => { q: 'bl', scope: Color }
241+
)
242+
243+
expect(results.to_h['colors']).to contain_exactly(blue, black)
244+
end
245+
end
203246
end

0 commit comments

Comments
 (0)