Skip to content

Commit ea72632

Browse files
authored
Merge branch 'main' into feat/documentsId
2 parents aa5c74f + 917e45d commit ea72632

File tree

7 files changed

+310
-10
lines changed

7 files changed

+310
-10
lines changed

.code-samples.meilisearch.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,23 @@ reset_typo_tolerance_1: |-
456456
.reset_typo_tolerance()
457457
.await
458458
.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();
459476
get_stop_words_1: |-
460477
let stop_words: Vec<String> = client
461478
.index("movies")

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ 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 = "10.0.0", default-features = false, features = ["aws_lc_rs"]}
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]
@@ -42,10 +42,12 @@ 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"

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+
}

src/client.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,92 @@ impl<Http: HttpClient> Client<Http> {
11121112
Ok(tasks)
11131113
}
11141114

1115+
/// List batches using the Batches API.
1116+
///
1117+
/// See: https://www.meilisearch.com/docs/reference/api/batches
1118+
///
1119+
/// # Example
1120+
///
1121+
/// ```
1122+
/// # use meilisearch_sdk::client::Client;
1123+
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
1124+
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
1125+
/// # tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {
1126+
/// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
1127+
/// let batches = client.get_batches().await.unwrap();
1128+
/// # let _ = batches;
1129+
/// # });
1130+
/// ```
1131+
pub async fn get_batches(&self) -> Result<crate::batches::BatchesResults, Error> {
1132+
let res = self
1133+
.http_client
1134+
.request::<(), (), crate::batches::BatchesResults>(
1135+
&format!("{}/batches", self.host),
1136+
Method::Get { query: () },
1137+
200,
1138+
)
1139+
.await?;
1140+
Ok(res)
1141+
}
1142+
1143+
/// List batches with pagination filters.
1144+
///
1145+
/// # Example
1146+
///
1147+
/// ```
1148+
/// # use meilisearch_sdk::{client::Client, batches::BatchesQuery};
1149+
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
1150+
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
1151+
/// # tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {
1152+
/// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
1153+
/// let mut query = BatchesQuery::new(&client);
1154+
/// query.with_limit(1);
1155+
/// let batches = client.get_batches_with(&query).await.unwrap();
1156+
/// # let _ = batches;
1157+
/// # });
1158+
/// ```
1159+
pub async fn get_batches_with(
1160+
&self,
1161+
query: &crate::batches::BatchesQuery<'_, Http>,
1162+
) -> Result<crate::batches::BatchesResults, Error> {
1163+
let res = self
1164+
.http_client
1165+
.request::<&crate::batches::BatchesQuery<'_, Http>, (), crate::batches::BatchesResults>(
1166+
&format!("{}/batches", self.host),
1167+
Method::Get { query },
1168+
200,
1169+
)
1170+
.await?;
1171+
Ok(res)
1172+
}
1173+
1174+
/// Get a single batch by its uid.
1175+
///
1176+
/// # Example
1177+
///
1178+
/// ```
1179+
/// # use meilisearch_sdk::client::Client;
1180+
/// # let MEILISEARCH_URL = option_env!("MEILISEARCH_URL").unwrap_or("http://localhost:7700");
1181+
/// # let MEILISEARCH_API_KEY = option_env!("MEILISEARCH_API_KEY").unwrap_or("masterKey");
1182+
/// # tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {
1183+
/// # let client = Client::new(MEILISEARCH_URL, Some(MEILISEARCH_API_KEY)).unwrap();
1184+
/// let uid: u32 = 42;
1185+
/// let batch = client.get_batch(uid).await.unwrap();
1186+
/// # let _ = batch;
1187+
/// # });
1188+
/// ```
1189+
pub async fn get_batch(&self, uid: u32) -> Result<crate::batches::Batch, Error> {
1190+
let res = self
1191+
.http_client
1192+
.request::<(), (), crate::batches::Batch>(
1193+
&format!("{}/batches/{}", self.host, uid),
1194+
Method::Get { query: () },
1195+
200,
1196+
)
1197+
.await?;
1198+
Ok(res)
1199+
}
1200+
11151201
/// Generates a new tenant token.
11161202
///
11171203
/// # Example

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@
230230
#![warn(clippy::all)]
231231
#![allow(clippy::needless_doctest_main)]
232232

233+
/// Module to interact with the Batches API.
234+
pub mod batches;
233235
/// Module containing the [`Client`](client::Client) struct.
234236
pub mod client;
235237
/// Module representing the [documents] structures.

src/tenant_tokens.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use time::OffsetDateTime;
66
#[cfg(not(target_arch = "wasm32"))]
77
use uuid::Uuid;
88

9-
#[cfg_attr(test, derive(Clone))]
109
#[derive(Debug, Serialize, Deserialize)]
1110
#[serde(rename_all = "camelCase")]
1211
struct TenantTokenClaim {

src/webhooks.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,14 @@ impl WebhookCreate {
6666
}
6767
}
6868

69-
#[derive(Debug, Clone, PartialEq, Eq)]
69+
#[derive(Debug, Clone, PartialEq, Eq, Default)]
7070
enum HeadersUpdate {
71+
#[default]
7172
NotSet,
7273
Reset,
7374
Set(BTreeMap<String, Option<String>>),
7475
}
7576

76-
impl Default for HeadersUpdate {
77-
fn default() -> Self {
78-
Self::NotSet
79-
}
80-
}
81-
8277
/// Payload used to update or delete settings of an existing webhook.
8378
#[derive(Debug, Clone, Default, PartialEq, Eq)]
8479
pub struct WebhookUpdate {

0 commit comments

Comments
 (0)