feat: Implement advanced filtering with new filter conditions and a strategy-based query builder.
This commit is contained in:
@@ -5,7 +5,8 @@ use axum::{
|
||||
use libertas_core::{
|
||||
error::CoreError,
|
||||
schema::{
|
||||
FilterParams, ListMediaOptions, MetadataFilter, PaginationParams, SortOrder, SortParams,
|
||||
FilterCondition, FilterOperator, FilterParams, ListMediaOptions, MetadataFilter,
|
||||
PaginationParams, SortOrder, SortParams,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -61,9 +62,44 @@ impl From<ListMediaParams> for ListMediaOptions {
|
||||
Some(PaginationParams { page, limit })
|
||||
};
|
||||
|
||||
let conditions = if params.filters.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let mut conds = Vec::new();
|
||||
for filter_str in params.filters {
|
||||
let parts: Vec<&str> = filter_str.splitn(3, ':').collect();
|
||||
if parts.len() == 3 {
|
||||
let field = parts[0].to_string();
|
||||
let op_str = parts[1];
|
||||
let value = parts[2].to_string();
|
||||
|
||||
let operator = match op_str.to_lowercase().as_str() {
|
||||
"eq" => Some(FilterOperator::Eq),
|
||||
"neq" => Some(FilterOperator::Neq),
|
||||
"like" => Some(FilterOperator::Like),
|
||||
"gt" => Some(FilterOperator::Gt),
|
||||
"lt" => Some(FilterOperator::Lt),
|
||||
"gte" => Some(FilterOperator::Gte),
|
||||
"lte" => Some(FilterOperator::Lte),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(op) = operator {
|
||||
conds.push(FilterCondition {
|
||||
field,
|
||||
operator: op,
|
||||
value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if conds.is_empty() { None } else { Some(conds) }
|
||||
};
|
||||
|
||||
let filter = Some(FilterParams {
|
||||
mime_type: params.mime_type,
|
||||
metadata_filters,
|
||||
conditions,
|
||||
});
|
||||
|
||||
ListMediaOptions {
|
||||
@@ -81,10 +117,33 @@ impl FromRequestParts<AppState> for ApiListMediaOptions {
|
||||
parts: &mut Parts,
|
||||
state: &AppState,
|
||||
) -> Result<Self, Self::Rejection> {
|
||||
let Query(params) = Query::<ListMediaParams>::from_request_parts(parts, state)
|
||||
let Query(raw_params) = Query::<Vec<(String, String)>>::from_request_parts(parts, state)
|
||||
.await
|
||||
.map_err(|e| ApiError::from(CoreError::Validation(e.to_string())))?;
|
||||
|
||||
let mut params = ListMediaParams {
|
||||
sort_by: None,
|
||||
order: None,
|
||||
mime_type: None,
|
||||
metadata: Vec::new(),
|
||||
filters: Vec::new(),
|
||||
page: None,
|
||||
limit: None,
|
||||
};
|
||||
|
||||
for (key, value) in raw_params {
|
||||
match key.as_str() {
|
||||
"sort_by" => params.sort_by = Some(value),
|
||||
"order" => params.order = Some(value),
|
||||
"mime_type" => params.mime_type = Some(value),
|
||||
"metadata" => params.metadata.push(value),
|
||||
"filters" => params.filters.push(value),
|
||||
"page" => params.page = value.parse().ok(),
|
||||
"limit" => params.limit = value.parse().ok(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ApiListMediaOptions(params.into()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ pub struct ListMediaParams {
|
||||
pub mime_type: Option<String>,
|
||||
#[serde(default)]
|
||||
pub metadata: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub filters: Vec<String>,
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user