diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 48cbbbd9..afa09c4c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2020-06-04 09:43:58 +0200 using RuboCop version 0.85.0. +# on 2020-06-04 16:06:38 +0200 using RuboCop version 0.85.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -15,7 +15,7 @@ Metrics/BlockLength: # Offense count: 1 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 181 + Max: 190 # Offense count: 2 # Configuration parameters: CountComments, ExcludedMethods. diff --git a/README.md b/README.md index aa338cc6..1f3aa5ba 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,12 @@ To launch a specific folder or file: $ bundle exec rspec spec/meilisearch/index/base_spec.rb ``` +To launch a single test in a specific file: + +```bash +$ bundle exec rspec spec/meilisearch/index/search_spec.rb -e 'does a basic search in index' +``` + ### Linter Each PR should pass the linter to be accepted. diff --git a/lib/meilisearch/index.rb b/lib/meilisearch/index.rb index 7075cbba..1be3594d 100644 --- a/lib/meilisearch/index.rb +++ b/lib/meilisearch/index.rb @@ -81,7 +81,16 @@ def delete_all_documents ### SEARCH def search(query, options = {}) - http_get "/indexes/#{@uid}/search", { q: query }.merge(options) + parsed_options = options.transform_keys(&:to_sym).map do |k, v| + if [:facetFilters, :facetsDistribution].include?(k) + [k, v.inspect] + elsif v.is_a?(Array) + [k, v.join(',')] + else + [k, v] + end + end.to_h + http_get "/indexes/#{@uid}/search", { q: query }.merge(parsed_options) end ### UPDATES diff --git a/spec/meilisearch/index/search_spec.rb b/spec/meilisearch/index/search_spec.rb index 74a4c628..1e93fe5b 100644 --- a/spec/meilisearch/index/search_spec.rb +++ b/spec/meilisearch/index/search_spec.rb @@ -3,11 +3,12 @@ RSpec.describe 'MeiliSearch::Index - Search' do before(:all) do documents = [ - { objectId: 123, title: 'Pride and Prejudice' }, - { objectId: 456, title: 'Le Petit Prince' }, - { objectId: 1, title: 'Alice In Wonderland' }, - { objectId: 1344, title: 'The Hobbit' }, - { objectId: 4, title: 'Harry Potter and the Half-Blood Prince' }, + { objectId: 123, title: 'Pride and Prejudice', genre: 'romance' }, + { objectId: 456, title: 'Le Petit Prince', genre: 'adventure' }, + { objectId: 1, title: 'Alice In Wonderland', genre: 'adventure' }, + { objectId: 2, title: 'Le Rouge et le Noir', genre: 'romance' }, + { objectId: 1344, title: 'The Hobbit', genre: 'adventure' }, + { objectId: 4, title: 'Harry Potter and the Half-Blood Prince', genre: 'fantasy' }, { objectId: 42, title: 'The Hitchhiker\'s Guide to the Galaxy' } ] client = MeiliSearch::Client.new($URL, $MASTER_KEY) @@ -21,10 +22,22 @@ @index.delete end + let(:default_search_response_keys) do + [ + 'hits', + 'offset', + 'limit', + 'nbHits', + 'exhaustiveNbHits', + 'processingTimeMs', + 'query' + ] + end + it 'does a basic search in index' do response = @index.search('prince') expect(response).to be_a(Hash) - expect(response).to have_key('hits') + expect(response.keys).to contain_exactly(*default_search_response_keys) expect(response['hits']).not_to be_empty expect(response['hits'].first).not_to have_key('_formatted') end @@ -32,7 +45,7 @@ it 'does a custom search with limit' do response = @index.search('the', limit: 1) expect(response).to be_a(Hash) - expect(response).to have_key('hits') + expect(response.keys).to contain_exactly(*default_search_response_keys) expect(response['hits'].count).to eq(1) expect(response['hits'].first).not_to have_key('_formatted') end @@ -40,8 +53,55 @@ it 'does a custom search with highlight' do response = @index.search('the', attributesToHighlight: '*') expect(response).to be_a(Hash) - expect(response).to have_key('hits') + expect(response.keys).to contain_exactly(*default_search_response_keys) expect(response['hits'].count).to eq(3) expect(response['hits'].first).to have_key('_formatted') end + + it 'does a custom search with attributesToRetrieve as string' do + response = @index.search('the', attributesToRetrieve: 'title') + expect(response).to be_a(Hash) + expect(response.keys).to contain_exactly(*default_search_response_keys) + expect(response['hits'].count).to eq(3) + expect(response['hits'].first).to have_key('title') + expect(response['hits'].first).not_to have_key('objectId') + expect(response['hits'].first).not_to have_key('genre') + end + + it 'does a custom search with attributesToRetrieve as an array of string' do + response = @index.search('the', attributesToRetrieve: ['title', 'genre']) + expect(response).to be_a(Hash) + expect(response.keys).to contain_exactly(*default_search_response_keys) + expect(response['hits'].count).to eq(3) + expect(response['hits'].first).to have_key('title') + expect(response['hits'].first).not_to have_key('objectId') + expect(response['hits'].first).to have_key('genre') + end + + it 'does a custom search with facetsDistribution' do + @index.update_attributes_for_faceting(['genre']) + sleep(0.1) + response = @index.search('prinec', facetsDistribution: ['genre']) + expect(response.keys).to contain_exactly( + *default_search_response_keys, + 'facetsDistribution', + 'exhaustiveFacetsCount' + ) + expect(response['exhaustiveFacetsCount']).to be true + expect(response['nbHits']).to eq(2) + expect(response['facetsDistribution'].keys).to contain_exactly('genre') + expect(response['facetsDistribution']['genre'].keys).to contain_exactly('romance', 'adventure', 'fantasy') + expect(response['facetsDistribution']['genre']['romance']).to eq(0) + expect(response['facetsDistribution']['genre']['adventure']).to eq(1) + expect(response['facetsDistribution']['genre']['fantasy']).to eq(1) + end + + it 'does a custom search with facetFilters' do + @index.update_attributes_for_faceting(['genre']) + sleep(0.1) + response = @index.search('prinec', facetFilters: ['genre: fantasy']) + expect(response.keys).to contain_exactly(*default_search_response_keys) + expect(response['nbHits']).to eq(1) + expect(response['hits'][0]['objectId']).to eq(4) + end end