diff --git a/lib/meilisearch/rails/multi_search.rb b/lib/meilisearch/rails/multi_search.rb index 64d2abc4..4126a40e 100644 --- a/lib/meilisearch/rails/multi_search.rb +++ b/lib/meilisearch/rails/multi_search.rb @@ -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 diff --git a/lib/meilisearch/rails/multi_search/result.rb b/lib/meilisearch/rails/multi_search/result.rb index 72d9fb44..593856ab 100644 --- a/lib/meilisearch/rails/multi_search/result.rb +++ b/lib/meilisearch/rails/multi_search/result.rb @@ -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 diff --git a/spec/multi_search/result_spec.rb b/spec/multi_search/result_spec.rb index ff63dc11..99c35a0f 100644 --- a/spec/multi_search/result_spec.rb +++ b/spec/multi_search/result_spec.rb @@ -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 diff --git a/spec/multi_search_spec.rb b/spec/multi_search_spec.rb index 2090692e..552bf76d 100644 --- a/spec/multi_search_spec.rb +++ b/spec/multi_search_spec.rb @@ -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' } @@ -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