diff --git a/libertas_api/src/extractors/query_options.rs b/libertas_api/src/extractors/query_options.rs index d3d4adf..5154e65 100644 --- a/libertas_api/src/extractors/query_options.rs +++ b/libertas_api/src/extractors/query_options.rs @@ -1,10 +1,21 @@ -use axum::{extract::{FromRequestParts, Query}, http::request::Parts}; -use libertas_core::{error::CoreError, schema::{FilterParams, ListMediaOptions, MetadataFilter, SortOrder, SortParams}}; +use axum::{ + 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}; pub struct ApiListMediaOptions(pub ListMediaOptions); +const DEFAULT_PAGE: u32 = 1; +const DEFAULT_LIMIT: u32 = 50; + impl From for ListMediaOptions { fn from(params: ListMediaParams) -> Self { let sort = params.sort_by.map(|field| { @@ -22,24 +33,44 @@ impl From for ListMediaOptions { None } else { Some( - params.metadata - .into_iter() - .filter_map(|s| { - s.split_once(":").map(|(key, value)| MetadataFilter { - tag_name: key.to_string(), - tag_value: value.to_string(), + params + .metadata + .into_iter() + .filter_map(|s| { + s.split_once(":").map(|(key, value)| MetadataFilter { + tag_name: key.to_string(), + tag_value: value.to_string(), + }) }) - }) - .collect::>() + .collect::>(), ) }; + 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 { mime_type: params.mime_type, metadata_filters, }); - ListMediaOptions { sort, filter } + ListMediaOptions { + sort, + filter, + pagination, + } } } @@ -56,4 +87,4 @@ impl FromRequestParts for ApiListMediaOptions { Ok(ApiListMediaOptions(params.into())) } -} \ No newline at end of file +} diff --git a/libertas_api/src/schema.rs b/libertas_api/src/schema.rs index 1312523..1edd940 100644 --- a/libertas_api/src/schema.rs +++ b/libertas_api/src/schema.rs @@ -37,6 +37,8 @@ pub struct ListMediaParams { pub mime_type: Option, #[serde(default)] pub metadata: Vec, + pub page: Option, + pub limit: Option, } #[derive(Deserialize)] diff --git a/libertas_core/src/schema.rs b/libertas_core/src/schema.rs index 6ed3a2a..dff75b4 100644 --- a/libertas_core/src/schema.rs +++ b/libertas_core/src/schema.rs @@ -63,11 +63,17 @@ pub struct FilterParams { // pub date_range: Option<(chrono::DateTime, chrono::DateTime)>, } +#[derive(Debug, Clone, Copy)] +pub struct PaginationParams { + pub page: u32, + pub limit: u32, +} + #[derive(Debug, Clone)] pub struct ListMediaOptions { pub sort: Option, pub filter: Option, - // pub pagination: Option, + pub pagination: Option, } #[derive(Debug, Clone)] diff --git a/libertas_infra/src/query_builder.rs b/libertas_infra/src/query_builder.rs index 5c1db4d..02c6923 100644 --- a/libertas_infra/src/query_builder.rs +++ b/libertas_infra/src/query_builder.rs @@ -99,12 +99,15 @@ impl QueryBuilder for MediaQueryBuilder { } // --- 3. Apply Pagination (Future-Proofing Stub) --- - // if let Some(pagination) = &options.pagination { - // query.push(" LIMIT "); - // query.push_bind(pagination.limit); - // query.push(" OFFSET "); - // query.push_bind(pagination.offset); - // } + if let Some(pagination) = &options.pagination { + let limit = pagination.limit as i64; + let offset = (pagination.page.saturating_sub(1) as i64) * limit; + + query.push(" LIMIT "); + query.push_bind(limit); + query.push(" OFFSET "); + query.push_bind(offset); + } Ok(query) }