Skip to content

Commit f438731

Browse files
meili-bors[bot]meili-botbidoubiwa
authored
Merge #472
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 <[email protected]> Co-authored-by: Charlotte Vermandel <[email protected]> Co-authored-by: cvermand <[email protected]>
2 parents cd3021c + 0b5d7e9 commit f438731

File tree

3 files changed

+147
-2
lines changed

3 files changed

+147
-2
lines changed

src/documents.rs

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::task_info::TaskInfo;
12
use async_trait::async_trait;
23
use serde::{de::DeserializeOwned, Deserialize, Serialize};
34

@@ -314,6 +315,35 @@ impl<'a> DocumentsQuery<'a> {
314315
}
315316
}
316317

318+
#[derive(Debug, Clone, Serialize)]
319+
pub struct DocumentDeletionQuery<'a> {
320+
#[serde(skip_serializing)]
321+
pub index: &'a Index,
322+
323+
/// Filters to apply.
324+
///
325+
/// Read the [dedicated guide](https://docs.meilisearch.com/reference/features/filtering.html) to learn the syntax.
326+
pub filter: Option<&'a str>,
327+
}
328+
329+
impl<'a> DocumentDeletionQuery<'a> {
330+
pub fn new(index: &Index) -> DocumentDeletionQuery {
331+
DocumentDeletionQuery {
332+
index,
333+
filter: None,
334+
}
335+
}
336+
337+
pub fn with_filter<'b>(&'b mut self, filter: &'a str) -> &'b mut DocumentDeletionQuery<'a> {
338+
self.filter = Some(filter);
339+
self
340+
}
341+
342+
pub async fn execute<T: DeserializeOwned + 'static>(&self) -> Result<TaskInfo, Error> {
343+
self.index.delete_documents_with(self).await
344+
}
345+
}
346+
317347
#[cfg(test)]
318348
mod tests {
319349
use super::*;
@@ -383,7 +413,6 @@ mod tests {
383413
#[meilisearch_test]
384414
async fn test_get_documents_with_execute(client: Client, index: Index) -> Result<(), Error> {
385415
setup_test_index(&client, &index).await?;
386-
// let documents = index.get_documents(None, None, None).await.unwrap();
387416
let documents = DocumentsQuery::new(&index)
388417
.with_limit(1)
389418
.with_offset(1)
@@ -399,6 +428,66 @@ mod tests {
399428
Ok(())
400429
}
401430

431+
#[meilisearch_test]
432+
async fn test_delete_documents_with(client: Client, index: Index) -> Result<(), Error> {
433+
setup_test_index(&client, &index).await?;
434+
index
435+
.set_filterable_attributes(["id"])
436+
.await?
437+
.wait_for_completion(&client, None, None)
438+
.await?;
439+
440+
let mut query = DocumentDeletionQuery::new(&index);
441+
query.with_filter("id = 1");
442+
index
443+
.delete_documents_with(&query)
444+
.await?
445+
.wait_for_completion(&client, None, None)
446+
.await?;
447+
let document_result = index.get_document::<MyObject>("1").await;
448+
449+
match document_result {
450+
Ok(_) => panic!("The test was expecting no documents to be returned but got one."),
451+
Err(e) => match e {
452+
Error::Meilisearch(err) => {
453+
assert_eq!(err.error_code, ErrorCode::DocumentNotFound);
454+
}
455+
_ => panic!("The error was expected to be a Meilisearch error, but it was not."),
456+
},
457+
}
458+
459+
Ok(())
460+
}
461+
462+
#[meilisearch_test]
463+
async fn test_delete_documents_with_filter_not_filterable(
464+
client: Client,
465+
index: Index,
466+
) -> Result<(), Error> {
467+
setup_test_index(&client, &index).await?;
468+
469+
let mut query = DocumentDeletionQuery::new(&index);
470+
query.with_filter("id = 1");
471+
let error = index
472+
.delete_documents_with(&query)
473+
.await?
474+
.wait_for_completion(&client, None, None)
475+
.await?;
476+
477+
let error = error.unwrap_failure();
478+
479+
assert!(matches!(
480+
error,
481+
MeilisearchError {
482+
error_code: ErrorCode::InvalidDocumentFilter,
483+
error_type: ErrorType::InvalidRequest,
484+
..
485+
}
486+
));
487+
488+
Ok(())
489+
}
490+
402491
#[meilisearch_test]
403492
async fn test_get_documents_with_only_one_param(
404493
client: Client,

src/indexes.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
client::Client,
3-
documents::{DocumentQuery, DocumentsQuery, DocumentsResults},
3+
documents::{DocumentDeletionQuery, DocumentQuery, DocumentsQuery, DocumentsResults},
44
errors::{Error, MeilisearchCommunicationError, MeilisearchError, MEILISEARCH_VERSION_HINT},
55
request::*,
66
search::*,
@@ -959,6 +959,61 @@ impl Index {
959959
.await
960960
}
961961

962+
/// Delete a selection of documents with filters.
963+
///
964+
/// # Example
965+
///
966+
/// ```
967+
/// # use serde::{Serialize, Deserialize};
968+
/// # use meilisearch_sdk::{client::*, documents::*};
969+
/// #
970+
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
971+
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
972+
/// #
973+
/// # #[derive(Serialize, Deserialize, Debug)]
974+
/// # struct Movie {
975+
/// # name: String,
976+
/// # id: String,
977+
/// # }
978+
/// #
979+
/// #
980+
/// # futures::executor::block_on(async move {
981+
/// #
982+
/// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY));
983+
/// let index = client.index("delete_documents_with");
984+
/// #
985+
/// # index.set_filterable_attributes(["id"]);
986+
/// # // add some documents
987+
/// # 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();
988+
///
989+
/// let mut query = DocumentDeletionQuery::new(&index);
990+
/// query.with_filter("id = 1");
991+
/// // delete some documents
992+
/// index.delete_documents_with(&query)
993+
/// .await
994+
/// .unwrap()
995+
/// .wait_for_completion(&client, None, None)
996+
/// .await
997+
/// .unwrap();
998+
/// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
999+
/// # });
1000+
/// ```
1001+
pub async fn delete_documents_with(
1002+
&self,
1003+
query: &DocumentDeletionQuery<'_>,
1004+
) -> Result<TaskInfo, Error> {
1005+
request::<(), &DocumentDeletionQuery, TaskInfo>(
1006+
&format!("{}/indexes/{}/documents/delete", self.client.host, self.uid),
1007+
self.client.get_api_key(),
1008+
Method::Post {
1009+
query: (),
1010+
body: query,
1011+
},
1012+
202,
1013+
)
1014+
.await
1015+
}
1016+
9621017
/// Alias for the [Index::update] method.
9631018
pub async fn set_primary_key(
9641019
&mut self,

src/tasks.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub struct DocumentAdditionOrUpdate {
6666
pub struct DocumentDeletion {
6767
pub provided_ids: Option<usize>,
6868
pub deleted_documents: Option<usize>,
69+
pub original_filter: Option<String>,
6970
}
7071

7172
#[derive(Debug, Clone, Deserialize)]

0 commit comments

Comments
 (0)