Implement the seek-based tasks list pagination

This commit is contained in:
Kerollmops 2022-05-31 11:56:51 +02:00
parent d22f07f5b2
commit 9d5cc88cd5
No known key found for this signature in database
GPG Key ID: 92ADA4E935E71FA4
2 changed files with 32 additions and 13 deletions

View File

@ -26,6 +26,8 @@ pub struct TaskFilterQuery {
type_: Option<CS<StarOr<TaskType>>>, type_: Option<CS<StarOr<TaskType>>>,
status: Option<CS<StarOr<TaskStatus>>>, status: Option<CS<StarOr<TaskStatus>>>,
index_uid: Option<CS<StarOr<IndexUid>>>, index_uid: Option<CS<StarOr<IndexUid>>>,
limit: Option<usize>, // TODO must not return an error when deser fail
after: Option<TaskId>, // TODO must not return an error when deser fail
} }
#[rustfmt::skip] #[rustfmt::skip]
@ -68,11 +70,13 @@ async fn get_tasks(
type_, type_,
status, status,
index_uid, index_uid,
limit,
after,
} = params.into_inner(); } = params.into_inner();
let search_rules = &meilisearch.filters().search_rules; let search_rules = &meilisearch.filters().search_rules;
// We first tranform a potential indexUid=* into a "not specified indexUid filter" // We first transform a potential indexUid=* into a "not specified indexUid filter"
// for every one of the filters: type, status, and indexUid. // for every one of the filters: type, status, and indexUid.
let type_ = type_.map(CS::into_inner).and_then(fold_star_or); let type_ = type_.map(CS::into_inner).and_then(fold_star_or);
let status = status.map(CS::into_inner).and_then(fold_star_or); let status = status.map(CS::into_inner).and_then(fold_star_or);
@ -128,13 +132,32 @@ async fn get_tasks(
indexes_filters indexes_filters
}; };
let tasks: TaskListView = meilisearch // We +1 just to know if there is more after this "page" or not.
.list_tasks(filters, None, None) let limit = limit.unwrap_or(DEFAULT_LIMIT).saturating_add(1);
// We -1 here because we need an offset and we must exclude the `after` one.
let offset = after.map(|n| n.saturating_sub(1));
let mut tasks_results = meilisearch
.list_tasks(filters, Some(limit), offset)
.await? .await?
.into_iter() .into_iter()
.map(TaskView::from) .map(TaskView::from)
.collect::<Vec<_>>() .collect::<Vec<_>>();
.into();
// If we were able to fetch the number +1 tasks we asked
// it means that there is more to come.
let after = if tasks_results.len() == limit {
tasks_results.pop();
tasks_results.last().map(|t| t.uid)
} else {
None
};
let tasks = TaskListView {
results: tasks_results,
limit: limit.saturating_sub(1),
after,
};
Ok(HttpResponse::Ok().json(tasks)) Ok(HttpResponse::Ok().json(tasks))
} }

View File

@ -180,7 +180,7 @@ fn serialize_duration<S: Serializer>(
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct TaskView { pub struct TaskView {
uid: TaskId, pub uid: TaskId,
index_uid: Option<String>, index_uid: Option<String>,
status: TaskStatus, status: TaskStatus,
#[serde(rename = "type")] #[serde(rename = "type")]
@ -369,13 +369,9 @@ impl From<Task> for TaskView {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct TaskListView { pub struct TaskListView {
results: Vec<TaskView>, pub results: Vec<TaskView>,
} pub limit: usize,
pub after: Option<TaskId>,
impl From<Vec<TaskView>> for TaskListView {
fn from(results: Vec<TaskView>) -> Self {
Self { results }
}
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]