Skip to content

Commit 94b25ea

Browse files
bors[bot]meili-botbidoubiwa
authored
Merge #437
437: Changes related to the next Meilisearch release (v1.1.0) r=bidoubiwa a=meili-bot Related to this issue: meilisearch/integration-guides#251 This PR: - gathers the changes related to the next Meilisearch release (v1.1.0) so that this package is ready when the official release is out. - should pass the tests against the [latest pre-release of Meilisearch](https://github.com/meilisearch/meilisearch/releases). - might eventually contain test failures until the Meilisearch v1.1.0 is out. ⚠️ This PR should NOT be merged until the next release of Meilisearch (v1.1.0) is out. _This PR is auto-generated for the [pre-release week](https://github.com/meilisearch/integration-guides/blob/main/resources/pre-release-week.md) purpose._ Co-authored-by: meili-bot <74670311+meili-bot@users.noreply.github.com> Co-authored-by: cvermand <33010418+bidoubiwa@users.noreply.github.com>
2 parents 4906288 + 1dc6af2 commit 94b25ea

File tree

4 files changed

+144
-7
lines changed

4 files changed

+144
-7
lines changed

src/client.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use serde::{Deserialize, Serialize};
1+
use serde::{de::DeserializeOwned, Deserialize, Serialize};
22
use serde_json::{json, Value};
33
use std::{collections::HashMap, time::Duration};
44
use time::OffsetDateTime;
@@ -8,6 +8,7 @@ use crate::{
88
indexes::*,
99
key::{Key, KeyBuilder, KeyUpdater, KeysQuery, KeysResults},
1010
request::*,
11+
search::*,
1112
task_info::TaskInfo,
1213
tasks::{Task, TasksCancelQuery, TasksDeleteQuery, TasksResults, TasksSearchQuery},
1314
utils::async_sleep,
@@ -63,6 +64,67 @@ impl Client {
6364
Ok(indexes_results)
6465
}
6566

67+
pub async fn execute_multi_search_query<T: 'static + DeserializeOwned>(
68+
&self,
69+
body: &MultiSearchQuery<'_, '_>,
70+
) -> Result<MultiSearchResponse<T>, Error> {
71+
request::<(), &MultiSearchQuery, MultiSearchResponse<T>>(
72+
&format!("{}/multi-search", &self.host),
73+
self.get_api_key(),
74+
Method::Post { body, query: () },
75+
200,
76+
)
77+
.await
78+
}
79+
80+
/// Make multiple search requests.
81+
///
82+
/// # Example
83+
///
84+
/// ```
85+
/// use serde::{Serialize, Deserialize};
86+
/// # use meilisearch_sdk::{client::*, indexes::*, search::*};
87+
///
88+
/// #
89+
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
90+
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
91+
/// #
92+
/// #[derive(Serialize, Deserialize, Debug)]
93+
/// struct Movie {
94+
/// name: String,
95+
/// description: String,
96+
/// }
97+
///
98+
/// # futures::executor::block_on(async move {
99+
/// let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY));
100+
/// let mut movies = client.index("search");
101+
///
102+
/// // add some documents
103+
/// # movies.add_or_replace(&[Movie{name:String::from("Interstellar"), description:String::from("Interstellar chronicles the adventures of a group of explorers who make use of a newly discovered wormhole to surpass the limitations on human space travel and conquer the vast distances involved in an interstellar voyage.")},Movie{name:String::from("Unknown"), description:String::from("Unknown")}], Some("name")).await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
104+
///
105+
/// let search_query_1 = SearchQuery::new(&movies)
106+
/// .with_query("Interstellar")
107+
/// .build();
108+
/// let search_query_2 = SearchQuery::new(&movies)
109+
/// .with_query("")
110+
/// .build();
111+
///
112+
/// let response = client
113+
/// .multi_search()
114+
/// .with_search_query(search_query_1)
115+
/// .with_search_query(search_query_2)
116+
/// .execute::<Movie>()
117+
/// .await
118+
/// .unwrap();
119+
///
120+
/// assert_eq!(response.results.len(), 2);
121+
/// # movies.delete().await.unwrap().wait_for_completion(&client, None, None).await.unwrap();
122+
/// # });
123+
/// ```
124+
pub fn multi_search(&self) -> MultiSearchQuery {
125+
MultiSearchQuery::new(self)
126+
}
127+
66128
/// Return the host associated with this index.
67129
///
68130
/// # Example

src/indexes.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,9 +1331,8 @@ impl Index {
13311331
/// client.wait_for_task(tasks.last().unwrap(), None, None).await.unwrap();
13321332
///
13331333
/// let movies_updated = movie_index.get_documents::<Movie>().await.unwrap();
1334-
/// assert!(movies_updated.results.len() >= 3);
13351334
///
1336-
/// assert!(&movies_updated.results[..] == &updated_movies[..]);
1335+
/// assert!(movies_updated.results.len() >= 3);
13371336
///
13381337
/// # movie_index.delete().await.unwrap().wait_for_completion(&client, None,
13391338
/// None).await.unwrap();

src/search.rs

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use crate::{errors::Error, indexes::Index};
1+
use crate::{client::Client, errors::Error, indexes::Index};
22
use either::Either;
33
use serde::{de::DeserializeOwned, Deserialize, Serialize, Serializer};
44
use serde_json::{Map, Value};
55
use std::collections::HashMap;
66

7-
#[derive(Deserialize, Debug, Eq, PartialEq)]
7+
#[derive(Deserialize, Debug, Eq, PartialEq, Clone)]
88
pub struct MatchRange {
99
pub start: usize,
1010
pub length: usize,
@@ -33,7 +33,7 @@ pub enum MatchingStrategies {
3333

3434
/// A single result.
3535
/// Contains the complete object, optionally the formatted object, and optionally an object that contains information about the matches.
36-
#[derive(Deserialize, Debug)]
36+
#[derive(Deserialize, Debug, Clone)]
3737
pub struct SearchResult<T> {
3838
/// The full result.
3939
#[serde(flatten)]
@@ -46,6 +46,12 @@ pub struct SearchResult<T> {
4646
pub matches_position: Option<HashMap<String, Vec<MatchRange>>>,
4747
}
4848

49+
#[derive(Deserialize, Debug)]
50+
#[serde(rename_all = "camelCase")]
51+
pub struct FacetStats {
52+
pub min: u32,
53+
pub max: u32,
54+
}
4955
#[derive(Deserialize, Debug)]
5056
#[serde(rename_all = "camelCase")]
5157
/// A struct containing search results and other information about the search.
@@ -68,10 +74,14 @@ pub struct SearchResults<T> {
6874
pub total_pages: Option<usize>,
6975
/// Distribution of the given facets
7076
pub facet_distribution: Option<HashMap<String, HashMap<String, usize>>>,
77+
/// facet stats of the numerical facets requested in the `facet` search parameter.
78+
pub facet_stats: Option<HashMap<String, FacetStats>>,
7179
/// Processing time of the query
7280
pub processing_time_ms: usize,
7381
/// Query originating the response
7482
pub query: String,
83+
/// Index uid on which the search was made
84+
pub index_uid: Option<String>,
7585
}
7686

7787
fn serialize_with_wildcard<S: Serializer, T: Serialize>(
@@ -279,6 +289,9 @@ pub struct SearchQuery<'a> {
279289
/// Defines the strategy on how to handle queries containing multiple words.
280290
#[serde(skip_serializing_if = "Option::is_none")]
281291
pub matching_strategy: Option<MatchingStrategies>,
292+
293+
#[serde(skip_serializing_if = "Option::is_none")]
294+
pub(crate) index_uid: Option<&'a str>,
282295
}
283296

284297
#[allow(missing_docs)]
@@ -303,6 +316,7 @@ impl<'a> SearchQuery<'a> {
303316
highlight_post_tag: None,
304317
show_matches_position: None,
305318
matching_strategy: None,
319+
index_uid: None,
306320
}
307321
}
308322
pub fn with_query<'b>(&'b mut self, query: &'a str) -> &'b mut SearchQuery<'a> {
@@ -453,6 +467,10 @@ impl<'a> SearchQuery<'a> {
453467
self.matching_strategy = Some(matching_strategy);
454468
self
455469
}
470+
pub fn with_index_uid<'b>(&'b mut self) -> &'b mut SearchQuery<'a> {
471+
self.index_uid = Some(&self.index.uid);
472+
self
473+
}
456474
pub fn build(&mut self) -> SearchQuery<'a> {
457475
self.clone()
458476
}
@@ -464,6 +482,43 @@ impl<'a> SearchQuery<'a> {
464482
}
465483
}
466484

485+
#[derive(Debug, Serialize, Clone)]
486+
#[serde(rename_all = "camelCase")]
487+
pub struct MultiSearchQuery<'a, 'b> {
488+
#[serde(skip_serializing)]
489+
client: &'a Client,
490+
pub queries: Vec<SearchQuery<'b>>,
491+
}
492+
493+
#[allow(missing_docs)]
494+
impl<'a, 'b> MultiSearchQuery<'a, 'b> {
495+
pub fn new(client: &'a Client) -> MultiSearchQuery<'a, 'b> {
496+
MultiSearchQuery {
497+
client,
498+
queries: Vec::new(),
499+
}
500+
}
501+
pub fn with_search_query(
502+
&mut self,
503+
mut search_query: SearchQuery<'b>,
504+
) -> &mut MultiSearchQuery<'a, 'b> {
505+
search_query.with_index_uid();
506+
self.queries.push(search_query);
507+
self
508+
}
509+
510+
/// Execute the query and fetch the results.
511+
pub async fn execute<T: 'static + DeserializeOwned>(
512+
&'a self,
513+
) -> Result<MultiSearchResponse<T>, Error> {
514+
self.client.execute_multi_search_query::<T>(self).await
515+
}
516+
}
517+
#[derive(Debug, Deserialize)]
518+
pub struct MultiSearchResponse<T> {
519+
pub results: Vec<SearchResults<T>>,
520+
}
521+
467522
#[cfg(test)]
468523
mod tests {
469524
use crate::{client::*, search::*};
@@ -516,6 +571,28 @@ mod tests {
516571
Ok(())
517572
}
518573

574+
#[meilisearch_test]
575+
async fn test_multi_search(client: Client, index: Index) -> Result<(), Error> {
576+
setup_test_index(&client, &index).await?;
577+
let search_query_1 = SearchQuery::new(&index)
578+
.with_query("Sorcerer's Stone")
579+
.build();
580+
let search_query_2 = SearchQuery::new(&index)
581+
.with_query("Chamber of Secrets")
582+
.build();
583+
584+
let response = client
585+
.multi_search()
586+
.with_search_query(search_query_1)
587+
.with_search_query(search_query_2)
588+
.execute::<Document>()
589+
.await
590+
.unwrap();
591+
592+
assert_eq!(response.results.len(), 2);
593+
Ok(())
594+
}
595+
519596
#[meilisearch_test]
520597
async fn test_query_builder(_client: Client, index: Index) -> Result<(), Error> {
521598
let mut query = SearchQuery::new(&index);

src/tasks.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,6 @@ mod test {
10571057
#[meilisearch_test]
10581058
async fn test_delete_tasks_with_params() -> Result<(), Error> {
10591059
let mut s = mockito::Server::new_async().await;
1060-
// let mut s = mockito::Server::new_async().await;
10611060
let mock_server_url = s.url();
10621061
let client = Client::new(mock_server_url, Some("masterKey"));
10631062
let path = "/tasks?indexUids=movies,test&statuses=equeued&types=documentDeletion&uids=1";

0 commit comments

Comments
 (0)