use serde_json::Value;
use crate::ast::{
Aliasable, Column, Comparable, Compare, ConditionTree, Function, Row, Select, SqlOp, Table,
Values,
};
#[cfg(any(feature = "postgresql", feature = "mysql"))]
use super::compare::{JsonCompare, JsonType};
use std::borrow::Cow;
#[derive(Debug, Clone, PartialEq)]
pub struct Expression<'a> {
pub(crate) kind: ExpressionKind<'a>,
pub(crate) alias: Option<Cow<'a, str>>,
}
impl<'a> Expression<'a> {
pub fn kind(&self) -> &ExpressionKind<'a> {
&self.kind
}
pub fn alias(&self) -> Option<&str> {
self.alias.as_ref().map(|s| s.as_ref())
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExpressionKind<'a> {
Parameterized(Value),
Raw(&'a str),
Column(Box<Column<'a>>),
Table(Box<Table<'a>>),
Row(Row<'a>),
Selection(Box<Select<'a>>),
Function(Box<Function<'a>>),
Asterisk(Option<Box<Table<'a>>>),
Op(Box<SqlOp<'a>>),
ConditionTree(ConditionTree<'a>),
Compare(Compare<'a>),
Value(Box<Expression<'a>>),
Values(Values<'a>),
Default,
}
pub fn raw(value: &str) -> Expression<'_> {
Expression {
kind: ExpressionKind::Raw(value),
alias: None,
}
}
pub fn asterisk() -> Expression<'static> {
Expression {
kind: ExpressionKind::Asterisk(None),
alias: None,
}
}
pub fn default_value() -> Expression<'static> {
Expression {
kind: ExpressionKind::Default,
alias: None,
}
}
impl<'a> From<Function<'a>> for Expression<'a> {
fn from(f: Function<'a>) -> Self {
Expression {
kind: ExpressionKind::Function(Box::new(f)),
alias: None,
}
}
}
impl<'a> From<SqlOp<'a>> for Expression<'a> {
fn from(p: SqlOp<'a>) -> Self {
Expression {
kind: ExpressionKind::Op(Box::new(p)),
alias: None,
}
}
}
impl<'a> From<Values<'a>> for Expression<'a> {
fn from(value: Values<'a>) -> Self {
Expression {
kind: ExpressionKind::Values(value),
alias: None,
}
}
}
impl<'a, T> From<T> for Expression<'a>
where
T: Into<Value>,
{
fn from(p: T) -> Self {
Expression {
kind: ExpressionKind::Parameterized(p.into()),
alias: None,
}
}
}
impl<'a> From<Row<'a>> for Expression<'a> {
fn from(value: Row<'a>) -> Self {
Expression {
kind: ExpressionKind::Row(value),
alias: None,
}
}
}
impl<'a> From<Table<'a>> for Expression<'a> {
fn from(value: Table<'a>) -> Self {
Self {
kind: ExpressionKind::Table(Box::new(value)),
alias: None,
}
}
}
impl<'a> From<ExpressionKind<'a>> for Expression<'a> {
fn from(kind: ExpressionKind<'a>) -> Self {
Self { kind, alias: None }
}
}
impl<'a> Aliasable<'a> for Expression<'a> {
type Target = Expression<'a>;
fn alias<T>(mut self, alias: T) -> Self::Target
where
T: Into<Cow<'a, str>>,
{
self.alias = Some(alias.into());
self
}
}
impl<'a> Comparable<'a> for Expression<'a> {
fn equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::Equals(Box::new(self), Box::new(comparison.into()))
}
fn not_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::NotEquals(Box::new(self), Box::new(comparison.into()))
}
fn less_than<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::LessThan(Box::new(self), Box::new(comparison.into()))
}
fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::LessThanOrEquals(Box::new(self), Box::new(comparison.into()))
}
fn greater_than<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::GreaterThan(Box::new(self), Box::new(comparison.into()))
}
fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::GreaterThanOrEquals(Box::new(self), Box::new(comparison.into()))
}
fn in_selection<T>(self, selection: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::In(Box::new(self), Box::new(selection.into()))
}
fn not_in_selection<T>(self, selection: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::NotIn(Box::new(self), Box::new(selection.into()))
}
fn like<T>(self, pattern: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::Like(Box::new(self), Box::new(pattern.into()))
}
fn not_like<T>(self, pattern: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::NotLike(Box::new(self), Box::new(pattern.into()))
}
#[allow(clippy::wrong_self_convention)]
fn is_null(self) -> Compare<'a> {
Compare::Null(Box::new(self))
}
#[allow(clippy::wrong_self_convention)]
fn is_not_null(self) -> Compare<'a> {
Compare::NotNull(Box::new(self))
}
fn between<T, V>(self, left: T, right: V) -> Compare<'a>
where
T: Into<Expression<'a>>,
V: Into<Expression<'a>>,
{
Compare::Between(
Box::new(self),
Box::new(left.into()),
Box::new(right.into()),
)
}
fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
where
T: Into<Expression<'a>>,
V: Into<Expression<'a>>,
{
Compare::NotBetween(
Box::new(self),
Box::new(left.into()),
Box::new(right.into()),
)
}
fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
where
T: Into<Cow<'a, str>>,
V: Into<Expression<'a>>,
{
Compare::Raw(
Box::new(self),
raw_comparator.into(),
Box::new(right.into()),
)
}
#[cfg(all(feature = "postgresql", feature = "mysql"))]
fn json_array_contains<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::JsonCompare(JsonCompare::ArrayContains(
Box::new(self),
Box::new(item.into()),
))
}
#[cfg(all(feature = "postgresql", feature = "mysql"))]
fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
Compare::JsonCompare(JsonCompare::ArrayNotContains(
Box::new(self),
Box::new(item.into()),
))
}
#[cfg(all(feature = "postgresql", feature = "mysql"))]
fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let array_starts_with: Expression =
super::function::json_extract_first_array_elem(self).into();
Compare::Equals(Box::new(array_starts_with), Box::new(item.into()))
}
#[cfg(all(feature = "postgresql", feature = "mysql"))]
fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let array_starts_with: Expression =
super::function::json_extract_first_array_elem(self).into();
Compare::NotEquals(Box::new(array_starts_with), Box::new(item.into()))
}
#[cfg(all(feature = "postgresql", feature = "mysql"))]
fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let array_ends_into: Expression =
super::function::json_extract_last_array_elem(self).into();
Compare::Equals(Box::new(array_ends_into), Box::new(item.into()))
}
#[cfg(all(feature = "postgresql", feature = "mysql"))]
fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let array_ends_into: Expression =
super::function::json_extract_last_array_elem(self).into();
Compare::NotEquals(Box::new(array_ends_into), Box::new(item.into()))
}
#[cfg(all(feature = "postgresql", feature = "mysql"))]
fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
where
T: Into<JsonType<'a>>,
{
Compare::JsonCompare(JsonCompare::TypeEquals(Box::new(self), json_type.into()))
}
#[cfg(all(feature = "postgresql", feature = "mysql"))]
fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
where
T: Into<JsonType<'a>>,
{
Compare::JsonCompare(JsonCompare::TypeNotEquals(Box::new(self), json_type.into()))
}
#[cfg(feature = "postgresql")]
fn any(self) -> Compare<'a> {
Compare::Any(Box::new(self))
}
#[cfg(feature = "postgresql")]
fn all(self) -> Compare<'a> {
Compare::All(Box::new(self))
}
}