diesel/expression_methods/bool_expression_methods.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
use crate::dsl;
use crate::expression::grouped::Grouped;
use crate::expression::operators::{And, Or};
use crate::expression::{AsExpression, Expression, TypedExpressionType};
use crate::sql_types::{self, BoolOrNullableBool, SqlType};
/// Methods present on boolean expressions
pub trait BoolExpressionMethods: Expression + Sized {
/// Creates a SQL `AND` expression
///
/// # Example
///
/// ```
/// # include!("../doctest_setup.rs");
/// #
/// # fn main() {
/// # run_test().unwrap();
/// # }
/// #
/// # fn run_test() -> QueryResult<()> {
/// # use schema::animals::dsl::*;
/// # let connection = &mut establish_connection();
/// #
/// diesel::insert_into(animals)
/// .values(&vec![
/// (species.eq("ferret"), legs.eq(4), name.eq("Freddy")),
/// (species.eq("ferret"), legs.eq(4), name.eq("Jack")),
/// ])
/// .execute(connection)?;
///
/// let data = animals.select((species, name))
/// .filter(species.eq("ferret").and(name.eq("Jack")))
/// .load(connection)?;
/// let expected = vec![
/// (String::from("ferret"), Some(String::from("Jack"))),
/// ];
/// assert_eq!(expected, data);
/// # Ok(())
/// # }
/// ```
fn and<T, ST>(self, other: T) -> dsl::And<Self, T, ST>
where
Self::SqlType: SqlType,
ST: SqlType + TypedExpressionType + BoolOrNullableBool,
T: AsExpression<ST>,
And<Self, T::Expression>: Expression,
{
Grouped(And::new(self, other.as_expression()))
}
/// Creates a SQL `OR` expression
///
/// The result will be wrapped in parenthesis, so that precedence matches
/// that of your function calls. For example, `false.and(false.or(true))`
/// will generate the SQL `FALSE AND (FALSE OR TRUE)`, which returns `false`
///
/// # Example
///
/// ```
/// # include!("../doctest_setup.rs");
/// #
/// # fn main() {
/// # run_test().unwrap();
/// # }
/// #
/// # fn run_test() -> QueryResult<()> {
/// # use schema::animals::dsl::*;
/// # let connection = &mut establish_connection();
/// #
/// diesel::insert_into(animals)
/// .values(&vec![
/// (species.eq("ferret"), legs.eq(4), name.eq("Freddy")),
/// (species.eq("ferret"), legs.eq(4), name.eq("Jack")),
/// ])
/// .execute(connection)?;
///
/// let data = animals.select((species, name))
/// .filter(species.eq("ferret").or(name.eq("Jack")))
/// .load(connection)?;
/// let expected = vec![
/// (String::from("dog"), Some(String::from("Jack"))),
/// (String::from("ferret"), Some(String::from("Freddy"))),
/// (String::from("ferret"), Some(String::from("Jack"))),
/// ];
/// assert_eq!(expected, data);
/// # Ok(())
/// # }
/// ```
fn or<T, ST>(self, other: T) -> dsl::Or<Self, T, ST>
where
Self::SqlType: SqlType,
ST: SqlType + TypedExpressionType + BoolOrNullableBool,
T: AsExpression<ST>,
Or<Self, T::Expression>: Expression,
{
Grouped(Or::new(self, other.as_expression()))
}
}
impl<T> BoolExpressionMethods for T
where
T: Expression,
T::SqlType: BoolOrNullableBool,
{
}
/// Allow ~type inference on [And](crate::helper_types::And) and [Or](crate::helper_types::Or)
/// helper types
///
/// This is used to be statistically correct as last generic parameter of `dsl::And` and `dsl::Or`
/// without having to specify an additional type parameter.
///
/// It works with types that are [Expression]s and have a [`SqlType`](Expression::SqlType) that is
/// either [`Bool`](sql_types::Bool) or [`Nullable<Bool>`](sql_types::Nullable), and with [`bool`]
/// (and `Option<bool>` and references to those).
///
/// Cases where an additional type parameter would still have to be specified in the helper type
/// generic parameters are:
/// - If this trait isn't implemented for the `other` parameter of the expression
/// (in that case the user (you?) probably wants to implement it)
/// - If the user actually was using the not-preferred implementation of `AsExpression`
/// (e.g. towards `Nullable<Bool>` instead of `Bool`)
pub trait PreferredBoolSqlType {
/// The preferred `Bool` SQL type for this AsExpression implementation.
///
/// That should be either `Bool` or `Nullable<Bool>`.
type PreferredSqlType;
}
impl<E: Expression> PreferredBoolSqlType for E
where
E::SqlType: BoolOrNullableBool,
{
type PreferredSqlType = <E as Expression>::SqlType;
}
/// This impl has to live in Diesel because otherwise it would conflict with the blanket impl above
/// because "diesel might add an implementation of Expression for bool"
impl PreferredBoolSqlType for bool {
type PreferredSqlType = sql_types::Bool;
}
impl PreferredBoolSqlType for &bool {
type PreferredSqlType = sql_types::Bool;
}
impl PreferredBoolSqlType for &&bool {
type PreferredSqlType = sql_types::Bool;
}
impl PreferredBoolSqlType for Option<bool> {
type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
}
impl PreferredBoolSqlType for &Option<bool> {
type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
}
impl PreferredBoolSqlType for &&Option<bool> {
type PreferredSqlType = sql_types::Nullable<sql_types::Bool>;
}