mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-12-03 18:45:11 +08:00
adds error handling and integration
This commit is contained in:
parent
83f50914ec
commit
3e031d8297
@ -1,10 +1,13 @@
|
|||||||
use crate::serde::{DeserializerError, SerializerError};
|
use crate::serde::{DeserializerError, SerializerError};
|
||||||
use serde_json::Error as SerdeJsonError;
|
use serde_json::Error as SerdeJsonError;
|
||||||
|
use pest::error::Error as PestError;
|
||||||
|
use crate::filters::Rule;
|
||||||
use std::{error, fmt, io};
|
use std::{error, fmt, io};
|
||||||
|
|
||||||
pub use heed::Error as HeedError;
|
|
||||||
pub use fst::Error as FstError;
|
|
||||||
pub use bincode::Error as BincodeError;
|
pub use bincode::Error as BincodeError;
|
||||||
|
pub use fst::Error as FstError;
|
||||||
|
pub use heed::Error as HeedError;
|
||||||
|
pub use pest::error as pest_error;
|
||||||
|
|
||||||
pub type MResult<T> = Result<T, Error>;
|
pub type MResult<T> = Result<T, Error>;
|
||||||
|
|
||||||
@ -25,6 +28,7 @@ pub enum Error {
|
|||||||
Serializer(SerializerError),
|
Serializer(SerializerError),
|
||||||
Deserializer(DeserializerError),
|
Deserializer(DeserializerError),
|
||||||
UnsupportedOperation(UnsupportedOperation),
|
UnsupportedOperation(UnsupportedOperation),
|
||||||
|
FilterParseError(PestError<Rule>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
@ -42,11 +46,11 @@ impl From<PestError<Rule>> for Error {
|
|||||||
Rule::not => "NOT",
|
Rule::not => "NOT",
|
||||||
Rule::string => "string",
|
Rule::string => "string",
|
||||||
Rule::word => "word",
|
Rule::word => "word",
|
||||||
Rule::greater => "field>value",
|
Rule::greater => "field > value",
|
||||||
Rule::less => "field<value",
|
Rule::less => "field < value",
|
||||||
Rule::eq => "field:value",
|
Rule::eq => "field = value",
|
||||||
Rule::leq => "field<=value",
|
Rule::leq => "field <= value",
|
||||||
Rule::geq => "field>=value",
|
Rule::geq => "field >= value",
|
||||||
Rule::key => "key",
|
Rule::key => "key",
|
||||||
_ => "other",
|
_ => "other",
|
||||||
};
|
};
|
||||||
@ -122,6 +126,7 @@ impl fmt::Display for Error {
|
|||||||
Serializer(e) => write!(f, "serializer error; {}", e),
|
Serializer(e) => write!(f, "serializer error; {}", e),
|
||||||
Deserializer(e) => write!(f, "deserializer error; {}", e),
|
Deserializer(e) => write!(f, "deserializer error; {}", e),
|
||||||
UnsupportedOperation(op) => write!(f, "unsupported operation; {}", op),
|
UnsupportedOperation(op) => write!(f, "unsupported operation; {}", op),
|
||||||
|
FilterParseError(e) => write!(f, "error parsing filter; {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate assert_matches;
|
extern crate assert_matches;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate pest_derive;
|
||||||
|
|
||||||
mod automaton;
|
mod automaton;
|
||||||
mod bucket_sort;
|
mod bucket_sort;
|
||||||
mod database;
|
mod database;
|
||||||
mod distinct_map;
|
mod distinct_map;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod filters;
|
||||||
mod levenshtein;
|
mod levenshtein;
|
||||||
mod number;
|
mod number;
|
||||||
mod query_builder;
|
mod query_builder;
|
||||||
@ -23,7 +26,8 @@ pub mod serde;
|
|||||||
pub mod store;
|
pub mod store;
|
||||||
|
|
||||||
pub use self::database::{BoxUpdateFn, Database, MainT, UpdateT};
|
pub use self::database::{BoxUpdateFn, Database, MainT, UpdateT};
|
||||||
pub use self::error::{Error, HeedError, FstError, MResult};
|
pub use self::error::{Error, HeedError, FstError, MResult, pest_error};
|
||||||
|
pub use self::filters::Filter;
|
||||||
pub use self::number::{Number, ParseNumberError};
|
pub use self::number::{Number, ParseNumberError};
|
||||||
pub use self::ranked_map::RankedMap;
|
pub use self::ranked_map::RankedMap;
|
||||||
pub use self::raw_document::RawDocument;
|
pub use self::raw_document::RawDocument;
|
||||||
|
@ -19,6 +19,7 @@ pub enum ResponseError {
|
|||||||
IndexNotFound(String),
|
IndexNotFound(String),
|
||||||
DocumentNotFound(String),
|
DocumentNotFound(String),
|
||||||
MissingHeader(String),
|
MissingHeader(String),
|
||||||
|
FilterParsing(String),
|
||||||
BadParameter(String, String),
|
BadParameter(String, String),
|
||||||
OpenIndex(String),
|
OpenIndex(String),
|
||||||
CreateIndex(String),
|
CreateIndex(String),
|
||||||
@ -73,11 +74,15 @@ impl IntoResponse for ResponseError {
|
|||||||
match self {
|
match self {
|
||||||
ResponseError::Internal(err) => {
|
ResponseError::Internal(err) => {
|
||||||
error!("internal server error: {}", err);
|
error!("internal server error: {}", err);
|
||||||
error(
|
error("Internal server error".to_string(),
|
||||||
String::from("Internal server error"),
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
ResponseError::FilterParsing(err) => {
|
||||||
|
warn!("error paring filter: {}", err);
|
||||||
|
error(format!("parsing error: {}", err),
|
||||||
|
StatusCode::BAD_REQUEST)
|
||||||
|
}
|
||||||
ResponseError::BadRequest(err) => {
|
ResponseError::BadRequest(err) => {
|
||||||
warn!("bad request: {}", err);
|
warn!("bad request: {}", err);
|
||||||
error(err, StatusCode::BAD_REQUEST)
|
error(err, StatusCode::BAD_REQUEST)
|
||||||
@ -159,7 +164,10 @@ impl From<FstError> for ResponseError {
|
|||||||
|
|
||||||
impl From<SearchError> for ResponseError {
|
impl From<SearchError> for ResponseError {
|
||||||
fn from(err: SearchError) -> ResponseError {
|
fn from(err: SearchError) -> ResponseError {
|
||||||
ResponseError::internal(err)
|
match err {
|
||||||
|
SearchError::FilterParsing(s) => ResponseError::FilterParsing(s),
|
||||||
|
_ => ResponseError::internal(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ use std::time::{Duration, Instant};
|
|||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use log::error;
|
use log::error;
|
||||||
|
use meilisearch_core::Filter;
|
||||||
use meilisearch_core::criterion::*;
|
use meilisearch_core::criterion::*;
|
||||||
use meilisearch_core::settings::RankingRule;
|
use meilisearch_core::settings::RankingRule;
|
||||||
use meilisearch_core::{Highlight, Index, MainT, RankedMap};
|
use meilisearch_core::{Highlight, Index, MainT, RankedMap};
|
||||||
@ -23,6 +24,7 @@ pub enum Error {
|
|||||||
RetrieveDocument(u64, String),
|
RetrieveDocument(u64, String),
|
||||||
DocumentNotFound(u64),
|
DocumentNotFound(u64),
|
||||||
CropFieldWrongType(String),
|
CropFieldWrongType(String),
|
||||||
|
FilterParsing(String),
|
||||||
AttributeNotFoundOnDocument(String),
|
AttributeNotFoundOnDocument(String),
|
||||||
AttributeNotFoundOnSchema(String),
|
AttributeNotFoundOnSchema(String),
|
||||||
MissingFilterValue,
|
MissingFilterValue,
|
||||||
@ -56,13 +58,26 @@ impl fmt::Display for Error {
|
|||||||
f.write_str("a filter is specifying an unknown schema attribute")
|
f.write_str("a filter is specifying an unknown schema attribute")
|
||||||
}
|
}
|
||||||
Internal(err) => write!(f, "internal error; {}", err),
|
Internal(err) => write!(f, "internal error; {}", err),
|
||||||
|
FilterParsing(err) => write!(f, "filter parsing error: {}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<meilisearch_core::Error> for Error {
|
impl From<meilisearch_core::Error> for Error {
|
||||||
fn from(error: meilisearch_core::Error) -> Self {
|
fn from(error: meilisearch_core::Error) -> Self {
|
||||||
Error::Internal(error.to_string())
|
use meilisearch_core::pest_error::LineColLocation::*;
|
||||||
|
match error {
|
||||||
|
meilisearch_core::Error::FilterParseError(e) => {
|
||||||
|
let (line, column) = match e.line_col {
|
||||||
|
Span((line, _), (column, _)) => (line, column),
|
||||||
|
Pos((line, column)) => (line, column),
|
||||||
|
};
|
||||||
|
let message = format!("parsing error on line {} at column {}: {}", line, column, e.variant.message());
|
||||||
|
|
||||||
|
Error::FilterParsing(message)
|
||||||
|
},
|
||||||
|
_ => Error::Internal(error.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,40 +186,21 @@ impl<'a> SearchBuilder<'a> {
|
|||||||
None => self.index.query_builder(),
|
None => self.index.query_builder(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(filters) = &self.filters {
|
if let Some(filter_expression) = &self.filters {
|
||||||
let mut split = filters.split(':');
|
let filter = Filter::parse(filter_expression, &schema)?;
|
||||||
match (split.next(), split.next()) {
|
|
||||||
(Some(_), None) | (Some(_), Some("")) => return Err(Error::MissingFilterValue),
|
|
||||||
(Some(attr), Some(value)) => {
|
|
||||||
let ref_reader = reader;
|
|
||||||
let ref_index = &self.index;
|
|
||||||
let value = value.trim().to_lowercase();
|
|
||||||
|
|
||||||
let attr = match schema.id(attr) {
|
|
||||||
Some(attr) => attr,
|
|
||||||
None => return Err(Error::UnknownFilteredAttribute),
|
|
||||||
};
|
|
||||||
|
|
||||||
query_builder.with_filter(move |id| {
|
query_builder.with_filter(move |id| {
|
||||||
let attr = attr;
|
let index = &self.index;
|
||||||
let index = ref_index;
|
let reader = &reader;
|
||||||
let reader = ref_reader;
|
let filter = &filter;
|
||||||
|
match filter.test(reader, index, id) {
|
||||||
match index.document_attribute::<Value>(reader, id, attr) {
|
Ok(res) => res,
|
||||||
Ok(Some(Value::String(s))) => s.to_lowercase() == value,
|
Err(e) => {
|
||||||
Ok(Some(Value::Bool(b))) => {
|
log::warn!("unexpected error during filtering: {}", e);
|
||||||
(value == "true" && b) || (value == "false" && !b)
|
false
|
||||||
}
|
}
|
||||||
Ok(Some(Value::Array(a))) => {
|
|
||||||
a.into_iter().any(|s| s.as_str() == Some(&value))
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(_, _) => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query_builder.with_fetch_timeout(self.timeout);
|
query_builder.with_fetch_timeout(self.timeout);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user