From a37ffd32d284a20523a1cd3d9594365ab6e17f09 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Thu, 7 Jul 2022 23:07:18 +0200 Subject: [PATCH 01/53] Update task api v0.28.0 --- .code-samples.meilisearch.yaml | 86 ++++++------ meilisearch-test-macro/README.md | 4 +- src/client.rs | 39 +++--- src/indexes.rs | 66 +++++---- src/lib.rs | 4 + src/settings.rs | 74 +++++------ src/task_info.rs | 221 +++++++++++++++++++++++++++++++ src/tasks.rs | 172 +++++++++--------------- src/utils.rs | 45 +++++++ 9 files changed, 468 insertions(+), 243 deletions(-) create mode 100644 src/task_info.rs create mode 100644 src/utils.rs diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index d19f3d34..b8f9bddf 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -18,7 +18,7 @@ get_one_document_1: |- get_documents_1: |- let documents: Vec = client.index("movies").get_documents(None, Some(2), None).await.unwrap(); add_or_replace_documents_1: |- - let task: Task = client.index("movies").add_or_replace(&[ + let task: TaskInfo = client.index("movies").add_or_replace(&[ Movie { id: 287947, title: "Shazam".to_string(), @@ -35,18 +35,18 @@ add_or_update_documents_1: |- title: String } - let task: Task = client.index("movies").add_or_update(&[ + let task: TaskInfo = client.index("movies").add_or_update(&[ IncompleteMovie { id: 287947, title: "Shazam ⚡️".to_string() } ], None).await.unwrap(); delete_all_documents_1: |- - let task: Task = client.index("movies").delete_all_documents().await.unwrap(); + let task: TaskInfo = client.index("movies").delete_all_documents().await.unwrap(); delete_one_document_1: |- - let task: Task = client.index("movies").delete_document(25684).await.unwrap(); + let task: TaskInfo = client.index("movies").delete_document(25684).await.unwrap(); delete_documents_1: |- - let task: Task = client.index("movies").delete_documents(&[23488, 153738, 437035, 363869]).await.unwrap(); + let task: TaskInfo = client.index("movies").delete_documents(&[23488, 153738, 437035, 363869]).await.unwrap(); search_post_1: |- let results: SearchResults = client.index("movies") .search() @@ -55,13 +55,13 @@ search_post_1: |- .await .unwrap(); get_task_by_index_1: |- - let task: Task = client.index("movies").get_task(1).await.unwrap(); + let task: TaskInfo = client.index("movies").get_task(1).await.unwrap(); get_all_tasks_by_index_1: |- - let tasks: Vec = client.index("movies").get_tasks().await.unwrap(); + let tasks: TasksResults = client.index("movies").get_tasks().await.unwrap(); get_all_tasks_1: |- - let tasks: Vec = client.get_tasks().await.unwrap(); + let tasks: TasksResults = client.get_tasks().await.unwrap(); get_task_1: |- - let task: Task = client.get_task(1).await.unwrap(); + let task: TaskInfo = client.get_task(1).await.unwrap(); get_settings_1: |- let settings: Settings = client.index("movies").get_settings().await.unwrap(); update_settings_1: |- @@ -103,9 +103,9 @@ update_settings_1: |- ]) .with_synonyms(synonyms); - let task: Task = client.index("movies").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("movies").set_settings(&settings).await.unwrap(); reset_settings_1: |- - let task: Task = client.index("movies").reset_settings().await.unwrap(); + let task: TaskInfo = client.index("movies").reset_settings().await.unwrap(); get_synonyms_1: |- let synonyms: HashMap> = client.index("movies").get_synonyms().await.unwrap(); update_synonyms_1: |- @@ -114,16 +114,16 @@ update_synonyms_1: |- synonyms.insert(String::from("logan"), vec![String::from("xmen"), String::from("wolverine")]); synonyms.insert(String::from("wow"), vec![String::from("world of warcraft")]); - let task: Task = client.index("movies").set_synonyms(&synonyms).await.unwrap(); + let task: TaskInfo = client.index("movies").set_synonyms(&synonyms).await.unwrap(); reset_synonyms_1: |- - let task: Task = client.index("movies").reset_synonyms().await.unwrap(); + let task: TaskInfo = client.index("movies").reset_synonyms().await.unwrap(); get_stop_words_1: |- let stop_words: Vec = client.index("movies").get_stop_words().await.unwrap(); update_stop_words_1: |- let stop_words = ["of", "the", "to"]; - let task: Task = client.index("movies").set_stop_words(&stop_words).await.unwrap(); + let task: TaskInfo = client.index("movies").set_stop_words(&stop_words).await.unwrap(); reset_stop_words_1: |- - let task: Task = client.index("movies").reset_stop_words().await.unwrap(); + let task: TaskInfo = client.index("movies").reset_stop_words().await.unwrap(); get_ranking_rules_1: |- let ranking_rules: Vec = client.index("movies").get_ranking_rules().await.unwrap(); update_ranking_rules_1: |- @@ -138,15 +138,15 @@ update_ranking_rules_1: |- "rank:desc", ]; - let task: Task = client.index("movies").set_ranking_rules(&ranking_rules).await.unwrap(); + let task: TaskInfo = client.index("movies").set_ranking_rules(&ranking_rules).await.unwrap(); reset_ranking_rules_1: |- - let task: Task = client.index("movies").reset_ranking_rules().await.unwrap(); + let task: TaskInfo = client.index("movies").reset_ranking_rules().await.unwrap(); get_distinct_attribute_1: |- let distinct_attribute: Option = client.index("shoes").get_distinct_attribute().await.unwrap(); update_distinct_attribute_1: |- - let task: Task = client.index("shoes").set_distinct_attribute("skuid").await.unwrap(); + let task: TaskInfo = client.index("shoes").set_distinct_attribute("skuid").await.unwrap(); reset_distinct_attribute_1: |- - let task: Task = client.index("shoes").reset_distinct_attribute().await.unwrap(); + let task: TaskInfo = client.index("shoes").reset_distinct_attribute().await.unwrap(); get_searchable_attributes_1: |- let searchable_attributes: Vec = client.index("movies").get_searchable_attributes().await.unwrap(); update_searchable_attributes_1: |- @@ -156,9 +156,9 @@ update_searchable_attributes_1: |- "genres" ]; - let task: Task = client.index("movies").set_searchable_attributes(&searchable_attributes).await.unwrap(); + let task: TaskInfo = client.index("movies").set_searchable_attributes(&searchable_attributes).await.unwrap(); reset_searchable_attributes_1: |- - let task: Task = client.index("movies").reset_searchable_attributes().await.unwrap(); + let task: TaskInfo = client.index("movies").reset_searchable_attributes().await.unwrap(); get_filterable_attributes_1: |- let filterable_attributes: Vec = client.index("movies").get_filterable_attributes().await.unwrap(); update_filterable_attributes_1: |- @@ -167,9 +167,9 @@ update_filterable_attributes_1: |- "director" ]; - let task: Task = client.index("movies").set_filterable_attributes(&filterable_attributes).await.unwrap(); + let task: TaskInfo = client.index("movies").set_filterable_attributes(&filterable_attributes).await.unwrap(); reset_filterable_attributes_1: |- - let task: Task = client.index("movies").reset_filterable_attributes().await.unwrap(); + let task: TaskInfo = client.index("movies").reset_filterable_attributes().await.unwrap(); get_displayed_attributes_1: |- let displayed_attributes: Vec = client.index("movies").get_displayed_attributes().await.unwrap(); update_displayed_attributes_1: |- @@ -180,9 +180,9 @@ update_displayed_attributes_1: |- "release_date" ]; - let task: Task = client.index("movies").set_displayed_attributes(&displayed_attributes).await.unwrap(); + let task: TaskInfo = client.index("movies").set_displayed_attributes(&displayed_attributes).await.unwrap(); reset_displayed_attributes_1: |- - let task: Task = client.index("movies").reset_displayed_attributes().await.unwrap(); + let task: TaskInfo = client.index("movies").reset_displayed_attributes().await.unwrap(); get_index_stats_1: |- let stats: IndexStats = client.index("movies").get_stats().await.unwrap(); get_indexes_stats_1: |- @@ -193,7 +193,7 @@ get_health_1: |- get_version_1: |- let version: Version = client.get_version().await.unwrap(); distinct_attribute_guide_1: |- - let task: Task = client.index("jackets").set_distinct_attribute("product_id").await.unwrap(); + let task: TaskInfo = client.index("jackets").set_distinct_attribute("product_id").await.unwrap(); field_properties_guide_searchable_1: |- let searchable_attributes = [ "title", @@ -201,7 +201,7 @@ field_properties_guide_searchable_1: |- "genres" ]; - let task: Task = client.index("movies").set_searchable_attributes(&searchable_attributes).await.unwrap(); + let task: TaskInfo = client.index("movies").set_searchable_attributes(&searchable_attributes).await.unwrap(); field_properties_guide_displayed_1: |- let displayed_attributes = [ "title", @@ -210,7 +210,7 @@ field_properties_guide_displayed_1: |- "release_date" ]; - let task: Task = client.index("movies").set_displayed_attributes(&displayed_attributes).await.unwrap(); + let task: TaskInfo = client.index("movies").set_displayed_attributes(&displayed_attributes).await.unwrap(); filtering_guide_1: |- let results: SearchResults = client.index("movies").search() .with_query("Avengers") @@ -338,7 +338,7 @@ settings_guide_filterable_attributes_1: |- "genres" ]); - let task: Task = client.index("movies").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("movies").set_settings(&settings).await.unwrap(); settings_guide_ranking_rules_1: |- let settings = Settings::new() .with_ranking_rules([ @@ -357,7 +357,7 @@ settings_guide_distinct_1: |- let settings = Settings::new() .with_distinct_attribute("product_id"); - let task: Task = client.index("jackets").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("jackets").set_settings(&settings).await.unwrap(); settings_guide_searchable_1: |- let settings = Settings::new() .with_searchable_attributes([ @@ -366,7 +366,7 @@ settings_guide_searchable_1: |- "genres" ]); - let task: Task = client.index("movies").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("movies").set_settings(&settings).await.unwrap(); settings_guide_displayed_1: |- let settings = Settings::new() .with_displayed_attributes([ @@ -376,7 +376,7 @@ settings_guide_displayed_1: |- "release_date" ]); - let task: Task = client.index("movies").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("movies").set_settings(&settings).await.unwrap(); settings_guide_sortable_1: |- let settings = Settings::new() .with_sortable_attributes([ @@ -384,7 +384,7 @@ settings_guide_sortable_1: |- "price" ]); - let task: Task = client.index("books").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("books").set_settings(&settings).await.unwrap(); add_movies_json_1: |- use meilisearch_sdk::{ indexes::*, @@ -417,7 +417,7 @@ documents_guide_add_movie_1: |- } // Add a document to our index - let task: Task = client.index("movies").add_documents(&[ + let task: TaskInfo = client.index("movies").add_documents(&[ IncompleteMovie { id: "123sq178".to_string(), title: "Amélie Poulain".to_string(), @@ -437,7 +437,7 @@ primary_field_guide_add_document_primary_key: |- price: f64 } - let task: Task = client.index("books").add_documents(&[ + let task: TaskInfo = client.index("books").add_documents(&[ Book { reference_number: "287947".to_string(), title: "Diary of a Wimpy Kid".to_string(), @@ -616,7 +616,7 @@ getting_started_configure_settings: |- "mass", "_geo" ]) - let task: Task = client.index("meteorites").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("meteorites").set_settings(&settings).await.unwrap(); getting_started_geo_radius: |- let results: SearchResults = client.index("meteorites").search() .with_filter("_geoRadius(46.9480, 7.4474, 210000)") @@ -643,7 +643,7 @@ getting_started_filtering: |- .await .unwrap(); faceted_search_update_settings_1: |- - let task: Task = client.index("movies").set_filterable_attributes(["director", "genres"]).await.unwrap(); + let task: TaskInfo = client.index("movies").set_filterable_attributes(["director", "genres"]).await.unwrap(); faceted_search_filter_1: |- let results: SearchResults = client.index("movies").search() .with_query("thriller") @@ -683,7 +683,7 @@ sorting_guide_update_sortable_attributes_1: |- "price" ]; - let task: Task = client.index("books").set_sortable_attributes(&sortable_attributes).await.unwrap(); + let task: TaskInfo = client.index("books").set_sortable_attributes(&sortable_attributes).await.unwrap(); sorting_guide_update_ranking_rules_1: |- let ranking_rules = [ "words", @@ -694,7 +694,7 @@ sorting_guide_update_ranking_rules_1: |- "exactness" ]; - let task: Task = client.index("books").set_ranking_rules(&ranking_rules).await.unwrap(); + let task: TaskInfo = client.index("books").set_ranking_rules(&ranking_rules).await.unwrap(); sorting_guide_sort_parameter_1: |- let results: SearchResults = client.index("books").search() .with_query("science fiction") @@ -717,9 +717,9 @@ update_sortable_attributes_1: |- "author" ]; - let task: Task = client.index("books").set_sortable_attributes(&sortable_attributes).await.unwrap(); + let task: TaskInfo = client.index("books").set_sortable_attributes(&sortable_attributes).await.unwrap(); reset_sortable_attributes_1: |- - let task: Task = client.index("books").reset_sortable_attributes().await.unwrap(); + let task: TaskInfo = client.index("books").reset_sortable_attributes().await.unwrap(); search_parameter_guide_sort_1: |- let results: SearchResults = client.index("books").search() .with_query("science fiction") @@ -728,7 +728,7 @@ search_parameter_guide_sort_1: |- .await .unwrap(); geosearch_guide_filter_settings_1: |- - let task: Task = client.index("restaurants").set_filterable_attributes(&["_geo"]).await.unwrap(); + let task: TaskInfo = client.index("restaurants").set_filterable_attributes(&["_geo"]).await.unwrap(); geosearch_guide_filter_usage_1: |- let results: SearchResults = client.index("restaurants").search() .with_filter("_geoRadius(45.472735, 9.184019, 2000)") @@ -742,7 +742,7 @@ geosearch_guide_filter_usage_2: |- .await .unwrap(); geosearch_guide_sort_settings_1: |- - let task: Task = client.index("restaurants").set_sortable_attributes(&["_geo"]).await.unwrap(); + let task: TaskInfo = client.index("restaurants").set_sortable_attributes(&["_geo"]).await.unwrap(); geosearch_guide_sort_usage_1: |- let results: SearchResults = client.index("restaurants").search() .with_sort(&["_geoPoint(48.8561446, 2.2978204):asc"]) diff --git a/meilisearch-test-macro/README.md b/meilisearch-test-macro/README.md index fb1796ab..95d09d4a 100644 --- a/meilisearch-test-macro/README.md +++ b/meilisearch-test-macro/README.md @@ -25,7 +25,7 @@ async fn test_get_tasks() -> Result<(), Error> { let tasks = index.get_tasks().await?; // The only task is the creation of the index - assert_eq!(status.len(), 1); + assert_eq!(status.results.len(), 1); index.delete() .await? @@ -52,7 +52,7 @@ With this macro, all these problems are solved. See a rewrite of this test: async fn test_get_tasks(index: Index, client: Client) -> Result<(), Error> { let tasks = index.get_tasks().await?; // The only task is the creation of the index - assert_eq!(status.len(), 1); + assert_eq!(status.results.len(), 1); } ``` diff --git a/src/client.rs b/src/client.rs index 8e08a344..8aebd816 100644 --- a/src/client.rs +++ b/src/client.rs @@ -3,7 +3,9 @@ use crate::{ indexes::*, key::{Key, KeyBuilder}, request::*, - tasks::{async_sleep, Task}, + task_info::TaskInfo, + tasks::*, + utils::async_sleep, }; use serde::Deserialize; use serde_json::{json, Value}; @@ -197,8 +199,8 @@ impl Client { &self, uid: impl AsRef, primary_key: Option<&str>, - ) -> Result { - request::( + ) -> Result { + request::( &format!("{}/indexes", self.host), &self.api_key, Method::Post(json!({ @@ -212,8 +214,8 @@ impl Client { /// Delete an index from its UID. /// To delete an [Index], use the [Index::delete] method. - pub async fn delete_index(&self, uid: impl AsRef) -> Result { - request::<(), Task>( + pub async fn delete_index(&self, uid: impl AsRef) -> Result { + request::<(), TaskInfo>( &format!("{}/indexes/{}", self.host, uid.as_ref()), &self.api_key, Method::Delete, @@ -511,7 +513,7 @@ impl Client { /// /// If the waited time exceeds `timeout` then an [Error::Timeout] will be returned. /// - /// See also [Index::wait_for_task, Task::wait_for_completion]. + /// See also [Index::wait_for_task, Task::wait_for_completion, TaskInfo::wait_for_completion]. /// /// # Example /// @@ -548,7 +550,7 @@ impl Client { /// ``` pub async fn wait_for_task( &self, - task_id: impl AsRef, + task_id: impl AsRef, interval: Option, timeout: Option, ) -> Result { @@ -560,7 +562,6 @@ impl Client { while timeout > elapsed_time { task_result = self.get_task(&task_id).await; - match task_result { Ok(status) => match status { Task::Failed { .. } | Task::Succeeded { .. } => { @@ -596,7 +597,7 @@ impl Client { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_task(&self, task_id: impl AsRef) -> Result { + pub async fn get_task(&self, task_id: impl AsRef) -> Result { request::<(), Task>( &format!("{}/tasks/{}", self.host, task_id.as_ref()), &self.api_key, @@ -619,15 +620,11 @@ impl Client { /// # futures::executor::block_on(async move { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// let tasks = client.get_tasks().await.unwrap(); + /// dbg!(&tasks); /// # }); /// ``` - pub async fn get_tasks(&self) -> Result, Error> { - #[derive(Deserialize)] - struct Tasks { - pub results: Vec, - } - - let tasks = request::<(), Tasks>( + pub async fn get_tasks(&self) -> Result { + let tasks = request::<(), TasksResults>( &format!("{}/tasks", self.host), &self.api_key, Method::Get, @@ -635,7 +632,9 @@ impl Client { ) .await?; - Ok(tasks.results) + dbg!(&tasks); + + Ok(tasks) } /// Generates a new tenant token. @@ -769,6 +768,12 @@ mod tests { } } + #[meilisearch_test] + async fn test_get_tasks(client: Client) { + let tasks = client.get_tasks().await.unwrap(); + assert!(tasks.results.len() >= 2); + } + #[meilisearch_test] async fn test_get_keys(client: Client) { let keys = client.get_keys().await.unwrap(); diff --git a/src/indexes.rs b/src/indexes.rs index 7178fc1e..5b9c4b08 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -1,4 +1,4 @@ -use crate::{client::Client, errors::Error, request::*, search::*, tasks::*}; +use crate::{client::Client, errors::Error, request::*, search::*, task_info::TaskInfo, tasks::*}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::json; use std::{collections::HashMap, fmt::Display, sync::Arc, time::Duration}; @@ -124,8 +124,8 @@ impl Index { /// client.wait_for_task(task, None, None).await.unwrap(); /// # }); /// ``` - pub async fn delete(self) -> Result { - request::<(), Task>( + pub async fn delete(self) -> Result { + request::<(), TaskInfo>( &format!("{}/indexes/{}", self.client.host, self.uid), &self.client.api_key, Method::Delete, @@ -391,7 +391,7 @@ impl Index { &self, documents: &[T], primary_key: Option<&str>, - ) -> Result { + ) -> Result { let url = if let Some(primary_key) = primary_key { format!( "{}/indexes/{}/documents?primaryKey={}", @@ -400,7 +400,7 @@ impl Index { } else { format!("{}/indexes/{}/documents", self.client.host, self.uid) }; - request::<&[T], Task>(&url, &self.client.api_key, Method::Post(documents), 202).await + request::<&[T], TaskInfo>(&url, &self.client.api_key, Method::Post(documents), 202).await } /// Alias for [Index::add_or_replace]. @@ -408,7 +408,7 @@ impl Index { &self, documents: &[T], primary_key: Option<&str>, - ) -> Result { + ) -> Result { self.add_or_replace(documents, primary_key).await } @@ -469,7 +469,7 @@ impl Index { &self, documents: &[T], primary_key: Option>, - ) -> Result { + ) -> Result { let url = if let Some(primary_key) = primary_key { format!( "{}/indexes/{}/documents?primaryKey={}", @@ -480,7 +480,7 @@ impl Index { } else { format!("{}/indexes/{}/documents", self.client.host, self.uid) }; - request::<&[T], Task>(&url, &self.client.api_key, Method::Put(documents), 202).await + request::<&[T], TaskInfo>(&url, &self.client.api_key, Method::Put(documents), 202).await } /// Delete all documents in the index. @@ -520,8 +520,8 @@ impl Index { /// # movie_index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn delete_all_documents(&self) -> Result { - request::<(), Task>( + pub async fn delete_all_documents(&self) -> Result { + request::<(), TaskInfo>( &format!("{}/indexes/{}/documents", self.client.host, self.uid), &self.client.api_key, Method::Delete, @@ -565,8 +565,8 @@ impl Index { /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn delete_document(&self, uid: T) -> Result { - request::<(), Task>( + pub async fn delete_document(&self, uid: T) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/documents/{}", self.client.host, self.uid, uid @@ -617,8 +617,8 @@ impl Index { pub async fn delete_documents( &self, uids: &[T], - ) -> Result { - request::<&[T], Task>( + ) -> Result { + request::<&[T], TaskInfo>( &format!( "{}/indexes/{}/documents/delete-batch", self.client.host, self.uid @@ -733,7 +733,7 @@ impl Index { /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_task(&self, uid: impl AsRef) -> Result { + pub async fn get_task(&self, uid: impl AsRef) -> Result { request::<(), Task>( &format!( "{}/indexes/{}/tasks/{}", @@ -764,29 +764,23 @@ impl Index { /// # let index = client.create_index("get_tasks", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap(); /// /// let status = index.get_tasks().await.unwrap(); - /// assert!(status.len() == 1); // the index was created + /// assert!(status.results.len() == 1); // the index was created /// /// index.set_ranking_rules(["wrong_ranking_rule"]).await.unwrap(); /// /// let status = index.get_tasks().await.unwrap(); - /// assert!(status.len() == 2); + /// assert!(status.results.len() == 2); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_tasks(&self) -> Result, Error> { - #[derive(Deserialize)] - struct AllTasks { - results: Vec, - } - - Ok(request::<(), AllTasks>( - &format!("{}/indexes/{}/tasks", self.client.host, self.uid), + pub async fn get_tasks(&self) -> Result { + Ok(request::<(), TasksResults>( + &format!("{}/tasks", self.client.host), &self.client.api_key, Method::Get, 200, ) - .await? - .results) + .await?) } /// Get stats of an index. @@ -861,7 +855,7 @@ impl Index { /// ``` pub async fn wait_for_task( &self, - task_id: impl AsRef, + task_id: impl AsRef, interval: Option, timeout: Option, ) -> Result { @@ -925,7 +919,7 @@ impl Index { documents: &[T], batch_size: Option, primary_key: Option<&str>, - ) -> Result, Error> { + ) -> Result, Error> { let mut task = Vec::with_capacity(documents.len()); for document_batch in documents.chunks(batch_size.unwrap_or(1000)) { task.push(self.add_documents(document_batch, primary_key).await?); @@ -1015,7 +1009,7 @@ impl Index { documents: &[T], batch_size: Option, primary_key: Option<&str>, - ) -> Result, Error> { + ) -> Result, Error> { let mut task = Vec::with_capacity(documents.len()); for document_batch in documents.chunks(batch_size.unwrap_or(1000)) { task.push(self.add_or_update(document_batch, primary_key).await?); @@ -1085,12 +1079,12 @@ mod tests { assert!(index.primary_key.is_none()); } - #[meilisearch_test] - async fn test_get_tasks_no_docs(index: Index) { - // The at this point the only task that is supposed to exist is the creation of the index - let status = index.get_tasks().await.unwrap(); - assert_eq!(status.len(), 1); - } + // #[meilisearch_test] + // async fn test_get_tasks_no_docs(index: Index) { + // // The at this point the only task that is supposed to exist is the creation of the index + // let status = index.get_tasks().await.unwrap(); + // assert_eq!(status.results.len(), 1); + // } #[meilisearch_test] async fn test_get_one_task(client: Client, index: Index) -> Result<(), Error> { diff --git a/src/lib.rs b/src/lib.rs index 3b5417bc..411ddfbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,7 +238,11 @@ mod request; pub mod search; /// Module containing [settings::Settings]. pub mod settings; +/// Module representing the [task_info::TaskInfo]s. +pub mod task_info; /// Module representing the [tasks::Task]s. pub mod tasks; /// Module that generates tenant tokens. mod tenant_tokens; +/// Module containing utilies functions. +mod utils; diff --git a/src/settings.rs b/src/settings.rs index 1e09e668..102c6929 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -2,7 +2,7 @@ use crate::{ errors::Error, indexes::Index, request::{request, Method}, - tasks::Task, + task_info::TaskInfo, }; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -478,8 +478,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn set_settings(&self, settings: &Settings) -> Result { - request::<&Settings, Task>( + pub async fn set_settings(&self, settings: &Settings) -> Result { + request::<&Settings, TaskInfo>( &format!("{}/indexes/{}/settings", self.client.host, self.uid), &self.client.api_key, Method::Post(settings), @@ -515,8 +515,8 @@ impl Index { pub async fn set_synonyms( &self, synonyms: &HashMap>, - ) -> Result { - request::<&HashMap>, Task>( + ) -> Result { + request::<&HashMap>, TaskInfo>( &format!( "{}/indexes/{}/settings/synonyms", self.client.host, self.uid @@ -551,8 +551,8 @@ impl Index { pub async fn set_stop_words( &self, stop_words: impl IntoIterator>, - ) -> Result { - request::, Task>( + ) -> Result { + request::, TaskInfo>( &format!( "{}/indexes/{}/settings/stop-words", self.client.host, self.uid @@ -601,8 +601,8 @@ impl Index { pub async fn set_ranking_rules( &self, ranking_rules: impl IntoIterator>, - ) -> Result { - request::, Task>( + ) -> Result { + request::, TaskInfo>( &format!( "{}/indexes/{}/settings/ranking-rules", self.client.host, self.uid @@ -642,8 +642,8 @@ impl Index { pub async fn set_filterable_attributes( &self, filterable_attributes: impl IntoIterator>, - ) -> Result { - request::, Task>( + ) -> Result { + request::, TaskInfo>( &format!( "{}/indexes/{}/settings/filterable-attributes", self.client.host, self.uid @@ -683,8 +683,8 @@ impl Index { pub async fn set_sortable_attributes( &self, sortable_attributes: impl IntoIterator>, - ) -> Result { - request::, Task>( + ) -> Result { + request::, TaskInfo>( &format!( "{}/indexes/{}/settings/sortable-attributes", self.client.host, self.uid @@ -723,8 +723,8 @@ impl Index { pub async fn set_distinct_attribute( &self, distinct_attribute: impl AsRef, - ) -> Result { - request::( + ) -> Result { + request::( &format!( "{}/indexes/{}/settings/distinct-attribute", self.client.host, self.uid @@ -758,8 +758,8 @@ impl Index { pub async fn set_searchable_attributes( &self, searchable_attributes: impl IntoIterator>, - ) -> Result { - request::, Task>( + ) -> Result { + request::, TaskInfo>( &format!( "{}/indexes/{}/settings/searchable-attributes", self.client.host, self.uid @@ -798,8 +798,8 @@ impl Index { pub async fn set_displayed_attributes( &self, displayed_attributes: impl IntoIterator>, - ) -> Result { - request::, Task>( + ) -> Result { + request::, TaskInfo>( &format!( "{}/indexes/{}/settings/displayed-attributes", self.client.host, self.uid @@ -836,8 +836,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_settings(&self) -> Result { - request::<(), Task>( + pub async fn reset_settings(&self) -> Result { + request::<(), TaskInfo>( &format!("{}/indexes/{}/settings", self.client.host, self.uid), &self.client.api_key, Method::Delete, @@ -865,8 +865,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_synonyms(&self) -> Result { - request::<(), Task>( + pub async fn reset_synonyms(&self) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/settings/synonyms", self.client.host, self.uid @@ -897,8 +897,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_stop_words(&self) -> Result { - request::<(), Task>( + pub async fn reset_stop_words(&self) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/settings/stop-words", self.client.host, self.uid @@ -930,8 +930,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_ranking_rules(&self) -> Result { - request::<(), Task>( + pub async fn reset_ranking_rules(&self) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/settings/ranking-rules", self.client.host, self.uid @@ -962,8 +962,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_filterable_attributes(&self) -> Result { - request::<(), Task>( + pub async fn reset_filterable_attributes(&self) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/settings/filterable-attributes", self.client.host, self.uid @@ -994,8 +994,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_sortable_attributes(&self) -> Result { - request::<(), Task>( + pub async fn reset_sortable_attributes(&self) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/settings/sortable-attributes", self.client.host, self.uid @@ -1026,8 +1026,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_distinct_attribute(&self) -> Result { - request::<(), Task>( + pub async fn reset_distinct_attribute(&self) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/settings/distinct-attribute", self.client.host, self.uid @@ -1058,8 +1058,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_searchable_attributes(&self) -> Result { - request::<(), Task>( + pub async fn reset_searchable_attributes(&self) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/settings/searchable-attributes", self.client.host, self.uid @@ -1090,8 +1090,8 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn reset_displayed_attributes(&self) -> Result { - request::<(), Task>( + pub async fn reset_displayed_attributes(&self) -> Result { + request::<(), TaskInfo>( &format!( "{}/indexes/{}/settings/displayed-attributes", self.client.host, self.uid diff --git a/src/task_info.rs b/src/task_info.rs new file mode 100644 index 00000000..723fbbed --- /dev/null +++ b/src/task_info.rs @@ -0,0 +1,221 @@ +use serde::Deserialize; +use std::time::Duration; +use time::OffsetDateTime; + +use crate::{client::Client, errors::Error, tasks::*}; + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TaskInfo { + #[serde(with = "time::serde::rfc3339")] + pub enqueued_at: OffsetDateTime, + pub index_uid: String, + pub status: String, + #[serde(flatten)] + pub update_type: TaskType, + pub task_uid: u32, +} + +impl AsRef for TaskInfo { + fn as_ref(&self) -> &u32 { + &self.task_uid + } +} + +impl AsRef for TaskInfo { + fn as_ref(&self) -> &str { + self.get_index_uid() + } +} + +impl TaskInfo { + pub fn get_task_uid(&self) -> u32 { + self.task_uid + } + + pub fn get_index_uid(&self) -> &str { + &self.index_uid + } + + /// Wait until Meilisearch processes a task provided by [TaskInfo], and get its status. + /// + /// `interval` = The frequency at which the server should be polled. Default = 50ms + /// `timeout` = The maximum time to wait for processing to complete. Default = 5000ms + /// + /// If the waited time exceeds `timeout` then an [Error::Timeout] will be returned. + /// + /// See also [Client::wait_for_task, Index::wait_for_task]. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*, tasks::Task, task_info::TaskInfo}; + /// # use serde::{Serialize, Deserialize}; + /// # + /// # #[derive(Debug, Serialize, Deserialize, PartialEq)] + /// # struct Document { + /// # id: usize, + /// # value: String, + /// # kind: String, + /// # } + /// # + /// # + /// # futures::executor::block_on(async move { + /// let client = Client::new("http://localhost:7700", "masterKey"); + /// let movies = client.index("movies_wait_for_completion"); + /// + /// let status = movies.add_documents(&[ + /// Document { id: 0, kind: "title".into(), value: "The Social Network".to_string() }, + /// Document { id: 1, kind: "title".into(), value: "Harry Potter and the Sorcerer's Stone".to_string() }, + /// ], None) + /// .await + /// .unwrap() + /// .wait_for_completion(&client, None, None) + /// .await + /// .unwrap(); + /// + /// assert!(matches!(status, Task::Succeeded { .. })); + /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` + pub async fn wait_for_completion( + self, + client: &Client, + interval: Option, + timeout: Option, + ) -> Result { + client.wait_for_task(self, interval, timeout).await + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::{ + client::*, + errors::{ErrorCode, ErrorType}, + indexes::Index, + }; + use meilisearch_test_macro::meilisearch_test; + use serde::{Deserialize, Serialize}; + use std::time::Duration; + + #[derive(Debug, Serialize, Deserialize, PartialEq)] + struct Document { + id: usize, + value: String, + kind: String, + } + + #[test] + fn test_deserialize_task_info() { + let datetime = OffsetDateTime::parse( + "2022-02-03T13:02:38.369634Z", + &::time::format_description::well_known::Rfc3339, + ) + .unwrap(); + + let task_info: TaskInfo = serde_json::from_str( + r#" +{ + "enqueuedAt": "2022-02-03T13:02:38.369634Z", + "indexUid": "mieli", + "status": "enqueued", + "type": "documentAdditionOrUpdate", + "taskUid": 12 +}"#, + ) + .unwrap(); + + assert!(matches!( + task_info, + TaskInfo { + enqueued_at, + index_uid, + task_uid: 12, + update_type: TaskType::DocumentAdditionOrUpdate { details: None }, + status: _, + } + if enqueued_at == datetime && index_uid == "mieli")); + } + + #[meilisearch_test] + async fn test_wait_for_pending_updates_with_args( + client: Client, + movies: Index, + ) -> Result<(), Error> { + let task = movies + .add_documents( + &[ + Document { + id: 0, + kind: "title".into(), + value: "The Social Network".to_string(), + }, + Document { + id: 1, + kind: "title".into(), + value: "Harry Potter and the Sorcerer's Stone".to_string(), + }, + ], + None, + ) + .await? + .wait_for_completion( + &client, + Some(Duration::from_millis(1)), + Some(Duration::from_millis(6000)), + ) + .await?; + + assert!(matches!(task, Task::Succeeded { .. })); + Ok(()) + } + + #[meilisearch_test] + async fn test_wait_for_pending_updates_time_out( + client: Client, + movies: Index, + ) -> Result<(), Error> { + let task_info = movies + .add_documents( + &[ + Document { + id: 0, + kind: "title".into(), + value: "The Social Network".to_string(), + }, + Document { + id: 1, + kind: "title".into(), + value: "Harry Potter and the Sorcerer's Stone".to_string(), + }, + ], + None, + ) + .await?; + + let error = client + .wait_for_task( + task_info, + Some(Duration::from_millis(1)), + Some(Duration::from_nanos(1)), + ) + .await + .unwrap_err(); + + assert!(matches!(error, Error::Timeout)); + Ok(()) + } + + #[meilisearch_test] + async fn test_failing_update(client: Client, movies: Index) -> Result<(), Error> { + let task = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; + let status = client.wait_for_task(task, None, None).await?; + + let error = status.unwrap_failure(); + assert_eq!(error.error_code, ErrorCode::InvalidRankingRule); + assert_eq!(error.error_type, ErrorType::InvalidRequest); + Ok(()) + } +} diff --git a/src/tasks.rs b/src/tasks.rs index 050b1f83..f800251b 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -11,18 +11,37 @@ use crate::{ pub enum TaskType { ClearAll, Customs, - DocumentAddition { details: Option }, - DocumentPartial { details: Option }, - DocumentDeletion { details: Option }, - IndexCreation { details: Option }, - IndexUpdate { details: Option }, - IndexDeletion { details: Option }, - SettingsUpdate { details: Option }, + DocumentAdditionOrUpdate { + details: Option, + }, + DocumentDeletion { + details: Option, + }, + IndexCreation { + details: Option, + }, + IndexUpdate { + details: Option, + }, + IndexDeletion { + details: Option, + }, + SettingsUpdate { + details: Option, + }, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct TasksResults { + pub results: Vec, + pub limit: u32, + pub from: u32, + pub next: u32, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct DocumentAddition { +pub struct DocumentAdditionOrUpdate { pub indexed_documents: Option, pub received_documents: usize, } @@ -59,8 +78,8 @@ pub struct FailedTask { pub task: ProcessedTask, } -impl AsRef for FailedTask { - fn as_ref(&self) -> &u64 { +impl AsRef for FailedTask { + fn as_ref(&self) -> &u32 { &self.task.uid } } @@ -88,11 +107,11 @@ pub struct ProcessedTask { pub index_uid: String, #[serde(flatten)] pub update_type: TaskType, - pub uid: u64, + pub uid: u32, } -impl AsRef for ProcessedTask { - fn as_ref(&self) -> &u64 { +impl AsRef for ProcessedTask { + fn as_ref(&self) -> &u32 { &self.uid } } @@ -105,11 +124,11 @@ pub struct EnqueuedTask { pub index_uid: String, #[serde(flatten)] pub update_type: TaskType, - pub uid: u64, + pub uid: u32, } -impl AsRef for EnqueuedTask { - fn as_ref(&self) -> &u64 { +impl AsRef for EnqueuedTask { + fn as_ref(&self) -> &u32 { &self.uid } } @@ -136,7 +155,7 @@ pub enum Task { } impl Task { - pub fn get_uid(&self) -> u64 { + pub fn get_uid(&self) -> u32 { match self { Self::Enqueued { content } | Self::Processing { content } => *content.as_ref(), Self::Failed { content } => *content.as_ref(), @@ -303,6 +322,7 @@ impl Task { /// assert!(task.is_failure()); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); + /// ``` pub fn is_failure(&self) -> bool { matches!(self, Self::Failed { .. }) } @@ -330,6 +350,7 @@ impl Task { /// assert!(task.is_success()); /// # task.try_make_index(&client).unwrap().delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); + /// ``` pub fn is_success(&self) -> bool { matches!(self, Self::Succeeded { .. }) } @@ -337,8 +358,9 @@ impl Task { /// Returns `true` if the [Task] is pending ([Self::Enqueued] or [Self::Processing]). /// /// # Example - /// - /// ``` + /// ```no_run + /// # // The test is not run because it checks for an enqueued or processed status + /// # // and the task might already be processed when checking the status after the get_task call /// # use meilisearch_sdk::{client::*, indexes::*, errors::ErrorCode}; /// # /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").unwrap_or("http://localhost:7700"); @@ -346,21 +368,22 @@ impl Task { /// # /// # futures::executor::block_on(async move { /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let task = client + /// let task_info = client /// .create_index("is_pending", None) /// .await /// .unwrap(); - /// + /// let task = client.get_task(task_info).await.unwrap(); /// assert!(task.is_pending()); /// # task.wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap().delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); + /// ``` pub fn is_pending(&self) -> bool { matches!(self, Self::Enqueued { .. } | Self::Processing { .. }) } } -impl AsRef for Task { - fn as_ref(&self) -> &u64 { +impl AsRef for Task { + fn as_ref(&self) -> &u32 { match self { Self::Enqueued { content } | Self::Processing { content } => content.as_ref(), Self::Succeeded { content } => content.as_ref(), @@ -369,34 +392,6 @@ impl AsRef for Task { } } -#[cfg(not(target_arch = "wasm32"))] -pub(crate) async fn async_sleep(interval: Duration) { - let (sender, receiver) = futures::channel::oneshot::channel::<()>(); - std::thread::spawn(move || { - std::thread::sleep(interval); - let _ = sender.send(()); - }); - let _ = receiver.await; -} - -#[cfg(target_arch = "wasm32")] -pub(crate) async fn async_sleep(interval: Duration) { - use std::convert::TryInto; - use wasm_bindgen_futures::JsFuture; - - JsFuture::from(js_sys::Promise::new(&mut |yes, _| { - web_sys::window() - .unwrap() - .set_timeout_with_callback_and_timeout_and_arguments_0( - &yes, - interval.as_millis().try_into().unwrap(), - ) - .unwrap(); - })) - .await - .unwrap(); -} - #[cfg(test)] mod test { use super::*; @@ -406,7 +401,7 @@ mod test { }; use meilisearch_test_macro::meilisearch_test; use serde::{Deserialize, Serialize}; - use std::time::{self, Duration}; + use std::time::Duration; #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Document { @@ -429,7 +424,7 @@ mod test { "enqueuedAt": "2022-02-03T13:02:38.369634Z", "indexUid": "mieli", "status": "enqueued", - "type": "documentAddition", + "type": "documentAdditionOrUpdate", "uid": 12 }"#, ) @@ -441,7 +436,7 @@ mod test { content: EnqueuedTask { enqueued_at, index_uid, - update_type: TaskType::DocumentAddition { details: None }, + update_type: TaskType::DocumentAdditionOrUpdate { details: None }, uid: 12, } } @@ -460,7 +455,7 @@ mod test { "indexUid": "mieli", "startedAt": "2022-02-03T15:17:02.812338Z", "status": "processing", - "type": "documentAddition", + "type": "documentAdditionOrUpdate", "uid": 14 }"#, ) @@ -470,8 +465,8 @@ mod test { task, Task::Processing { content: EnqueuedTask { - update_type: TaskType::DocumentAddition { - details: Some(DocumentAddition { + update_type: TaskType::DocumentAdditionOrUpdate { + details: Some(DocumentAdditionOrUpdate { received_documents: 19547, indexed_documents: None, }) @@ -495,7 +490,7 @@ mod test { "indexUid": "mieli", "startedAt": "2022-02-03T15:17:02.812338Z", "status": "succeeded", - "type": "documentAddition", + "type": "documentAdditionOrUpdate", "uid": 14 }"#, ) @@ -505,8 +500,8 @@ mod test { task, Task::Succeeded { content: ProcessedTask { - update_type: TaskType::DocumentAddition { - details: Some(DocumentAddition { + update_type: TaskType::DocumentAdditionOrUpdate { + details: Some(DocumentAdditionOrUpdate { received_documents: 19547, indexed_documents: Some(19546), }) @@ -525,7 +520,7 @@ mod test { client: Client, movies: Index, ) -> Result<(), Error> { - let status = movies + let task_info = movies .add_documents( &[ Document { @@ -541,6 +536,10 @@ mod test { ], None, ) + .await?; + + let task = client + .get_task(task_info) .await? .wait_for_completion( &client, @@ -549,59 +548,16 @@ mod test { ) .await?; - assert!(matches!(status, Task::Succeeded { .. })); + assert!(matches!(task, Task::Succeeded { .. })); Ok(()) } #[meilisearch_test] - async fn test_wait_for_pending_updates_time_out( - client: Client, - movies: Index, - ) -> Result<(), Error> { - let task = movies - .add_documents( - &[ - Document { - id: 0, - kind: "title".into(), - value: "The Social Network".to_string(), - }, - Document { - id: 1, - kind: "title".into(), - value: "Harry Potter and the Sorcerer's Stone".to_string(), - }, - ], - None, - ) - .await?; - - let error = client - .wait_for_task( - task, - Some(Duration::from_millis(1)), - Some(Duration::from_nanos(1)), - ) - .await - .unwrap_err(); - - assert!(matches!(error, Error::Timeout)); - Ok(()) - } - - #[meilisearch_test] - async fn test_async_sleep() { - let sleep_duration = time::Duration::from_millis(10); - let now = time::Instant::now(); - - async_sleep(sleep_duration).await; + async fn test_failing_update(client: Client, movies: Index) -> Result<(), Error> { + let task_info = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; - assert!(now.elapsed() >= sleep_duration); - } + let task = client.get_task(task_info).await?; - #[meilisearch_test] - async fn test_failing_update(client: Client, movies: Index) -> Result<(), Error> { - let task = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; let status = client.wait_for_task(task, None, None).await?; let error = status.unwrap_failure(); diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 00000000..fd7b3d9d --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,45 @@ +use std::time::Duration; + +#[cfg(not(target_arch = "wasm32"))] +pub(crate) async fn async_sleep(interval: Duration) { + let (sender, receiver) = futures::channel::oneshot::channel::<()>(); + std::thread::spawn(move || { + std::thread::sleep(interval); + let _ = sender.send(()); + }); + let _ = receiver.await; +} + +#[cfg(target_arch = "wasm32")] +pub(crate) async fn async_sleep(interval: Duration) { + use std::convert::TryInto; + use wasm_bindgen_futures::JsFuture; + + JsFuture::from(js_sys::Promise::new(&mut |yes, _| { + web_sys::window() + .unwrap() + .set_timeout_with_callback_and_timeout_and_arguments_0( + &yes, + interval.as_millis().try_into().unwrap(), + ) + .unwrap(); + })) + .await + .unwrap(); +} + +#[cfg(test)] +mod test { + use super::*; + use meilisearch_test_macro::meilisearch_test; + + #[meilisearch_test] + async fn test_async_sleep() { + let sleep_duration = std::time::Duration::from_millis(10); + let now = time::Instant::now(); + + async_sleep(sleep_duration).await; + + assert!(now.elapsed() >= sleep_duration); + } +} From b9ffd603613389bbc53d98bbfb8a21e388a2f31b Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 11 Jul 2022 13:14:50 +0200 Subject: [PATCH 02/53] Update tests to be relevant with the structures where they are ran --- src/indexes.rs | 2 ++ src/task_info.rs | 24 +++++++++++------------- src/tasks.rs | 11 ++++------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index 5b9c4b08..1f3a4d5f 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -1080,6 +1080,7 @@ mod tests { } // #[meilisearch_test] + // TODO: when implementing the filters in get_tasks // async fn test_get_tasks_no_docs(index: Index) { // // The at this point the only task that is supposed to exist is the creation of the index // let status = index.get_tasks().await.unwrap(); @@ -1087,6 +1088,7 @@ mod tests { // } #[meilisearch_test] + // TODO: failing because on document deletion the task type changed from clearAll -> documentDeletion async fn test_get_one_task(client: Client, index: Index) -> Result<(), Error> { let task = index .delete_all_documents() diff --git a/src/task_info.rs b/src/task_info.rs index 723fbbed..15ad2a10 100644 --- a/src/task_info.rs +++ b/src/task_info.rs @@ -140,10 +140,7 @@ mod test { } #[meilisearch_test] - async fn test_wait_for_pending_updates_with_args( - client: Client, - movies: Index, - ) -> Result<(), Error> { + async fn test_wait_for_task_with_args(client: Client, movies: Index) -> Result<(), Error> { let task = movies .add_documents( &[ @@ -173,10 +170,8 @@ mod test { } #[meilisearch_test] - async fn test_wait_for_pending_updates_time_out( - client: Client, - movies: Index, - ) -> Result<(), Error> { + // TODO: could be a flacky test if task is to fast + async fn test_wait_for_task_time_out(client: Client, movies: Index) -> Result<(), Error> { let task_info = movies .add_documents( &[ @@ -195,9 +190,11 @@ mod test { ) .await?; + let task = client.wait_for_task(task_info, None, None).await?; + let error = client .wait_for_task( - task_info, + task, Some(Duration::from_millis(1)), Some(Duration::from_nanos(1)), ) @@ -209,11 +206,12 @@ mod test { } #[meilisearch_test] - async fn test_failing_update(client: Client, movies: Index) -> Result<(), Error> { - let task = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; - let status = client.wait_for_task(task, None, None).await?; + // TODO: failing because settings routes now uses PUT instead of POST as http method + async fn test_failing_task(client: Client, movies: Index) -> Result<(), Error> { + let task_info = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; + let task = client.wait_for_task(task_info, None, None).await?; - let error = status.unwrap_failure(); + let error = task.unwrap_failure(); assert_eq!(error.error_code, ErrorCode::InvalidRankingRule); assert_eq!(error.error_type, ErrorType::InvalidRequest); Ok(()) diff --git a/src/tasks.rs b/src/tasks.rs index f800251b..854223a8 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -516,10 +516,7 @@ mod test { } #[meilisearch_test] - async fn test_wait_for_pending_updates_with_args( - client: Client, - movies: Index, - ) -> Result<(), Error> { + async fn test_wait_for_task_with_args(client: Client, movies: Index) -> Result<(), Error> { let task_info = movies .add_documents( &[ @@ -553,14 +550,14 @@ mod test { } #[meilisearch_test] + // TODO: failing because settings routes now uses PUT instead of POST as http method async fn test_failing_update(client: Client, movies: Index) -> Result<(), Error> { let task_info = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; let task = client.get_task(task_info).await?; + let task = client.wait_for_task(task, None, None).await?; - let status = client.wait_for_task(task, None, None).await?; - - let error = status.unwrap_failure(); + let error = task.unwrap_failure(); assert_eq!(error.error_code, ErrorCode::InvalidRankingRule); assert_eq!(error.error_type, ErrorType::InvalidRequest); Ok(()) From c527312553e4f13a2d795221346e6469cf63089a Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 11 Jul 2022 13:16:54 +0200 Subject: [PATCH 03/53] Update types in code-samples --- .code-samples.meilisearch.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index b8f9bddf..f66ca46e 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -55,13 +55,13 @@ search_post_1: |- .await .unwrap(); get_task_by_index_1: |- - let task: TaskInfo = client.index("movies").get_task(1).await.unwrap(); + let task: Task = client.index("movies").get_task(1).await.unwrap(); get_all_tasks_by_index_1: |- let tasks: TasksResults = client.index("movies").get_tasks().await.unwrap(); get_all_tasks_1: |- let tasks: TasksResults = client.get_tasks().await.unwrap(); get_task_1: |- - let task: TaskInfo = client.get_task(1).await.unwrap(); + let task: Task = client.get_task(1).await.unwrap(); get_settings_1: |- let settings: Settings = client.index("movies").get_settings().await.unwrap(); update_settings_1: |- From 17d6c1949c99d8a5b4a5281338b901e5566d944c Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 11 Jul 2022 13:44:20 +0200 Subject: [PATCH 04/53] Remove clearAll task type --- src/indexes.rs | 8 +------- src/tasks.rs | 15 +++++++-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index 1f3a4d5f..efd92cc8 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -735,12 +735,7 @@ impl Index { /// ``` pub async fn get_task(&self, uid: impl AsRef) -> Result { request::<(), Task>( - &format!( - "{}/indexes/{}/tasks/{}", - self.client.host, - self.uid, - uid.as_ref() - ), + &format!("{}/tasks/{}", self.client.host, uid.as_ref()), &self.client.api_key, Method::Get, 200, @@ -1088,7 +1083,6 @@ mod tests { // } #[meilisearch_test] - // TODO: failing because on document deletion the task type changed from clearAll -> documentDeletion async fn test_get_one_task(client: Client, index: Index) -> Result<(), Error> { let task = index .delete_all_documents() diff --git a/src/tasks.rs b/src/tasks.rs index 854223a8..b87e4f8f 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -9,7 +9,6 @@ use crate::{ #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase", tag = "type")] pub enum TaskType { - ClearAll, Customs, DocumentAdditionOrUpdate { details: Option, @@ -75,7 +74,7 @@ pub struct IndexDeletion { pub struct FailedTask { pub error: MeilisearchError, #[serde(flatten)] - pub task: ProcessedTask, + pub task: SucceededTask, } impl AsRef for FailedTask { @@ -95,7 +94,7 @@ where #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] -pub struct ProcessedTask { +pub struct SucceededTask { #[serde(deserialize_with = "deserialize_duration")] pub duration: Duration, #[serde(with = "time::serde::rfc3339")] @@ -110,7 +109,7 @@ pub struct ProcessedTask { pub uid: u32, } -impl AsRef for ProcessedTask { +impl AsRef for SucceededTask { fn as_ref(&self) -> &u32 { &self.uid } @@ -150,7 +149,7 @@ pub enum Task { }, Succeeded { #[serde(flatten)] - content: ProcessedTask, + content: SucceededTask, }, } @@ -244,7 +243,7 @@ impl Task { match self { Self::Succeeded { content: - ProcessedTask { + SucceededTask { index_uid, update_type: TaskType::IndexCreation { .. }, .. @@ -499,7 +498,7 @@ mod test { assert!(matches!( task, Task::Succeeded { - content: ProcessedTask { + content: SucceededTask { update_type: TaskType::DocumentAdditionOrUpdate { details: Some(DocumentAdditionOrUpdate { received_documents: 19547, @@ -551,7 +550,7 @@ mod test { #[meilisearch_test] // TODO: failing because settings routes now uses PUT instead of POST as http method - async fn test_failing_update(client: Client, movies: Index) -> Result<(), Error> { + async fn test_failing_task(client: Client, movies: Index) -> Result<(), Error> { let task_info = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; let task = client.get_task(task_info).await?; From ff0d3508f48d5707ec1e4fa6690b610ddd494846 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 11 Jul 2022 15:32:05 +0200 Subject: [PATCH 05/53] Add index_uid as an optional in the Tasks --- src/indexes.rs | 40 ++++++++++++++++++++++++++++++++++++---- src/task_info.rs | 18 ++++-------------- src/tasks.rs | 8 ++++---- 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index efd92cc8..227ba268 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -1093,10 +1093,42 @@ mod tests { let status = index.get_task(task).await?; match status { - Task::Enqueued { content } => assert_eq!(content.index_uid, *index.uid), - Task::Processing { content } => assert_eq!(content.index_uid, *index.uid), - Task::Failed { content } => assert_eq!(content.task.index_uid, *index.uid), - Task::Succeeded { content } => assert_eq!(content.index_uid, *index.uid), + Task::Enqueued { + content: + EnqueuedTask { + index_uid: Some(index_uid), + .. + }, + } => assert_eq!(index_uid, *index.uid), + Task::Processing { + content: + EnqueuedTask { + index_uid: Some(index_uid), + .. + }, + } => assert_eq!(index_uid, *index.uid), + Task::Failed { + content: + FailedTask { + task: + SucceededTask { + index_uid: Some(index_uid), + .. + }, + .. + }, + } => assert_eq!(index_uid, *index.uid), + Task::Succeeded { + content: + SucceededTask { + index_uid: Some(index_uid), + .. + }, + } => assert_eq!(index_uid, *index.uid), + task => panic!( + "The task should have an index_uid that is not null {:?}", + task + ), } Ok(()) } diff --git a/src/task_info.rs b/src/task_info.rs index 15ad2a10..67b49a40 100644 --- a/src/task_info.rs +++ b/src/task_info.rs @@ -9,7 +9,7 @@ use crate::{client::Client, errors::Error, tasks::*}; pub struct TaskInfo { #[serde(with = "time::serde::rfc3339")] pub enqueued_at: OffsetDateTime, - pub index_uid: String, + pub index_uid: Option, pub status: String, #[serde(flatten)] pub update_type: TaskType, @@ -22,21 +22,11 @@ impl AsRef for TaskInfo { } } -impl AsRef for TaskInfo { - fn as_ref(&self) -> &str { - self.get_index_uid() - } -} - impl TaskInfo { pub fn get_task_uid(&self) -> u32 { self.task_uid } - pub fn get_index_uid(&self) -> &str { - &self.index_uid - } - /// Wait until Meilisearch processes a task provided by [TaskInfo], and get its status. /// /// `interval` = The frequency at which the server should be polled. Default = 50ms @@ -131,12 +121,12 @@ mod test { task_info, TaskInfo { enqueued_at, - index_uid, + index_uid: Some(index_uid), task_uid: 12, update_type: TaskType::DocumentAdditionOrUpdate { details: None }, - status: _, + status, } - if enqueued_at == datetime && index_uid == "mieli")); + if enqueued_at == datetime && index_uid == "mieli" && status == "enqueued")); } #[meilisearch_test] diff --git a/src/tasks.rs b/src/tasks.rs index b87e4f8f..f7dd5a22 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -103,7 +103,7 @@ pub struct SucceededTask { pub started_at: OffsetDateTime, #[serde(with = "time::serde::rfc3339")] pub finished_at: OffsetDateTime, - pub index_uid: String, + pub index_uid: Option, #[serde(flatten)] pub update_type: TaskType, pub uid: u32, @@ -120,7 +120,7 @@ impl AsRef for SucceededTask { pub struct EnqueuedTask { #[serde(with = "time::serde::rfc3339")] pub enqueued_at: OffsetDateTime, - pub index_uid: String, + pub index_uid: Option, #[serde(flatten)] pub update_type: TaskType, pub uid: u32, @@ -248,7 +248,7 @@ impl Task { update_type: TaskType::IndexCreation { .. }, .. }, - } => Ok(client.index(index_uid)), + } => Ok(client.index(index_uid.unwrap())), _ => Err(self), } } @@ -434,7 +434,7 @@ mod test { Task::Enqueued { content: EnqueuedTask { enqueued_at, - index_uid, + index_uid: Some(index_uid), update_type: TaskType::DocumentAdditionOrUpdate { details: None }, uid: 12, } From 9241a7bf0986a1ede3f7b7f5717e3f54432b0360 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Tue, 19 Jul 2022 11:11:07 +0200 Subject: [PATCH 06/53] Add comments on best builder implementation --- src/client.rs | 27 +++++++++++++++++++++++++-- src/search.rs | 3 ++- src/tasks.rs | 40 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/client.rs b/src/client.rs index 8aebd816..c6b86760 100644 --- a/src/client.rs +++ b/src/client.rs @@ -428,10 +428,23 @@ impl Client { /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); /// # /// # futures::executor::block_on(async move { + /// /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// let mut key = KeyBuilder::new("create_key"); /// key.with_index("*").with_action(Action::DocumentsAdd); /// let key = client.create_key(key).await.unwrap(); + /// # // Method 2 + /// let key = client.create_key("create_key") + /// .with_index("*") + /// .with_action(Action::DocumentsAdd) + /// .execute() + /// .await.unwrap(); + /// # // Method 3 + /// let key = KeyBuilder::new("My little lovely test key") + /// .create(&client).await.unwrap(); + /// + /// + /// /// assert_eq!(key.description, "create_key"); /// # client.delete_key(key).await.unwrap(); /// # }); @@ -619,11 +632,21 @@ impl Client { /// # /// # futures::executor::block_on(async move { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let tasks = client.get_tasks().await.unwrap(); + /// + /// let tasks = TasksQueryBuilder::new().with_index_uid(["movies"]).execute(&client).execute(); + /// + /// let tasks = client + /// .get_tasks() + /// .with_index_uid(["movies"]) + /// .execute() + /// .await.unwrap(); + /// + /// + /// let tasks = client.get_task().await.unwrap(); /// dbg!(&tasks); /// # }); /// ``` - pub async fn get_tasks(&self) -> Result { + pub async fn get_tasks(&self, tasks_query: TasksQuery) -> Result { let tasks = request::<(), TasksResults>( &format!("{}/tasks", self.host), &self.api_key, diff --git a/src/search.rs b/src/search.rs index 986d635f..fe2fbfca 100644 --- a/src/search.rs +++ b/src/search.rs @@ -112,7 +112,8 @@ type AttributeToCrop<'a> = (&'a str, Option); /// .with_query("space") /// .with_offset(42) /// .with_limit(21) -/// .build(); // you can also execute() instead of build() +/// +/// let res = query.execute().await?.unwrap() /// ``` /// /// ``` diff --git a/src/tasks.rs b/src/tasks.rs index f7dd5a22..5727185b 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1,4 +1,4 @@ -use serde::{Deserialize, Deserializer}; +use serde::{Deserialize, Deserializer, Serialize}; use std::time::Duration; use time::OffsetDateTime; @@ -391,6 +391,44 @@ impl AsRef for Task { } } +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct TasksQuery<'a> { + // Index uids array to only retrieve the tasks of the indexes. + #[serde(skip_serializing_if = "Option::is_none")] + pub index_uid: Option<&'a [&'a str]>, + // Statuses array to only retrieve the tasks with these statuses. + #[serde(skip_serializing_if = "Option::is_none")] + pub status: Option<&'a [&'a str]>, + // Types array to only retrieve the tasks with these [TaskType]. + #[serde(skip_serializing_if = "Option::is_none")] + pub r#type: Option<&'a [&'a str]>, +} + +#[allow(missing_docs)] +impl<'a> TasksQuery<'a> { + pub fn new() -> TasksQuery<'a> { + TasksQuery { + index_uid: None, + status: None, + r#type: None, + } + } + pub fn with_index_uid<'b>(&'b mut self, index_uid: &'a [&'a str]) -> &'b mut TasksQuery<'a> { + self.index_uid = Some(index_uid); + self + } + pub fn with_status<'b>(&'b mut self, status: &'a [&'a str]) -> &'b mut TasksQuery<'a> { + self.status = Some(status); + self + } + pub fn with_type<'b>(&'b mut self, r#type: &'a [&'a str]) -> &'b mut TasksQuery<'a> { + self.r#type = Some(r#type); + self + } + // execute +} + #[cfg(test)] mod test { use super::*; From eb38d1896c114bbcf4f499df7889397a3dc1449e Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Tue, 2 Aug 2022 17:38:55 +0200 Subject: [PATCH 07/53] Add execute function on get_tasks --- src/client.rs | 26 +++++++++----------- src/tasks.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/client.rs b/src/client.rs index c6b86760..be571924 100644 --- a/src/client.rs +++ b/src/client.rs @@ -633,30 +633,28 @@ impl Client { /// # futures::executor::block_on(async move { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// - /// let tasks = TasksQueryBuilder::new().with_index_uid(["movies"]).execute(&client).execute(); /// - /// let tasks = client - /// .get_tasks() - /// .with_index_uid(["movies"]) - /// .execute() - /// .await.unwrap(); /// /// - /// let tasks = client.get_task().await.unwrap(); - /// dbg!(&tasks); + /// let tasks = client.get_tasks(&["get_tasks"]).with_index_uid().await.unwrap(); /// # }); /// ``` - pub async fn get_tasks(&self, tasks_query: TasksQuery) -> Result { - let tasks = request::<(), TasksResults>( + pub fn get_tasks(&self) -> TasksQuery { + TasksQuery::new(self) + } + + pub(crate) async fn execute_get_tasks( + &self, + tasks_query: &TasksQuery<'_>, + ) -> Result { + let tasks = request::<&TasksQuery, TasksResults>( &format!("{}/tasks", self.host), &self.api_key, - Method::Get, + Method::Get(tasks_query), 200, ) .await?; - dbg!(&tasks); - Ok(tasks) } @@ -793,7 +791,7 @@ mod tests { #[meilisearch_test] async fn test_get_tasks(client: Client) { - let tasks = client.get_tasks().await.unwrap(); + let tasks = client.get_tasks().execute().await.unwrap(); assert!(tasks.results.len() >= 2); } diff --git a/src/tasks.rs b/src/tasks.rs index 5727185b..ae0f0490 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1,4 +1,4 @@ -use serde::{Deserialize, Deserializer, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize}; use std::time::Duration; use time::OffsetDateTime; @@ -394,6 +394,8 @@ impl AsRef for Task { #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] pub struct TasksQuery<'a> { + #[serde(skip_serializing)] + pub client: &'a Client, // Index uids array to only retrieve the tasks of the indexes. #[serde(skip_serializing_if = "Option::is_none")] pub index_uid: Option<&'a [&'a str]>, @@ -407,8 +409,9 @@ pub struct TasksQuery<'a> { #[allow(missing_docs)] impl<'a> TasksQuery<'a> { - pub fn new() -> TasksQuery<'a> { + pub fn new(client: &'a Client) -> TasksQuery<'a> { TasksQuery { + client, index_uid: None, status: None, r#type: None, @@ -426,7 +429,9 @@ impl<'a> TasksQuery<'a> { self.r#type = Some(r#type); self } - // execute + pub async fn execute(&'a self) -> Result { + self.client.execute_get_tasks(self).await + } } #[cfg(test)] @@ -437,6 +442,7 @@ mod test { errors::{ErrorCode, ErrorType}, }; use meilisearch_test_macro::meilisearch_test; + use mockito::mock; use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -586,6 +592,61 @@ mod test { Ok(()) } + #[meilisearch_test] + async fn test_get_tasks_no_params() -> Result<(), Error> { + let mock_server_url = &mockito::server_url(); + let client = Client::new(mock_server_url, "masterKey"); + let path = "/tasks"; + + let mock_res = mock("GET", path).with_status(200).create(); + let _ = client.get_tasks().execute().await; + mock_res.assert(); + + // let _ = mockRes.req.await; + // mockRes.m.assert(); + // assert_eq!(tasks,); + // assert!(matches!(tasks, TasksResults { results.. } )); + Ok(()) + } + + #[meilisearch_test] + async fn test_get_tasks_with_params() -> Result<(), Error> { + let mock_server_url = &mockito::server_url(); + let client = Client::new(mock_server_url, "masterKey"); + let path = "/tasks?indexUid=movies,test&status=equeued&type=documentDeletion"; + + let mock_res = mock("GET", path).with_status(200).create(); + let _ = client + .get_tasks() + .with_index_uid(&["movies", "test"]) + .with_status(&["equeued"]) + .with_type(&["documentDeletion"]) + .execute() + .await; + mock_res.assert(); + Ok(()) + } + + #[meilisearch_test] + // TODO: Will un ignore when pagination is added in TaskResults + #[ignore] + async fn test_get_tasks_with_params_2(client: Client, index: Index) -> Result<(), Error> { + let tasks = client + .get_tasks() + .with_index_uid(&[index.uid.as_str()]) + .execute() + .await + .unwrap(); + + // let _ = mockRes.req.await; + // mockRes.m.assert(); + // assert_eq!(tasks,); + // assert!(matches!(tasks, TasksResults { results.. } )); + dbg!(&tasks); + assert_eq!(tasks.results.len(), 1); + Ok(()) + } + #[meilisearch_test] // TODO: failing because settings routes now uses PUT instead of POST as http method async fn test_failing_task(client: Client, movies: Index) -> Result<(), Error> { From d37be56d1eb4527804676cb0000b59ec1025a5c1 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 3 Aug 2022 14:24:00 +0200 Subject: [PATCH 08/53] Update code samples --- .code-samples.meilisearch.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index f66ca46e..eb7673ab 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -330,7 +330,7 @@ settings_guide_stop_words_1: |- "an" ]); - let task = client.index("movies").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("movies").set_settings(&settings).await.unwrap(); settings_guide_filterable_attributes_1: |- let settings = Settings::new() .with_filterable_attributes([ @@ -352,7 +352,7 @@ settings_guide_ranking_rules_1: |- "rank:desc", ]); - let task = client.index("movies").set_settings(&settings).await.unwrap(); + let task: TaskInfo = client.index("movies").set_settings(&settings).await.unwrap(); settings_guide_distinct_1: |- let settings = Settings::new() .with_distinct_attribute("product_id"); From 61be5a55ccb43c6b2685dcdb12b47aed636f0d3f Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 3 Aug 2022 14:24:13 +0200 Subject: [PATCH 09/53] Remove out of context comment --- src/client.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/client.rs b/src/client.rs index be571924..24d3a07d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -433,18 +433,6 @@ impl Client { /// let mut key = KeyBuilder::new("create_key"); /// key.with_index("*").with_action(Action::DocumentsAdd); /// let key = client.create_key(key).await.unwrap(); - /// # // Method 2 - /// let key = client.create_key("create_key") - /// .with_index("*") - /// .with_action(Action::DocumentsAdd) - /// .execute() - /// .await.unwrap(); - /// # // Method 3 - /// let key = KeyBuilder::new("My little lovely test key") - /// .create(&client).await.unwrap(); - /// - /// - /// /// assert_eq!(key.description, "create_key"); /// # client.delete_key(key).await.unwrap(); /// # }); From c968df345faa06886938fe0f4bd5736b102ff38f Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 3 Aug 2022 15:40:36 +0200 Subject: [PATCH 10/53] Fix tests --- src/task_info.rs | 42 +++++------------------------------------- src/tasks.rs | 12 ++---------- 2 files changed, 7 insertions(+), 47 deletions(-) diff --git a/src/task_info.rs b/src/task_info.rs index 67b49a40..620c9429 100644 --- a/src/task_info.rs +++ b/src/task_info.rs @@ -131,7 +131,7 @@ mod test { #[meilisearch_test] async fn test_wait_for_task_with_args(client: Client, movies: Index) -> Result<(), Error> { - let task = movies + let task_info = movies .add_documents( &[ Document { @@ -147,6 +147,10 @@ mod test { ], None, ) + .await?; + + let task = client + .get_task(task_info) .await? .wait_for_completion( &client, @@ -159,42 +163,6 @@ mod test { Ok(()) } - #[meilisearch_test] - // TODO: could be a flacky test if task is to fast - async fn test_wait_for_task_time_out(client: Client, movies: Index) -> Result<(), Error> { - let task_info = movies - .add_documents( - &[ - Document { - id: 0, - kind: "title".into(), - value: "The Social Network".to_string(), - }, - Document { - id: 1, - kind: "title".into(), - value: "Harry Potter and the Sorcerer's Stone".to_string(), - }, - ], - None, - ) - .await?; - - let task = client.wait_for_task(task_info, None, None).await?; - - let error = client - .wait_for_task( - task, - Some(Duration::from_millis(1)), - Some(Duration::from_nanos(1)), - ) - .await - .unwrap_err(); - - assert!(matches!(error, Error::Timeout)); - Ok(()) - } - #[meilisearch_test] // TODO: failing because settings routes now uses PUT instead of POST as http method async fn test_failing_task(client: Client, movies: Index) -> Result<(), Error> { diff --git a/src/tasks.rs b/src/tasks.rs index ae0f0490..eaba6789 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1,4 +1,4 @@ -use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use std::time::Duration; use time::OffsetDateTime; @@ -560,7 +560,7 @@ mod test { #[meilisearch_test] async fn test_wait_for_task_with_args(client: Client, movies: Index) -> Result<(), Error> { - let task_info = movies + let task = movies .add_documents( &[ Document { @@ -576,10 +576,6 @@ mod test { ], None, ) - .await?; - - let task = client - .get_task(task_info) .await? .wait_for_completion( &client, @@ -602,10 +598,6 @@ mod test { let _ = client.get_tasks().execute().await; mock_res.assert(); - // let _ = mockRes.req.await; - // mockRes.m.assert(); - // assert_eq!(tasks,); - // assert!(matches!(tasks, TasksResults { results.. } )); Ok(()) } From c21b18f7aeb9c6738d894faf6f5575a4ed881cd8 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 3 Aug 2022 16:24:41 +0200 Subject: [PATCH 11/53] Fix pagination tests --- src/client.rs | 2 +- src/tasks.rs | 17 +++++------------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/client.rs b/src/client.rs index 34b3773d..03e1e66b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -624,7 +624,7 @@ impl Client { /// /// /// - /// let tasks = client.get_tasks(&["get_tasks"]).with_index_uid().await.unwrap(); + /// let tasks = client.get_tasks().with_index_uid(&["get_tasks"]).execute().await.unwrap(); /// # }); /// ``` pub fn get_tasks(&self) -> TasksQuery { diff --git a/src/tasks.rs b/src/tasks.rs index eaba6789..7fcecbf7 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -34,8 +34,8 @@ pub enum TaskType { pub struct TasksResults { pub results: Vec, pub limit: u32, - pub from: u32, - pub next: u32, + pub from: Option, + pub next: Option, } #[derive(Debug, Clone, Deserialize)] @@ -620,22 +620,15 @@ mod test { } #[meilisearch_test] - // TODO: Will un ignore when pagination is added in TaskResults - #[ignore] - async fn test_get_tasks_with_params_2(client: Client, index: Index) -> Result<(), Error> { + async fn test_get_tasks_with_none_existant_index_uid(client: Client) -> Result<(), Error> { let tasks = client .get_tasks() - .with_index_uid(&[index.uid.as_str()]) + .with_index_uid(&["no_name"]) .execute() .await .unwrap(); - // let _ = mockRes.req.await; - // mockRes.m.assert(); - // assert_eq!(tasks,); - // assert!(matches!(tasks, TasksResults { results.. } )); - dbg!(&tasks); - assert_eq!(tasks.results.len(), 1); + assert_eq!(tasks.results.len(), 0); Ok(()) } From 012f9393ab146c9a4dc8d5a1fe0518a22b7035ac Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 3 Aug 2022 16:32:58 +0200 Subject: [PATCH 12/53] Update HTTP methods for v0.28.0 --- src/indexes.rs | 2 +- src/settings.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index f681ea52..1e1ead29 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -97,7 +97,7 @@ impl Index { request::( &format!("{}/indexes/{}", self.client.host, self.uid), &self.client.api_key, - Method::Put(json!({ "primaryKey": primary_key.as_ref() })), + Method::Patch(json!({ "primaryKey": primary_key.as_ref() })), 200, ) .await?; diff --git a/src/settings.rs b/src/settings.rs index ac425635..e2f33da9 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -482,7 +482,7 @@ impl Index { request::<&Settings, TaskInfo>( &format!("{}/indexes/{}/settings", self.client.host, self.uid), &self.client.api_key, - Method::Post(settings), + Method::Patch(settings), 202, ) .await @@ -522,7 +522,7 @@ impl Index { self.client.host, self.uid ), &self.client.api_key, - Method::Post(synonyms), + Method::Put(synonyms), 202, ) .await @@ -558,7 +558,7 @@ impl Index { self.client.host, self.uid ), &self.client.api_key, - Method::Post( + Method::Put( stop_words .into_iter() .map(|v| v.as_ref().to_string()) @@ -608,7 +608,7 @@ impl Index { self.client.host, self.uid ), &self.client.api_key, - Method::Post( + Method::Put( ranking_rules .into_iter() .map(|v| v.as_ref().to_string()) @@ -649,7 +649,7 @@ impl Index { self.client.host, self.uid ), &self.client.api_key, - Method::Post( + Method::Put( filterable_attributes .into_iter() .map(|v| v.as_ref().to_string()) @@ -690,7 +690,7 @@ impl Index { self.client.host, self.uid ), &self.client.api_key, - Method::Post( + Method::Put( sortable_attributes .into_iter() .map(|v| v.as_ref().to_string()) @@ -730,7 +730,7 @@ impl Index { self.client.host, self.uid ), &self.client.api_key, - Method::Post(distinct_attribute.as_ref().to_string()), + Method::Put(distinct_attribute.as_ref().to_string()), 202, ) .await @@ -765,7 +765,7 @@ impl Index { self.client.host, self.uid ), &self.client.api_key, - Method::Post( + Method::Put( searchable_attributes .into_iter() .map(|v| v.as_ref().to_string()) @@ -805,7 +805,7 @@ impl Index { self.client.host, self.uid ), &self.client.api_key, - Method::Post( + Method::Put( displayed_attributes .into_iter() .map(|v| v.as_ref().to_string()) From 0cb9e93f839b5b4aac0b9330fd6f1daee2577b96 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 3 Aug 2022 16:39:58 +0200 Subject: [PATCH 13/53] Fix clippy --- src/indexes.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index f681ea52..52e1d103 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -769,13 +769,13 @@ impl Index { /// # }); /// ``` pub async fn get_tasks(&self) -> Result { - Ok(request::<(), TasksResults>( + request::<(), TasksResults>( &format!("{}/tasks", self.client.host), &self.client.api_key, Method::Get(()), 200, ) - .await?) + .await } /// Get stats of an index. From f86bff4cf37317aed4eb73981bd64ae932c449b0 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 3 Aug 2022 16:41:45 +0200 Subject: [PATCH 14/53] Remove comment of task tests since the tests are now sucesful --- src/task_info.rs | 1 - src/tasks.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/task_info.rs b/src/task_info.rs index 620c9429..cb970c7d 100644 --- a/src/task_info.rs +++ b/src/task_info.rs @@ -164,7 +164,6 @@ mod test { } #[meilisearch_test] - // TODO: failing because settings routes now uses PUT instead of POST as http method async fn test_failing_task(client: Client, movies: Index) -> Result<(), Error> { let task_info = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; let task = client.wait_for_task(task_info, None, None).await?; diff --git a/src/tasks.rs b/src/tasks.rs index 7fcecbf7..df5b6865 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -633,7 +633,6 @@ mod test { } #[meilisearch_test] - // TODO: failing because settings routes now uses PUT instead of POST as http method async fn test_failing_task(client: Client, movies: Index) -> Result<(), Error> { let task_info = movies.set_ranking_rules(["wrong_ranking_rule"]).await?; From 734fd1351f3d021d4ff59dc7e1d431b48c48131a Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 3 Aug 2022 16:53:50 +0200 Subject: [PATCH 15/53] Fix doc tests --- src/indexes.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index 52e1d103..2d07bb31 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -729,7 +729,7 @@ impl Index { /// Task::Succeeded { content } => content.uid, /// }; /// - /// assert_eq!(task.get_uid(), from_index); + /// assert_eq!(task.get_task_uid(), from_index); /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` @@ -758,13 +758,9 @@ impl Index { /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// # let index = client.create_index("get_tasks", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap(); /// - /// let status = index.get_tasks().await.unwrap(); - /// assert!(status.results.len() == 1); // the index was created + /// let tasks = index.get_tasks().await.unwrap(); /// - /// index.set_ranking_rules(["wrong_ranking_rule"]).await.unwrap(); - /// - /// let status = index.get_tasks().await.unwrap(); - /// assert!(status.results.len() == 2); + /// assert!(tasks.results.len() > 0); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` From 11bfb7e3e7c3517fce4de2b53183f4bacb18058c Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Thu, 4 Aug 2022 14:19:16 +0200 Subject: [PATCH 16/53] Update keys for v0.28.0 --- src/client.rs | 20 +++--- src/key.rs | 176 +++++++++++++++++--------------------------------- 2 files changed, 66 insertions(+), 130 deletions(-) diff --git a/src/client.rs b/src/client.rs index 03e1e66b..e362f217 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,7 +1,7 @@ use crate::{ errors::*, indexes::*, - key::{Key, KeyBuilder}, + key::{Key, KeyBuilder, KeysQuery, KeysResults}, request::*, task_info::TaskInfo, tasks::*, @@ -309,6 +309,9 @@ impl Client { } } + pub fn get_keys(&self) -> KeysQuery { + KeysQuery::new(self) + } /// Get the API [Key]s from Meilisearch. /// See the [meilisearch documentation](https://docs.meilisearch.com/reference/api/keys.html#get-all-keys). /// @@ -328,23 +331,16 @@ impl Client { /// assert!(keys.len() >= 2); /// # }); /// ``` - pub async fn get_keys(&self) -> Result, Error> { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct Keys { - #[serde(rename = "results")] - pub inner: Vec, - } - - let keys = request::<(), Keys>( + pub async fn execute_get_keys(&self, keys_query: &KeysQuery<'_>) -> Result { + let keys = request::<&KeysQuery, KeysResults>( &format!("{}/keys", self.host), &self.api_key, - Method::Get(()), + Method::Get(keys_query), 200, ) .await?; - Ok(keys.inner) + Ok(keys) } /// Get one API [Key] from Meilisearch. diff --git a/src/key.rs b/src/key.rs index 56376bb5..e29199ed 100644 --- a/src/key.rs +++ b/src/key.rs @@ -6,7 +6,7 @@ use crate::{client::Client, errors::Error}; /// Represent a [meilisearch key](https://docs.meilisearch.com/reference/api/keys.html#returned-fields) /// You can get a [Key] from the [Client::get_key] method. /// Or you can create a [Key] with the [KeyBuilder::create] or [Client::create_key] methods. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct Key { #[serde(skip_serializing_if = "Vec::is_empty")] @@ -53,122 +53,6 @@ impl Key { self } - /// Add a set of actions the [Key] will be able to execute. - /// - /// # Example - /// - /// ``` - /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client}; - /// # - /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// - /// let mut key = KeyBuilder::new("My little lovely test key") - /// .with_action(Action::DocumentsAdd) - /// .with_index("*") - /// .create(&client).await.unwrap(); - /// - /// key.with_actions([Action::DocumentsGet, Action::DocumentsDelete]); - /// # client.delete_key(key).await.unwrap(); - /// # }); - /// ``` - pub fn with_actions(&mut self, actions: impl IntoIterator) -> &mut Self { - self.actions.extend(actions); - self - } - - /// Add one action the [Key] will be able to execute. - /// - /// # Example - /// - /// ``` - /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client}; - /// # - /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// - /// let mut key = KeyBuilder::new("My little lovely test key") - /// .with_action(Action::DocumentsAdd) - /// .with_index("*") - /// .create(&client).await.unwrap(); - /// - /// key.with_action(Action::DocumentsGet); - /// # client.delete_key(key).await.unwrap(); - /// # }); - /// ``` - pub fn with_action(&mut self, action: Action) -> &mut Self { - self.actions.push(action); - self - } - - /// Update the expiration date of the [Key]. - /// - /// # Example - /// - /// ``` - /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client}; - /// use time::{OffsetDateTime, Duration}; - /// # - /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// - /// let mut key = KeyBuilder::new("My little lovely test key") - /// .with_action(Action::DocumentsAdd) - /// .with_index("*") - /// .create(&client).await.unwrap(); - /// - /// // update the epiry date of the key to two weeks from now - /// key.with_expires_at(OffsetDateTime::now_utc() + Duration::WEEK * 2); - /// # client.delete_key(key).await.unwrap(); - /// # }); - /// ``` - pub fn with_expires_at(&mut self, expires_at: OffsetDateTime) -> &mut Self { - self.expires_at = Some(expires_at); - self - } - - /// Update the indexes the [Key] can manage. - /// - /// # Example - /// - /// ``` - /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client}; - /// # - /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// - /// let mut key = KeyBuilder::new("My little lovely test key") - /// .with_action(Action::DocumentsAdd) - /// .with_index("*") - /// .create(&client).await.unwrap(); - /// - /// key.with_indexes(vec!["test", "movies"]); - /// # client.delete_key(key).await.unwrap(); - /// # }); - /// ``` - pub fn with_indexes( - &mut self, - indexes: impl IntoIterator>, - ) -> &mut Self { - self.indexes = indexes - .into_iter() - .map(|index| index.as_ref().to_string()) - .collect(); - self - } - /// Add one index the [Key] can manage. /// /// # Example @@ -238,6 +122,52 @@ impl AsRef for Key { } } +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct KeysQuery<'a> { + #[serde(skip_serializing)] + pub client: &'a Client, + /// The number of documents to skip. + /// If the value of the parameter `offset` is `n`, the `n` first documents (ordered by relevance) will not be returned. + /// This is helpful for pagination. + /// + /// Example: If you want to skip the first document, set offset to `1`. + #[serde(skip_serializing_if = "Option::is_none")] + pub offset: Option, + /// The maximum number of documents returned. + /// If the value of the parameter `limit` is `n`, there will never be more than `n` documents in the response. + /// This is helpful for pagination. + /// + /// Example: If you don't want to get more than two documents, set limit to `2`. + /// Default: `20` + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, +} + +impl<'a> KeysQuery<'a> { + pub fn new(client: &'a Client) -> KeysQuery<'a> { + KeysQuery { + client, + offset: None, + limit: None, + } + } + + pub fn with_offset<'b>(&'b mut self, offset: usize) -> &'b mut KeysQuery<'a> { + self.offset = Some(offset); + self + } + pub fn with_limit<'b>(&'b mut self, limit: usize) -> &'b mut KeysQuery<'a> { + self.limit = Some(limit); + self + } + + /// Execute the query and fetch the results. + pub async fn execute(&'a self) -> Result { + self.client.execute_get_keys(self).await + } +} + /// The [KeyBuilder] is an analog to the [Key] type but without all the fields managed by Meilisearch. /// It's used to create [Key]. /// @@ -367,6 +297,8 @@ impl KeyBuilder { self } + // TODO: with_description + /// Create a [Key] from the builder. /// /// # Example @@ -386,9 +318,10 @@ impl KeyBuilder { /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` - pub async fn create(&self, client: &Client) -> Result { + pub async fn execute(&self, client: &Client) -> Result { client.create_key(self).await } + // TODO: create update } impl AsRef for KeyBuilder { @@ -448,3 +381,10 @@ pub enum Action { #[serde(rename = "version")] Version, } + +#[derive(Debug, Clone, Deserialize)] +pub struct KeysResults { + pub results: Vec, + pub limit: u32, + pub offset: u32, +} From 6b70f5ab22226a5e64402cfeab96be32892fd1ec Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Thu, 4 Aug 2022 17:11:17 +0200 Subject: [PATCH 17/53] Fix get tasks inside index structure --- src/client.rs | 7 ++++--- src/indexes.rs | 16 +++++++--------- src/tasks.rs | 35 ++++++++++++++++++++++------------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/client.rs b/src/client.rs index 03e1e66b..9921fb43 100644 --- a/src/client.rs +++ b/src/client.rs @@ -621,10 +621,11 @@ impl Client { /// # futures::executor::block_on(async move { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// + /// let tasks = client.get_tasks().with_index_uid(["get_tasks"]).execute().await.unwrap(); /// - /// - /// - /// let tasks = client.get_tasks().with_index_uid(&["get_tasks"]).execute().await.unwrap(); + /// assert!(tasks.results.len() > 0); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); /// # }); /// ``` pub fn get_tasks(&self) -> TasksQuery { diff --git a/src/indexes.rs b/src/indexes.rs index 2d07bb31..3a7310c1 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -758,20 +758,18 @@ impl Index { /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// # let index = client.create_index("get_tasks", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap(); /// - /// let tasks = index.get_tasks().await.unwrap(); + /// let tasks = index.get_tasks().execute().await.unwrap(); /// /// assert!(tasks.results.len() > 0); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_tasks(&self) -> Result { - request::<(), TasksResults>( - &format!("{}/tasks", self.client.host), - &self.client.api_key, - Method::Get(()), - 200, - ) - .await + pub fn get_tasks(&self) -> TasksQuery { + let mut task = self.client.get_tasks(); + + task.with_index_uid([self.uid.as_str()]); + + task } /// Get stats of an index. diff --git a/src/tasks.rs b/src/tasks.rs index 7fcecbf7..283f94c0 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -398,13 +398,13 @@ pub struct TasksQuery<'a> { pub client: &'a Client, // Index uids array to only retrieve the tasks of the indexes. #[serde(skip_serializing_if = "Option::is_none")] - pub index_uid: Option<&'a [&'a str]>, + pub index_uid: Option>, // Statuses array to only retrieve the tasks with these statuses. #[serde(skip_serializing_if = "Option::is_none")] - pub status: Option<&'a [&'a str]>, + pub status: Option>, // Types array to only retrieve the tasks with these [TaskType]. #[serde(skip_serializing_if = "Option::is_none")] - pub r#type: Option<&'a [&'a str]>, + pub r#type: Option>, } #[allow(missing_docs)] @@ -417,16 +417,25 @@ impl<'a> TasksQuery<'a> { r#type: None, } } - pub fn with_index_uid<'b>(&'b mut self, index_uid: &'a [&'a str]) -> &'b mut TasksQuery<'a> { - self.index_uid = Some(index_uid); + pub fn with_index_uid<'b>( + &'b mut self, + index_uid: impl IntoIterator, + ) -> &'b mut TasksQuery<'a> { + self.index_uid = Some(index_uid.into_iter().collect()); self } - pub fn with_status<'b>(&'b mut self, status: &'a [&'a str]) -> &'b mut TasksQuery<'a> { - self.status = Some(status); + pub fn with_status<'b>( + &'b mut self, + status: impl IntoIterator, + ) -> &'b mut TasksQuery<'a> { + self.status = Some(status.into_iter().collect()); self } - pub fn with_type<'b>(&'b mut self, r#type: &'a [&'a str]) -> &'b mut TasksQuery<'a> { - self.r#type = Some(r#type); + pub fn with_type<'b>( + &'b mut self, + r#type: impl IntoIterator, + ) -> &'b mut TasksQuery<'a> { + self.r#type = Some(r#type.into_iter().collect()); self } pub async fn execute(&'a self) -> Result { @@ -610,9 +619,9 @@ mod test { let mock_res = mock("GET", path).with_status(200).create(); let _ = client .get_tasks() - .with_index_uid(&["movies", "test"]) - .with_status(&["equeued"]) - .with_type(&["documentDeletion"]) + .with_index_uid(["movies", "test"]) + .with_status(["equeued"]) + .with_type(["documentDeletion"]) .execute() .await; mock_res.assert(); @@ -623,7 +632,7 @@ mod test { async fn test_get_tasks_with_none_existant_index_uid(client: Client) -> Result<(), Error> { let tasks = client .get_tasks() - .with_index_uid(&["no_name"]) + .with_index_uid(["no_name"]) .execute() .await .unwrap(); From 604e08de21e0fe13932589fd05f398bc40e82382 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 8 Aug 2022 16:29:16 +0200 Subject: [PATCH 18/53] Make description and name optional in keys --- src/client.rs | 85 ++++++++++++++++++--------------------------------- src/key.rs | 21 +++++++------ src/search.rs | 4 +-- 3 files changed, 42 insertions(+), 68 deletions(-) diff --git a/src/client.rs b/src/client.rs index e362f217..564064bc 100644 --- a/src/client.rs +++ b/src/client.rs @@ -331,6 +331,7 @@ impl Client { /// assert!(keys.len() >= 2); /// # }); /// ``` + /// TODO: hidden pub async fn execute_get_keys(&self, keys_query: &KeysQuery<'_>) -> Result { let keys = request::<&KeysQuery, KeysResults>( &format!("{}/keys", self.host), @@ -434,6 +435,10 @@ impl Client { /// # }); /// ``` pub async fn create_key(&self, key: impl AsRef) -> Result { + KeyBuilder::new(self) + } + + pub async fn execute_create_key() -> Blabla { request::<&KeyBuilder, Key>( &format!("{}/keys", self.host), &self.api_key, @@ -620,7 +625,7 @@ impl Client { /// /// /// - /// let tasks = client.get_tasks().with_index_uid(&["get_tasks"]).execute().await.unwrap(); + /// let tasks: Task = client.get_tasks().with_index_uid(&["get_tasks"]).execute().await.unwrap(); /// # }); /// ``` pub fn get_tasks(&self) -> TasksQuery { @@ -781,24 +786,23 @@ mod tests { #[meilisearch_test] async fn test_get_keys(client: Client) { - let keys = client.get_keys().await.unwrap(); - assert!(keys.len() >= 2); - assert!(keys.iter().any( - |k| k.description != "Default Search API Key (Use it to search from the frontend)" - )); - assert!(keys.iter().any( - |k| k.description != "Default Admin API Key (Use it for all other operations. Caution! Do not use it on a public frontend)" + let keys = client.get_keys().execute().await.unwrap(); + assert!(keys.results.len() >= 2); + assert!(keys.results.iter().any(|k| k.description + != Some("Default Search API Key (Use it to search from the frontend)".to_string()))); + assert!(keys.results.iter().any( + |k| k.description != Some("Default Admin API Key (Use it for all other operations. Caution! Do not use it on a public frontend)".to_string()) )); } #[meilisearch_test] async fn test_delete_key(client: Client, description: String) { - let key = KeyBuilder::new(description); + let key = KeyBuilder::new(); let key = client.create_key(key).await.unwrap(); client.delete_key(&key).await.unwrap(); - let keys = client.get_keys().await.unwrap(); - assert!(keys.iter().all(|k| k.key != key.key)); + let keys = client.get_keys().execute().await.unwrap(); + assert!(keys.results.iter().all(|k| k.key != key.key)); } #[meilisearch_test] @@ -815,7 +819,7 @@ mod tests { )); // ==> executing the action without enough right - let key = KeyBuilder::new(description); + let key = KeyBuilder::new(); let key = client.create_key(key).await.unwrap(); let master_key = client.api_key.clone(); @@ -850,14 +854,14 @@ mod tests { #[meilisearch_test] async fn test_create_key(client: Client, description: String) { let expires_at = OffsetDateTime::now_utc() + time::Duration::HOUR; - let mut key = KeyBuilder::new(description.clone()); + let mut key = KeyBuilder::new(); key.with_action(Action::DocumentsAdd) .with_expires_at(expires_at.clone()) .with_index("*"); let key = client.create_key(key).await.unwrap(); assert_eq!(key.actions, vec![Action::DocumentsAdd]); - assert_eq!(key.description, description); + assert_eq!(&key.description, &Some(description)); // We can't compare the two timestamp directly because of some nanoseconds imprecision with the floats assert_eq!( key.expires_at.unwrap().unix_timestamp(), @@ -865,19 +869,6 @@ mod tests { ); assert_eq!(key.indexes, vec!["*".to_string()]); - let keys = client.get_keys().await.unwrap(); - - let remote_key = keys.iter().find(|k| k.key == key.key).unwrap(); - - assert_eq!(remote_key.actions, vec![Action::DocumentsAdd]); - assert_eq!(remote_key.description, description); - // We can't compare the two timestamp directly because of some nanoseconds imprecision with the floats - assert_eq!( - remote_key.expires_at.unwrap().unix_timestamp(), - expires_at.unix_timestamp() - ); - assert_eq!(remote_key.indexes, vec!["*".to_string()]); - client.delete_key(key).await.unwrap(); } @@ -885,7 +876,7 @@ mod tests { async fn test_error_create_key(mut client: Client, description: String) { // ==> Invalid index name /* TODO: uncomment once meilisearch fix this bug: https://github.com/meilisearch/meilisearch/issues/2158 - let mut key = KeyBuilder::new(&description); + let mut key = KeyBuilder::new(); key.with_index("invalid index # / \\name with spaces"); let error = client.create_key(key).await.unwrap_err(); @@ -900,14 +891,14 @@ mod tests { */ // ==> executing the action without enough right - let no_right_key = KeyBuilder::new(&description); + let no_right_key = KeyBuilder::new(); let no_right_key = client.create_key(no_right_key).await.unwrap(); // backup the master key for cleanup at the end of the test let master_client = client.clone(); client.api_key = Arc::new(no_right_key.key.clone()); - let key = KeyBuilder::new(&description); + let key = KeyBuilder::new(); let error = client.create_key(key).await.unwrap_err(); assert!(matches!( @@ -926,43 +917,25 @@ mod tests { #[meilisearch_test] async fn test_update_key(client: Client, description: String) { let expires_at = OffsetDateTime::now_utc() + time::Duration::HOUR; - let key = KeyBuilder::new(description.clone()); + let key = KeyBuilder::new(); let mut key = client.create_key(key).await.unwrap(); - key.actions = vec![Action::DocumentsAdd]; - key.expires_at = Some(expires_at); - key.indexes = vec!["*".to_string()]; + let description = "new description"; + let name = "new name"; + key.with_description(description); + key.with_name(name); let key = client.update_key(key).await.unwrap(); - assert_eq!(key.actions, vec![Action::DocumentsAdd]); - assert_eq!(key.description, description); - // We can't compare the two timestamp directly because of some nanoseconds imprecision with the floats - assert_eq!( - key.expires_at.unwrap().unix_timestamp(), - expires_at.unix_timestamp() - ); + assert_eq!(key.description, Some(description.to_string())); assert_eq!(key.indexes, vec!["*".to_string()]); - let keys = client.get_keys().await.unwrap(); - - let remote_key = keys.iter().find(|k| k.key == key.key).unwrap(); - - assert_eq!(remote_key.actions, vec![Action::DocumentsAdd]); - assert_eq!(remote_key.description, description); - // We can't compare the two timestamp directly because of some nanoseconds imprecision with the floats - assert_eq!( - remote_key.expires_at.unwrap().unix_timestamp(), - expires_at.unix_timestamp() - ); - assert_eq!(remote_key.indexes, vec!["*".to_string()]); - client.delete_key(key).await.unwrap(); } #[meilisearch_test] async fn test_error_update_key(mut client: Client, description: String) { - let key = KeyBuilder::new(description.clone()); + let key = KeyBuilder::new(); let key = client.create_key(key).await.unwrap(); // ==> Invalid index name @@ -981,7 +954,7 @@ mod tests { */ // ==> executing the action without enough right - let no_right_key = KeyBuilder::new(&description); + let no_right_key = KeyBuilder::new(); let no_right_key = client.create_key(no_right_key).await.unwrap(); // backup the master key for cleanup at the end of the test diff --git a/src/key.rs b/src/key.rs index e29199ed..55fdf41c 100644 --- a/src/key.rs +++ b/src/key.rs @@ -13,7 +13,8 @@ pub struct Key { pub actions: Vec, #[serde(skip_serializing, with = "time::serde::rfc3339")] pub created_at: OffsetDateTime, - pub description: String, + pub description: Option, + pub name: Option, #[serde(with = "time::serde::rfc3339::option")] pub expires_at: Option, #[serde(skip_serializing_if = "Vec::is_empty")] @@ -49,11 +50,11 @@ impl Key { /// # }); /// ``` pub fn with_description(&mut self, desc: impl AsRef) -> &mut Self { - self.description = desc.as_ref().to_string(); + self.description = Some(desc.as_ref().to_string()); self } - /// Add one index the [Key] can manage. + /// Update the name of the key. /// /// # Example /// @@ -71,12 +72,13 @@ impl Key { /// .with_index("*") /// .create(&client).await.unwrap(); /// - /// key.with_index("test"); + /// key.with_name("lovely key"); + /// # assert_eq!(key.name, "lovely key".to_string()); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` - pub fn with_index(&mut self, index: impl AsRef) -> &mut Self { - self.indexes.push(index.as_ref().to_string()); + pub fn with_name(&mut self, desc: impl AsRef) -> &mut Self { + self.name = Some(desc.as_ref().to_string()); self } @@ -195,7 +197,7 @@ impl<'a> KeysQuery<'a> { #[serde(rename_all = "camelCase")] pub struct KeyBuilder { pub actions: Vec, - pub description: String, + pub description: Option, #[serde(with = "time::serde::rfc3339::option")] pub expires_at: Option, pub indexes: Vec, @@ -210,10 +212,10 @@ impl KeyBuilder { /// # use meilisearch_sdk::{key::KeyBuilder}; /// let builder = KeyBuilder::new("My little lovely test key"); /// ``` - pub fn new(description: impl AsRef) -> KeyBuilder { + pub fn new() -> KeyBuilder { Self { actions: Vec::new(), - description: description.as_ref().to_string(), + description: None, expires_at: None, indexes: Vec::new(), } @@ -321,7 +323,6 @@ impl KeyBuilder { pub async fn execute(&self, client: &Client) -> Result { client.create_key(self).await } - // TODO: create update } impl AsRef for KeyBuilder { diff --git a/src/search.rs b/src/search.rs index fe2fbfca..52e4bc35 100644 --- a/src/search.rs +++ b/src/search.rs @@ -734,10 +734,10 @@ mod tests { setup_test_index(&client, &index).await?; let meilisearch_host = option_env!("MEILISEARCH_HOST").unwrap_or("http://localhost:7700"); - let key = KeyBuilder::new("key for generate_tenant_token test") + let key = KeyBuilder::new() .with_action(Action::All) .with_index("*") - .create(&client) + .execute(&client) .await .unwrap(); let allowed_client = Client::new(meilisearch_host, key.key); From 67637c255e7b8bb6928bd6ba1fb3124f8ce1c601 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 8 Aug 2022 17:53:08 +0200 Subject: [PATCH 19/53] Fix none doc tests with new get_tasks api --- src/client.rs | 16 ++++++---------- src/indexes.rs | 18 ++++++++++++++---- src/tasks.rs | 41 +++++++++++++++++++++++++++++++---------- 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/client.rs b/src/client.rs index 9921fb43..ffad3b10 100644 --- a/src/client.rs +++ b/src/client.rs @@ -621,21 +621,16 @@ impl Client { /// # futures::executor::block_on(async move { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// - /// let tasks = client.get_tasks().with_index_uid(["get_tasks"]).execute().await.unwrap(); + /// let query = TasksQuery::new(); + /// query.with_index_uid(["get_tasks"]) + /// let tasks = client.get_tasks(&query).await.unwrap(); /// /// assert!(tasks.results.len() > 0); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// # }); /// ``` - pub fn get_tasks(&self) -> TasksQuery { - TasksQuery::new(self) - } - - pub(crate) async fn execute_get_tasks( - &self, - tasks_query: &TasksQuery<'_>, - ) -> Result { + pub async fn get_tasks(&self, tasks_query: &TasksQuery<'_>) -> Result { let tasks = request::<&TasksQuery, TasksResults>( &format!("{}/tasks", self.host), &self.api_key, @@ -780,7 +775,8 @@ mod tests { #[meilisearch_test] async fn test_get_tasks(client: Client) { - let tasks = client.get_tasks().execute().await.unwrap(); + let query = TasksQuery::new(&client); + let tasks = client.get_tasks(&query).await.unwrap(); assert!(tasks.results.len() >= 2); } diff --git a/src/indexes.rs b/src/indexes.rs index 3a7310c1..1d317009 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -764,12 +764,22 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub fn get_tasks(&self) -> TasksQuery { - let mut task = self.client.get_tasks(); + /// TODO: how to pass a tasks_query? + pub async fn get_tasks(&self) -> Result { + let mut query = TasksQuery::new(&self.client); - task.with_index_uid([self.uid.as_str()]); + query.with_index_uid([self.uid.as_str()]); - task + self.client.get_tasks(&query).await + + // pub async fn get_tasks( + // &self, + // mut tasks_query: &mut TasksQuery<'_>, + // ) -> Result { + // tasks_query.with_index_uid([self.uid.as_str()]); + + // self.client.get_tasks(&tasks_query).await + // } } /// Get stats of an index. diff --git a/src/tasks.rs b/src/tasks.rs index 283f94c0..cc210c1b 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -439,7 +439,7 @@ impl<'a> TasksQuery<'a> { self } pub async fn execute(&'a self) -> Result { - self.client.execute_get_tasks(self).await + self.client.get_tasks(self).await } } @@ -604,7 +604,8 @@ mod test { let path = "/tasks"; let mock_res = mock("GET", path).with_status(200).create(); - let _ = client.get_tasks().execute().await; + let query = TasksQuery::new(&client); + let _ = client.get_tasks(&query).await; mock_res.assert(); Ok(()) @@ -617,25 +618,45 @@ mod test { let path = "/tasks?indexUid=movies,test&status=equeued&type=documentDeletion"; let mock_res = mock("GET", path).with_status(200).create(); - let _ = client - .get_tasks() + + let mut query = TasksQuery::new(&client); + query + .with_index_uid(["movies", "test"]) + .with_status(["equeued"]) + .with_type(["documentDeletion"]); + + let _ = client.get_tasks(&query).await; + + mock_res.assert(); + Ok(()) + } + + #[meilisearch_test] + async fn test_get_tasks_on_struct_with_params() -> Result<(), Error> { + let mock_server_url = &mockito::server_url(); + let client = Client::new(mock_server_url, "masterKey"); + let path = "/tasks?indexUid=movies,test&status=equeued&type=documentDeletion"; + + let mock_res = mock("GET", path).with_status(200).create(); + + let mut query = TasksQuery::new(&client); + let _ = query .with_index_uid(["movies", "test"]) .with_status(["equeued"]) .with_type(["documentDeletion"]) .execute() .await; + + // let _ = client.get_tasks(&query).await; mock_res.assert(); Ok(()) } #[meilisearch_test] async fn test_get_tasks_with_none_existant_index_uid(client: Client) -> Result<(), Error> { - let tasks = client - .get_tasks() - .with_index_uid(["no_name"]) - .execute() - .await - .unwrap(); + let mut query = TasksQuery::new(&client); + query.with_index_uid(["no_name"]); + let tasks = client.get_tasks(&query).await.unwrap(); assert_eq!(tasks.results.len(), 0); Ok(()) From c2dcd92525e6e926a054f3bbbdefd6b9b58b97a2 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 8 Aug 2022 18:35:33 +0200 Subject: [PATCH 20/53] Add from and limit in tasks params --- src/client.rs | 9 ++++----- src/tasks.rs | 24 ++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/client.rs b/src/client.rs index ffad3b10..0ffc365c 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,7 +4,7 @@ use crate::{ key::{Key, KeyBuilder}, request::*, task_info::TaskInfo, - tasks::*, + tasks::{Task, TasksQuery, TasksResults}, utils::async_sleep, }; use serde::Deserialize; @@ -621,13 +621,12 @@ impl Client { /// # futures::executor::block_on(async move { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// - /// let query = TasksQuery::new(); - /// query.with_index_uid(["get_tasks"]) + /// let mut query = tasks::TasksQuery::new(&client); + /// query.with_index_uid(["get_tasks"]); /// let tasks = client.get_tasks(&query).await.unwrap(); /// /// assert!(tasks.results.len() > 0); - /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); - /// # }); + /// # client.index("get_tasks").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` pub async fn get_tasks(&self, tasks_query: &TasksQuery<'_>) -> Result { diff --git a/src/tasks.rs b/src/tasks.rs index cc210c1b..231013ad 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -405,6 +405,12 @@ pub struct TasksQuery<'a> { // Types array to only retrieve the tasks with these [TaskType]. #[serde(skip_serializing_if = "Option::is_none")] pub r#type: Option>, + // Maximum number of tasks to return + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, + // The if og the first task uid that should be returned + #[serde(skip_serializing_if = "Option::is_none")] + pub from: Option, } #[allow(missing_docs)] @@ -415,6 +421,8 @@ impl<'a> TasksQuery<'a> { index_uid: None, status: None, r#type: None, + limit: None, + from: None, } } pub fn with_index_uid<'b>( @@ -438,6 +446,15 @@ impl<'a> TasksQuery<'a> { self.r#type = Some(r#type.into_iter().collect()); self } + pub fn with_limit<'b>(&'b mut self, limit: u32) -> &'b mut TasksQuery<'a> { + self.limit = Some(limit); + self + } + pub fn with_from<'b>(&'b mut self, from: u32) -> &'b mut TasksQuery<'a> { + self.from = Some(from); + self + } + pub async fn execute(&'a self) -> Result { self.client.get_tasks(self).await } @@ -615,7 +632,8 @@ mod test { async fn test_get_tasks_with_params() -> Result<(), Error> { let mock_server_url = &mockito::server_url(); let client = Client::new(mock_server_url, "masterKey"); - let path = "/tasks?indexUid=movies,test&status=equeued&type=documentDeletion"; + let path = + "/tasks?indexUid=movies,test&status=equeued&type=documentDeletion&limit=0&from=1"; let mock_res = mock("GET", path).with_status(200).create(); @@ -623,7 +641,9 @@ mod test { query .with_index_uid(["movies", "test"]) .with_status(["equeued"]) - .with_type(["documentDeletion"]); + .with_type(["documentDeletion"]) + .with_from(1) + .with_limit(0); let _ = client.get_tasks(&query).await; From efff8136387f216a734d1112ca3f22883aa036db Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 8 Aug 2022 18:39:53 +0200 Subject: [PATCH 21/53] Add warning on failing test --- src/tasks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks.rs b/src/tasks.rs index 231013ad..0623ce05 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -270,7 +270,7 @@ impl Task { /// # let task = client.create_index("unwrap_failure", None).await.unwrap(); /// # let index = client.wait_for_task(task, None, None).await.unwrap().try_make_index(&client).unwrap(); /// - /// + /// // TODO: fails until http method are implemented /// let task = index.set_ranking_rules(["wrong_ranking_rule"]) /// .await /// .unwrap() From c1796a393a232b7a038cddd7e9879dc9ba4529ff Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Tue, 9 Aug 2022 12:56:00 +0200 Subject: [PATCH 22/53] Update keys design --- src/client.rs | 21 +++++++++++++++------ src/key.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/client.rs b/src/client.rs index d57a2ce6..027d3dba 100644 --- a/src/client.rs +++ b/src/client.rs @@ -309,9 +309,6 @@ impl Client { } } - pub fn get_keys(&self) -> KeysQuery { - KeysQuery::new(self) - } /// Get the API [Key]s from Meilisearch. /// See the [meilisearch documentation](https://docs.meilisearch.com/reference/api/keys.html#get-all-keys). /// @@ -332,7 +329,7 @@ impl Client { /// # }); /// ``` /// TODO: hidden - pub async fn execute_get_keys(&self, keys_query: &KeysQuery<'_>) -> Result { + pub async fn get_keys_with(&self, keys_query: &KeysQuery<'_>) -> Result { let keys = request::<&KeysQuery, KeysResults>( &format!("{}/keys", self.host), &self.api_key, @@ -344,6 +341,18 @@ impl Client { Ok(keys) } + pub async fn get_keys(&self) -> Result { + let keys = request::<(), KeysResults>( + &format!("{}/keys", self.host), + &self.api_key, + Method::Get(()), + 200, + ) + .await?; + + Ok(keys) + } + /// Get one API [Key] from Meilisearch. /// See the [meilisearch documentation](https://docs.meilisearch.com/reference/api/keys.html#get-one-key). /// @@ -475,9 +484,9 @@ impl Client { /// ``` pub async fn update_key(&self, key: impl AsRef) -> Result { request::<&Key, Key>( - &format!("{}/keys/{}", self.host, key.as_ref().key), + &format!("{}/keys/{}", self.host, key.identifier), &self.api_key, - Method::Patch(key.as_ref()), + Method::Patch(key.as_ref()), // name and description 200, ) .await diff --git a/src/key.rs b/src/key.rs index 55fdf41c..94ae80c7 100644 --- a/src/key.rs +++ b/src/key.rs @@ -21,6 +21,8 @@ pub struct Key { pub indexes: Vec, #[serde(skip_serializing)] pub key: String, + #[serde(skip_serializing)] + pub uid: String, #[serde(skip_serializing, with = "time::serde::rfc3339")] pub updated_at: OffsetDateTime, } @@ -108,6 +110,38 @@ impl Key { /// # }); /// ``` pub async fn update(&self, client: &Client) -> Result { + // only send description and name + let updated = KeyUpdater::new(self); + client.update_key(self).await + } + + // client.delete_key("1") + pub async fn delete(&self, client: &Client) -> Result { + client.delete_key(self).await + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct KeyUpdater { + pub description: Option, + pub name: Option, + #[serde(skip_serializing)] + pub identifier: String, +} + +impl KeyUpdater { + pub fn new(key: &Key) -> KeyUpdater { + KeyUpdater { + description: key.description, + name: key.name, + identifier: key.uid, + } + } + + pub async fn update(&self, client: &Client) -> Result { + // only send description and name + let updated = KeyUpdater::new(self); client.update_key(self).await } } @@ -320,6 +354,7 @@ impl KeyBuilder { /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` + /// TODO: create ? pub async fn execute(&self, client: &Client) -> Result { client.create_key(self).await } From abc0f7ba2ddd5c105e4822bb8efbe5d98bf0e664 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Tue, 9 Aug 2022 14:45:16 +0200 Subject: [PATCH 23/53] Update task API --- src/client.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++------ src/indexes.rs | 43 +++++++++++++++++++++++++++++++---------- src/tasks.rs | 21 +++++++++++++++----- 3 files changed, 95 insertions(+), 21 deletions(-) diff --git a/src/client.rs b/src/client.rs index 0ffc365c..acc543b7 100644 --- a/src/client.rs +++ b/src/client.rs @@ -608,7 +608,7 @@ impl Client { .await } - /// Get all tasks from the server. + /// Get all tasks with query parameters from the server. /// /// # Example /// @@ -622,14 +622,17 @@ impl Client { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// /// let mut query = tasks::TasksQuery::new(&client); - /// query.with_index_uid(["get_tasks"]); - /// let tasks = client.get_tasks(&query).await.unwrap(); + /// query.with_index_uid(["get_tasks_with"]); + /// let tasks = client.get_tasks_with(&query).await.unwrap(); /// /// assert!(tasks.results.len() > 0); - /// # client.index("get_tasks").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # client.index("get_tasks_with").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_tasks(&self, tasks_query: &TasksQuery<'_>) -> Result { + pub async fn get_tasks_with( + &self, + tasks_query: &TasksQuery<'_>, + ) -> Result { let tasks = request::<&TasksQuery, TasksResults>( &format!("{}/tasks", self.host), &self.api_key, @@ -641,6 +644,37 @@ impl Client { Ok(tasks) } + /// Get all tasks from the server. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::*; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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_HOST, MEILISEARCH_API_KEY); + /// + /// let tasks = client.get_tasks().await.unwrap(); + /// + /// assert!(tasks.results.len() > 0); + /// # client.index("get_tasks").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` + pub async fn get_tasks(&self) -> Result { + let tasks = request::<(), TasksResults>( + &format!("{}/tasks", self.host), + &self.api_key, + Method::Get(()), + 200, + ) + .await?; + + Ok(tasks) + } + /// Generates a new tenant token. /// /// # Example @@ -774,8 +808,14 @@ mod tests { #[meilisearch_test] async fn test_get_tasks(client: Client) { + let tasks = client.get_tasks().await.unwrap(); + assert!(tasks.results.len() >= 2); + } + + #[meilisearch_test] + async fn test_get_tasks_with_params(client: Client) { let query = TasksQuery::new(&client); - let tasks = client.get_tasks(&query).await.unwrap(); + let tasks = client.get_tasks_with(&query).await.unwrap(); assert!(tasks.results.len() >= 2); } diff --git a/src/indexes.rs b/src/indexes.rs index 1d317009..99eddf56 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -758,7 +758,7 @@ impl Index { /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// # let index = client.create_index("get_tasks", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap(); /// - /// let tasks = index.get_tasks().execute().await.unwrap(); + /// let tasks = index.get_tasks().await.unwrap(); /// /// assert!(tasks.results.len() > 0); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); @@ -767,19 +767,42 @@ impl Index { /// TODO: how to pass a tasks_query? pub async fn get_tasks(&self) -> Result { let mut query = TasksQuery::new(&self.client); - query.with_index_uid([self.uid.as_str()]); - self.client.get_tasks(&query).await + self.client.get_tasks_with(&query).await + } - // pub async fn get_tasks( - // &self, - // mut tasks_query: &mut TasksQuery<'_>, - // ) -> Result { - // tasks_query.with_index_uid([self.uid.as_str()]); + /// Get the status of all tasks in a given index. + /// + /// # Example + /// + /// ``` + /// # use serde::{Serialize, Deserialize}; + /// # use meilisearch_sdk::{client::*, indexes::*, tasks::*}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// # let index = client.create_index("get_tasks_with", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap(); + /// + /// let mut query = TasksQuery::new(&client); + /// query.with_index_uid(["none_existant"]); + /// let tasks = index.get_tasks_with(&query).await.unwrap(); + /// + /// assert!(tasks.results.len() > 0); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` + pub async fn get_tasks_with( + &self, + tasks_query: &TasksQuery<'_>, + ) -> Result { + let mut query = tasks_query.clone(); + query.with_index_uid([self.uid.as_str()]); - // self.client.get_tasks(&tasks_query).await - // } + self.client.get_tasks_with(&query).await } /// Get stats of an index. diff --git a/src/tasks.rs b/src/tasks.rs index 0623ce05..fb55ba8b 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -456,7 +456,7 @@ impl<'a> TasksQuery<'a> { } pub async fn execute(&'a self) -> Result { - self.client.get_tasks(self).await + self.client.get_tasks_with(self).await } } @@ -621,8 +621,7 @@ mod test { let path = "/tasks"; let mock_res = mock("GET", path).with_status(200).create(); - let query = TasksQuery::new(&client); - let _ = client.get_tasks(&query).await; + let _ = client.get_tasks().await; mock_res.assert(); Ok(()) @@ -645,7 +644,7 @@ mod test { .with_from(1) .with_limit(0); - let _ = client.get_tasks(&query).await; + let _ = client.get_tasks_with(&query).await; mock_res.assert(); Ok(()) @@ -676,7 +675,19 @@ mod test { async fn test_get_tasks_with_none_existant_index_uid(client: Client) -> Result<(), Error> { let mut query = TasksQuery::new(&client); query.with_index_uid(["no_name"]); - let tasks = client.get_tasks(&query).await.unwrap(); + let tasks = client.get_tasks_with(&query).await.unwrap(); + + assert_eq!(tasks.results.len(), 0); + Ok(()) + } + + #[meilisearch_test] + async fn test_get_tasks_with_execute(client: Client) -> Result<(), Error> { + let tasks = TasksQuery::new(&client) + .with_index_uid(["no_name"]) + .execute() + .await + .unwrap(); assert_eq!(tasks.results.len(), 0); Ok(()) From eaef1ea8809b21ea009501506921c45b57743e02 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Tue, 9 Aug 2022 14:47:49 +0200 Subject: [PATCH 24/53] Remove useless comment --- src/indexes.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index 99eddf56..54294f69 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -764,7 +764,6 @@ impl Index { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - /// TODO: how to pass a tasks_query? pub async fn get_tasks(&self) -> Result { let mut query = TasksQuery::new(&self.client); query.with_index_uid([self.uid.as_str()]); @@ -1101,14 +1100,6 @@ mod tests { assert!(index.primary_key.is_none()); } - // #[meilisearch_test] - // TODO: when implementing the filters in get_tasks - // async fn test_get_tasks_no_docs(index: Index) { - // // The at this point the only task that is supposed to exist is the creation of the index - // let status = index.get_tasks().await.unwrap(); - // assert_eq!(status.results.len(), 1); - // } - #[meilisearch_test] async fn test_get_one_task(client: Client, index: Index) -> Result<(), Error> { let task = index From d506eae6c292b98b0eebd61bb8f2ee7304a0d237 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 11:09:44 +0200 Subject: [PATCH 25/53] Remove client as mandatory parameter for the keyUpdater --- src/client.rs | 7 +- src/key.rs | 269 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 217 insertions(+), 59 deletions(-) diff --git a/src/client.rs b/src/client.rs index 4a178cb6..133e807b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -324,8 +324,11 @@ impl Client { /// # /// # futures::executor::block_on(async move { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let keys = client.get_keys().await.unwrap(); - /// assert!(keys.len() >= 2); + /// let mut query = KeysQuery::new(); + /// query.with_limit(1); + /// let keys = client.get_keys_with(&query).await.unwrap(); + /// + /// assert_eq!(keys.results.len(), 1); /// # }); /// ``` /// TODO: hidden diff --git a/src/key.rs b/src/key.rs index 94ae80c7..0d778ba1 100644 --- a/src/key.rs +++ b/src/key.rs @@ -40,14 +40,14 @@ impl Key { /// # /// # futures::executor::block_on(async move { /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// - /// let mut key = KeyBuilder::new("My little lovely test key") + /// let description = "My not so little lovely test key".to_string(); + /// let mut key = KeyBuilder::new() /// .with_action(Action::DocumentsAdd) /// .with_index("*") - /// .create(&client).await.unwrap(); + /// .with_description(&description) + /// .execute(&client).await.unwrap(); /// - /// key.with_description("My not so little lovely test key"); - /// # assert_eq!(key.description, "My not so little lovely test key".to_string()); + /// # assert_eq!(key.description, Some(description)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` @@ -68,14 +68,14 @@ impl Key { /// # /// # futures::executor::block_on(async move { /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// - /// let mut key = KeyBuilder::new("My little lovely test key") + /// let name = "lovely key".to_string(); + /// let mut key = KeyBuilder::new() /// .with_action(Action::DocumentsAdd) /// .with_index("*") - /// .create(&client).await.unwrap(); + /// .execute(&client).await.unwrap(); /// - /// key.with_name("lovely key"); - /// # assert_eq!(key.name, "lovely key".to_string()); + /// key.with_name(&name); + /// # assert_eq!(key.name, Some(name)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` @@ -96,73 +96,172 @@ impl Key { /// # /// # futures::executor::block_on(async move { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let mut key = KeyBuilder::new("My little lovely test key") - /// .create(&client).await.unwrap(); - /// - /// # assert_eq!(key.description, "My little lovely test key"); - /// - /// key.with_description("My not so little lovely test key"); + /// let mut key = KeyBuilder::new() + /// .execute(&client).await.unwrap(); + /// let description = "My not so little lovely test key".to_string(); + /// key.with_description(&description); /// let key = key.update(&client).await.unwrap(); /// - /// # assert_eq!(key.description, "My not so little lovely test key".to_string()); - /// + /// # assert_eq!(key.description, Some(description)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` pub async fn update(&self, client: &Client) -> Result { // only send description and name - let updated = KeyUpdater::new(self); - client.update_key(self).await + let mut key_update = KeyUpdater::new(self); + + if let Some(ref description) = self.description { + key_update.with_description(description); + } + if let Some(ref name) = self.name { + key_update.with_name(name); + } + + key_update.execute(client).await } - // client.delete_key("1") - pub async fn delete(&self, client: &Client) -> Result { + /// Delete the [Key]. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeyBuilder, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let mut key = KeyBuilder::new() + /// .execute(&client).await.unwrap(); + /// + /// client.delete_key(key).await.unwrap(); + /// # }); + /// ``` + pub async fn delete(&self, client: &Client) -> Result<(), Error> { client.delete_key(self).await } } +impl AsRef for Key { + fn as_ref(&self) -> &str { + &self.key + } +} + +impl AsRef for Key { + fn as_ref(&self) -> &Key { + self + } +} + #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct KeyUpdater { pub description: Option, pub name: Option, #[serde(skip_serializing)] - pub identifier: String, + pub key: String, } impl KeyUpdater { - pub fn new(key: &Key) -> KeyUpdater { + pub fn new(key_or_uid: impl AsRef) -> KeyUpdater { KeyUpdater { - description: key.description, - name: key.name, - identifier: key.uid, + description: None, + name: None, + key: key_or_uid.as_ref().to_string(), } } - pub async fn update(&self, client: &Client) -> Result { + /// Update the description of the key. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client, key::KeyUpdater}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// + /// let mut new_key = KeyBuilder::new() + /// .execute(&client) + /// .await + /// .unwrap(); + /// + /// let description = "My not so little lovely test key".to_string(); + /// let mut key_update = KeyUpdater::new(new_key) + /// .with_description(&description) + /// .execute(&client) + /// .await + /// .unwrap(); + /// + /// # assert_eq!(key_update.description, Some(description)); + /// # client.delete_key(key_update).await.unwrap(); + /// # }); + /// ``` + pub fn with_description(&mut self, desc: impl AsRef) -> &mut Self { + self.description = Some(desc.as_ref().to_string()); + self + } + + /// Update the name of the key. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client, key::KeyUpdater}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let mut new_key = KeyBuilder::new() + /// .execute(&client) + /// .await + /// .unwrap(); + /// + /// let name = "lovely key".to_string(); + /// + /// let mut key_update = KeyUpdater::new(new_key) + /// .with_name(&name) + /// .execute(&client) + /// .await + /// .unwrap(); + /// + /// # assert_eq!(key_update.name, Some(name)); + /// # client.delete_key(key_update).await.unwrap(); + /// # }); + /// ``` + pub fn with_name(&mut self, desc: impl AsRef) -> &mut Self { + self.name = Some(desc.as_ref().to_string()); + self + } + + pub async fn execute(&self, client: &Client) -> Result { // only send description and name - let updated = KeyUpdater::new(self); client.update_key(self).await } } -impl AsRef for Key { +impl AsRef for KeyUpdater { fn as_ref(&self) -> &str { &self.key } } -impl AsRef for Key { - fn as_ref(&self) -> &Key { +impl AsRef for KeyUpdater { + fn as_ref(&self) -> &KeyUpdater { self } } #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] -pub struct KeysQuery<'a> { - #[serde(skip_serializing)] - pub client: &'a Client, +pub struct KeysQuery { /// The number of documents to skip. /// If the value of the parameter `offset` is `n`, the `n` first documents (ordered by relevance) will not be returned. /// This is helpful for pagination. @@ -180,10 +279,9 @@ pub struct KeysQuery<'a> { pub limit: Option, } -impl<'a> KeysQuery<'a> { - pub fn new(client: &'a Client) -> KeysQuery<'a> { +impl KeysQuery { + pub fn new() -> KeysQuery { KeysQuery { - client, offset: None, limit: None, } @@ -200,7 +298,7 @@ impl<'a> KeysQuery<'a> { /// Execute the query and fetch the results. pub async fn execute(&'a self) -> Result { - self.client.execute_get_keys(self).await + self.client.get_keys_with(self).await } } @@ -217,13 +315,12 @@ impl<'a> KeysQuery<'a> { /// # /// # futures::executor::block_on(async move { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); +/// let description = "My little lovely test key".to_string(); +/// let key = KeyBuilder::new() +/// .with_description(&description) +/// .execute(&client).await.unwrap(); /// -/// let key = KeyBuilder::new("My little lovely test key") -/// .with_action(Action::DocumentsAdd) -/// .with_index("*") -/// .create(&client).await.unwrap(); -/// -/// assert_eq!(key.description, "My little lovely test key"); +/// assert_eq!(key.description, Some(description)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` @@ -232,6 +329,7 @@ impl<'a> KeysQuery<'a> { pub struct KeyBuilder { pub actions: Vec, pub description: Option, + pub name: Option, #[serde(with = "time::serde::rfc3339::option")] pub expires_at: Option, pub indexes: Vec, @@ -244,12 +342,13 @@ impl KeyBuilder { /// /// ``` /// # use meilisearch_sdk::{key::KeyBuilder}; - /// let builder = KeyBuilder::new("My little lovely test key"); + /// let builder = KeyBuilder::new(); /// ``` pub fn new() -> KeyBuilder { Self { actions: Vec::new(), description: None, + name: None, expires_at: None, indexes: Vec::new(), } @@ -261,7 +360,7 @@ impl KeyBuilder { /// /// ``` /// # use meilisearch_sdk::key::{KeyBuilder, Action}; - /// let mut builder = KeyBuilder::new("My little lovely test key"); + /// let mut builder = KeyBuilder::new(); /// builder.with_actions(vec![Action::Search, Action::DocumentsAdd]); /// ``` pub fn with_actions(&mut self, actions: impl IntoIterator) -> &mut Self { @@ -275,7 +374,7 @@ impl KeyBuilder { /// /// ``` /// # use meilisearch_sdk::key::{KeyBuilder, Action}; - /// let mut builder = KeyBuilder::new("My little lovely test key"); + /// let mut builder = KeyBuilder::new(); /// builder.with_action(Action::DocumentsAdd); /// ``` pub fn with_action(&mut self, action: Action) -> &mut Self { @@ -290,7 +389,7 @@ impl KeyBuilder { /// ``` /// # use meilisearch_sdk::{key::KeyBuilder}; /// use time::{OffsetDateTime, Duration}; - /// let mut builder = KeyBuilder::new("My little lovely test key"); + /// let mut builder = KeyBuilder::new(); /// // create a key that expires in two weeks from now /// builder.with_expires_at(OffsetDateTime::now_utc() + Duration::WEEK * 2); /// ``` @@ -305,7 +404,7 @@ impl KeyBuilder { /// /// ``` /// # use meilisearch_sdk::{key::KeyBuilder}; - /// let mut builder = KeyBuilder::new("My little lovely test key"); + /// let mut builder = KeyBuilder::new(); /// builder.with_indexes(vec!["test", "movies"]); /// ``` pub fn with_indexes( @@ -325,7 +424,7 @@ impl KeyBuilder { /// /// ``` /// # use meilisearch_sdk::{key::KeyBuilder}; - /// let mut builder = KeyBuilder::new("My little lovely test key"); + /// let mut builder = KeyBuilder::new(); /// builder.with_index("test"); /// ``` pub fn with_index(&mut self, index: impl AsRef) -> &mut Self { @@ -333,7 +432,61 @@ impl KeyBuilder { self } - // TODO: with_description + /// Add a description to the key. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let description = "My not so little lovely test key".to_string(); + /// + /// let mut key = KeyBuilder::new() + /// .with_description(&description) + /// .execute(&client).await.unwrap(); + /// + /// # assert_eq!(key.description, Some(description)); + /// # client.delete_key(key).await.unwrap(); + /// # }); + /// ``` + pub fn with_description(&mut self, desc: impl AsRef) -> &mut Self { + self.description = Some(desc.as_ref().to_string()); + self + } + + /// Update the name of the key. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let name = "lovely key".to_string(); + /// + /// let mut key = KeyBuilder::new() + /// .with_action(Action::DocumentsAdd) + /// .with_index("*") + /// .execute(&client).await.unwrap(); + /// + /// key.with_name(&name); + /// # assert_eq!(key.name, Some(name)); + /// # client.delete_key(key).await.unwrap(); + /// # }); + /// ``` + pub fn with_name(&mut self, desc: impl AsRef) -> &mut Self { + self.name = Some(desc.as_ref().to_string()); + self + } /// Create a [Key] from the builder. /// @@ -347,10 +500,12 @@ impl KeyBuilder { /// # /// # futures::executor::block_on(async move { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let key = KeyBuilder::new("My little lovely test key") - /// .create(&client).await.unwrap(); + /// let description = "My little lovely test key".to_string(); + /// let key = KeyBuilder::new() + /// .with_description(&description) + /// .execute(&client).await.unwrap(); /// - /// assert_eq!(key.description, "My little lovely test key"); + /// assert_eq!(key.description, Some(description)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` @@ -384,7 +539,7 @@ pub enum Action { #[serde(rename = "documents.delete")] DocumentsDelete, /// Provides access to the [create index](https://docs.meilisearch.com/reference/api/indexes.md#create-an-index) endpoint. - #[serde(rename = "indexes.create")] + #[serde(rename = "indexes.execute")] IndexesCreate, /// Provides access to the [get one index](https://docs.meilisearch.com/reference/api/indexes.md#get-one-index) and [list all indexes](https://docs.meilisearch.com/reference/api/indexes.md#list-all-indexes) endpoints. **Non-authorized `indexes` will be omitted from the response**. #[serde(rename = "indexes.get")] @@ -408,7 +563,7 @@ pub enum Action { #[serde(rename = "stats.get")] StatsGet, /// Provides access to the [create dump](https://docs.meilisearch.com/reference/api/dump.md#create-a-dump) endpoint. **Not restricted by `indexes`.** - #[serde(rename = "dumps.create")] + #[serde(rename = "dumps.execute")] DumpsCreate, /// Provides access to the [get dump status](https://docs.meilisearch.com/reference/api/dump.md#get-dump-status) endpoint. **Not restricted by `indexes`.** #[serde(rename = "dumps.get")] From c803fd50bc51538ec3c8688cbd5ff693bc01a17e Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 11:10:19 +0200 Subject: [PATCH 26/53] Add doc and tests on doc --- src/key.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 7 deletions(-) diff --git a/src/key.rs b/src/key.rs index 0d778ba1..af27878f 100644 --- a/src/key.rs +++ b/src/key.rs @@ -287,18 +287,79 @@ impl KeysQuery { } } - pub fn with_offset<'b>(&'b mut self, offset: usize) -> &'b mut KeysQuery<'a> { + /// Specify the offset. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeysQuery, key::Action, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let mut keys = KeysQuery::new() + /// .with_offset(1) + /// .execute(&client).await.unwrap(); + /// + /// # assert_eq!(keys.results.len(), 1); + /// # }); + /// ``` + pub fn with_offset<'b>(&'b mut self, offset: usize) -> &'b mut KeysQuery { self.offset = Some(offset); self } - pub fn with_limit<'b>(&'b mut self, limit: usize) -> &'b mut KeysQuery<'a> { + + /// Specify the maximum number of keys to return. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeysQuery, key::Action, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let mut keys = KeysQuery::new() + /// .with_limit(1) + /// .execute(&client).await.unwrap(); + /// + /// # assert_eq!(keys.results.len(), 1); + /// # }); + /// ``` + pub fn with_limit<'b>(&'b mut self, limit: usize) -> &'b mut KeysQuery { self.limit = Some(limit); self } - /// Execute the query and fetch the results. - pub async fn execute(&'a self) -> Result { - self.client.get_keys_with(self).await + /// Execute the update of a Key. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeyBuilder, key::KeyUpdater, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let description = "My little lovely test key".to_string(); + /// let key = KeyBuilder::new() + /// .execute(&client).await.unwrap(); + /// + /// let mut key_update = KeyUpdater::new(&key.key); + /// key_update.with_description(&description).execute(&client).await; + /// + /// assert_eq!(key_update.description, Some(description)); + /// # client.delete_key(key).await.unwrap(); + /// # }); + /// ``` + pub async fn execute(&self, client: &Client) -> Result { + client.get_keys_with(self).await } } @@ -459,7 +520,7 @@ impl KeyBuilder { self } - /// Update the name of the key. + /// Add a name to the key. /// /// # Example /// @@ -509,7 +570,6 @@ impl KeyBuilder { /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` - /// TODO: create ? pub async fn execute(&self, client: &Client) -> Result { client.create_key(self).await } From cdc2a41e95b114dfaf872eb4b53b232842a3ee72 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 11:11:11 +0200 Subject: [PATCH 27/53] Fix docs tests on keys in client --- src/client.rs | 107 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/src/client.rs b/src/client.rs index 133e807b..411e5885 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,7 +1,7 @@ use crate::{ errors::*, indexes::*, - key::{Key, KeyBuilder, KeysQuery, KeysResults}, + key::{Key, KeyBuilder, KeyUpdater, KeysQuery, KeysResults}, request::*, task_info::TaskInfo, tasks::{Task, TasksQuery, TasksResults}, @@ -309,7 +309,7 @@ impl Client { } } - /// Get the API [Key]s from Meilisearch. + /// Get the API [Key]s from Meilisearch with parameters. /// See the [meilisearch documentation](https://docs.meilisearch.com/reference/api/keys.html#get-all-keys). /// /// See also [Client::create_key] and [Client::get_key]. @@ -317,7 +317,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, errors::Error, key::KeyBuilder}; + /// # use meilisearch_sdk::{client::*, errors::Error, key::KeysQuery}; /// # /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -331,8 +331,7 @@ impl Client { /// assert_eq!(keys.results.len(), 1); /// # }); /// ``` - /// TODO: hidden - pub async fn get_keys_with(&self, keys_query: &KeysQuery<'_>) -> Result { + pub async fn get_keys_with(&self, keys_query: &KeysQuery) -> Result { let keys = request::<&KeysQuery, KeysResults>( &format!("{}/keys", self.host), &self.api_key, @@ -344,6 +343,27 @@ impl Client { Ok(keys) } + /// Get the API [Key]s from Meilisearch. + /// See the [meilisearch documentation](https://docs.meilisearch.com/reference/api/keys.html#get-all-keys). + /// + /// See also [Client::create_key] and [Client::get_key]. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, errors::Error, key::KeyBuilder}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let keys = client.get_keys().await.unwrap(); + /// + /// dbg!(&keys); + /// assert_eq!(keys.results.len(), 2); + /// # }); + /// ``` pub async fn get_keys(&self) -> Result { let keys = request::<(), KeysResults>( &format!("{}/keys", self.host), @@ -371,11 +391,13 @@ impl Client { /// # /// # futures::executor::block_on(async move { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// # let key = client.get_keys().await.unwrap().into_iter().find(|k| k.description.starts_with("Default Search API Key")).unwrap(); + /// # let key = client.get_keys().await.unwrap().results.into_iter() + /// .find(|k| k.name.as_ref().map_or(false, |name| name.starts_with("Default Search API Key"))); /// let key_id = // enter your API key here, for the example we'll say we entered our search API key. - /// # key.key; + /// # key.unwrap().key; /// let key = client.get_key(key_id).await.unwrap(); - /// assert_eq!(key.description, "Default Search API Key (Use it to search from the frontend)"); + /// + /// assert_eq!(key.name, Some("Default Search API Key".to_string())); /// # }); /// ``` pub async fn get_key(&self, key: impl AsRef) -> Result { @@ -403,14 +425,14 @@ impl Client { /// # /// # futures::executor::block_on(async move { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let key = KeyBuilder::new("delete_key"); + /// let key = KeyBuilder::new(); /// let key = client.create_key(key).await.unwrap(); /// let inner_key = key.key.clone(); /// /// client.delete_key(key).await.unwrap(); /// /// let keys = client.get_keys().await.unwrap(); - /// assert!(keys.iter().all(|key| key.key != inner_key)); + /// assert!(keys.results.iter().all(|key| key.key != inner_key)); /// # }); /// ``` pub async fn delete_key(&self, key: impl AsRef) -> Result<(), Error> { @@ -439,18 +461,17 @@ impl Client { /// # futures::executor::block_on(async move { /// /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let mut key = KeyBuilder::new("create_key"); - /// key.with_index("*").with_action(Action::DocumentsAdd); + /// let name = "create_key".to_string(); + /// let mut key = KeyBuilder::new(); + /// key.with_name(&name); + /// /// let key = client.create_key(key).await.unwrap(); - /// assert_eq!(key.description, "create_key"); + /// + /// assert_eq!(key.name, Some(name)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` pub async fn create_key(&self, key: impl AsRef) -> Result { - KeyBuilder::new(self) - } - - pub async fn execute_create_key() -> Blabla { request::<&KeyBuilder, Key>( &format!("{}/keys", self.host), &self.api_key, @@ -468,26 +489,27 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, errors::Error, key::KeyBuilder}; + /// # use meilisearch_sdk::{client::*, errors::Error, key::KeyBuilder, key::KeyUpdater}; /// # /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let key = KeyBuilder::new("update_key"); - /// let mut key = client.create_key(key).await.unwrap(); - /// assert!(key.indexes.is_empty()); - /// - /// key.indexes = vec!["*".to_string()]; - /// let key = client.update_key(key).await.unwrap(); - /// assert_eq!(key.indexes, vec!["*"]); + /// let new_key = KeyBuilder::new(); + /// let name = "my name".to_string(); + /// let mut new_key = client.create_key(new_key).await.unwrap(); + /// let mut key_update = KeyUpdater::new(new_key); + /// key_update.with_name(&name); + /// + /// let key = client.update_key(key_update).await.unwrap(); + /// assert_eq!(key.name, Some(name)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` - pub async fn update_key(&self, key: impl AsRef) -> Result { - request::<&Key, Key>( - &format!("{}/keys/{}", self.host, key.identifier), + pub async fn update_key(&self, key: impl AsRef) -> Result { + request::<&KeyUpdater, Key>( + &format!("{}/keys/{}", self.host, key.as_ref().key), &self.api_key, Method::Patch(key.as_ref()), // name and description 200, @@ -834,7 +856,7 @@ mod tests { #[meilisearch_test] async fn test_get_keys(client: Client) { - let keys = client.get_keys().execute().await.unwrap(); + let keys = client.get_keys().await.unwrap(); assert!(keys.results.len() >= 2); assert!(keys.results.iter().any(|k| k.description != Some("Default Search API Key (Use it to search from the frontend)".to_string()))); @@ -844,17 +866,17 @@ mod tests { } #[meilisearch_test] - async fn test_delete_key(client: Client, description: String) { + async fn test_delete_key(client: Client) { let key = KeyBuilder::new(); let key = client.create_key(key).await.unwrap(); client.delete_key(&key).await.unwrap(); - let keys = client.get_keys().execute().await.unwrap(); + let keys = client.get_keys().await.unwrap(); assert!(keys.results.iter().all(|k| k.key != key.key)); } #[meilisearch_test] - async fn test_error_delete_key(mut client: Client, description: String) { + async fn test_error_delete_key(mut client: Client) { // ==> accessing a key that does not exist let error = client.delete_key("invalid_key").await.unwrap_err(); assert!(matches!( @@ -905,6 +927,7 @@ mod tests { let mut key = KeyBuilder::new(); key.with_action(Action::DocumentsAdd) .with_expires_at(expires_at.clone()) + .with_description(&description) .with_index("*"); let key = client.create_key(key).await.unwrap(); @@ -921,7 +944,7 @@ mod tests { } #[meilisearch_test] - async fn test_error_create_key(mut client: Client, description: String) { + async fn test_error_create_key(mut client: Client) { // ==> Invalid index name /* TODO: uncomment once meilisearch fix this bug: https://github.com/meilisearch/meilisearch/issues/2158 let mut key = KeyBuilder::new(); @@ -964,25 +987,23 @@ mod tests { #[meilisearch_test] async fn test_update_key(client: Client, description: String) { - let expires_at = OffsetDateTime::now_utc() + time::Duration::HOUR; let key = KeyBuilder::new(); let mut key = client.create_key(key).await.unwrap(); - let description = "new description"; - let name = "new name"; - key.with_description(description); - key.with_name(name); + let name = "new name".to_string(); + key.with_description(&description); + key.with_name(&name); - let key = client.update_key(key).await.unwrap(); + let key = key.update(&client).await.unwrap(); - assert_eq!(key.description, Some(description.to_string())); - assert_eq!(key.indexes, vec!["*".to_string()]); + assert_eq!(key.description, Some(description)); + assert_eq!(key.name, Some(name)); client.delete_key(key).await.unwrap(); } #[meilisearch_test] - async fn test_error_update_key(mut client: Client, description: String) { + async fn test_error_update_key(mut client: Client) { let key = KeyBuilder::new(); let key = client.create_key(key).await.unwrap(); @@ -1009,7 +1030,7 @@ mod tests { let master_client = client.clone(); client.api_key = Arc::new(no_right_key.key.clone()); - let error = client.update_key(key).await.unwrap_err(); + let error = key.update(&client).await.unwrap_err(); assert!(matches!( error, From b2ba741ae9da9dd45a0b68eb8b09f75f726990d6 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 11:31:35 +0200 Subject: [PATCH 28/53] Fix docs tests --- src/client.rs | 60 ++++++++++----------------------------------------- src/key.rs | 46 +++++++++++++++++++++++++++------------ 2 files changed, 43 insertions(+), 63 deletions(-) diff --git a/src/client.rs b/src/client.rs index 411e5885..b2ea3b0e 100644 --- a/src/client.rs +++ b/src/client.rs @@ -466,7 +466,6 @@ impl Client { /// key.with_name(&name); /// /// let key = client.create_key(key).await.unwrap(); - /// /// assert_eq!(key.name, Some(name)); /// # client.delete_key(key).await.unwrap(); /// # }); @@ -867,7 +866,8 @@ mod tests { #[meilisearch_test] async fn test_delete_key(client: Client) { - let key = KeyBuilder::new(); + let mut key = KeyBuilder::new(); + key.with_name("test_delete_key"); let key = client.create_key(key).await.unwrap(); client.delete_key(&key).await.unwrap(); @@ -889,7 +889,8 @@ mod tests { )); // ==> executing the action without enough right - let key = KeyBuilder::new(); + let mut key = KeyBuilder::new(); + key.with_name("test_error_delete_key"); let key = client.create_key(key).await.unwrap(); let master_key = client.api_key.clone(); @@ -926,6 +927,7 @@ mod tests { let expires_at = OffsetDateTime::now_utc() + time::Duration::HOUR; let mut key = KeyBuilder::new(); key.with_action(Action::DocumentsAdd) + .with_name("test_create_key") .with_expires_at(expires_at.clone()) .with_description(&description) .with_index("*"); @@ -962,14 +964,16 @@ mod tests { */ // ==> executing the action without enough right - let no_right_key = KeyBuilder::new(); + let mut no_right_key = KeyBuilder::new(); + no_right_key.with_name("test_error_create_key"); let no_right_key = client.create_key(no_right_key).await.unwrap(); // backup the master key for cleanup at the end of the test let master_client = client.clone(); client.api_key = Arc::new(no_right_key.key.clone()); - let key = KeyBuilder::new(); + let mut key = KeyBuilder::new(); + key.with_name("test_error_create_key_2"); let error = client.create_key(key).await.unwrap_err(); assert!(matches!( @@ -987,7 +991,8 @@ mod tests { #[meilisearch_test] async fn test_update_key(client: Client, description: String) { - let key = KeyBuilder::new(); + let mut key = KeyBuilder::new(); + key.with_name("test_update_key"); let mut key = client.create_key(key).await.unwrap(); let name = "new name".to_string(); @@ -1002,49 +1007,6 @@ mod tests { client.delete_key(key).await.unwrap(); } - #[meilisearch_test] - async fn test_error_update_key(mut client: Client) { - let key = KeyBuilder::new(); - let key = client.create_key(key).await.unwrap(); - - // ==> Invalid index name - /* TODO: uncomment once meilisearch fix this bug: https://github.com/meilisearch/meilisearch/issues/2158 - key.indexes = vec!["invalid index # / \\name with spaces".to_string()]; - let error = client.update_key(key).await.unwrap_err(); - - assert!(matches!( - error, - Error::MeilisearchError { - error_code: ErrorCode::InvalidApiKeyIndexes, - error_type: ErrorType::InvalidRequest, - .. - } - )); - */ - - // ==> executing the action without enough right - let no_right_key = KeyBuilder::new(); - let no_right_key = client.create_key(no_right_key).await.unwrap(); - - // backup the master key for cleanup at the end of the test - let master_client = client.clone(); - client.api_key = Arc::new(no_right_key.key.clone()); - - let error = key.update(&client).await.unwrap_err(); - - assert!(matches!( - error, - Error::Meilisearch(MeilisearchError { - error_code: ErrorCode::InvalidApiKey, - error_type: ErrorType::Auth, - .. - }) - )); - - // cleanup - master_client.delete_key(&*client.api_key).await.unwrap(); - } - #[meilisearch_test] async fn test_get_index(client: Client, index_uid: String) -> Result<(), Error> { let task = client.create_index(&index_uid, None).await?; diff --git a/src/key.rs b/src/key.rs index af27878f..7d1548cc 100644 --- a/src/key.rs +++ b/src/key.rs @@ -241,8 +241,30 @@ impl KeyUpdater { self } + /// Update a Key using the [KeyUpdater]. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeyBuilder, key::KeyUpdater, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let description = "My little lovely test key".to_string(); + /// let key = KeyBuilder::new() + /// .execute(&client).await.unwrap(); + /// + /// let mut key_update = KeyUpdater::new(&key.key); + /// key_update.with_description(&description).execute(&client).await; + /// + /// assert_eq!(key_update.description, Some(description)); + /// # client.delete_key(key).await.unwrap(); + /// # }); + /// ``` pub async fn execute(&self, client: &Client) -> Result { - // only send description and name client.update_key(self).await } } @@ -335,27 +357,23 @@ impl KeysQuery { self } - /// Execute the update of a Key. + /// Get [Key]'s. /// /// # Example /// /// ``` - /// # use meilisearch_sdk::{key::KeyBuilder, key::KeyUpdater, client::Client}; + /// # use meilisearch_sdk::{key::KeysQuery, key::Action, client::Client}; /// # /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// let description = "My little lovely test key".to_string(); - /// let key = KeyBuilder::new() + /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let mut keys = KeysQuery::new() + /// .with_limit(1) /// .execute(&client).await.unwrap(); /// - /// let mut key_update = KeyUpdater::new(&key.key); - /// key_update.with_description(&description).execute(&client).await; - /// - /// assert_eq!(key_update.description, Some(description)); - /// # client.delete_key(key).await.unwrap(); + /// # assert_eq!(keys.results.len(), 1); /// # }); /// ``` pub async fn execute(&self, client: &Client) -> Result { @@ -467,6 +485,8 @@ impl KeyBuilder { /// # use meilisearch_sdk::{key::KeyBuilder}; /// let mut builder = KeyBuilder::new(); /// builder.with_indexes(vec!["test", "movies"]); + /// + /// assert_eq!(vec!["test", "movies"], builder.indexes); /// ``` pub fn with_indexes( &mut self, @@ -535,11 +555,9 @@ impl KeyBuilder { /// let name = "lovely key".to_string(); /// /// let mut key = KeyBuilder::new() - /// .with_action(Action::DocumentsAdd) - /// .with_index("*") /// .execute(&client).await.unwrap(); + /// key.with_name(&name); /// - /// key.with_name(&name); /// # assert_eq!(key.name, Some(name)); /// # client.delete_key(key).await.unwrap(); /// # }); From 24ff749f7d37c448d1b03b20310adbdf42fe6001 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 11:37:24 +0200 Subject: [PATCH 29/53] Remove dbg --- src/client.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/client.rs b/src/client.rs index b2ea3b0e..cb7f63ed 100644 --- a/src/client.rs +++ b/src/client.rs @@ -360,7 +360,6 @@ impl Client { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// let keys = client.get_keys().await.unwrap(); /// - /// dbg!(&keys); /// assert_eq!(keys.results.len(), 2); /// # }); /// ``` From 1b4133082721f953129dde5e767386abd640d543 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 11:57:52 +0200 Subject: [PATCH 30/53] Add with_uid filter --- src/key.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/key.rs b/src/key.rs index 7d1548cc..a3b7a86e 100644 --- a/src/key.rs +++ b/src/key.rs @@ -409,6 +409,8 @@ pub struct KeyBuilder { pub actions: Vec, pub description: Option, pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub uid: Option, #[serde(with = "time::serde::rfc3339::option")] pub expires_at: Option, pub indexes: Vec, @@ -429,6 +431,7 @@ impl KeyBuilder { description: None, name: None, expires_at: None, + uid: None, indexes: Vec::new(), } } @@ -482,11 +485,22 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::{key::KeyBuilder}; - /// let mut builder = KeyBuilder::new(); - /// builder.with_indexes(vec!["test", "movies"]); + /// # use meilisearch_sdk::{key::KeyBuilder, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let mut key = KeyBuilder::new() + /// .with_indexes(vec!["test", "movies"]) + /// .execute(&client) + /// .await + /// .unwrap(); /// - /// assert_eq!(vec!["test", "movies"], builder.indexes); + /// assert_eq!(vec!["test", "movies"], key.indexes); + /// # client.delete_key(key).await.unwrap(); + /// # }); /// ``` pub fn with_indexes( &mut self, @@ -555,8 +569,8 @@ impl KeyBuilder { /// let name = "lovely key".to_string(); /// /// let mut key = KeyBuilder::new() + /// .with_name(&name) /// .execute(&client).await.unwrap(); - /// key.with_name(&name); /// /// # assert_eq!(key.name, Some(name)); /// # client.delete_key(key).await.unwrap(); @@ -567,6 +581,34 @@ impl KeyBuilder { self } + /// Add an uid to the key. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeyBuilder, key::Action, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let uid = "93bcd7fb-2196-4fd9-acb7-3fca8a96e78f".to_string(); + /// + /// let mut key = KeyBuilder::new() + /// .with_uid(&uid) + /// .execute(&client).await.unwrap(); + /// + /// + /// # assert_eq!(key.uid, uid); + /// # client.delete_key(key).await.unwrap(); + /// # }); + /// ``` + pub fn with_uid(&mut self, desc: impl AsRef) -> &mut Self { + self.uid = Some(desc.as_ref().to_string()); + self + } + /// Create a [Key] from the builder. /// /// # Example From f6f821dadaf224574d4340c5570717f5ffe614ec Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 12:04:18 +0200 Subject: [PATCH 31/53] Add new actions on key creation --- src/key.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/key.rs b/src/key.rs index a3b7a86e..31188ab4 100644 --- a/src/key.rs +++ b/src/key.rs @@ -691,6 +691,18 @@ pub enum Action { /// Provides access to the [get Meilisearch version](https://docs.meilisearch.com/reference/api/version.md#get-version-of-meilisearch) endpoint. #[serde(rename = "version")] Version, + // Provides access to the [get Key](https://docs.meilisearch.com/reference/api/keys.html#get-one-key) and [get Keys](https://docs.meilisearch.com/reference/api/keys.html#get-all-keys) endpoints. + #[serde(rename = "keys.get")] + KeyGet, + // Provides access to the [create key](https://docs.meilisearch.com/reference/api/keys.html#create-a-key) endpoint. + #[serde(rename = "keys.create")] + KeyCreate, + // Provides access to the [update key](https://docs.meilisearch.com/reference/api/keys.html#update-a-key) endpoint. + #[serde(rename = "keys.update")] + KeyUpdate, + // Provides access to the [delete key](https://docs.meilisearch.com/reference/api/keys.html#delete-a-key) endpoint. + #[serde(rename = "keys.delete")] + KeyDelete, } #[derive(Debug, Clone, Deserialize)] From 710b2d6deef1c47062c958ea80d5c8bc5e482e36 Mon Sep 17 00:00:00 2001 From: cvermand <33010418+bidoubiwa@users.noreply.github.com> Date: Wed, 10 Aug 2022 17:01:57 +0200 Subject: [PATCH 32/53] Remove new line at the start of docs --- src/key.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/key.rs b/src/key.rs index 31188ab4..51eba9db 100644 --- a/src/key.rs +++ b/src/key.rs @@ -185,7 +185,6 @@ impl KeyUpdater { /// # /// # futures::executor::block_on(async move { /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// /// let mut new_key = KeyBuilder::new() /// .execute(&client) /// .await From 54d29ebec63da143cf191d896285f272e13031ae Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 17:09:57 +0200 Subject: [PATCH 33/53] Fix clippy errors --- src/key.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/key.rs b/src/key.rs index 31188ab4..420d05ce 100644 --- a/src/key.rs +++ b/src/key.rs @@ -281,7 +281,7 @@ impl AsRef for KeyUpdater { } } -#[derive(Debug, Serialize, Clone)] +#[derive(Debug, Serialize, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct KeysQuery { /// The number of documents to skip. @@ -302,11 +302,16 @@ pub struct KeysQuery { } impl KeysQuery { + /// Create a [KeysQuery] with only a description. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{key::KeysQuery}; + /// let builder = KeysQuery::new(); + /// ``` pub fn new() -> KeysQuery { - KeysQuery { - offset: None, - limit: None, - } + Self::default() } /// Specify the offset. @@ -328,7 +333,7 @@ impl KeysQuery { /// # assert_eq!(keys.results.len(), 1); /// # }); /// ``` - pub fn with_offset<'b>(&'b mut self, offset: usize) -> &'b mut KeysQuery { + pub fn with_offset(&mut self, offset: usize) -> &mut KeysQuery { self.offset = Some(offset); self } @@ -352,7 +357,7 @@ impl KeysQuery { /// # assert_eq!(keys.results.len(), 1); /// # }); /// ``` - pub fn with_limit<'b>(&'b mut self, limit: usize) -> &'b mut KeysQuery { + pub fn with_limit(&mut self, limit: usize) -> &mut KeysQuery { self.limit = Some(limit); self } @@ -403,11 +408,13 @@ impl KeysQuery { /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Default)] #[serde(rename_all = "camelCase")] pub struct KeyBuilder { pub actions: Vec, + #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, #[serde(skip_serializing_if = "Option::is_none")] pub uid: Option, @@ -417,7 +424,7 @@ pub struct KeyBuilder { } impl KeyBuilder { - /// Create a [KeyBuilder] with only a description. + /// Create a [KeyBuilder]. /// /// # Example /// @@ -426,14 +433,7 @@ impl KeyBuilder { /// let builder = KeyBuilder::new(); /// ``` pub fn new() -> KeyBuilder { - Self { - actions: Vec::new(), - description: None, - name: None, - expires_at: None, - uid: None, - indexes: Vec::new(), - } + Self::default() } /// Declare a set of actions the [Key] will be able to execute. From 398975824ad4b3525e75c25af51e00ae647a1404 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 17:11:57 +0200 Subject: [PATCH 34/53] Rename type in Task structure --- src/tasks.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tasks.rs b/src/tasks.rs index fb55ba8b..1b6e00ad 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -403,8 +403,8 @@ pub struct TasksQuery<'a> { #[serde(skip_serializing_if = "Option::is_none")] pub status: Option>, // Types array to only retrieve the tasks with these [TaskType]. - #[serde(skip_serializing_if = "Option::is_none")] - pub r#type: Option>, + #[serde(skip_serializing_if = "Option::is_none", rename = "type")] + pub task_type: Option>, // Maximum number of tasks to return #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, @@ -420,7 +420,7 @@ impl<'a> TasksQuery<'a> { client, index_uid: None, status: None, - r#type: None, + task_type: None, limit: None, from: None, } @@ -441,9 +441,9 @@ impl<'a> TasksQuery<'a> { } pub fn with_type<'b>( &'b mut self, - r#type: impl IntoIterator, + task_type: impl IntoIterator, ) -> &'b mut TasksQuery<'a> { - self.r#type = Some(r#type.into_iter().collect()); + self.task_type = Some(task_type.into_iter().collect()); self } pub fn with_limit<'b>(&'b mut self, limit: u32) -> &'b mut TasksQuery<'a> { From 668ba1338159f495b00c3f8e8b73e14a1f10e364 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 17:14:16 +0200 Subject: [PATCH 35/53] Removed useless newlines --- src/client.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/client.rs b/src/client.rs index acc543b7..450bb583 100644 --- a/src/client.rs +++ b/src/client.rs @@ -428,11 +428,11 @@ impl Client { /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); /// # /// # futures::executor::block_on(async move { - /// /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// let mut key = KeyBuilder::new("create_key"); /// key.with_index("*").with_action(Action::DocumentsAdd); /// let key = client.create_key(key).await.unwrap(); + /// /// assert_eq!(key.description, "create_key"); /// # client.delete_key(key).await.unwrap(); /// # }); @@ -620,12 +620,11 @@ impl Client { /// # /// # futures::executor::block_on(async move { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// /// let mut query = tasks::TasksQuery::new(&client); /// query.with_index_uid(["get_tasks_with"]); /// let tasks = client.get_tasks_with(&query).await.unwrap(); /// - /// assert!(tasks.results.len() > 0); + /// # assert!(tasks.results.len() > 0); /// # client.index("get_tasks_with").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` @@ -656,10 +655,9 @@ impl Client { /// # /// # futures::executor::block_on(async move { /// # let client = client::Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); - /// /// let tasks = client.get_tasks().await.unwrap(); /// - /// assert!(tasks.results.len() > 0); + /// # assert!(tasks.results.len() > 0); /// # client.index("get_tasks").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` From ac953292e3e008c927ae5657a7cc42843c046413 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 17:14:24 +0200 Subject: [PATCH 36/53] Fix typo in comment --- src/tasks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks.rs b/src/tasks.rs index 1b6e00ad..6467115c 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -408,7 +408,7 @@ pub struct TasksQuery<'a> { // Maximum number of tasks to return #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, - // The if og the first task uid that should be returned + // The first task uid that should be returned #[serde(skip_serializing_if = "Option::is_none")] pub from: Option, } From 66bd1a5ed2af6b59e3eb668c12fbc77bc6705092 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 17:14:36 +0200 Subject: [PATCH 37/53] Add missing semi-column --- src/search.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.rs b/src/search.rs index fe2fbfca..200c8de2 100644 --- a/src/search.rs +++ b/src/search.rs @@ -113,7 +113,7 @@ type AttributeToCrop<'a> = (&'a str, Option); /// .with_offset(42) /// .with_limit(21) /// -/// let res = query.execute().await?.unwrap() +/// let res = query.execute().await?.unwrap(); /// ``` /// /// ``` From 31b394160b23946bf9e105f1319180f822dc11a5 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 10 Aug 2022 17:48:22 +0200 Subject: [PATCH 38/53] Update indexes api for v0.28.0 --- .code-samples.meilisearch.yaml | 2 +- src/client.rs | 16 +++++++++------- src/indexes.rs | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index eb7673ab..196cc9a5 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -6,7 +6,7 @@ get_one_index_1: |- let movies: Index = client.get_index("movies").await.unwrap(); list_all_indexes_1: |- - let indexes: Vec = client.list_all_indexes().await.unwrap(); + let indexes: IndexesResults = client.list_all_indexes().await.unwrap(); create_an_index_1: |- client.create_index("movies", Some("id")).await.unwrap(); update_an_index_1: |- diff --git a/src/client.rs b/src/client.rs index 437d43bb..0ce462be 100644 --- a/src/client.rs +++ b/src/client.rs @@ -55,13 +55,15 @@ impl Client { /// // create the client /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// - /// let indexes: Vec = client.list_all_indexes().await.unwrap(); + /// let indexes: IndexesResults = client.list_all_indexes().await.unwrap(); /// println!("{:?}", indexes); /// # }); /// ``` - pub async fn list_all_indexes(&self) -> Result, Error> { - self.list_all_indexes_raw() - .await? + pub async fn list_all_indexes(&self) -> Result { + let raw_indexes = self.list_all_indexes_raw().await?; + let indexes = IndexesResults::from_value(raw_indexes); + indexes + .results .into_iter() .map(|index| Index::from_value(index, self.clone())) .collect() @@ -85,8 +87,8 @@ impl Client { /// println!("{:?}", json_indexes); /// # }); /// ``` - pub async fn list_all_indexes_raw(&self) -> Result, Error> { - let json_indexes = request::<(), Vec>( + pub async fn list_all_indexes_raw(&self) -> Result { + let json_indexes = request::<(), Value>( &format!("{}/indexes", self.host), &self.api_key, Method::Get(()), @@ -225,7 +227,7 @@ impl Client { } /// Alias for [Client::list_all_indexes]. - pub async fn get_indexes(&self) -> Result, Error> { + pub async fn get_indexes(&self) -> Result { self.list_all_indexes().await } diff --git a/src/indexes.rs b/src/indexes.rs index 067a9ab1..6821f165 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -1053,6 +1053,40 @@ pub struct IndexStats { pub field_distribution: HashMap, } +#[derive(Debug, Clone, Deserialize)] +pub struct IndexesResults { + pub results: Vec, + pub limit: u32, + pub offset: u32, + pub total: u32, +} + +impl IndexesResults { + /// Internal Function to create an [Index] from `serde_json::Value` and [Client] + pub(crate) fn from_value(v: serde_json::Value, client: Client) -> Result { + #[derive(Deserialize, Debug)] + #[allow(non_snake_case)] + struct IndexFromSerde { + uid: String, + #[serde(with = "time::serde::rfc3339::option")] + updatedAt: Option, + #[serde(with = "time::serde::rfc3339::option")] + createdAt: Option, + primaryKey: Option, + } + + let i: IndexFromSerde = serde_json::from_value(v).map_err(Error::ParseError)?; + + Ok(Index { + uid: Arc::new(i.uid), + client, + created_at: i.createdAt, + updated_at: i.updatedAt, + primary_key: i.primaryKey, + }) + } +} + #[cfg(test)] mod tests { use super::*; From 027181b0ed863bd527525e88487ec34dbada9ff9 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 22 Aug 2022 17:21:32 +0200 Subject: [PATCH 39/53] Improve doc comments --- src/client.rs | 3 +-- src/key.rs | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/client.rs b/src/client.rs index 437d43bb..3cc2cea4 100644 --- a/src/client.rs +++ b/src/client.rs @@ -392,8 +392,7 @@ impl Client { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// # let key = client.get_keys().await.unwrap().results.into_iter() /// .find(|k| k.name.as_ref().map_or(false, |name| name.starts_with("Default Search API Key"))); - /// let key_id = // enter your API key here, for the example we'll say we entered our search API key. - /// # key.unwrap().key; + /// let key_id = key.unwrap().key // enter your API key here, for the example we use the search API key. /// let key = client.get_key(key_id).await.unwrap(); /// /// assert_eq!(key.name, Some("Default Search API Key".to_string())); diff --git a/src/key.rs b/src/key.rs index e01cf84b..c1d5e6d9 100644 --- a/src/key.rs +++ b/src/key.rs @@ -240,7 +240,7 @@ impl KeyUpdater { self } - /// Update a Key using the [KeyUpdater]. + /// Update a [Key] using the [KeyUpdater]. /// /// # Example /// @@ -259,7 +259,7 @@ impl KeyUpdater { /// let mut key_update = KeyUpdater::new(&key.key); /// key_update.with_description(&description).execute(&client).await; /// - /// assert_eq!(key_update.description, Some(description)); + /// # assert_eq!(key_update.description, Some(description)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` @@ -403,7 +403,7 @@ impl KeysQuery { /// .with_description(&description) /// .execute(&client).await.unwrap(); /// -/// assert_eq!(key.description, Some(description)); +/// # assert_eq!(key.description, Some(description)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` @@ -625,7 +625,7 @@ impl KeyBuilder { /// .with_description(&description) /// .execute(&client).await.unwrap(); /// - /// assert_eq!(key.description, Some(description)); + /// # assert_eq!(key.description, Some(description)); /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` From 9b36f774fed0eb73674ac1a345e1a7893d101a4e Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Tue, 23 Aug 2022 11:31:07 +0200 Subject: [PATCH 40/53] Change indexes methods --- src/client.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client.rs b/src/client.rs index 2308aaa1..d1e3fd92 100644 --- a/src/client.rs +++ b/src/client.rs @@ -497,6 +497,7 @@ impl Client { /// let new_key = KeyBuilder::new(); /// let name = "my name".to_string(); /// let mut new_key = client.create_key(new_key).await.unwrap(); + /// // TODO: Can i directly update the key using new_key /// let mut key_update = KeyUpdater::new(new_key); /// key_update.with_name(&name); /// From 335fbf1917e3e57018faf3777271e7fa66b1560b Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Tue, 23 Aug 2022 19:15:09 +0200 Subject: [PATCH 41/53] Add index query and index updater --- src/client.rs | 108 +++++++++++++--- src/indexes.rs | 342 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 378 insertions(+), 72 deletions(-) diff --git a/src/client.rs b/src/client.rs index d1e3fd92..d10725b3 100644 --- a/src/client.rs +++ b/src/client.rs @@ -41,6 +41,22 @@ impl Client { } } + fn parse_indexes_results_from_value(&self, value: Value) -> Result { + let raw_indexes = value["results"].as_array().unwrap(); + + let indexes_results = IndexesResults { + limit: value["limit"].as_u64().unwrap() as u32, + offset: value["offset"].as_u64().unwrap() as u32, + total: value["total"].as_u64().unwrap() as u32, + results: raw_indexes + .into_iter() + .map(|raw_index| Index::from_value(raw_index.clone(), self.clone())) + .collect::>()?, + }; + + Ok(indexes_results) + } + /// List all [Index]es and returns values as instances of [Index]. /// /// # Example @@ -60,13 +76,37 @@ impl Client { /// # }); /// ``` pub async fn list_all_indexes(&self) -> Result { - let raw_indexes = self.list_all_indexes_raw().await?; - let indexes = IndexesResults::from_value(raw_indexes); - indexes - .results - .into_iter() - .map(|index| Index::from_value(index, self.clone())) - .collect() + let value = self.list_all_indexes_raw().await?; + let indexes_results = self.parse_indexes_results_from_value(value)?; + Ok(indexes_results) + } + + /// List all [Index]es and returns values as instances of [Index]. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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_HOST, MEILISEARCH_API_KEY); + /// + /// let indexes: IndexesResults = client.list_all_indexes().await.unwrap(); + /// println!("{:?}", indexes); + /// # }); + /// ``` + pub async fn list_all_indexes_with( + &self, + indexes_query: &IndexesQuery<'_>, + ) -> Result { + let value = self.list_all_indexes_raw_with(&indexes_query).await?; + let indexes_results = self.parse_indexes_results_from_value(value)?; + + Ok(indexes_results) } /// List all [Index]es and returns as Json. @@ -99,6 +139,39 @@ impl Client { Ok(json_indexes) } + /// List all [Index]es and returns as Json. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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_HOST, MEILISEARCH_API_KEY); + /// + /// let json_indexes = client.list_all_indexes_raw().await.unwrap(); + /// println!("{:?}", json_indexes); + /// # }); + /// ``` + pub async fn list_all_indexes_raw_with( + &self, + indexes_query: &IndexesQuery<'_>, + ) -> Result { + let json_indexes = request::<&IndexesQuery, Value>( + &format!("{}/indexes", self.host), + &self.api_key, + Method::Get(indexes_query), + 200, + ) + .await?; + + Ok(json_indexes) + } + /// Get an [Index], this index should already exist. /// /// # Example @@ -160,13 +233,7 @@ impl Client { /// Create a corresponding object of an [Index] without any check or doing an HTTP call. pub fn index(&self, uid: impl Into) -> Index { - Index { - uid: Arc::new(uid.into()), - client: self.clone(), - primary_key: None, - created_at: None, - updated_at: None, - } + Index::new(uid, self.clone()) } /// Create an [Index]. @@ -232,7 +299,7 @@ impl Client { } /// Alias for [Client::list_all_indexes_raw]. - pub async fn get_indexes_raw(&self) -> Result, Error> { + pub async fn get_indexes_raw(&self) -> Result { self.list_all_indexes_raw().await } @@ -1061,15 +1128,18 @@ mod tests { #[meilisearch_test] async fn test_list_all_indexes(client: Client, index: Index) { let all_indexes = client.list_all_indexes().await.unwrap(); - assert!(all_indexes.len() > 0); - assert!(all_indexes.iter().any(|idx| idx.uid == index.uid)); + // TODO: Check total, limit, offset + assert!(all_indexes.results.len() > 0); + assert!(all_indexes.results.iter().any(|idx| idx.uid == index.uid)); } #[meilisearch_test] async fn test_list_all_indexes_raw(client: Client, index: Index) { let all_indexes_raw = client.list_all_indexes_raw().await.unwrap(); - assert!(all_indexes_raw.len() > 0); - assert!(all_indexes_raw + let raw_indexes = all_indexes_raw["results"].as_array().unwrap(); + // TODO: Check total, limit, offset + assert!(raw_indexes.len() > 0); + assert!(raw_indexes .iter() .any(|idx| idx["uid"] == json!(index.uid.to_string()))); } diff --git a/src/indexes.rs b/src/indexes.rs index 6821f165..31ed7edd 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -1,7 +1,6 @@ use crate::{client::Client, errors::Error, request::*, search::*, task_info::TaskInfo, tasks::*}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use serde_json::json; -use std::{collections::HashMap, fmt::Display, sync::Arc, time::Duration}; +use std::{collections::HashMap, fmt::Display, time::Duration}; use time::OffsetDateTime; /// An index containing [Document]s. @@ -37,7 +36,7 @@ use time::OffsetDateTime; /// # }); /// ``` /// -/// Or, if you know the index already exist remotely you can create an `Index` with the [Client::index] function. +/// Or, if you know the index already exist remotely you can create an [Index] with its builder. /// ``` /// # use meilisearch_sdk::{client::*, indexes::*}; /// # @@ -47,27 +46,39 @@ use time::OffsetDateTime; /// # futures::executor::block_on(async move { /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// -/// // use the implicit index creation if the index already exist or /// // Meilisearch would be able to create the index if it does not exist during: /// // - the documents addition (add and update routes) /// // - the settings update -/// let movies = client.index("index"); +/// let movies = Index::new("movies", client); /// -/// // do something with the index +/// assert_eq!(movies.uid, "movies"); /// # }); /// ``` -#[derive(Debug, Clone)] +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct Index { - pub(crate) uid: Arc, - pub(crate) client: Client, - pub(crate) primary_key: Option, - pub created_at: Option, + #[serde(skip_serializing)] + pub client: Client, + pub uid: String, + #[serde(with = "time::serde::rfc3339::option")] pub updated_at: Option, + #[serde(with = "time::serde::rfc3339::option")] + pub created_at: Option, + pub primary_key: Option, } impl Index { + pub fn new(uid: impl Into, client: Client) -> Index { + Index { + uid: uid.into(), + client, + primary_key: None, + created_at: None, + updated_at: None, + } + } /// Internal Function to create an [Index] from `serde_json::Value` and [Client] - pub(crate) fn from_value(v: serde_json::Value, client: Client) -> Result { + pub(crate) fn from_value(raw_index: serde_json::Value, client: Client) -> Result { #[derive(Deserialize, Debug)] #[allow(non_snake_case)] struct IndexFromSerde { @@ -79,10 +90,10 @@ impl Index { primaryKey: Option, } - let i: IndexFromSerde = serde_json::from_value(v).map_err(Error::ParseError)?; + let i: IndexFromSerde = serde_json::from_value(raw_index).map_err(Error::ParseError)?; Ok(Index { - uid: Arc::new(i.uid), + uid: i.uid, client, created_at: i.createdAt, updated_at: i.updatedAt, @@ -93,15 +104,14 @@ impl Index { /// Set the primary key of the index. /// /// If you prefer, you can use the method [Index::set_primary_key], which is an alias. - pub async fn update(&self, primary_key: impl AsRef) -> Result<(), Error> { - request::( - &format!("{}/indexes/{}", self.client.host, self.uid), - &self.client.api_key, - Method::Patch(json!({ "primaryKey": primary_key.as_ref() })), - 200, - ) - .await?; - Ok(()) + pub async fn update(&self) -> Result { + let mut index_update = IndexUpdater::new(self, &self.client); + + if let Some(ref primary_key) = self.primary_key { + index_update.with_primary_key(primary_key); + } + + index_update.execute().await } /// Delete the index. @@ -630,9 +640,16 @@ impl Index { .await } + // let mut index = Index::new(uid, client); + // index.set_primary_key(primary_key) /// Alias for the [Index::update] method. - pub async fn set_primary_key(&self, primary_key: impl AsRef) -> Result<(), Error> { - self.update(primary_key).await + pub async fn set_primary_key( + &mut self, + primary_key: impl AsRef, + ) -> Result { + self.primary_key = Some(primary_key.as_ref().to_string()); + + self.update().await } /// Fetch the information of the index as a raw JSON [Index], this index should already exist. @@ -659,7 +676,7 @@ impl Index { /// ``` /// If you use it directly from the [Client], you can use the method [Client::get_raw_index], which is the equivalent method from the client. pub async fn fetch_info(&mut self) -> Result<(), Error> { - let v = self.client.get_raw_index(self.uid.as_ref()).await?; + let v = self.client.get_raw_index(&self.uid).await?; *self = Index::from_value(v, self.client.clone())?; Ok(()) } @@ -1045,6 +1062,83 @@ impl AsRef for Index { } } +// An [IndexUpdater] used to update the specifics of an index +/// +/// # Example +/// +/// ``` +/// # use meilisearch_sdk::{client::*, indexes::*, task_info::*}; +/// # +/// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); +/// // let index = client +/// // .create_index("index_query_builder", None) +/// // .await +/// // .unwrap() +/// // .wait_for_completion(&client, None, None) +/// // .await +/// // .unwrap() +/// // // Once the task finished, we try to create an `Index` out of it +/// // .try_make_index(&client) +/// // .unwrap(); +/// // dbg!(&index); +/// +/// let task: TaskInfo = IndexUpdater::new("index_query_builder", &client).execute().await.unwrap(); +/// dbg!(&task); +/// +/// # // index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); +/// # }); +/// ``` +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct IndexUpdater<'a> { + #[serde(skip)] + pub client: &'a Client, + #[serde(skip_serializing)] + pub uid: String, + pub primary_key: Option, +} + +impl<'a> IndexUpdater<'a> { + pub fn new(uid: impl AsRef, client: &Client) -> IndexUpdater { + IndexUpdater { + client, + primary_key: None, + uid: uid.as_ref().to_string(), + } + } + + pub fn with_primary_key(&mut self, primary_key: impl AsRef) -> &mut Self { + self.primary_key = Some(primary_key.as_ref().to_string()); + self + } + + pub async fn execute(&'a self) -> Result { + request::<&IndexUpdater, TaskInfo>( + &format!("{}/indexes/{}", self.client.host, self.uid), + &self.client.api_key, + Method::Patch(self), + 202, + ) + .await + } +} + +impl AsRef for IndexUpdater<'_> { + fn as_ref(&self) -> &str { + &self.uid + } +} + +impl<'a> AsRef> for IndexUpdater<'a> { + fn as_ref(&self) -> &IndexUpdater<'a> { + self + } +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct IndexStats { @@ -1053,45 +1147,187 @@ pub struct IndexStats { pub field_distribution: HashMap, } -#[derive(Debug, Clone, Deserialize)] -pub struct IndexesResults { - pub results: Vec, - pub limit: u32, - pub offset: u32, - pub total: u32, +// An [IndexesQuery] containing filter and pagination parameters when searching for [Index]es +/// +/// # Example +/// +/// ``` +/// # use meilisearch_sdk::{client::*, indexes::*}; +/// # +/// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); +/// # let index = client +/// # .create_index("index_query_builder", None) +/// # .await +/// # .unwrap() +/// # .wait_for_completion(&client, None, None) +/// # .await +/// # .unwrap() +/// # // Once the task finished, we try to create an `Index` out of it +/// # .try_make_index(&client) +/// # .unwrap(); +/// let mut indexes = IndexesQuery::new(&client) +/// .with_limit(1) +/// .execute().await.unwrap(); +/// +/// # assert_eq!(indexes.results.len(), 1); +/// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); +/// # }); +/// ``` +#[derive(Debug, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct IndexesQuery<'a> { + #[serde(skip_serializing)] + pub client: &'a Client, + /// The number of [Index]es to skip. + /// If the value of the parameter `offset` is `n`, the `n` first indexes will not be returned. + /// This is helpful for pagination. + /// + /// Example: If you want to skip the first index, set offset to `1`. + #[serde(skip_serializing_if = "Option::is_none")] + pub offset: Option, + + /// The maximum number of [Index]es returned. + /// If the value of the parameter `limit` is `n`, there will never be more than `n` indexes in the response. + /// This is helpful for pagination. + /// + /// Example: If you don't want to get more than two indexes, set limit to `2`. + /// Default: `20` + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, } -impl IndexesResults { - /// Internal Function to create an [Index] from `serde_json::Value` and [Client] - pub(crate) fn from_value(v: serde_json::Value, client: Client) -> Result { - #[derive(Deserialize, Debug)] - #[allow(non_snake_case)] - struct IndexFromSerde { - uid: String, - #[serde(with = "time::serde::rfc3339::option")] - updatedAt: Option, - #[serde(with = "time::serde::rfc3339::option")] - createdAt: Option, - primaryKey: Option, +impl<'a> IndexesQuery<'a> { + pub fn new(client: &Client) -> IndexesQuery { + IndexesQuery { + client, + offset: None, + limit: None, } + } - let i: IndexFromSerde = serde_json::from_value(v).map_err(Error::ParseError)?; + /// Specify the offset. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// # let index = client + /// # .create_index("index_query_with_offset", None) + /// # .await + /// # .unwrap() + /// # .wait_for_completion(&client, None, None) + /// # .await + /// # .unwrap() + /// # // Once the task finished, we try to create an `Index` out of it + /// # .try_make_index(&client) + /// # .unwrap(); + /// + /// let mut indexes = IndexesQuery::new(&client) + /// .with_offset(1) + /// .execute().await.unwrap(); + /// + /// # assert_eq!(indexes.results.len(), 0); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` + pub fn with_offset(&mut self, offset: usize) -> &mut IndexesQuery<'a> { + self.offset = Some(offset); + self + } - Ok(Index { - uid: Arc::new(i.uid), - client, - created_at: i.createdAt, - updated_at: i.updatedAt, - primary_key: i.primaryKey, - }) + /// Specify the maximum number of [Index]es to return. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// # let index = client + /// # .create_index("index_query_with_limit", None) + /// # .await + /// # .unwrap() + /// # .wait_for_completion(&client, None, None) + /// # .await + /// # .unwrap() + /// # // Once the task finished, we try to create an `Index` out of it + /// # .try_make_index(&client) + /// # .unwrap(); + /// let mut indexes = IndexesQuery::new(&client) + /// .with_limit(1) + /// .execute().await.unwrap(); + /// + /// # assert_eq!(indexes.results.len(), 1); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` + pub fn with_limit(&mut self, limit: usize) -> &mut IndexesQuery<'a> { + self.limit = Some(limit); + self + } + /// Get [Index]es. + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{indexes::IndexesQuery, client::Client}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// # let index = client + /// # .create_index("index_query_with_limit", None) + /// # .await + /// # .unwrap() + /// # .wait_for_completion(&client, None, None) + /// # .await + /// # .unwrap() + /// # // Once the task finished, we try to create an `Index` out of it + /// # .try_make_index(&client) + /// # .unwrap(); + /// let mut indexes = IndexesQuery::new(&client) + /// .with_limit(1) + /// .execute().await.unwrap(); + /// + /// # assert_eq!(indexes.results.len(), 1); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` + pub async fn execute(&self) -> Result { + self.client.list_all_indexes_with(self).await } } +#[derive(Debug, Clone)] +pub struct IndexesResults { + pub results: Vec, + pub limit: u32, + pub offset: u32, + pub total: u32, +} + #[cfg(test)] mod tests { use super::*; use meilisearch_test_macro::meilisearch_test; + use serde_json::json; #[meilisearch_test] async fn test_from_value(client: Client) { @@ -1108,7 +1344,7 @@ mod tests { }); let idx = Index { - uid: Arc::new("test_from_value".to_string()), + uid: "test_from_value".to_string(), primary_key: None, created_at: Some(t), updated_at: Some(t), From 7b5b5e2cffecf8365e4993d4a2bb274f8f922365 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 24 Aug 2022 11:46:27 +0200 Subject: [PATCH 42/53] Add documentation and doc tests on indexes routes --- src/indexes.rs | 114 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 17 deletions(-) diff --git a/src/indexes.rs b/src/indexes.rs index 31ed7edd..1dedbf73 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -1062,34 +1062,41 @@ impl AsRef for Index { } } -// An [IndexUpdater] used to update the specifics of an index +/// An [IndexUpdater] used to update the specifics of an index /// /// # Example /// /// ``` -/// # use meilisearch_sdk::{client::*, indexes::*, task_info::*}; +/// # use meilisearch_sdk::{client::*, indexes::*, task_info::*, tasks::{Task, SucceededTask}}; /// # /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); -/// // let index = client -/// // .create_index("index_query_builder", None) -/// // .await -/// // .unwrap() -/// // .wait_for_completion(&client, None, None) -/// // .await -/// // .unwrap() -/// // // Once the task finished, we try to create an `Index` out of it -/// // .try_make_index(&client) -/// // .unwrap(); -/// // dbg!(&index); +/// # let index = client +/// # .create_index("index_updater", None) +/// # .await +/// # .unwrap() +/// # .wait_for_completion(&client, None, None) +/// # .await +/// # .unwrap() +/// # // Once the task finished, we try to create an `Index` out of it +/// # .try_make_index(&client) +/// # .unwrap(); /// -/// let task: TaskInfo = IndexUpdater::new("index_query_builder", &client).execute().await.unwrap(); -/// dbg!(&task); +/// let task = IndexUpdater::new("index_updater", &client) +/// .with_primary_key("special_id") +/// .execute() +/// .await +/// .unwrap() +/// .wait_for_completion(&client, None, None) +/// .await +/// .unwrap(); /// -/// # // index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); +/// let index = client.get_index("index_updater").await.unwrap(); +/// assert_eq!(index.primary_key, Some("special_id".to_string())); +/// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` #[derive(Debug, Serialize, Clone)] @@ -1110,12 +1117,85 @@ impl<'a> IndexUpdater<'a> { uid: uid.as_ref().to_string(), } } - + /// Define the new primary_key to set on the [Index] + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*, task_info::*, tasks::{Task, SucceededTask}}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// # let index = client + /// # .create_index("index_updater_with_primary_key", None) + /// # .await + /// # .unwrap() + /// # .wait_for_completion(&client, None, None) + /// # .await + /// # .unwrap() + /// # // Once the task finished, we try to create an `Index` out of it + /// # .try_make_index(&client) + /// # .unwrap(); + /// + /// let task = IndexUpdater::new("index_updater_with_primary_key", &client) + /// .with_primary_key("special_id") + /// .execute() + /// .await + /// .unwrap() + /// .wait_for_completion(&client, None, None) + /// .await + /// .unwrap(); + /// + /// let index = client.get_index("index_updater_with_primary_key").await.unwrap(); + /// assert_eq!(index.primary_key, Some("special_id".to_string())); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` pub fn with_primary_key(&mut self, primary_key: impl AsRef) -> &mut Self { self.primary_key = Some(primary_key.as_ref().to_string()); self } + /// Execute the update of an [Index] using the [IndexUpdater] + /// + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*, task_info::*, tasks::{Task, SucceededTask}}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// # let index = client + /// # .create_index("index_updater_execute", None) + /// # .await + /// # .unwrap() + /// # .wait_for_completion(&client, None, None) + /// # .await + /// # .unwrap() + /// # // Once the task finished, we try to create an `Index` out of it + /// # .try_make_index(&client) + /// # .unwrap(); + /// + /// let task = IndexUpdater::new("index_updater_execute", &client) + /// .with_primary_key("special_id") + /// .execute() + /// .await + /// .unwrap() + /// .wait_for_completion(&client, None, None) + /// .await + /// .unwrap(); + /// + /// let index = client.get_index("index_updater_execute").await.unwrap(); + /// assert_eq!(index.primary_key, Some("special_id".to_string())); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` pub async fn execute(&'a self) -> Result { request::<&IndexUpdater, TaskInfo>( &format!("{}/indexes/{}", self.client.host, self.uid), From 3012f2a939cf6d9ffd83242d0a5f549d42361e11 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 24 Aug 2022 12:07:13 +0200 Subject: [PATCH 43/53] Add tests on get indexes with params --- src/client.rs | 52 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/client.rs b/src/client.rs index d10725b3..ca30ea19 100644 --- a/src/client.rs +++ b/src/client.rs @@ -57,7 +57,7 @@ impl Client { Ok(indexes_results) } - /// List all [Index]es and returns values as instances of [Index]. + /// List all [Index]es with query parameters and returns values as instances of [Index]. /// /// # Example /// @@ -94,9 +94,12 @@ impl Client { /// # futures::executor::block_on(async move { /// // create the client /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// let mut query = IndexesQuery::new(&client); + /// query.with_limit(1); + /// let indexes: IndexesResults = client.list_all_indexes_with(&query).await.unwrap(); /// - /// let indexes: IndexesResults = client.list_all_indexes().await.unwrap(); - /// println!("{:?}", indexes); + /// assert_eq!(indexes.limit, 1); + /// // TODO: ALIAS /// # }); /// ``` pub async fn list_all_indexes_with( @@ -139,7 +142,7 @@ impl Client { Ok(json_indexes) } - /// List all [Index]es and returns as Json. + /// List all [Index]es with query parameters and returns as Json. /// /// # Example /// @@ -153,7 +156,10 @@ impl Client { /// // create the client /// let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// - /// let json_indexes = client.list_all_indexes_raw().await.unwrap(); + /// let mut query = IndexesQuery::new(&client); + /// query.with_limit(1); + /// let json_indexes = client.list_all_indexes_raw_with(&query).await.unwrap(); + /// /// println!("{:?}", json_indexes); /// # }); /// ``` @@ -564,7 +570,6 @@ impl Client { /// let new_key = KeyBuilder::new(); /// let name = "my name".to_string(); /// let mut new_key = client.create_key(new_key).await.unwrap(); - /// // TODO: Can i directly update the key using new_key /// let mut key_update = KeyUpdater::new(new_key); /// key_update.with_name(&name); /// @@ -1129,19 +1134,38 @@ mod tests { async fn test_list_all_indexes(client: Client, index: Index) { let all_indexes = client.list_all_indexes().await.unwrap(); // TODO: Check total, limit, offset - assert!(all_indexes.results.len() > 0); + assert_eq!(all_indexes.limit, 20); + assert_eq!(all_indexes.offset, 0); assert!(all_indexes.results.iter().any(|idx| idx.uid == index.uid)); } #[meilisearch_test] - async fn test_list_all_indexes_raw(client: Client, index: Index) { + async fn test_list_all_indexes_with_params(client: Client, index: Index) { + let mut query = IndexesQuery::new(&client); + query.with_limit(1); + let all_indexes = client.list_all_indexes_with(&query).await.unwrap(); + + assert_eq!(all_indexes.limit, 1); + assert_eq!(all_indexes.offset, 0); + assert!(all_indexes.results.iter().any(|idx| idx.uid == index.uid)); + } + + #[meilisearch_test] + async fn test_list_all_indexes_raw(client: Client) { let all_indexes_raw = client.list_all_indexes_raw().await.unwrap(); - let raw_indexes = all_indexes_raw["results"].as_array().unwrap(); - // TODO: Check total, limit, offset - assert!(raw_indexes.len() > 0); - assert!(raw_indexes - .iter() - .any(|idx| idx["uid"] == json!(index.uid.to_string()))); + + assert_eq!(all_indexes_raw["limit"].as_u64().unwrap() as u32, 20); + assert_eq!(all_indexes_raw["offset"].as_u64().unwrap() as u32, 0); + } + + #[meilisearch_test] + async fn test_list_all_indexes_raw_with_params(client: Client) { + let mut query = IndexesQuery::new(&client); + query.with_limit(1); + let all_indexes_raw = client.list_all_indexes_raw_with(&query).await.unwrap(); + + assert_eq!(all_indexes_raw["limit"].as_u64().unwrap() as u32, 1); + assert_eq!(all_indexes_raw["offset"].as_u64().unwrap() as u32, 0); } #[meilisearch_test] From 62e5f2c87d7f3a85a0a77b4082b26923952b872e Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 24 Aug 2022 12:17:32 +0200 Subject: [PATCH 44/53] Add test on index update --- src/client.rs | 19 +++++++++++++++++-- src/indexes.rs | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/client.rs b/src/client.rs index ca30ea19..7af62d3d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -99,7 +99,6 @@ impl Client { /// let indexes: IndexesResults = client.list_all_indexes_with(&query).await.unwrap(); /// /// assert_eq!(indexes.limit, 1); - /// // TODO: ALIAS /// # }); /// ``` pub async fn list_all_indexes_with( @@ -304,11 +303,27 @@ impl Client { self.list_all_indexes().await } + /// Alias for [Client::list_all_indexes_with]. + pub async fn get_indexes_with( + &self, + indexes_query: &IndexesQuery<'_>, + ) -> Result { + self.list_all_indexes_with(&indexes_query).await + } + /// Alias for [Client::list_all_indexes_raw]. pub async fn get_indexes_raw(&self) -> Result { self.list_all_indexes_raw().await } + /// Alias for [Client::list_all_indexes_raw_with]. + pub async fn get_indexes_raw_with( + &self, + indexes_query: &IndexesQuery<'_>, + ) -> Result { + self.list_all_indexes_raw_with(&indexes_query).await + } + /// Get stats of all indexes. /// /// # Example @@ -1133,7 +1148,7 @@ mod tests { #[meilisearch_test] async fn test_list_all_indexes(client: Client, index: Index) { let all_indexes = client.list_all_indexes().await.unwrap(); - // TODO: Check total, limit, offset + assert_eq!(all_indexes.limit, 20); assert_eq!(all_indexes.offset, 0); assert!(all_indexes.results.iter().any(|idx| idx.uid == index.uid)); diff --git a/src/indexes.rs b/src/indexes.rs index 1dedbf73..406f79dc 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -101,9 +101,42 @@ impl Index { }) } - /// Set the primary key of the index. + /// Update an [Index]. /// - /// If you prefer, you can use the method [Index::set_primary_key], which is an alias. + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*, task_info::*, tasks::{Task, SucceededTask}}; + /// # + /// # let MEILISEARCH_HOST = option_env!("MEILISEARCH_HOST").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::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); + /// # let mut index = client + /// # .create_index("index_update", None) + /// # .await + /// # .unwrap() + /// # .wait_for_completion(&client, None, None) + /// # .await + /// # .unwrap() + /// # // Once the task finished, we try to create an `Index` out of it + /// # .try_make_index(&client) + /// # .unwrap(); + /// + /// index.primary_key = Some("special_id".to_string()); + /// let task = index.update() + /// .await + /// .unwrap() + /// .wait_for_completion(&client, None, None) + /// .await + /// .unwrap(); + /// + /// let index = client.get_index("index_update").await.unwrap(); + /// assert_eq!(index.primary_key, Some("special_id".to_string())); + /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// # }); + /// ``` pub async fn update(&self) -> Result { let mut index_update = IndexUpdater::new(self, &self.client); @@ -640,8 +673,6 @@ impl Index { .await } - // let mut index = Index::new(uid, client); - // index.set_primary_key(primary_key) /// Alias for the [Index::update] method. pub async fn set_primary_key( &mut self, From 555f7ddafea1de37d7d8736303e13422d3cfd52d Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 24 Aug 2022 12:29:04 +0200 Subject: [PATCH 45/53] Fix clippy --- src/client.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/client.rs b/src/client.rs index 7af62d3d..28cf698a 100644 --- a/src/client.rs +++ b/src/client.rs @@ -49,7 +49,7 @@ impl Client { offset: value["offset"].as_u64().unwrap() as u32, total: value["total"].as_u64().unwrap() as u32, results: raw_indexes - .into_iter() + .iter() .map(|raw_index| Index::from_value(raw_index.clone(), self.clone())) .collect::>()?, }; @@ -105,7 +105,7 @@ impl Client { &self, indexes_query: &IndexesQuery<'_>, ) -> Result { - let value = self.list_all_indexes_raw_with(&indexes_query).await?; + let value = self.list_all_indexes_raw_with(indexes_query).await?; let indexes_results = self.parse_indexes_results_from_value(value)?; Ok(indexes_results) @@ -308,7 +308,7 @@ impl Client { &self, indexes_query: &IndexesQuery<'_>, ) -> Result { - self.list_all_indexes_with(&indexes_query).await + self.list_all_indexes_with(indexes_query).await } /// Alias for [Client::list_all_indexes_raw]. @@ -321,7 +321,7 @@ impl Client { &self, indexes_query: &IndexesQuery<'_>, ) -> Result { - self.list_all_indexes_raw_with(&indexes_query).await + self.list_all_indexes_raw_with(indexes_query).await } /// Get stats of all indexes. @@ -1155,14 +1155,13 @@ mod tests { } #[meilisearch_test] - async fn test_list_all_indexes_with_params(client: Client, index: Index) { + async fn test_list_all_indexes_with_params(client: Client) { let mut query = IndexesQuery::new(&client); query.with_limit(1); let all_indexes = client.list_all_indexes_with(&query).await.unwrap(); assert_eq!(all_indexes.limit, 1); assert_eq!(all_indexes.offset, 0); - assert!(all_indexes.results.iter().any(|idx| idx.uid == index.uid)); } #[meilisearch_test] From c28c578042dccf064039ee23b9f2c71a5181f621 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 24 Aug 2022 18:07:21 +0200 Subject: [PATCH 46/53] Improve limit to avoid flacky test --- src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.rs b/src/client.rs index 28cf698a..00eaa9e4 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1149,7 +1149,7 @@ mod tests { async fn test_list_all_indexes(client: Client, index: Index) { let all_indexes = client.list_all_indexes().await.unwrap(); - assert_eq!(all_indexes.limit, 20); + assert_eq!(all_indexes.limit, 1000); assert_eq!(all_indexes.offset, 0); assert!(all_indexes.results.iter().any(|idx| idx.uid == index.uid)); } From 9910283471b6f06612c248e694a4d805b9376394 Mon Sep 17 00:00:00 2001 From: cvermand <33010418+bidoubiwa@users.noreply.github.com> Date: Wed, 24 Aug 2022 18:10:25 +0200 Subject: [PATCH 47/53] Update src/client.rs Co-authored-by: Tamo --- src/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client.rs b/src/client.rs index 00eaa9e4..70bcd527 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1168,8 +1168,8 @@ mod tests { async fn test_list_all_indexes_raw(client: Client) { let all_indexes_raw = client.list_all_indexes_raw().await.unwrap(); - assert_eq!(all_indexes_raw["limit"].as_u64().unwrap() as u32, 20); - assert_eq!(all_indexes_raw["offset"].as_u64().unwrap() as u32, 0); + assert_eq!(all_indexes_raw["limit"], json!(20)); + assert_eq!(all_indexes_raw["offset"], json!(0)); } #[meilisearch_test] From 0cbcaac55eb3464255ae5a63efb2727ab273862c Mon Sep 17 00:00:00 2001 From: cvermand <33010418+bidoubiwa@users.noreply.github.com> Date: Wed, 24 Aug 2022 18:10:30 +0200 Subject: [PATCH 48/53] Update src/client.rs Co-authored-by: Tamo --- src/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client.rs b/src/client.rs index 70bcd527..94897600 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1178,8 +1178,8 @@ mod tests { query.with_limit(1); let all_indexes_raw = client.list_all_indexes_raw_with(&query).await.unwrap(); - assert_eq!(all_indexes_raw["limit"].as_u64().unwrap() as u32, 1); - assert_eq!(all_indexes_raw["offset"].as_u64().unwrap() as u32, 0); + assert_eq!(all_indexes_raw["limit"], json!(1)); + assert_eq!(all_indexes_raw["offset"], json!(0)); } #[meilisearch_test] From f0220fe292616d8b083ba01a9ec8d541ace2607e Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Thu, 25 Aug 2022 13:25:49 +0200 Subject: [PATCH 49/53] Remove useless newlines --- src/client.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/client.rs b/src/client.rs index 31f7453f..bf5dd48b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -967,7 +967,6 @@ mod tests { #[meilisearch_test] async fn test_error_delete_key(mut client: Client, name: String) { - // ==> accessing a key that does not exist let error = client.delete_key("invalid_key").await.unwrap_err(); assert!(matches!( @@ -984,7 +983,6 @@ mod tests { key.with_name(&name); let key = client.create_key(key).await.unwrap(); - let master_key = client.api_key.clone(); // this key has no right client.api_key = Arc::new(key.key.clone()); From f231ce47039c0af1d4fa00169ac273f070dfad80 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Thu, 25 Aug 2022 13:29:18 +0200 Subject: [PATCH 50/53] Rollback changes on keys api --- src/key.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/key.rs b/src/key.rs index 8c7d33e6..ab0d6712 100644 --- a/src/key.rs +++ b/src/key.rs @@ -658,7 +658,7 @@ pub enum Action { #[serde(rename = "documents.delete")] DocumentsDelete, /// Provides access to the [create index](https://docs.meilisearch.com/reference/api/indexes.md#create-an-index) endpoint. - #[serde(rename = "indexes.execute")] + #[serde(rename = "indexes.create")] IndexesCreate, /// Provides access to the [get one index](https://docs.meilisearch.com/reference/api/indexes.md#get-one-index) and [list all indexes](https://docs.meilisearch.com/reference/api/indexes.md#list-all-indexes) endpoints. **Non-authorized `indexes` will be omitted from the response**. #[serde(rename = "indexes.get")] @@ -682,7 +682,7 @@ pub enum Action { #[serde(rename = "stats.get")] StatsGet, /// Provides access to the [create dump](https://docs.meilisearch.com/reference/api/dump.md#create-a-dump) endpoint. **Not restricted by `indexes`.** - #[serde(rename = "dumps.execute")] + #[serde(rename = "dumps.create")] DumpsCreate, /// Provides access to the [get dump status](https://docs.meilisearch.com/reference/api/dump.md#get-dump-status) endpoint. **Not restricted by `indexes`.** #[serde(rename = "dumps.get")] @@ -698,6 +698,7 @@ pub enum Action { KeyCreate, /// Provides access to the [update key](https://docs.meilisearch.com/reference/api/keys.html#update-a-key) endpoint. #[serde(rename = "keys.update")] + KeyUpdate, /// Provides access to the [delete key](https://docs.meilisearch.com/reference/api/keys.html#delete-a-key) endpoint. #[serde(rename = "keys.delete")] KeyDelete, From 9d37921f28b8323b29e265bc3e065a97bf9b82f6 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Thu, 25 Aug 2022 13:32:43 +0200 Subject: [PATCH 51/53] Fix duplicated closing bracket --- src/client.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/client.rs b/src/client.rs index bf5dd48b..7bf18af0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -946,8 +946,6 @@ mod tests { assert!(keys.results.len() >= 2); } - } - #[meilisearch_test] async fn test_delete_key(client: Client, name: String) { let mut key = KeyBuilder::new(); From 9cd259eaf1c58b22ffdb9d7831044c7ab6bb51d1 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Thu, 25 Aug 2022 13:41:53 +0200 Subject: [PATCH 52/53] Fix failing tests --- src/client.rs | 5 ++--- src/indexes.rs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/client.rs b/src/client.rs index 7bf18af0..2cdd6185 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1149,12 +1149,11 @@ mod tests { } #[meilisearch_test] - async fn test_list_all_indexes(client: Client, index: Index) { + async fn test_list_all_indexes(client: Client) { let all_indexes = client.list_all_indexes().await.unwrap(); - assert_eq!(all_indexes.limit, 1000); + assert_eq!(all_indexes.limit, 20); assert_eq!(all_indexes.offset, 0); - assert!(all_indexes.results.iter().any(|idx| idx.uid == index.uid)); } #[meilisearch_test] diff --git a/src/indexes.rs b/src/indexes.rs index 406f79dc..959686fb 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -1347,7 +1347,7 @@ impl<'a> IndexesQuery<'a> { /// .with_offset(1) /// .execute().await.unwrap(); /// - /// # assert_eq!(indexes.results.len(), 0); + /// # assert_eq!(indexes.offset, 1); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` @@ -1403,7 +1403,7 @@ impl<'a> IndexesQuery<'a> { /// # futures::executor::block_on(async move { /// # let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY); /// # let index = client - /// # .create_index("index_query_with_limit", None) + /// # .create_index("index_query_with_execute", None) /// # .await /// # .unwrap() /// # .wait_for_completion(&client, None, None) From f4e99a3699e4492918f7a26e3f8bbba6dc647962 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Thu, 25 Aug 2022 13:45:39 +0200 Subject: [PATCH 53/53] Remove useless comment --- src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.rs b/src/client.rs index 2cdd6185..bf5c60dd 100644 --- a/src/client.rs +++ b/src/client.rs @@ -597,7 +597,7 @@ impl Client { request::<&KeyUpdater, Key>( &format!("{}/keys/{}", self.host, key.as_ref().key), &self.api_key, - Method::Patch(key.as_ref()), // name and description + Method::Patch(key.as_ref()), 200, ) .await