use crate::read::Sorter;
use crate::{MaybeSend, MaybeSync};
use serde::Serialize;
use serde_json::Value as JsonValue;
use std::fmt::Debug;
#[derive(Debug, Clone, Default)]
pub struct Pagination {
pub skip: Option<i64>,
pub limit: Option<i64>,
}
pub trait Query: Debug + Serialize + MaybeSend + MaybeSync {
fn filter(&self) -> Option<rest_sql::RestSql> {
derive_filter_from_serde(self)
}
fn pagination(&self) -> Option<Pagination> {
None
}
fn default_sort() -> Option<Vec<Sorter>>
where
Self: Sized,
{
None
}
fn sort(&self) -> Option<Vec<Sorter>>
where
Self: Sized,
{
Self::default_sort()
}
}
pub fn derive_filter_from_serde<T: Serialize + ?Sized>(val: &T) -> Option<rest_sql::RestSql> {
use rest_sql::{Ast, Constraint, Operator};
let json = serde_json::to_value(val).ok()?;
let JsonValue::Object(map) = json else {
return None;
};
let constraints: Vec<Ast> = map
.into_iter()
.filter(|(_, v)| !v.is_null())
.filter_map(|(k, v)| {
json_to_rsql_value(v).map(|rv| {
Ast::Constraint(Constraint {
field: k,
operator: Operator::Eq,
value: rv,
})
})
})
.collect();
Ast::try_and(constraints).and_then(|ast| rest_sql::RestSql::from_ast(ast).ok())
}
fn json_to_rsql_value(v: JsonValue) -> Option<rest_sql::Value> {
use rest_sql::Value;
match v {
JsonValue::Bool(b) => Some(Value::Bool(b)),
JsonValue::Number(n) => {
if let Some(i) = n.as_i64() {
Some(Value::Int(i))
} else {
n.as_f64().map(Value::Float)
}
}
JsonValue::String(s) => Some(Value::String(s)),
JsonValue::Array(arr) => {
let items: Option<Vec<_>> = arr.into_iter().map(json_to_rsql_value).collect();
items.map(Value::List)
}
JsonValue::Null | JsonValue::Object(_) => None,
}
}