use axum::{ Json, extract::{Query, State}, }; use pinakes_core::{ model::Pagination, search::{SearchRequest, SortOrder, parse_search_query}, }; use crate::{ dto::{MediaResponse, SearchParams, SearchRequestBody, SearchResponse}, error::ApiError, state::AppState, }; fn resolve_sort(sort: Option<&str>) -> SortOrder { match sort { Some("date_asc") => SortOrder::DateAsc, Some("date_desc") => SortOrder::DateDesc, Some("name_asc") => SortOrder::NameAsc, Some("name_desc") => SortOrder::NameDesc, Some("size_asc") => SortOrder::SizeAsc, Some("size_desc") => SortOrder::SizeDesc, _ => SortOrder::Relevance, } } pub async fn search( State(state): State, Query(params): Query, ) -> Result, ApiError> { if params.q.len() > 2048 { return Err(ApiError( pinakes_core::error::PinakesError::InvalidOperation( "search query exceeds maximum length of 2048 characters".into(), ), )); } let query = parse_search_query(¶ms.q)?; let sort = resolve_sort(params.sort.as_deref()); let request = SearchRequest { query, sort, pagination: Pagination::new( params.offset.unwrap_or(0), params.limit.unwrap_or(50).min(1000), None, ), }; let results = state.storage.search(&request).await?; let roots = state.config.read().await.directories.roots.clone(); Ok(Json(SearchResponse { items: results .items .into_iter() .map(|item| MediaResponse::new(item, &roots)) .collect(), total_count: results.total_count, })) } pub async fn search_post( State(state): State, Json(body): Json, ) -> Result, ApiError> { if body.q.len() > 2048 { return Err(ApiError( pinakes_core::error::PinakesError::InvalidOperation( "search query exceeds maximum length of 2048 characters".into(), ), )); } let query = parse_search_query(&body.q)?; let sort = resolve_sort(body.sort.as_deref()); let request = SearchRequest { query, sort, pagination: Pagination::new( body.offset.unwrap_or(0), body.limit.unwrap_or(50).min(1000), None, ), }; let results = state.storage.search(&request).await?; let roots = state.config.read().await.directories.roots.clone(); Ok(Json(SearchResponse { items: results .items .into_iter() .map(|item| MediaResponse::new(item, &roots)) .collect(), total_count: results.total_count, })) }