mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-01-19 01:18:31 +08:00
Draft implementation of filter support for /delete-by-batch route
This commit is contained in:
parent
1afde4fea5
commit
05cc463fbc
@ -17,6 +17,7 @@ use meilisearch_types::error::{Code, ResponseError};
|
||||
use meilisearch_types::heed::RoTxn;
|
||||
use meilisearch_types::index_uid::IndexUid;
|
||||
use meilisearch_types::milli::update::IndexDocumentsMethod;
|
||||
use meilisearch_types::milli::InternalError;
|
||||
use meilisearch_types::star_or::OptionStarOrList;
|
||||
use meilisearch_types::tasks::KindWithContent;
|
||||
use meilisearch_types::{milli, Document, Index};
|
||||
@ -373,22 +374,96 @@ async fn document_addition(
|
||||
Ok(task.into())
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DocumentDeletionQuery {
|
||||
Ids(Vec<Value>),
|
||||
Object { filter: Option<Value> },
|
||||
}
|
||||
|
||||
/// Parses a Json encoded document id and validate it, returning a user error when it is one.
|
||||
/// FIXME: stolen from milli
|
||||
fn validate_document_id_value(document_id: Value) -> String {
|
||||
match document_id {
|
||||
Value::String(string) => match validate_document_id(&string) {
|
||||
Some(s) if s.len() == string.len() => string,
|
||||
Some(s) => s.to_string(),
|
||||
None => panic!(),
|
||||
},
|
||||
Value::Number(number) if number.is_i64() => number.to_string(),
|
||||
_content => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// FIXME: stolen from milli
|
||||
fn validate_document_id(document_id: &str) -> Option<&str> {
|
||||
if !document_id.is_empty()
|
||||
&& document_id.chars().all(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_'))
|
||||
{
|
||||
Some(document_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete_documents(
|
||||
index_scheduler: GuardedData<ActionPolicy<{ actions::DOCUMENTS_DELETE }>, Data<IndexScheduler>>,
|
||||
index_uid: web::Path<String>,
|
||||
body: web::Json<Vec<Value>>,
|
||||
body: web::Json<DocumentDeletionQuery>,
|
||||
req: HttpRequest,
|
||||
analytics: web::Data<dyn Analytics>,
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
debug!("called with params: {:?}", body);
|
||||
let index_uid = IndexUid::try_from(index_uid.into_inner())?;
|
||||
let index_uid = index_uid.into_inner();
|
||||
|
||||
analytics.delete_documents(DocumentDeletionKind::PerBatch, &req);
|
||||
|
||||
let ids = body
|
||||
.iter()
|
||||
.map(|v| v.as_str().map(String::from).unwrap_or_else(|| v.to_string()))
|
||||
.collect();
|
||||
let ids = match body.into_inner() {
|
||||
DocumentDeletionQuery::Ids(body) => body
|
||||
.iter()
|
||||
.map(|v| v.as_str().map(String::from).unwrap_or_else(|| v.to_string()))
|
||||
.collect(),
|
||||
DocumentDeletionQuery::Object { filter } => {
|
||||
debug!("filter: {:?}", filter);
|
||||
|
||||
// FIXME: spawn_blocking
|
||||
if let Some(ref filter) = filter {
|
||||
if let Some(facets) = crate::search::parse_filter(filter)? {
|
||||
debug!("facets: {:?}", facets);
|
||||
|
||||
let index = index_scheduler.index(&index_uid)?;
|
||||
let rtxn = index.read_txn()?;
|
||||
let filtered_candidates = facets.evaluate(&rtxn, &index)?;
|
||||
debug!("filtered_candidates.len(): {:?}", filtered_candidates.len());
|
||||
|
||||
// FIXME: unwraps
|
||||
let primary_key = index.primary_key(&rtxn)?.unwrap();
|
||||
let primary_key = index.fields_ids_map(&rtxn)?.id(primary_key).unwrap();
|
||||
|
||||
let documents = index.documents(&rtxn, filtered_candidates.into_iter())?;
|
||||
debug!("documents.len(): {:?}", documents.len());
|
||||
let documents: Vec<String> = documents
|
||||
.into_iter()
|
||||
.map(|(_, document)| {
|
||||
let value = document.get(primary_key).unwrap();
|
||||
let value: Value = serde_json::from_slice(value)
|
||||
.map_err(InternalError::SerdeJson)
|
||||
.unwrap();
|
||||
|
||||
validate_document_id_value(value)
|
||||
})
|
||||
.collect();
|
||||
debug!("documents: {:?}", documents);
|
||||
documents
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let task =
|
||||
KindWithContent::DocumentDeletion { index_uid: index_uid.to_string(), documents_ids: ids };
|
||||
|
@ -745,7 +745,7 @@ fn format_value<A: AsRef<[u8]>>(
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_filter(facets: &Value) -> Result<Option<Filter>, MeilisearchHttpError> {
|
||||
pub fn parse_filter(facets: &Value) -> Result<Option<Filter>, MeilisearchHttpError> {
|
||||
match facets {
|
||||
Value::String(expr) => {
|
||||
let condition = Filter::from_str(expr)?;
|
||||
|
Loading…
Reference in New Issue
Block a user