Skip to content

Commit 0740230

Browse files
authored
Merge branch 'main' into feat/multi-modal-search
2 parents 1891ff3 + bcc931a commit 0740230

File tree

11 files changed

+948
-9
lines changed

11 files changed

+948
-9
lines changed

.code-samples.meilisearch.yaml

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ get_documents_post_1: |-
142142
.execute::<Movies>()
143143
.await
144144
.unwrap();
145+
get_documents_by_ids_1: |-
146+
let index = client.index("books");
147+
let documents: DocumentsResults = DocumentsQuery::new(&index)
148+
.with_ids(["1", "2"]) // retrieve documents by IDs
149+
.execute::<Movies>()
150+
.await
151+
.unwrap();
145152
add_or_replace_documents_1: |-
146153
let task: TaskInfo = client
147154
.index("movies")
@@ -449,6 +456,23 @@ reset_typo_tolerance_1: |-
449456
.reset_typo_tolerance()
450457
.await
451458
.unwrap();
459+
get_all_batches_1: |-
460+
let mut query = meilisearch_sdk::batches::BatchesQuery::new(&client);
461+
query.with_limit(20);
462+
let batches: meilisearch_sdk::batches::BatchesResults =
463+
client.get_batches_with(&query).await.unwrap();
464+
get_batch_1: |-
465+
let uid: u32 = 42;
466+
let batch: meilisearch_sdk::batches::Batch = client
467+
.get_batch(uid)
468+
.await
469+
.unwrap();
470+
get_all_batches_paginating_1: |-
471+
let mut query = meilisearch_sdk::batches::BatchesQuery::new(&client);
472+
query.with_limit(2);
473+
query.with_from(40);
474+
let batches: meilisearch_sdk::batches::BatchesResults =
475+
client.get_batches_with(&query).await.unwrap();
452476
get_stop_words_1: |-
453477
let stop_words: Vec<String> = client
454478
.index("movies")
@@ -695,10 +719,16 @@ distinct_attribute_guide_1: |-
695719
.set_distinct_attribute("product_id")
696720
.await
697721
.unwrap();
722+
compact_index_1: |-
723+
let task: TaskInfo = client
724+
.index("INDEX_UID")
725+
.compact()
726+
.await
727+
.unwrap();
698728
field_properties_guide_searchable_1: |-
699729
let searchable_attributes = [
700730
"title",
701-
"overvieww",
731+
"overview",
702732
"genres"
703733
];
704734
@@ -710,7 +740,7 @@ field_properties_guide_searchable_1: |-
710740
field_properties_guide_displayed_1: |-
711741
let displayed_attributes = [
712742
"title",
713-
"overvieww",
743+
"overview",
714744
"genres",
715745
"release_date"
716746
];
@@ -1970,3 +2000,22 @@ update_embedders_1: |-
19702000
.set_embedders(&embedders)
19712001
.await
19722002
.unwrap();
2003+
webhooks_get_1: |-
2004+
let webhooks = client.get_webhooks().await.unwrap();
2005+
webhooks_get_single_1: |-
2006+
let webhook = client.get_webhook("WEBHOOK_UUID").await.unwrap();
2007+
webhooks_post_1: |-
2008+
let mut payload = meilisearch_sdk::webhooks::WebhookCreate::new("WEBHOOK_TARGET_URL");
2009+
payload
2010+
.insert_header("authorization", "SECURITY_KEY")
2011+
.insert_header("referer", "https://example.com");
2012+
let webhook = client.create_webhook(&payload).await.unwrap();
2013+
webhooks_patch_1: |-
2014+
let mut update = meilisearch_sdk::webhooks::WebhookUpdate::new();
2015+
update.remove_header("referer");
2016+
let webhook = client
2017+
.update_webhook("WEBHOOK_UUID", &update)
2018+
.await
2019+
.unwrap();
2020+
webhooks_delete_1: |-
2021+
client.delete_webhook("WEBHOOK_UUID").await.unwrap();

Cargo.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,28 @@ meilisearch-index-setting-macro = { path = "meilisearch-index-setting-macro", ve
2626
pin-project-lite = { version = "0.2.16", optional = true }
2727
reqwest = { version = "0.12.22", optional = true, default-features = false, features = ["http2", "stream"] }
2828
bytes = { version = "1.10.1", optional = true }
29-
uuid = { version = "1.17.0", features = ["v4"] }
29+
uuid = { version = "1.17.0", features = ["v4", "serde"] }
3030
futures-core = "0.3.31"
3131
futures-io = "0.3.31"
3232
futures-channel = "0.3.31"
3333
futures-util = { version = "0.3.31", default-features = false, features = ["io"] }
3434

3535
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
36-
jsonwebtoken = { version = "9.3.1", default-features = false }
36+
jsonwebtoken = { version = "10.2.0", default-features = false }
3737
tokio = { version = "1.38", optional = true, features = ["time"] }
3838

3939
[target.'cfg(target_arch = "wasm32")'.dependencies]
40-
uuid = { version = "1.17.0", default-features = false, features = ["v4", "js"] }
40+
uuid = { version = "1.17.0", default-features = false, features = ["v4", "js", "serde"] }
4141
web-sys = "0.3.77"
4242
wasm-bindgen-futures = "0.4"
4343

4444
[features]
45-
default = ["reqwest", "tls"]
45+
default = ["reqwest", "tls", "jwt_aws_lc_rs"]
4646
reqwest = ["dep:reqwest", "dep:tokio", "pin-project-lite", "bytes"]
4747
tls = ["reqwest/rustls-tls"]
4848
futures-unsend = []
49+
jwt_aws_lc_rs = ["jsonwebtoken/aws_lc_rs"]
50+
jwt_rust_crypto = ["jsonwebtoken/rust_crypto"]
4951

5052
[dev-dependencies]
5153
futures-await-test = "0.3"

examples/web_app_graphql/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ actix-web = "4.4.0"
1212
async-graphql = "6.0.11"
1313
async-graphql-actix-web = "6.0.11"
1414
diesel = { version = "2.1.4", features = ["postgres"] }
15-
diesel-async = { version = "0.6.1", features = ["postgres", "deadpool"] }
15+
diesel-async = { version = "0.7.3", features = ["postgres", "deadpool"] }
1616
diesel_migrations = "2.1.0"
1717
dotenvy = "0.15.7"
1818
env_logger = "0.11.3"
@@ -22,5 +22,5 @@ log = "0.4.20"
2222
meilisearch-sdk = "0.24.3"
2323
serde = { version = "1.0.192", features = ["derive"] }
2424
serde_json = "1.0.108"
25-
thiserror = "1.0.51"
25+
thiserror = "2.0.17"
2626
validator = { version = "0.20.0", features = ["derive"] }

src/batches.rs

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
use serde::{Deserialize, Serialize};
2+
use time::OffsetDateTime;
3+
4+
use crate::{client::Client, errors::Error, request::HttpClient};
5+
6+
/// Types and queries for the Meilisearch Batches API.
7+
///
8+
/// See: https://www.meilisearch.com/docs/reference/api/batches
9+
#[derive(Debug, Clone, Deserialize)]
10+
#[serde(rename_all = "camelCase")]
11+
pub struct Batch {
12+
/// Unique identifier of the batch.
13+
pub uid: u32,
14+
/// When the batch was enqueued.
15+
#[serde(default, with = "time::serde::rfc3339::option")]
16+
pub enqueued_at: Option<OffsetDateTime>,
17+
/// When the batch started processing.
18+
#[serde(default, with = "time::serde::rfc3339::option")]
19+
pub started_at: Option<OffsetDateTime>,
20+
/// When the batch finished processing.
21+
#[serde(default, with = "time::serde::rfc3339::option")]
22+
pub finished_at: Option<OffsetDateTime>,
23+
/// Index uid related to this batch (if applicable).
24+
#[serde(skip_serializing_if = "Option::is_none")]
25+
pub index_uid: Option<String>,
26+
/// The task uids that are part of this batch.
27+
#[serde(skip_serializing_if = "Option::is_none")]
28+
pub task_uids: Option<Vec<u32>>,
29+
/// The strategy that caused the autobatcher to stop batching tasks.
30+
///
31+
/// Introduced in Meilisearch v1.15.
32+
#[serde(skip_serializing_if = "Option::is_none")]
33+
pub batch_strategy: Option<BatchStrategy>,
34+
}
35+
36+
/// Reason why the autobatcher stopped batching tasks.
37+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
38+
#[serde(rename_all = "snake_case")]
39+
#[non_exhaustive]
40+
pub enum BatchStrategy {
41+
/// The batch reached its configured size threshold.
42+
SizeLimitReached,
43+
/// The batch reached its configured time window threshold.
44+
TimeLimitReached,
45+
/// Unknown strategy (forward-compatibility).
46+
#[serde(other)]
47+
Unknown,
48+
}
49+
50+
#[derive(Debug, Clone, Deserialize)]
51+
#[serde(rename_all = "camelCase")]
52+
pub struct BatchesResults {
53+
pub results: Vec<Batch>,
54+
pub total: u32,
55+
pub limit: u32,
56+
#[serde(skip_serializing_if = "Option::is_none")]
57+
pub from: Option<u32>,
58+
#[serde(skip_serializing_if = "Option::is_none")]
59+
pub next: Option<u32>,
60+
}
61+
62+
/// Query builder for listing batches.
63+
#[derive(Debug, Serialize, Clone)]
64+
#[serde(rename_all = "camelCase")]
65+
pub struct BatchesQuery<'a, Http: HttpClient> {
66+
#[serde(skip_serializing)]
67+
client: &'a Client<Http>,
68+
/// Maximum number of batches to return.
69+
#[serde(skip_serializing_if = "Option::is_none")]
70+
limit: Option<u32>,
71+
/// The first batch uid that should be returned.
72+
#[serde(skip_serializing_if = "Option::is_none")]
73+
from: Option<u32>,
74+
}
75+
76+
impl<'a, Http: HttpClient> BatchesQuery<'a, Http> {
77+
#[must_use]
78+
pub fn new(client: &'a Client<Http>) -> BatchesQuery<'a, Http> {
79+
BatchesQuery {
80+
client,
81+
limit: None,
82+
from: None,
83+
}
84+
}
85+
86+
#[must_use]
87+
pub fn with_limit(&mut self, limit: u32) -> &mut Self {
88+
self.limit = Some(limit);
89+
self
90+
}
91+
92+
#[must_use]
93+
pub fn with_from(&mut self, from: u32) -> &mut Self {
94+
self.from = Some(from);
95+
self
96+
}
97+
98+
/// Execute the query and list batches.
99+
pub async fn execute(&self) -> Result<BatchesResults, Error> {
100+
self.client.get_batches_with(self).await
101+
}
102+
}
103+
104+
#[cfg(test)]
105+
mod tests {
106+
use crate::batches::BatchStrategy;
107+
use crate::client::Client;
108+
109+
#[tokio::test]
110+
async fn test_get_batches_parses_batch_strategy() {
111+
let mut s = mockito::Server::new_async().await;
112+
let base = s.url();
113+
114+
let response_body = serde_json::json!({
115+
"results": [
116+
{
117+
"uid": 42,
118+
"enqueuedAt": "2024-10-11T11:49:53.000Z",
119+
"startedAt": "2024-10-11T11:49:54.000Z",
120+
"finishedAt": "2024-10-11T11:49:55.000Z",
121+
"indexUid": "movies",
122+
"taskUids": [1, 2, 3],
123+
"batchStrategy": "time_limit_reached"
124+
}
125+
],
126+
"limit": 20,
127+
"from": null,
128+
"next": null,
129+
"total": 1
130+
})
131+
.to_string();
132+
133+
let _m = s
134+
.mock("GET", "/batches")
135+
.with_status(200)
136+
.with_header("content-type", "application/json")
137+
.with_body(response_body)
138+
.create_async()
139+
.await;
140+
141+
let client = Client::new(base, None::<String>).unwrap();
142+
let batches = client.get_batches().await.expect("list batches failed");
143+
assert_eq!(batches.results.len(), 1);
144+
let b = &batches.results[0];
145+
assert_eq!(b.uid, 42);
146+
assert_eq!(b.batch_strategy, Some(BatchStrategy::TimeLimitReached));
147+
}
148+
149+
#[tokio::test]
150+
async fn test_get_batch_by_uid_parses_batch_strategy() {
151+
let mut s = mockito::Server::new_async().await;
152+
let base = s.url();
153+
154+
let response_body = serde_json::json!({
155+
"uid": 99,
156+
"batchStrategy": "size_limit_reached",
157+
"taskUids": [10, 11]
158+
})
159+
.to_string();
160+
161+
let _m = s
162+
.mock("GET", "/batches/99")
163+
.with_status(200)
164+
.with_header("content-type", "application/json")
165+
.with_body(response_body)
166+
.create_async()
167+
.await;
168+
169+
let client = Client::new(base, None::<String>).unwrap();
170+
let batch = client.get_batch(99).await.expect("get batch failed");
171+
assert_eq!(batch.uid, 99);
172+
assert_eq!(batch.batch_strategy, Some(BatchStrategy::SizeLimitReached));
173+
}
174+
175+
#[tokio::test]
176+
async fn test_query_serialization_for_batches() {
177+
use mockito::Matcher;
178+
let mut s = mockito::Server::new_async().await;
179+
let base = s.url();
180+
181+
let _m = s
182+
.mock("GET", "/batches")
183+
.match_query(Matcher::AllOf(vec![
184+
Matcher::UrlEncoded("limit".into(), "2".into()),
185+
Matcher::UrlEncoded("from".into(), "40".into()),
186+
]))
187+
.with_status(200)
188+
.with_header("content-type", "application/json")
189+
.with_body(r#"{"results":[],"limit":2,"total":0}"#)
190+
.create_async()
191+
.await;
192+
193+
let client = Client::new(base, None::<String>).unwrap();
194+
let mut q = crate::batches::BatchesQuery::new(&client);
195+
let _ = q.with_limit(2).with_from(40);
196+
let res = client.get_batches_with(&q).await.expect("request failed");
197+
assert_eq!(res.limit, 2);
198+
}
199+
}

0 commit comments

Comments
 (0)