Simplify declaration of the error codes

This commit is contained in:
Loïc Lecrenier 2023-01-11 12:33:45 +01:00 committed by Tamo
parent 808e184069
commit 2bc2e99ff3
No known key found for this signature in database
GPG Key ID: 20CD8020AFA88D69
3 changed files with 177 additions and 447 deletions

View File

@ -254,14 +254,14 @@ impl<T> From<v5::Setting<T>> for v6::Setting<T> {
impl From<v5::ResponseError> for v6::ResponseError { impl From<v5::ResponseError> for v6::ResponseError {
fn from(error: v5::ResponseError) -> Self { fn from(error: v5::ResponseError) -> Self {
let code = match error.error_code.as_ref() { 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_already_exists" => v6::Code::IndexAlreadyExists,
"index_not_found" => v6::Code::IndexNotFound, "index_not_found" => v6::Code::IndexNotFound,
"invalid_index_uid" => v6::Code::InvalidIndexUid, "invalid_index_uid" => v6::Code::InvalidIndexUid,
"invalid_min_word_length_for_typo" => v6::Code::InvalidMinWordLengthForTypo, "invalid_min_word_length_for_typo" => v6::Code::InvalidMinWordLengthForTypo,
"invalid_state" => v6::Code::InvalidState, "invalid_state" => v6::Code::InvalidState,
"primary_key_inference_failed" => v6::Code::NoPrimaryKeyCandidateFound, "primary_key_inference_failed" => v6::Code::IndexPrimaryKeyNoCandidateFound,
"index_primary_key_already_exists" => v6::Code::PrimaryKeyAlreadyPresent, "index_primary_key_already_exists" => v6::Code::IndexPrimaryKeyAlreadyExists,
"max_fields_limit_exceeded" => v6::Code::MaxFieldsLimitExceeded, "max_fields_limit_exceeded" => v6::Code::MaxFieldsLimitExceeded,
"missing_document_id" => v6::Code::MissingDocumentId, "missing_document_id" => v6::Code::MissingDocumentId,
"invalid_document_id" => v6::Code::InvalidDocumentId, "invalid_document_id" => v6::Code::InvalidDocumentId,
@ -274,16 +274,16 @@ impl From<v5::ResponseError> for v6::ResponseError {
"internal" => v6::Code::Internal, "internal" => v6::Code::Internal,
"invalid_geo_field" => v6::Code::InvalidDocumentGeoField, "invalid_geo_field" => v6::Code::InvalidDocumentGeoField,
"invalid_ranking_rule" => v6::Code::InvalidSettingsRankingRules, "invalid_ranking_rule" => v6::Code::InvalidSettingsRankingRules,
"invalid_store_file" => v6::Code::InvalidStore, "invalid_store_file" => v6::Code::InvalidStoreFile,
"invalid_api_key" => v6::Code::InvalidToken, "invalid_api_key" => v6::Code::InvalidApiKey,
"missing_authorization_header" => v6::Code::MissingAuthorizationHeader, "missing_authorization_header" => v6::Code::MissingAuthorizationHeader,
"no_space_left_on_device" => v6::Code::NoSpaceLeftOnDevice, "no_space_left_on_device" => v6::Code::NoSpaceLeftOnDevice,
"dump_not_found" => v6::Code::DumpNotFound, "dump_not_found" => v6::Code::DumpNotFound,
"task_not_found" => v6::Code::TaskNotFound, "task_not_found" => v6::Code::TaskNotFound,
"payload_too_large" => v6::Code::PayloadTooLarge, "payload_too_large" => v6::Code::PayloadTooLarge,
"unretrievable_document" => v6::Code::DocumentNotFound, "unretrievable_document" => v6::Code::UnretrievableDocument,
"unsupported_media_type" => v6::Code::UnsupportedMediaType, "unsupported_media_type" => v6::Code::UnsupportedMediaType,
"dump_already_processing" => v6::Code::DumpAlreadyInProgress, "dump_already_processing" => v6::Code::DumpAlreadyProcessing,
"dump_process_failed" => v6::Code::DumpProcessFailed, "dump_process_failed" => v6::Code::DumpProcessFailed,
"invalid_content_type" => v6::Code::InvalidContentType, "invalid_content_type" => v6::Code::InvalidContentType,
"missing_content_type" => v6::Code::MissingContentType, "missing_content_type" => v6::Code::MissingContentType,

View File

@ -139,8 +139,8 @@ impl ErrorCode for Error {
match self { match self {
Error::IndexNotFound(_) => Code::IndexNotFound, Error::IndexNotFound(_) => Code::IndexNotFound,
Error::IndexAlreadyExists(_) => Code::IndexAlreadyExists, Error::IndexAlreadyExists(_) => Code::IndexAlreadyExists,
Error::SwapDuplicateIndexesFound(_) => Code::InvalidDuplicateIndexesFound, Error::SwapDuplicateIndexesFound(_) => Code::InvalidSwapDuplicateIndexFound,
Error::SwapDuplicateIndexFound(_) => Code::InvalidDuplicateIndexesFound, Error::SwapDuplicateIndexFound(_) => Code::InvalidSwapDuplicateIndexFound,
Error::SwapIndexNotFound(_) => Code::InvalidSwapIndexes, Error::SwapIndexNotFound(_) => Code::InvalidSwapIndexes,
Error::SwapIndexesNotFound(_) => Code::InvalidSwapIndexes, Error::SwapIndexesNotFound(_) => Code::InvalidSwapIndexes,
Error::InvalidTaskDate { field, .. } => (*field).into(), Error::InvalidTaskDate { field, .. } => (*field).into(),
@ -150,8 +150,8 @@ impl ErrorCode for Error {
Error::InvalidTaskCanceledBy { .. } => Code::InvalidTaskCanceledBy, Error::InvalidTaskCanceledBy { .. } => Code::InvalidTaskCanceledBy,
Error::InvalidIndexUid { .. } => Code::InvalidIndexUid, Error::InvalidIndexUid { .. } => Code::InvalidIndexUid,
Error::TaskNotFound(_) => Code::TaskNotFound, Error::TaskNotFound(_) => Code::TaskNotFound,
Error::TaskDeletionWithEmptyQuery => Code::TaskDeletionWithEmptyQuery, Error::TaskDeletionWithEmptyQuery => Code::MissingTaskFilters,
Error::TaskCancelationWithEmptyQuery => Code::TaskCancelationWithEmptyQuery, Error::TaskCancelationWithEmptyQuery => Code::MissingTaskFilters,
Error::Dump(e) => e.error_code(), Error::Dump(e) => e.error_code(),
Error::Milli(e) => e.error_code(), Error::Milli(e) => e.error_code(),
Error::ProcessBatchPanicked => Code::Internal, Error::ProcessBatchPanicked => Code::Internal,

View File

@ -1,9 +1,12 @@
use std::convert::Infallible;
use std::marker::PhantomData;
use std::{fmt, io}; use std::{fmt, io};
use actix_web::http::StatusCode; use actix_web::http::StatusCode;
use actix_web::{self as aweb, HttpResponseBuilder}; use actix_web::{self as aweb, HttpResponseBuilder};
use aweb::rt::task::JoinError; use aweb::rt::task::JoinError;
use convert_case::Casing; use convert_case::Casing;
use deserr::{DeserializeError, IntoValue, MergeWithError, ValuePointerRef};
use milli::heed::{Error as HeedError, MdbError}; use milli::heed::{Error as HeedError, MdbError};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -31,7 +34,7 @@ impl ResponseError {
Self { Self {
code: code.http(), code: code.http(),
message, message,
error_code: code.err_code().error_name.to_string(), error_code: code.err_code().error_name,
error_type: code.type_(), error_type: code.type_(),
error_link: code.url(), error_link: code.url(),
} }
@ -48,7 +51,7 @@ impl std::error::Error for ResponseError {}
impl<T> From<T> for ResponseError impl<T> From<T> for ResponseError
where where
T: ErrorCode, T: std::error::Error + ErrorCode,
{ {
fn from(other: T) -> Self { fn from(other: T) -> Self {
Self::from_msg(other.to_string(), other.error_code()) 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; fn error_code(&self) -> Code;
/// returns the HTTP status code associated with the error /// returns the HTTP status code associated with the error
@ -111,416 +114,24 @@ impl fmt::Display for ErrorType {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] macro_rules! make_error_codes {
pub enum Code { ($($code_ident:ident, $err_type:ident, $status:ident);*) => {
// error related to your setup #[repr(u32)]
IoError, #[derive(Debug, Clone, Copy, PartialEq, Eq)]
NoSpaceLeftOnDevice, pub enum Code {
TooManyOpenFiles, $($code_ident),*
}
// index related error impl Code {
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 /// associate a `Code` variant to the actual ErrCode
fn err_code(&self) -> ErrCode { fn err_code(&self) -> ErrCode {
use Code::*;
match self { match self {
// related to the setup $(
IoError => ErrCode::system("io_error", StatusCode::INTERNAL_SERVER_ERROR), Code::$code_ident => {
TooManyOpenFiles => { ErrCode::$err_type( stringify!($code_ident).to_case(convert_case::Case::Snake), StatusCode::$status)
ErrCode::system("too_many_open_files", StatusCode::INTERNAL_SERVER_ERROR)
} }
NoSpaceLeftOnDevice => { )*
ErrCode::system("no_space_left_on_device", StatusCode::INTERNAL_SERVER_ERROR)
} }
// 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)
}
// invalid database
InvalidStore => {
ErrCode::internal("invalid_store_file", StatusCode::INTERNAL_SERVER_ERROR)
}
// 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 HTTP status code associated with the `Code` /// return the HTTP status code associated with the `Code`
fn http(&self) -> StatusCode { fn http(&self) -> StatusCode {
self.err_code().status_code self.err_code().status_code
@ -543,29 +154,148 @@ impl Code {
self.name().to_case(convert_case::Case::Kebab) 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
}
}
)*
}
}
}
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 /// Internal structure providing a convenient way to create error codes
struct ErrCode { struct ErrCode {
status_code: StatusCode, status_code: StatusCode,
error_type: ErrorType, error_type: ErrorType,
error_name: &'static str, error_name: String,
} }
impl ErrCode { 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 } 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 } 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 } 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 } ErrCode { status_code, error_name, error_type: ErrorType::System }
} }
} }
@ -591,7 +321,7 @@ impl ErrorCode for milli::Error {
| UserError::DocumentLimitReached | UserError::DocumentLimitReached
| UserError::AccessingSoftDeletedDocument { .. } | UserError::AccessingSoftDeletedDocument { .. }
| UserError::UnknownInternalDocumentId { .. } => Code::Internal, | UserError::UnknownInternalDocumentId { .. } => Code::Internal,
UserError::InvalidStoreFile => Code::InvalidStore, UserError::InvalidStoreFile => Code::InvalidStoreFile,
UserError::NoSpaceLeftOnDevice => Code::NoSpaceLeftOnDevice, UserError::NoSpaceLeftOnDevice => Code::NoSpaceLeftOnDevice,
UserError::MaxDatabaseSizeReached => Code::DatabaseSizeLimitReached, UserError::MaxDatabaseSizeReached => Code::DatabaseSizeLimitReached,
UserError::AttributeLimitReached => Code::MaxFieldsLimitExceeded, UserError::AttributeLimitReached => Code::MaxFieldsLimitExceeded,
@ -600,15 +330,15 @@ impl ErrorCode for milli::Error {
UserError::InvalidDocumentId { .. } | UserError::TooManyDocumentIds { .. } => { UserError::InvalidDocumentId { .. } | UserError::TooManyDocumentIds { .. } => {
Code::InvalidDocumentId Code::InvalidDocumentId
} }
UserError::NoPrimaryKeyCandidateFound => Code::NoPrimaryKeyCandidateFound, UserError::NoPrimaryKeyCandidateFound => Code::IndexPrimaryKeyNoCandidateFound,
UserError::MultiplePrimaryKeyCandidatesFound { .. } => { UserError::MultiplePrimaryKeyCandidatesFound { .. } => {
Code::MultiplePrimaryKeyCandidatesFound Code::IndexPrimaryKeyMultipleCandidatesFound
} }
UserError::PrimaryKeyCannotBeChanged(_) => Code::PrimaryKeyAlreadyPresent, UserError::PrimaryKeyCannotBeChanged(_) => Code::IndexPrimaryKeyAlreadyExists,
UserError::SortRankingRuleMissing => Code::InvalidSearchSort, UserError::SortRankingRuleMissing => Code::InvalidSearchSort,
UserError::InvalidFacetsDistribution { .. } => Code::BadRequest, UserError::InvalidFacetsDistribution { .. } => Code::BadRequest,
UserError::InvalidSortableAttribute { .. } => Code::InvalidSearchSort, UserError::InvalidSortableAttribute { .. } => Code::InvalidSearchSort,
UserError::CriterionError(_) => Code::InvalidSettingsRankingRules, UserError::CriterionError(_) => Code::InvalidRankingRule,
UserError::InvalidGeoField { .. } => Code::InvalidDocumentGeoField, UserError::InvalidGeoField { .. } => Code::InvalidDocumentGeoField,
UserError::SortError(_) => Code::InvalidSearchSort, UserError::SortError(_) => Code::InvalidSearchSort,
UserError::InvalidMinTypoWordLenSetting(_, _) => { UserError::InvalidMinTypoWordLenSetting(_, _) => {
@ -639,7 +369,7 @@ impl ErrorCode for HeedError {
fn error_code(&self) -> Code { fn error_code(&self) -> Code {
match self { match self {
HeedError::Mdb(MdbError::MapFull) => Code::DatabaseSizeLimitReached, 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::Io(e) => e.error_code(),
HeedError::Mdb(_) HeedError::Mdb(_)
| HeedError::Encoding | HeedError::Encoding