use std::ops::{BitAnd, BitOr};
#[derive(Debug, Clone, PartialEq)]
pub enum Ast {
And(Vec<Ast>),
Or(Vec<Ast>),
Constraint(Constraint),
}
impl Ast {
pub fn and(nodes: impl IntoIterator<Item = Ast>) -> Ast {
let v: Vec<_> = nodes.into_iter().collect();
assert!(!v.is_empty(), "Ast::and requires at least one node");
if v.len() == 1 {
v.into_iter().next().unwrap()
} else {
Ast::And(v)
}
}
pub fn or(nodes: impl IntoIterator<Item = Ast>) -> Ast {
let v: Vec<_> = nodes.into_iter().collect();
assert!(!v.is_empty(), "Ast::or requires at least one node");
if v.len() == 1 {
v.into_iter().next().unwrap()
} else {
Ast::Or(v)
}
}
pub fn try_and(nodes: impl IntoIterator<Item = Ast>) -> Option<Ast> {
let v: Vec<_> = nodes.into_iter().collect();
if v.is_empty() {
None
} else if v.len() == 1 {
v.into_iter().next()
} else {
Some(Ast::And(v))
}
}
pub fn try_or(nodes: impl IntoIterator<Item = Ast>) -> Option<Ast> {
let v: Vec<_> = nodes.into_iter().collect();
if v.is_empty() {
None
} else if v.len() == 1 {
v.into_iter().next()
} else {
Some(Ast::Or(v))
}
}
pub fn try_and_opts(nodes: impl IntoIterator<Item = Option<Ast>>) -> Option<Ast> {
Self::try_and(nodes.into_iter().flatten())
}
pub fn try_or_opts(nodes: impl IntoIterator<Item = Option<Ast>>) -> Option<Ast> {
Self::try_or(nodes.into_iter().flatten())
}
}
impl BitAnd for Ast {
type Output = Ast;
fn bitand(self, rhs: Ast) -> Ast {
match (self, rhs) {
(Ast::And(mut a), Ast::And(b)) => {
a.extend(b);
Ast::And(a)
}
(Ast::And(mut a), rhs) => {
a.push(rhs);
Ast::And(a)
}
(lhs, rhs) => Ast::And(vec![lhs, rhs]),
}
}
}
impl BitOr for Ast {
type Output = Ast;
fn bitor(self, rhs: Ast) -> Ast {
match (self, rhs) {
(Ast::Or(mut a), Ast::Or(b)) => {
a.extend(b);
Ast::Or(a)
}
(Ast::Or(mut a), rhs) => {
a.push(rhs);
Ast::Or(a)
}
(lhs, rhs) => Ast::Or(vec![lhs, rhs]),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Constraint {
pub field: String,
pub operator: Operator,
pub value: Value,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Operator {
Eq,
Neq,
Lt,
Lte,
Gt,
Gte,
In,
Out,
Like,
Ilike,
Between,
Null,
NotNull,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Int(i64),
Float(f64),
String(String),
Date(String),
DateTime(String),
List(Vec<Value>),
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Value::Bool(v)
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Value::Int(v as i64)
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::Int(v)
}
}
impl From<f32> for Value {
fn from(v: f32) -> Self {
Value::Float(v as f64)
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value::Float(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Value::String(v.to_owned())
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Value::String(v)
}
}