mod parse;
mod to_query_string;
mod validate;
use bigdecimal::BigDecimal;
use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
use std::collections::HashMap;
use thiserror::Error;
use uuid::Uuid;
pub use parse::parse_str;
pub use to_query_string::{to_query_string, write_query_string};
#[deprecated = "Use ParseError instead."]
pub use ParseError as Error;
#[derive(Clone, Debug, Error, PartialEq, Eq)]
pub enum ParseError {
#[error("Error during general parsing.")]
Parsing,
#[error("Error parsing a UUID.")]
ParsingUuid,
#[error("Error parsing a number.")]
ParsingNumber,
#[error("Error parsing a date.")]
ParsingDate,
#[error("Error parsing a time.")]
ParsingTime,
#[error("Error parsing a date and time.")]
ParsingDateTime,
#[error("Error parsing a time zone offset.")]
ParsingTimeZone,
#[error("Error parsing a named time zone.")]
ParsingTimeZoneNamed,
#[error("Error parsing a Unicode code point escape sequence.")]
ParsingUnicodeCodePoint,
}
#[derive(Clone, Debug, Error, PartialEq, Eq)]
pub enum ValidationError {
#[error("Logical join requires boolean operands: lhs = {lhs:?}, rhs = {rhs:?}.")]
LogicalJoinRequiresBooleans { lhs: Type, rhs: Type },
#[error("Logical NOT requires a boolean operand but got {given:?}.")]
LogicalNotRequiresBoolean { given: Type },
#[error("Comparing incompatible types: lhs = {lhs:?}, rhs = {rhs:?}.")]
ComparingIncompatibleTypes { lhs: Type, rhs: Type },
#[error("Undefined identifier '{name}'.")]
UndefinedIdentifier { name: String },
#[error("Undefined function '{name}'.")]
UndefinedFunction { name: String },
#[error(
"Function '{name}' expected {expected}{} arguments but got {given}.",
if *is_variadic { " or more" } else { "" }
)]
IncorrectFunctionArgumentsCount {
name: String,
is_variadic: bool,
expected: usize,
given: usize,
},
#[error("Function '{name}' argument {position} expected type {expected:?} but got {given:?}.")]
IncorrectFunctionArgumentType {
name: String,
position: usize,
expected: Type,
given: Type,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
Or(Box<Expr>, Box<Expr>),
And(Box<Expr>, Box<Expr>),
Not(Box<Expr>),
Compare(Box<Expr>, CompareOperator, Box<Expr>),
In(Box<Expr>, Vec<Expr>),
Function(String, Vec<Expr>),
Identifier(String),
Value(Value),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CompareOperator {
Equal,
NotEqual,
GreaterThan,
GreaterOrEqual,
LessThan,
LessOrEqual,
}
impl std::fmt::Display for CompareOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompareOperator::Equal => write!(f, "eq"),
CompareOperator::NotEqual => write!(f, "ne"),
CompareOperator::GreaterThan => write!(f, "gt"),
CompareOperator::GreaterOrEqual => write!(f, "ge"),
CompareOperator::LessThan => write!(f, "lt"),
CompareOperator::LessOrEqual => write!(f, "le"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
Null,
Bool(bool),
Number(BigDecimal),
Uuid(Uuid),
DateTime(DateTime<Utc>),
Date(NaiveDate),
Time(NaiveTime),
String(String),
}
#[derive(Copy, Clone, Debug, Eq)]
pub enum Type {
Null,
Boolean,
Number,
Uuid,
DateTime,
Date,
Time,
String,
}
impl PartialEq for Type {
fn eq(&self, other: &Self) -> bool {
use core::mem::discriminant as variant;
variant(self) == variant(other)
|| variant(other) == variant(&Type::Null)
|| variant(self) == variant(&Type::Null)
}
}
pub struct IdentifiersTypeMap(HashMap<String, Type>);
pub struct FunctionsTypeMap(HashMap<String, (Vec<Type>, Option<Type>, Type)>);
impl From<HashMap<String, Type>> for IdentifiersTypeMap {
fn from(map: HashMap<String, Type>) -> Self {
Self(map)
}
}
impl From<HashMap<String, (Vec<Type>, Option<Type>, Type)>> for FunctionsTypeMap {
fn from(map: HashMap<String, (Vec<Type>, Option<Type>, Type)>) -> Self {
Self(map)
}
}