use adminx_core::storage::{FilterClause, FilterOp};
use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc};
use sea_orm::sea_query::{Alias, Expr, Order, Query, SelectStatement, SimpleExpr};
use sea_orm::Value as SeaValue;
use serde_json::Value;
fn range_expr(v: &str) -> SimpleExpr {
let ndt = NaiveDateTime::parse_from_str(v, "%Y-%m-%dT%H:%M:%S")
.ok()
.or_else(|| {
NaiveDate::parse_from_str(v, "%Y-%m-%d")
.ok()
.and_then(|d| d.and_hms_opt(0, 0, 0))
});
match ndt {
Some(ndt) => Expr::val(DateTime::<Utc>::from_naive_utc_and_offset(ndt, Utc)).into(),
None => Expr::val(filter_value(v)).into(),
}
}
fn filter_value(v: &str) -> SeaValue {
match v {
"true" => true.into(),
"false" => false.into(),
_ => match v.parse::<i64>() {
Ok(i) => i.into(),
Err(_) => v.to_owned().into(),
},
}
}
fn apply_filters(select: &mut SelectStatement, filters: &[FilterClause]) {
for f in filters {
let col = Expr::col(Alias::new(&f.field));
match f.op {
FilterOp::Eq => {
select.and_where(col.eq(filter_value(&f.value)));
}
FilterOp::Contains => {
select.and_where(col.like(format!("%{}%", f.value)));
}
FilterOp::Gte => {
select.and_where(col.gte(range_expr(&f.value)));
}
FilterOp::Lte => {
select.and_where(col.lte(range_expr(&f.value)));
}
}
}
}
pub fn json_to_sea_value(v: &Value) -> SeaValue {
match v {
Value::Null => SeaValue::String(None),
Value::Bool(b) => (*b).into(),
Value::Number(n) => {
if let Some(i) = n.as_i64() {
i.into()
} else if let Some(u) = n.as_u64() {
(u as i64).into()
} else if let Some(f) = n.as_f64() {
f.into()
} else {
n.to_string().into()
}
}
Value::String(s) => s.clone().into(),
other => other.to_string().into(),
}
}
pub fn id_to_sea_value(id: &str) -> SeaValue {
if let Ok(i) = id.parse::<i64>() {
i.into()
} else {
id.to_owned().into()
}
}
pub fn value_expr(v: SeaValue) -> SimpleExpr {
Expr::val(v).into()
}
pub fn build_list_select(
table: &str,
per_page: u64,
offset: u64,
sort_by: &Option<String>,
sort_desc: bool,
filters: &[FilterClause],
) -> SelectStatement {
let mut select = Query::select();
select
.expr(Expr::cust("*"))
.from(Alias::new(table))
.limit(per_page)
.offset(offset);
apply_filters(&mut select, filters);
if let Some(col) = sort_by {
let order = if sort_desc { Order::Desc } else { Order::Asc };
select.order_by(Alias::new(col), order);
}
select.to_owned()
}
pub fn build_count_select(table: &str, filters: &[FilterClause]) -> SelectStatement {
let mut select = Query::select();
select
.expr(Expr::cust("COUNT(*) AS count"))
.from(Alias::new(table));
apply_filters(&mut select, filters);
select.to_owned()
}
pub fn build_get_select(table: &str, pk: &str, id: &str) -> SelectStatement {
Query::select()
.expr(Expr::cust("*"))
.from(Alias::new(table))
.and_where(Expr::col(Alias::new(pk)).eq(id_to_sea_value(id)))
.limit(1)
.to_owned()
}
pub fn build_find_select(table: &str, column: &str, value: &str) -> SelectStatement {
Query::select()
.expr(Expr::cust("*"))
.from(Alias::new(table))
.and_where(Expr::col(Alias::new(column)).eq(value.to_owned()))
.limit(1)
.to_owned()
}