Skip to content

Commit 7166542

Browse files
committed
Add batchStrategy field to batches
1 parent e90a3c2 commit 7166542

File tree

4 files changed

+218
-0
lines changed

4 files changed

+218
-0
lines changed

.code-samples.meilisearch.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,16 @@ reset_typo_tolerance_1: |-
449449
.reset_typo_tolerance()
450450
.await
451451
.unwrap();
452+
get_all_batches_1: |-
453+
let batches: BatchesResults = client
454+
.get_batches()
455+
.await
456+
.unwrap();
457+
get_batch_1: |-
458+
let batch: Batch = client
459+
.get_batch(42)
460+
.await
461+
.unwrap();
452462
get_stop_words_1: |-
453463
let stop_words: Vec<String> = client
454464
.index("movies")

src/batches.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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+
#[serde(default)]
14+
pub uid: u32,
15+
/// When the batch was enqueued.
16+
#[serde(default, with = "time::serde::rfc3339::option")]
17+
pub enqueued_at: Option<OffsetDateTime>,
18+
/// When the batch started processing.
19+
#[serde(default, with = "time::serde::rfc3339::option")]
20+
pub started_at: Option<OffsetDateTime>,
21+
/// When the batch finished processing.
22+
#[serde(default, with = "time::serde::rfc3339::option")]
23+
pub finished_at: Option<OffsetDateTime>,
24+
/// Index uid related to this batch (if applicable).
25+
#[serde(skip_serializing_if = "Option::is_none")]
26+
pub index_uid: Option<String>,
27+
/// The task uids that are part of this batch.
28+
#[serde(skip_serializing_if = "Option::is_none")]
29+
pub task_uids: Option<Vec<u32>>,
30+
/// The strategy that caused the autobatcher to stop batching tasks.
31+
///
32+
/// Introduced in Meilisearch v1.15.
33+
#[serde(skip_serializing_if = "Option::is_none")]
34+
pub batch_strategy: Option<String>,
35+
}
36+
37+
#[derive(Debug, Clone, Deserialize)]
38+
#[serde(rename_all = "camelCase")]
39+
pub struct BatchesResults {
40+
pub results: Vec<Batch>,
41+
#[serde(skip_serializing_if = "Option::is_none")]
42+
pub total: Option<u64>,
43+
#[serde(skip_serializing_if = "Option::is_none")]
44+
pub limit: Option<u32>,
45+
#[serde(skip_serializing_if = "Option::is_none")]
46+
pub from: Option<u32>,
47+
#[serde(skip_serializing_if = "Option::is_none")]
48+
pub next: Option<u32>,
49+
}
50+
51+
/// Query builder for listing batches.
52+
#[derive(Debug, Serialize, Clone)]
53+
#[serde(rename_all = "camelCase")]
54+
pub struct BatchesQuery<'a, Http: HttpClient> {
55+
#[serde(skip_serializing)]
56+
client: &'a Client<Http>,
57+
/// Maximum number of batches to return.
58+
#[serde(skip_serializing_if = "Option::is_none")]
59+
limit: Option<u32>,
60+
/// The first batch uid that should be returned.
61+
#[serde(skip_serializing_if = "Option::is_none")]
62+
from: Option<u32>,
63+
}
64+
65+
impl<'a, Http: HttpClient> BatchesQuery<'a, Http> {
66+
#[must_use]
67+
pub fn new(client: &'a Client<Http>) -> BatchesQuery<'a, Http> {
68+
BatchesQuery {
69+
client,
70+
limit: None,
71+
from: None,
72+
}
73+
}
74+
75+
#[must_use]
76+
pub fn with_limit(&mut self, limit: u32) -> &mut Self {
77+
self.limit = Some(limit);
78+
self
79+
}
80+
81+
#[must_use]
82+
pub fn with_from(&mut self, from: u32) -> &mut Self {
83+
self.from = Some(from);
84+
self
85+
}
86+
87+
/// Execute the query and list batches.
88+
pub async fn execute(&self) -> Result<BatchesResults, Error> {
89+
self.client.get_batches_with(self).await
90+
}
91+
}
92+
93+
#[cfg(test)]
94+
mod tests {
95+
use crate::client::Client;
96+
97+
#[tokio::test]
98+
async fn test_get_batches_parses_batch_strategy() {
99+
let mut s = mockito::Server::new_async().await;
100+
let base = s.url();
101+
102+
let response_body = serde_json::json!({
103+
"results": [
104+
{
105+
"uid": 42,
106+
"enqueuedAt": "2024-10-11T11:49:53.000Z",
107+
"startedAt": "2024-10-11T11:49:54.000Z",
108+
"finishedAt": "2024-10-11T11:49:55.000Z",
109+
"indexUid": "movies",
110+
"taskUids": [1, 2, 3],
111+
"batchStrategy": "time_limit_reached"
112+
}
113+
],
114+
"limit": 20,
115+
"from": null,
116+
"next": null,
117+
"total": 1
118+
})
119+
.to_string();
120+
121+
let _m = s
122+
.mock("GET", "/batches")
123+
.with_status(200)
124+
.with_header("content-type", "application/json")
125+
.with_body(response_body)
126+
.create_async()
127+
.await;
128+
129+
let client = Client::new(base, None::<String>).unwrap();
130+
let batches = client.get_batches().await.expect("list batches failed");
131+
assert_eq!(batches.results.len(), 1);
132+
let b = &batches.results[0];
133+
assert_eq!(b.uid, 42);
134+
assert_eq!(b.batch_strategy.as_deref(), Some("time_limit_reached"));
135+
}
136+
137+
#[tokio::test]
138+
async fn test_get_batch_by_uid_parses_batch_strategy() {
139+
let mut s = mockito::Server::new_async().await;
140+
let base = s.url();
141+
142+
let response_body = serde_json::json!({
143+
"uid": 99,
144+
"batchStrategy": "size_limit_reached",
145+
"taskUids": [10, 11]
146+
})
147+
.to_string();
148+
149+
let _m = s
150+
.mock("GET", "/batches/99")
151+
.with_status(200)
152+
.with_header("content-type", "application/json")
153+
.with_body(response_body)
154+
.create_async()
155+
.await;
156+
157+
let client = Client::new(base, None::<String>).unwrap();
158+
let batch = client.get_batch(99).await.expect("get batch failed");
159+
assert_eq!(batch.uid, 99);
160+
assert_eq!(batch.batch_strategy.as_deref(), Some("size_limit_reached"));
161+
}
162+
}

src/client.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,50 @@ 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+
pub async fn get_batches(&self) -> Result<crate::batches::BatchesResults, Error> {
1119+
let res = self
1120+
.http_client
1121+
.request::<(), (), crate::batches::BatchesResults>(
1122+
&format!("{}/batches", self.host),
1123+
Method::Get { query: () },
1124+
200,
1125+
)
1126+
.await?;
1127+
Ok(res)
1128+
}
1129+
1130+
/// List batches with pagination filters.
1131+
pub async fn get_batches_with(
1132+
&self,
1133+
query: &crate::batches::BatchesQuery<'_, Http>,
1134+
) -> Result<crate::batches::BatchesResults, Error> {
1135+
let res = self
1136+
.http_client
1137+
.request::<&crate::batches::BatchesQuery<'_, Http>, (), crate::batches::BatchesResults>(
1138+
&format!("{}/batches", self.host),
1139+
Method::Get { query },
1140+
200,
1141+
)
1142+
.await?;
1143+
Ok(res)
1144+
}
1145+
1146+
/// Get a single batch by its uid.
1147+
pub async fn get_batch(&self, uid: u32) -> Result<crate::batches::Batch, Error> {
1148+
let res = self
1149+
.http_client
1150+
.request::<(), (), crate::batches::Batch>(
1151+
&format!("{}/batches/{}", self.host, uid),
1152+
Method::Get { query: () },
1153+
200,
1154+
)
1155+
.await?;
1156+
Ok(res)
1157+
}
1158+
11151159
/// Generates a new tenant token.
11161160
///
11171161
/// # 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.

0 commit comments

Comments
 (0)