3889: Display the total number of tasks matching a filter/query r=dureuill a=Kerollmops

This PR returns a new field on the `/tasks` routes. The `total` field exposes the total number of tasks that matches the given filter/query. It is useful to display information on a user interface and can help understand when progress is made in processing tasks, i.e., the total number of tasks on `/tasks?statuses=succeeded` will increase over time.

Fixes #3888.

- [ ] Update the specs fo the `/tasks` route.

## How have I implemented it?

I found it much easier to run two times the task filtering system. Once with the original `from` and `limit` parameters and a second time without. The second call will return the total number of tasks that match the query, not only the number of tasks on the current page.

So far, in terms of performance, there doesn't seem to be any issue. I tried different filters with something like 250k tasks. Note that there is a limit of 1M tasks in the queue.

Co-authored-by: Clément Renault <clement@meilisearch.com>
This commit is contained in:
meili-bors[bot] 2023-07-06 10:23:09 +00:00 committed by GitHub
commit ff192bb480
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
95 changed files with 174 additions and 68 deletions

View File

@ -138,6 +138,12 @@ impl Query {
index_vec.push(index_uid); index_vec.push(index_uid);
Self { index_uids: Some(index_vec), ..self } Self { index_uids: Some(index_vec), ..self }
} }
// Removes the `from` and `limit` restrictions from the query.
// Useful to get the total number of tasks matching a filter.
pub fn without_limits(self) -> Self {
Query { limit: None, from: None, ..self }
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -822,7 +828,8 @@ impl IndexScheduler {
Ok(nbr_index_processing_tasks > 0) Ok(nbr_index_processing_tasks > 0)
} }
/// Return the task ids matching the query from the user's point of view. /// Return the task ids matching the query along with the total number of tasks
/// by ignoring the from and limit parameters from the user's point of view.
/// ///
/// There are two differences between an internal query and a query executed by /// There are two differences between an internal query and a query executed by
/// the user. /// the user.
@ -835,7 +842,13 @@ impl IndexScheduler {
rtxn: &RoTxn, rtxn: &RoTxn,
query: &Query, query: &Query,
filters: &meilisearch_auth::AuthFilter, filters: &meilisearch_auth::AuthFilter,
) -> Result<RoaringBitmap> { ) -> Result<(RoaringBitmap, u64)> {
// compute all tasks matching the filter by ignoring the limits, to find the number of tasks matching
// the filter.
// As this causes us to compute the filter twice it is slightly inefficient, but doing it this way spares
// us from modifying the underlying implementation, and the performance remains sufficient.
// Should this change, we would modify `get_task_ids` to directly return the number of matching tasks.
let total_tasks = self.get_task_ids(rtxn, &query.clone().without_limits())?;
let mut tasks = self.get_task_ids(rtxn, query)?; let mut tasks = self.get_task_ids(rtxn, query)?;
// If the query contains a list of index uid or there is a finite list of authorized indexes, // If the query contains a list of index uid or there is a finite list of authorized indexes,
@ -858,10 +871,11 @@ impl IndexScheduler {
} }
} }
Ok(tasks) Ok((tasks, total_tasks.len()))
} }
/// Return the tasks matching the query from the user's point of view. /// Return the tasks matching the query from the user's point of view along
/// with the total number of tasks matching the query, ignoring from and limit.
/// ///
/// There are two differences between an internal query and a query executed by /// There are two differences between an internal query and a query executed by
/// the user. /// the user.
@ -873,11 +887,10 @@ impl IndexScheduler {
&self, &self,
query: Query, query: Query,
filters: &meilisearch_auth::AuthFilter, filters: &meilisearch_auth::AuthFilter,
) -> Result<Vec<Task>> { ) -> Result<(Vec<Task>, u64)> {
let rtxn = self.env.read_txn()?; let rtxn = self.env.read_txn()?;
let tasks = self.get_task_ids_from_authorized_indexes(&rtxn, &query, filters)?; let (tasks, total) = self.get_task_ids_from_authorized_indexes(&rtxn, &query, filters)?;
let tasks = self.get_existing_tasks( let tasks = self.get_existing_tasks(
&rtxn, &rtxn,
tasks.into_iter().rev().take(query.limit.unwrap_or(u32::MAX) as usize), tasks.into_iter().rev().take(query.limit.unwrap_or(u32::MAX) as usize),
@ -888,16 +901,19 @@ impl IndexScheduler {
let ret = tasks.into_iter(); let ret = tasks.into_iter();
if processing.is_empty() { if processing.is_empty() {
Ok(ret.collect()) Ok((ret.collect(), total))
} else { } else {
Ok(ret Ok((
.map(|task| match processing.contains(task.uid) { ret.map(|task| {
true => { if processing.contains(task.uid) {
Task { status: Status::Processing, started_at: Some(started_at), ..task } Task { status: Status::Processing, started_at: Some(started_at), ..task }
} else {
task
} }
false => task,
}) })
.collect()) .collect(),
total,
))
} }
} }
@ -2781,43 +2797,43 @@ mod tests {
let rtxn = index_scheduler.env.read_txn().unwrap(); let rtxn = index_scheduler.env.read_txn().unwrap();
let query = Query { limit: Some(0), ..Default::default() }; let query = Query { limit: Some(0), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[]"); snapshot!(snapshot_bitmap(&tasks), @"[]");
let query = Query { limit: Some(1), ..Default::default() }; let query = Query { limit: Some(1), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[2,]"); snapshot!(snapshot_bitmap(&tasks), @"[2,]");
let query = Query { limit: Some(2), ..Default::default() }; let query = Query { limit: Some(2), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[1,2,]"); snapshot!(snapshot_bitmap(&tasks), @"[1,2,]");
let query = Query { from: Some(1), ..Default::default() }; let query = Query { from: Some(1), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[0,1,]"); snapshot!(snapshot_bitmap(&tasks), @"[0,1,]");
let query = Query { from: Some(2), ..Default::default() }; let query = Query { from: Some(2), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[0,1,2,]"); snapshot!(snapshot_bitmap(&tasks), @"[0,1,2,]");
let query = Query { from: Some(1), limit: Some(1), ..Default::default() }; let query = Query { from: Some(1), limit: Some(1), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[1,]"); snapshot!(snapshot_bitmap(&tasks), @"[1,]");
let query = Query { from: Some(1), limit: Some(2), ..Default::default() }; let query = Query { from: Some(1), limit: Some(2), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[0,1,]"); snapshot!(snapshot_bitmap(&tasks), @"[0,1,]");
@ -2844,13 +2860,13 @@ mod tests {
let rtxn = index_scheduler.env.read_txn().unwrap(); let rtxn = index_scheduler.env.read_txn().unwrap();
let query = Query { statuses: Some(vec![Status::Processing]), ..Default::default() }; let query = Query { statuses: Some(vec![Status::Processing]), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[0,]"); // only the processing tasks in the first tick snapshot!(snapshot_bitmap(&tasks), @"[0,]"); // only the processing tasks in the first tick
let query = Query { statuses: Some(vec![Status::Enqueued]), ..Default::default() }; let query = Query { statuses: Some(vec![Status::Enqueued]), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[1,2,]"); // only the enqueued tasks in the first tick snapshot!(snapshot_bitmap(&tasks), @"[1,2,]"); // only the enqueued tasks in the first tick
@ -2859,7 +2875,7 @@ mod tests {
statuses: Some(vec![Status::Enqueued, Status::Processing]), statuses: Some(vec![Status::Enqueued, Status::Processing]),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
snapshot!(snapshot_bitmap(&tasks), @"[0,1,2,]"); // both enqueued and processing tasks in the first tick snapshot!(snapshot_bitmap(&tasks), @"[0,1,2,]"); // both enqueued and processing tasks in the first tick
@ -2869,7 +2885,7 @@ mod tests {
after_started_at: Some(start_time), after_started_at: Some(start_time),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// both enqueued and processing tasks in the first tick, but limited to those with a started_at // both enqueued and processing tasks in the first tick, but limited to those with a started_at
@ -2881,7 +2897,7 @@ mod tests {
before_started_at: Some(start_time), before_started_at: Some(start_time),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// both enqueued and processing tasks in the first tick, but limited to those with a started_at // both enqueued and processing tasks in the first tick, but limited to those with a started_at
@ -2894,7 +2910,7 @@ mod tests {
before_started_at: Some(start_time + Duration::minutes(1)), before_started_at: Some(start_time + Duration::minutes(1)),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// both enqueued and processing tasks in the first tick, but limited to those with a started_at // both enqueued and processing tasks in the first tick, but limited to those with a started_at
@ -2921,7 +2937,7 @@ mod tests {
before_started_at: Some(start_time + Duration::minutes(1)), before_started_at: Some(start_time + Duration::minutes(1)),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// both succeeded and processing tasks in the first tick, but limited to those with a started_at // both succeeded and processing tasks in the first tick, but limited to those with a started_at
@ -2934,7 +2950,7 @@ mod tests {
before_started_at: Some(start_time), before_started_at: Some(start_time),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// both succeeded and processing tasks in the first tick, but limited to those with a started_at // both succeeded and processing tasks in the first tick, but limited to those with a started_at
@ -2947,7 +2963,7 @@ mod tests {
before_started_at: Some(second_start_time + Duration::minutes(1)), before_started_at: Some(second_start_time + Duration::minutes(1)),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// both succeeded and processing tasks in the first tick, but limited to those with a started_at // both succeeded and processing tasks in the first tick, but limited to those with a started_at
@ -2967,7 +2983,7 @@ mod tests {
let rtxn = index_scheduler.env.read_txn().unwrap(); let rtxn = index_scheduler.env.read_txn().unwrap();
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// we run the same query to verify that, and indeed find that the last task is matched // we run the same query to verify that, and indeed find that the last task is matched
@ -2979,7 +2995,7 @@ mod tests {
before_started_at: Some(second_start_time + Duration::minutes(1)), before_started_at: Some(second_start_time + Duration::minutes(1)),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// enqueued, succeeded, or processing tasks started after the second part of the test, should // enqueued, succeeded, or processing tasks started after the second part of the test, should
@ -2991,7 +3007,7 @@ mod tests {
// now the last task should have failed // now the last task should have failed
snapshot!(snapshot_index_scheduler(&index_scheduler), name: "end"); snapshot!(snapshot_index_scheduler(&index_scheduler), name: "end");
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// so running the last query should return nothing // so running the last query should return nothing
@ -3003,7 +3019,7 @@ mod tests {
before_started_at: Some(second_start_time + Duration::minutes(1)), before_started_at: Some(second_start_time + Duration::minutes(1)),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// but the same query on failed tasks should return the last task // but the same query on failed tasks should return the last task
@ -3015,7 +3031,7 @@ mod tests {
before_started_at: Some(second_start_time + Duration::minutes(1)), before_started_at: Some(second_start_time + Duration::minutes(1)),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// but the same query on failed tasks should return the last task // but the same query on failed tasks should return the last task
@ -3028,7 +3044,7 @@ mod tests {
before_started_at: Some(second_start_time + Duration::minutes(1)), before_started_at: Some(second_start_time + Duration::minutes(1)),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// same query but with an invalid uid // same query but with an invalid uid
@ -3041,7 +3057,7 @@ mod tests {
before_started_at: Some(second_start_time + Duration::minutes(1)), before_started_at: Some(second_start_time + Duration::minutes(1)),
..Default::default() ..Default::default()
}; };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// same query but with a valid uid // same query but with a valid uid
@ -3073,14 +3089,14 @@ mod tests {
let rtxn = index_scheduler.env.read_txn().unwrap(); let rtxn = index_scheduler.env.read_txn().unwrap();
let query = Query { index_uids: Some(vec!["catto".to_owned()]), ..Default::default() }; let query = Query { index_uids: Some(vec!["catto".to_owned()]), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// only the first task associated with catto is returned, the indexSwap tasks are excluded! // only the first task associated with catto is returned, the indexSwap tasks are excluded!
snapshot!(snapshot_bitmap(&tasks), @"[0,]"); snapshot!(snapshot_bitmap(&tasks), @"[0,]");
let query = Query { index_uids: Some(vec!["catto".to_owned()]), ..Default::default() }; let query = Query { index_uids: Some(vec!["catto".to_owned()]), ..Default::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes( .get_task_ids_from_authorized_indexes(
&rtxn, &rtxn,
&query, &query,
@ -3094,7 +3110,7 @@ mod tests {
snapshot!(snapshot_bitmap(&tasks), @"[]"); snapshot!(snapshot_bitmap(&tasks), @"[]");
let query = Query::default(); let query = Query::default();
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes( .get_task_ids_from_authorized_indexes(
&rtxn, &rtxn,
&query, &query,
@ -3108,7 +3124,7 @@ mod tests {
snapshot!(snapshot_bitmap(&tasks), @"[1,]"); snapshot!(snapshot_bitmap(&tasks), @"[1,]");
let query = Query::default(); let query = Query::default();
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes( .get_task_ids_from_authorized_indexes(
&rtxn, &rtxn,
&query, &query,
@ -3127,7 +3143,7 @@ mod tests {
snapshot!(snapshot_bitmap(&tasks), @"[0,1,]"); snapshot!(snapshot_bitmap(&tasks), @"[0,1,]");
let query = Query::default(); let query = Query::default();
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// we asked for all the tasks with all index authorized -> all tasks returned // we asked for all the tasks with all index authorized -> all tasks returned
@ -3160,7 +3176,7 @@ mod tests {
let rtxn = index_scheduler.read_txn().unwrap(); let rtxn = index_scheduler.read_txn().unwrap();
let query = Query { canceled_by: Some(vec![task_cancelation.uid]), ..Query::default() }; let query = Query { canceled_by: Some(vec![task_cancelation.uid]), ..Query::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default()) .get_task_ids_from_authorized_indexes(&rtxn, &query, &AuthFilter::default())
.unwrap(); .unwrap();
// 0 is not returned because it was not canceled, 3 is not returned because it is the uid of the // 0 is not returned because it was not canceled, 3 is not returned because it is the uid of the
@ -3168,7 +3184,7 @@ mod tests {
snapshot!(snapshot_bitmap(&tasks), @"[1,2,]"); snapshot!(snapshot_bitmap(&tasks), @"[1,2,]");
let query = Query { canceled_by: Some(vec![task_cancelation.uid]), ..Query::default() }; let query = Query { canceled_by: Some(vec![task_cancelation.uid]), ..Query::default() };
let tasks = index_scheduler let (tasks, _) = index_scheduler
.get_task_ids_from_authorized_indexes( .get_task_ids_from_authorized_indexes(
&rtxn, &rtxn,
&query, &query,

View File

@ -325,7 +325,7 @@ async fn cancel_tasks(
let query = params.into_query(); let query = params.into_query();
let tasks = index_scheduler.get_task_ids_from_authorized_indexes( let (tasks, _) = index_scheduler.get_task_ids_from_authorized_indexes(
&index_scheduler.read_txn()?, &index_scheduler.read_txn()?,
&query, &query,
index_scheduler.filters(), index_scheduler.filters(),
@ -370,7 +370,7 @@ async fn delete_tasks(
); );
let query = params.into_query(); let query = params.into_query();
let tasks = index_scheduler.get_task_ids_from_authorized_indexes( let (tasks, _) = index_scheduler.get_task_ids_from_authorized_indexes(
&index_scheduler.read_txn()?, &index_scheduler.read_txn()?,
&query, &query,
index_scheduler.filters(), index_scheduler.filters(),
@ -387,6 +387,7 @@ async fn delete_tasks(
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct AllTasks { pub struct AllTasks {
results: Vec<TaskView>, results: Vec<TaskView>,
total: u64,
limit: u32, limit: u32,
from: Option<u32>, from: Option<u32>,
next: Option<u32>, next: Option<u32>,
@ -406,23 +407,17 @@ async fn get_tasks(
let limit = params.limit.0; let limit = params.limit.0;
let query = params.into_query(); let query = params.into_query();
let mut tasks_results: Vec<TaskView> = index_scheduler let filters = index_scheduler.filters();
.get_tasks_from_authorized_indexes(query, index_scheduler.filters())? let (tasks, total) = index_scheduler.get_tasks_from_authorized_indexes(query, filters)?;
.into_iter() let mut results: Vec<_> = tasks.iter().map(TaskView::from_task).collect();
.map(|t| TaskView::from_task(&t))
.collect();
// If we were able to fetch the number +1 tasks we asked // If we were able to fetch the number +1 tasks we asked
// it means that there is more to come. // it means that there is more to come.
let next = if tasks_results.len() == limit as usize { let next = if results.len() == limit as usize { results.pop().map(|t| t.uid) } else { None };
tasks_results.pop().map(|t| t.uid)
} else {
None
};
let from = tasks_results.first().map(|t| t.uid); let from = results.first().map(|t| t.uid);
let tasks = AllTasks { results, limit: limit.saturating_sub(1), total, from, next };
let tasks = AllTasks { results: tasks_results, limit: limit.saturating_sub(1), from, next };
Ok(HttpResponse::Ok().json(tasks)) Ok(HttpResponse::Ok().json(tasks))
} }
@ -444,10 +439,10 @@ async fn get_task(
analytics.publish("Tasks Seen".to_string(), json!({ "per_task_uid": true }), Some(&req)); analytics.publish("Tasks Seen".to_string(), json!({ "per_task_uid": true }), Some(&req));
let query = index_scheduler::Query { uids: Some(vec![task_uid]), ..Query::default() }; let query = index_scheduler::Query { uids: Some(vec![task_uid]), ..Query::default() };
let filters = index_scheduler.filters();
let (tasks, _) = index_scheduler.get_tasks_from_authorized_indexes(query, filters)?;
if let Some(task) = if let Some(task) = tasks.first() {
index_scheduler.get_tasks_from_authorized_indexes(query, index_scheduler.filters())?.first()
{
let task_view = TaskView::from_task(task); let task_view = TaskView::from_task(task);
Ok(HttpResponse::Ok().json(task_view)) Ok(HttpResponse::Ok().json(task_view))
} else { } else {

View File

@ -43,7 +43,7 @@ async fn import_dump_v1_movie_raw() {
assert_eq!(code, 200); assert_eq!(code, 200);
assert_eq!( assert_eq!(
tasks, tasks,
json!({ "results": [{"uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31968 }, "error": null, "duration": "PT9.317060500S", "enqueuedAt": "2021-09-08T09:08:45.153219Z", "startedAt": "2021-09-08T09:08:45.3961665Z", "finishedAt": "2021-09-08T09:08:54.713227Z" }], "limit": 20, "from": 0, "next": null }) json!({ "results": [{"uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31968 }, "error": null, "duration": "PT9.317060500S", "enqueuedAt": "2021-09-08T09:08:45.153219Z", "startedAt": "2021-09-08T09:08:45.3961665Z", "finishedAt": "2021-09-08T09:08:54.713227Z" }], "total": 1, "limit": 20, "from": 0, "next": null })
); );
// finally we're just going to check that we can still get a few documents by id // finally we're just going to check that we can still get a few documents by id
@ -135,7 +135,7 @@ async fn import_dump_v1_movie_with_settings() {
assert_eq!(code, 200); assert_eq!(code, 200);
assert_eq!( assert_eq!(
tasks, tasks,
json!({ "results": [{ "uid": 1, "indexUid": "indexUID", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, "details": { "displayedAttributes": ["genres", "id", "overview", "poster", "release_date", "title"], "searchableAttributes": ["title", "overview"], "filterableAttributes": ["genres"], "sortableAttributes": ["genres"], "stopWords": ["of", "the"] }, "error": null, "duration": "PT7.288826907S", "enqueuedAt": "2021-09-08T09:34:40.882977Z", "startedAt": "2021-09-08T09:34:40.883073093Z", "finishedAt": "2021-09-08T09:34:48.1719Z"}, { "uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31968 }, "error": null, "duration": "PT9.090735774S", "enqueuedAt": "2021-09-08T09:34:16.036101Z", "startedAt": "2021-09-08T09:34:16.261191226Z", "finishedAt": "2021-09-08T09:34:25.351927Z" }], "limit": 20, "from": 1, "next": null }) json!({ "results": [{ "uid": 1, "indexUid": "indexUID", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, "details": { "displayedAttributes": ["genres", "id", "overview", "poster", "release_date", "title"], "searchableAttributes": ["title", "overview"], "filterableAttributes": ["genres"], "sortableAttributes": ["genres"], "stopWords": ["of", "the"] }, "error": null, "duration": "PT7.288826907S", "enqueuedAt": "2021-09-08T09:34:40.882977Z", "startedAt": "2021-09-08T09:34:40.883073093Z", "finishedAt": "2021-09-08T09:34:48.1719Z"}, { "uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31968 }, "error": null, "duration": "PT9.090735774S", "enqueuedAt": "2021-09-08T09:34:16.036101Z", "startedAt": "2021-09-08T09:34:16.261191226Z", "finishedAt": "2021-09-08T09:34:25.351927Z" }], "total": 2, "limit": 20, "from": 1, "next": null })
); );
// finally we're just going to check that we can still get a few documents by id // finally we're just going to check that we can still get a few documents by id
@ -317,7 +317,7 @@ async fn import_dump_v2_movie_raw() {
assert_eq!(code, 200); assert_eq!(code, 200);
assert_eq!( assert_eq!(
tasks, tasks,
json!({ "results": [{"uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT41.751156S", "enqueuedAt": "2021-09-08T08:30:30.550282Z", "startedAt": "2021-09-08T08:30:30.553012Z", "finishedAt": "2021-09-08T08:31:12.304168Z" }], "limit": 20, "from": 0, "next": null }) json!({ "results": [{"uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT41.751156S", "enqueuedAt": "2021-09-08T08:30:30.550282Z", "startedAt": "2021-09-08T08:30:30.553012Z", "finishedAt": "2021-09-08T08:31:12.304168Z" }], "total": 1, "limit": 20, "from": 0, "next": null })
); );
// finally we're just going to check that we can still get a few documents by id // finally we're just going to check that we can still get a few documents by id
@ -409,7 +409,7 @@ async fn import_dump_v2_movie_with_settings() {
assert_eq!(code, 200); assert_eq!(code, 200);
assert_eq!( assert_eq!(
tasks, tasks,
json!({ "results": [{ "uid": 1, "indexUid": "indexUID", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, "details": { "displayedAttributes": ["title", "genres", "overview", "poster", "release_date"], "searchableAttributes": ["title", "overview"], "filterableAttributes": ["genres"], "stopWords": ["of", "the"] }, "error": null, "duration": "PT37.488777S", "enqueuedAt": "2021-09-08T08:24:02.323444Z", "startedAt": "2021-09-08T08:24:02.324145Z", "finishedAt": "2021-09-08T08:24:39.812922Z" }, { "uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT39.941318S", "enqueuedAt": "2021-09-08T08:21:14.742672Z", "startedAt": "2021-09-08T08:21:14.750166Z", "finishedAt": "2021-09-08T08:21:54.691484Z" }], "limit": 20, "from": 1, "next": null }) json!({ "results": [{ "uid": 1, "indexUid": "indexUID", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, "details": { "displayedAttributes": ["title", "genres", "overview", "poster", "release_date"], "searchableAttributes": ["title", "overview"], "filterableAttributes": ["genres"], "stopWords": ["of", "the"] }, "error": null, "duration": "PT37.488777S", "enqueuedAt": "2021-09-08T08:24:02.323444Z", "startedAt": "2021-09-08T08:24:02.324145Z", "finishedAt": "2021-09-08T08:24:39.812922Z" }, { "uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT39.941318S", "enqueuedAt": "2021-09-08T08:21:14.742672Z", "startedAt": "2021-09-08T08:21:14.750166Z", "finishedAt": "2021-09-08T08:21:54.691484Z" }], "total": 2, "limit": 20, "from": 1, "next": null })
); );
// finally we're just going to check that we can still get a few documents by id // finally we're just going to check that we can still get a few documents by id
@ -591,7 +591,7 @@ async fn import_dump_v3_movie_raw() {
assert_eq!(code, 200); assert_eq!(code, 200);
assert_eq!( assert_eq!(
tasks, tasks,
json!({ "results": [{"uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT41.751156S", "enqueuedAt": "2021-09-08T08:30:30.550282Z", "startedAt": "2021-09-08T08:30:30.553012Z", "finishedAt": "2021-09-08T08:31:12.304168Z" }], "limit": 20, "from": 0, "next": null }) json!({ "results": [{"uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT41.751156S", "enqueuedAt": "2021-09-08T08:30:30.550282Z", "startedAt": "2021-09-08T08:30:30.553012Z", "finishedAt": "2021-09-08T08:31:12.304168Z" }], "total": 1, "limit": 20, "from": 0, "next": null })
); );
// finally we're just going to check that we can still get a few documents by id // finally we're just going to check that we can still get a few documents by id
@ -683,7 +683,7 @@ async fn import_dump_v3_movie_with_settings() {
assert_eq!(code, 200); assert_eq!(code, 200);
assert_eq!( assert_eq!(
tasks, tasks,
json!({ "results": [{ "uid": 1, "indexUid": "indexUID", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, "details": { "displayedAttributes": ["title", "genres", "overview", "poster", "release_date"], "searchableAttributes": ["title", "overview"], "filterableAttributes": ["genres"], "stopWords": ["of", "the"] }, "error": null, "duration": "PT37.488777S", "enqueuedAt": "2021-09-08T08:24:02.323444Z", "startedAt": "2021-09-08T08:24:02.324145Z", "finishedAt": "2021-09-08T08:24:39.812922Z" }, { "uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT39.941318S", "enqueuedAt": "2021-09-08T08:21:14.742672Z", "startedAt": "2021-09-08T08:21:14.750166Z", "finishedAt": "2021-09-08T08:21:54.691484Z" }], "limit": 20, "from": 1, "next": null }) json!({ "results": [{ "uid": 1, "indexUid": "indexUID", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, "details": { "displayedAttributes": ["title", "genres", "overview", "poster", "release_date"], "searchableAttributes": ["title", "overview"], "filterableAttributes": ["genres"], "stopWords": ["of", "the"] }, "error": null, "duration": "PT37.488777S", "enqueuedAt": "2021-09-08T08:24:02.323444Z", "startedAt": "2021-09-08T08:24:02.324145Z", "finishedAt": "2021-09-08T08:24:39.812922Z" }, { "uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT39.941318S", "enqueuedAt": "2021-09-08T08:21:14.742672Z", "startedAt": "2021-09-08T08:21:14.750166Z", "finishedAt": "2021-09-08T08:21:54.691484Z" }], "total": 2, "limit": 20, "from": 1, "next": null })
); );
// finally we're just going to check that we can["results"] still get a few documents by id // finally we're just going to check that we can["results"] still get a few documents by id
@ -865,7 +865,7 @@ async fn import_dump_v4_movie_raw() {
assert_eq!(code, 200); assert_eq!(code, 200);
assert_eq!( assert_eq!(
tasks, tasks,
json!({ "results": [{"uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT41.751156S", "enqueuedAt": "2021-09-08T08:30:30.550282Z", "startedAt": "2021-09-08T08:30:30.553012Z", "finishedAt": "2021-09-08T08:31:12.304168Z" }], "limit" : 20, "from": 0, "next": null }) json!({ "results": [{"uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT41.751156S", "enqueuedAt": "2021-09-08T08:30:30.550282Z", "startedAt": "2021-09-08T08:30:30.553012Z", "finishedAt": "2021-09-08T08:31:12.304168Z" }], "total": 1, "limit" : 20, "from": 0, "next": null })
); );
// finally we're just going to check that we can still get a few documents by id // finally we're just going to check that we can still get a few documents by id
@ -957,7 +957,7 @@ async fn import_dump_v4_movie_with_settings() {
assert_eq!(code, 200); assert_eq!(code, 200);
assert_eq!( assert_eq!(
tasks, tasks,
json!({ "results": [{ "uid": 1, "indexUid": "indexUID", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, "details": { "displayedAttributes": ["title", "genres", "overview", "poster", "release_date"], "searchableAttributes": ["title", "overview"], "filterableAttributes": ["genres"], "stopWords": ["of", "the"] }, "error": null, "duration": "PT37.488777S", "enqueuedAt": "2021-09-08T08:24:02.323444Z", "startedAt": "2021-09-08T08:24:02.324145Z", "finishedAt": "2021-09-08T08:24:39.812922Z" }, { "uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT39.941318S", "enqueuedAt": "2021-09-08T08:21:14.742672Z", "startedAt": "2021-09-08T08:21:14.750166Z", "finishedAt": "2021-09-08T08:21:54.691484Z" }], "limit": 20, "from": 1, "next": null }) json!({ "results": [{ "uid": 1, "indexUid": "indexUID", "status": "succeeded", "type": "settingsUpdate", "canceledBy": null, "details": { "displayedAttributes": ["title", "genres", "overview", "poster", "release_date"], "searchableAttributes": ["title", "overview"], "filterableAttributes": ["genres"], "stopWords": ["of", "the"] }, "error": null, "duration": "PT37.488777S", "enqueuedAt": "2021-09-08T08:24:02.323444Z", "startedAt": "2021-09-08T08:24:02.324145Z", "finishedAt": "2021-09-08T08:24:39.812922Z" }, { "uid": 0, "indexUid": "indexUID", "status": "succeeded", "type": "documentAdditionOrUpdate", "canceledBy": null, "details": { "receivedDocuments": 0, "indexedDocuments": 31944 }, "error": null, "duration": "PT39.941318S", "enqueuedAt": "2021-09-08T08:21:14.742672Z", "startedAt": "2021-09-08T08:21:14.750166Z", "finishedAt": "2021-09-08T08:21:54.691484Z" }], "total": 2, "limit": 20, "from": 1, "next": null })
); );
// finally we're just going to check that we can still get a few documents by id // finally we're just going to check that we can still get a few documents by id

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:08:54.713227Z" "finishedAt": "2021-09-08T09:08:54.713227Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:08:54.713227Z" "finishedAt": "2021-09-08T09:08:54.713227Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:08:54.713227Z" "finishedAt": "2021-09-08T09:08:54.713227Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:08:54.713227Z" "finishedAt": "2021-09-08T09:08:54.713227Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:08:54.713227Z" "finishedAt": "2021-09-08T09:08:54.713227Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:08:54.713227Z" "finishedAt": "2021-09-08T09:08:54.713227Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:08:54.713227Z" "finishedAt": "2021-09-08T09:08:54.713227Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:34:25.351927Z" "finishedAt": "2021-09-08T09:34:25.351927Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:34:25.351927Z" "finishedAt": "2021-09-08T09:34:25.351927Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -40,6 +40,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:34:48.1719Z" "finishedAt": "2021-09-08T09:34:48.1719Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -40,6 +40,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:34:48.1719Z" "finishedAt": "2021-09-08T09:34:48.1719Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -40,6 +40,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:34:48.1719Z" "finishedAt": "2021-09-08T09:34:48.1719Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -40,6 +40,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:34:48.1719Z" "finishedAt": "2021-09-08T09:34:48.1719Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -40,6 +40,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:34:48.1719Z" "finishedAt": "2021-09-08T09:34:48.1719Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -45,6 +45,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:26:57.319083Z" "finishedAt": "2021-09-08T09:26:57.319083Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:28:46.369971Z" "finishedAt": "2021-09-08T09:28:46.369971Z"
} }
], ],
"total": 92,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:28:46.369971Z" "finishedAt": "2021-09-08T09:28:46.369971Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:28:46.369971Z" "finishedAt": "2021-09-08T09:28:46.369971Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:28:46.369971Z" "finishedAt": "2021-09-08T09:28:46.369971Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:28:46.369971Z" "finishedAt": "2021-09-08T09:28:46.369971Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T09:28:46.369971Z" "finishedAt": "2021-09-08T09:28:46.369971Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:21:54.691484Z" "finishedAt": "2021-09-08T08:21:54.691484Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:21:54.691484Z" "finishedAt": "2021-09-08T08:21:54.691484Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -41,6 +41,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:40:28.669652Z" "finishedAt": "2021-09-08T08:40:28.669652Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 92,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:21:54.691484Z" "finishedAt": "2021-09-08T08:21:54.691484Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:21:54.691484Z" "finishedAt": "2021-09-08T08:21:54.691484Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -41,6 +41,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:40:28.669652Z" "finishedAt": "2021-09-08T08:40:28.669652Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 92,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:31:12.304168Z" "finishedAt": "2021-09-08T08:31:12.304168Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:21:54.691484Z" "finishedAt": "2021-09-08T08:21:54.691484Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:21:54.691484Z" "finishedAt": "2021-09-08T08:21:54.691484Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -36,6 +36,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:24:39.812922Z" "finishedAt": "2021-09-08T08:24:39.812922Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -41,6 +41,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:40:28.669652Z" "finishedAt": "2021-09-08T08:40:28.669652Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 92,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2021-09-08T08:51:53.095314Z" "finishedAt": "2021-09-08T08:51:53.095314Z"
} }
], ],
"total": 93,
"limit": 1, "limit": 1,
"from": 92, "from": 92,
"next": 91 "next": 91

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2022-06-08T14:59:24.804443Z" "finishedAt": "2022-06-08T14:59:24.804443Z"
} }
], ],
"total": 1,
"limit": 1, "limit": 1,
"from": 0, "from": 0,
"next": null "next": null

View File

@ -20,6 +20,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "2022-06-08T14:59:29.997781Z" "finishedAt": "2022-06-08T14:59:29.997781Z"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 1, "from": 1,
"next": 0 "next": 0

View File

@ -19,6 +19,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 5,
"limit": 1, "limit": 1,
"from": 4, "from": 4,
"next": 3 "next": 3

View File

@ -24,6 +24,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 2,
"limit": 1, "limit": 1,
"from": 2, "from": 2,
"next": 0 "next": 0

View File

@ -19,6 +19,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 5,
"limit": 1, "limit": 1,
"from": 4, "from": 4,
"next": 3 "next": 3

View File

@ -19,6 +19,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 5,
"limit": 1, "limit": 1,
"from": 4, "from": 4,
"next": 3 "next": 3

View File

@ -19,6 +19,7 @@ source: meilisearch/tests/dumps/mod.rs
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 5,
"limit": 1, "limit": 1,
"from": 4, "from": 4,
"next": 3 "next": 3

View File

@ -55,6 +55,7 @@ async fn swap_indexes() {
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 2,
"limit": 20, "limit": 20,
"from": 1, "from": 1,
"next": null "next": null
@ -128,6 +129,7 @@ async fn swap_indexes() {
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 3,
"limit": 20, "limit": 20,
"from": 2, "from": 2,
"next": null "next": null
@ -193,6 +195,7 @@ async fn swap_indexes() {
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 5,
"limit": 2, "limit": 2,
"from": 4, "from": 4,
"next": 2 "next": 2
@ -336,6 +339,7 @@ async fn swap_indexes() {
"finishedAt": "[date]" "finishedAt": "[date]"
} }
], ],
"total": 6,
"limit": 20, "limit": 20,
"from": 5, "from": 5,
"next": null "next": null