diff --git a/meilisearch-http/src/error.rs b/meilisearch-http/src/error.rs index ef2a910d5..e05853062 100644 --- a/meilisearch-http/src/error.rs +++ b/meilisearch-http/src/error.rs @@ -7,39 +7,109 @@ use serde_json::json; #[derive(Debug)] pub enum ResponseError { - Internal(String), - BadRequest(String), - MissingAuthorizationHeader, - InvalidToken(String), - NotFound(String), - IndexNotFound(String), - DocumentNotFound(String), - MissingHeader(String), - FilterParsing(String), BadParameter(String, String), - OpenIndex(String), + BadRequest(String), CreateIndex(String), + DocumentNotFound(String), + IndexNotFound(String), + Internal(String), InvalidIndexUid, + InvalidToken(String), Maintenance, + MissingAuthorizationHeader, + MissingFilterValue, + MissingHeader(String), + NotFound(String), + OpenIndex(String), + FilterParsing(String), + RetrieveDocument(u64, String), + SearchDocuments(String), + UnknownFilteredAttribute, +} + +impl ResponseError { + pub fn internal(err: impl fmt::Display) -> ResponseError { + ResponseError::Internal(err.to_string()) + } + + pub fn bad_request(err: impl fmt::Display) -> ResponseError { + ResponseError::BadRequest(err.to_string()) + } + + pub fn missing_authorization_header() -> ResponseError { + ResponseError::MissingAuthorizationHeader + } + + pub fn invalid_token(err: impl fmt::Display) -> ResponseError { + ResponseError::InvalidToken(err.to_string()) + } + + pub fn not_found(err: impl fmt::Display) -> ResponseError { + ResponseError::NotFound(err.to_string()) + } + + pub fn index_not_found(err: impl fmt::Display) -> ResponseError { + ResponseError::IndexNotFound(err.to_string()) + } + + pub fn document_not_found(err: impl fmt::Display) -> ResponseError { + ResponseError::DocumentNotFound(err.to_string()) + } + + pub fn missing_header(err: impl fmt::Display) -> ResponseError { + ResponseError::MissingHeader(err.to_string()) + } + + pub fn bad_parameter(param: impl fmt::Display, err: impl fmt::Display) -> ResponseError { + ResponseError::BadParameter(param.to_string(), err.to_string()) + } + + pub fn open_index(err: impl fmt::Display) -> ResponseError { + ResponseError::OpenIndex(err.to_string()) + } + + pub fn create_index(err: impl fmt::Display) -> ResponseError { + ResponseError::CreateIndex(err.to_string()) + } + + pub fn invalid_index_uid() -> ResponseError { + ResponseError::InvalidIndexUid + } + + pub fn maintenance() -> ResponseError { + ResponseError::Maintenance + } + + pub fn retrieve_document(doc_id: u64, err: impl fmt::Display) -> ResponseError { + ResponseError::RetrieveDocument(doc_id, err.to_string()) + } + + pub fn search_documents(err: impl fmt::Display) -> ResponseError { + ResponseError::SearchDocuments(err.to_string()) + } } impl fmt::Display for ResponseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Internal(err) => write!(f, "{}", err), - Self::BadRequest(err) => write!(f, "{}", err), - Self::MissingAuthorizationHeader => write!(f, "You must have an authorization token"), - Self::InvalidToken(err) => write!(f, "Invalid API key: {}", err), - Self::NotFound(err) => write!(f, "{} not found", err), - Self::IndexNotFound(index_uid) => write!(f, "Index {} not found", index_uid), - Self::DocumentNotFound(document_id) => write!(f, "Document with id {} not found", document_id), - Self::MissingHeader(header) => write!(f, "Header {} is missing", header), Self::BadParameter(param, err) => write!(f, "Url parameter {} error: {}", param, err), - Self::OpenIndex(err) => write!(f, "Impossible to open index; {}", err), + Self::BadRequest(err) => write!(f, "{}", err), Self::CreateIndex(err) => write!(f, "Impossible to create index; {}", err), - Self::InvalidIndexUid => write!(f, "Index must have a valid uid; Index uid can be of type integer or string only composed of alphanumeric characters, hyphens (-) and underscores (_)."), - Self::Maintenance => write!(f, "Server is in maintenance, please try again later"), + Self::DocumentNotFound(document_id) => write!(f, "Document with id {} not found", document_id), + Self::IndexNotFound(index_uid) => write!(f, "Index {} not found", index_uid), + Self::Internal(err) => write!(f, "{}", err), + Self::InvalidIndexUid => f.write_str("Index must have a valid uid; Index uid can be of type integer or string only composed of alphanumeric characters, hyphens (-) and underscores (_)."), + Self::InvalidToken(err) => write!(f, "Invalid API key: {}", err), + Self::Maintenance => f.write_str("Server is in maintenance, please try again later"), Self::FilterParsing(err) => write!(f, "parsing error: {}", err), + Self::MissingAuthorizationHeader => f.write_str("You must have an authorization token"), + Self::MissingFilterValue => f.write_str("a filter doesn't have a value to compare it with"), + Self::MissingHeader(header) => write!(f, "Header {} is missing", header), + Self::NotFound(err) => write!(f, "{} not found", err), + Self::OpenIndex(err) => write!(f, "Impossible to open index; {}", err), + Self::RetrieveDocument(id, err) => write!(f, "impossible to retrieve the document with id: {}; {}", id, err), + Self::SearchDocuments(err) => write!(f, "impossible to search documents; {}", err), + Self::UnknownFilteredAttribute => f.write_str("a filter is specifying an unknown schema attribute"), } } } @@ -53,20 +123,66 @@ impl aweb::error::ResponseError for ResponseError { fn status_code(&self) -> StatusCode { match *self { - Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, - Self::BadRequest(_) => StatusCode::BAD_REQUEST, - Self::MissingAuthorizationHeader => StatusCode::FORBIDDEN, - Self::InvalidToken(_) => StatusCode::UNAUTHORIZED, - Self::NotFound(_) => StatusCode::NOT_FOUND, - Self::IndexNotFound(_) => StatusCode::NOT_FOUND, - Self::DocumentNotFound(_) => StatusCode::NOT_FOUND, - Self::MissingHeader(_) => StatusCode::UNAUTHORIZED, Self::BadParameter(_, _) => StatusCode::BAD_REQUEST, - Self::OpenIndex(_) => StatusCode::BAD_REQUEST, + Self::BadRequest(_) => StatusCode::BAD_REQUEST, Self::CreateIndex(_) => StatusCode::BAD_REQUEST, + Self::DocumentNotFound(_) => StatusCode::NOT_FOUND, + Self::IndexNotFound(_) => StatusCode::NOT_FOUND, + Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::InvalidIndexUid => StatusCode::BAD_REQUEST, + Self::InvalidToken(_) => StatusCode::UNAUTHORIZED, Self::Maintenance => StatusCode::SERVICE_UNAVAILABLE, Self::FilterParsing(_) => StatusCode::BAD_REQUEST, + Self::MissingAuthorizationHeader => StatusCode::FORBIDDEN, + Self::MissingFilterValue => StatusCode::BAD_REQUEST, + Self::MissingHeader(_) => StatusCode::UNAUTHORIZED, + Self::NotFound(_) => StatusCode::NOT_FOUND, + Self::OpenIndex(_) => StatusCode::BAD_REQUEST, + Self::RetrieveDocument(_, _) => StatusCode::BAD_REQUEST, + Self::SearchDocuments(_) => StatusCode::BAD_REQUEST, + Self::UnknownFilteredAttribute => StatusCode::BAD_REQUEST, } } } + +impl From for ResponseError { + fn from(err: meilisearch_core::HeedError) -> ResponseError { + ResponseError::Internal(err.to_string()) + } +} + +impl From for ResponseError { + fn from(err: meilisearch_core::FstError) -> ResponseError { + ResponseError::Internal(err.to_string()) + } +} + +impl From for ResponseError { + fn from(err: meilisearch_core::Error) -> ResponseError { + use meilisearch_core::pest_error::LineColLocation::*; + match err { + 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()); + + ResponseError::FilterParsing(message) + }, + _ => ResponseError::Internal(err.to_string()), + } + } +} + +impl From for ResponseError { + fn from(err: meilisearch_schema::Error) -> ResponseError { + ResponseError::Internal(err.to_string()) + } +} + +impl From for ResponseError { + fn from(err: actix_http::Error) -> ResponseError { + ResponseError::Internal(err.to_string()) + } +} diff --git a/meilisearch-http/src/helpers/meilisearch.rs b/meilisearch-http/src/helpers/meilisearch.rs index 5b0563ae0..2cd9d3379 100644 --- a/meilisearch-http/src/helpers/meilisearch.rs +++ b/meilisearch-http/src/helpers/meilisearch.rs @@ -1,8 +1,5 @@ use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; -use std::convert::From; -use std::error; -use std::fmt; use std::hash::{Hash, Hasher}; use std::time::{Duration, Instant}; @@ -19,74 +16,7 @@ use serde_json::Value; use siphasher::sip::SipHasher; use slice_group_by::GroupBy; -#[derive(Debug)] -pub enum Error { - SearchDocuments(String), - RetrieveDocument(u64, String), - DocumentNotFound(u64), - CropFieldWrongType(String), - FilterParsing(String), - AttributeNotFoundOnDocument(String), - AttributeNotFoundOnSchema(String), - MissingFilterValue, - UnknownFilteredAttribute, - Internal(String), -} - -impl error::Error for Error {} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use Error::*; - - match self { - SearchDocuments(err) => write!(f, "impossible to search documents; {}", err), - RetrieveDocument(id, err) => write!( - f, - "impossible to retrieve the document with id: {}; {}", - id, err - ), - DocumentNotFound(id) => write!(f, "document {} not found", id), - CropFieldWrongType(field) => { - write!(f, "the field {} cannot be cropped it's not a string", field) - } - AttributeNotFoundOnDocument(field) => { - write!(f, "field {} is not found on document", field) - } - AttributeNotFoundOnSchema(field) => write!(f, "field {} is not found on schema", field), - MissingFilterValue => f.write_str("a filter doesn't have a value to compare it with"), - UnknownFilteredAttribute => { - f.write_str("a filter is specifying an unknown schema attribute") - } - Internal(err) => write!(f, "internal error; {}", err), - FilterParsing(err) => write!(f, "filter parsing error: {}", err), - } - } -} - -impl From for Error { - fn from(error: meilisearch_core::Error) -> Self { - 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()), - } - } -} - -impl From for Error { - fn from(error: heed::Error) -> Self { - Error::Internal(error.to_string()) - } -} +use crate::error::ResponseError; pub trait IndexSearchExt { fn new_search(&self, query: String) -> SearchBuilder; @@ -169,17 +99,14 @@ impl<'a> SearchBuilder<'a> { self } - pub fn search(&self, reader: &heed::RoTxn) -> Result { - let schema = self.index.main.schema(reader); - let schema = schema.map_err(|e| Error::Internal(e.to_string()))?; - let schema = match schema { - Some(schema) => schema, - None => return Err(Error::Internal(String::from("missing schema"))), - }; + pub fn search(&self, reader: &heed::RoTxn) -> Result { + let schema = self + .index + .main + .schema(reader)? + .ok_or(ResponseError::internal("missing schema"))?; - let ranked_map = self.index.main.ranked_map(reader); - let ranked_map = ranked_map.map_err(|e| Error::Internal(e.to_string()))?; - let ranked_map = ranked_map.unwrap_or_default(); + let ranked_map = self.index.main.ranked_map(reader)?.unwrap_or_default(); // Change criteria let mut query_builder = match self.get_criteria(reader, &ranked_map, &schema)? { @@ -221,9 +148,8 @@ impl<'a> SearchBuilder<'a> { } let start = Instant::now(); - let result = - query_builder.query(reader, &self.query, self.offset..(self.offset + self.limit)); - let (docs, nb_hits) = result.map_err(|e| Error::SearchDocuments(e.to_string()))?; + let result = query_builder.query(reader, &self.query, self.offset..(self.offset + self.limit)); + let (docs, nb_hits) = result.map_err(ResponseError::search_documents)?; let time_ms = start.elapsed().as_millis() as usize; let mut all_attributes: HashSet<&str> = HashSet::new(); @@ -255,11 +181,19 @@ impl<'a> SearchBuilder<'a> { let mut hits = Vec::with_capacity(self.limit); for doc in docs { + // retrieve the content of document in kv store + let attributes: Option> = self + .attributes_to_retrieve + .as_ref() + .map(|a| a.iter().map(|a| a.as_str()).collect()); + let mut document: IndexMap = self .index - .document(reader, Some(&all_attributes), doc.id) - .map_err(|e| Error::RetrieveDocument(doc.id.0, e.to_string()))? - .ok_or(Error::DocumentNotFound(doc.id.0))?; + .document(reader, attributes.as_ref(), doc.id) + .map_err(|e| ResponseError::retrieve_document(doc.id.0, e))? + .ok_or(ResponseError::internal( + "Impossible to retrieve a document id returned by the engine", + ))?; let mut formatted = document.iter() .filter(|(key, _)| all_formatted.contains(key.as_str())) @@ -320,7 +254,7 @@ impl<'a> SearchBuilder<'a> { reader: &heed::RoTxn, ranked_map: &'a RankedMap, schema: &Schema, - ) -> Result>, Error> { + ) -> Result>, ResponseError> { let ranking_rules = self.index.main.ranking_rules(reader)?; if let Some(ranking_rules) = ranking_rules { diff --git a/meilisearch-http/src/routes/document.rs b/meilisearch-http/src/routes/document.rs index 54183108f..27407fa4d 100644 --- a/meilisearch-http/src/routes/document.rs +++ b/meilisearch-http/src/routes/document.rs @@ -1,7 +1,5 @@ -use std::collections::HashSet; -use std::collections::BTreeSet; +use std::collections::{BTreeSet, HashSet}; -use actix_web as aweb; use actix_web::{delete, get, post, put, web, HttpResponse}; use indexmap::IndexMap; use serde::Deserialize; @@ -23,22 +21,18 @@ pub struct DocumentParam { pub async fn get_document( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let document_id = meilisearch_core::serde::compute_document_id(path.document_id.clone()); + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let document_id = meilisearch_core::serde::compute_document_id(&path.document_id); - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; let response = index - .document::(&reader, None, document_id) - .map_err(|_| ResponseError::DocumentNotFound(path.document_id.clone()))? - .ok_or(ResponseError::DocumentNotFound(path.document_id.clone()))?; + .document::(&reader, None, document_id)? + .ok_or(ResponseError::document_not_found(&path.document_id))?; Ok(HttpResponse::Ok().json(response)) } @@ -47,28 +41,21 @@ pub async fn get_document( pub async fn delete_document( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let document_id = meilisearch_core::serde::compute_document_id(path.document_id.clone()); + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let document_id = meilisearch_core::serde::compute_document_id(&path.document_id); - let mut update_writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut update_writer = data.db.update_write_txn()?; let mut documents_deletion = index.documents_deletion(); documents_deletion.delete_document_by_id(document_id); - let update_id = documents_deletion - .finalize(&mut update_writer) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let update_id = documents_deletion.finalize(&mut update_writer)?; - update_writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + update_writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -86,32 +73,29 @@ pub async fn get_all_documents( data: web::Data, path: web::Path, params: web::Query, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let offset = params.offset.unwrap_or(0); let limit = params.limit.unwrap_or(20); - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; let documents_ids: Result, _> = index .documents_fields_counts - .documents_ids(&reader) - .map_err(|_| ResponseError::Internal(path.index_uid.clone()))? + .documents_ids(&reader)? .skip(offset) .take(limit) .collect(); - let documents_ids = documents_ids.map_err(|err| ResponseError::Internal(err.to_string()))?; + let documents_ids = documents_ids?; let attributes: Option> = params - .attributes_to_retrieve.as_ref() + .attributes_to_retrieve + .as_ref() .map(|a| a.split(',').collect()); let mut response = Vec::::new(); @@ -145,48 +129,33 @@ async fn update_multiple_documents( params: web::Query, body: web::Json>, is_partial: bool, -) -> aweb::Result { +) -> Result { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; let mut schema = index .main - .schema(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to retrieve the schema".to_string(), - ))?; + .schema(&reader)? + .ok_or(ResponseError::internal("Impossible to retrieve the schema"))?; if schema.primary_key().is_none() { - let id = match params.primary_key.clone() { - Some(id) => id, - None => body.first().and_then(|docs| find_primary_key(docs)).ok_or( - ResponseError::BadRequest("Could not infer a primary key".to_string()), - )?, + let id = match ¶ms.primary_key { + Some(id) => id.to_string(), + None => body + .first() + .and_then(find_primary_key) + .ok_or(ResponseError::bad_request("Could not infer a primary key"))?, }; - let mut writer = data - .db - .main_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.main_write_txn()?; - schema - .set_primary_key(&id) - .map_err(|e| ResponseError::Internal(e.to_string()))?; - index - .main - .put_schema(&mut writer, &schema) - .map_err(|e| ResponseError::Internal(e.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + schema.set_primary_key(&id)?; + index.main.put_schema(&mut writer, &schema)?; + writer.commit()?; } let mut document_addition = if is_partial { @@ -199,16 +168,9 @@ async fn update_multiple_documents( document_addition.update_document(document); } - let mut update_writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let update_id = document_addition - .finalize(&mut update_writer) - .map_err(|e| ResponseError::Internal(e.to_string()))?; - update_writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut update_writer = data.db.update_write_txn()?; + let update_id = document_addition.finalize(&mut update_writer)?; + update_writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -219,7 +181,7 @@ pub async fn add_documents( path: web::Path, params: web::Query, body: web::Json>, -) -> aweb::Result { +) -> Result { update_multiple_documents(data, path, params, body, false).await } @@ -229,7 +191,7 @@ pub async fn update_documents( path: web::Path, params: web::Query, body: web::Json>, -) -> aweb::Result { +) -> Result { update_multiple_documents(data, path, params, body, true).await } @@ -238,16 +200,13 @@ pub async fn delete_documents( data: web::Data, path: web::Path, body: web::Json>, -) -> aweb::Result { +) -> Result { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; let mut documents_deletion = index.documents_deletion(); @@ -258,13 +217,9 @@ pub async fn delete_documents( } } - let update_id = documents_deletion - .finalize(&mut writer) - .map_err(|e| ResponseError::Internal(e.to_string()))?; + let update_id = documents_deletion.finalize(&mut writer)?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -273,24 +228,17 @@ pub async fn delete_documents( pub async fn clear_all_documents( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; - let update_id = index - .clear_all(&mut writer) - .map_err(|e| ResponseError::Internal(e.to_string()))?; + let update_id = index.clear_all(&mut writer)?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } diff --git a/meilisearch-http/src/routes/health.rs b/meilisearch-http/src/routes/health.rs index 8b4433303..825d79ef5 100644 --- a/meilisearch-http/src/routes/health.rs +++ b/meilisearch-http/src/routes/health.rs @@ -1,6 +1,5 @@ use crate::error::ResponseError; use crate::Data; -use actix_web as aweb; use actix_web::{get, put, web, HttpResponse}; use heed::types::{Str, Unit}; use serde::Deserialize; @@ -8,49 +7,32 @@ use serde::Deserialize; const UNHEALTHY_KEY: &str = "_is_unhealthy"; #[get("/health")] -pub async fn get_health(data: web::Data) -> aweb::Result { - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; +pub async fn get_health(data: web::Data) -> Result { + let reader = data.db.main_read_txn()?; let common_store = data.db.common_store(); if let Ok(Some(_)) = common_store.get::<_, Str, Unit>(&reader, UNHEALTHY_KEY) { - return Err(ResponseError::Maintenance.into()); + return Err(ResponseError::Maintenance); } Ok(HttpResponse::Ok().finish()) } -pub async fn set_healthy(data: web::Data) -> aweb::Result { - let mut writer = data - .db - .main_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; +pub async fn set_healthy(data: web::Data) -> Result { + let mut writer = data.db.main_write_txn()?; let common_store = data.db.common_store(); - common_store - .delete::<_, Str>(&mut writer, UNHEALTHY_KEY) - .map_err(|e| ResponseError::Internal(e.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + common_store.delete::<_, Str>(&mut writer, UNHEALTHY_KEY)?; + writer.commit()?; Ok(HttpResponse::Ok().finish()) } -pub async fn set_unhealthy(data: web::Data) -> aweb::Result { - let mut writer = data - .db - .main_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; +pub async fn set_unhealthy(data: web::Data) -> Result { + let mut writer = data.db.main_write_txn()?; let common_store = data.db.common_store(); - common_store - .put::<_, Str, Unit>(&mut writer, UNHEALTHY_KEY, &()) - .map_err(|e| ResponseError::Internal(e.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + common_store.put::<_, Str, Unit>(&mut writer, UNHEALTHY_KEY, &())?; + writer.commit()?; Ok(HttpResponse::Ok().finish()) } @@ -64,7 +46,7 @@ pub struct HealtBody { pub async fn change_healthyness( data: web::Data, body: web::Json, -) -> aweb::Result { +) -> Result { if body.health { set_healthy(data).await } else { diff --git a/meilisearch-http/src/routes/index.rs b/meilisearch-http/src/routes/index.rs index 8e6dac8ca..d46160e76 100644 --- a/meilisearch-http/src/routes/index.rs +++ b/meilisearch-http/src/routes/index.rs @@ -1,4 +1,3 @@ -use actix_web as aweb; use actix_web::{delete, get, post, put, web, HttpResponse}; use chrono::{DateTime, Utc}; use log::error; @@ -29,11 +28,8 @@ pub struct IndexResponse { } #[get("/indexes")] -pub async fn list_indexes(data: web::Data) -> aweb::Result { - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; +pub async fn list_indexes(data: web::Data) -> Result { + let reader = data.db.main_read_txn()?; let mut response = Vec::new(); @@ -42,26 +38,20 @@ pub async fn list_indexes(data: web::Data) -> aweb::Result { match index { Some(index) => { - let name = index - .main - .name(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the name of an index".to_string(), - ))?; + let name = index.main.name(&reader)?.ok_or(ResponseError::internal( + "Impossible to get the name of an index", + ))?; let created_at = index .main - .created_at(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the create date of an index".to_string(), + .created_at(&reader)? + .ok_or(ResponseError::internal( + "Impossible to get the create date of an index", ))?; let updated_at = index .main - .updated_at(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the last update date of an index".to_string(), + .updated_at(&reader)? + .ok_or(ResponseError::internal( + "Impossible to get the last update date of an index", ))?; let primary_key = match index.main.schema(&reader) { @@ -95,37 +85,28 @@ pub async fn list_indexes(data: web::Data) -> aweb::Result { pub async fn get_index( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; - let name = index - .main - .name(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the name of an index".to_string(), - ))?; + let name = index.main.name(&reader)?.ok_or(ResponseError::internal( + "Impossible to get the name of an index", + ))?; let created_at = index .main - .created_at(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the create date of an index".to_string(), + .created_at(&reader)? + .ok_or(ResponseError::internal( + "Impossible to get the create date of an index", ))?; let updated_at = index .main - .updated_at(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the last update date of an index".to_string(), + .updated_at(&reader)? + .ok_or(ResponseError::internal( + "Impossible to get the last update date of an index", ))?; let primary_key = match index.main.schema(&reader) { @@ -157,11 +138,11 @@ pub struct IndexCreateRequest { pub async fn create_index( data: web::Data, body: web::Json, -) -> aweb::Result { +) -> Result { if let (None, None) = (body.name.clone(), body.uid.clone()) { - return Err( - ResponseError::BadRequest("Index creation must have an uid".to_string()).into(), - ); + return Err(ResponseError::bad_request( + "Index creation must have an uid", + )); } let uid = match body.uid.clone() { @@ -172,7 +153,7 @@ pub async fn create_index( { uid } else { - return Err(ResponseError::InvalidIndexUid.into()); + return Err(ResponseError::InvalidIndexUid); } } None => loop { @@ -186,50 +167,33 @@ pub async fn create_index( let created_index = data .db .create_index(&uid) - .map_err(|e| ResponseError::CreateIndex(e.to_string()))?; + .map_err(ResponseError::create_index)?; - let mut writer = data - .db - .main_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.main_write_txn()?; let name = body.name.clone().unwrap_or(uid.clone()); - created_index - .main - .put_name(&mut writer, &name) - .map_err(|e| ResponseError::Internal(e.to_string()))?; + created_index.main.put_name(&mut writer, &name)?; let created_at = created_index .main - .created_at(&writer) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal("".to_string()))?; + .created_at(&writer)? + .ok_or(ResponseError::internal("Impossible to read created at"))?; let updated_at = created_index .main - .updated_at(&writer) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal("".to_string()))?; + .updated_at(&writer)? + .ok_or(ResponseError::internal("Impossible to read updated at"))?; if let Some(id) = body.primary_key.clone() { - if let Some(mut schema) = created_index - .main - .schema(&writer) - .map_err(|e| ResponseError::Internal(e.to_string()))? - { + if let Some(mut schema) = created_index.main.schema(&writer)? { schema .set_primary_key(&id) - .map_err(|e| ResponseError::BadRequest(e.to_string()))?; - created_index - .main - .put_schema(&mut writer, &schema) - .map_err(|e| ResponseError::Internal(e.to_string()))?; + .map_err(ResponseError::bad_request)?; + created_index.main.put_schema(&mut writer, &schema)?; } } - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + writer.commit()?; Ok(HttpResponse::Created().json(IndexResponse { name, @@ -262,83 +226,53 @@ pub async fn update_index( data: web::Data, path: web::Path, body: web::Json, -) -> aweb::Result { +) -> Result { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let mut writer = data - .db - .main_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.main_write_txn()?; if let Some(name) = body.name.clone() { - index - .main - .put_name(&mut writer, &name) - .map_err(|e| ResponseError::Internal(e.to_string()))?; + index.main.put_name(&mut writer, &name)?; } if let Some(id) = body.primary_key.clone() { - if let Some(mut schema) = index - .main - .schema(&writer) - .map_err(|e| ResponseError::Internal(e.to_string()))? - { + if let Some(mut schema) = index.main.schema(&writer)? { match schema.primary_key() { Some(_) => { - return Err(ResponseError::BadRequest( - "The primary key cannot be updated".to_string(), - ) - .into()); + return Err(ResponseError::bad_request( + "The primary key cannot be updated", + )); } None => { - schema - .set_primary_key(&id) - .map_err(|e| ResponseError::Internal(e.to_string()))?; - index - .main - .put_schema(&mut writer, &schema) - .map_err(|e| ResponseError::Internal(e.to_string()))?; + schema.set_primary_key(&id)?; + index.main.put_schema(&mut writer, &schema)?; } } } } - index - .main - .put_updated_at(&mut writer) - .map_err(|e| ResponseError::Internal(e.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + index.main.put_updated_at(&mut writer)?; + writer.commit()?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; - let name = index - .main - .name(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the name of an index".to_string(), - ))?; + let name = index.main.name(&reader)?.ok_or(ResponseError::internal( + "Impossible to get the name of an index", + ))?; let created_at = index .main - .created_at(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the create date of an index".to_string(), + .created_at(&reader)? + .ok_or(ResponseError::internal( + "Impossible to get the create date of an index", ))?; let updated_at = index .main - .updated_at(&reader) - .map_err(|e| ResponseError::Internal(e.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to get the last update date of an index".to_string(), + .updated_at(&reader)? + .ok_or(ResponseError::internal( + "Impossible to get the last update date of an index", ))?; let primary_key = match index.main.schema(&reader) { @@ -362,12 +296,10 @@ pub async fn update_index( pub async fn delete_index( data: web::Data, path: web::Path, -) -> aweb::Result { - data.db - .delete_index(&path.index_uid) - .map_err(|e| ResponseError::Internal(e.to_string()))?; +) -> Result { + data.db.delete_index(&path.index_uid)?; - HttpResponse::NoContent().await + Ok(HttpResponse::NoContent().finish()) } #[derive(Default, Deserialize)] @@ -380,24 +312,22 @@ pub struct UpdateParam { pub async fn get_update_status( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let reader = data - .db - .update_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.update_read_txn()?; - let status = index - .update_status(&reader, path.update_id) - .map_err(|e| ResponseError::Internal(e.to_string()))?; + let status = index.update_status(&reader, path.update_id)?; match status { Some(status) => Ok(HttpResponse::Ok().json(status)), - None => Err(ResponseError::NotFound(format!("Update {} not found", path.update_id)).into()), + None => Err(ResponseError::NotFound(format!( + "Update {} not found", + path.update_id + ))), } } @@ -405,20 +335,15 @@ pub async fn get_update_status( pub async fn get_all_updates_status( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let reader = data - .db - .update_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.update_read_txn()?; - let response = index - .all_updates_status(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let response = index.all_updates_status(&reader)?; Ok(HttpResponse::Ok().json(response)) } diff --git a/meilisearch-http/src/routes/search.rs b/meilisearch-http/src/routes/search.rs index 92112c4a4..3dcfc2a93 100644 --- a/meilisearch-http/src/routes/search.rs +++ b/meilisearch-http/src/routes/search.rs @@ -2,13 +2,11 @@ use std::collections::{HashSet, HashMap}; use std::time::Duration; use log::warn; -use meilisearch_core::Index; -use actix_web as aweb; use actix_web::{get, web}; -use serde::{Deserialize}; +use serde::Deserialize; use crate::error::ResponseError; -use crate::helpers::meilisearch::{Error, IndexSearchExt, SearchResult}; +use crate::helpers::meilisearch::{IndexSearchExt, SearchResult}; use crate::routes::IndexParam; use crate::Data; @@ -32,24 +30,18 @@ pub async fn search_with_url_query( data: web::Data, path: web::Path, params: web::Query, -) -> aweb::Result> { +) -> Result, ResponseError> { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; let schema = index .main - .schema(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))? - .ok_or(ResponseError::Internal( - "Impossible to retrieve the schema".to_string(), - ))?; + .schema(&reader)? + .ok_or(ResponseError::internal("Impossible to retrieve the schema"))?; let mut search_builder = index.new_search(params.q.clone()); @@ -145,11 +137,5 @@ pub async fn search_with_url_query( } } - let response = match search_builder.search(&reader) { - Ok(response) => response, - Err(Error::Internal(message)) => return Err(ResponseError::Internal(message).into()), - Err(others) => return Err(ResponseError::BadRequest(others.to_string()).into()), - }; - - Ok(web::Json(response)) + Ok(web::Json(search_builder.search(&reader)?)) } diff --git a/meilisearch-http/src/routes/setting.rs b/meilisearch-http/src/routes/setting.rs index ca37ee1ac..928736dd1 100644 --- a/meilisearch-http/src/routes/setting.rs +++ b/meilisearch-http/src/routes/setting.rs @@ -1,4 +1,3 @@ -use actix_web as aweb; use actix_web::{delete, get, post, web, HttpResponse}; use meilisearch_core::settings::{Settings, SettingsUpdate, UpdateState, DEFAULT_RANKING_RULES}; use std::collections::{BTreeMap, BTreeSet, HashSet}; @@ -12,26 +11,19 @@ pub async fn update_all( data: web::Data, path: web::Path, body: web::Json, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; let settings = body .into_inner() .into_update() - .map_err(|e| ResponseError::BadRequest(e.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .map_err(ResponseError::bad_request)?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -40,71 +32,42 @@ pub async fn update_all( pub async fn get_all( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; - let stop_words_fst = index - .main - .stop_words_fst(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let stop_words = stop_words_fst - .unwrap_or_default() - .stream() - .into_strs() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let stop_words_fst = index.main.stop_words_fst(&reader)?; + let stop_words = stop_words_fst.unwrap_or_default().stream().into_strs()?; let stop_words: BTreeSet = stop_words.into_iter().collect(); - let synonyms_fst = index - .main - .synonyms_fst(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))? - .unwrap_or_default(); - let synonyms_list = synonyms_fst - .stream() - .into_strs() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let synonyms_fst = index.main.synonyms_fst(&reader)?.unwrap_or_default(); + let synonyms_list = synonyms_fst.stream().into_strs()?; let mut synonyms = BTreeMap::new(); let index_synonyms = &index.synonyms; for synonym in synonyms_list { - let alternative_list = index_synonyms - .synonyms(&reader, synonym.as_bytes()) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let alternative_list = index_synonyms.synonyms(&reader, synonym.as_bytes())?; if let Some(list) = alternative_list { - let list = list - .stream() - .into_strs() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let list = list.stream().into_strs()?; synonyms.insert(synonym, list); } } let ranking_rules = index .main - .ranking_rules(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))? + .ranking_rules(&reader)? .unwrap_or(DEFAULT_RANKING_RULES.to_vec()) .into_iter() .map(|r| r.to_string()) .collect(); - let distinct_attribute = index - .main - .distinct_attribute(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let distinct_attribute = index.main.distinct_attribute(&reader)?; - let schema = index - .main - .schema(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let schema = index.main.schema(&reader)?; let searchable_attributes = schema.clone().map(|s| { s.indexed_name() @@ -139,15 +102,12 @@ pub async fn get_all( pub async fn delete_all( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let mut writer = data.db.update_write_txn()?; let settings = SettingsUpdate { ranking_rules: UpdateState::Clear, @@ -160,12 +120,8 @@ pub async fn delete_all( accept_new_fields: UpdateState::Clear, }; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -174,20 +130,16 @@ pub async fn delete_all( pub async fn get_rules( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let reader = data.db.main_read_txn()?; let ranking_rules = index .main - .ranking_rules(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))? + .ranking_rules(&reader)? .unwrap_or(DEFAULT_RANKING_RULES.to_vec()) .into_iter() .map(|r| r.to_string()) @@ -201,30 +153,21 @@ pub async fn update_rules( data: web::Data, path: web::Path, body: web::Json>>, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = Settings { ranking_rules: Some(body.into_inner()), ..Settings::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let settings = settings - .into_update() - .map_err(|e| ResponseError::BadRequest(e.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let settings = settings.into_update().map_err(ResponseError::bad_request)?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -233,28 +176,21 @@ pub async fn update_rules( pub async fn delete_rules( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let mut writer = data.db.update_write_txn()?; let settings = SettingsUpdate { ranking_rules: UpdateState::Clear, ..SettingsUpdate::default() }; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let update_id = index.settings_update(&mut writer, settings)?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -263,19 +199,13 @@ pub async fn delete_rules( pub async fn get_distinct( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let distinct_attribute = index - .main - .distinct_attribute(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let reader = data.db.main_read_txn()?; + let distinct_attribute = index.main.distinct_attribute(&reader)?; Ok(HttpResponse::Ok().json(distinct_attribute)) } @@ -285,30 +215,21 @@ pub async fn update_distinct( data: web::Data, path: web::Path, body: web::Json>, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = Settings { distinct_attribute: Some(body.into_inner()), ..Settings::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let settings = settings - .into_update() - .map_err(|e| ResponseError::BadRequest(e.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let settings = settings.into_update().map_err(ResponseError::bad_request)?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -317,28 +238,21 @@ pub async fn update_distinct( pub async fn delete_distinct( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let mut writer = data.db.update_write_txn()?; let settings = SettingsUpdate { distinct_attribute: UpdateState::Clear, ..SettingsUpdate::default() }; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let update_id = index.settings_update(&mut writer, settings)?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -347,19 +261,13 @@ pub async fn delete_distinct( pub async fn get_searchable( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let schema = index - .main - .schema(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let reader = data.db.main_read_txn()?; + let schema = index.main.schema(&reader)?; let searchable_attributes: Option> = schema.map(|s| s.indexed_name().iter().map(|i| (*i).to_string()).collect()); @@ -371,30 +279,21 @@ pub async fn update_searchable( data: web::Data, path: web::Path, body: web::Json>>, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = Settings { searchable_attributes: Some(body.into_inner()), ..Settings::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let settings = settings - .into_update() - .map_err(|e| ResponseError::BadRequest(e.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let settings = settings.into_update().map_err(ResponseError::bad_request)?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -403,27 +302,20 @@ pub async fn update_searchable( pub async fn delete_searchable( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = SettingsUpdate { searchable_attributes: UpdateState::Clear, ..SettingsUpdate::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -432,20 +324,14 @@ pub async fn delete_searchable( pub async fn get_displayed( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let reader = data.db.main_read_txn()?; - let schema = index - .main - .schema(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let schema = index.main.schema(&reader)?; let displayed_attributes: Option> = schema.map(|s| { s.displayed_name() @@ -462,30 +348,21 @@ pub async fn update_displayed( data: web::Data, path: web::Path, body: web::Json>>, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = Settings { displayed_attributes: Some(body.into_inner()), ..Settings::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let settings = settings - .into_update() - .map_err(|e| ResponseError::BadRequest(e.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let settings = settings.into_update().map_err(ResponseError::bad_request)?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -494,27 +371,20 @@ pub async fn update_displayed( pub async fn delete_displayed( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = SettingsUpdate { displayed_attributes: UpdateState::Clear, ..SettingsUpdate::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -523,20 +393,14 @@ pub async fn delete_displayed( pub async fn get_accept_new_fields( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let reader = data.db.main_read_txn()?; - let schema = index - .main - .schema(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let schema = index.main.schema(&reader)?; let accept_new_fields = schema.map(|s| s.accept_new_fields()); @@ -548,30 +412,21 @@ pub async fn update_accept_new_fields( data: web::Data, path: web::Path, body: web::Json>, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = Settings { accept_new_fields: Some(body.into_inner()), ..Settings::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let settings = settings - .into_update() - .map_err(|e| ResponseError::BadRequest(e.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let settings = settings.into_update().map_err(ResponseError::bad_request)?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } diff --git a/meilisearch-http/src/routes/stats.rs b/meilisearch-http/src/routes/stats.rs index ee804457e..9f2449e65 100644 --- a/meilisearch-http/src/routes/stats.rs +++ b/meilisearch-http/src/routes/stats.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use actix_web as aweb; use actix_web::{get, web}; use chrono::{DateTime, Utc}; use log::error; @@ -25,36 +24,22 @@ pub struct IndexStatsResponse { pub async fn index_stats( data: web::Data, path: web::Path, -) -> aweb::Result> { +) -> Result, ResponseError> { let index = data .db - .open_index(path.index_uid.clone()) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .open_index(&path.index_uid) + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; - let number_of_documents = index - .main - .number_of_documents(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let number_of_documents = index.main.number_of_documents(&reader)?; - let fields_frequency = index - .main - .fields_frequency(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))? - .unwrap_or_default(); + let fields_frequency = index.main.fields_frequency(&reader)?.unwrap_or_default(); - let update_reader = data - .db - .update_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let update_reader = data.db.update_read_txn()?; let is_indexing = data - .is_indexing(&update_reader, &path.index_uid) - .map_err(|err| ResponseError::Internal(err.to_string()))? + .is_indexing(&update_reader, &path.index_uid)? .unwrap_or_default(); Ok(web::Json(IndexStatsResponse { @@ -73,37 +58,23 @@ pub struct StatsResult { } #[get("/stats")] -pub async fn get_stats(data: web::Data) -> aweb::Result> { +pub async fn get_stats(data: web::Data) -> Result, ResponseError> { let mut index_list = HashMap::new(); - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let update_reader = data - .db - .update_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; + let update_reader = data.db.update_read_txn()?; let indexes_set = data.db.indexes_uids(); for index_uid in indexes_set { let index = data.db.open_index(&index_uid); match index { Some(index) => { - let number_of_documents = index - .main - .number_of_documents(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let number_of_documents = index.main.number_of_documents(&reader)?; - let fields_frequency = index - .main - .fields_frequency(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))? - .unwrap_or_default(); + let fields_frequency = index.main.fields_frequency(&reader)?.unwrap_or_default(); let is_indexing = data - .is_indexing(&update_reader, &index_uid) - .map_err(|err| ResponseError::Internal(err.to_string()))? + .is_indexing(&update_reader, &index_uid)? .unwrap_or_default(); let response = IndexStatsResponse { @@ -120,16 +91,14 @@ pub async fn get_stats(data: web::Data) -> aweb::Result, path: web::Path) -> aweb::Result { +pub async fn get( + data: web::Data, + path: web::Path, +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let stop_words_fst = index - .main - .stop_words_fst(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let stop_words = stop_words_fst - .unwrap_or_default() - .stream() - .into_strs() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; + let reader = data.db.main_read_txn()?; + let stop_words_fst = index.main.stop_words_fst(&reader)?; + let stop_words = stop_words_fst.unwrap_or_default().stream().into_strs()?; Ok(HttpResponse::Ok().json(stop_words)) } @@ -36,27 +27,20 @@ pub async fn update( data: web::Data, path: web::Path, body: web::Json>, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = SettingsUpdate { stop_words: UpdateState::Update(body.into_inner()), ..SettingsUpdate::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -65,27 +49,20 @@ pub async fn update( pub async fn delete( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = SettingsUpdate { stop_words: UpdateState::Clear, ..SettingsUpdate::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } diff --git a/meilisearch-http/src/routes/synonym.rs b/meilisearch-http/src/routes/synonym.rs index 7892988a6..adf76ba99 100644 --- a/meilisearch-http/src/routes/synonym.rs +++ b/meilisearch-http/src/routes/synonym.rs @@ -1,6 +1,5 @@ use std::collections::BTreeMap; -use actix_web as aweb; use actix_web::{delete, get, post, web, HttpResponse}; use indexmap::IndexMap; use meilisearch_core::settings::{SettingsUpdate, UpdateState}; @@ -10,41 +9,27 @@ use crate::routes::{IndexParam, IndexUpdateResponse}; use crate::Data; #[get("/indexes/{index_uid}/settings/synonyms")] -pub async fn get(data: web::Data, path: web::Path) -> aweb::Result { +pub async fn get( + data: web::Data, + path: web::Path, +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; - let reader = data - .db - .main_read_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let reader = data.db.main_read_txn()?; - let synonyms_fst = index - .main - .synonyms_fst(&reader) - .map_err(|err| ResponseError::Internal(err.to_string()))? - .unwrap_or_default(); - let synonyms_list = synonyms_fst - .stream() - .into_strs() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let synonyms_fst = index.main.synonyms_fst(&reader)?.unwrap_or_default(); + let synonyms_list = synonyms_fst.stream().into_strs()?; let mut synonyms = IndexMap::new(); - let index_synonyms = &index.synonyms; - for synonym in synonyms_list { - let alternative_list = index_synonyms - .synonyms(&reader, synonym.as_bytes()) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let alternative_list = index_synonyms.synonyms(&reader, synonym.as_bytes())?; if let Some(list) = alternative_list { - let list = list - .stream() - .into_strs() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let list = list.stream().into_strs()?; synonyms.insert(synonym, list); } } @@ -57,27 +42,20 @@ pub async fn update( data: web::Data, path: web::Path, body: web::Json>>, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = SettingsUpdate { synonyms: UpdateState::Update(body.into_inner()), ..SettingsUpdate::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let update_id = index.settings_update(&mut writer, settings)?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) } @@ -86,28 +64,21 @@ pub async fn update( pub async fn delete( data: web::Data, path: web::Path, -) -> aweb::Result { +) -> Result { let index = data .db .open_index(&path.index_uid) - .ok_or(ResponseError::IndexNotFound(path.index_uid.clone()))?; + .ok_or(ResponseError::index_not_found(&path.index_uid))?; let settings = SettingsUpdate { synonyms: UpdateState::Clear, ..SettingsUpdate::default() }; - let mut writer = data - .db - .update_write_txn() - .map_err(|err| ResponseError::Internal(err.to_string()))?; - let update_id = index - .settings_update(&mut writer, settings) - .map_err(|err| ResponseError::Internal(err.to_string()))?; + let mut writer = data.db.update_write_txn()?; + let update_id = index.settings_update(&mut writer, settings)?; - writer - .commit() - .map_err(|err| ResponseError::Internal(err.to_string()))?; + writer.commit()?; Ok(HttpResponse::Accepted().json(IndexUpdateResponse::with_id(update_id))) }