From adc864e2b226a870a554b8e661488460d6bbd537 Mon Sep 17 00:00:00 2001 From: Thomas BESSOU Date: Thu, 12 Oct 2023 15:53:23 +0200 Subject: [PATCH 1/4] Add support for CASE WHEN ... ELSE ... END expression --- diesel/src/expression/case_when.rs | 128 ++++++++++++++++++++++++++ diesel/src/expression/helper_types.rs | 9 ++ diesel/src/expression/mod.rs | 3 + 3 files changed, 140 insertions(+) create mode 100644 diesel/src/expression/case_when.rs diff --git a/diesel/src/expression/case_when.rs b/diesel/src/expression/case_when.rs new file mode 100644 index 000000000000..5834a83ec530 --- /dev/null +++ b/diesel/src/expression/case_when.rs @@ -0,0 +1,128 @@ +use crate::expression::grouped::Grouped; +use crate::expression::helper_types::case_when_else; +use crate::expression::Expression; +use crate::sql_types::{BoolOrNullableBool, SqlType}; + +use super::{AsExpression, TypedExpressionType}; + +/// Creates a SQL `CASE WHEN ... ELSE ... END` expression +/// +/// # Example +/// +/// ```rust +/// # include!("../doctest_setup.rs"); +/// # +/// # fn main() { +/// # use schema::users::dsl::*; +/// # let connection = &mut establish_connection(); +/// use diesel::dsl::case_when_else; +/// +/// let users_with_name: Vec<(i32, i32)> = users +/// .select((id, case_when_else(name.eq("Sean"), id, 0))) +/// .load(connection) +/// .unwrap(); +/// +/// assert_eq!(&[(1, 1), (2, 0)], users_with_name.as_slice()); +/// # } +/// ``` +pub fn case_when_else( + condition: C, + if_true: T, + if_false: F, +) -> case_when_else +where + C: Expression, + ::SqlType: BoolOrNullableBool, + T: AsExpression, + F: AsExpression, + ST: SqlType + TypedExpressionType, +{ + CaseWhenElse { + condition: Grouped(condition), + if_true: Grouped(if_true.as_expression()), + if_false: Grouped(if_false.as_expression()), + } +} + +pub(crate) use case_when_else_impl::CaseWhenElse; +mod case_when_else_impl { + use diesel_derives::{DieselNumericOps, QueryId, ValidGrouping}; + + use crate::expression::{AppearsOnTable, Expression, SelectableExpression}; + use crate::query_builder::{AstPass, QueryFragment}; + use crate::query_source::aliasing; + use crate::sql_types::BoolOrNullableBool; + + #[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, ValidGrouping)] + pub struct CaseWhenElse { + pub(super) condition: C, + pub(super) if_true: T, + pub(super) if_false: F, + } + + impl SelectableExpression for CaseWhenElse + where + CaseWhenElse: AppearsOnTable, + C: SelectableExpression, + T: SelectableExpression, + F: SelectableExpression, + { + } + + impl AppearsOnTable for CaseWhenElse + where + CaseWhenElse: Expression, + C: AppearsOnTable, + T: AppearsOnTable, + F: AppearsOnTable, + { + } + + impl Expression for CaseWhenElse + where + C: Expression, + ::SqlType: BoolOrNullableBool, + T: Expression, + F: Expression::SqlType>, + { + type SqlType = ::SqlType; + } + impl QueryFragment for CaseWhenElse + where + C: QueryFragment, + T: QueryFragment, + F: QueryFragment, + DB: crate::backend::Backend, + { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> crate::result::QueryResult<()> { + out.push_sql("CASE WHEN "); + self.condition.walk_ast(out.reborrow())?; + out.push_sql(" THEN "); + self.if_true.walk_ast(out.reborrow())?; + out.push_sql(" ELSE "); + self.if_false.walk_ast(out.reborrow())?; + out.push_sql(" END"); + Ok(()) + } + } + impl aliasing::FieldAliasMapper for CaseWhenElse + where + S: aliasing::AliasSource, + C: aliasing::FieldAliasMapper, + T: aliasing::FieldAliasMapper, + F: aliasing::FieldAliasMapper, + { + type Out = CaseWhenElse< + >::Out, + >::Out, + >::Out, + >; + fn map(self, alias: &aliasing::Alias) -> Self::Out { + CaseWhenElse { + condition: self.condition.map(alias), + if_true: self.if_true.map(alias), + if_false: self.if_false.map(alias), + } + } + } +} diff --git a/diesel/src/expression/helper_types.rs b/diesel/src/expression/helper_types.rs index fee01a8904aa..801ba5c8863b 100644 --- a/diesel/src/expression/helper_types.rs +++ b/diesel/src/expression/helper_types.rs @@ -120,6 +120,15 @@ pub type Like = Grouped = Grouped>>>; +/// The return type of [`case_when_else()`](crate::expression::case_when::case_when_else) +#[allow(non_camel_case_types)] +pub type case_when_else::SqlType> = + crate::expression::case_when::CaseWhenElse< + Grouped, + Grouped>, + Grouped>, + >; + /// Represents the return type of [`.as_select()`](crate::prelude::SelectableHelper::as_select) pub type AsSelect = SelectBy; diff --git a/diesel/src/expression/mod.rs b/diesel/src/expression/mod.rs index 48b7fe942222..f54d5244a470 100644 --- a/diesel/src/expression/mod.rs +++ b/diesel/src/expression/mod.rs @@ -36,6 +36,7 @@ mod not; pub(crate) mod nullable; #[macro_use] pub(crate) mod operators; +mod case_when; pub(crate) mod select_by; mod sql_literal; pub(crate) mod subselect; @@ -51,6 +52,8 @@ pub use self::operators::Concat; pub(crate) mod dsl { use crate::dsl::SqlTypeOf; + #[doc(inline)] + pub use super::case_when::*; #[doc(inline)] pub use super::count::*; #[doc(inline)] From db456977545873a75c1501fc544754bf65a85536 Mon Sep 17 00:00:00 2001 From: Thomas BESSOU Date: Thu, 12 Oct 2023 16:39:07 +0200 Subject: [PATCH 2/4] add comment about how it interacts with nullability --- diesel/src/expression/case_when.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/diesel/src/expression/case_when.rs b/diesel/src/expression/case_when.rs index 5834a83ec530..3f6792f659b7 100644 --- a/diesel/src/expression/case_when.rs +++ b/diesel/src/expression/case_when.rs @@ -25,6 +25,12 @@ use super::{AsExpression, TypedExpressionType}; /// assert_eq!(&[(1, 1), (2, 0)], users_with_name.as_slice()); /// # } /// ``` +/// +/// Note that the SQL types of the `if_true` and `if_false` expressions should +/// be equal. This includes whether they are wrapped in +/// [`Nullable`](crate::sql_types::Nullable), so you may need to call +/// [`nullable`](crate::expression_methods::NullableExpressionMethods::nullable) +/// on one of them. pub fn case_when_else( condition: C, if_true: T, From c88e6412cef2514a888601a78f83f7dd80bff0b8 Mon Sep 17 00:00:00 2001 From: Thomas BESSOU Date: Mon, 23 Oct 2023 21:43:36 +0200 Subject: [PATCH 3/4] Full support for case_when with recursive types --- diesel/src/expression/case_when.rs | 397 ++++++++++++++++++++++---- diesel/src/expression/helper_types.rs | 25 +- 2 files changed, 357 insertions(+), 65 deletions(-) diff --git a/diesel/src/expression/case_when.rs b/diesel/src/expression/case_when.rs index 3f6792f659b7..bdf092c5a3a7 100644 --- a/diesel/src/expression/case_when.rs +++ b/diesel/src/expression/case_when.rs @@ -1,24 +1,42 @@ use crate::expression::grouped::Grouped; -use crate::expression::helper_types::case_when_else; -use crate::expression::Expression; +use crate::expression::{helper_types, Expression}; use crate::sql_types::{BoolOrNullableBool, SqlType}; +use diesel_derives::{DieselNumericOps, QueryId, ValidGrouping}; use super::{AsExpression, TypedExpressionType}; -/// Creates a SQL `CASE WHEN ... ELSE ... END` expression +/// Creates a SQL `CASE WHEN ... END` expression /// /// # Example /// -/// ```rust +/// ``` +/// # include!("../doctest_setup.rs"); +/// # +/// # fn main() { +/// # use schema::users::dsl::*; +/// # let connection = &mut establish_connection(); +/// use diesel::dsl::case_when; +/// +/// let users_with_name: Vec<(i32, Option)> = users +/// .select((id, case_when(name.eq("Sean"), id))) +/// .load(connection) +/// .unwrap(); +/// +/// assert_eq!(&[(1, Some(1)), (2, None)], users_with_name.as_slice()); +/// # } +/// ``` +/// +/// # `ELSE` clause +/// ``` /// # include!("../doctest_setup.rs"); /// # /// # fn main() { /// # use schema::users::dsl::*; /// # let connection = &mut establish_connection(); -/// use diesel::dsl::case_when_else; +/// use diesel::dsl::case_when; /// /// let users_with_name: Vec<(i32, i32)> = users -/// .select((id, case_when_else(name.eq("Sean"), id, 0))) +/// .select((id, case_when(name.eq("Sean"), id).else_(0))) /// .load(connection) /// .unwrap(); /// @@ -26,108 +44,369 @@ use super::{AsExpression, TypedExpressionType}; /// # } /// ``` /// -/// Note that the SQL types of the `if_true` and `if_false` expressions should +/// Note that the SQL types of the `case_when` and `else` expressions should /// be equal. This includes whether they are wrapped in /// [`Nullable`](crate::sql_types::Nullable), so you may need to call /// [`nullable`](crate::expression_methods::NullableExpressionMethods::nullable) /// on one of them. -pub fn case_when_else( - condition: C, - if_true: T, - if_false: F, -) -> case_when_else +/// +/// # More `WHEN` branches +/// ``` +/// # include!("../doctest_setup.rs"); +/// # +/// # fn main() { +/// # use schema::users::dsl::*; +/// # let connection = &mut establish_connection(); +/// use diesel::dsl::case_when; +/// +/// let users_with_name: Vec<(i32, Option)> = users +/// .select((id, case_when(name.eq("Sean"), id).when(name.eq("Tess"), 2))) +/// .load(connection) +/// .unwrap(); +/// +/// assert_eq!(&[(1, Some(1)), (2, Some(2))], users_with_name.as_slice()); +/// # } +/// ``` +pub fn case_when(condition: C, if_true: T) -> helper_types::case_when where C: Expression, ::SqlType: BoolOrNullableBool, T: AsExpression, - F: AsExpression, ST: SqlType + TypedExpressionType, { - CaseWhenElse { - condition: Grouped(condition), - if_true: Grouped(if_true.as_expression()), - if_false: Grouped(if_false.as_expression()), + CaseWhen { + whens: CaseWhenConditionsLeaf { + when: Grouped(condition), + then: Grouped(if_true.as_expression()), + }, + else_expr: NoElseExpression, + } +} + +/// A SQL `CASE WHEN ... END` expression +#[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, ValidGrouping)] +pub struct CaseWhen { + whens: Whens, + else_expr: E, +} + +impl CaseWhen { + /// Add an additional `WHEN ... THEN ...` branch to the `CASE` expression + /// + /// See the [`case_when`] documentation for more details. + pub fn when(self, condition: C, if_true: T) -> helper_types::When + where + Self: CaseWhenTypesExtractor, + C: Expression, + ::SqlType: BoolOrNullableBool, + T: AsExpression<::OutputExpressionSpecifiedSqlType>, + { + CaseWhen { + whens: CaseWhenConditionsIntermediateNode { + first_whens: self.whens, + last_when: CaseWhenConditionsLeaf { + when: Grouped(condition), + then: Grouped(if_true.as_expression()), + }, + }, + else_expr: self.else_expr, + } } } -pub(crate) use case_when_else_impl::CaseWhenElse; -mod case_when_else_impl { - use diesel_derives::{DieselNumericOps, QueryId, ValidGrouping}; +impl CaseWhen { + /// Sets the `ELSE` branch of the `CASE` expression + /// + /// See the [`case_when`] documentation for more details. + pub fn else_(self, if_no_other_branch_matched: E) -> helper_types::Else_ + where + Self: CaseWhenTypesExtractor, + E: AsExpression<::OutputExpressionSpecifiedSqlType>, + { + CaseWhen { + whens: self.whens, + else_expr: ElseExpression { + expr: Grouped(if_no_other_branch_matched.as_expression()), + }, + } + } +} + +pub(crate) use non_public_types::*; +mod non_public_types { + use super::CaseWhen; - use crate::expression::{AppearsOnTable, Expression, SelectableExpression}; + use diesel_derives::{QueryId, ValidGrouping}; + + use crate::expression::{ + AppearsOnTable, Expression, SelectableExpression, TypedExpressionType, + }; use crate::query_builder::{AstPass, QueryFragment}; use crate::query_source::aliasing; - use crate::sql_types::BoolOrNullableBool; + use crate::sql_types::{BoolOrNullableBool, IntoNullable, SqlType}; + + #[derive(Debug, Clone, Copy, QueryId, ValidGrouping)] + pub struct CaseWhenConditionsLeaf { + pub(super) when: W, + pub(super) then: T, + } + + #[derive(Debug, Clone, Copy, QueryId, ValidGrouping)] + pub struct CaseWhenConditionsIntermediateNode { + pub(super) first_whens: Whens, + pub(super) last_when: CaseWhenConditionsLeaf, + } + + pub trait CaseWhenConditions { + type OutputExpressionSpecifiedSqlType: SqlType + TypedExpressionType; + } + impl CaseWhenConditions for CaseWhenConditionsLeaf + where + ::SqlType: SqlType + TypedExpressionType, + { + type OutputExpressionSpecifiedSqlType = T::SqlType; + } + // This intentionally doesn't re-check inner `Whens` here, because this trait is + // only used to allow expression SQL type inference for `.when` calls so we + // want to make it as lightweight as possible for fast compilation. Actual + // guarantees are provided by the other implementations below + impl CaseWhenConditions for CaseWhenConditionsIntermediateNode + where + ::SqlType: SqlType + TypedExpressionType, + { + type OutputExpressionSpecifiedSqlType = T::SqlType; + } + + #[derive(Debug, Clone, Copy, QueryId, ValidGrouping)] + pub struct NoElseExpression; + #[derive(Debug, Clone, Copy, QueryId, ValidGrouping)] + pub struct ElseExpression { + pub(super) expr: E, + } + + /// Largely internal trait used to define the [`When`] and [`Else_`] type + /// aliases + /// + /// It should typically not be needed in user code unless writing extremely + /// generic functions + pub trait CaseWhenTypesExtractor { + /// The + /// This may not be the actual output expression type: if there is no + /// `else` it will be made `Nullable` + type OutputExpressionSpecifiedSqlType: SqlType + TypedExpressionType; + type Whens; + type Else; + } + impl CaseWhenTypesExtractor for CaseWhen + where + Whens: CaseWhenConditions, + { + type OutputExpressionSpecifiedSqlType = Whens::OutputExpressionSpecifiedSqlType; + type Whens = Whens; + type Else = E; + } - #[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, ValidGrouping)] - pub struct CaseWhenElse { - pub(super) condition: C, - pub(super) if_true: T, - pub(super) if_false: F, + impl SelectableExpression for CaseWhen, NoElseExpression> + where + CaseWhen, NoElseExpression>: AppearsOnTable, + W: SelectableExpression, + T: SelectableExpression, + { } - impl SelectableExpression for CaseWhenElse + impl SelectableExpression + for CaseWhen, ElseExpression> where - CaseWhenElse: AppearsOnTable, - C: SelectableExpression, + CaseWhen, ElseExpression>: AppearsOnTable, + W: SelectableExpression, T: SelectableExpression, - F: SelectableExpression, + E: SelectableExpression, { } - impl AppearsOnTable for CaseWhenElse + impl SelectableExpression + for CaseWhen, E> where - CaseWhenElse: Expression, - C: AppearsOnTable, + Self: AppearsOnTable, + W: SelectableExpression, + T: SelectableExpression, + CaseWhen: SelectableExpression, + { + } + + impl AppearsOnTable for CaseWhen, NoElseExpression> + where + CaseWhen, NoElseExpression>: Expression, + W: AppearsOnTable, T: AppearsOnTable, - F: AppearsOnTable, { } - impl Expression for CaseWhenElse + impl AppearsOnTable for CaseWhen, ElseExpression> where - C: Expression, - ::SqlType: BoolOrNullableBool, + CaseWhen, ElseExpression>: Expression, + W: AppearsOnTable, + T: AppearsOnTable, + E: AppearsOnTable, + { + } + + impl AppearsOnTable + for CaseWhen, E> + where + Self: Expression, + W: AppearsOnTable, + T: AppearsOnTable, + CaseWhen: AppearsOnTable, + { + } + + impl Expression for CaseWhen, NoElseExpression> + where + W: Expression, + ::SqlType: BoolOrNullableBool, T: Expression, - F: Expression::SqlType>, + ::SqlType: IntoNullable, + <::SqlType as IntoNullable>::Nullable: SqlType + TypedExpressionType, + { + type SqlType = <::SqlType as IntoNullable>::Nullable; + } + impl Expression for CaseWhen, ElseExpression> + where + W: Expression, + ::SqlType: BoolOrNullableBool, + T: Expression, + { + type SqlType = T::SqlType; + } + impl Expression for CaseWhen, E> + where + CaseWhen, E>: Expression, + CaseWhen: Expression< + SqlType = , E> as Expression>::SqlType, + >, { - type SqlType = ::SqlType; + type SqlType = , E> as Expression>::SqlType; } - impl QueryFragment for CaseWhenElse + + impl QueryFragment for CaseWhen + where + DB: crate::backend::Backend, + Whens: QueryFragment, + E: QueryFragment, + { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> crate::QueryResult<()> { + out.push_sql("CASE"); + self.whens.walk_ast(out.reborrow())?; + self.else_expr.walk_ast(out.reborrow())?; + out.push_sql(" END"); + Ok(()) + } + } + + impl QueryFragment for CaseWhenConditionsLeaf + where + DB: crate::backend::Backend, + W: QueryFragment, + T: QueryFragment, + { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> crate::QueryResult<()> { + out.push_sql(" WHEN "); + self.when.walk_ast(out.reborrow())?; + out.push_sql(" THEN "); + self.then.walk_ast(out.reborrow())?; + Ok(()) + } + } + + impl QueryFragment for CaseWhenConditionsIntermediateNode where - C: QueryFragment, + DB: crate::backend::Backend, + Whens: QueryFragment, + W: QueryFragment, T: QueryFragment, - F: QueryFragment, + { + fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> crate::QueryResult<()> { + self.first_whens.walk_ast(out.reborrow())?; + self.last_when.walk_ast(out.reborrow())?; + Ok(()) + } + } + + impl QueryFragment for NoElseExpression + where + DB: crate::backend::Backend, + { + fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> crate::result::QueryResult<()> { + let _ = out; + Ok(()) + } + } + impl QueryFragment for ElseExpression + where + E: QueryFragment, DB: crate::backend::Backend, { fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> crate::result::QueryResult<()> { - out.push_sql("CASE WHEN "); - self.condition.walk_ast(out.reborrow())?; - out.push_sql(" THEN "); - self.if_true.walk_ast(out.reborrow())?; out.push_sql(" ELSE "); - self.if_false.walk_ast(out.reborrow())?; - out.push_sql(" END"); + self.expr.walk_ast(out.reborrow())?; Ok(()) } } - impl aliasing::FieldAliasMapper for CaseWhenElse + + impl aliasing::FieldAliasMapper for CaseWhen + where + S: aliasing::AliasSource, + Conditions: aliasing::FieldAliasMapper, + E: aliasing::FieldAliasMapper, + { + type Out = CaseWhen< + >::Out, + >::Out, + >; + fn map(self, alias: &aliasing::Alias) -> Self::Out { + CaseWhen { + whens: self.whens.map(alias), + else_expr: self.else_expr.map(alias), + } + } + } + + impl aliasing::FieldAliasMapper for CaseWhenConditionsLeaf + where + S: aliasing::AliasSource, + W: aliasing::FieldAliasMapper, + T: aliasing::FieldAliasMapper, + { + type Out = CaseWhenConditionsLeaf< + >::Out, + >::Out, + >; + fn map(self, alias: &aliasing::Alias) -> Self::Out { + CaseWhenConditionsLeaf { + when: self.when.map(alias), + then: self.then.map(alias), + } + } + } + + impl aliasing::FieldAliasMapper + for CaseWhenConditionsIntermediateNode where S: aliasing::AliasSource, - C: aliasing::FieldAliasMapper, + W: aliasing::FieldAliasMapper, T: aliasing::FieldAliasMapper, - F: aliasing::FieldAliasMapper, + Whens: aliasing::FieldAliasMapper, { - type Out = CaseWhenElse< - >::Out, + type Out = CaseWhenConditionsIntermediateNode< + >::Out, >::Out, - >::Out, + >::Out, >; fn map(self, alias: &aliasing::Alias) -> Self::Out { - CaseWhenElse { - condition: self.condition.map(alias), - if_true: self.if_true.map(alias), - if_false: self.if_false.map(alias), + CaseWhenConditionsIntermediateNode { + first_whens: self.first_whens.map(alias), + last_when: self.last_when.map(alias), } } } diff --git a/diesel/src/expression/helper_types.rs b/diesel/src/expression/helper_types.rs index 801ba5c8863b..bd06d445fd2e 100644 --- a/diesel/src/expression/helper_types.rs +++ b/diesel/src/expression/helper_types.rs @@ -5,6 +5,7 @@ use super::array_comparison::{AsInExpression, In, NotIn}; use super::grouped::Grouped; use super::select_by::SelectBy; use super::{AsExpression, Expression}; +use crate::expression; use crate::expression_methods::PreferredBoolSqlType; use crate::sql_types; @@ -120,14 +121,26 @@ pub type Like = Grouped = Grouped>>>; -/// The return type of [`case_when_else()`](crate::expression::case_when::case_when_else) +/// The return type of [`case_when()`](expression::case_when::case_when) #[allow(non_camel_case_types)] -pub type case_when_else::SqlType> = - crate::expression::case_when::CaseWhenElse< +pub type case_when::SqlType> = expression::case_when::CaseWhen< + expression::case_when::CaseWhenConditionsLeaf, Grouped>>, + expression::case_when::NoElseExpression, +>; +/// The return type of [`case_when(...).when(...)`](expression::case_when::CaseWhen::when) +pub type When = expression::case_when::CaseWhen< + expression::case_when::CaseWhenConditionsIntermediateNode< Grouped, - Grouped>, - Grouped>, - >; + Grouped::OutputExpressionSpecifiedSqlType>>, + ::Whens, + >, + ::Else, +>; +/// The return type of [`case_when(...).else_(...)`](expression::case_when::CaseWhen::else_) +pub type Else_ = expression::case_when::CaseWhen< + ::Whens, + expression::case_when::ElseExpression::OutputExpressionSpecifiedSqlType>>>, +>; /// Represents the return type of [`.as_select()`](crate::prelude::SelectableHelper::as_select) pub type AsSelect = SelectBy; From 6f45bae8a94487489fc374a81cd2a3a6a5c14e84 Mon Sep 17 00:00:00 2001 From: Thomas BESSOU Date: Tue, 24 Oct 2023 21:13:11 +0200 Subject: [PATCH 4/4] else_ -> otherwise --- diesel/src/expression/case_when.rs | 10 ++++++---- diesel/src/expression/helper_types.rs | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/diesel/src/expression/case_when.rs b/diesel/src/expression/case_when.rs index bdf092c5a3a7..e5c4df80279a 100644 --- a/diesel/src/expression/case_when.rs +++ b/diesel/src/expression/case_when.rs @@ -36,7 +36,7 @@ use super::{AsExpression, TypedExpressionType}; /// use diesel::dsl::case_when; /// /// let users_with_name: Vec<(i32, i32)> = users -/// .select((id, case_when(name.eq("Sean"), id).else_(0))) +/// .select((id, case_when(name.eq("Sean"), id).otherwise(0))) /// .load(connection) /// .unwrap(); /// @@ -117,8 +117,10 @@ impl CaseWhen { impl CaseWhen { /// Sets the `ELSE` branch of the `CASE` expression /// + /// It is named this way because `else` is a reserved keyword in Rust + /// /// See the [`case_when`] documentation for more details. - pub fn else_(self, if_no_other_branch_matched: E) -> helper_types::Else_ + pub fn otherwise(self, if_no_other_branch_matched: E) -> helper_types::Otherwise where Self: CaseWhenTypesExtractor, E: AsExpression<::OutputExpressionSpecifiedSqlType>, @@ -184,8 +186,8 @@ mod non_public_types { pub(super) expr: E, } - /// Largely internal trait used to define the [`When`] and [`Else_`] type - /// aliases + /// Largely internal trait used to define the [`When`] and [`Otherwise`] + /// type aliases /// /// It should typically not be needed in user code unless writing extremely /// generic functions diff --git a/diesel/src/expression/helper_types.rs b/diesel/src/expression/helper_types.rs index bd06d445fd2e..5104b93a0c05 100644 --- a/diesel/src/expression/helper_types.rs +++ b/diesel/src/expression/helper_types.rs @@ -136,8 +136,8 @@ pub type When = expression::case_when::CaseWhen< >, ::Else, >; -/// The return type of [`case_when(...).else_(...)`](expression::case_when::CaseWhen::else_) -pub type Else_ = expression::case_when::CaseWhen< +/// The return type of [`case_when(...).otherwise(...)`](expression::case_when::CaseWhen::otherwise) +pub type Otherwise = expression::case_when::CaseWhen< ::Whens, expression::case_when::ElseExpression::OutputExpressionSpecifiedSqlType>>>, >;