use super::ExpressionKind;
use crate::ast::{Column, ConditionTree, Expression};
use std::borrow::Cow;
#[derive(Debug, Clone, PartialEq)]
pub enum Compare<'a> {
Equals(Box<Expression<'a>>, Box<Expression<'a>>),
NotEquals(Box<Expression<'a>>, Box<Expression<'a>>),
LessThan(Box<Expression<'a>>, Box<Expression<'a>>),
LessThanOrEquals(Box<Expression<'a>>, Box<Expression<'a>>),
GreaterThan(Box<Expression<'a>>, Box<Expression<'a>>),
GreaterThanOrEquals(Box<Expression<'a>>, Box<Expression<'a>>),
In(Box<Expression<'a>>, Box<Expression<'a>>),
NotIn(Box<Expression<'a>>, Box<Expression<'a>>),
Like(Box<Expression<'a>>, Box<Expression<'a>>),
NotLike(Box<Expression<'a>>, Box<Expression<'a>>),
Null(Box<Expression<'a>>),
NotNull(Box<Expression<'a>>),
Between(
Box<Expression<'a>>,
Box<Expression<'a>>,
Box<Expression<'a>>,
),
NotBetween(
Box<Expression<'a>>,
Box<Expression<'a>>,
Box<Expression<'a>>,
),
Raw(Box<Expression<'a>>, Cow<'a, str>, Box<Expression<'a>>),
#[cfg(any(feature = "postgresql", feature = "mysql"))]
JsonCompare(JsonCompare<'a>),
#[cfg(feature = "postgresql")]
Any(Box<Expression<'a>>),
#[cfg(feature = "postgresql")]
All(Box<Expression<'a>>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum JsonCompare<'a> {
ArrayOverlaps(Box<Expression<'a>>, Box<Expression<'a>>),
ArrayContains(Box<Expression<'a>>, Box<Expression<'a>>),
ArrayContained(Box<Expression<'a>>, Box<Expression<'a>>),
ArrayNotContains(Box<Expression<'a>>, Box<Expression<'a>>),
TypeEquals(Box<Expression<'a>>, JsonType<'a>),
TypeNotEquals(Box<Expression<'a>>, JsonType<'a>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum JsonType<'a> {
Array,
Object,
String,
Number,
Boolean,
Null,
ColumnRef(Box<Column<'a>>),
}
impl<'a> From<Column<'a>> for JsonType<'a> {
fn from(col: Column<'a>) -> Self {
JsonType::ColumnRef(Box::new(col))
}
}
impl<'a> From<Compare<'a>> for ConditionTree<'a> {
fn from(cmp: Compare<'a>) -> Self {
ConditionTree::single(Expression::from(cmp))
}
}
impl<'a> From<Compare<'a>> for Expression<'a> {
fn from(cmp: Compare<'a>) -> Self {
Expression {
kind: ExpressionKind::Compare(cmp),
alias: None,
}
}
}
pub trait Comparable<'a> {
fn equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn not_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn less_than<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn greater_than<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn in_selection<T>(self, selection: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn not_in_selection<T>(self, selection: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn like<T>(self, pattern: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
fn not_like<T>(self, pattern: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[allow(clippy::wrong_self_convention)]
fn is_null(self) -> Compare<'a>;
#[allow(clippy::wrong_self_convention)]
fn is_not_null(self) -> Compare<'a>;
fn between<T, V>(self, left: T, right: V) -> Compare<'a>
where
T: Into<Expression<'a>>,
V: Into<Expression<'a>>;
fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
where
T: Into<Expression<'a>>,
V: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn array_overlaps<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn array_contains<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn array_contained<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
where
T: Into<JsonType<'a>>;
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
where
T: Into<JsonType<'a>>;
#[cfg(feature = "postgresql")]
fn any(self) -> Compare<'a>;
#[cfg(feature = "postgresql")]
fn all(self) -> Compare<'a>;
fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
where
T: Into<Cow<'a, str>>,
V: Into<Expression<'a>>;
}
impl<'a, U> Comparable<'a> for U
where
U: Into<Column<'a>>,
{
fn equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.equals(comparison)
}
fn not_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.not_equals(comparison)
}
fn less_than<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.less_than(comparison)
}
fn less_than_or_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.less_than_or_equals(comparison)
}
fn greater_than<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.greater_than(comparison)
}
fn greater_than_or_equals<T>(self, comparison: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.greater_than_or_equals(comparison)
}
fn in_selection<T>(self, selection: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.in_selection(selection)
}
fn not_in_selection<T>(self, selection: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.not_in_selection(selection)
}
fn like<T>(self, pattern: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.like(pattern)
}
fn not_like<T>(self, pattern: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.not_like(pattern)
}
#[allow(clippy::wrong_self_convention)]
fn is_null(self) -> Compare<'a> {
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.is_null()
}
#[allow(clippy::wrong_self_convention)]
fn is_not_null(self) -> Compare<'a> {
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.is_not_null()
}
fn between<T, V>(self, left: T, right: V) -> Compare<'a>
where
T: Into<Expression<'a>>,
V: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.between(left, right)
}
fn not_between<T, V>(self, left: T, right: V) -> Compare<'a>
where
T: Into<Expression<'a>>,
V: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.not_between(left, right)
}
fn compare_raw<T, V>(self, raw_comparator: T, right: V) -> Compare<'a>
where
T: Into<Cow<'a, str>>,
V: Into<Expression<'a>>,
{
let left: Column<'a> = self.into();
let left: Expression<'a> = left.into();
let right: Expression<'a> = right.into();
left.compare_raw(raw_comparator.into(), right)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn array_overlaps<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.array_overlaps(item)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn array_contains<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.array_contains(item)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn array_contained<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.array_contained(item)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_not_contains<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.json_array_not_contains(item)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_begins_with<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.json_array_begins_with(item)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_not_begins_with<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.json_array_not_begins_with(item)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_ends_into<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.json_array_ends_into(item)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_array_not_ends_into<T>(self, item: T) -> Compare<'a>
where
T: Into<Expression<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.json_array_not_ends_into(item)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_type_equals<T>(self, json_type: T) -> Compare<'a>
where
T: Into<JsonType<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.json_type_equals(json_type)
}
#[cfg(any(feature = "postgresql", feature = "mysql"))]
fn json_type_not_equals<T>(self, json_type: T) -> Compare<'a>
where
T: Into<JsonType<'a>>,
{
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.json_type_not_equals(json_type)
}
#[cfg(feature = "postgresql")]
fn any(self) -> Compare<'a> {
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.any()
}
#[cfg(feature = "postgresql")]
fn all(self) -> Compare<'a> {
let col: Column<'a> = self.into();
let val: Expression<'a> = col.into();
val.all()
}
}