Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 145 additions & 3 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use crate::{
key::{Key, KeyBuilder, KeyUpdater, KeysQuery, KeysResults},
request::*,
task_info::TaskInfo,
tasks::{Task, TasksCancelQuery, TasksResults, TasksSearchQuery},
tasks::{Task, TasksCancelQuery, TasksDeleteQuery, TasksResults, TasksSearchQuery},
utils::async_sleep,
};
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::{collections::HashMap, time::Duration};
use time::OffsetDateTime;
Expand All @@ -19,6 +19,11 @@ pub struct Client {
pub(crate) api_key: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SwapIndexes {
pub indexes: (String, String),
}

impl Client {
/// Create a client using the specified server.
/// Don't put a '/' at the end of the host.
Expand Down Expand Up @@ -329,6 +334,56 @@ impl Client {
self.list_all_indexes_raw_with(indexes_query).await
}

/// Swaps a list of two [Index]'es.
///
/// # Example
///
/// ```
/// # use meilisearch_sdk::{client::*, indexes::*};
/// #
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
/// #
/// # futures::executor::block_on(async move {
/// // Create the client
/// let client = Client::new(MEILISEARCH_URL, MEILISEARCH_API_KEY);
///
/// let task_index_1 = client.create_index("swap_index_1", None).await.unwrap();
/// let task_index_2 = client.create_index("swap_index_2", None).await.unwrap();
///
/// // Wait for the task to complete
/// task_index_2.wait_for_completion(&client, None, None).await.unwrap();
///
/// let task = client
/// .swap_indexes([&SwapIndexes {
/// indexes: (
/// "swap_index_1".to_string(),
/// "swap_index_2".to_string(),
/// ),
/// }])
/// .await
/// .unwrap();
///
/// # client.index("swap_index_1").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
/// # client.index("swap_index_2").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
/// # });
/// ```
pub async fn swap_indexes(
&self,
indexes: impl IntoIterator<Item = &SwapIndexes>,
) -> Result<TaskInfo, Error> {
request::<(), Vec<&SwapIndexes>, TaskInfo>(
&format!("{}/swap-indexes", self.host),
&self.api_key,
Method::Post {
query: (),
body: indexes.into_iter().collect(),
},
202,
)
.await
}

/// Get stats of all indexes.
///
/// # Example
Expand Down Expand Up @@ -788,7 +843,7 @@ impl Client {
/// # let client = client::Client::new(MEILISEARCH_URL, MEILISEARCH_API_KEY);
///
/// let mut query = tasks::TasksCancelQuery::new(&client);
/// query.with_index_uids(["get_tasks_with"]);
/// query.with_index_uids(["movies"]);
///
/// let res = client.cancel_tasks_with(&query).await.unwrap();
/// # });
Expand All @@ -811,6 +866,40 @@ impl Client {
Ok(tasks)
}

/// Delete tasks with filters [TasksDeleteQuery]
///
/// # Example
///
/// ```
/// # use meilisearch_sdk::*;
/// #
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
/// #
/// # futures::executor::block_on(async move {
/// # let client = client::Client::new(MEILISEARCH_URL, MEILISEARCH_API_KEY);
///
/// let mut query = tasks::TasksDeleteQuery::new(&client);
/// query.with_index_uids(["movies"]);
///
/// let res = client.delete_tasks_with(&query).await.unwrap();
/// # });
/// ```
pub async fn delete_tasks_with(
&self,
filters: &TasksDeleteQuery<'_>,
) -> Result<TaskInfo, Error> {
let tasks = request::<&TasksDeleteQuery, (), TaskInfo>(
&format!("{}/tasks", self.host),
&self.api_key,
Method::Delete { query: filters },
200,
)
.await?;

Ok(tasks)
}

/// Get all tasks from the server.
///
/// # Example
Expand Down Expand Up @@ -927,6 +1016,59 @@ mod tests {
use std::mem;
use time::OffsetDateTime;

#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Document {
id: String,
}

#[meilisearch_test]
async fn test_swapping_two_indexes(client: Client) {
let index_1 = client.index("test_swapping_two_indexes_1");
let index_2 = client.index("test_swapping_two_indexes_2");

let t0 = index_1
.add_documents(
&[Document {
id: "1".to_string(),
}],
None,
)
.await
.unwrap();

index_2
.add_documents(
&[Document {
id: "2".to_string(),
}],
None,
)
.await
.unwrap();

t0.wait_for_completion(&client, None, None).await.unwrap();

let task = client
.swap_indexes([&SwapIndexes {
indexes: (
"test_swapping_two_indexes_1".to_string(),
"test_swapping_two_indexes_2".to_string(),
),
}])
.await
.unwrap();
task.wait_for_completion(&client, None, None).await.unwrap();

let document = index_1.get_document("2").await.unwrap();

assert_eq!(
Document {
id: "2".to_string()
},
document
);
}

#[meilisearch_test]
async fn test_methods_has_qualified_version_as_header() {
let mock_server_url = &mockito::server_url();
Expand Down
91 changes: 90 additions & 1 deletion src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use time::OffsetDateTime;

use crate::{
client::Client, errors::Error, errors::MeilisearchError, indexes::Index, settings::Settings,
task_info::TaskInfo,
task_info::TaskInfo, SwapIndexes,
};

#[derive(Debug, Clone, Deserialize)]
Expand Down Expand Up @@ -32,9 +32,15 @@ pub enum TaskType {
DumpCreation {
details: Option<DumpCreation>,
},
IndexSwap {
details: Option<IndexSwap>,
},
TaskCancelation {
details: Option<TaskCancelation>,
},
TaskDeletion {
details: Option<TaskDeletion>,
},
SnapshotCreation {
details: Option<SnapshotCreation>,
},
Expand Down Expand Up @@ -89,6 +95,12 @@ pub struct DumpCreation {
pub dump_uid: Option<String>,
}

#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IndexSwap {
pub swaps: Vec<SwapIndexes>,
}

#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskCancelation {
Expand All @@ -97,6 +109,14 @@ pub struct TaskCancelation {
pub original_filters: String,
}

#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TaskDeletion {
pub matched_tasks: usize,
pub deleted_tasks: usize,
pub original_filters: String,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct FailedTask {
Expand Down Expand Up @@ -433,8 +453,12 @@ pub struct TasksPaginationFilters {
#[derive(Debug, Serialize, Clone)]
pub struct TasksCancelFilters {}

#[derive(Debug, Serialize, Clone)]
pub struct TasksDeleteFilters {}

pub type TasksSearchQuery<'a> = TasksQuery<'a, TasksPaginationFilters>;
pub type TasksCancelQuery<'a> = TasksQuery<'a, TasksCancelFilters>;
pub type TasksDeleteQuery<'a> = TasksQuery<'a, TasksDeleteFilters>;

#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -591,6 +615,29 @@ impl<'a> TasksQuery<'a, TasksCancelFilters> {
}
}

impl<'a> TasksQuery<'a, TasksDeleteFilters> {
pub fn new(client: &'a Client) -> TasksQuery<'a, TasksDeleteFilters> {
TasksQuery {
client,
index_uids: None,
statuses: None,
task_types: None,
uids: None,
before_enqueued_at: None,
after_enqueued_at: None,
before_started_at: None,
after_started_at: None,
before_finished_at: None,
after_finished_at: None,
pagination: TasksDeleteFilters {},
}
}

pub async fn execute(&'a self) -> Result<TaskInfo, Error> {
self.client.delete_tasks_with(self).await
}
}

impl<'a> TasksQuery<'a, TasksPaginationFilters> {
pub fn new(client: &'a Client) -> TasksQuery<'a, TasksPaginationFilters> {
TasksQuery {
Expand Down Expand Up @@ -982,4 +1029,46 @@ mod test {
mock_res.assert();
Ok(())
}

#[meilisearch_test]
async fn test_delete_tasks_with_params() -> Result<(), Error> {
let mock_server_url = &mockito::server_url();
let client = Client::new(mock_server_url, "masterKey");
let path = "/tasks?indexUids=movies,test&statuses=equeued&types=documentDeletion&uids=1";

let mock_res = mock("DELETE", path).with_status(200).create();

let mut query = TasksDeleteQuery::new(&client);
query
.with_index_uids(["movies", "test"])
.with_statuses(["equeued"])
.with_types(["documentDeletion"])
.with_uids([&1]);

let _ = client.delete_tasks_with(&query).await;

mock_res.assert();
Ok(())
}

#[meilisearch_test]
async fn test_delete_tasks_with_params_execute() -> Result<(), Error> {
let mock_server_url = &mockito::server_url();
let client = Client::new(mock_server_url, "masterKey");
let path = "/tasks?indexUids=movies,test&statuses=equeued&types=documentDeletion&uids=1";

let mock_res = mock("DELETE", path).with_status(200).create();

let mut query = TasksDeleteQuery::new(&client);
let _ = query
.with_index_uids(["movies", "test"])
.with_statuses(["equeued"])
.with_types(["documentDeletion"])
.with_uids([&1])
.execute()
.await;

mock_res.assert();
Ok(())
}
}