use crate::query::expr::SqlExpr;
#[derive(Debug, Clone)]
pub enum FilterExpr {
Comparison {
column: String,
operator: String,
value: Value,
},
ColumnComparison {
left_column: String,
operator: String,
right_column: String,
},
In { column: String, values: Vec<Value> },
NotIn { column: String, values: Vec<Value> },
InSubquery {
column: String,
subquery_sql: String,
subquery_params: Vec<crate::model::Value>,
},
NotInSubquery {
column: String,
subquery_sql: String,
subquery_params: Vec<crate::model::Value>,
},
And(Box<FilterExpr>, Box<FilterExpr>),
Or(Box<FilterExpr>, Box<FilterExpr>),
IsNull { column: String },
IsNotNull { column: String },
Between {
column: String,
min: Value,
max: Value,
},
Exists {
subquery_sql: String,
subquery_params: Vec<crate::model::Value>,
},
NotExists {
subquery_sql: String,
subquery_params: Vec<crate::model::Value>,
},
ExprComparison {
left: SqlExpr,
operator: String,
right: SqlExpr,
},
ExprIn { expr: SqlExpr, values: Vec<SqlExpr> },
ExprNotIn { expr: SqlExpr, values: Vec<SqlExpr> },
ExprBetween {
expr: SqlExpr,
min: SqlExpr,
max: SqlExpr,
},
ExprIsNull { expr: SqlExpr },
ExprIsNotNull { expr: SqlExpr },
TextSearch { expr: SqlExpr, query: String },
}
pub type Value = crate::model::Value;
#[cfg(feature = "postgresql")]
pub(crate) fn infer_filter_value_rust_type(value: &Value) -> &'static str {
match value {
Value::Integer(_) => "i32",
Value::BigInt(_) => "i64",
Value::Duration(_) => "Duration",
Value::Text(_) => "String",
Value::TextArray(_) => "Vec<String>",
Value::Real(_) => "f64",
Value::Boolean(_) => "bool",
Value::Bytes(_) => "Vec<u8>",
Value::IntegerArray(_) => "Vec<i32>",
Value::BigIntArray(_) => "Vec<i64>",
Value::NullableBigIntArray(_) => "Vec<Option<i64>>",
Value::DateTime(_) => "NaiveDateTime",
Value::Date(_) => "NaiveDate",
Value::Time(_) => "NaiveTime",
Value::Json(_) => "String",
Value::Uuid(_) => "String",
Value::Null => "i32",
}
}
#[cfg(feature = "postgresql")]
pub(crate) fn infer_model_value_rust_type(value: &crate::model::Value) -> &'static str {
infer_filter_value_rust_type(value)
}
pub trait Subquery {
fn to_subquery_sql(&self) -> (String, Vec<crate::model::Value>);
}
impl FilterExpr {
pub fn and(self, other: FilterExpr) -> Self {
FilterExpr::And(Box::new(self), Box::new(other))
}
pub fn or(self, other: FilterExpr) -> Self {
FilterExpr::Or(Box::new(self), Box::new(other))
}
}
#[derive(Debug, Clone)]
pub enum OrderDirection {
Asc,
Desc,
}
#[derive(Debug, Clone)]
pub struct OrderBy {
pub column: String,
pub direction: OrderDirection,
expr: Option<SqlExpr>,
}
impl OrderBy {
pub fn asc(column: String) -> Self {
Self {
column,
direction: OrderDirection::Asc,
expr: None,
}
}
pub fn desc(column: String) -> Self {
Self {
column,
direction: OrderDirection::Desc,
expr: None,
}
}
pub fn asc_expr(expr: SqlExpr) -> Self {
Self {
column: expr.to_sql_no_params(crate::query::builder::default_db_type()),
direction: OrderDirection::Asc,
expr: Some(expr),
}
}
pub fn desc_expr(expr: SqlExpr) -> Self {
Self {
column: expr.to_sql_no_params(crate::query::builder::default_db_type()),
direction: OrderDirection::Desc,
expr: Some(expr),
}
}
pub fn to_sql(&self) -> String {
let dir = match self.direction {
OrderDirection::Asc => "ASC",
OrderDirection::Desc => "DESC",
};
let expr_sql = self
.expr
.as_ref()
.map(|expr| expr.to_sql_no_params(crate::query::builder::default_db_type()))
.unwrap_or_else(|| self.column.clone());
format!("{} {}", expr_sql, dir)
}
pub fn to_sql_for(&self, db_type: crate::abstract_layer::DbType) -> String {
let dir = match self.direction {
OrderDirection::Asc => "ASC",
OrderDirection::Desc => "DESC",
};
let expr_sql = self
.expr
.as_ref()
.map(|expr| expr.to_sql_no_params(db_type))
.unwrap_or_else(|| crate::model::quote_column_reference(db_type, &self.column));
format!("{} {}", expr_sql, dir)
}
}