diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index efcf98a4..87438e7b 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -655,3 +655,21 @@ reset_search_cutoff_1: |- client.index('movies').reset_search_cutoff_ms get_similar_post_1: |- client.index('INDEX_NAME').search_similar_documents('TARGET_DOCUMENT_ID') +search_parameter_reference_ranking_score_threshold_1: |- + client.index('INDEX_NAME').search('badman', { + rankingScoreThreshold: 0.2 + }) +search_parameter_reference_distinct_1: |- + client.index('INDEX_NAME').search('QUERY TERMS', { + distinct: 'ATTRIBUTE_A' + }) +distinct_attribute_guide_filterable_1: |- + client.index('products').update_filterable_attributes([ + 'product_id', + 'sku', + 'url' + ]) +distinct_attribute_guide_distinct_parameter_1: |- + client.index('products').search('white shirt', { + distinct: 'sku' + }) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1e4b6a07..dd4fa883 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,7 +19,7 @@ jobs: matrix: ruby-version: ['3.1', '3.2', '3.3'] name: integration-tests (ruby ${{ matrix.ruby-version }}) - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Ruby ${{ matrix.ruby-version }} diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 5a5b9cff..7e33d7b1 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2024-06-01 14:58:01 UTC using RuboCop version 1.63.5. +# on 2024-09-10 01:25:16 UTC using RuboCop version 1.65.1. # 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 diff --git a/Gemfile b/Gemfile index 5d069e5e..2487b1d9 100644 --- a/Gemfile +++ b/Gemfile @@ -18,5 +18,5 @@ group :development, :test do end group :development do - gem 'rubocop', '~> 1.64.1', require: false + gem 'rubocop', '~> 1.66.0', require: false end diff --git a/docker-compose.yml b/docker-compose.yml index 091047f5..1c94bad7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ volumes: services: package: - image: ruby:3.0 + image: ruby:3.3 tty: true stdin_open: true working_dir: /home/package diff --git a/lib/meilisearch.rb b/lib/meilisearch.rb index f7a58e49..e72bb54a 100644 --- a/lib/meilisearch.rb +++ b/lib/meilisearch.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'json' + require 'meilisearch/version' require 'meilisearch/utils' require 'meilisearch/models/task' diff --git a/lib/meilisearch/error.rb b/lib/meilisearch/error.rb index 01420f09..02a1f40e 100644 --- a/lib/meilisearch/error.rb +++ b/lib/meilisearch/error.rb @@ -70,6 +70,15 @@ def initialize(message = nil) end end + class InvalidDocumentId < Error + attr_reader :message + + def initialize(message = nil) + @message = "The document id is invalid. #{message}" + super(@message) + end + end + module TenantToken class ExpireOrInvalidSignature < MeiliSearch::Error; end class InvalidApiKey < MeiliSearch::Error; end diff --git a/lib/meilisearch/index.rb b/lib/meilisearch/index.rb index 6c6a7643..96b45bea 100644 --- a/lib/meilisearch/index.rb +++ b/lib/meilisearch/index.rb @@ -220,6 +220,10 @@ def delete_documents!(documents_ids) alias delete_multiple_documents! delete_documents! def delete_document(document_id) + if document_id.nil? || document_id.to_s.empty? + raise MeiliSearch::InvalidDocumentId, 'document_id cannot be empty or nil' + end + encode_document = URI.encode_www_form_component(document_id) response = http_delete "/indexes/#{@uid}/documents/#{encode_document}" diff --git a/lib/meilisearch/version.rb b/lib/meilisearch/version.rb index 7291b5c4..af2165b0 100644 --- a/lib/meilisearch/version.rb +++ b/lib/meilisearch/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module MeiliSearch - VERSION = '0.28.0' + VERSION = '0.28.3' def self.qualified_version "Meilisearch Ruby (v#{VERSION})" diff --git a/meilisearch.gemspec b/meilisearch.gemspec index 3fa62de9..6fb3e896 100644 --- a/meilisearch.gemspec +++ b/meilisearch.gemspec @@ -15,6 +15,6 @@ Gem::Specification.new do |s| s.files = Dir['{lib}/**/*', 'LICENSE', 'README.md'] s.required_ruby_version = '>= 3.0.0' - s.add_dependency 'httparty', '~> 0.17.1' + s.add_dependency 'httparty', '~> 0.17' s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/spec/meilisearch/client/errors_spec.rb b/spec/meilisearch/client/errors_spec.rb index 10843cf4..1c010c68 100644 --- a/spec/meilisearch/client/errors_spec.rb +++ b/spec/meilisearch/client/errors_spec.rb @@ -33,4 +33,12 @@ end.to raise_error(MeiliSearch::CommunicationError) end end + + context 'when document id is invalid' do + it 'raises MeiliSearch::InvalidDocumentId' do + expect do + client.index('movies').delete_document(nil) + end.to raise_error(MeiliSearch::InvalidDocumentId) + end + end end diff --git a/spec/meilisearch/index/documents_spec.rb b/spec/meilisearch/index/documents_spec.rb index b1984f78..d54d5a5f 100644 --- a/spec/meilisearch/index/documents_spec.rb +++ b/spec/meilisearch/index/documents_spec.rb @@ -393,6 +393,10 @@ describe '#delete_document' do before { index.add_documents(documents).await } + it 'if the document id is nil, it raises an error' do + expect { index.delete_document(nil) }.to raise_error(MeiliSearch::InvalidDocumentId) + end + it 'deletes one document from index' do id = 456 index.delete_document(id).await diff --git a/spec/meilisearch/index/search/attributes_to_highlight_spec.rb b/spec/meilisearch/index/search/attributes_to_highlight_spec.rb index 498f7cf6..d9df5b0a 100644 --- a/spec/meilisearch/index/search/attributes_to_highlight_spec.rb +++ b/spec/meilisearch/index/search/attributes_to_highlight_spec.rb @@ -7,7 +7,7 @@ response = index.search('the', attributes_to_highlight: ['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'].count).to eq(4) expect(response['hits'].first).to have_key('_formatted') expect(response['hits'].first['_formatted']['title']).to eq('The Hobbit') end @@ -16,7 +16,7 @@ response = index.search('', attributes_to_highlight: ['*']) expect(response).to be_a(Hash) expect(response.keys).to contain_exactly(*DEFAULT_SEARCH_RESPONSE_KEYS) - expect(response['hits'].count).to eq(7) + expect(response['hits'].count).to eq(8) expect(response['hits'].first).to have_key('_formatted') end diff --git a/spec/meilisearch/index/search/attributes_to_retrieve_spec.rb b/spec/meilisearch/index/search/attributes_to_retrieve_spec.rb index ee7d6422..d82e455b 100644 --- a/spec/meilisearch/index/search/attributes_to_retrieve_spec.rb +++ b/spec/meilisearch/index/search/attributes_to_retrieve_spec.rb @@ -7,7 +7,7 @@ response = index.search('the', attributes_to_retrieve: ['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'].count).to eq(4) 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') @@ -17,7 +17,7 @@ response = index.search('the', attributes_to_retrieve: ['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'].count).to eq(4) 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') @@ -27,7 +27,7 @@ response = index.search('the', attributes_to_retrieve: ['*']) 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'].count).to eq(4) expect(response['hits'].first).to have_key('objectId') expect(response['hits'].first).to have_key('title') expect(response['hits'].first).to have_key('genre') diff --git a/spec/meilisearch/index/search/distinct_spec.rb b/spec/meilisearch/index/search/distinct_spec.rb new file mode 100644 index 00000000..d6d0dabd --- /dev/null +++ b/spec/meilisearch/index/search/distinct_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +RSpec.describe 'MeiliSearch::Index - Distinct search' do + include_context 'search books with genre' + + before do + index.update_filterable_attributes(['genre']).await + end + + it 'does a search without distinct' do + response = index.search('harry potter') + expect(response['hits'].count).to eq(2) + end + + it 'does a custom search with distinct' do + response = index.search('harry potter', { distinct: 'genre' }) + expect(response['hits'].count).to eq(1) + end +end diff --git a/spec/meilisearch/index/search/q_spec.rb b/spec/meilisearch/index/search/q_spec.rb index d018e8be..7b17cbc1 100644 --- a/spec/meilisearch/index/search/q_spec.rb +++ b/spec/meilisearch/index/search/q_spec.rb @@ -64,7 +64,7 @@ response = index.search('coco "harry"') expect(response).to be_a(Hash) expect(response.keys).to contain_exactly(*DEFAULT_SEARCH_RESPONSE_KEYS) - expect(response['hits'].count).to eq(1) + expect(response['hits'].count).to eq(2) expect(response['hits'].first['objectId']).to eq(4) expect(response['hits'].first).not_to have_key('_formatted') end diff --git a/spec/meilisearch/index/search/ranking_score_threshold_spec.rb b/spec/meilisearch/index/search/ranking_score_threshold_spec.rb new file mode 100644 index 00000000..7d25e94f --- /dev/null +++ b/spec/meilisearch/index/search/ranking_score_threshold_spec.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +RSpec.describe 'MeiliSearch::Index - Search with rankingScoreThreshold' do + include_context 'search books with genre' + + it 'does a custom search with rankingScoreThreshold' do + response = index.search('harry potter and the prisoner of azkaban', { rankingScoreThreshold: 0.9 }) + expect(response['hits'].count).to be(0) + + response = index.search('harry potter and the', { rankingScoreThreshold: 0.3 }) + expect(response['hits'].count).to be(2) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 346e72a5..18170866 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -37,6 +37,7 @@ require 'meilisearch' require 'byebug' +require 'time' # Globals for all tests URL = format('http://%s:%s', diff --git a/spec/support/books_contexts.rb b/spec/support/books_contexts.rb index 83e40d2c..8d1a886e 100644 --- a/spec/support/books_contexts.rb +++ b/spec/support/books_contexts.rb @@ -4,12 +4,13 @@ let(:index) { client.index('books') } let(:documents) do [ - { 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: 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: 7, title: 'Harry Potter and the Chamber of Secrets', genre: 'fantasy' }, { objectId: 42, title: 'The Hitchhiker\'s Guide to the Galaxy' } ] end