Skip to content

Commit

Permalink
Implement multi-search pagination and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
ellnix committed Feb 23, 2024
1 parent ef6b019 commit b0248af
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 29 deletions.
46 changes: 36 additions & 10 deletions lib/meilisearch/rails/multi_search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,45 @@ module Rails
class << self
def multi_search(searches)
search_parameters = searches.map do |(index_target, options)|
index_uid = case index_target
when String, Symbol
index_target
else
index_target.index.uid
end

options.except(:class_name).merge(index_uid: index_uid)
paginate(options) if pagination_enabled?
normalize(options, index_target)
end

raw_results = client.multi_search(search_parameters)['results']
MultiSearchResult.new(searches, client.multi_search(search_parameters))
end


private

def normalize(options, index_target)
options
.except(:class_name)
.merge!(index_uid: index_uid_from_target(index_target))
end

def index_uid_from_target(index_target)
case index_target
when String, Symbol
index_target
else
index_target.index.uid
end
end

def paginate(options)
%w[page hitsPerPage hits_per_page].each do |key|
# Deletes hitsPerPage to avoid passing along a meilisearch-ruby warning/exception
value = options.delete(key) || options.delete(key.to_sym)
options[key.underscore.to_sym] = value.to_i if value
end

# It is required to activate the finite pagination in Meilisearch v0.30 (or newer),
# to have at least `hits_per_page` defined or `page` in the search request.
options[:page] ||= 1
end

MultiSearchResult.new(searches, raw_results)
def pagination_enabled?
MeiliSearch::Rails.configuration[:pagination_backend]
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/meilisearch/rails/multi_search/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def initialize(searches, raw_results)
@results = {}
@metadata = {}

searches.zip(raw_results).each do |(index_target, search_options), result|
searches.zip(raw_results['results']).each do |(index_target, search_options), result|
index_target = search_options[:class_name].constantize if search_options[:class_name]

@results[index_target] = case index_target
Expand Down
30 changes: 16 additions & 14 deletions spec/multi_search/result_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@

describe MeiliSearch::Rails::MultiSearchResult do # rubocop:todo RSpec/FilePath
let(:raw_results) do
[
{ 'indexUid' => 'books_index',
'hits' => [{ 'name' => 'Steve Jobs', 'id' => '3', 'author' => 'Walter Isaacson', 'premium' => nil, 'released' => nil, 'genre' => nil }],
'query' => 'Steve', 'processingTimeMs' => 0, 'limit' => 20, 'offset' => 0, 'estimatedTotalHits' => 1 },
{ 'indexUid' => 'products_index',
'hits' => [{ 'id' => '4', 'href' => 'ebay', 'name' => 'palm pixi plus' }],
'query' => 'palm', 'processingTimeMs' => 0, 'limit' => 1, 'offset' => 0, 'estimatedTotalHits' => 2 },
{ 'indexUid' => 'color_index',
'hits' => [
{ 'name' => 'black', 'id' => '5', 'short_name' => 'bla', 'hex' => 0 },
{ 'name' => 'blue', 'id' => '4', 'short_name' => 'blu', 'hex' => 255 }
],
'query' => 'bl', 'processingTimeMs' => 0, 'limit' => 20, 'offset' => 0, 'estimatedTotalHits' => 2 }
]
{
'results' => [
{ 'indexUid' => 'books_index',
'hits' => [{ 'name' => 'Steve Jobs', 'id' => '3', 'author' => 'Walter Isaacson', 'premium' => nil, 'released' => nil, 'genre' => nil }],
'query' => 'Steve', 'processingTimeMs' => 0, 'limit' => 20, 'offset' => 0, 'estimatedTotalHits' => 1 },
{ 'indexUid' => 'products_index',
'hits' => [{ 'id' => '4', 'href' => 'ebay', 'name' => 'palm pixi plus' }],
'query' => 'palm', 'processingTimeMs' => 0, 'limit' => 1, 'offset' => 0, 'estimatedTotalHits' => 2 },
{ 'indexUid' => 'color_index',
'hits' => [
{ 'name' => 'black', 'id' => '5', 'short_name' => 'bla', 'hex' => 0 },
{ 'name' => 'blue', 'id' => '4', 'short_name' => 'blu', 'hex' => 255 }
],
'query' => 'bl', 'processingTimeMs' => 0, 'limit' => 20, 'offset' => 0, 'estimatedTotalHits' => 2 }
]
}
end

it 'is enumerable' do
Expand Down
25 changes: 21 additions & 4 deletions spec/multi_search_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
def reset_indexes
[Book, Color, Product].each do |klass|
klass.delete_all
klass.index.delete_all_documents
klass.clear_index!
end
end

before(:all) { reset_indexes } # rubocop:todo RSpec/BeforeAfterAll

after { reset_indexes }
before { reset_indexes }

let!(:palm_pixi_plus) { Product.create!(name: 'palm pixi plus', href: 'ebay', tags: ['terrible']) }
let!(:steve_jobs) { Book.create! name: 'Steve Jobs', author: 'Walter Isaacson' }
Expand Down Expand Up @@ -96,4 +94,23 @@ def reset_indexes
)
end
end

context 'with pagination' do
it 'it properly paginates each search' do
MeiliSearch::Rails.configuration[:pagination_backend] = :kaminari

results = MeiliSearch::Rails.multi_search(
Book => { q: 'Steve' },
Product => { q: 'palm', page: 1, hits_per_page: 1 },
Color.index.uid => { q: 'bl', page: 1, 'hitsPerPage' => '1' }
)

expect(results).to contain_exactly(
steve_jobs, palm_pixi_plus,
a_hash_including('name' => 'black', 'short_name' => 'bla')
)

MeiliSearch::Rails.configuration[:pagination_backend] = nil
end
end
end

0 comments on commit b0248af

Please sign in to comment.