use crate::{expr::SimpleExpr, types::LogicalChainOper};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConditionType {
Any,
All,
}
#[derive(Debug, Clone)]
pub struct Condition {
pub(crate) negate: bool,
pub(crate) condition_type: ConditionType,
pub(crate) conditions: Vec<ConditionExpression>,
}
pub trait IntoCondition {
fn into_condition(self) -> Condition;
}
pub type Cond = Condition;
#[derive(Debug, Clone)]
pub enum ConditionExpression {
Condition(Condition),
SimpleExpr(SimpleExpr),
}
#[derive(Debug, Clone)]
pub enum ConditionHolderContents {
Empty,
Chain(Vec<LogicalChainOper>),
Condition(Condition),
}
#[derive(Debug, Clone)]
pub struct ConditionHolder {
pub contents: ConditionHolderContents,
}
impl Condition {
#[allow(clippy::should_implement_trait)]
pub fn add<C>(mut self, condition: C) -> Self
where
C: Into<ConditionExpression>,
{
let mut expr: ConditionExpression = condition.into();
if let ConditionExpression::Condition(ref mut c) = expr {
if c.conditions.is_empty() {
return self;
}
if c.conditions.len() == 1 && !c.negate {
expr = c.conditions.pop().unwrap();
}
}
self.conditions.push(expr);
self
}
#[allow(clippy::should_implement_trait)]
pub fn add_option<C>(self, other: Option<C>) -> Self
where
C: Into<ConditionExpression>,
{
if let Some(other) = other {
self.add(other)
} else {
self
}
}
pub fn any() -> Condition {
Condition {
negate: false,
condition_type: ConditionType::Any,
conditions: Vec::new(),
}
}
pub fn all() -> Condition {
Condition {
negate: false,
condition_type: ConditionType::All,
conditions: Vec::new(),
}
}
#[allow(clippy::should_implement_trait)]
pub fn not(mut self) -> Self {
self.negate = !self.negate;
self
}
}
impl std::convert::From<Condition> for ConditionExpression {
fn from(condition: Condition) -> Self {
ConditionExpression::Condition(condition)
}
}
impl std::convert::From<SimpleExpr> for ConditionExpression {
fn from(condition: SimpleExpr) -> Self {
ConditionExpression::SimpleExpr(condition)
}
}
#[macro_export]
macro_rules! any {
( $( $x:expr ),* ) => {
{
let mut tmp = sea_query::Condition::any();
$(
tmp = tmp.add($x);
)*
tmp
}
};
}
#[macro_export]
macro_rules! all {
( $( $x:expr ),* ) => {
{
let mut tmp = sea_query::Condition::all();
$(
tmp = tmp.add($x);
)*
tmp
}
};
}
pub trait ConditionalStatement {
fn and_where(&mut self, other: SimpleExpr) -> &mut Self {
self.cond_where(other)
}
fn and_where_option(&mut self, other: Option<SimpleExpr>) -> &mut Self {
if let Some(other) = other {
self.and_where(other);
}
self
}
#[deprecated(
since = "0.12.0",
note = "Please use [`ConditionalStatement::cond_where`]. Calling `or_where` after `and_where` will panic."
)]
fn or_where(&mut self, other: SimpleExpr) -> &mut Self {
self.and_or_where(LogicalChainOper::Or(other))
}
#[doc(hidden)]
fn and_or_where(&mut self, condition: LogicalChainOper) -> &mut Self;
fn cond_where<C>(&mut self, condition: C) -> &mut Self
where
C: IntoCondition;
}
impl IntoCondition for SimpleExpr {
fn into_condition(self) -> Condition {
Condition::all().add(self)
}
}
impl IntoCondition for Condition {
fn into_condition(self) -> Condition {
self
}
}
impl Default for ConditionHolderContents {
fn default() -> Self {
Self::Empty
}
}
impl Default for ConditionHolder {
fn default() -> Self {
Self::new()
}
}
impl ConditionHolder {
pub fn new() -> Self {
Self {
contents: ConditionHolderContents::Empty,
}
}
pub fn new_with_condition(condition: Condition) -> Self {
let mut slf = Self::new();
slf.add_condition(condition);
slf
}
pub fn is_empty(&self) -> bool {
match &self.contents {
ConditionHolderContents::Empty => true,
ConditionHolderContents::Chain(c) => c.is_empty(),
ConditionHolderContents::Condition(c) => c.conditions.is_empty(),
}
}
pub fn is_one(&self) -> bool {
match &self.contents {
ConditionHolderContents::Empty => true,
ConditionHolderContents::Chain(c) => c.len() == 1,
ConditionHolderContents::Condition(c) => c.conditions.len() == 1,
}
}
pub fn add_and_or(&mut self, condition: LogicalChainOper) {
match &mut self.contents {
ConditionHolderContents::Empty => {
self.contents = ConditionHolderContents::Chain(vec![condition])
}
ConditionHolderContents::Chain(c) => c.push(condition),
ConditionHolderContents::Condition(_) => {
panic!("Cannot mix `and_where`/`or_where` and `cond_where` in statements")
}
}
}
pub fn add_condition(&mut self, condition: Condition) {
match std::mem::take(&mut self.contents) {
ConditionHolderContents::Empty => {
self.contents = ConditionHolderContents::Condition(condition);
}
ConditionHolderContents::Condition(current) => {
self.contents = ConditionHolderContents::Condition(current.add(condition));
}
ConditionHolderContents::Chain(_) => {
panic!("Cannot mix `and_where`/`or_where` and `cond_where` in statements")
}
}
}
}