diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a58c1689..56f453e5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -32,6 +32,11 @@ jobs: with: command: check args: --workspace --all-targets --all + - name: Cargo check no default features + uses: actions-rs/cargo@v1 + with: + command: check + args: --workspace --all-targets --all --no-default-features linter: name: clippy-check diff --git a/Cargo.toml b/Cargo.toml index 286df5c4..fd9db04b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ meilisearch-index-setting-macro = { path = "meilisearch-index-setting-macro", ve [target.'cfg(not(target_arch = "wasm32"))'.dependencies] futures = "0.3" futures-io = "0.3.26" -isahc = { version = "1.0", features = ["http2", "text-decoding"], default_features = false } +isahc = { version = "1.0", features = ["http2", "text-decoding"], optional = true, default_features = false } uuid = { version = "1.1.2", features = ["v4"] } [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -37,8 +37,8 @@ wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" [features] -default = ["isahc-static-curl"] -isahc-static-curl = ["isahc/static-curl"] +default = ["isahc", "isahc", "isahc-static-curl"] +isahc-static-curl = ["isahc", "isahc", "isahc/static-curl"] isahc-static-ssl = ["isahc/static-ssl"] [dev-dependencies] diff --git a/README.md b/README.md index c8638325..b0be50f9 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,12 @@ Json output: } ``` +#### Using users customized HttpClient + +If you want to change the `HttpClient` you can incorporate using the `Client::new_with_client` method. +To use it, you need to implement the `HttpClient Trait`(`isahc` is used by default). +There are [using-reqwest-example](./examples/cli-app-with-reqwest) of using `reqwest`. + ## ๐ŸŒ Running in the Browser with WASM This crate fully supports WASM. diff --git a/examples/cli-app-with-reqwest/Cargo.toml b/examples/cli-app-with-reqwest/Cargo.toml new file mode 100644 index 00000000..54494538 --- /dev/null +++ b/examples/cli-app-with-reqwest/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "cli-app-with-reqwest" +version = "0.0.0" +edition = "2021" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +meilisearch-sdk = { path = "../..", default-features = false } +futures = "0.3" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +lazy_static = "1.4.0" +reqwest = "0.11.16" +async-trait = "0.1.51" +tokio = { version = "1.27.0", features = ["full"] } \ No newline at end of file diff --git a/examples/cli-app-with-reqwest/assets/clothes.json b/examples/cli-app-with-reqwest/assets/clothes.json new file mode 100644 index 00000000..99fedf29 --- /dev/null +++ b/examples/cli-app-with-reqwest/assets/clothes.json @@ -0,0 +1,74 @@ +[ + { + "id": 1, + "seaon": "winter", + "article": "sweater", + "cost": 63.40, + "size":"L", + "pattern":"striped" + }, + { + "id": 2, + "seaon": "spring", + "article": "sweat pants", + "cost": 18.00, + "size":"XXXL", + "pattern":"floral" + }, + { + "id": 3, + "seaon": "fall", + "article": "t-shirt", + "cost": 1634.90, + "size":"M", + "pattern":"solid black" + }, + { + "id": 4, + "seaon": "summer", + "article": "tank top", + "cost": 3.40, + "size":"L", + "pattern":"diagonal" + }, + { + "id": 5, + "seaon": "winter", + "article": "jeans", + "cost": 4.20, + "size":"XL", + "pattern":"striped" + }, + { + "id": 6, + "seaon": "spring", + "article": "sun dress", + "cost": 12634.56, + "size":"L", + "pattern":"floral" + }, + { + "id": 7, + "seaon": "fall", + "article": "sweatshirt", + "cost": 90.80, + "size":"M", + "pattern":"checker" + }, + { + "id": 8, + "seaon": "summer", + "article": "shorts", + "cost": 16.34, + "size":"XS", + "pattern":"solid beige" + }, + { + "id": 9, + "seaon": "winter", + "article": "jacket", + "cost": 634, + "size":"L", + "pattern":"camo" + } +] \ No newline at end of file diff --git a/examples/cli-app-with-reqwest/src/main.rs b/examples/cli-app-with-reqwest/src/main.rs new file mode 100644 index 00000000..e5a53cde --- /dev/null +++ b/examples/cli-app-with-reqwest/src/main.rs @@ -0,0 +1,273 @@ +use async_trait::async_trait; +use lazy_static::lazy_static; +use meilisearch_sdk::errors::Error; +use meilisearch_sdk::request::{ + add_query_parameters, parse_response, qualified_version, HttpClient, Method, +}; +use meilisearch_sdk::{client::*, settings::Settings}; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; +use serde_json::to_string; +use std::fmt; +use std::io::stdin; + +lazy_static! { + static ref CLIENT: Client = + Client::new_with_client("http://localhost:7700", Some("masterKey"), ReqwestClient); +} + +#[derive(Debug, Clone, Serialize)] +pub struct ReqwestClient; + +#[async_trait(?Send)] +impl HttpClient for ReqwestClient { + async fn request( + self, + url: &str, + apikey: Option<&str>, + method: Method, + expected_status_code: u16, + ) -> Result + where + Query: Serialize + Send + Sync, + Body: Serialize + Send + Sync, + Output: DeserializeOwned + 'static + Send, + { + let response = match &method { + Method::Get { query } => { + let url = add_query_parameters(url, query)?; + let client = reqwest::Client::new(); + let mut builder = client.request(reqwest::Method::GET, url.as_str()); + builder = builder.header(reqwest::header::USER_AGENT, qualified_version()); + if let Some(apikey) = apikey { + builder = + builder.header(reqwest::header::AUTHORIZATION, format!("Bearer {apikey}")); + } + let req = builder.build().unwrap(); + client.execute(req).await.unwrap() + } + Method::Post { query, body } => { + let url = add_query_parameters(url, query)?; + let client = reqwest::Client::new(); + let mut builder = client.request(reqwest::Method::POST, url.as_str()); + if let Some(apikey) = apikey { + builder = + builder.header(reqwest::header::AUTHORIZATION, format!("Bearer {apikey}")); + } + builder = builder.header(reqwest::header::CONTENT_TYPE, "application/json"); + let req = builder.body(to_string(body).unwrap()).build().unwrap(); + client.execute(req).await.unwrap() + } + Method::Patch { query, body } => { + let url = add_query_parameters(url, query)?; + let client = reqwest::Client::new(); + let mut builder = client.request(reqwest::Method::PATCH, url.as_str()); + if let Some(apikey) = apikey { + builder = + builder.header(reqwest::header::AUTHORIZATION, format!("Bearer {apikey}")); + } + builder = builder.header(reqwest::header::CONTENT_TYPE, "application/json"); + let req = builder.body(to_string(body).unwrap()).build().unwrap(); + client.execute(req).await.unwrap() + } + Method::Put { query, body } => { + let url = add_query_parameters(url, query)?; + let client = reqwest::Client::new(); + let mut builder = client.request(reqwest::Method::PUT, url.as_str()); + if let Some(apikey) = apikey { + builder = + builder.header(reqwest::header::AUTHORIZATION, format!("Bearer {apikey}")); + } + builder = builder.header(reqwest::header::CONTENT_TYPE, "application/json"); + let req = builder.body(to_string(body).unwrap()).build().unwrap(); + client.execute(req).await.unwrap() + } + Method::Delete { query } => { + let url = add_query_parameters(url, query)?; + let client = reqwest::Client::new(); + let mut builder = client.request(reqwest::Method::DELETE, url.as_str()); + if let Some(apikey) = apikey { + builder = + builder.header(reqwest::header::AUTHORIZATION, format!("Bearer {apikey}")); + } + builder = builder.header(reqwest::header::CONTENT_TYPE, "application/json"); + let req = builder.build().unwrap(); + client.execute(req).await.unwrap() + } + }; + + let status = response.status().as_u16(); + + let mut body = response.text().await.unwrap(); + + if body.is_empty() { + body = "null".to_string(); + } + + parse_response(status, expected_status_code, &body, url.to_string()) + } + + async fn stream_request< + 'a, + Query: Serialize + Send + Sync, + Body: futures::AsyncRead + Send + Sync + 'static, + Output: DeserializeOwned + 'static, + >( + self, + _url: &str, + _apikey: Option<&str>, + _method: Method, + _content_type: &str, + _expected_status_code: u16, + ) -> Result { + unimplemented!("stream_request is not implemented for ReqwestClient") + } +} + +#[tokio::main] +async fn main() { + // build the index + build_index().await; + + // enter in search queries or quit + loop { + println!("Enter a search query or type \"q\" or \"quit\" to quit:"); + let mut input_string = String::new(); + stdin() + .read_line(&mut input_string) + .expect("Failed to read line"); + match input_string.trim() { + "quit" | "q" | "" => { + println!("exiting..."); + break; + } + _ => { + search(input_string.trim()).await; + } + } + } + // get rid of the index at the end, doing this only so users don't have the index without knowing + let _ = CLIENT.delete_index("clothes").await.unwrap(); +} + +async fn search(query: &str) { + // make the search query, which excutes and serializes hits into the + // ClothesDisplay struct + let query_results = CLIENT + .index("clothes") + .search() + .with_query(query) + .execute::() + .await + .unwrap() + .hits; + + // display the query results + if query_results.is_empty() { + println!("no results..."); + } else { + for clothes in query_results { + let display = clothes.result; + println!("{}", format_args!("{}", display)); + } + } +} + +async fn build_index() { + // reading and parsing the file + let content = include_str!("../assets/clothes.json"); + + // serialize the string to clothes objects + let clothes: Vec = serde_json::from_str(content).unwrap(); + + //create displayed attributes + let displayed_attributes = ["article", "cost", "size", "pattern"]; + + // Create ranking rules + let ranking_rules = ["words", "typo", "attribute", "exactness", "cost:asc"]; + + //create searchable attributes + let searchable_attributes = ["seaon", "article", "size", "pattern"]; + + // create the synonyms hashmap + let mut synonyms = std::collections::HashMap::new(); + synonyms.insert("sweater", vec!["cardigan", "long-sleeve"]); + synonyms.insert("sweat pants", vec!["joggers", "gym pants"]); + synonyms.insert("t-shirt", vec!["tees", "tshirt"]); + + //create the settings struct + let settings = Settings::new() + .with_ranking_rules(ranking_rules) + .with_searchable_attributes(searchable_attributes) + .with_displayed_attributes(displayed_attributes) + .with_synonyms(synonyms); + + //add the settings to the index + let result = CLIENT + .index("clothes") + .set_settings(&settings) + .await + .unwrap() + .wait_for_completion(&CLIENT, None, None) + .await + .unwrap(); + + if result.is_failure() { + panic!( + "Encountered an error while setting settings for index: {:?}", + result.unwrap_failure() + ); + } + + // add the documents + let result = CLIENT + .index("clothes") + .add_or_update(&clothes, Some("id")) + .await + .unwrap() + .wait_for_completion(&CLIENT, None, None) + .await + .unwrap(); + + if result.is_failure() { + panic!( + "Encountered an error while sending the documents: {:?}", + result.unwrap_failure() + ); + } +} + +/// Base search object. +#[derive(Serialize, Deserialize, Debug)] +pub struct Clothes { + id: usize, + seaon: String, + article: String, + cost: f32, + size: String, + pattern: String, +} + +/// Search results get serialized to this struct +#[derive(Serialize, Deserialize, Debug)] +pub struct ClothesDisplay { + article: String, + cost: f32, + size: String, + pattern: String, +} + +impl fmt::Display for ClothesDisplay { + // This trait requires `fmt` with this exact signature. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Write strictly the first element into the supplied output + // stream: `f`. Returns `fmt::Result` which indicates whether the + // operation succeeded or failed. Note that `write!` uses syntax which + // is very similar to `println!`. + write!( + f, + "result\n article: {},\n price: {},\n size: {},\n pattern: {}\n", + self.article, self.cost, self.size, self.pattern + ) + } +} diff --git a/examples/cli-app/src/main.rs b/examples/cli-app/src/main.rs index 653b8e57..64b5cd17 100644 --- a/examples/cli-app/src/main.rs +++ b/examples/cli-app/src/main.rs @@ -1,6 +1,7 @@ use futures::executor::block_on; use lazy_static::lazy_static; -use meilisearch_sdk::{client::*, Settings}; +use meilisearch_sdk::client::Client; +use meilisearch_sdk::settings::Settings; use serde::{Deserialize, Serialize}; use std::fmt; use std::io::stdin; diff --git a/examples/settings.rs b/examples/settings.rs index 1524ab8c..7397a946 100644 --- a/examples/settings.rs +++ b/examples/settings.rs @@ -1,4 +1,4 @@ -use meilisearch_sdk::{Client, Index, Settings}; +use meilisearch_sdk::{client::Client, indexes::Index, settings::Settings}; // we need an async runtime #[tokio::main(flavor = "current_thread")] diff --git a/examples/web_app/src/lib.rs b/examples/web_app/src/lib.rs index 68274703..004914f7 100644 --- a/examples/web_app/src/lib.rs +++ b/examples/web_app/src/lib.rs @@ -1,6 +1,8 @@ #![recursion_limit = "512"] use lazy_static::lazy_static; -use meilisearch_sdk::{Client, Index, SearchResults, Selectors::All}; +use meilisearch_sdk::client::Client; +use meilisearch_sdk::indexes::Index; +use meilisearch_sdk::search::{SearchResults, Selectors::All}; use serde_json::{Map, Value}; use std::rc::Rc; use wasm_bindgen::prelude::*; diff --git a/meilisearch-index-setting-macro/src/lib.rs b/meilisearch-index-setting-macro/src/lib.rs index 71c4e805..d1b32379 100644 --- a/meilisearch-index-setting-macro/src/lib.rs +++ b/meilisearch-index-setting-macro/src/lib.rs @@ -127,8 +127,8 @@ fn get_index_config_implementation( get_settings_token_for_string(&distinct_key_attribute, "with_distinct_attribute"); quote! { - #[::meilisearch_sdk::macro_helper::async_trait] - impl ::meilisearch_sdk::documents::IndexConfig for #struct_ident { + #[::meilisearch_sdk::macro_helper::async_trait(?Send)] + impl ::meilisearch_sdk::documents::IndexConfig<::meilisearch_sdk::request::IsahcClient> for #struct_ident { const INDEX_STR: &'static str = #index_name; fn generate_settings() -> ::meilisearch_sdk::settings::Settings { @@ -140,7 +140,7 @@ fn get_index_config_implementation( #distinct_attr_token } - async fn generate_index(client: &::meilisearch_sdk::client::Client) -> ::std::result::Result<::meilisearch_sdk::indexes::Index, ::meilisearch_sdk::tasks::Task> { + async fn generate_index(client: &::meilisearch_sdk::client::Client<::meilisearch_sdk::request::IsahcClient>) -> std::result::Result<::meilisearch_sdk::indexes::Index<::meilisearch_sdk::request::IsahcClient>, ::meilisearch_sdk::tasks::Task> { return client.create_index(#index_name, #primary_key_token) .await.unwrap() .wait_for_completion(&client, ::std::option::Option::None, ::std::option::Option::None) diff --git a/meilisearch-test-macro/src/lib.rs b/meilisearch-test-macro/src/lib.rs index 2a9b0ee6..d20afbbf 100644 --- a/meilisearch-test-macro/src/lib.rs +++ b/meilisearch-test-macro/src/lib.rs @@ -1,4 +1,3 @@ -#![warn(clippy::pedantic)] #![recursion_limit = "4096"] extern crate proc_macro; @@ -6,7 +5,10 @@ extern crate proc_macro; use proc_macro::TokenStream; use proc_macro2::Span; use quote::quote; -use syn::*; +use syn::{ + parse_macro_input, parse_quote, Expr, FnArg, Ident, Item, PatType, Path, Stmt, Type, TypePath, + Visibility, +}; #[proc_macro_attribute] pub fn meilisearch_test(params: TokenStream, input: TokenStream) -> TokenStream { @@ -83,13 +85,13 @@ pub fn meilisearch_test(params: TokenStream, input: TokenStream) -> TokenStream // First we need to check if a client will be used and create it if itโ€™s the case if use_client { outer_block.push(parse_quote!( - let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); + let meilisearch_url = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); )); outer_block.push(parse_quote!( - let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); + let meilisearch_api_key = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); )); outer_block.push(parse_quote!( - let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)); + let client = Client::new(meilisearch_url, Some(meilisearch_api_key)); )); } diff --git a/src/client.rs b/src/client.rs index 4b4874af..a7f45011 100644 --- a/src/client.rs +++ b/src/client.rs @@ -4,16 +4,23 @@ use std::{collections::HashMap, time::Duration}; use time::OffsetDateTime; use crate::{ - errors::*, indexes::*, request::*, search::*, utils::async_sleep, Key, KeyBuilder, KeyUpdater, - KeysQuery, KeysResults, Task, TaskInfo, TasksCancelQuery, TasksDeleteQuery, TasksResults, - TasksSearchQuery, + errors::*, + indexes::*, + key::{Key, KeyBuilder, KeyUpdater, KeysQuery, KeysResults}, + request::*, + search::*, + task_info::TaskInfo, + tasks::{Task, TasksCancelQuery, TasksDeleteQuery, TasksResults, TasksSearchQuery}, + utils::async_sleep, + DefaultHttpClient, }; /// The top-level struct of the SDK, representing a client containing [indexes](../indexes/struct.Index.html). #[derive(Debug, Clone)] -pub struct Client { +pub struct Client { pub(crate) host: String, pub(crate) api_key: Option, + pub http_client: Http, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -21,6 +28,8 @@ pub struct SwapIndexes { pub indexes: (String, String), } +#[cfg(feature = "isahc")] +#[cfg(not(target_arch = "wasm32"))] impl Client { /// Create a client using the specified server. /// @@ -41,11 +50,58 @@ impl Client { pub fn new(host: impl Into, api_key: Option>) -> Client { Client { host: host.into(), - api_key: api_key.map(Into::into), + api_key: api_key.map(|api_key| api_key.into()), + http_client: IsahcClient, + } + } +} + +#[cfg(target_arch = "wasm32")] +impl Client { + /// Create a client using the specified server. + /// Don't put a '/' at the end of the host. + /// In production mode, see [the documentation about authentication](https://docs.meilisearch.com/reference/features/authentication.html#authentication). + /// # Example + /// + /// ``` + /// # use meilisearch_sdk::{client::*, indexes::*}; + /// # + /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); + /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); + /// # + /// // create the client + /// let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)); + /// ``` + pub fn new( + host: impl Into, + api_key: Option>, + ) -> Client { + Client { + host: host.into(), + api_key: api_key.map(|key| key.into()), + http_client: WebSysClient::new(), + } + } +} + +impl Client { + // Create a client with a custom http client + pub fn new_with_client( + host: impl Into, + api_key: Option>, + http_client: Http, + ) -> Client { + Client { + host: host.into(), + api_key: api_key.map(|key| key.into()), + http_client, } } - fn parse_indexes_results_from_value(&self, value: &Value) -> Result { + fn parse_indexes_results_from_value( + &self, + value: &Value, + ) -> Result, Error> { let raw_indexes = value["results"].as_array().unwrap(); let indexes_results = IndexesResults { @@ -61,17 +117,19 @@ impl Client { Ok(indexes_results) } - pub async fn execute_multi_search_query( + pub async fn execute_multi_search_query( &self, - body: &MultiSearchQuery<'_, '_>, + body: &MultiSearchQuery<'_, '_, Http>, ) -> Result, Error> { - request::<(), &MultiSearchQuery, MultiSearchResponse>( - &format!("{}/multi-search", &self.host), - self.get_api_key(), - Method::Post { body, query: () }, - 200, - ) - .await + self.http_client + .clone() + .request::<(), &MultiSearchQuery, MultiSearchResponse>( + &format!("{}/multi-search", &self.host), + self.get_api_key(), + Method::Post { body, query: () }, + 200, + ) + .await } /// Make multiple search requests. @@ -117,7 +175,7 @@ impl Client { /// # }); /// ``` #[must_use] - pub fn multi_search(&self) -> MultiSearchQuery { + pub fn multi_search(&self) -> MultiSearchQuery { MultiSearchQuery::new(self) } @@ -167,10 +225,11 @@ impl Client { /// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)); /// let indexes: IndexesResults = 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 { + pub async fn list_all_indexes(&self) -> Result, Error> { let value = self.list_all_indexes_raw().await?; let indexes_results = self.parse_indexes_results_from_value(&value)?; Ok(indexes_results) @@ -198,8 +257,8 @@ impl Client { /// ``` pub async fn list_all_indexes_with( &self, - indexes_query: &IndexesQuery<'_>, - ) -> Result { + indexes_query: &IndexesQuery<'_, Http>, + ) -> Result, Error> { let value = self.list_all_indexes_raw_with(indexes_query).await?; let indexes_results = self.parse_indexes_results_from_value(&value)?; @@ -224,13 +283,15 @@ impl Client { /// # }); /// ``` pub async fn list_all_indexes_raw(&self) -> Result { - let json_indexes = request::<(), (), Value>( - &format!("{}/indexes", self.host), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await?; + let http_client = self.http_client.clone(); + let json_indexes = http_client + .request::<(), (), Value>( + &format!("{}/indexes", self.host), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await?; Ok(json_indexes) } @@ -257,17 +318,19 @@ impl Client { /// ``` pub async fn list_all_indexes_raw_with( &self, - indexes_query: &IndexesQuery<'_>, + indexes_query: &IndexesQuery<'_, Http>, ) -> Result { - let json_indexes = request::<&IndexesQuery, (), Value>( - &format!("{}/indexes", self.host), - self.get_api_key(), - Method::Get { - query: indexes_query, - }, - 200, - ) - .await?; + let http_client = self.http_client.clone(); + let json_indexes = http_client + .request::<&IndexesQuery, (), Value>( + &format!("{}/indexes", self.host), + self.get_api_key(), + Method::Get { + query: indexes_query, + }, + 200, + ) + .await?; Ok(json_indexes) } @@ -291,7 +354,7 @@ impl Client { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_index(&self, uid: impl AsRef) -> Result { + pub async fn get_index(&self, uid: impl AsRef) -> Result, Error> { let mut idx = self.index(uid.as_ref()); idx.fetch_info().await?; Ok(idx) @@ -319,17 +382,19 @@ impl Client { /// # }); /// ``` pub async fn get_raw_index(&self, uid: impl AsRef) -> Result { - request::<(), (), Value>( - &format!("{}/indexes/{}", self.host, uid.as_ref()), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.http_client + .clone() + .request::<(), (), Value>( + &format!("{}/indexes/{}", self.host, uid.as_ref()), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Create a corresponding object of an [Index] without any check or doing an HTTP call. - pub fn index(&self, uid: impl Into) -> Index { + pub fn index(&self, uid: impl Into) -> Index { Index::new(uid, self.clone()) } @@ -366,44 +431,48 @@ impl Client { uid: impl AsRef, primary_key: Option<&str>, ) -> Result { - request::<(), Value, TaskInfo>( - &format!("{}/indexes", self.host), - self.get_api_key(), - Method::Post { - query: (), - body: json!({ - "uid": uid.as_ref(), - "primaryKey": primary_key, - }), - }, - 202, - ) - .await + self.http_client + .clone() + .request::<(), Value, TaskInfo>( + &format!("{}/indexes", self.host), + self.get_api_key(), + Method::Post { + query: (), + body: json!({ + "uid": uid.as_ref(), + "primaryKey": primary_key, + }), + }, + 202, + ) + .await } /// 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::<(), (), TaskInfo>( - &format!("{}/indexes/{}", self.host, uid.as_ref()), - self.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.http_client + .clone() + .request::<(), (), TaskInfo>( + &format!("{}/indexes/{}", self.host, uid.as_ref()), + self.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Alias for [`Client::list_all_indexes`]. - pub async fn get_indexes(&self) -> Result { + pub async fn get_indexes(&self) -> Result, Error> { self.list_all_indexes().await } /// Alias for [`Client::list_all_indexes_with`]. pub async fn get_indexes_with( &self, - indexes_query: &IndexesQuery<'_>, - ) -> Result { + indexes_query: &IndexesQuery<'_, Http>, + ) -> Result, Error> { self.list_all_indexes_with(indexes_query).await } @@ -415,7 +484,7 @@ impl Client { /// Alias for [`Client::list_all_indexes_raw_with`]. pub async fn get_indexes_raw_with( &self, - indexes_query: &IndexesQuery<'_>, + indexes_query: &IndexesQuery<'_, Http>, ) -> Result { self.list_all_indexes_raw_with(indexes_query).await } @@ -448,24 +517,26 @@ impl Client { /// .await /// .unwrap(); /// - /// # client.index("swap_index_1").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); - /// # client.index("swap_index_2").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// client.index("swap_index_1").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); + /// client.index("swap_index_2").delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` pub async fn swap_indexes( &self, indexes: impl IntoIterator, ) -> Result { - request::<(), Vec<&SwapIndexes>, TaskInfo>( - &format!("{}/swap-indexes", self.host), - self.get_api_key(), - Method::Post { - query: (), - body: indexes.into_iter().collect(), - }, - 202, - ) - .await + self.http_client + .clone() + .request::<(), Vec<&SwapIndexes>, TaskInfo>( + &format!("{}/swap-indexes", self.host), + self.get_api_key(), + Method::Post { + query: (), + body: indexes.into_iter().collect(), + }, + 202, + ) + .await } /// Get stats of all [Indexes](Index). @@ -484,13 +555,15 @@ impl Client { /// # }); /// ``` pub async fn get_stats(&self) -> Result { - request::<(), (), ClientStats>( - &format!("{}/stats", self.host), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.http_client + .clone() + .request::<(), (), ClientStats>( + &format!("{}/stats", self.host), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get health of Meilisearch server. @@ -498,7 +571,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, Error, ErrorCode}; + /// # use meilisearch_sdk::{client::*, errors::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -511,13 +584,15 @@ impl Client { /// # }); /// ``` pub async fn health(&self) -> Result { - request::<(), (), Health>( - &format!("{}/health", self.host), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.http_client + .clone() + .request::<(), (), Health>( + &format!("{}/health", self.host), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get health of Meilisearch server. @@ -552,7 +627,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, Error, KeysQuery}; + /// # use meilisearch_sdk::{client::*, errors::Error, key::KeysQuery}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -568,13 +643,15 @@ impl Client { /// # }); /// ``` pub async fn get_keys_with(&self, keys_query: &KeysQuery) -> Result { - let keys = request::<&KeysQuery, (), KeysResults>( - &format!("{}/keys", self.host), - self.get_api_key(), - Method::Get { query: keys_query }, - 200, - ) - .await?; + let http_client = self.http_client.clone(); + let keys = http_client + .request::<&KeysQuery, (), KeysResults>( + &format!("{}/keys", self.host), + self.get_api_key(), + Method::Get { query: keys_query }, + 200, + ) + .await?; Ok(keys) } @@ -586,7 +663,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, Error, KeyBuilder}; + /// # use meilisearch_sdk::{client::*, errors::Error, key::KeyBuilder}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -599,13 +676,15 @@ impl Client { /// # }); /// ``` pub async fn get_keys(&self) -> Result { - let keys = request::<(), (), KeysResults>( - &format!("{}/keys", self.host), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await?; + let http_client = self.http_client.clone(); + let keys = http_client + .request::<(), (), KeysResults>( + &format!("{}/keys", self.host), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await?; Ok(keys) } @@ -617,7 +696,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, Error, KeyBuilder}; + /// # use meilisearch_sdk::{client::*, errors::Error, key::KeyBuilder}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -633,13 +712,15 @@ impl Client { /// # }); /// ``` pub async fn get_key(&self, key: impl AsRef) -> Result { - request::<(), (), Key>( - &format!("{}/keys/{}", self.host, key.as_ref()), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.http_client + .clone() + .request::<(), (), Key>( + &format!("{}/keys/{}", self.host, key.as_ref()), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Delete an API [Key] from Meilisearch. @@ -649,7 +730,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, Error, KeyBuilder}; + /// # use meilisearch_sdk::{client::*, errors::Error, key::KeyBuilder}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -668,13 +749,15 @@ impl Client { /// # }); /// ``` pub async fn delete_key(&self, key: impl AsRef) -> Result<(), Error> { - request::<(), (), ()>( - &format!("{}/keys/{}", self.host, key.as_ref()), - self.get_api_key(), - Method::Delete { query: () }, - 204, - ) - .await + self.http_client + .clone() + .request::<(), (), ()>( + &format!("{}/keys/{}", self.host, key.as_ref()), + self.get_api_key(), + Method::Delete { query: () }, + 204, + ) + .await } /// Create an API [Key] in Meilisearch. @@ -684,7 +767,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, Error, KeyBuilder, Action}; + /// # use meilisearch_sdk::{client::*, errors::Error, key::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -702,16 +785,18 @@ impl Client { /// # }); /// ``` pub async fn create_key(&self, key: impl AsRef) -> Result { - request::<(), &KeyBuilder, Key>( - &format!("{}/keys", self.host), - self.get_api_key(), - Method::Post { - query: (), - body: key.as_ref(), - }, - 201, - ) - .await + self.http_client + .clone() + .request::<(), &KeyBuilder, Key>( + &format!("{}/keys", self.host), + self.get_api_key(), + Method::Post { + query: (), + body: key.as_ref(), + }, + 201, + ) + .await } /// Update an API [Key] in Meilisearch. @@ -721,7 +806,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, Error, KeyBuilder, KeyUpdater}; + /// # use meilisearch_sdk::{client::*, errors::Error, key::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -742,16 +827,18 @@ impl Client { /// # }); /// ``` pub async fn update_key(&self, key: impl AsRef) -> Result { - request::<(), &KeyUpdater, Key>( - &format!("{}/keys/{}", self.host, key.as_ref().key), - self.get_api_key(), - Method::Patch { - body: key.as_ref(), - query: (), - }, - 200, - ) - .await + self.http_client + .clone() + .request::<(), &KeyUpdater, Key>( + &format!("{}/keys/{}", self.host, key.as_ref().key), + self.get_api_key(), + Method::Patch { + body: key.as_ref(), + query: (), + }, + 200, + ) + .await } /// Get version of the Meilisearch server. @@ -759,7 +846,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*}; + /// # use meilisearch_sdk::client::*; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -770,13 +857,15 @@ impl Client { /// # }); /// ``` pub async fn get_version(&self) -> Result { - request::<(), (), Version>( - &format!("{}/version", self.host), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.http_client + .clone() + .request::<(), (), Version>( + &format!("{}/version", self.host), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Wait until Meilisearch processes a [Task], and get its status. @@ -792,7 +881,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, Task}; + /// # use meilisearch_sdk::{client::*, indexes::*, tasks::*}; /// # use serde::{Serialize, Deserialize}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); @@ -858,7 +947,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::*; + /// # use meilisearch_sdk::{client::*, tasks::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -873,13 +962,15 @@ impl Client { /// # }); /// ``` pub async fn get_task(&self, task_id: impl AsRef) -> Result { - request::<(), (), Task>( - &format!("{}/tasks/{}", self.host, task_id.as_ref()), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.http_client + .clone() + .request::<(), (), Task>( + &format!("{}/tasks/{}", self.host, task_id.as_ref()), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get all tasks with query parameters from the server. @@ -887,7 +978,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::*; + /// # use meilisearch_sdk::{client::*, tasks::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -902,15 +993,17 @@ impl Client { /// ``` pub async fn get_tasks_with( &self, - tasks_query: &TasksSearchQuery<'_>, + tasks_query: &TasksSearchQuery<'_, Http>, ) -> Result { - let tasks = request::<&TasksSearchQuery, (), TasksResults>( - &format!("{}/tasks", self.host), - self.get_api_key(), - Method::Get { query: tasks_query }, - 200, - ) - .await?; + let http_client = self.http_client.clone(); + let tasks = http_client + .request::<&TasksSearchQuery, (), TasksResults>( + &format!("{}/tasks", self.host), + self.get_api_key(), + Method::Get { query: tasks_query }, + 200, + ) + .await?; Ok(tasks) } @@ -920,7 +1013,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::*; + /// # use meilisearch_sdk::{client::*, tasks::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -935,18 +1028,20 @@ impl Client { /// ``` pub async fn cancel_tasks_with( &self, - filters: &TasksCancelQuery<'_>, + filters: &TasksCancelQuery<'_, Http>, ) -> Result { - let tasks = request::<&TasksCancelQuery, (), TaskInfo>( - &format!("{}/tasks/cancel", self.host), - self.get_api_key(), - Method::Post { - query: filters, - body: (), - }, - 200, - ) - .await?; + let http_client = self.http_client.clone(); + let tasks = http_client + .request::<&TasksCancelQuery, (), TaskInfo>( + &format!("{}/tasks/cancel", self.host), + self.get_api_key(), + Method::Post { + query: filters, + body: (), + }, + 200, + ) + .await?; Ok(tasks) } @@ -956,7 +1051,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::*; + /// # use meilisearch_sdk::{client::*, tasks::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -971,15 +1066,17 @@ impl Client { /// ``` pub async fn delete_tasks_with( &self, - filters: &TasksDeleteQuery<'_>, + filters: &TasksDeleteQuery<'_, Http>, ) -> Result { - let tasks = request::<&TasksDeleteQuery, (), TaskInfo>( - &format!("{}/tasks", self.host), - self.get_api_key(), - Method::Delete { query: filters }, - 200, - ) - .await?; + let http_client = self.http_client.clone(); + let tasks = http_client + .request::<&TasksDeleteQuery, (), TaskInfo>( + &format!("{}/tasks", self.host), + self.get_api_key(), + Method::Delete { query: filters }, + 200, + ) + .await?; Ok(tasks) } @@ -989,7 +1086,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::*; + /// # use meilisearch_sdk::{client::*, tasks::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -1002,13 +1099,15 @@ impl Client { /// # }); /// ``` pub async fn get_tasks(&self) -> Result { - let tasks = request::<(), (), TasksResults>( - &format!("{}/tasks", self.host), - self.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await?; + let http_client = self.http_client.clone(); + let tasks = http_client + .request::<(), (), TasksResults>( + &format!("{}/tasks", self.host), + self.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await?; Ok(tasks) } @@ -1018,7 +1117,7 @@ impl Client { /// # Example /// /// ``` - /// # use meilisearch_sdk::*; + /// # use meilisearch_sdk::client::Client; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -1103,7 +1202,7 @@ mod tests { use meilisearch_test_macro::meilisearch_test; - use crate::{client::*, Action, KeyBuilder, TasksSearchQuery}; + use crate::{client::*, key::Action}; #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Document { @@ -1165,6 +1264,7 @@ mod tests { let path = "/hello"; let address = &format!("{mock_server_url}{path}"); let user_agent = &*qualified_version(); + let client = Client::new(mock_server_url, None::); let assertions = vec![ ( @@ -1172,14 +1272,19 @@ mod tests { .match_header("User-Agent", user_agent) .create_async() .await, - request::<(), (), ()>(address, None, Method::Get { query: () }, 200), + client.http_client.request::<(), (), ()>( + address, + None, + Method::Get { query: () }, + 200, + ), ), ( s.mock("POST", path) .match_header("User-Agent", user_agent) .create_async() .await, - request::<(), (), ()>( + client.http_client.request::<(), (), ()>( address, None, Method::Post { @@ -1194,14 +1299,19 @@ mod tests { .match_header("User-Agent", user_agent) .create_async() .await, - request::<(), (), ()>(address, None, Method::Delete { query: () }, 200), + client.http_client.request::<(), (), ()>( + address, + None, + Method::Delete { query: () }, + 200, + ), ), ( s.mock("PUT", path) .match_header("User-Agent", user_agent) .create_async() .await, - request::<(), (), ()>( + client.http_client.request::<(), (), ()>( address, None, Method::Put { @@ -1216,7 +1326,7 @@ mod tests { .match_header("User-Agent", user_agent) .create_async() .await, - request::<(), (), ()>( + client.http_client.request::<(), (), ()>( address, None, Method::Patch { @@ -1359,7 +1469,6 @@ mod tests { } )); */ - // ==> executing the action without enough right let mut no_right_key = KeyBuilder::new(); no_right_key.with_name(&format!("{name}_1")); diff --git a/src/documents.rs b/src/documents.rs index 7816c6ec..50713aef 100644 --- a/src/documents.rs +++ b/src/documents.rs @@ -1,4 +1,3 @@ -use crate::TaskInfo; use async_trait::async_trait; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -20,7 +19,10 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; /// ## Sample usage: /// ``` /// use serde::{Serialize, Deserialize}; -/// use meilisearch_sdk::{IndexConfig, Settings, Index, Client}; +/// use meilisearch_sdk::documents::IndexConfig; +/// use meilisearch_sdk::settings::Settings; +/// use meilisearch_sdk::indexes::Index; +/// use meilisearch_sdk::client::Client; /// /// #[derive(Serialize, Deserialize, IndexConfig)] /// struct Movie { @@ -45,18 +47,23 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; /// ``` pub use meilisearch_index_setting_macro::IndexConfig; -use crate::{Client, Error, Index, Settings, Task}; +use crate::client::Client; +use crate::request::HttpClient; +use crate::settings::Settings; +use crate::task_info::TaskInfo; +use crate::tasks::Task; +use crate::{errors::Error, indexes::Index}; -#[async_trait] -pub trait IndexConfig { +#[async_trait(?Send)] +pub trait IndexConfig { const INDEX_STR: &'static str; #[must_use] - fn index(client: &Client) -> Index { + fn index(client: &Client) -> Index { client.index(Self::INDEX_STR) } fn generate_settings() -> Settings; - async fn generate_index(client: &Client) -> Result; + async fn generate_index(client: &Client) -> Result, Task>; } #[derive(Debug, Clone, Deserialize)] @@ -68,18 +75,18 @@ pub struct DocumentsResults { } #[derive(Debug, Clone, Serialize)] -pub struct DocumentQuery<'a> { +pub struct DocumentQuery<'a, Http: HttpClient> { #[serde(skip_serializing)] - pub index: &'a Index, + pub index: &'a Index, /// The fields that should appear in the documents. By default, all of the fields are present. #[serde(skip_serializing_if = "Option::is_none")] pub fields: Option>, } -impl<'a> DocumentQuery<'a> { +impl<'a, Http: HttpClient> DocumentQuery<'a, Http> { #[must_use] - pub fn new(index: &Index) -> DocumentQuery { + pub fn new(index: &Index) -> DocumentQuery { DocumentQuery { index, fields: None, @@ -105,7 +112,7 @@ impl<'a> DocumentQuery<'a> { pub fn with_fields( &mut self, fields: impl IntoIterator, - ) -> &mut DocumentQuery<'a> { + ) -> &mut DocumentQuery<'a, Http> { self.fields = Some(fields.into_iter().collect()); self } @@ -147,7 +154,7 @@ impl<'a> DocumentQuery<'a> { /// ); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); - pub async fn execute( + pub async fn execute( &self, document_id: &str, ) -> Result { @@ -156,9 +163,9 @@ impl<'a> DocumentQuery<'a> { } #[derive(Debug, Clone, Serialize)] -pub struct DocumentsQuery<'a> { +pub struct DocumentsQuery<'a, Http: HttpClient> { #[serde(skip_serializing)] - pub index: &'a Index, + pub index: &'a Index, /// The number of documents to skip. /// @@ -191,9 +198,9 @@ pub struct DocumentsQuery<'a> { pub filter: Option<&'a str>, } -impl<'a> DocumentsQuery<'a> { +impl<'a, Http: HttpClient> DocumentsQuery<'a, Http> { #[must_use] - pub fn new(index: &Index) -> DocumentsQuery { + pub fn new(index: &Index) -> DocumentsQuery { DocumentsQuery { index, offset: None, @@ -218,7 +225,7 @@ impl<'a> DocumentsQuery<'a> { /// /// let mut documents_query = DocumentsQuery::new(&index).with_offset(1); /// ``` - pub fn with_offset(&mut self, offset: usize) -> &mut DocumentsQuery<'a> { + pub fn with_offset(&mut self, offset: usize) -> &mut DocumentsQuery<'a, Http> { self.offset = Some(offset); self } @@ -240,7 +247,7 @@ impl<'a> DocumentsQuery<'a> { /// /// documents_query.with_limit(1); /// ``` - pub fn with_limit(&mut self, limit: usize) -> &mut DocumentsQuery<'a> { + pub fn with_limit(&mut self, limit: usize) -> &mut DocumentsQuery<'a, Http> { self.limit = Some(limit); self } @@ -265,12 +272,12 @@ impl<'a> DocumentsQuery<'a> { pub fn with_fields( &mut self, fields: impl IntoIterator, - ) -> &mut DocumentsQuery<'a> { + ) -> &mut DocumentsQuery<'a, Http> { self.fields = Some(fields.into_iter().collect()); self } - pub fn with_filter<'b>(&'b mut self, filter: &'a str) -> &'b mut DocumentsQuery<'a> { + pub fn with_filter<'b>(&'b mut self, filter: &'a str) -> &'b mut DocumentsQuery<'a, Http> { self.filter = Some(filter); self } @@ -305,7 +312,7 @@ impl<'a> DocumentsQuery<'a> { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn execute( + pub async fn execute( &self, ) -> Result, Error> { self.index.get_documents_with::(self).await @@ -313,9 +320,9 @@ impl<'a> DocumentsQuery<'a> { } #[derive(Debug, Clone, Serialize)] -pub struct DocumentDeletionQuery<'a> { +pub struct DocumentDeletionQuery<'a, Http: HttpClient> { #[serde(skip_serializing)] - pub index: &'a Index, + pub index: &'a Index, /// Filters to apply. /// @@ -323,16 +330,19 @@ pub struct DocumentDeletionQuery<'a> { pub filter: Option<&'a str>, } -impl<'a> DocumentDeletionQuery<'a> { +impl<'a, Http: HttpClient> DocumentDeletionQuery<'a, Http> { #[must_use] - pub fn new(index: &Index) -> DocumentDeletionQuery { + pub fn new(index: &Index) -> DocumentDeletionQuery { DocumentDeletionQuery { index, filter: None, } } - pub fn with_filter<'b>(&'b mut self, filter: &'a str) -> &'b mut DocumentDeletionQuery<'a> { + pub fn with_filter<'b>( + &'b mut self, + filter: &'a str, + ) -> &'b mut DocumentDeletionQuery<'a, Http> { self.filter = Some(filter); self } @@ -345,7 +355,7 @@ impl<'a> DocumentDeletionQuery<'a> { #[cfg(test)] mod tests { use super::*; - use crate::{client::*, errors::*, indexes::*}; + use crate::{client::Client, errors::*, indexes::*, request::IsahcClient}; use meilisearch_test_macro::meilisearch_test; use serde::{Deserialize, Serialize}; @@ -357,7 +367,10 @@ mod tests { #[allow(unused)] #[derive(IndexConfig)] - struct MovieClips { + struct MovieClips + where + IsahcClient: HttpClient, + { #[index_config(primary_key)] movie_id: u64, #[index_config(distinct)] @@ -374,7 +387,10 @@ mod tests { #[allow(unused)] #[derive(IndexConfig)] - struct VideoClips { + struct VideoClips + where + IsahcClient: HttpClient, + { video_id: u64, } diff --git a/src/dumps.rs b/src/dumps.rs index 6f112a1a..7dfcd987 100644 --- a/src/dumps.rs +++ b/src/dumps.rs @@ -38,11 +38,11 @@ //! # }); //! ``` -use crate::{request::*, Client, Error, TaskInfo}; +use crate::{client::Client, errors::Error, request::*, task_info::TaskInfo}; /// Dump related methods. /// See the [dumps](crate::dumps) module. -impl Client { +impl Client { /// Triggers a dump creation process. /// /// Once the process is complete, a dump is created in the [dumps directory](https://www.meilisearch.com/docs/learn/configuration/instance_options#dump-directory). @@ -73,21 +73,23 @@ impl Client { /// # }); /// ``` pub async fn create_dump(&self) -> Result { - request::<(), (), TaskInfo>( - &format!("{}/dumps", self.host), - self.get_api_key(), - Method::Post { - query: (), - body: (), - }, - 202, - ) - .await + self.http_client + .clone() + .request::<(), (), TaskInfo>( + &format!("{}/dumps", self.host), + self.get_api_key(), + Method::Post { + query: (), + body: (), + }, + 202, + ) + .await } } /// Alias for [`create_dump`](Client::create_dump). -pub async fn create_dump(client: &Client) -> Result { +pub async fn create_dump(client: &Client) -> Result { client.create_dump().await } diff --git a/src/errors.rs b/src/errors.rs index 461e841b..23ac5dbd 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -46,6 +46,7 @@ pub enum Error { InvalidTenantToken(#[from] jsonwebtoken::errors::Error), /// The http client encountered an error. + #[cfg(feature = "isahc")] #[cfg(not(target_arch = "wasm32"))] #[error("HTTP request failed: {}", .0)] HttpError(isahc::Error), @@ -276,6 +277,7 @@ impl std::fmt::Display for ErrorCode { } } +#[cfg(feature = "isahc")] #[cfg(not(target_arch = "wasm32"))] impl From for Error { fn from(error: isahc::Error) -> Error { diff --git a/src/features.rs b/src/features.rs index 3f1ac91f..a1784418 100644 --- a/src/features.rs +++ b/src/features.rs @@ -1,6 +1,7 @@ use crate::{ - request::{request, Method}, - Client, Error, + client::Client, + errors::Error, + request::{HttpClient, Method}, }; use serde::{Deserialize, Serialize}; @@ -18,7 +19,7 @@ pub struct ExperimentalFeaturesResult { /// # Example /// /// ``` -/// # use meilisearch_sdk::{Client, ExperimentalFeatures}; +/// # use meilisearch_sdk::{client::Client, features::ExperimentalFeatures}; /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); /// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)); @@ -27,16 +28,16 @@ pub struct ExperimentalFeaturesResult { /// ``` #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] -pub struct ExperimentalFeatures<'a> { +pub struct ExperimentalFeatures<'a, Http: HttpClient> { #[serde(skip_serializing)] - client: &'a Client, + client: &'a Client, #[serde(skip_serializing_if = "Option::is_none")] pub vector_store: Option, } -impl<'a> ExperimentalFeatures<'a> { +impl<'a, Http: HttpClient> ExperimentalFeatures<'a, Http> { #[must_use] - pub fn new(client: &'a Client) -> Self { + pub fn new(client: &'a Client) -> Self { ExperimentalFeatures { client, vector_store: None, @@ -53,7 +54,7 @@ impl<'a> ExperimentalFeatures<'a> { /// # Example /// /// ``` - /// # use meilisearch_sdk::{Client, ExperimentalFeatures}; + /// # use meilisearch_sdk::{client::Client, features::ExperimentalFeatures}; /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); /// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)); @@ -63,13 +64,16 @@ impl<'a> ExperimentalFeatures<'a> { /// }); /// ``` pub async fn get(&self) -> Result { - request::<(), (), ExperimentalFeaturesResult>( - &format!("{}/experimental-features", self.client.host), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), ExperimentalFeaturesResult>( + &format!("{}/experimental-features", self.client.host), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Update the experimental features @@ -77,7 +81,7 @@ impl<'a> ExperimentalFeatures<'a> { /// # Example /// /// ``` - /// # use meilisearch_sdk::{Client, ExperimentalFeatures}; + /// # use meilisearch_sdk::{client::Client, features::ExperimentalFeatures}; /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); /// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)); @@ -88,16 +92,19 @@ impl<'a> ExperimentalFeatures<'a> { /// }); /// ``` pub async fn update(&self) -> Result { - request::<(), &Self, ExperimentalFeaturesResult>( - &format!("{}/experimental-features", self.client.host), - self.client.get_api_key(), - Method::Patch { - query: (), - body: self, - }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), &Self, ExperimentalFeaturesResult>( + &format!("{}/experimental-features", self.client.host), + self.client.get_api_key(), + Method::Patch { + query: (), + body: self, + }, + 200, + ) + .await } } diff --git a/src/indexes.rs b/src/indexes.rs index c9bca878..952f4a99 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -1,7 +1,12 @@ use crate::{ - request::*, search::*, tasks::*, Client, DocumentDeletionQuery, DocumentQuery, DocumentsQuery, - DocumentsResults, Error, MeilisearchCommunicationError, MeilisearchError, TaskInfo, - MEILISEARCH_VERSION_HINT, + client::Client, + documents::{DocumentDeletionQuery, DocumentQuery, DocumentsQuery, DocumentsResults}, + errors::{Error, MeilisearchCommunicationError, MeilisearchError, MEILISEARCH_VERSION_HINT}, + request::*, + search::*, + task_info::TaskInfo, + tasks::*, + DefaultHttpClient, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{collections::HashMap, fmt::Display, time::Duration}; @@ -60,9 +65,9 @@ use time::OffsetDateTime; /// ``` #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] -pub struct Index { +pub struct Index { #[serde(skip_serializing)] - pub client: Client, + pub client: Client, pub uid: String, #[serde(with = "time::serde::rfc3339::option")] pub updated_at: Option, @@ -71,8 +76,8 @@ pub struct Index { pub primary_key: Option, } -impl Index { - pub fn new(uid: impl Into, client: Client) -> Index { +impl Index { + pub fn new(uid: impl Into, client: Client) -> Index { Index { uid: uid.into(), client, @@ -82,7 +87,10 @@ impl Index { } } /// Internal Function to create an [Index] from `serde_json::Value` and [Client]. - pub(crate) fn from_value(raw_index: serde_json::Value, client: Client) -> Result { + pub(crate) fn from_value( + raw_index: serde_json::Value, + client: Client, + ) -> Result, Error> { #[derive(Deserialize, Debug)] #[allow(non_snake_case)] struct IndexFromSerde { @@ -110,7 +118,7 @@ impl Index { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, task_info::*, Task, SucceededTask}; + /// # use meilisearch_sdk::{client::*, indexes::*, task_info::*, tasks::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -174,13 +182,16 @@ impl Index { /// # }); /// ``` pub async fn delete(self) -> Result { - request::<(), (), TaskInfo>( - &format!("{}/indexes/{}", self.client.host, self.uid), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!("{}/indexes/{}", self.client.host, self.uid), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Search for documents matching a specific query in the index. @@ -215,17 +226,20 @@ impl Index { /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn execute_query( + pub async fn execute_query( &self, - body: &SearchQuery<'_>, + body: &SearchQuery<'_, Http>, ) -> Result, Error> { - request::<(), &SearchQuery, SearchResults>( - &format!("{}/indexes/{}/search", self.client.host, self.uid), - self.client.get_api_key(), - Method::Post { body, query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), &SearchQuery, SearchResults>( + &format!("{}/indexes/{}/search", self.client.host, self.uid), + self.client.get_api_key(), + Method::Post { body, query: () }, + 200, + ) + .await } /// Search for documents matching a specific query in the index. @@ -265,7 +279,7 @@ impl Index { /// # }); /// ``` #[must_use] - pub fn search(&self) -> SearchQuery { + pub fn search(&self) -> SearchQuery { SearchQuery::new(self) } @@ -303,7 +317,7 @@ impl Index { /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_document( + pub async fn get_document( &self, document_id: &str, ) -> Result { @@ -311,14 +325,16 @@ impl Index { "{}/indexes/{}/documents/{}", self.client.host, self.uid, document_id ); - - request::<(), (), T>( - &url, - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), T>( + &url, + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get one document with parameters. @@ -358,25 +374,27 @@ impl Index { /// ); /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); - pub async fn get_document_with( + pub async fn get_document_with( &self, document_id: &str, - document_query: &DocumentQuery<'_>, + document_query: &DocumentQuery<'_, Http>, ) -> Result { let url = format!( "{}/indexes/{}/documents/{}", self.client.host, self.uid, document_id ); - - request::<&DocumentQuery, (), T>( - &url, - self.client.get_api_key(), - Method::Get { - query: document_query, - }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<&DocumentQuery, (), T>( + &url, + self.client.get_api_key(), + Method::Get { + query: document_query, + }, + 200, + ) + .await } /// Get documents by batch. @@ -408,18 +426,20 @@ impl Index { /// # movie_index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_documents( + pub async fn get_documents( &self, ) -> Result, Error> { let url = format!("{}/indexes/{}/documents", self.client.host, self.uid); - - request::<(), (), DocumentsResults>( - &url, - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), DocumentsResults>( + &url, + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get documents by batch with parameters. @@ -459,53 +479,60 @@ impl Index { /// # movie_index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn get_documents_with( + pub async fn get_documents_with( &self, - documents_query: &DocumentsQuery<'_>, + documents_query: &DocumentsQuery<'_, Http>, ) -> Result, Error> { if documents_query.filter.is_some() { let url = format!("{}/indexes/{}/documents/fetch", self.client.host, self.uid); - return request::<(), &DocumentsQuery, DocumentsResults>( + return self + .client + .http_client + .clone() + .request::<(), &DocumentsQuery, DocumentsResults>( + &url, + self.client.get_api_key(), + Method::Post { + body: documents_query, + query: (), + }, + 200, + ) + .await + .map_err(|err| match err { + Error::MeilisearchCommunication(error) => { + Error::MeilisearchCommunication(MeilisearchCommunicationError { + status_code: error.status_code, + url: error.url, + message: Some(format!("{}.", MEILISEARCH_VERSION_HINT)), + }) + } + Error::Meilisearch(error) => Error::Meilisearch(MeilisearchError { + error_code: error.error_code, + error_link: error.error_link, + error_type: error.error_type, + error_message: format!( + "{}\n{}.", + error.error_message, MEILISEARCH_VERSION_HINT + ), + }), + _ => err, + }); + } + + let url = format!("{}/indexes/{}/documents", self.client.host, self.uid); + self.client + .http_client + .clone() + .request::<&DocumentsQuery, (), DocumentsResults>( &url, self.client.get_api_key(), - Method::Post { - body: documents_query, - query: (), + Method::Get { + query: documents_query, }, 200, ) .await - .map_err(|err| match err { - Error::MeilisearchCommunication(error) => { - Error::MeilisearchCommunication(MeilisearchCommunicationError { - status_code: error.status_code, - url: error.url, - message: Some(format!("{MEILISEARCH_VERSION_HINT}.")), - }) - } - Error::Meilisearch(error) => Error::Meilisearch(MeilisearchError { - error_code: error.error_code, - error_link: error.error_link, - error_type: error.error_type, - error_message: format!( - "{}\n{}.", - error.error_message, MEILISEARCH_VERSION_HINT - ), - }), - _ => err, - }); - } - - let url = format!("{}/indexes/{}/documents", self.client.host, self.uid); - request::<&DocumentsQuery, (), DocumentsResults>( - &url, - self.client.get_api_key(), - Method::Get { - query: documents_query, - }, - 200, - ) - .await } /// Add a list of documents or replace them if they already exist. @@ -561,7 +588,7 @@ impl Index { /// # movie_index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn add_or_replace( + pub async fn add_or_replace( &self, documents: &[T], primary_key: Option<&str>, @@ -574,16 +601,19 @@ impl Index { } else { format!("{}/indexes/{}/documents", self.client.host, self.uid) }; - request::<(), &[T], TaskInfo>( - &url, - self.client.get_api_key(), - Method::Post { - query: (), - body: documents, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &[T], TaskInfo>( + &url, + self.client.get_api_key(), + Method::Post { + query: (), + body: documents, + }, + 202, + ) + .await } /// Add a raw and unchecked payload to meilisearch. @@ -640,21 +670,23 @@ impl Index { } else { format!("{}/indexes/{}/documents", self.client.host, self.uid) }; - stream_request::<(), T, TaskInfo>( - &url, - self.client.get_api_key(), - Method::Post { - query: (), - body: payload, - }, - content_type, - 202, - ) - .await + let http_clint = self.client.http_client.clone(); + http_clint + .stream_request::<(), T, TaskInfo>( + &url, + self.client.get_api_key(), + Method::Post { + query: (), + body: payload, + }, + content_type, + 202, + ) + .await } /// Alias for [`Index::add_or_replace`]. - pub async fn add_documents( + pub async fn add_documents( &self, documents: &[T], primary_key: Option<&str>, @@ -896,7 +928,7 @@ impl Index { /// # movie_index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn add_or_update( + pub async fn add_or_update( &self, documents: &[T], primary_key: Option>, @@ -911,16 +943,18 @@ impl Index { } else { format!("{}/indexes/{}/documents", self.client.host, self.uid) }; - request::<(), &[T], TaskInfo>( - &url, - self.client.get_api_key(), - Method::Put { - query: (), - body: documents, - }, - 202, - ) - .await + let client = self.client.http_client.clone(); + client + .request::<(), &[T], TaskInfo>( + &url, + self.client.get_api_key(), + Method::Put { + query: (), + body: documents, + }, + 202, + ) + .await } /// Add a raw and unchecked payload to meilisearch. @@ -978,17 +1012,19 @@ impl Index { } else { format!("{}/indexes/{}/documents", self.client.host, self.uid) }; - stream_request::<(), T, TaskInfo>( - &url, - self.client.get_api_key(), - Method::Put { - query: (), - body: payload, - }, - content_type, - 202, - ) - .await + let http_client = self.client.http_client.clone(); + http_client + .stream_request::<(), T, TaskInfo>( + &url, + self.client.get_api_key(), + Method::Put { + query: (), + body: payload, + }, + content_type, + 202, + ) + .await } /// Delete all documents in the [Index]. @@ -1028,13 +1064,16 @@ impl Index { /// # }); /// ``` pub async fn delete_all_documents(&self) -> Result { - request::<(), (), TaskInfo>( - &format!("{}/indexes/{}/documents", self.client.host, self.uid), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!("{}/indexes/{}/documents", self.client.host, self.uid), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Delete one document based on its unique id. @@ -1071,16 +1110,19 @@ impl Index { /// # }); /// ``` pub async fn delete_document(&self, uid: T) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/documents/{}", - self.client.host, self.uid, uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/documents/{}", + self.client.host, self.uid, uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Delete a selection of documents based on array of document id's. @@ -1119,23 +1161,26 @@ impl Index { /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn delete_documents( + pub async fn delete_documents( &self, uids: &[T], ) -> Result { - request::<(), &[T], TaskInfo>( - &format!( - "{}/indexes/{}/documents/delete-batch", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Post { - query: (), - body: uids, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &[T], TaskInfo>( + &format!( + "{}/indexes/{}/documents/delete-batch", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Post { + query: (), + body: uids, + }, + 202, + ) + .await } /// Delete a selection of documents with filters. @@ -1179,18 +1224,21 @@ impl Index { /// ``` pub async fn delete_documents_with( &self, - query: &DocumentDeletionQuery<'_>, + query: &DocumentDeletionQuery<'_, Http>, ) -> Result { - request::<(), &DocumentDeletionQuery, TaskInfo>( - &format!("{}/indexes/{}/documents/delete", self.client.host, self.uid), - self.client.get_api_key(), - Method::Post { - query: (), - body: query, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &DocumentDeletionQuery, TaskInfo>( + &format!("{}/indexes/{}/documents/delete", self.client.host, self.uid), + self.client.get_api_key(), + Method::Post { + query: (), + body: query, + }, + 202, + ) + .await } /// Alias for the [`Index::update`] method. @@ -1308,13 +1356,16 @@ impl Index { /// # }); /// ``` pub async fn get_task(&self, uid: impl AsRef) -> Result { - request::<(), (), Task>( - &format!("{}/tasks/{}", self.client.host, uid.as_ref()), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Task>( + &format!("{}/tasks/{}", self.client.host, uid.as_ref()), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get the status of all tasks in a given index. @@ -1369,7 +1420,7 @@ impl Index { /// ``` pub async fn get_tasks_with( &self, - tasks_query: &TasksQuery<'_, TasksPaginationFilters>, + tasks_query: &TasksQuery<'_, TasksPaginationFilters, Http>, ) -> Result { let mut query = tasks_query.clone(); query.with_index_uids([self.uid.as_str()]); @@ -1397,13 +1448,16 @@ impl Index { /// # }); /// ``` pub async fn get_stats(&self) -> Result { - request::<(), (), IndexStats>( - &format!("{}/indexes/{}/stats", self.client.host, self.uid), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), IndexStats>( + &format!("{}/indexes/{}/stats", self.client.host, self.uid), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Wait until Meilisearch processes a [Task], and get its status. @@ -1510,7 +1564,7 @@ impl Index { /// # None).await.unwrap(); /// # }); /// ``` - pub async fn add_documents_in_batches( + pub async fn add_documents_in_batches( &self, documents: &[T], batch_size: Option, @@ -1598,7 +1652,7 @@ impl Index { /// # None).await.unwrap(); /// # }); /// ``` - pub async fn update_documents_in_batches( + pub async fn update_documents_in_batches( &self, documents: &[T], batch_size: Option, @@ -1612,7 +1666,7 @@ impl Index { } } -impl AsRef for Index { +impl AsRef for Index { fn as_ref(&self) -> &str { &self.uid } @@ -1655,16 +1709,16 @@ impl AsRef for Index { /// ``` #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] -pub struct IndexUpdater<'a> { +pub struct IndexUpdater<'a, Http: HttpClient> { #[serde(skip)] - pub client: &'a Client, + 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 { +impl<'a, Http: HttpClient> IndexUpdater<'a, Http> { + pub fn new(uid: impl AsRef, client: &Client) -> IndexUpdater { IndexUpdater { client, primary_key: None, @@ -1708,7 +1762,10 @@ impl<'a> IndexUpdater<'a> { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub fn with_primary_key(&mut self, primary_key: impl AsRef) -> &mut IndexUpdater<'a> { + pub fn with_primary_key( + &mut self, + primary_key: impl AsRef, + ) -> &mut IndexUpdater<'a, Http> { self.primary_key = Some(primary_key.as_ref().to_string()); self } @@ -1751,27 +1808,30 @@ impl<'a> IndexUpdater<'a> { /// # }); /// ``` pub async fn execute(&'a self) -> Result { - request::<(), &IndexUpdater, TaskInfo>( - &format!("{}/indexes/{}", self.client.host, self.uid), - self.client.get_api_key(), - Method::Patch { - query: (), - body: self, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &IndexUpdater, TaskInfo>( + &format!("{}/indexes/{}", self.client.host, self.uid), + self.client.get_api_key(), + Method::Patch { + query: (), + body: self, + }, + 202, + ) + .await } } -impl AsRef for IndexUpdater<'_> { +impl AsRef for IndexUpdater<'_, Http> { fn as_ref(&self) -> &str { &self.uid } } -impl<'a> AsRef> for IndexUpdater<'a> { - fn as_ref(&self) -> &IndexUpdater<'a> { +impl<'a, Http: HttpClient> AsRef> for IndexUpdater<'a, Http> { + fn as_ref(&self) -> &IndexUpdater<'a, Http> { self } } @@ -1816,9 +1876,9 @@ pub struct IndexStats { /// ``` #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] -pub struct IndexesQuery<'a> { +pub struct IndexesQuery<'a, Http: HttpClient> { #[serde(skip_serializing)] - pub client: &'a Client, + pub client: &'a Client, /// The number of [Indexes](Index) to skip. /// /// If the value of the parameter `offset` is `n`, the `n` first indexes will not be returned. @@ -1840,9 +1900,9 @@ pub struct IndexesQuery<'a> { pub limit: Option, } -impl<'a> IndexesQuery<'a> { +impl<'a, Http: HttpClient> IndexesQuery<'a, Http> { #[must_use] - pub fn new(client: &Client) -> IndexesQuery { + pub fn new(client: &Client) -> IndexesQuery { IndexesQuery { client, offset: None, @@ -1880,7 +1940,7 @@ impl<'a> IndexesQuery<'a> { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub fn with_offset(&mut self, offset: usize) -> &mut IndexesQuery<'a> { + pub fn with_offset(&mut self, offset: usize) -> &mut IndexesQuery<'a, Http> { self.offset = Some(offset); self } @@ -1915,7 +1975,7 @@ impl<'a> IndexesQuery<'a> { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub fn with_limit(&mut self, limit: usize) -> &mut IndexesQuery<'a> { + pub fn with_limit(&mut self, limit: usize) -> &mut IndexesQuery<'a, Http> { self.limit = Some(limit); self } @@ -1949,14 +2009,14 @@ impl<'a> IndexesQuery<'a> { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn execute(&self) -> Result { + pub async fn execute(&self) -> Result, Error> { self.client.list_all_indexes_with(self).await } } #[derive(Debug, Clone)] -pub struct IndexesResults { - pub results: Vec, +pub struct IndexesResults { + pub results: Vec>, pub limit: u32, pub offset: u32, pub total: u32, @@ -2152,6 +2212,7 @@ mod tests { Ok(()) } #[meilisearch_test] + async fn test_get_one_task(client: Client, index: Index) -> Result<(), Error> { let task = index .delete_all_documents() diff --git a/src/key.rs b/src/key.rs index 84217b69..3c8f51a7 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use time::OffsetDateTime; -use crate::{Client, Error}; +use crate::{client::Client, errors::Error, request::HttpClient}; /// Represents a [meilisearch key](https://www.meilisearch.com/docs/reference/api/keys#returned-fields). /// @@ -33,7 +33,7 @@ impl Key { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -61,7 +61,7 @@ impl Key { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -92,7 +92,7 @@ impl Key { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Client}; + /// # use meilisearch_sdk::{key::KeyBuilder, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -113,7 +113,7 @@ impl Key { /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` - pub async fn update(&self, client: &Client) -> Result { + pub async fn update(&self, client: &Client) -> Result { // only send description and name let mut key_update = KeyUpdater::new(self); @@ -132,7 +132,7 @@ impl Key { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Client}; + /// # use meilisearch_sdk::{key::KeyBuilder, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -145,7 +145,7 @@ impl Key { /// client.delete_key(key).await.unwrap(); /// # }); /// ``` - pub async fn delete(&self, client: &Client) -> Result<(), Error> { + pub async fn delete(&self, client: &Client) -> Result<(), Error> { client.delete_key(self).await } } @@ -185,7 +185,7 @@ impl KeyUpdater { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action, Client, KeyUpdater}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -218,7 +218,7 @@ impl KeyUpdater { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action, Client, KeyUpdater}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -251,7 +251,7 @@ impl KeyUpdater { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, KeyUpdater, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -269,7 +269,7 @@ impl KeyUpdater { /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` - pub async fn execute(&self, client: &Client) -> Result { + pub async fn execute(&self, client: &Client) -> Result { client.update_key(self).await } } @@ -328,7 +328,7 @@ impl KeysQuery { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeysQuery, Action, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -352,7 +352,7 @@ impl KeysQuery { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeysQuery, Action, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -376,7 +376,7 @@ impl KeysQuery { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeysQuery, Action, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -390,7 +390,10 @@ impl KeysQuery { /// assert_eq!(keys.results.len(), 1); /// # }); /// ``` - pub async fn execute(&self, client: &Client) -> Result { + pub async fn execute( + &self, + client: &Client, + ) -> Result { client.get_keys_with(self).await } } @@ -402,7 +405,7 @@ impl KeysQuery { /// # Example /// /// ``` -/// # use meilisearch_sdk::{KeyBuilder, Action, Client}; +/// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -439,7 +442,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::KeyBuilder; + /// # use meilisearch_sdk::key::KeyBuilder; /// let builder = KeyBuilder::new(); /// ``` #[must_use] @@ -452,7 +455,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action}; + /// # use meilisearch_sdk::key::*; /// let mut builder = KeyBuilder::new(); /// builder.with_actions(vec![Action::Search, Action::DocumentsAdd]); /// ``` @@ -466,7 +469,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action}; + /// # use meilisearch_sdk::key::*; /// let mut builder = KeyBuilder::new(); /// builder.with_action(Action::DocumentsAdd); /// ``` @@ -480,7 +483,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::KeyBuilder; + /// # use meilisearch_sdk::key::KeyBuilder; /// # use time::{OffsetDateTime, Duration}; /// let mut builder = KeyBuilder::new(); /// // create a key that expires in two weeks from now @@ -496,7 +499,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Client}; + /// # use meilisearch_sdk::{key::KeyBuilder, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -529,7 +532,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::KeyBuilder; + /// # use meilisearch_sdk::key::KeyBuilder; /// let mut builder = KeyBuilder::new(); /// builder.with_index("test"); /// ``` @@ -543,7 +546,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -569,7 +572,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -595,7 +598,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Action, Client}; + /// # use meilisearch_sdk::{key::*, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -621,7 +624,7 @@ impl KeyBuilder { /// # Example /// /// ``` - /// # use meilisearch_sdk::{KeyBuilder, Client}; + /// # use meilisearch_sdk::{key::KeyBuilder, client::Client}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -637,7 +640,7 @@ impl KeyBuilder { /// # client.delete_key(key).await.unwrap(); /// # }); /// ``` - pub async fn execute(&self, client: &Client) -> Result { + pub async fn execute(&self, client: &Client) -> Result { client.create_key(self).await } } diff --git a/src/lib.rs b/src/lib.rs index 9543aa2a..e7ae60b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -219,6 +219,12 @@ //! "query": "wonder" //! } //! ``` +//! +//! ### Using users customized HttpClient +//! +//! If you want to change the `HttpClient` you can incorporate using the `Client::new_with_client` method. +//! To use it, you need to implement the `HttpClient Trait`(`isahc` is used by default). +//! There are [using-reqwest-example](./examples/cli-app-with-reqwest) of using `reqwest`. #![warn(clippy::all)] #![allow(clippy::needless_doctest_main)] @@ -237,7 +243,7 @@ pub mod features; pub mod indexes; /// Module containing the [`Key`] struct. pub mod key; -mod request; +pub mod request; /// Module related to search queries and results. pub mod search; /// Module containing [`Settings`]. @@ -251,17 +257,14 @@ mod tenant_tokens; /// Module containing utilizes functions. mod utils; -pub use client::*; -pub use documents::*; -pub use dumps::*; -pub use errors::*; -pub use features::*; -pub use indexes::*; -pub use key::*; -pub use search::*; -pub use settings::*; -pub use task_info::*; -pub use tasks::*; +#[cfg(feature = "isahc")] +#[cfg(not(target_arch = "wasm32"))] +pub type DefaultHttpClient = request::IsahcClient; +#[cfg(target_arch = "wasm32")] +pub type DefaultHttpClient = request::WebSysClient; + +#[cfg(not(feature = "isahc"))] +pub type DefaultHttpClient = std::convert::Infallible; #[cfg(test)] /// Support for the `IndexConfig` derive proc macro in the crate's tests. diff --git a/src/request.rs b/src/request.rs index ce8803d6..1bfc1bf4 100644 --- a/src/request.rs +++ b/src/request.rs @@ -1,10 +1,14 @@ -use crate::{Error, MeilisearchCommunicationError, MeilisearchError}; +use std::convert::Infallible; + +use async_trait::async_trait; use log::{error, trace, warn}; use serde::{de::DeserializeOwned, Serialize}; -use serde_json::{from_str, to_string}; +use serde_json::from_str; + +use crate::errors::{Error, MeilisearchCommunicationError, MeilisearchError}; #[derive(Debug)] -pub(crate) enum Method { +pub enum Method { Get { query: Q }, Post { query: Q, body: B }, Patch { query: Q, body: B }, @@ -12,324 +16,394 @@ pub(crate) enum Method { Delete { query: Q }, } -#[cfg(not(target_arch = "wasm32"))] -pub fn add_query_parameters(url: &str, query: &Query) -> Result { - let query = yaup::to_string(query)?; +#[async_trait(?Send)] +pub trait HttpClient: Clone + Send + Sync { + async fn request( + self, + url: &str, + apikey: Option<&str>, + method: Method, + expected_status_code: u16, + ) -> Result + where + Query: Serialize + Send + Sync, + Body: Serialize + Send + Sync, + Output: DeserializeOwned + 'static + Send; + + #[cfg(not(target_arch = "wasm32"))] + async fn stream_request< + 'a, + Query: Serialize + Send + Sync, + Body: futures_io::AsyncRead + Send + Sync + 'static, + Output: DeserializeOwned + 'static, + >( + self, + url: &str, + apikey: Option<&str>, + method: Method, + content_type: &str, + expected_status_code: u16, + ) -> Result; +} - if query.is_empty() { - Ok(url.to_string()) - } else { - Ok(format!("{url}?{query}")) +#[cfg(feature = "isahc")] +#[derive(Debug, Clone, Copy, Default, Serialize)] +pub struct IsahcClient; + +#[cfg(feature = "isahc")] +impl IsahcClient { + pub fn new() -> Self { + IsahcClient + } +} + +#[cfg(target_arch = "wasm32")] +#[derive(Debug, Clone, Copy, Default, Serialize)] +pub struct WebSysClient; + +#[cfg(target_arch = "wasm32")] +impl WebSysClient { + pub fn new() -> Self { + WebSysClient } } +#[cfg(feature = "isahc")] #[cfg(not(target_arch = "wasm32"))] -pub(crate) async fn request< - Query: Serialize, - Body: Serialize, - Output: DeserializeOwned + 'static, ->( - url: &str, - apikey: Option<&str>, - method: Method, - expected_status_code: u16, -) -> Result { - use isahc::http::header; - use isahc::http::method::Method as HttpMethod; - use isahc::*; - - let builder = Request::builder().header(header::USER_AGENT, qualified_version()); - let builder = match apikey { - Some(apikey) => builder.header(header::AUTHORIZATION, format!("Bearer {apikey}")), - None => builder, - }; +#[async_trait(?Send)] +impl HttpClient for IsahcClient { + async fn request( + self, + url: &str, + apikey: Option<&str>, + method: Method, + expected_status_code: u16, + ) -> Result + where + Query: Serialize + Send + Sync, + Body: Serialize + Send + Sync, + Output: DeserializeOwned + 'static + Send, + { + use isahc::http::header; + use isahc::http::method::Method as HttpMethod; + use isahc::*; + use serde_json::to_string; + + let builder = Request::builder().header(header::USER_AGENT, qualified_version()); + let builder = match apikey { + Some(apikey) => builder.header(header::AUTHORIZATION, format!("Bearer {apikey}")), + None => builder, + }; - let mut response = match &method { - Method::Get { query } => { - let url = add_query_parameters(url, query)?; - - builder - .method(HttpMethod::GET) - .uri(url) - .body(()) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - Method::Delete { query } => { - let url = add_query_parameters(url, query)?; - - builder - .method(HttpMethod::DELETE) - .uri(url) - .body(()) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - Method::Post { query, body } => { - let url = add_query_parameters(url, query)?; - - builder - .method(HttpMethod::POST) - .uri(url) - .header(header::CONTENT_TYPE, "application/json") - .body(to_string(&body).unwrap()) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - Method::Patch { query, body } => { - let url = add_query_parameters(url, query)?; - - builder - .method(HttpMethod::PATCH) - .uri(url) - .header(header::CONTENT_TYPE, "application/json") - .body(to_string(&body).unwrap()) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - Method::Put { query, body } => { - let url = add_query_parameters(url, query)?; - - builder - .method(HttpMethod::PUT) - .uri(url) - .header(header::CONTENT_TYPE, "application/json") - .body(to_string(&body).unwrap()) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - }; + let mut response = match &method { + Method::Get { query } => { + let url = add_query_parameters(url, query)?; + + builder + .method(HttpMethod::GET) + .uri(url) + .body(()) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + Method::Delete { query } => { + let url = add_query_parameters(url, query)?; + + builder + .method(HttpMethod::DELETE) + .uri(url) + .body(()) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + Method::Post { query, body } => { + let url = add_query_parameters(url, query)?; + + builder + .method(HttpMethod::POST) + .uri(url) + .header(header::CONTENT_TYPE, "application/json") + .body(to_string(&body).unwrap()) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + Method::Patch { query, body } => { + let url = add_query_parameters(url, query)?; + + builder + .method(HttpMethod::PATCH) + .uri(url) + .header(header::CONTENT_TYPE, "application/json") + .body(to_string(&body).unwrap()) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + Method::Put { query, body } => { + let url = add_query_parameters(url, query)?; + + builder + .method(HttpMethod::PUT) + .uri(url) + .header(header::CONTENT_TYPE, "application/json") + .body(to_string(&body).unwrap()) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + }; - let status = response.status().as_u16(); + let status = response.status().as_u16(); - let mut body = response - .text() - .await - .map_err(|e| crate::errors::Error::HttpError(e.into()))?; + let mut body = response + .text() + .await + .map_err(|e| crate::errors::Error::HttpError(e.into()))?; - if body.is_empty() { - body = "null".to_string(); + if body.is_empty() { + body = "null".to_string(); + } + + parse_response(status, expected_status_code, &body, url.to_string()) + // parse_response(status, expected_status_code, body) } - parse_response(status, expected_status_code, &body, url.to_string()) - // parse_response(status, expected_status_code, body) -} + async fn stream_request< + 'a, + Query: Serialize + Send + Sync, + Body: futures_io::AsyncRead + Send + Sync + 'static, + Output: DeserializeOwned + 'static, + >( + self, + url: &str, + apikey: Option<&str>, + method: Method, + content_type: &str, + expected_status_code: u16, + ) -> Result { + use isahc::http::header; + use isahc::http::method::Method as HttpMethod; + use isahc::*; + + let builder = Request::builder().header(header::USER_AGENT, qualified_version()); + let builder = match apikey { + Some(apikey) => builder.header(header::AUTHORIZATION, format!("Bearer {apikey}")), + None => builder, + }; -#[cfg(not(target_arch = "wasm32"))] -pub(crate) async fn stream_request< - 'a, - Query: Serialize, - Body: futures_io::AsyncRead + Send + Sync + 'static, - Output: DeserializeOwned + 'static, ->( - url: &str, - apikey: Option<&str>, - method: Method, - content_type: &str, - expected_status_code: u16, -) -> Result { - use isahc::http::header; - use isahc::http::method::Method as HttpMethod; - use isahc::*; - - let builder = Request::builder().header(header::USER_AGENT, qualified_version()); - let builder = match apikey { - Some(apikey) => builder.header(header::AUTHORIZATION, format!("Bearer {apikey}")), - None => builder, - }; + let mut response = match method { + Method::Get { query } => { + let url = add_query_parameters(url, &query)?; + + builder + .method(HttpMethod::GET) + .uri(url) + .body(()) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + Method::Delete { query } => { + let url = add_query_parameters(url, &query)?; + + builder + .method(HttpMethod::DELETE) + .uri(url) + .body(()) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + Method::Post { query, body } => { + let url = add_query_parameters(url, &query)?; + + builder + .method(HttpMethod::POST) + .uri(url) + .header(header::CONTENT_TYPE, content_type) + .body(AsyncBody::from_reader(body)) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + Method::Patch { query, body } => { + let url = add_query_parameters(url, &query)?; + + builder + .method(HttpMethod::PATCH) + .uri(url) + .header(header::CONTENT_TYPE, content_type) + .body(AsyncBody::from_reader(body)) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + Method::Put { query, body } => { + let url = add_query_parameters(url, &query)?; + + builder + .method(HttpMethod::PUT) + .uri(url) + .header(header::CONTENT_TYPE, content_type) + .body(AsyncBody::from_reader(body)) + .map_err(|_| crate::errors::Error::InvalidRequest)? + .send_async() + .await? + } + }; - let mut response = match method { - Method::Get { query } => { - let url = add_query_parameters(url, &query)?; - - builder - .method(HttpMethod::GET) - .uri(url) - .body(()) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - Method::Delete { query } => { - let url = add_query_parameters(url, &query)?; - - builder - .method(HttpMethod::DELETE) - .uri(url) - .body(()) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - Method::Post { query, body } => { - let url = add_query_parameters(url, &query)?; - - builder - .method(HttpMethod::POST) - .uri(url) - .header(header::CONTENT_TYPE, content_type) - .body(AsyncBody::from_reader(body)) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - Method::Patch { query, body } => { - let url = add_query_parameters(url, &query)?; - - builder - .method(HttpMethod::PATCH) - .uri(url) - .header(header::CONTENT_TYPE, content_type) - .body(AsyncBody::from_reader(body)) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - Method::Put { query, body } => { - let url = add_query_parameters(url, &query)?; - - builder - .method(HttpMethod::PUT) - .uri(url) - .header(header::CONTENT_TYPE, content_type) - .body(AsyncBody::from_reader(body)) - .map_err(|_| crate::errors::Error::InvalidRequest)? - .send_async() - .await? - } - }; + let status = response.status().as_u16(); - let status = response.status().as_u16(); + let mut body = response + .text() + .await + .map_err(|e| crate::errors::Error::HttpError(e.into()))?; - let mut body = response - .text() - .await - .map_err(|e| crate::errors::Error::HttpError(e.into()))?; + if body.is_empty() { + body = "null".to_string(); + } - if body.is_empty() { - body = "null".to_string(); + parse_response(status, expected_status_code, &body, url.to_string()) + // parse_response(status, expected_status_code, body) } - - parse_response(status, expected_status_code, &body, url.to_string()) } #[cfg(target_arch = "wasm32")] -pub fn add_query_parameters( - mut url: String, - query: &Query, -) -> Result { - let query = yaup::to_string(query)?; - - if !query.is_empty() { - url = format!("{}?{}", url, query); - }; - return Ok(url); -} -#[cfg(target_arch = "wasm32")] -pub(crate) async fn request< - Query: Serialize, - Body: Serialize, - Output: DeserializeOwned + 'static, ->( - url: &str, - apikey: Option<&str>, - method: Method, - expected_status_code: u16, -) -> Result { - use wasm_bindgen::JsValue; - use wasm_bindgen_futures::JsFuture; - use web_sys::{Headers, RequestInit, Response}; - - const CONTENT_TYPE: &str = "Content-Type"; - const JSON: &str = "application/json"; - - // The 2 following unwraps should not be able to fail - let mut mut_url = url.to_string(); - let headers = Headers::new().unwrap(); - if let Some(apikey) = apikey { +#[async_trait(?Send)] +impl HttpClient for WebSysClient { + async fn request( + self, + url: &str, + apikey: Option<&str>, + method: Method, + expected_status_code: u16, + ) -> Result + where + Query: Serialize + Send + Sync, + Body: Serialize + Send + Sync, + Output: DeserializeOwned + 'static, + { + use serde_json::to_string; + use wasm_bindgen::JsValue; + use wasm_bindgen_futures::JsFuture; + use web_sys::{Headers, RequestInit, Response}; + + const CONTENT_TYPE: &str = "Content-Type"; + const JSON: &str = "application/json"; + + // The 2 following unwraps should not be able to fail + let mut mut_url = url.clone().to_string(); + let headers = Headers::new().unwrap(); + if let Some(apikey) = apikey { + headers + .append("Authorization", format!("Bearer {}", apikey).as_str()) + .unwrap(); + } headers - .append("Authorization", format!("Bearer {}", apikey).as_str()) + .append("X-Meilisearch-Client", qualified_version().as_str()) .unwrap(); - } - headers - .append("X-Meilisearch-Client", qualified_version().as_str()) - .unwrap(); - let mut request: RequestInit = RequestInit::new(); - request.headers(&headers); + let mut request: RequestInit = RequestInit::new(); + request.headers(&headers); - match &method { - Method::Get { query } => { - mut_url = add_query_parameters(mut_url, &query)?; + match &method { + Method::Get { query } => { + mut_url = add_query_parameters(mut_url, &query)?; - request.method("GET"); - } - Method::Delete { query } => { - mut_url = add_query_parameters(mut_url, &query)?; - request.method("DELETE"); - } - Method::Patch { query, body } => { - mut_url = add_query_parameters(mut_url, &query)?; - request.method("PATCH"); - headers.append(CONTENT_TYPE, JSON).unwrap(); - request.body(Some(&JsValue::from_str(&to_string(body).unwrap()))); - } - Method::Post { query, body } => { - mut_url = add_query_parameters(mut_url, &query)?; - request.method("POST"); - headers.append(CONTENT_TYPE, JSON).unwrap(); - request.body(Some(&JsValue::from_str(&to_string(body).unwrap()))); - } - Method::Put { query, body } => { - mut_url = add_query_parameters(mut_url, &query)?; - request.method("PUT"); - headers.append(CONTENT_TYPE, JSON).unwrap(); - request.body(Some(&JsValue::from_str(&to_string(body).unwrap()))); + request.method("GET"); + } + Method::Delete { query } => { + mut_url = add_query_parameters(mut_url, &query)?; + request.method("DELETE"); + } + Method::Patch { query, body } => { + mut_url = add_query_parameters(mut_url, &query)?; + request.method("PATCH"); + headers.append(CONTENT_TYPE, JSON).unwrap(); + request.body(Some(&JsValue::from_str(&to_string(body).unwrap()))); + } + Method::Post { query, body } => { + mut_url = add_query_parameters(mut_url, &query)?; + request.method("POST"); + headers.append(CONTENT_TYPE, JSON).unwrap(); + request.body(Some(&JsValue::from_str(&to_string(body).unwrap()))); + } + Method::Put { query, body } => { + mut_url = add_query_parameters(mut_url, &query)?; + request.method("PUT"); + headers.append(CONTENT_TYPE, JSON).unwrap(); + request.body(Some(&JsValue::from_str(&to_string(body).unwrap()))); + } } - } - let window = web_sys::window().unwrap(); // TODO remove this unwrap - let response = - match JsFuture::from(window.fetch_with_str_and_init(mut_url.as_str(), &request)).await { + let window = web_sys::window().unwrap(); // TODO remove this unwrap + let response = match JsFuture::from( + window.fetch_with_str_and_init(mut_url.as_str(), &request), + ) + .await + { Ok(response) => Response::from(response), Err(e) => { error!("Network error: {:?}", e); return Err(Error::UnreachableServer); } }; - let status = response.status() as u16; - let text = match response.text() { - Ok(text) => match JsFuture::from(text).await { - Ok(text) => text, + let status = response.status() as u16; + let text = match response.text() { + Ok(text) => match JsFuture::from(text).await { + Ok(text) => text, + Err(e) => { + error!("Invalid response: {:?}", e); + return Err(Error::HttpError("Invalid response".to_string())); + } + }, Err(e) => { error!("Invalid response: {:?}", e); return Err(Error::HttpError("Invalid response".to_string())); } - }, - Err(e) => { - error!("Invalid response: {:?}", e); - return Err(Error::HttpError("Invalid response".to_string())); - } - }; + }; - if let Some(t) = text.as_string() { - if t.is_empty() { - parse_response(status, expected_status_code, "null", url.to_string()) + if let Some(t) = text.as_string() { + if t.is_empty() { + parse_response(status, expected_status_code, "null", url.to_string()) + } else { + parse_response(status, expected_status_code, &t, url.to_string()) + } } else { - parse_response(status, expected_status_code, &t, url.to_string()) + error!("Invalid response"); + Err(Error::HttpError("Invalid utf8".to_string())) } + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn add_query_parameters(url: &str, query: &Query) -> Result { + let query = yaup::to_string(query)?; + + if query.is_empty() { + Ok(url.to_string()) } else { - error!("Invalid response"); - Err(Error::HttpError("Invalid utf8".to_string())) + Ok(format!("{url}?{query}")) } } -fn parse_response( +#[cfg(target_arch = "wasm32")] +pub fn add_query_parameters( + mut url: String, + query: &Query, +) -> Result { + let query = yaup::to_string(query)?; + + if !query.is_empty() { + url = format!("{}?{}", url, query); + }; + return Ok(url); +} + +pub fn parse_response( status_code: u16, expected_status_code: u16, body: &str, @@ -375,3 +449,38 @@ pub fn qualified_version() -> String { format!("Meilisearch Rust (v{})", VERSION.unwrap_or("unknown")) } + +#[async_trait(?Send)] +impl HttpClient for Infallible { + async fn request( + self, + _url: &str, + _apikey: Option<&str>, + _method: Method, + _expected_status_code: u16, + ) -> Result + where + Query: Serialize + Send + Sync, + Body: Serialize + Send + Sync, + Output: DeserializeOwned + 'static + Send, + { + unreachable!() + } + + #[cfg(not(target_arch = "wasm32"))] + async fn stream_request< + 'a, + Query: Serialize + Send + Sync, + Body: futures_io::AsyncRead + Send + Sync + 'static, + Output: DeserializeOwned + 'static, + >( + self, + _url: &str, + _apikey: Option<&str>, + _method: Method, + _content_type: &str, + _expected_status_code: u16, + ) -> Result { + unreachable!() + } +} diff --git a/src/search.rs b/src/search.rs index 560f71d2..f8982f28 100644 --- a/src/search.rs +++ b/src/search.rs @@ -1,6 +1,8 @@ -use crate::{Client, Error, Index}; +use crate::{ + client::Client, errors::Error, indexes::Index, request::HttpClient, DefaultHttpClient, +}; use either::Either; -use serde::{de::DeserializeOwned, Deserialize, Serialize, Serializer}; +use serde::{de::DeserializeOwned, ser::SerializeStruct, Deserialize, Serialize, Serializer}; use serde_json::{Map, Value}; use std::collections::HashMap; @@ -57,6 +59,7 @@ pub struct FacetStats { pub min: f64, pub max: f64, } + #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] /// A struct containing search results and other information about the search. @@ -147,7 +150,7 @@ type AttributeToCrop<'a> = (&'a str, Option); /// /// ``` /// # use serde::{Serialize, Deserialize}; -/// # use meilisearch_sdk::{Client, SearchQuery, Index}; +/// # use meilisearch_sdk::{client::Client, search::*, indexes::Index}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -182,7 +185,7 @@ type AttributeToCrop<'a> = (&'a str, Option); /// ``` /// /// ``` -/// # use meilisearch_sdk::{Client, SearchQuery, Index}; +/// # use meilisearch_sdk::{client::Client, search::*, indexes::Index}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -197,9 +200,9 @@ type AttributeToCrop<'a> = (&'a str, Option); /// ``` #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] -pub struct SearchQuery<'a> { +pub struct SearchQuery<'a, Http: HttpClient> { #[serde(skip_serializing)] - index: &'a Index, + index: &'a Index, /// The text that will be searched for among the documents. #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "q")] @@ -328,9 +331,9 @@ pub struct SearchQuery<'a> { } #[allow(missing_docs)] -impl<'a> SearchQuery<'a> { +impl<'a, Http: HttpClient> SearchQuery<'a, Http> { #[must_use] - pub fn new(index: &'a Index) -> SearchQuery<'a> { + pub fn new(index: &'a Index) -> SearchQuery<'a, Http> { SearchQuery { index, query: None, @@ -355,16 +358,16 @@ impl<'a> SearchQuery<'a> { index_uid: None, } } - pub fn with_query<'b>(&'b mut self, query: &'a str) -> &'b mut SearchQuery<'a> { + pub fn with_query<'b>(&'b mut self, query: &'a str) -> &'b mut SearchQuery<'a, Http> { self.query = Some(query); self } - pub fn with_offset<'b>(&'b mut self, offset: usize) -> &'b mut SearchQuery<'a> { + pub fn with_offset<'b>(&'b mut self, offset: usize) -> &'b mut SearchQuery<'a, Http> { self.offset = Some(offset); self } - pub fn with_limit<'b>(&'b mut self, limit: usize) -> &'b mut SearchQuery<'a> { + pub fn with_limit<'b>(&'b mut self, limit: usize) -> &'b mut SearchQuery<'a, Http> { self.limit = Some(limit); self } @@ -395,7 +398,7 @@ impl<'a> SearchQuery<'a> { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub fn with_page<'b>(&'b mut self, page: usize) -> &'b mut SearchQuery<'a> { + pub fn with_page<'b>(&'b mut self, page: usize) -> &'b mut SearchQuery<'a, Http> { self.page = Some(page); self } @@ -427,128 +430,151 @@ impl<'a> SearchQuery<'a> { /// # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub fn with_hits_per_page<'b>(&'b mut self, hits_per_page: usize) -> &'b mut SearchQuery<'a> { + pub fn with_hits_per_page<'b>( + &'b mut self, + hits_per_page: usize, + ) -> &'b mut SearchQuery<'a, Http> { self.hits_per_page = Some(hits_per_page); self } - pub fn with_filter<'b>(&'b mut self, filter: &'a str) -> &'b mut SearchQuery<'a> { + pub fn with_filter<'b>(&'b mut self, filter: &'a str) -> &'b mut SearchQuery<'a, Http> { self.filter = Some(Filter::new(Either::Left(filter))); self } - pub fn with_array_filter<'b>(&'b mut self, filter: Vec<&'a str>) -> &'b mut SearchQuery<'a> { + pub fn with_array_filter<'b>( + &'b mut self, + filter: Vec<&'a str>, + ) -> &'b mut SearchQuery<'a, Http> { self.filter = Some(Filter::new(Either::Right(filter))); self } pub fn with_facets<'b>( &'b mut self, facets: Selectors<&'a [&'a str]>, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.facets = Some(facets); self } - pub fn with_sort<'b>(&'b mut self, sort: &'a [&'a str]) -> &'b mut SearchQuery<'a> { + pub fn with_sort<'b>(&'b mut self, sort: &'a [&'a str]) -> &'b mut SearchQuery<'a, Http> { self.sort = Some(sort); self } + pub fn with_attributes_to_search_on<'b>( &'b mut self, attributes_to_search_on: &'a [&'a str], - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.attributes_to_search_on = Some(attributes_to_search_on); self } pub fn with_attributes_to_retrieve<'b>( &'b mut self, attributes_to_retrieve: Selectors<&'a [&'a str]>, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.attributes_to_retrieve = Some(attributes_to_retrieve); self } pub fn with_attributes_to_crop<'b>( &'b mut self, attributes_to_crop: Selectors<&'a [(&'a str, Option)]>, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.attributes_to_crop = Some(attributes_to_crop); self } - pub fn with_crop_length<'b>(&'b mut self, crop_length: usize) -> &'b mut SearchQuery<'a> { + pub fn with_crop_length<'b>(&'b mut self, crop_length: usize) -> &'b mut SearchQuery<'a, Http> { self.crop_length = Some(crop_length); self } - pub fn with_crop_marker<'b>(&'b mut self, crop_marker: &'a str) -> &'b mut SearchQuery<'a> { + pub fn with_crop_marker<'b>( + &'b mut self, + crop_marker: &'a str, + ) -> &'b mut SearchQuery<'a, Http> { self.crop_marker = Some(crop_marker); self } pub fn with_attributes_to_highlight<'b>( &'b mut self, attributes_to_highlight: Selectors<&'a [&'a str]>, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.attributes_to_highlight = Some(attributes_to_highlight); self } pub fn with_highlight_pre_tag<'b>( &'b mut self, highlight_pre_tag: &'a str, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.highlight_pre_tag = Some(highlight_pre_tag); self } pub fn with_highlight_post_tag<'b>( &'b mut self, highlight_post_tag: &'a str, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.highlight_post_tag = Some(highlight_post_tag); self } pub fn with_show_matches_position<'b>( &'b mut self, show_matches_position: bool, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.show_matches_position = Some(show_matches_position); self } + pub fn with_show_ranking_score<'b>( &'b mut self, show_ranking_score: bool, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.show_ranking_score = Some(show_ranking_score); self } pub fn with_matching_strategy<'b>( &'b mut self, matching_strategy: MatchingStrategies, - ) -> &'b mut SearchQuery<'a> { + ) -> &'b mut SearchQuery<'a, Http> { self.matching_strategy = Some(matching_strategy); self } - pub fn with_index_uid<'b>(&'b mut self) -> &'b mut SearchQuery<'a> { + pub fn with_index_uid<'b>(&'b mut self) -> &'b mut SearchQuery<'a, Http> { self.index_uid = Some(&self.index.uid); self } - #[must_use] - pub fn build(&mut self) -> SearchQuery<'a> { + pub fn build(&mut self) -> SearchQuery<'a, Http> { self.clone() } /// Execute the query and fetch the results. - pub async fn execute( + pub async fn execute( &'a self, ) -> Result, Error> { self.index.execute_query::(self).await } } -#[derive(Debug, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct MultiSearchQuery<'a, 'b> { - #[serde(skip_serializing)] - client: &'a Client, - pub queries: Vec>, +// TODO: Make it works with the serde derive macro +// #[derive(Debug, Serialize, Clone)] +// #[serde(rename_all = "camelCase")] +#[derive(Debug, Clone)] +pub struct MultiSearchQuery<'a, 'b, Http: HttpClient = DefaultHttpClient> { + // #[serde(skip_serializing)] + client: &'a Client, + pub queries: Vec>, +} + +impl<'a, 'b, Http: HttpClient> Serialize for MultiSearchQuery<'a, 'b, Http> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut strukt = serializer.serialize_struct("MultiSearchQuery", 1)?; + strukt.serialize_field("queries", &self.queries)?; + strukt.end() + } } #[allow(missing_docs)] -impl<'a, 'b> MultiSearchQuery<'a, 'b> { +impl<'a, 'b, Http: HttpClient> MultiSearchQuery<'a, 'b, Http> { #[must_use] - pub fn new(client: &'a Client) -> MultiSearchQuery<'a, 'b> { + pub fn new(client: &'a Client) -> MultiSearchQuery<'a, 'b, Http> { MultiSearchQuery { client, queries: Vec::new(), @@ -556,15 +582,15 @@ impl<'a, 'b> MultiSearchQuery<'a, 'b> { } pub fn with_search_query( &mut self, - mut search_query: SearchQuery<'b>, - ) -> &mut MultiSearchQuery<'a, 'b> { + mut search_query: SearchQuery<'b, Http>, + ) -> &mut MultiSearchQuery<'a, 'b, Http> { search_query.with_index_uid(); self.queries.push(search_query); self } /// Execute the query and fetch the results. - pub async fn execute( + pub async fn execute( &'a self, ) -> Result, Error> { self.client.execute_multi_search_query::(self).await @@ -577,7 +603,11 @@ pub struct MultiSearchResponse { #[cfg(test)] mod tests { - use crate::{client::*, search::*}; + use crate::{ + client::*, + key::{Action, KeyBuilder}, + search::*, + }; use big_s::S; use meilisearch_test_macro::meilisearch_test; use serde::{Deserialize, Serialize}; @@ -598,6 +628,7 @@ mod tests { } impl PartialEq> for Document { + #[allow(clippy::cmp_owned)] fn eq(&self, rhs: &Map) -> bool { self.id.to_string() == rhs["id"] && self.value == rhs["value"] @@ -833,22 +864,6 @@ mod tests { Ok(()) } - #[meilisearch_test] - async fn test_query_facet_stats(client: Client, index: Index) -> Result<(), Error> { - setup_test_index(&client, &index).await?; - - let mut query = SearchQuery::new(&index); - query.with_facets(Selectors::All); - let results: SearchResults = index.execute_query(&query).await?; - let facet_stats = results.facet_stats.unwrap(); - - assert_eq!(facet_stats.get("number").unwrap().min, 0.0); - - assert_eq!(facet_stats.get("number").unwrap().max, 90.0); - - Ok(()) - } - #[meilisearch_test] async fn test_query_attributes_to_retrieve(client: Client, index: Index) -> Result<(), Error> { setup_test_index(&client, &index).await?; @@ -866,20 +881,6 @@ mod tests { Ok(()) } - #[meilisearch_test] - async fn test_query_attributes_to_search_on(client: Client, index: Index) -> Result<(), Error> { - setup_test_index(&client, &index).await?; - - let results: SearchResults = index - .search() - .with_query("title") - .with_attributes_to_search_on(&["kind"]) - .execute() - .await?; - assert_eq!(results.hits.len(), 8); - Ok(()) - } - #[meilisearch_test] async fn test_query_sort(client: Client, index: Index) -> Result<(), Error> { setup_test_index(&client, &index).await?; @@ -1136,8 +1137,6 @@ mod tests { client: Client, index: Index, ) -> Result<(), Error> { - use crate::{Action, KeyBuilder}; - setup_test_index(&client, &index).await?; let meilisearch_url = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); diff --git a/src/settings.rs b/src/settings.rs index 2296d150..25a2fa16 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,6 +1,8 @@ use crate::{ - request::{request, Method}, - Error, Index, TaskInfo, + errors::Error, + indexes::Index, + request::{HttpClient, Method}, + task_info::TaskInfo, }; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -41,7 +43,7 @@ pub struct FacetingSettings { /// # Example /// /// ``` -/// # use meilisearch_sdk::Settings; +/// # use meilisearch_sdk::settings::Settings; /// let settings = Settings::new() /// .with_stop_words(["a", "the", "of"]); /// @@ -286,7 +288,7 @@ impl Settings { } } -impl Index { +impl Index { /// Get [Settings] of the [Index]. /// /// # Example @@ -307,13 +309,16 @@ impl Index { /// # }); /// ``` pub async fn get_settings(&self) -> Result { - request::<(), (), Settings>( - &format!("{}/indexes/{}/settings", self.client.host, self.uid), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Settings>( + &format!("{}/indexes/{}/settings", self.client.host, self.uid), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [synonyms](https://www.meilisearch.com/docs/reference/api/settings#get-synonyms) of the [Index]. @@ -337,16 +342,19 @@ impl Index { /// # }); /// ``` pub async fn get_synonyms(&self) -> Result>, Error> { - request::<(), (), HashMap>>( - &format!( - "{}/indexes/{}/settings/synonyms", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), HashMap>>( + &format!( + "{}/indexes/{}/settings/synonyms", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [pagination](https://www.meilisearch.com/docs/reference/api/settings#pagination) of the [Index]. @@ -370,16 +378,19 @@ impl Index { /// # }); /// ``` pub async fn get_pagination(&self) -> Result { - request::<(), (), PaginationSetting>( - &format!( - "{}/indexes/{}/settings/pagination", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), PaginationSetting>( + &format!( + "{}/indexes/{}/settings/pagination", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [stop-words](https://www.meilisearch.com/docs/reference/api/settings#stop-words) of the [Index]. @@ -402,16 +413,19 @@ impl Index { /// # }); /// ``` pub async fn get_stop_words(&self) -> Result, Error> { - request::<(), (), Vec>( - &format!( - "{}/indexes/{}/settings/stop-words", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Vec>( + &format!( + "{}/indexes/{}/settings/stop-words", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [ranking rules](https://www.meilisearch.com/docs/reference/api/settings#ranking-rules) of the [Index]. @@ -435,16 +449,19 @@ impl Index { /// # }); /// ``` pub async fn get_ranking_rules(&self) -> Result, Error> { - request::<(), (), Vec>( - &format!( - "{}/indexes/{}/settings/ranking-rules", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Vec>( + &format!( + "{}/indexes/{}/settings/ranking-rules", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [filterable attributes](https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes) of the [Index]. @@ -468,16 +485,19 @@ impl Index { /// # }); /// ``` pub async fn get_filterable_attributes(&self) -> Result, Error> { - request::<(), (), Vec>( - &format!( - "{}/indexes/{}/settings/filterable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Vec>( + &format!( + "{}/indexes/{}/settings/filterable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [sortable attributes](https://www.meilisearch.com/docs/reference/api/settings#sortable-attributes) of the [Index]. @@ -501,16 +521,19 @@ impl Index { /// # }); /// ``` pub async fn get_sortable_attributes(&self) -> Result, Error> { - request::<(), (), Vec>( - &format!( - "{}/indexes/{}/settings/sortable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Vec>( + &format!( + "{}/indexes/{}/settings/sortable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get the [distinct attribute](https://www.meilisearch.com/docs/reference/api/settings#distinct-attribute) of the [Index]. @@ -534,16 +557,19 @@ impl Index { /// # }); /// ``` pub async fn get_distinct_attribute(&self) -> Result, Error> { - request::<(), (), Option>( - &format!( - "{}/indexes/{}/settings/distinct-attribute", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Option>( + &format!( + "{}/indexes/{}/settings/distinct-attribute", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [searchable attributes](https://www.meilisearch.com/docs/reference/api/settings#searchable-attributes) of the [Index]. @@ -567,16 +593,19 @@ impl Index { /// # }); /// ``` pub async fn get_searchable_attributes(&self) -> Result, Error> { - request::<(), (), Vec>( - &format!( - "{}/indexes/{}/settings/searchable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Vec>( + &format!( + "{}/indexes/{}/settings/searchable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [displayed attributes](https://www.meilisearch.com/docs/reference/api/settings#displayed-attributes) of the [Index]. @@ -600,16 +629,19 @@ impl Index { /// # }); /// ``` pub async fn get_displayed_attributes(&self) -> Result, Error> { - request::<(), (), Vec>( - &format!( - "{}/indexes/{}/settings/displayed-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Vec>( + &format!( + "{}/indexes/{}/settings/displayed-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [faceting](https://www.meilisearch.com/docs/reference/api/settings#faceting) settings of the [Index]. @@ -633,16 +665,19 @@ impl Index { /// # }); /// ``` pub async fn get_faceting(&self) -> Result { - request::<(), (), FacetingSettings>( - &format!( - "{}/indexes/{}/settings/faceting", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), FacetingSettings>( + &format!( + "{}/indexes/{}/settings/faceting", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [dictionary](https://www.meilisearch.com/docs/reference/api/settings#dictionary) of the [Index]. @@ -665,16 +700,19 @@ impl Index { /// # }); /// ``` pub async fn get_dictionary(&self) -> Result, Error> { - request::<(), (), Vec>( - &format!( - "{}/indexes/{}/settings/dictionary", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), Vec>( + &format!( + "{}/indexes/{}/settings/dictionary", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [proximity_precision](https://www.meilisearch.com/docs/reference/api/settings#proximity-precision) of the [Index]. @@ -697,16 +735,19 @@ impl Index { /// # }); /// ``` pub async fn get_proximity_precision(&self) -> Result { - request::<(), (), String>( - &format!( - "{}/indexes/{}/settings/proximity-precision", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), String>( + &format!( + "{}/indexes/{}/settings/proximity-precision", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Get [typo tolerance](https://www.meilisearch.com/docs/learn/configuration/typo_tolerance#typo-tolerance) of the [Index]. @@ -727,16 +768,19 @@ impl Index { /// # }); /// ``` pub async fn get_typo_tolerance(&self) -> Result { - request::<(), (), TypoToleranceSettings>( - &format!( - "{}/indexes/{}/settings/typo-tolerance", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Get { query: () }, - 200, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TypoToleranceSettings>( + &format!( + "{}/indexes/{}/settings/typo-tolerance", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Get { query: () }, + 200, + ) + .await } /// Update [settings](../settings/struct.Settings) of the [Index]. @@ -746,7 +790,7 @@ impl Index { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, Settings, PaginationSetting}; + /// # use meilisearch_sdk::{client::*, indexes::*, settings::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -767,16 +811,19 @@ impl Index { /// # }); /// ``` pub async fn set_settings(&self, settings: &Settings) -> Result { - request::<(), &Settings, TaskInfo>( - &format!("{}/indexes/{}/settings", self.client.host, self.uid), - self.client.get_api_key(), - Method::Patch { - query: (), - body: settings, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &Settings, TaskInfo>( + &format!("{}/indexes/{}/settings", self.client.host, self.uid), + self.client.get_api_key(), + Method::Patch { + query: (), + body: settings, + }, + 202, + ) + .await } /// Update [synonyms](https://www.meilisearch.com/docs/reference/api/settings#synonyms) of the [Index]. @@ -784,7 +831,7 @@ impl Index { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, Settings}; + /// # use meilisearch_sdk::{client::*, indexes::*, settings::Settings}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -807,19 +854,22 @@ impl Index { &self, synonyms: &HashMap>, ) -> Result { - request::<(), &HashMap>, TaskInfo>( - &format!( - "{}/indexes/{}/settings/synonyms", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: synonyms, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &HashMap>, TaskInfo>( + &format!( + "{}/indexes/{}/settings/synonyms", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: synonyms, + }, + 202, + ) + .await } /// Update [pagination](https://www.meilisearch.com/docs/reference/api/settings#pagination) of the [Index]. @@ -827,7 +877,7 @@ impl Index { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, Settings, PaginationSetting}; + /// # use meilisearch_sdk::{client::*, indexes::*, settings::*}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -843,19 +893,22 @@ impl Index { /// # }); /// ``` pub async fn set_pagination(&self, pagination: PaginationSetting) -> Result { - request::<(), &PaginationSetting, TaskInfo>( - &format!( - "{}/indexes/{}/settings/pagination", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Patch { - query: (), - body: &pagination, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &PaginationSetting, TaskInfo>( + &format!( + "{}/indexes/{}/settings/pagination", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Patch { + query: (), + body: &pagination, + }, + 202, + ) + .await } /// Update [stop-words](https://www.meilisearch.com/docs/reference/api/settings#stop-words) of the [Index]. @@ -863,7 +916,7 @@ impl Index { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, Settings}; + /// # use meilisearch_sdk::{client::*, indexes::*, settings::Settings}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -882,22 +935,25 @@ impl Index { &self, stop_words: impl IntoIterator>, ) -> Result { - request::<(), Vec, TaskInfo>( - &format!( - "{}/indexes/{}/settings/stop-words", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: stop_words - .into_iter() - .map(|v| v.as_ref().to_string()) - .collect(), - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), Vec, TaskInfo>( + &format!( + "{}/indexes/{}/settings/stop-words", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: stop_words + .into_iter() + .map(|v| v.as_ref().to_string()) + .collect(), + }, + 202, + ) + .await } /// Update [ranking rules](https://www.meilisearch.com/docs/reference/api/settings#ranking-rules) of the [Index]. @@ -933,22 +989,25 @@ impl Index { &self, ranking_rules: impl IntoIterator>, ) -> Result { - request::<(), Vec, TaskInfo>( - &format!( - "{}/indexes/{}/settings/ranking-rules", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: ranking_rules - .into_iter() - .map(|v| v.as_ref().to_string()) - .collect(), - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), Vec, TaskInfo>( + &format!( + "{}/indexes/{}/settings/ranking-rules", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: ranking_rules + .into_iter() + .map(|v| v.as_ref().to_string()) + .collect(), + }, + 202, + ) + .await } /// Update [filterable attributes](https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes) of the [Index]. @@ -975,22 +1034,25 @@ impl Index { &self, filterable_attributes: impl IntoIterator>, ) -> Result { - request::<(), Vec, TaskInfo>( - &format!( - "{}/indexes/{}/settings/filterable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: filterable_attributes - .into_iter() - .map(|v| v.as_ref().to_string()) - .collect(), - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), Vec, TaskInfo>( + &format!( + "{}/indexes/{}/settings/filterable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: filterable_attributes + .into_iter() + .map(|v| v.as_ref().to_string()) + .collect(), + }, + 202, + ) + .await } /// Update [sortable attributes](https://www.meilisearch.com/docs/reference/api/settings#sortable-attributes) of the [Index]. @@ -1017,22 +1079,25 @@ impl Index { &self, sortable_attributes: impl IntoIterator>, ) -> Result { - request::<(), Vec, TaskInfo>( - &format!( - "{}/indexes/{}/settings/sortable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: sortable_attributes - .into_iter() - .map(|v| v.as_ref().to_string()) - .collect(), - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), Vec, TaskInfo>( + &format!( + "{}/indexes/{}/settings/sortable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: sortable_attributes + .into_iter() + .map(|v| v.as_ref().to_string()) + .collect(), + }, + 202, + ) + .await } /// Update the [distinct attribute](https://www.meilisearch.com/docs/reference/api/settings#distinct-attribute) of the [Index]. @@ -1058,19 +1123,22 @@ impl Index { &self, distinct_attribute: impl AsRef, ) -> Result { - request::<(), String, TaskInfo>( - &format!( - "{}/indexes/{}/settings/distinct-attribute", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: distinct_attribute.as_ref().to_string(), - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), String, TaskInfo>( + &format!( + "{}/indexes/{}/settings/distinct-attribute", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: distinct_attribute.as_ref().to_string(), + }, + 202, + ) + .await } /// Update [searchable attributes](https://www.meilisearch.com/docs/reference/api/settings#searchable-attributes) of the [Index]. @@ -1096,22 +1164,25 @@ impl Index { &self, searchable_attributes: impl IntoIterator>, ) -> Result { - request::<(), Vec, TaskInfo>( - &format!( - "{}/indexes/{}/settings/searchable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: searchable_attributes - .into_iter() - .map(|v| v.as_ref().to_string()) - .collect(), - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), Vec, TaskInfo>( + &format!( + "{}/indexes/{}/settings/searchable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: searchable_attributes + .into_iter() + .map(|v| v.as_ref().to_string()) + .collect(), + }, + 202, + ) + .await } /// Update [displayed attributes](https://www.meilisearch.com/docs/reference/api/settings#displayed-attributes) of the [Index]. @@ -1137,22 +1208,25 @@ impl Index { &self, displayed_attributes: impl IntoIterator>, ) -> Result { - request::<(), Vec, TaskInfo>( - &format!( - "{}/indexes/{}/settings/displayed-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: displayed_attributes - .into_iter() - .map(|v| v.as_ref().to_string()) - .collect(), - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), Vec, TaskInfo>( + &format!( + "{}/indexes/{}/settings/displayed-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: displayed_attributes + .into_iter() + .map(|v| v.as_ref().to_string()) + .collect(), + }, + 202, + ) + .await } /// Update [faceting](https://www.meilisearch.com/docs/reference/api/settings#faceting) settings of the [Index]. @@ -1179,19 +1253,22 @@ impl Index { /// # }); /// ``` pub async fn set_faceting(&self, faceting: &FacetingSettings) -> Result { - request::<(), &FacetingSettings, TaskInfo>( - &format!( - "{}/indexes/{}/settings/faceting", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Patch { - query: (), - body: faceting, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &FacetingSettings, TaskInfo>( + &format!( + "{}/indexes/{}/settings/faceting", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Patch { + query: (), + body: faceting, + }, + 202, + ) + .await } /// Update [dictionary](https://www.meilisearch.com/docs/reference/api/settings#dictionary) of the [Index]. @@ -1217,22 +1294,25 @@ impl Index { &self, dictionary: impl IntoIterator>, ) -> Result { - request::<(), Vec, TaskInfo>( - &format!( - "{}/indexes/{}/settings/dictionary", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: dictionary - .into_iter() - .map(|v| v.as_ref().to_string()) - .collect(), - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), Vec, TaskInfo>( + &format!( + "{}/indexes/{}/settings/dictionary", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: dictionary + .into_iter() + .map(|v| v.as_ref().to_string()) + .collect(), + }, + 202, + ) + .await } /// Update [typo tolerance](https://www.meilisearch.com/docs/learn/configuration/typo_tolerance#typo-tolerance) settings of the [Index]. @@ -1265,19 +1345,22 @@ impl Index { &self, typo_tolerance: &TypoToleranceSettings, ) -> Result { - request::<(), &TypoToleranceSettings, TaskInfo>( - &format!( - "{}/indexes/{}/settings/typo-tolerance", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Patch { - query: (), - body: typo_tolerance, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), &TypoToleranceSettings, TaskInfo>( + &format!( + "{}/indexes/{}/settings/typo-tolerance", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Patch { + query: (), + body: typo_tolerance, + }, + 202, + ) + .await } /// Update [proximity-precision](https://www.meilisearch.com/docs/learn/configuration/proximity-precision) settings of the [Index]. @@ -1303,19 +1386,22 @@ impl Index { &self, proximity_precision: String, ) -> Result { - request::<(), String, TaskInfo>( - &format!( - "{}/indexes/{}/settings/proximity-precision", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Put { - query: (), - body: proximity_precision, - }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), String, TaskInfo>( + &format!( + "{}/indexes/{}/settings/proximity-precision", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Put { + query: (), + body: proximity_precision, + }, + 202, + ) + .await } /// Reset [Settings] of the [Index]. @@ -1340,13 +1426,16 @@ impl Index { /// # }); /// ``` pub async fn reset_settings(&self) -> Result { - request::<(), (), TaskInfo>( - &format!("{}/indexes/{}/settings", self.client.host, self.uid), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!("{}/indexes/{}/settings", self.client.host, self.uid), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [synonyms](https://www.meilisearch.com/docs/reference/api/settings#synonyms) of the [Index]. @@ -1369,16 +1458,19 @@ impl Index { /// # }); /// ``` pub async fn reset_synonyms(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/synonyms", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/synonyms", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [pagination](https://www.meilisearch.com/docs/learn/configuration/settings#pagination) of the [Index]. @@ -1401,16 +1493,19 @@ impl Index { /// # }); /// ``` pub async fn reset_pagination(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/pagination", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/pagination", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [stop-words](https://www.meilisearch.com/docs/reference/api/settings#stop-words) of the [Index]. /// @@ -1432,16 +1527,19 @@ impl Index { /// # }); /// ``` pub async fn reset_stop_words(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/stop-words", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/stop-words", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [ranking rules](https://www.meilisearch.com/docs/learn/core_concepts/relevancy#ranking-rules) of the [Index] to default value. @@ -1466,16 +1564,19 @@ impl Index { /// # }); /// ``` pub async fn reset_ranking_rules(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/ranking-rules", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/ranking-rules", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [filterable attributes](https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes) of the [Index]. @@ -1498,16 +1599,19 @@ impl Index { /// # }); /// ``` pub async fn reset_filterable_attributes(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/filterable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/filterable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [sortable attributes](https://www.meilisearch.com/docs/reference/api/settings#sortable-attributes) of the [Index]. @@ -1530,16 +1634,19 @@ impl Index { /// # }); /// ``` pub async fn reset_sortable_attributes(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/sortable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/sortable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset the [distinct attribute](https://www.meilisearch.com/docs/reference/api/settings#distinct-attribute) of the [Index]. @@ -1562,16 +1669,19 @@ impl Index { /// # }); /// ``` pub async fn reset_distinct_attribute(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/distinct-attribute", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/distinct-attribute", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [searchable attributes](https://www.meilisearch.com/docs/learn/configuration/displayed_searchable_attributes#searchable-fields) of @@ -1595,16 +1705,19 @@ impl Index { /// # }); /// ``` pub async fn reset_searchable_attributes(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/searchable-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/searchable-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [displayed attributes](https://www.meilisearch.com/docs/reference/api/settings#displayed-attributes) of the [Index] (enable all attributes). @@ -1627,16 +1740,19 @@ impl Index { /// # }); /// ``` pub async fn reset_displayed_attributes(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/displayed-attributes", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/displayed-attributes", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [faceting](https://www.meilisearch.com/docs/reference/api/settings#faceting) settings of the [Index]. @@ -1659,16 +1775,19 @@ impl Index { /// # }); /// ``` pub async fn reset_faceting(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/faceting", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/faceting", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [dictionary](https://www.meilisearch.com/docs/reference/api/settings#dictionary) of the [Index]. @@ -1691,16 +1810,19 @@ impl Index { /// # }); /// ``` pub async fn reset_dictionary(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/dictionary", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/dictionary", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [typo tolerance](https://www.meilisearch.com/docs/learn/configuration/typo_tolerance#typo-tolerance) settings of the [Index]. @@ -1723,16 +1845,19 @@ impl Index { /// # }); /// ``` pub async fn reset_typo_tolerance(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/typo-tolerance", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/typo-tolerance", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } /// Reset [proximity precision](https://www.meilisearch.com/docs/learn/configuration/typo_tolerance#typo-tolerance) settings of the [Index]. @@ -1755,16 +1880,19 @@ impl Index { /// # }); /// ``` pub async fn reset_proximity_precision(&self) -> Result { - request::<(), (), TaskInfo>( - &format!( - "{}/indexes/{}/settings/proximity-precision", - self.client.host, self.uid - ), - self.client.get_api_key(), - Method::Delete { query: () }, - 202, - ) - .await + self.client + .http_client + .clone() + .request::<(), (), TaskInfo>( + &format!( + "{}/indexes/{}/settings/proximity-precision", + self.client.host, self.uid + ), + self.client.get_api_key(), + Method::Delete { query: () }, + 202, + ) + .await } } diff --git a/src/task_info.rs b/src/task_info.rs index f34017f3..1e872c0d 100644 --- a/src/task_info.rs +++ b/src/task_info.rs @@ -2,7 +2,7 @@ use serde::Deserialize; use std::time::Duration; use time::OffsetDateTime; -use crate::{tasks::*, Client, Error}; +use crate::{client::Client, errors::Error, request::HttpClient, tasks::*}; #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] @@ -41,7 +41,7 @@ impl TaskInfo { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, Task, TaskInfo}; + /// # use meilisearch_sdk::{client::*, indexes::*, tasks::*}; /// # use serde::{Serialize, Deserialize}; /// # /// # #[derive(Debug, Serialize, Deserialize, PartialEq)] @@ -72,9 +72,9 @@ impl TaskInfo { /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn wait_for_completion( + pub async fn wait_for_completion( self, - client: &Client, + client: &Client, interval: Option, timeout: Option, ) -> Result { @@ -85,7 +85,11 @@ impl TaskInfo { #[cfg(test)] mod test { use super::*; - use crate::{client::*, ErrorCode, ErrorType, Index}; + use crate::{ + client::*, + errors::{ErrorCode, ErrorType}, + indexes::Index, + }; use big_s::S; use meilisearch_test_macro::meilisearch_test; use serde::{Deserialize, Serialize}; diff --git a/src/tasks.rs b/src/tasks.rs index 7dbfb926..c9299e0b 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -2,7 +2,10 @@ use serde::{Deserialize, Deserializer, Serialize}; use std::time::Duration; use time::OffsetDateTime; -use crate::{Client, Error, Index, MeilisearchError, Settings, SwapIndexes, TaskInfo}; +use crate::{ + client::Client, client::SwapIndexes, errors::Error, errors::MeilisearchError, indexes::Index, + request::HttpClient, settings::Settings, task_info::TaskInfo, +}; #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase", tag = "type")] @@ -246,7 +249,7 @@ impl Task { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, Task}; + /// # use meilisearch_sdk::{client::*, indexes::*, tasks::Task}; /// # use serde::{Serialize, Deserialize}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); @@ -278,9 +281,9 @@ impl Task { /// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap(); /// # }); /// ``` - pub async fn wait_for_completion( + pub async fn wait_for_completion( self, - client: &Client, + client: &Client, interval: Option, timeout: Option, ) -> Result { @@ -311,7 +314,10 @@ impl Task { /// # }); /// ``` #[allow(clippy::result_large_err)] // Since `self` has been consumed, this is not an issue - pub fn try_make_index(self, client: &Client) -> Result { + pub fn try_make_index( + self, + client: &Client, + ) -> Result, Self> { match self { Self::Succeeded { content: @@ -332,7 +338,7 @@ impl Task { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, ErrorCode}; + /// # use meilisearch_sdk::{client::*, indexes::*, errors::ErrorCode}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -371,7 +377,7 @@ impl Task { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, ErrorCode}; + /// # use meilisearch_sdk::{client::*, indexes::*, errors::ErrorCode}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -402,7 +408,7 @@ impl Task { /// # Example /// /// ``` - /// # use meilisearch_sdk::{client::*, indexes::*, ErrorCode}; + /// # use meilisearch_sdk::{client::*, indexes::*, errors::ErrorCode}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -432,7 +438,7 @@ impl Task { /// ```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::*, ErrorCode}; + /// # use meilisearch_sdk::{client::*, indexes::*, errors::ErrorCode}; /// # /// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700"); /// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey"); @@ -482,15 +488,15 @@ pub struct TasksCancelFilters {} #[derive(Debug, Serialize, Clone)] pub struct TasksDeleteFilters {} -pub type TasksSearchQuery<'a> = TasksQuery<'a, TasksPaginationFilters>; -pub type TasksCancelQuery<'a> = TasksQuery<'a, TasksCancelFilters>; -pub type TasksDeleteQuery<'a> = TasksQuery<'a, TasksDeleteFilters>; +pub type TasksSearchQuery<'a, Http> = TasksQuery<'a, TasksPaginationFilters, Http>; +pub type TasksCancelQuery<'a, Http> = TasksQuery<'a, TasksCancelFilters, Http>; +pub type TasksDeleteQuery<'a, Http> = TasksQuery<'a, TasksDeleteFilters, Http>; #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] -pub struct TasksQuery<'a, T> { +pub struct TasksQuery<'a, T, Http: HttpClient> { #[serde(skip_serializing)] - client: &'a Client, + client: &'a Client, // Index uids array to only retrieve the tasks of the indexes. #[serde(skip_serializing_if = "Option::is_none")] index_uids: Option>, @@ -548,89 +554,89 @@ pub struct TasksQuery<'a, T> { } #[allow(missing_docs)] -impl<'a, T> TasksQuery<'a, T> { +impl<'a, T, Http: HttpClient> TasksQuery<'a, T, Http> { pub fn with_index_uids<'b>( &'b mut self, index_uids: impl IntoIterator, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.index_uids = Some(index_uids.into_iter().collect()); self } pub fn with_statuses<'b>( &'b mut self, statuses: impl IntoIterator, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.statuses = Some(statuses.into_iter().collect()); self } pub fn with_types<'b>( &'b mut self, task_types: impl IntoIterator, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.task_types = Some(task_types.into_iter().collect()); self } pub fn with_uids<'b>( &'b mut self, uids: impl IntoIterator, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.uids = Some(uids.into_iter().collect()); self } pub fn with_before_enqueued_at<'b>( &'b mut self, before_enqueued_at: &'a OffsetDateTime, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.before_enqueued_at = Some(*before_enqueued_at); self } pub fn with_after_enqueued_at<'b>( &'b mut self, after_enqueued_at: &'a OffsetDateTime, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.after_enqueued_at = Some(*after_enqueued_at); self } pub fn with_before_started_at<'b>( &'b mut self, before_started_at: &'a OffsetDateTime, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.before_started_at = Some(*before_started_at); self } pub fn with_after_started_at<'b>( &'b mut self, after_started_at: &'a OffsetDateTime, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.after_started_at = Some(*after_started_at); self } pub fn with_before_finished_at<'b>( &'b mut self, before_finished_at: &'a OffsetDateTime, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.before_finished_at = Some(*before_finished_at); self } pub fn with_after_finished_at<'b>( &'b mut self, after_finished_at: &'a OffsetDateTime, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.after_finished_at = Some(*after_finished_at); self } pub fn with_canceled_by<'b>( &'b mut self, task_uids: impl IntoIterator, - ) -> &'b mut TasksQuery<'a, T> { + ) -> &'b mut TasksQuery<'a, T, Http> { self.canceled_by = Some(task_uids.into_iter().collect()); self } } -impl<'a> TasksQuery<'a, TasksCancelFilters> { +impl<'a, Http: HttpClient> TasksQuery<'a, TasksCancelFilters, Http> { #[must_use] - pub fn new(client: &'a Client) -> TasksQuery<'a, TasksCancelFilters> { + pub fn new(client: &'a Client) -> TasksQuery<'a, TasksCancelFilters, Http> { TasksQuery { client, index_uids: None, @@ -653,9 +659,9 @@ impl<'a> TasksQuery<'a, TasksCancelFilters> { } } -impl<'a> TasksQuery<'a, TasksDeleteFilters> { +impl<'a, Http: HttpClient> TasksQuery<'a, TasksDeleteFilters, Http> { #[must_use] - pub fn new(client: &'a Client) -> TasksQuery<'a, TasksDeleteFilters> { + pub fn new(client: &'a Client) -> TasksQuery<'a, TasksDeleteFilters, Http> { TasksQuery { client, index_uids: None, @@ -678,9 +684,9 @@ impl<'a> TasksQuery<'a, TasksDeleteFilters> { } } -impl<'a> TasksQuery<'a, TasksPaginationFilters> { +impl<'a, Http: HttpClient> TasksQuery<'a, TasksPaginationFilters, Http> { #[must_use] - pub fn new(client: &'a Client) -> TasksQuery<'a, TasksPaginationFilters> { + pub fn new(client: &'a Client) -> TasksQuery<'a, TasksPaginationFilters, Http> { TasksQuery { client, index_uids: None, @@ -703,14 +709,14 @@ impl<'a> TasksQuery<'a, TasksPaginationFilters> { pub fn with_limit<'b>( &'b mut self, limit: u32, - ) -> &'b mut TasksQuery<'a, TasksPaginationFilters> { + ) -> &'b mut TasksQuery<'a, TasksPaginationFilters, Http> { self.pagination.limit = Some(limit); self } pub fn with_from<'b>( &'b mut self, from: u32, - ) -> &'b mut TasksQuery<'a, TasksPaginationFilters> { + ) -> &'b mut TasksQuery<'a, TasksPaginationFilters, Http> { self.pagination.from = Some(from); self } @@ -722,7 +728,10 @@ impl<'a> TasksQuery<'a, TasksPaginationFilters> { #[cfg(test)] mod test { use super::*; - use crate::{client::*, ErrorCode, ErrorType}; + use crate::{ + client::*, + errors::{ErrorCode, ErrorType}, + }; use big_s::S; use meilisearch_test_macro::meilisearch_test; use serde::{Deserialize, Serialize}; diff --git a/src/tenant_tokens.rs b/src/tenant_tokens.rs index 19dfa63d..80d12a23 100644 --- a/src/tenant_tokens.rs +++ b/src/tenant_tokens.rs @@ -1,4 +1,4 @@ -use crate::Error; +use crate::errors::Error; use jsonwebtoken::{encode, EncodingKey, Header}; use serde::{Deserialize, Serialize}; use serde_json::Value;