sql-orm 0.2.0-rc.1

Public API crate for the sql-orm workspace.
Documentation
use sql_orm_query::Predicate;

pub trait PredicateCompositionExt {
    fn and(self, other: Predicate) -> Predicate;

    fn or(self, other: Predicate) -> Predicate;

    fn not(self) -> Predicate;
}

impl PredicateCompositionExt for Predicate {
    fn and(self, other: Predicate) -> Predicate {
        match (self, other) {
            (Predicate::And(mut left), Predicate::And(right)) => {
                left.extend(right);
                Predicate::and(left)
            }
            (Predicate::And(mut left), right) => {
                left.push(right);
                Predicate::and(left)
            }
            (left, Predicate::And(mut right)) => {
                let mut predicates = vec![left];
                predicates.append(&mut right);
                Predicate::and(predicates)
            }
            (left, right) => Predicate::and(vec![left, right]),
        }
    }

    fn or(self, other: Predicate) -> Predicate {
        match (self, other) {
            (Predicate::Or(mut left), Predicate::Or(right)) => {
                left.extend(right);
                Predicate::or(left)
            }
            (Predicate::Or(mut left), right) => {
                left.push(right);
                Predicate::or(left)
            }
            (left, Predicate::Or(mut right)) => {
                let mut predicates = vec![left];
                predicates.append(&mut right);
                Predicate::or(predicates)
            }
            (left, right) => Predicate::or(vec![left, right]),
        }
    }

    fn not(self) -> Predicate {
        Predicate::negate(self)
    }
}

#[cfg(test)]
mod tests {
    use super::PredicateCompositionExt;
    use sql_orm_core::SqlValue;
    use sql_orm_query::{Expr, Predicate};

    #[test]
    fn and_combines_two_predicates() {
        let left = Predicate::eq(
            Expr::value(SqlValue::Bool(true)),
            Expr::value(SqlValue::Bool(true)),
        );
        let right = Predicate::gt(
            Expr::value(SqlValue::I64(10)),
            Expr::value(SqlValue::I64(5)),
        );

        assert_eq!(
            left.clone().and(right.clone()),
            Predicate::and(vec![left, right])
        );
    }

    #[test]
    fn and_flattens_existing_and_groups() {
        let first = Predicate::eq(Expr::value(SqlValue::I64(1)), Expr::value(SqlValue::I64(1)));
        let second = Predicate::eq(Expr::value(SqlValue::I64(2)), Expr::value(SqlValue::I64(2)));
        let third = Predicate::eq(Expr::value(SqlValue::I64(3)), Expr::value(SqlValue::I64(3)));

        assert_eq!(
            Predicate::and(vec![first.clone(), second.clone()]).and(third.clone()),
            Predicate::and(vec![first, second, third])
        );
    }

    #[test]
    fn or_combines_and_flattens_predicates() {
        let first = Predicate::eq(Expr::value(SqlValue::I64(1)), Expr::value(SqlValue::I64(1)));
        let second = Predicate::eq(Expr::value(SqlValue::I64(2)), Expr::value(SqlValue::I64(2)));
        let third = Predicate::eq(Expr::value(SqlValue::I64(3)), Expr::value(SqlValue::I64(3)));

        assert_eq!(
            Predicate::or(vec![first.clone(), second.clone()]).or(third.clone()),
            Predicate::or(vec![first, second, third])
        );
    }

    #[test]
    fn not_wraps_predicate_in_negation() {
        let predicate = Predicate::eq(
            Expr::value(SqlValue::Bool(true)),
            Expr::value(SqlValue::Bool(false)),
        );

        assert_eq!(predicate.clone().not(), Predicate::negate(predicate));
    }
}