use crate::filter::ops::OpVal;
use crate::filter::{OpValBool, OpValFloat64, OpValInt32, OpValInt64, OpValString};
pub trait IntoFilterNodes {
fn filter_nodes(self, rel: Option<String>) -> Vec<FilterNode>;
}
#[derive(Debug, Clone, Default)]
pub struct FilterNodeOptions {
pub cast_as: Option<String>, pub cast_column_as: Option<String>, }
#[derive(Debug, Clone)]
pub struct FilterNode {
pub rel: Option<String>, pub name: String,
pub opvals: Vec<OpVal>,
pub options: FilterNodeOptions,
#[cfg(feature = "with-sea-query")]
pub for_sea_condition: Option<crate::filter::ForSeaCondition>,
}
impl FilterNode {
pub fn new(name: impl Into<String>, opvals: impl Into<Vec<OpVal>>) -> FilterNode {
FilterNode {
rel: None,
name: name.into(),
opvals: opvals.into(),
options: FilterNodeOptions::default(),
#[cfg(feature = "with-sea-query")]
for_sea_condition: None,
}
}
pub fn new_with_rel(rel: Option<String>, name: impl Into<String>, opvals: impl Into<Vec<OpVal>>) -> FilterNode {
FilterNode {
rel,
name: name.into(),
opvals: opvals.into(),
options: FilterNodeOptions::default(),
#[cfg(feature = "with-sea-query")]
for_sea_condition: None,
}
}
}
macro_rules! from_tuples_opval {
($($OV:ident),+) => {
$(
impl From<(&str, $OV)> for FilterNode {
fn from((name, ov): (&str, $OV)) -> Self {
let opvals = vec![ov.into()];
FilterNode::new(name, opvals)
}
}
impl From<(&str, Vec<$OV>)> for FilterNode {
fn from((name, ovs): (&str, Vec<$OV>)) -> Self {
let opvals: Vec<OpVal> = ovs.into_iter().map(|v| OpVal::from(v)).collect();
FilterNode::new(name, opvals)
}
}
)+
};
}
from_tuples_opval!(
OpValString,
OpValInt64,
OpValFloat64,
OpValBool
);
impl From<(&str, &str)> for FilterNode {
fn from((name, ov): (&str, &str)) -> Self {
let opvals = vec![OpValString::Eq(ov.to_string()).into()];
FilterNode::new(name.to_string(), opvals)
}
}
impl From<(&str, &String)> for FilterNode {
fn from((name, ov): (&str, &String)) -> Self {
let opvals = vec![OpValString::Eq(ov.to_string()).into()];
FilterNode::new(name.to_string(), opvals)
}
}
impl From<(&str, String)> for FilterNode {
fn from((name, ov): (&str, String)) -> Self {
let opvals = vec![OpValString::Eq(ov).into()];
FilterNode::new(name.to_string(), opvals)
}
}
macro_rules! from_tuples_num{
($(($nt:ty, $ov:ident)),+) => {
$(
impl From<(&str, $nt)> for FilterNode {
fn from((name, ov): (&str, $nt)) -> Self {
let opvals = vec![$ov::Eq(ov).into()];
FilterNode::new(name.to_string(), opvals)
}
}
)+
};
}
from_tuples_num!(
(i64, OpValInt64),
(i32, OpValInt32),
(f64, OpValFloat64)
);
impl From<(&str, bool)> for FilterNode {
fn from((name, ov): (&str, bool)) -> Self {
let opvals = vec![OpValBool::Eq(ov).into()];
FilterNode::new(name.to_string(), opvals)
}
}
#[cfg(feature = "with-sea-query")]
mod with_sea_query {
use super::*;
use crate::filter::{ForSeaCondition, IntoSeaError, OpValValue, SeaResult};
use crate::sea_utils::StringIden;
use sea_query::{ColumnRef, ConditionExpression, IntoColumnRef, IntoIden};
impl FilterNode {
pub fn into_sea_cond_expr_list(self) -> SeaResult<Vec<ConditionExpression>> {
let col: ColumnRef = match self.rel {
Some(rel) => ColumnRef::TableColumn(StringIden(rel).into_iden(), StringIden(self.name).into_iden()),
None => StringIden(self.name).into_column_ref(),
};
let mut node_sea_exprs: Vec<ConditionExpression> = Vec::new();
let for_sea_cond = self.for_sea_condition;
let node_options = &self.options;
for op_val in self.opvals.into_iter() {
let cond_expr = match op_val {
OpVal::String(ov) => ov.into_sea_cond_expr(&col, node_options)?,
OpVal::Int64(ov) => ov.into_sea_cond_expr(&col, node_options)?,
OpVal::Int32(ov) => ov.into_sea_cond_expr(&col, node_options)?,
OpVal::Float64(ov) => ov.into_sea_cond_expr(&col, node_options)?,
OpVal::Bool(ov) => ov.into_sea_cond_expr(&col, node_options)?,
OpVal::Value(ov) => {
let Some(for_sea_cond) = for_sea_cond.as_ref() else {
return Err(IntoSeaError::Custom(
"OpValsValue must have a #[modql(to_sea_value_fn=\"fn_name\"] or to_sea_condition_fn attribute"
.to_string(),
));
};
match for_sea_cond {
ForSeaCondition::ToSeaValue(to_sea_value) => {
OpValValue::into_sea_cond_expr_with_json_to_sea(ov, &col, node_options, to_sea_value)?
}
ForSeaCondition::ToSeaCondition(to_sea_condition) => to_sea_condition.call(&col, ov)?,
}
}
};
node_sea_exprs.push(cond_expr);
}
Ok(node_sea_exprs)
}
}
}