Skip to content

Commit

Permalink
Merge #472
Browse files Browse the repository at this point in the history
472: Add delete_documents_with method for Meilisearch v1.2 r=bidoubiwa a=bidoubiwa

following this spec: meilisearch/specifications#236

- Add a method `index.delete_documents_with`  that lets you select a range of documents to delete based on the provided filters.


Co-authored-by: meili-bot <74670311+meili-bot@users.noreply.github.com>
Co-authored-by: Charlotte Vermandel <charlottevermandel@gmail.com>
Co-authored-by: cvermand <33010418+bidoubiwa@users.noreply.github.com>
  • Loading branch information
4 people committed May 31, 2023
2 parents cd3021c + 0b5d7e9 commit ff49da8
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 2 deletions.
91 changes: 90 additions & 1 deletion src/documents.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::task_info::TaskInfo;
use async_trait::async_trait;
use serde::{de::DeserializeOwned, Deserialize, Serialize};

Expand Down Expand Up @@ -314,6 +315,35 @@ impl<'a> DocumentsQuery<'a> {
}
}

#[derive(Debug, Clone, Serialize)]
pub struct DocumentDeletionQuery<'a> {
#[serde(skip_serializing)]
pub index: &'a Index,

/// Filters to apply.
///
/// Read the [dedicated guide](https://docs.meilisearch.com/reference/features/filtering.html) to learn the syntax.
pub filter: Option<&'a str>,
}

impl<'a> DocumentDeletionQuery<'a> {
pub fn new(index: &Index) -> DocumentDeletionQuery {
DocumentDeletionQuery {
index,
filter: None,
}
}

pub fn with_filter<'b>(&'b mut self, filter: &'a str) -> &'b mut DocumentDeletionQuery<'a> {
self.filter = Some(filter);
self
}

pub async fn execute<T: DeserializeOwned + 'static>(&self) -> Result<TaskInfo, Error> {
self.index.delete_documents_with(self).await
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -383,7 +413,6 @@ mod tests {
#[meilisearch_test]
async fn test_get_documents_with_execute(client: Client, index: Index) -> Result<(), Error> {
setup_test_index(&client, &index).await?;
// let documents = index.get_documents(None, None, None).await.unwrap();
let documents = DocumentsQuery::new(&index)
.with_limit(1)
.with_offset(1)
Expand All @@ -399,6 +428,66 @@ mod tests {
Ok(())
}

#[meilisearch_test]
async fn test_delete_documents_with(client: Client, index: Index) -> Result<(), Error> {
setup_test_index(&client, &index).await?;
index
.set_filterable_attributes(["id"])
.await?
.wait_for_completion(&client, None, None)
.await?;

let mut query = DocumentDeletionQuery::new(&index);
query.with_filter("id = 1");
index
.delete_documents_with(&query)
.await?
.wait_for_completion(&client, None, None)
.await?;
let document_result = index.get_document::<MyObject>("1").await;

match document_result {
Ok(_) => panic!("The test was expecting no documents to be returned but got one."),
Err(e) => match e {
Error::Meilisearch(err) => {
assert_eq!(err.error_code, ErrorCode::DocumentNotFound);
}
_ => panic!("The error was expected to be a Meilisearch error, but it was not."),
},
}

Ok(())
}

#[meilisearch_test]
async fn test_delete_documents_with_filter_not_filterable(
client: Client,
index: Index,
) -> Result<(), Error> {
setup_test_index(&client, &index).await?;

let mut query = DocumentDeletionQuery::new(&index);
query.with_filter("id = 1");
let error = index
.delete_documents_with(&query)
.await?
.wait_for_completion(&client, None, None)
.await?;

let error = error.unwrap_failure();

assert!(matches!(
error,
MeilisearchError {
error_code: ErrorCode::InvalidDocumentFilter,
error_type: ErrorType::InvalidRequest,
..
}
));

Ok(())
}

#[meilisearch_test]
async fn test_get_documents_with_only_one_param(
client: Client,
Expand Down
57 changes: 56 additions & 1 deletion src/indexes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
client::Client,
documents::{DocumentQuery, DocumentsQuery, DocumentsResults},
documents::{DocumentDeletionQuery, DocumentQuery, DocumentsQuery, DocumentsResults},
errors::{Error, MeilisearchCommunicationError, MeilisearchError, MEILISEARCH_VERSION_HINT},
request::*,
search::*,
Expand Down Expand Up @@ -959,6 +959,61 @@ impl Index {
.await
}

/// Delete a selection of documents with filters.
///
/// # Example
///
/// ```
/// # use serde::{Serialize, Deserialize};
/// # use meilisearch_sdk::{client::*, documents::*};
/// #
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
/// #
/// # #[derive(Serialize, Deserialize, Debug)]
/// # struct Movie {
/// # name: String,
/// # id: String,
/// # }
/// #
/// #
/// # futures::executor::block_on(async move {
/// #
/// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY));
/// let index = client.index("delete_documents_with");
/// #
/// # index.set_filterable_attributes(["id"]);
/// # // add some documents
/// # index.add_or_replace(&[Movie{id:String::from("1"), name: String::from("First movie") }, Movie{id:String::from("1"), name: String::from("First movie") }], Some("id")).await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
///
/// let mut query = DocumentDeletionQuery::new(&index);
/// query.with_filter("id = 1");
/// // delete some documents
/// index.delete_documents_with(&query)
/// .await
/// .unwrap()
/// .wait_for_completion(&client, None, None)
/// .await
/// .unwrap();
/// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
/// # });
/// ```
pub async fn delete_documents_with(
&self,
query: &DocumentDeletionQuery<'_>,
) -> Result<TaskInfo, Error> {
request::<(), &DocumentDeletionQuery, TaskInfo>(
&format!("{}/indexes/{}/documents/delete", self.client.host, self.uid),
self.client.get_api_key(),
Method::Post {
query: (),
body: query,
},
202,
)
.await
}

/// Alias for the [Index::update] method.
pub async fn set_primary_key(
&mut self,
Expand Down
1 change: 1 addition & 0 deletions src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub struct DocumentAdditionOrUpdate {
pub struct DocumentDeletion {
pub provided_ids: Option<usize>,
pub deleted_documents: Option<usize>,
pub original_filter: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
Expand Down

0 comments on commit ff49da8

Please sign in to comment.