From 2bc2e99ff3799604769468b65ec7356ba249a3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Lecrenier?= Date: Wed, 11 Jan 2023 12:33:45 +0100 Subject: [PATCH] Simplify declaration of the error codes --- dump/src/reader/compat/v5_to_v6.rs | 14 +- index-scheduler/src/error.rs | 8 +- meilisearch-types/src/error.rs | 602 ++++++++--------------------- 3 files changed, 177 insertions(+), 447 deletions(-) diff --git a/dump/src/reader/compat/v5_to_v6.rs b/dump/src/reader/compat/v5_to_v6.rs index 0216d490e..5039625ef 100644 --- a/dump/src/reader/compat/v5_to_v6.rs +++ b/dump/src/reader/compat/v5_to_v6.rs @@ -254,14 +254,14 @@ impl From> for v6::Setting { impl From for v6::ResponseError { fn from(error: v5::ResponseError) -> Self { let code = match error.error_code.as_ref() { - "index_creation_failed" => v6::Code::CreateIndex, + "index_creation_failed" => v6::Code::IndexCreationFailed, "index_already_exists" => v6::Code::IndexAlreadyExists, "index_not_found" => v6::Code::IndexNotFound, "invalid_index_uid" => v6::Code::InvalidIndexUid, "invalid_min_word_length_for_typo" => v6::Code::InvalidMinWordLengthForTypo, "invalid_state" => v6::Code::InvalidState, - "primary_key_inference_failed" => v6::Code::NoPrimaryKeyCandidateFound, - "index_primary_key_already_exists" => v6::Code::PrimaryKeyAlreadyPresent, + "primary_key_inference_failed" => v6::Code::IndexPrimaryKeyNoCandidateFound, + "index_primary_key_already_exists" => v6::Code::IndexPrimaryKeyAlreadyExists, "max_fields_limit_exceeded" => v6::Code::MaxFieldsLimitExceeded, "missing_document_id" => v6::Code::MissingDocumentId, "invalid_document_id" => v6::Code::InvalidDocumentId, @@ -274,16 +274,16 @@ impl From for v6::ResponseError { "internal" => v6::Code::Internal, "invalid_geo_field" => v6::Code::InvalidDocumentGeoField, "invalid_ranking_rule" => v6::Code::InvalidSettingsRankingRules, - "invalid_store_file" => v6::Code::InvalidStore, - "invalid_api_key" => v6::Code::InvalidToken, + "invalid_store_file" => v6::Code::InvalidStoreFile, + "invalid_api_key" => v6::Code::InvalidApiKey, "missing_authorization_header" => v6::Code::MissingAuthorizationHeader, "no_space_left_on_device" => v6::Code::NoSpaceLeftOnDevice, "dump_not_found" => v6::Code::DumpNotFound, "task_not_found" => v6::Code::TaskNotFound, "payload_too_large" => v6::Code::PayloadTooLarge, - "unretrievable_document" => v6::Code::DocumentNotFound, + "unretrievable_document" => v6::Code::UnretrievableDocument, "unsupported_media_type" => v6::Code::UnsupportedMediaType, - "dump_already_processing" => v6::Code::DumpAlreadyInProgress, + "dump_already_processing" => v6::Code::DumpAlreadyProcessing, "dump_process_failed" => v6::Code::DumpProcessFailed, "invalid_content_type" => v6::Code::InvalidContentType, "missing_content_type" => v6::Code::MissingContentType, diff --git a/index-scheduler/src/error.rs b/index-scheduler/src/error.rs index 0be6e4e32..013bcf595 100644 --- a/index-scheduler/src/error.rs +++ b/index-scheduler/src/error.rs @@ -139,8 +139,8 @@ impl ErrorCode for Error { match self { Error::IndexNotFound(_) => Code::IndexNotFound, Error::IndexAlreadyExists(_) => Code::IndexAlreadyExists, - Error::SwapDuplicateIndexesFound(_) => Code::InvalidDuplicateIndexesFound, - Error::SwapDuplicateIndexFound(_) => Code::InvalidDuplicateIndexesFound, + Error::SwapDuplicateIndexesFound(_) => Code::InvalidSwapDuplicateIndexFound, + Error::SwapDuplicateIndexFound(_) => Code::InvalidSwapDuplicateIndexFound, Error::SwapIndexNotFound(_) => Code::InvalidSwapIndexes, Error::SwapIndexesNotFound(_) => Code::InvalidSwapIndexes, Error::InvalidTaskDate { field, .. } => (*field).into(), @@ -150,8 +150,8 @@ impl ErrorCode for Error { Error::InvalidTaskCanceledBy { .. } => Code::InvalidTaskCanceledBy, Error::InvalidIndexUid { .. } => Code::InvalidIndexUid, Error::TaskNotFound(_) => Code::TaskNotFound, - Error::TaskDeletionWithEmptyQuery => Code::TaskDeletionWithEmptyQuery, - Error::TaskCancelationWithEmptyQuery => Code::TaskCancelationWithEmptyQuery, + Error::TaskDeletionWithEmptyQuery => Code::MissingTaskFilters, + Error::TaskCancelationWithEmptyQuery => Code::MissingTaskFilters, Error::Dump(e) => e.error_code(), Error::Milli(e) => e.error_code(), Error::ProcessBatchPanicked => Code::Internal, diff --git a/meilisearch-types/src/error.rs b/meilisearch-types/src/error.rs index ced817cb7..32552df47 100644 --- a/meilisearch-types/src/error.rs +++ b/meilisearch-types/src/error.rs @@ -1,9 +1,12 @@ +use std::convert::Infallible; +use std::marker::PhantomData; use std::{fmt, io}; use actix_web::http::StatusCode; use actix_web::{self as aweb, HttpResponseBuilder}; use aweb::rt::task::JoinError; use convert_case::Casing; +use deserr::{DeserializeError, IntoValue, MergeWithError, ValuePointerRef}; use milli::heed::{Error as HeedError, MdbError}; use serde::{Deserialize, Serialize}; @@ -31,7 +34,7 @@ impl ResponseError { Self { code: code.http(), message, - error_code: code.err_code().error_name.to_string(), + error_code: code.err_code().error_name, error_type: code.type_(), error_link: code.url(), } @@ -48,7 +51,7 @@ impl std::error::Error for ResponseError {} impl From for ResponseError where - T: ErrorCode, + T: std::error::Error + ErrorCode, { fn from(other: T) -> Self { Self::from_msg(other.to_string(), other.error_code()) @@ -66,7 +69,7 @@ impl aweb::error::ResponseError for ResponseError { } } -pub trait ErrorCode: std::error::Error { +pub trait ErrorCode { fn error_code(&self) -> Code; /// returns the HTTP status code associated with the error @@ -111,461 +114,188 @@ impl fmt::Display for ErrorType { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Code { - // error related to your setup - IoError, - NoSpaceLeftOnDevice, - TooManyOpenFiles, - - // index related error - CreateIndex, - IndexAlreadyExists, - InvalidIndexPrimaryKey, - IndexNotFound, - InvalidIndexUid, - MissingIndexUid, - InvalidMinWordLengthForTypo, - InvalidIndexLimit, - InvalidIndexOffset, - - DuplicateIndexFound, - - // invalid state error - InvalidState, - NoPrimaryKeyCandidateFound, - MultiplePrimaryKeyCandidatesFound, - PrimaryKeyAlreadyPresent, - - MaxFieldsLimitExceeded, - MissingDocumentId, - InvalidDocumentId, - - // Invalid swap-indexes - InvalidSwapIndexes, - InvalidDuplicateIndexesFound, - - // Invalid settings update request - InvalidSettingsDisplayedAttributes, - InvalidSettingsSearchableAttributes, - InvalidSettingsFilterableAttributes, - InvalidSettingsSortableAttributes, - InvalidSettingsRankingRules, - InvalidSettingsStopWords, - InvalidSettingsSynonyms, - InvalidSettingsDistinctAttribute, - InvalidSettingsTypoTolerance, - InvalidSettingsFaceting, - InvalidSettingsPagination, - - // Invalid search request - InvalidSearchQ, - InvalidSearchOffset, - InvalidSearchLimit, - InvalidSearchPage, - InvalidSearchHitsPerPage, - InvalidSearchAttributesToRetrieve, - InvalidSearchAttributesToCrop, - InvalidSearchCropLength, - InvalidSearchAttributesToHighlight, - InvalidSearchShowMatchesPosition, - InvalidSearchFilter, - InvalidSearchSort, - InvalidSearchFacets, - InvalidSearchHighlightPreTag, - InvalidSearchHighlightPostTag, - InvalidSearchCropMarker, - InvalidSearchMatchingStrategy, - - // Related to the tasks - InvalidTaskUids, - InvalidTaskTypes, - InvalidTaskStatuses, - InvalidTaskCanceledBy, - InvalidTaskLimit, - InvalidTaskFrom, - InvalidTaskBeforeEnqueuedAt, - InvalidTaskAfterEnqueuedAt, - InvalidTaskBeforeStartedAt, - InvalidTaskAfterStartedAt, - InvalidTaskBeforeFinishedAt, - InvalidTaskAfterFinishedAt, - - // Documents API - InvalidDocumentFields, - InvalidDocumentLimit, - InvalidDocumentOffset, - - BadParameter, - BadRequest, - DatabaseSizeLimitReached, - DocumentNotFound, - Internal, - InvalidDocumentGeoField, - InvalidStore, - InvalidToken, - MissingAuthorizationHeader, - MissingMasterKey, - DumpNotFound, - TaskNotFound, - TaskDeletionWithEmptyQuery, - TaskCancelationWithEmptyQuery, - PayloadTooLarge, - UnsupportedMediaType, - - DumpAlreadyInProgress, - DumpProcessFailed, - // Only used when importing a dump - UnretrievableErrorCode, - - InvalidContentType, - MissingContentType, - MalformedPayload, - MissingPayload, - - ApiKeyNotFound, - - MissingApiKeyActions, - MissingApiKeyExpiresAt, - MissingApiKeyIndexes, - - InvalidApiKeyOffset, - InvalidApiKeyLimit, - InvalidApiKeyActions, - InvalidApiKeyIndexes, - InvalidApiKeyExpiresAt, - InvalidApiKeyDescription, - InvalidApiKeyName, - InvalidApiKeyUid, - ImmutableField, - ApiKeyAlreadyExists, -} - -impl Code { - /// associate a `Code` variant to the actual ErrCode - fn err_code(&self) -> ErrCode { - use Code::*; - - match self { - // related to the setup - IoError => ErrCode::system("io_error", StatusCode::INTERNAL_SERVER_ERROR), - TooManyOpenFiles => { - ErrCode::system("too_many_open_files", StatusCode::INTERNAL_SERVER_ERROR) +macro_rules! make_error_codes { + ($($code_ident:ident, $err_type:ident, $status:ident);*) => { + #[repr(u32)] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub enum Code { + $($code_ident),* + } + impl Code { + /// associate a `Code` variant to the actual ErrCode + fn err_code(&self) -> ErrCode { + match self { + $( + Code::$code_ident => { + ErrCode::$err_type( stringify!($code_ident).to_case(convert_case::Case::Snake), StatusCode::$status) + } + )* + } } - NoSpaceLeftOnDevice => { - ErrCode::system("no_space_left_on_device", StatusCode::INTERNAL_SERVER_ERROR) + /// return the HTTP status code associated with the `Code` + fn http(&self) -> StatusCode { + self.err_code().status_code } - // index related errors - // create index is thrown on internal error while creating an index. - CreateIndex => { - ErrCode::internal("index_creation_failed", StatusCode::INTERNAL_SERVER_ERROR) - } - IndexAlreadyExists => ErrCode::invalid("index_already_exists", StatusCode::CONFLICT), - // thrown when requesting an unexisting index - IndexNotFound => ErrCode::invalid("index_not_found", StatusCode::NOT_FOUND), - InvalidIndexUid => ErrCode::invalid("invalid_index_uid", StatusCode::BAD_REQUEST), - MissingIndexUid => ErrCode::invalid("missing_index_uid", StatusCode::BAD_REQUEST), - InvalidIndexPrimaryKey => { - ErrCode::invalid("invalid_index_primary_key", StatusCode::BAD_REQUEST) - } - InvalidIndexLimit => ErrCode::invalid("invalid_index_limit", StatusCode::BAD_REQUEST), - InvalidIndexOffset => ErrCode::invalid("invalid_index_offset", StatusCode::BAD_REQUEST), - - // invalid state error - InvalidState => ErrCode::internal("invalid_state", StatusCode::INTERNAL_SERVER_ERROR), - // thrown when no primary key has been set - NoPrimaryKeyCandidateFound => { - ErrCode::invalid("index_primary_key_no_candidate_found", StatusCode::BAD_REQUEST) - } - MultiplePrimaryKeyCandidatesFound => ErrCode::invalid( - "index_primary_key_multiple_candidates_found", - StatusCode::BAD_REQUEST, - ), - // error thrown when trying to set an already existing primary key - PrimaryKeyAlreadyPresent => { - ErrCode::invalid("index_primary_key_already_exists", StatusCode::BAD_REQUEST) + /// return error name, used as error code + fn name(&self) -> String { + self.err_code().error_name.to_string() } - // invalid database - InvalidStore => { - ErrCode::internal("invalid_store_file", StatusCode::INTERNAL_SERVER_ERROR) + /// return the error type + fn type_(&self) -> String { + self.err_code().error_type.to_string() } - // invalid document - MaxFieldsLimitExceeded => { - ErrCode::invalid("max_fields_limit_exceeded", StatusCode::BAD_REQUEST) - } - MissingDocumentId => ErrCode::invalid("missing_document_id", StatusCode::BAD_REQUEST), - InvalidDocumentId => ErrCode::invalid("invalid_document_id", StatusCode::BAD_REQUEST), - - BadParameter => ErrCode::invalid("bad_parameter", StatusCode::BAD_REQUEST), - BadRequest => ErrCode::invalid("bad_request", StatusCode::BAD_REQUEST), - DatabaseSizeLimitReached => { - ErrCode::internal("database_size_limit_reached", StatusCode::INTERNAL_SERVER_ERROR) - } - DocumentNotFound => ErrCode::invalid("document_not_found", StatusCode::NOT_FOUND), - Internal => ErrCode::internal("internal", StatusCode::INTERNAL_SERVER_ERROR), - InvalidDocumentGeoField => { - ErrCode::invalid("invalid_document_geo_field", StatusCode::BAD_REQUEST) - } - InvalidToken => ErrCode::authentication("invalid_api_key", StatusCode::FORBIDDEN), - MissingAuthorizationHeader => { - ErrCode::authentication("missing_authorization_header", StatusCode::UNAUTHORIZED) - } - MissingMasterKey => { - ErrCode::authentication("missing_master_key", StatusCode::UNAUTHORIZED) - } - TaskNotFound => ErrCode::invalid("task_not_found", StatusCode::NOT_FOUND), - TaskDeletionWithEmptyQuery => { - ErrCode::invalid("missing_task_filters", StatusCode::BAD_REQUEST) - } - TaskCancelationWithEmptyQuery => { - ErrCode::invalid("missing_task_filters", StatusCode::BAD_REQUEST) - } - DumpNotFound => ErrCode::invalid("dump_not_found", StatusCode::NOT_FOUND), - PayloadTooLarge => ErrCode::invalid("payload_too_large", StatusCode::PAYLOAD_TOO_LARGE), - UnsupportedMediaType => { - ErrCode::invalid("unsupported_media_type", StatusCode::UNSUPPORTED_MEDIA_TYPE) - } - - // error related to dump - DumpAlreadyInProgress => { - ErrCode::invalid("dump_already_processing", StatusCode::CONFLICT) - } - DumpProcessFailed => { - ErrCode::internal("dump_process_failed", StatusCode::INTERNAL_SERVER_ERROR) - } - MissingContentType => { - ErrCode::invalid("missing_content_type", StatusCode::UNSUPPORTED_MEDIA_TYPE) - } - MalformedPayload => ErrCode::invalid("malformed_payload", StatusCode::BAD_REQUEST), - InvalidContentType => { - ErrCode::invalid("invalid_content_type", StatusCode::UNSUPPORTED_MEDIA_TYPE) - } - MissingPayload => ErrCode::invalid("missing_payload", StatusCode::BAD_REQUEST), - // This one can only happen when importing a dump and encountering an unknown code in the task queue. - UnretrievableErrorCode => { - ErrCode::invalid("unretrievable_error_code", StatusCode::BAD_REQUEST) - } - - // error related to keys - ApiKeyNotFound => ErrCode::invalid("api_key_not_found", StatusCode::NOT_FOUND), - - MissingApiKeyExpiresAt => { - ErrCode::invalid("missing_api_key_expires_at", StatusCode::BAD_REQUEST) - } - - MissingApiKeyActions => { - ErrCode::invalid("missing_api_key_actions", StatusCode::BAD_REQUEST) - } - - MissingApiKeyIndexes => { - ErrCode::invalid("missing_api_key_indexes", StatusCode::BAD_REQUEST) - } - - InvalidApiKeyOffset => { - ErrCode::invalid("invalid_api_key_offset", StatusCode::BAD_REQUEST) - } - InvalidApiKeyLimit => { - ErrCode::invalid("invalid_api_key_limit", StatusCode::BAD_REQUEST) - } - InvalidApiKeyActions => { - ErrCode::invalid("invalid_api_key_actions", StatusCode::BAD_REQUEST) - } - InvalidApiKeyIndexes => { - ErrCode::invalid("invalid_api_key_indexes", StatusCode::BAD_REQUEST) - } - InvalidApiKeyExpiresAt => { - ErrCode::invalid("invalid_api_key_expires_at", StatusCode::BAD_REQUEST) - } - InvalidApiKeyDescription => { - ErrCode::invalid("invalid_api_key_description", StatusCode::BAD_REQUEST) - } - InvalidApiKeyName => ErrCode::invalid("invalid_api_key_name", StatusCode::BAD_REQUEST), - InvalidApiKeyUid => ErrCode::invalid("invalid_api_key_uid", StatusCode::BAD_REQUEST), - ApiKeyAlreadyExists => ErrCode::invalid("api_key_already_exists", StatusCode::CONFLICT), - ImmutableField => ErrCode::invalid("immutable_field", StatusCode::BAD_REQUEST), - InvalidMinWordLengthForTypo => { - ErrCode::invalid("invalid_min_word_length_for_typo", StatusCode::BAD_REQUEST) - } - DuplicateIndexFound => { - ErrCode::invalid("duplicate_index_found", StatusCode::BAD_REQUEST) - } - - // Swap indexes error - InvalidSwapIndexes => ErrCode::invalid("invalid_swap_indexes", StatusCode::BAD_REQUEST), - InvalidDuplicateIndexesFound => { - ErrCode::invalid("invalid_swap_duplicate_index_found", StatusCode::BAD_REQUEST) - } - - // Invalid settings - InvalidSettingsDisplayedAttributes => { - ErrCode::invalid("invalid_settings_displayed_attributes", StatusCode::BAD_REQUEST) - } - InvalidSettingsSearchableAttributes => { - ErrCode::invalid("invalid_settings_searchable_attributes", StatusCode::BAD_REQUEST) - } - InvalidSettingsFilterableAttributes => { - ErrCode::invalid("invalid_settings_filterable_attributes", StatusCode::BAD_REQUEST) - } - InvalidSettingsSortableAttributes => { - ErrCode::invalid("invalid_settings_sortable_attributes", StatusCode::BAD_REQUEST) - } - InvalidSettingsRankingRules => { - ErrCode::invalid("invalid_settings_ranking_rules", StatusCode::BAD_REQUEST) - } - InvalidSettingsStopWords => { - ErrCode::invalid("invalid_settings_stop_words", StatusCode::BAD_REQUEST) - } - InvalidSettingsSynonyms => { - ErrCode::invalid("invalid_settings_synonyms", StatusCode::BAD_REQUEST) - } - InvalidSettingsDistinctAttribute => { - ErrCode::invalid("invalid_settings_distinct_attribute", StatusCode::BAD_REQUEST) - } - InvalidSettingsTypoTolerance => { - ErrCode::invalid("invalid_settings_typo_tolerance", StatusCode::BAD_REQUEST) - } - InvalidSettingsFaceting => { - ErrCode::invalid("invalid_settings_faceting", StatusCode::BAD_REQUEST) - } - InvalidSettingsPagination => { - ErrCode::invalid("invalid_settings_pagination", StatusCode::BAD_REQUEST) - } - - // Invalid search - InvalidSearchQ => ErrCode::invalid("invalid_search_q", StatusCode::BAD_REQUEST), - InvalidSearchOffset => { - ErrCode::invalid("invalid_search_offset", StatusCode::BAD_REQUEST) - } - InvalidSearchLimit => ErrCode::invalid("invalid_search_limit", StatusCode::BAD_REQUEST), - InvalidSearchPage => ErrCode::invalid("invalid_search_page", StatusCode::BAD_REQUEST), - InvalidSearchHitsPerPage => { - ErrCode::invalid("invalid_search_hits_per_page", StatusCode::BAD_REQUEST) - } - InvalidSearchAttributesToRetrieve => { - ErrCode::invalid("invalid_search_attributes_to_retrieve", StatusCode::BAD_REQUEST) - } - InvalidSearchAttributesToCrop => { - ErrCode::invalid("invalid_search_attributes_to_crop", StatusCode::BAD_REQUEST) - } - InvalidSearchCropLength => { - ErrCode::invalid("invalid_search_crop_length", StatusCode::BAD_REQUEST) - } - InvalidSearchAttributesToHighlight => { - ErrCode::invalid("invalid_search_attributes_to_highlight", StatusCode::BAD_REQUEST) - } - InvalidSearchShowMatchesPosition => { - ErrCode::invalid("invalid_search_show_matches_position", StatusCode::BAD_REQUEST) - } - InvalidSearchFilter => { - ErrCode::invalid("invalid_search_filter", StatusCode::BAD_REQUEST) - } - InvalidSearchSort => ErrCode::invalid("invalid_search_sort", StatusCode::BAD_REQUEST), - InvalidSearchFacets => { - ErrCode::invalid("invalid_search_facets", StatusCode::BAD_REQUEST) - } - InvalidSearchHighlightPreTag => { - ErrCode::invalid("invalid_search_highlight_pre_tag", StatusCode::BAD_REQUEST) - } - InvalidSearchHighlightPostTag => { - ErrCode::invalid("invalid_search_highlight_post_tag", StatusCode::BAD_REQUEST) - } - InvalidSearchCropMarker => { - ErrCode::invalid("invalid_search_crop_marker", StatusCode::BAD_REQUEST) - } - InvalidSearchMatchingStrategy => { - ErrCode::invalid("invalid_search_matching_strategy", StatusCode::BAD_REQUEST) - } - - // Related to the tasks - InvalidTaskUids => ErrCode::invalid("invalid_task_uids", StatusCode::BAD_REQUEST), - InvalidTaskTypes => ErrCode::invalid("invalid_task_types", StatusCode::BAD_REQUEST), - InvalidTaskStatuses => { - ErrCode::invalid("invalid_task_statuses", StatusCode::BAD_REQUEST) - } - InvalidTaskCanceledBy => { - ErrCode::invalid("invalid_task_canceled_by", StatusCode::BAD_REQUEST) - } - InvalidTaskLimit => ErrCode::invalid("invalid_task_limit", StatusCode::BAD_REQUEST), - InvalidTaskFrom => ErrCode::invalid("invalid_task_from", StatusCode::BAD_REQUEST), - InvalidTaskBeforeEnqueuedAt => { - ErrCode::invalid("invalid_task_before_enqueued_at", StatusCode::BAD_REQUEST) - } - InvalidTaskAfterEnqueuedAt => { - ErrCode::invalid("invalid_task_after_enqueued_at", StatusCode::BAD_REQUEST) - } - InvalidTaskBeforeStartedAt => { - ErrCode::invalid("invalid_task_before_started_at", StatusCode::BAD_REQUEST) - } - InvalidTaskAfterStartedAt => { - ErrCode::invalid("invalid_task_after_started_at", StatusCode::BAD_REQUEST) - } - InvalidTaskBeforeFinishedAt => { - ErrCode::invalid("invalid_task_before_finished_at", StatusCode::BAD_REQUEST) - } - InvalidTaskAfterFinishedAt => { - ErrCode::invalid("invalid_task_after_finished_at", StatusCode::BAD_REQUEST) - } - - InvalidDocumentFields => { - ErrCode::invalid("invalid_document_fields", StatusCode::BAD_REQUEST) - } - InvalidDocumentLimit => { - ErrCode::invalid("invalid_document_limit", StatusCode::BAD_REQUEST) - } - InvalidDocumentOffset => { - ErrCode::invalid("invalid_document_offset", StatusCode::BAD_REQUEST) + /// return the doc url associated with the error + fn url(&self) -> String { + format!( + "https://docs.meilisearch.com/errors#{}", + self.name().to_case(convert_case::Case::Kebab) + ) } } + pub mod deserr_codes { + use super::{Code, ErrorCode}; + $( + #[derive(Default)] + pub struct $code_ident; + impl ErrorCode for $code_ident { + fn error_code(&self) -> Code { + Code::$code_ident + } + } + )* + } } - - /// return the HTTP status code associated with the `Code` - fn http(&self) -> StatusCode { - self.err_code().status_code - } - - /// return error name, used as error code - fn name(&self) -> String { - self.err_code().error_name.to_string() - } - - /// return the error type - fn type_(&self) -> String { - self.err_code().error_type.to_string() - } - - /// return the doc url associated with the error - fn url(&self) -> String { - format!( - "https://docs.meilisearch.com/errors#{}", - self.name().to_case(convert_case::Case::Kebab) - ) - } +} +make_error_codes! { +ApiKeyAlreadyExists , invalid , CONFLICT ; +ApiKeyNotFound , invalid , NOT_FOUND ; +BadParameter , invalid , BAD_REQUEST; +BadRequest , invalid , BAD_REQUEST; +DatabaseSizeLimitReached , internal , INTERNAL_SERVER_ERROR; +DocumentNotFound , invalid , NOT_FOUND; +DumpAlreadyProcessing , invalid , CONFLICT; +DumpNotFound , invalid , NOT_FOUND; +DumpProcessFailed , internal , INTERNAL_SERVER_ERROR; +DuplicateIndexFound , invalid , BAD_REQUEST; +ImmutableField , invalid , BAD_REQUEST; +IndexAlreadyExists , invalid , CONFLICT ; +IndexCreationFailed , internal , INTERNAL_SERVER_ERROR; +IndexNotFound , invalid , NOT_FOUND; +IndexPrimaryKeyAlreadyExists , invalid , BAD_REQUEST ; +IndexPrimaryKeyNoCandidateFound , invalid , BAD_REQUEST ; +IndexPrimaryKeyMultipleCandidatesFound, invalid , BAD_REQUEST; +Internal , internal , INTERNAL_SERVER_ERROR ; +InvalidApiKeyActions , invalid , BAD_REQUEST ; +InvalidApiKeyDescription , invalid , BAD_REQUEST ; +InvalidApiKeyExpiresAt , invalid , BAD_REQUEST ; +InvalidApiKeyIndexes , invalid , BAD_REQUEST ; +InvalidApiKeyLimit , invalid , BAD_REQUEST ; +InvalidApiKeyName , invalid , BAD_REQUEST ; +InvalidApiKeyOffset , invalid , BAD_REQUEST ; +InvalidApiKeyUid , invalid , BAD_REQUEST ; +InvalidApiKey , authentication, FORBIDDEN ; +InvalidContentType , invalid , UNSUPPORTED_MEDIA_TYPE ; +InvalidDocumentFields , invalid , BAD_REQUEST ; +InvalidDocumentGeoField , invalid , BAD_REQUEST ; +InvalidDocumentId , invalid , BAD_REQUEST ; +InvalidDocumentLimit , invalid , BAD_REQUEST ; +InvalidDocumentOffset , invalid , BAD_REQUEST ; +InvalidIndexLimit , invalid , BAD_REQUEST ; +InvalidIndexOffset , invalid , BAD_REQUEST ; +InvalidIndexPrimaryKey , invalid , BAD_REQUEST ; +InvalidIndexUid , invalid , BAD_REQUEST ; +InvalidMinWordLengthForTypo , invalid , BAD_REQUEST ; +InvalidRankingRule , invalid , BAD_REQUEST ; +InvalidSearchAttributesToCrop , invalid , BAD_REQUEST ; +InvalidSearchAttributesToHighlight , invalid , BAD_REQUEST ; +InvalidSearchAttributesToRetrieve , invalid , BAD_REQUEST ; +InvalidSearchCropLength , invalid , BAD_REQUEST ; +InvalidSearchCropMarker , invalid , BAD_REQUEST ; +InvalidSearchFacets , invalid , BAD_REQUEST ; +InvalidSearchFilter , invalid , BAD_REQUEST ; +InvalidSearchHighlightPostTag , invalid , BAD_REQUEST ; +InvalidSearchHighlightPreTag , invalid , BAD_REQUEST ; +InvalidSearchHitsPerPage , invalid , BAD_REQUEST ; +InvalidSearchLimit , invalid , BAD_REQUEST ; +InvalidSearchMatchingStrategy , invalid , BAD_REQUEST ; +InvalidSearchOffset , invalid , BAD_REQUEST ; +InvalidSearchPage , invalid , BAD_REQUEST ; +InvalidSearchQ , invalid , BAD_REQUEST ; +InvalidSearchShowMatchesPosition , invalid , BAD_REQUEST ; +InvalidSearchSort , invalid , BAD_REQUEST ; +InvalidSettingsDisplayedAttributes , invalid , BAD_REQUEST ; +InvalidSettingsDistinctAttribute , invalid , BAD_REQUEST ; +InvalidSettingsFaceting , invalid , BAD_REQUEST ; +InvalidSettingsFilterableAttributes , invalid , BAD_REQUEST ; +InvalidSettingsPagination , invalid , BAD_REQUEST ; +InvalidSettingsRankingRules , invalid , BAD_REQUEST ; +InvalidSettingsSearchableAttributes , invalid , BAD_REQUEST ; +InvalidSettingsSortableAttributes , invalid , BAD_REQUEST ; +InvalidSettingsStopWords , invalid , BAD_REQUEST ; +InvalidSettingsSynonyms , invalid , BAD_REQUEST ; +InvalidSettingsTypoTolerance , invalid , BAD_REQUEST ; +InvalidState , internal , INTERNAL_SERVER_ERROR ; +InvalidStoreFile , internal , INTERNAL_SERVER_ERROR ; +InvalidSwapDuplicateIndexFound , invalid , BAD_REQUEST ; +InvalidSwapIndexes , invalid , BAD_REQUEST ; +InvalidTaskAfterEnqueuedAt , invalid , BAD_REQUEST ; +InvalidTaskAfterFinishedAt , invalid , BAD_REQUEST ; +InvalidTaskAfterStartedAt , invalid , BAD_REQUEST ; +InvalidTaskBeforeEnqueuedAt , invalid , BAD_REQUEST ; +InvalidTaskBeforeFinishedAt , invalid , BAD_REQUEST ; +InvalidTaskBeforeStartedAt , invalid , BAD_REQUEST ; +InvalidTaskCanceledBy , invalid , BAD_REQUEST ; +InvalidTaskFrom , invalid , BAD_REQUEST ; +InvalidTaskLimit , invalid , BAD_REQUEST ; +InvalidTaskStatuses , invalid , BAD_REQUEST ; +InvalidTaskTypes , invalid , BAD_REQUEST ; +InvalidTaskUids , invalid , BAD_REQUEST ; +IoError , system , UNPROCESSABLE_ENTITY; +MalformedPayload , invalid , BAD_REQUEST ; +MaxFieldsLimitExceeded , invalid , BAD_REQUEST ; +MissingApiKeyActions , invalid , BAD_REQUEST ; +MissingApiKeyExpiresAt , invalid , BAD_REQUEST ; +MissingApiKeyIndexes , invalid , BAD_REQUEST ; +MissingAuthorizationHeader , authentication, UNAUTHORIZED ; +MissingContentType , invalid , UNSUPPORTED_MEDIA_TYPE ; +MissingDocumentId , invalid , BAD_REQUEST ; +MissingIndexUid , invalid , BAD_REQUEST ; +MissingMasterKey , authentication, UNAUTHORIZED ; +MissingPayload , invalid , BAD_REQUEST ; +MissingTaskFilters , invalid , BAD_REQUEST ; +NoSpaceLeftOnDevice , system , UNPROCESSABLE_ENTITY; +PayloadTooLarge , invalid , PAYLOAD_TOO_LARGE ; +TaskNotFound , invalid , NOT_FOUND ; +TooManyOpenFiles , system , UNPROCESSABLE_ENTITY ; +UnretrievableDocument , internal , BAD_REQUEST ; +UnretrievableErrorCode , invalid , BAD_REQUEST ; +UnsupportedMediaType , invalid , UNSUPPORTED_MEDIA_TYPE } /// Internal structure providing a convenient way to create error codes struct ErrCode { status_code: StatusCode, error_type: ErrorType, - error_name: &'static str, + error_name: String, } impl ErrCode { - fn authentication(error_name: &'static str, status_code: StatusCode) -> ErrCode { + fn authentication(error_name: String, status_code: StatusCode) -> ErrCode { ErrCode { status_code, error_name, error_type: ErrorType::AuthenticationError } } - fn internal(error_name: &'static str, status_code: StatusCode) -> ErrCode { + fn internal(error_name: String, status_code: StatusCode) -> ErrCode { ErrCode { status_code, error_name, error_type: ErrorType::InternalError } } - fn invalid(error_name: &'static str, status_code: StatusCode) -> ErrCode { + fn invalid(error_name: String, status_code: StatusCode) -> ErrCode { ErrCode { status_code, error_name, error_type: ErrorType::InvalidRequestError } } - fn system(error_name: &'static str, status_code: StatusCode) -> ErrCode { + fn system(error_name: String, status_code: StatusCode) -> ErrCode { ErrCode { status_code, error_name, error_type: ErrorType::System } } } @@ -591,7 +321,7 @@ impl ErrorCode for milli::Error { | UserError::DocumentLimitReached | UserError::AccessingSoftDeletedDocument { .. } | UserError::UnknownInternalDocumentId { .. } => Code::Internal, - UserError::InvalidStoreFile => Code::InvalidStore, + UserError::InvalidStoreFile => Code::InvalidStoreFile, UserError::NoSpaceLeftOnDevice => Code::NoSpaceLeftOnDevice, UserError::MaxDatabaseSizeReached => Code::DatabaseSizeLimitReached, UserError::AttributeLimitReached => Code::MaxFieldsLimitExceeded, @@ -600,15 +330,15 @@ impl ErrorCode for milli::Error { UserError::InvalidDocumentId { .. } | UserError::TooManyDocumentIds { .. } => { Code::InvalidDocumentId } - UserError::NoPrimaryKeyCandidateFound => Code::NoPrimaryKeyCandidateFound, + UserError::NoPrimaryKeyCandidateFound => Code::IndexPrimaryKeyNoCandidateFound, UserError::MultiplePrimaryKeyCandidatesFound { .. } => { - Code::MultiplePrimaryKeyCandidatesFound + Code::IndexPrimaryKeyMultipleCandidatesFound } - UserError::PrimaryKeyCannotBeChanged(_) => Code::PrimaryKeyAlreadyPresent, + UserError::PrimaryKeyCannotBeChanged(_) => Code::IndexPrimaryKeyAlreadyExists, UserError::SortRankingRuleMissing => Code::InvalidSearchSort, UserError::InvalidFacetsDistribution { .. } => Code::BadRequest, UserError::InvalidSortableAttribute { .. } => Code::InvalidSearchSort, - UserError::CriterionError(_) => Code::InvalidSettingsRankingRules, + UserError::CriterionError(_) => Code::InvalidRankingRule, UserError::InvalidGeoField { .. } => Code::InvalidDocumentGeoField, UserError::SortError(_) => Code::InvalidSearchSort, UserError::InvalidMinTypoWordLenSetting(_, _) => { @@ -639,7 +369,7 @@ impl ErrorCode for HeedError { fn error_code(&self) -> Code { match self { HeedError::Mdb(MdbError::MapFull) => Code::DatabaseSizeLimitReached, - HeedError::Mdb(MdbError::Invalid) => Code::InvalidStore, + HeedError::Mdb(MdbError::Invalid) => Code::InvalidStoreFile, HeedError::Io(e) => e.error_code(), HeedError::Mdb(_) | HeedError::Encoding