meilisearch_sdk/lib.rs
1//! # 🚀 Getting started
2//!
3//! ### Add Documents <!-- omit in TOC -->
4//!
5//! ```
6//! use meilisearch_sdk::client::*;
7//! use serde::{Serialize, Deserialize};
8//! use futures::executor::block_on;
9//!
10//! #[derive(Serialize, Deserialize, Debug)]
11//! struct Movie {
12//! id: usize,
13//! title: String,
14//! genres: Vec<String>,
15//! }
16//!
17//!
18//! #[tokio::main(flavor = "current_thread")]
19//! async fn main() {
20//! # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
21//! # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
22//! // Create a client (without sending any request so that can't fail)
23//! let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
24//!
25//! # let index = client.create_index("movies", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap();
26//! // An index is where the documents are stored.
27//! let movies = client.index("movies");
28//!
29//! // Add some movies in the index. If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
30//! movies.add_documents(&[
31//! Movie { id: 1, title: String::from("Carol"), genres: vec!["Romance".to_string(), "Drama".to_string()] },
32//! Movie { id: 2, title: String::from("Wonder Woman"), genres: vec!["Action".to_string(), "Adventure".to_string()] },
33//! Movie { id: 3, title: String::from("Life of Pi"), genres: vec!["Adventure".to_string(), "Drama".to_string()] },
34//! Movie { id: 4, title: String::from("Mad Max"), genres: vec!["Adventure".to_string(), "Science Fiction".to_string()] },
35//! Movie { id: 5, title: String::from("Moana"), genres: vec!["Fantasy".to_string(), "Action".to_string()] },
36//! Movie { id: 6, title: String::from("Philadelphia"), genres: vec!["Drama".to_string()] },
37//! ], Some("id")).await.unwrap();
38//! # index.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
39//! }
40//! ```
41//!
42//! With the `uid`, you can check the status (`enqueued`, `canceled`, `processing`, `succeeded` or `failed`) of your documents addition using the [task](https://www.meilisearch.com/docs/reference/api/tasks#get-task).
43//!
44//! ### Basic Search <!-- omit in TOC -->
45//!
46//! ```
47//! # use meilisearch_sdk::client::*;
48//! # use serde::{Serialize, Deserialize};
49//! # #[derive(Serialize, Deserialize, Debug)]
50//! # struct Movie {
51//! # id: usize,
52//! # title: String,
53//! # genres: Vec<String>,
54//! # }
55//! # fn main() { tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {
56//! # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
57//! # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
58//! # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
59//! # let movies = client.create_index("movies_2", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap();
60//! // Meilisearch is typo-tolerant:
61//! println!("{:?}", client.index("movies_2").search().with_query("caorl").execute::<Movie>().await.unwrap().hits);
62//! # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
63//! # })}
64//! ```
65//!
66//! Output:
67//! ```text
68//! [Movie { id: 1, title: String::from("Carol"), genres: vec!["Romance", "Drama"] }]
69//! ```
70//!
71//! Json output:
72//! ```json
73//! {
74//! "hits": [{
75//! "id": 1,
76//! "title": "Carol",
77//! "genres": ["Romance", "Drama"]
78//! }],
79//! "offset": 0,
80//! "limit": 10,
81//! "processingTimeMs": 1,
82//! "query": "caorl"
83//! }
84//! ```
85//!
86//! ### Custom Search <!-- omit in toc -->
87//!
88//! ```
89//! # use meilisearch_sdk::{client::*, search::*};
90//! # use serde::{Serialize, Deserialize};
91//! # #[derive(Serialize, Deserialize, Debug)]
92//! # struct Movie {
93//! # id: usize,
94//! # title: String,
95//! # genres: Vec<String>,
96//! # }
97//! # fn main() { tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {
98//! # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
99//! # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
100//! # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
101//! # let movies = client.create_index("movies_3", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap();
102//! let search_result = client.index("movies_3")
103//! .search()
104//! .with_query("phil")
105//! .with_attributes_to_highlight(Selectors::Some(&["*"]))
106//! .execute::<Movie>()
107//! .await
108//! .unwrap();
109//! println!("{:?}", search_result.hits);
110//! # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
111//! # })}
112//! ```
113//!
114//! Json output:
115//! ```json
116//! {
117//! "hits": [
118//! {
119//! "id": 6,
120//! "title": "Philadelphia",
121//! "_formatted": {
122//! "id": 6,
123//! "title": "<em>Phil</em>adelphia",
124//! "genre": ["Drama"]
125//! }
126//! }
127//! ],
128//! "offset": 0,
129//! "limit": 20,
130//! "processingTimeMs": 0,
131//! "query": "phil"
132//! }
133//! ```
134//!
135//! ### Custom Search With Filters <!-- omit in TOC -->
136//!
137//! If you want to enable filtering, you must add your attributes to the `filterableAttributes`
138//! index setting.
139//!
140//! ```
141//! # use meilisearch_sdk::{client::*};
142//! # use serde::{Serialize, Deserialize};
143//! # fn main() { tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {
144//! # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
145//! # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
146//! # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
147//! # let movies = client.create_index("movies_4", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap();
148//! let filterable_attributes = [
149//! "id",
150//! "genres",
151//! ];
152//! client.index("movies_4").set_filterable_attributes(&filterable_attributes).await.unwrap();
153//! # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
154//! # })}
155//! ```
156//!
157//! You only need to perform this operation once.
158//!
159//! Note that Meilisearch will rebuild your index whenever you update `filterableAttributes`. Depending on the size of your dataset, this might take time. You can track the process using the [tasks](https://www.meilisearch.com/docs/reference/api/tasks#get-task).
160//!
161//! Then, you can perform the search:
162//!
163//! ```
164//! # use meilisearch_sdk::{client::*, search::*};
165//! # use serde::{Serialize, Deserialize};
166//! # #[derive(Serialize, Deserialize, Debug)]
167//! # struct Movie {
168//! # id: usize,
169//! # title: String,
170//! # genres: Vec<String>,
171//! # }
172//! # fn main() { tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {
173//! # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
174//! # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
175//! # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
176//! # let movies = client.create_index("movies_5", None).await.unwrap().wait_for_completion(&client, None, None).await.unwrap().try_make_index(&client).unwrap();
177//! # let filterable_attributes = [
178//! # "id",
179//! # "genres"
180//! # ];
181//! # movies.set_filterable_attributes(&filterable_attributes).await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
182//! # movies.add_documents(&[
183//! # Movie { id: 1, title: String::from("Carol"), genres: vec!["Romance".to_string(), "Drama".to_string()] },
184//! # Movie { id: 2, title: String::from("Wonder Woman"), genres: vec!["Action".to_string(), "Adventure".to_string()] },
185//! # Movie { id: 3, title: String::from("Life of Pi"), genres: vec!["Adventure".to_string(), "Drama".to_string()] },
186//! # Movie { id: 4, title: String::from("Mad Max"), genres: vec!["Adventure".to_string(), "Science Fiction".to_string()] },
187//! # Movie { id: 5, title: String::from("Moana"), genres: vec!["Fantasy".to_string(), "Action".to_string()] },
188//! # Movie { id: 6, title: String::from("Philadelphia"), genres: vec!["Drama".to_string()] },
189//! # ], Some("id")).await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
190//! let search_result = client.index("movies_5")
191//! .search()
192//! .with_query("wonder")
193//! .with_filter("id > 1 AND genres = Action")
194//! .execute::<Movie>()
195//! .await
196//! .unwrap();
197//! println!("{:?}", search_result.hits);
198//! # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
199//! # })}
200//! ```
201//!
202//! Json output:
203//! ```json
204//! {
205//! "hits": [
206//! {
207//! "id": 2,
208//! "title": "Wonder Woman",
209//! "genres": ["Action", "Adventure"]
210//! }
211//! ],
212//! "offset": 0,
213//! "limit": 20,
214//! "estimatedTotalHits": 1,
215//! "processingTimeMs": 0,
216//! "query": "wonder"
217//! }
218//! ```
219//!
220//! ### Customize the `HttpClient` <!-- omit in TOC -->
221//!
222//! By default, the SDK uses [`reqwest`](https://docs.rs/reqwest/latest/reqwest/) to make http calls.
223//! The SDK lets you customize the http client by implementing the `HttpClient` trait yourself and
224//! initializing the `Client` with the `new_with_client` method.
225//! You may be interested by the `futures-unsend` feature which lets you specify a non-Send http client.
226//!
227//! ### Wasm support <!-- omit in TOC -->
228//!
229//! The SDK supports wasm through reqwest. You'll need to enable the `futures-unsend` feature while importing it, though.
230#![warn(clippy::all)]
231#![allow(clippy::needless_doctest_main)]
232
233/// Module to interact with the Batches API.
234pub mod batches;
235/// Module containing the [`Client`](client::Client) struct.
236pub mod client;
237/// Module representing the [documents] structures.
238pub mod documents;
239/// Module containing the [dumps] trait.
240pub mod dumps;
241/// Module containing the [`errors::Error`] struct.
242pub mod errors;
243/// Module related to runtime and instance features.
244pub mod features;
245/// Module containing the Index struct.
246pub mod indexes;
247/// Module containing the [`Key`](key::Key) struct.
248pub mod key;
249/// Module for Network configuration API (sharding/remotes).
250pub mod network;
251pub mod request;
252/// Module related to search queries and results.
253pub mod search;
254/// Module containing [`Settings`](settings::Settings).
255pub mod settings;
256/// Module related to [similar queries](https://www.meilisearch.com/docs/learn/ai_powered_search/retrieve_related_search_results#return-similar-documents).
257pub mod similar;
258/// Module containing the [snapshots](snapshots::create_snapshot)-feature.
259pub mod snapshots;
260/// Module representing the [`TaskInfo`](task_info::TaskInfo)s.
261pub mod task_info;
262/// Module representing the [`Task`](tasks::Task)s.
263pub mod tasks;
264/// Module that generates tenant tokens.
265#[cfg(not(target_arch = "wasm32"))]
266mod tenant_tokens;
267/// Module containing utilizes functions.
268mod utils;
269/// Module to manage webhooks.
270pub mod webhooks;
271
272#[cfg(feature = "reqwest")]
273pub mod reqwest;
274
275#[cfg(feature = "reqwest")]
276pub type DefaultHttpClient = reqwest::ReqwestClient;
277
278#[cfg(not(feature = "reqwest"))]
279pub type DefaultHttpClient = std::convert::Infallible;
280
281#[cfg(test)]
282/// Support for the `IndexConfig` derive proc macro in the crate's tests.
283extern crate self as meilisearch_sdk;
284/// Can't assume that the user of proc_macro will have access to `async_trait` crate. So exporting the `async-trait` crate from `meilisearch_sdk` in a hidden module.
285#[doc(hidden)]
286pub mod macro_helper {
287 pub use async_trait::async_trait;
288}