use crate::{
condition::{Condition, ConditionKind},
group::{Conjunction, Group, Node},
order::Order,
value::Value,
};
#[derive(Clone)]
pub struct Query {
pub(crate) nodes: Vec<Node>,
pub(crate) order: Option<(String, Order)>,
pub(crate) limit: Option<u64>,
pub(crate) offset: Option<u64>,
}
impl Query {
pub fn new() -> Self {
Self { nodes: vec![], order: None, limit: None, offset: None }
}
fn push(mut self, kind: ConditionKind, values: Vec<Value>) -> Self {
self.nodes.push(Node::Cond(Condition { kind, values }));
self
}
pub fn eq(self, col: &str, val: impl Into<Value>) -> Self {
self.push(ConditionKind::Eq(col.into()), vec![val.into()])
}
pub fn ne(self, col: &str, val: impl Into<Value>) -> Self {
self.push(ConditionKind::Ne(col.into()), vec![val.into()])
}
pub fn gt(self, col: &str, val: impl Into<Value>) -> Self {
self.push(ConditionKind::Gt(col.into()), vec![val.into()])
}
pub fn gte(self, col: &str, val: impl Into<Value>) -> Self {
self.push(ConditionKind::Gte(col.into()), vec![val.into()])
}
pub fn lt(self, col: &str, val: impl Into<Value>) -> Self {
self.push(ConditionKind::Lt(col.into()), vec![val.into()])
}
pub fn lte(self, col: &str, val: impl Into<Value>) -> Self {
self.push(ConditionKind::Lte(col.into()), vec![val.into()])
}
pub fn is_null(self, col: &str) -> Self {
self.push(ConditionKind::IsNull(col.into()), vec![])
}
pub fn is_not_null(self, col: &str) -> Self {
self.push(ConditionKind::IsNotNull(col.into()), vec![])
}
pub fn filter_optional(self, col: &str, val: Option<impl Into<Value>>) -> Self {
let v = val.map(Into::into).unwrap_or(Value::Null);
self.push(ConditionKind::FilterOptional(col.into()), vec![v])
}
pub fn filter_optional_gte(self, col: &str, val: Option<impl Into<Value>>) -> Self {
let v = val.map(Into::into).unwrap_or(Value::Null);
self.push(ConditionKind::FilterOptionalGte(col.into()), vec![v])
}
pub fn filter_optional_lte(self, col: &str, val: Option<impl Into<Value>>) -> Self {
let v = val.map(Into::into).unwrap_or(Value::Null);
self.push(ConditionKind::FilterOptionalLte(col.into()), vec![v])
}
pub fn in_<T: Into<Value>>(self, col: &str, vals: Vec<T>) -> Self {
let values = vals.into_iter().map(Into::into).collect();
self.push(ConditionKind::In(col.into()), values)
}
pub fn not_in<T: Into<Value>>(self, col: &str, vals: Vec<T>) -> Self {
let values = vals.into_iter().map(Into::into).collect();
self.push(ConditionKind::NotIn(col.into()), values)
}
pub fn like(self, col: &str, pat: impl Into<Value>) -> Self {
self.push(ConditionKind::Like(col.into()), vec![pat.into()])
}
pub fn not_like(self, col: &str, pat: impl Into<Value>) -> Self {
self.push(ConditionKind::NotLike(col.into()), vec![pat.into()])
}
pub fn between(self, col: &str, lo: impl Into<Value>, hi: impl Into<Value>) -> Self {
self.push(ConditionKind::Between(col.into()), vec![lo.into(), hi.into()])
}
pub fn or(mut self, f: impl FnOnce(Query) -> Query) -> Self {
let inner = f(Query::new());
self.nodes.push(Node::Group(Group { conjunction: Conjunction::Or, nodes: inner.nodes }));
self
}
pub fn and(mut self, f: impl FnOnce(Query) -> Query) -> Self {
let inner = f(Query::new());
self.nodes.push(Node::Group(Group { conjunction: Conjunction::And, nodes: inner.nodes }));
self
}
pub fn order_by(mut self, col: &str, dir: Order) -> Self {
self.order = Some((col.into(), dir));
self
}
pub fn limit(mut self, n: u64) -> Self { self.limit = Some(n); self }
pub fn offset(mut self, n: u64) -> Self { self.offset = Some(n); self }
}
impl Default for Query {
fn default() -> Self { Self::new() }
}