feat: Add pagination support to ListMediaParams and ListMediaOptions

This commit is contained in:
2025-11-15 17:54:00 +01:00
parent b80c4e0895
commit dd10211c63
4 changed files with 61 additions and 19 deletions

View File

@@ -1,10 +1,21 @@
use axum::{extract::{FromRequestParts, Query}, http::request::Parts}; use axum::{
use libertas_core::{error::CoreError, schema::{FilterParams, ListMediaOptions, MetadataFilter, SortOrder, SortParams}}; extract::{FromRequestParts, Query},
http::request::Parts,
};
use libertas_core::{
error::CoreError,
schema::{
FilterParams, ListMediaOptions, MetadataFilter, PaginationParams, SortOrder, SortParams,
},
};
use crate::{error::ApiError, schema::ListMediaParams, state::AppState}; use crate::{error::ApiError, schema::ListMediaParams, state::AppState};
pub struct ApiListMediaOptions(pub ListMediaOptions); pub struct ApiListMediaOptions(pub ListMediaOptions);
const DEFAULT_PAGE: u32 = 1;
const DEFAULT_LIMIT: u32 = 50;
impl From<ListMediaParams> for ListMediaOptions { impl From<ListMediaParams> for ListMediaOptions {
fn from(params: ListMediaParams) -> Self { fn from(params: ListMediaParams) -> Self {
let sort = params.sort_by.map(|field| { let sort = params.sort_by.map(|field| {
@@ -22,7 +33,8 @@ impl From<ListMediaParams> for ListMediaOptions {
None None
} else { } else {
Some( Some(
params.metadata params
.metadata
.into_iter() .into_iter()
.filter_map(|s| { .filter_map(|s| {
s.split_once(":").map(|(key, value)| MetadataFilter { s.split_once(":").map(|(key, value)| MetadataFilter {
@@ -30,16 +42,35 @@ impl From<ListMediaParams> for ListMediaOptions {
tag_value: value.to_string(), tag_value: value.to_string(),
}) })
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>(),
) )
}; };
let pagination = {
let page = params.page.unwrap_or(DEFAULT_PAGE);
let limit = params.limit.unwrap_or(DEFAULT_LIMIT);
let page = if page == 0 { DEFAULT_PAGE } else { page };
let limit = if limit > (DEFAULT_LIMIT * 2) {
DEFAULT_LIMIT * 2
} else {
limit
};
Some(PaginationParams { page, limit })
};
let filter = Some(FilterParams { let filter = Some(FilterParams {
mime_type: params.mime_type, mime_type: params.mime_type,
metadata_filters, metadata_filters,
}); });
ListMediaOptions { sort, filter } ListMediaOptions {
sort,
filter,
pagination,
}
} }
} }

View File

@@ -37,6 +37,8 @@ pub struct ListMediaParams {
pub mime_type: Option<String>, pub mime_type: Option<String>,
#[serde(default)] #[serde(default)]
pub metadata: Vec<String>, pub metadata: Vec<String>,
pub page: Option<u32>,
pub limit: Option<u32>,
} }
#[derive(Deserialize)] #[derive(Deserialize)]

View File

@@ -63,11 +63,17 @@ pub struct FilterParams {
// pub date_range: Option<(chrono::DateTime<chrono::Utc>, chrono::DateTime<chrono::Utc>)>, // pub date_range: Option<(chrono::DateTime<chrono::Utc>, chrono::DateTime<chrono::Utc>)>,
} }
#[derive(Debug, Clone, Copy)]
pub struct PaginationParams {
pub page: u32,
pub limit: u32,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ListMediaOptions { pub struct ListMediaOptions {
pub sort: Option<SortParams>, pub sort: Option<SortParams>,
pub filter: Option<FilterParams>, pub filter: Option<FilterParams>,
// pub pagination: Option<PaginationParams>, pub pagination: Option<PaginationParams>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@@ -99,12 +99,15 @@ impl QueryBuilder<ListMediaOptions> for MediaQueryBuilder {
} }
// --- 3. Apply Pagination (Future-Proofing Stub) --- // --- 3. Apply Pagination (Future-Proofing Stub) ---
// if let Some(pagination) = &options.pagination { if let Some(pagination) = &options.pagination {
// query.push(" LIMIT "); let limit = pagination.limit as i64;
// query.push_bind(pagination.limit); let offset = (pagination.page.saturating_sub(1) as i64) * limit;
// query.push(" OFFSET ");
// query.push_bind(pagination.offset); query.push(" LIMIT ");
// } query.push_bind(limit);
query.push(" OFFSET ");
query.push_bind(offset);
}
Ok(query) Ok(query)
} }