Skip to content

Commit f749de4

Browse files
committed
feat: Add queryVector to search responses and support index renaming
1 parent c029adb commit f749de4

File tree

5 files changed

+139
-7
lines changed

5 files changed

+139
-7
lines changed

.code-samples.meilisearch.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ update_an_index_1: |-
9494
.execute()
9595
.await
9696
.unwrap();
97+
rename_an_index_1: |-
98+
curl \
99+
-X PATCH 'MEILISEARCH_URL/indexes/INDEX_A' \
100+
-H 'Content-Type: application/json' \
101+
--data-binary '{ "uid": "INDEX_B" }'
97102
delete_an_index_1: |-
98103
client.index("movies")
99104
.delete()

src/client.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub struct Client<Http: HttpClient = DefaultHttpClient> {
2727
#[derive(Debug, Clone, Serialize, Deserialize)]
2828
pub struct SwapIndexes {
2929
pub indexes: (String, String),
30+
#[serde(skip_serializing_if = "Option::is_none")]
31+
pub rename: Option<bool>,
3032
}
3133

3234
#[cfg(feature = "reqwest")]
@@ -202,7 +204,7 @@ impl<Http: HttpClient> Client<Http> {
202204
///
203205
/// [1]: https://www.meilisearch.com/docs/learn/multi_search/multi_search_vs_federated_search#what-is-federated-search
204206
#[must_use]
205-
pub fn multi_search(&self) -> MultiSearchQuery<Http> {
207+
pub fn multi_search(&self) -> MultiSearchQuery<'_, '_, Http> {
206208
MultiSearchQuery::new(self)
207209
}
208210

@@ -532,6 +534,7 @@ impl<Http: HttpClient> Client<Http> {
532534
/// "swap_index_1".to_string(),
533535
/// "swap_index_2".to_string(),
534536
/// ),
537+
/// rename: None,
535538
/// }])
536539
/// .await
537540
/// .unwrap();
@@ -1249,6 +1252,7 @@ mod tests {
12491252
"test_swapping_two_indexes_1".to_string(),
12501253
"test_swapping_two_indexes_2".to_string(),
12511254
),
1255+
rename: None,
12521256
}])
12531257
.await
12541258
.unwrap();
@@ -1351,6 +1355,37 @@ mod tests {
13511355
assert_eq!(tasks.limit, 20);
13521356
}
13531357

1358+
#[meilisearch_test]
1359+
async fn test_rename_index_via_swap(client: Client, name: String) -> Result<(), Error> {
1360+
let from = format!("{name}_from");
1361+
let to = format!("{name}_to");
1362+
1363+
client
1364+
.create_index(&from, None)
1365+
.await?
1366+
.wait_for_completion(&client, None, None)
1367+
.await?;
1368+
1369+
let task = client
1370+
.swap_indexes([&SwapIndexes {
1371+
indexes: (from.clone(), to.clone()),
1372+
rename: Some(true),
1373+
}])
1374+
.await?;
1375+
task.wait_for_completion(&client, None, None).await?;
1376+
1377+
let new_index = client.get_index(&to).await?;
1378+
assert_eq!(new_index.uid, to);
1379+
1380+
new_index
1381+
.delete()
1382+
.await?
1383+
.wait_for_completion(&client, None, None)
1384+
.await?;
1385+
1386+
Ok(())
1387+
}
1388+
13541389
#[meilisearch_test]
13551390
async fn test_get_tasks_with_params(client: Client) {
13561391
let query = TasksSearchQuery::new(&client);

src/documents.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ pub struct DocumentQuery<'a, Http: HttpClient> {
8686

8787
impl<'a, Http: HttpClient> DocumentQuery<'a, Http> {
8888
#[must_use]
89-
pub fn new(index: &Index<Http>) -> DocumentQuery<Http> {
89+
pub fn new(index: &Index<Http>) -> DocumentQuery<'_, Http> {
9090
DocumentQuery {
9191
index,
9292
fields: None,
@@ -200,7 +200,7 @@ pub struct DocumentsQuery<'a, Http: HttpClient> {
200200

201201
impl<'a, Http: HttpClient> DocumentsQuery<'a, Http> {
202202
#[must_use]
203-
pub fn new(index: &Index<Http>) -> DocumentsQuery<Http> {
203+
pub fn new(index: &Index<Http>) -> DocumentsQuery<'_, Http> {
204204
DocumentsQuery {
205205
index,
206206
offset: None,
@@ -332,7 +332,7 @@ pub struct DocumentDeletionQuery<'a, Http: HttpClient> {
332332

333333
impl<'a, Http: HttpClient> DocumentDeletionQuery<'a, Http> {
334334
#[must_use]
335-
pub fn new(index: &Index<Http>) -> DocumentDeletionQuery<Http> {
335+
pub fn new(index: &Index<Http>) -> DocumentDeletionQuery<'_, Http> {
336336
DocumentDeletionQuery {
337337
index,
338338
filter: None,

src/indexes.rs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ impl<Http: HttpClient> Index<Http> {
276276
/// # });
277277
/// ```
278278
#[must_use]
279-
pub fn search(&self) -> SearchQuery<Http> {
279+
pub fn search(&self) -> SearchQuery<'_, Http> {
280280
SearchQuery::new(self)
281281
}
282282

@@ -1773,15 +1773,19 @@ pub struct IndexUpdater<'a, Http: HttpClient> {
17731773
pub client: &'a Client<Http>,
17741774
#[serde(skip_serializing)]
17751775
pub uid: String,
1776+
/// New uid to rename the index to
1777+
#[serde(rename = "uid", skip_serializing_if = "Option::is_none")]
1778+
pub new_uid: Option<String>,
17761779
pub primary_key: Option<String>,
17771780
}
17781781

17791782
impl<'a, Http: HttpClient> IndexUpdater<'a, Http> {
1780-
pub fn new(uid: impl AsRef<str>, client: &Client<Http>) -> IndexUpdater<Http> {
1783+
pub fn new(uid: impl AsRef<str>, client: &Client<Http>) -> IndexUpdater<'_, Http> {
17811784
IndexUpdater {
17821785
client,
17831786
primary_key: None,
17841787
uid: uid.as_ref().to_string(),
1788+
new_uid: None,
17851789
}
17861790
}
17871791
/// Define the new `primary_key` to set on the [Index].
@@ -1829,6 +1833,12 @@ impl<'a, Http: HttpClient> IndexUpdater<'a, Http> {
18291833
self
18301834
}
18311835

1836+
/// Define a new `uid` to rename the index.
1837+
pub fn with_uid(&mut self, new_uid: impl AsRef<str>) -> &mut IndexUpdater<'a, Http> {
1838+
self.new_uid = Some(new_uid.as_ref().to_string());
1839+
self
1840+
}
1841+
18321842
/// Execute the update of an [Index] using the [`IndexUpdater`].
18331843
///
18341844
/// # Example
@@ -1976,7 +1986,7 @@ pub struct IndexesQuery<'a, Http: HttpClient> {
19761986

19771987
impl<'a, Http: HttpClient> IndexesQuery<'a, Http> {
19781988
#[must_use]
1979-
pub fn new(client: &Client<Http>) -> IndexesQuery<Http> {
1989+
pub fn new(client: &Client<Http>) -> IndexesQuery<'_, Http> {
19801990
IndexesQuery {
19811991
client,
19821992
offset: None,
@@ -2223,6 +2233,40 @@ mod tests {
22232233
Ok(())
22242234
}
22252235

2236+
#[meilisearch_test]
2237+
async fn test_rename_index_via_update(client: Client, name: String) -> Result<(), Error> {
2238+
let from = format!("{name}_from");
2239+
let to = format!("{name}_to");
2240+
2241+
// Create source index
2242+
client
2243+
.create_index(&from, None)
2244+
.await?
2245+
.wait_for_completion(&client, None, None)
2246+
.await?;
2247+
2248+
// Rename using index update
2249+
IndexUpdater::new(&from, &client)
2250+
.with_uid(&to)
2251+
.execute()
2252+
.await?
2253+
.wait_for_completion(&client, None, None)
2254+
.await?;
2255+
2256+
// New index should exist
2257+
let new_index = client.get_index(&to).await?;
2258+
assert_eq!(new_index.uid, to);
2259+
2260+
// cleanup
2261+
new_index
2262+
.delete()
2263+
.await?
2264+
.wait_for_completion(&client, None, None)
2265+
.await?;
2266+
2267+
Ok(())
2268+
}
2269+
22262270
#[meilisearch_test]
22272271
async fn test_add_documents_ndjson(client: Client, index: Index) -> Result<(), Error> {
22282272
let ndjson = r#"{ "id": 1, "body": "doggo" }{ "id": 2, "body": "catto" }"#.as_bytes();

src/search.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,16 @@ pub struct SearchResults<T> {
121121
pub query: String,
122122
/// Index uid on which the search was made.
123123
pub index_uid: Option<String>,
124+
/// The query vector returned when `retrieveVectors` is enabled.
125+
/// Accept multiple possible field names to be forward/backward compatible with server variations.
126+
#[serde(
127+
rename = "queryVector",
128+
alias = "query_vector",
129+
alias = "queryEmbedding",
130+
alias = "query_embedding",
131+
skip_serializing_if = "Option::is_none"
132+
)]
133+
pub query_vector: Option<Vec<f32>>,
124134
}
125135

126136
fn serialize_attributes_to_crop_with_wildcard<S: Serializer>(
@@ -2017,6 +2027,44 @@ pub(crate) mod tests {
20172027
Ok(())
20182028
}
20192029

2030+
#[meilisearch_test]
2031+
async fn test_query_vector_in_response(client: Client, index: Index) -> Result<(), Error> {
2032+
setup_embedder(&client, &index).await?;
2033+
setup_test_index(&client, &index).await?;
2034+
2035+
let mut query = SearchQuery::new(&index);
2036+
let qv = vectorize(false, 0);
2037+
query
2038+
.with_hybrid("default", 1.0)
2039+
.with_vector(&qv)
2040+
.with_retrieve_vectors(true);
2041+
2042+
let results: SearchResults<Document> = index.execute_query(&query).await?;
2043+
2044+
if results.query_vector.is_none() {
2045+
use crate::request::Method;
2046+
let url = format!("{}/indexes/{}/search", index.client.get_host(), index.uid);
2047+
let raw: serde_json::Value = index
2048+
.client
2049+
.http_client
2050+
.request::<(), &SearchQuery<_>, serde_json::Value>(
2051+
&url,
2052+
Method::Post {
2053+
body: &query,
2054+
query: (),
2055+
},
2056+
200,
2057+
)
2058+
.await
2059+
.unwrap();
2060+
eprintln!("DEBUG raw search response: {}", raw);
2061+
}
2062+
2063+
assert!(results.query_vector.is_some());
2064+
assert_eq!(results.query_vector.as_ref().unwrap().len(), 11);
2065+
Ok(())
2066+
}
2067+
20202068
#[meilisearch_test]
20212069
async fn test_hybrid(client: Client, index: Index) -> Result<(), Error> {
20222070
setup_embedder(&client, &index).await?;

0 commit comments

Comments
 (0)