Skip to main content

diesel/expression/
cast.rs

1//! SQL `CAST(expr AS sql_type)` expression support
2
3use crate::expression::{AppearsOnTable, Expression, SelectableExpression, ValidGrouping};
4use crate::query_source::aliasing::{AliasSource, FieldAliasMapper};
5use crate::result::QueryResult;
6use crate::{query_builder, query_source, sql_types};
7
8use core::marker::PhantomData;
9
10pub(crate) mod private {
11    use super::*;
12
13    #[derive(#[automatically_derived]
impl<E: ::core::fmt::Debug, ST: ::core::fmt::Debug> ::core::fmt::Debug for
    Cast<E, ST> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "Cast", "expr",
            &self.expr, "sql_type", &&self.sql_type)
    }
}Debug, #[automatically_derived]
impl<E: ::core::clone::Clone, ST: ::core::clone::Clone> ::core::clone::Clone
    for Cast<E, ST> {
    #[inline]
    fn clone(&self) -> Cast<E, ST> {
        Cast {
            expr: ::core::clone::Clone::clone(&self.expr),
            sql_type: ::core::clone::Clone::clone(&self.sql_type),
        }
    }
}Clone, #[automatically_derived]
impl<E: ::core::marker::Copy, ST: ::core::marker::Copy> ::core::marker::Copy
    for Cast<E, ST> {
}Copy, const _: () =
    {
        use diesel;
        #[allow(non_camel_case_types)]
        impl<E: diesel::query_builder::QueryId,
            ST: diesel::query_builder::QueryId> diesel::query_builder::QueryId
            for Cast<E, ST> {
            type QueryId =
                Cast<<E as diesel::query_builder::QueryId>::QueryId,
                <ST as diesel::query_builder::QueryId>::QueryId>;
            const HAS_STATIC_QUERY_ID: bool =
                <E as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID &&
                        <ST as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID
                    && true;
            const IS_WINDOW_FUNCTION: bool =
                <E as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION ||
                        <ST as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION
                    || false;
        }
    };diesel::query_builder::QueryId, const _: () =
    {
        use diesel;
        use diesel::internal::derives::numeric_ops as ops;
        use diesel::expression::{Expression, AsExpression};
        use diesel::sql_types::ops::{Add, Sub, Mul, Div};
        use diesel::sql_types::{SqlType, SingleValue};
        impl<E, ST, __Rhs> ::core::ops::Add<__Rhs> for Cast<E, ST> where
            Self: Expression, Self: Expression,
            <Self as Expression>::SqlType: Add,
            <<Self as Expression>::SqlType as Add>::Rhs: SqlType +
            SingleValue,
            __Rhs: AsExpression<<<Self as Expression>::SqlType as Add>::Rhs> {
            type Output = ops::Add<Self, __Rhs::Expression>;
            fn add(self, rhs: __Rhs) -> Self::Output {
                ops::Add::new(self, rhs.as_expression())
            }
        }
        impl<E, ST, __Rhs> ::core::ops::Sub<__Rhs> for Cast<E, ST> where
            Self: Expression, Self: Expression,
            <Self as Expression>::SqlType: Sub,
            <<Self as Expression>::SqlType as Sub>::Rhs: SqlType +
            SingleValue,
            __Rhs: AsExpression<<<Self as Expression>::SqlType as Sub>::Rhs> {
            type Output = ops::Sub<Self, __Rhs::Expression>;
            fn sub(self, rhs: __Rhs) -> Self::Output {
                ops::Sub::new(self, rhs.as_expression())
            }
        }
        impl<E, ST, __Rhs> ::core::ops::Mul<__Rhs> for Cast<E, ST> where
            Self: Expression, Self: Expression,
            <Self as Expression>::SqlType: Mul,
            <<Self as Expression>::SqlType as Mul>::Rhs: SqlType +
            SingleValue,
            __Rhs: AsExpression<<<Self as Expression>::SqlType as Mul>::Rhs> {
            type Output = ops::Mul<Self, __Rhs::Expression>;
            fn mul(self, rhs: __Rhs) -> Self::Output {
                ops::Mul::new(self, rhs.as_expression())
            }
        }
        impl<E, ST, __Rhs> ::core::ops::Div<__Rhs> for Cast<E, ST> where
            Self: Expression, Self: Expression,
            <Self as Expression>::SqlType: Div,
            <<Self as Expression>::SqlType as Div>::Rhs: SqlType +
            SingleValue,
            __Rhs: AsExpression<<<Self as Expression>::SqlType as Div>::Rhs> {
            type Output = ops::Div<Self, __Rhs::Expression>;
            fn div(self, rhs: __Rhs) -> Self::Output {
                ops::Div::new(self, rhs.as_expression())
            }
        }
    };sql_types::DieselNumericOps)]
14    pub struct Cast<E, ST> {
15        pub(super) expr: E,
16        pub(super) sql_type: PhantomData<ST>,
17    }
18}
19pub(crate) use private::Cast;
20
21impl<E, ST> Cast<E, ST> {
22    pub(crate) fn new(expr: E) -> Self {
23        Self {
24            expr,
25            sql_type: PhantomData,
26        }
27    }
28}
29
30impl<E, ST, GroupByClause> ValidGrouping<GroupByClause> for Cast<E, ST>
31where
32    E: ValidGrouping<GroupByClause>,
33{
34    type IsAggregate = E::IsAggregate;
35}
36
37impl<E, ST, QS> SelectableExpression<QS> for Cast<E, ST>
38where
39    Cast<E, ST>: AppearsOnTable<QS>,
40    E: SelectableExpression<QS>,
41{
42}
43
44impl<E, ST, QS> AppearsOnTable<QS> for Cast<E, ST>
45where
46    Cast<E, ST>: Expression,
47    E: AppearsOnTable<QS>,
48{
49}
50
51impl<E, ST> Expression for Cast<E, ST>
52where
53    E: Expression,
54    ST: sql_types::SingleValue,
55{
56    type SqlType = ST;
57}
58
59impl<E, ST, DB> query_builder::QueryFragment<DB> for Cast<E, ST>
60where
61    E: query_builder::QueryFragment<DB>,
62    DB: diesel::backend::Backend,
63    ST: KnownCastSqlTypeName<DB>,
64{
65    fn walk_ast<'b>(&'b self, mut out: query_builder::AstPass<'_, 'b, DB>) -> QueryResult<()> {
66        out.push_sql("CAST(");
67        self.expr.walk_ast(out.reborrow())?;
68        out.push_sql(" AS ");
69        out.push_sql(ST::SQL_TYPE_NAME);
70        out.push_sql(")");
71        Ok(())
72    }
73}
74
75/// We know what to write as `sql_type` in the `CAST(expr AS sql_type)` SQL for
76/// `Self`
77///
78/// That is what is returned by `Self::sql_type_name()`
79#[diagnostic::on_unimplemented(
80    note = "In order to use `CAST`, it is necessary that Diesel knows how to express the name \
81		of this type in the given backend.",
82    note = "If you run into this error message and believe that this cast should be supported \
83            open a PR that adds that trait implementation here: https://github.com/diesel-rs/diesel/blob/2fafe60a8f4ca3407dca5fe010a6092fa8a1858a/diesel/src/expression/cast.rs#L113."
84)]
85pub trait KnownCastSqlTypeName<DB> {
86    /// What to write as `sql_type` in the `CAST(expr AS sql_type)` SQL for
87    /// `Self`
88    const SQL_TYPE_NAME: &'static str;
89}
90
91impl<ST, DB> KnownCastSqlTypeName<DB> for sql_types::Nullable<ST>
92where
93    ST: KnownCastSqlTypeName<DB>,
94{
95    const SQL_TYPE_NAME: &'static str = <ST as KnownCastSqlTypeName<DB>>::SQL_TYPE_NAME;
96}
97
98macro_rules! type_name {
99    ($($backend: ty: $backend_feature: literal { $($type: ident => $val: literal,)+ })*) => {
100        $(
101            $(
102				#[cfg(feature = $backend_feature)]
103                impl KnownCastSqlTypeName<$backend> for sql_types::$type {
104                    const SQL_TYPE_NAME: &'static str = $val;
105                }
106            )*
107        )*
108    };
109}
110
111impl KnownCastSqlTypeName<diesel::sqlite::Sqlite> for sql_types::Jsonb {
    const SQL_TYPE_NAME: &'static str = "jsonb";
}type_name! {
112    diesel::pg::Pg: "postgres_backend" {
113        Bool => "bool",
114        Int2 => "int2",
115        Int4 => "int4",
116        Int8 => "int8",
117        Float => "float4",
118        Double => "float8",
119        Numeric => "numeric",
120        Text => "text",
121        Date => "date",
122        Interval => "interval",
123        Time => "time",
124        Timestamp => "timestamp",
125        Uuid => "uuid",
126        Json => "json",
127        Jsonb => "jsonb",
128        Inet => "inet",
129        Cidr => "cidr",
130    }
131    diesel::mysql::Mysql: "mysql_backend" {
132        Int8 => "signed",
133        Text => "char",
134        Date => "date",
135        Datetime => "datetime",
136        Decimal => "decimal",
137        Time => "time",
138    }
139    diesel::sqlite::Sqlite: "sqlite" {
140        Int4 => "integer",
141        Int8 => "bigint",
142        Double => "real",
143        Text => "text",
144        Json => "json",
145        Jsonb => "jsonb",
146    }
147}
148
149impl<S, E, ST> FieldAliasMapper<S> for Cast<E, ST>
150where
151    S: AliasSource,
152    E: FieldAliasMapper<S>,
153{
154    type Out = Cast<<E as FieldAliasMapper<S>>::Out, ST>;
155
156    fn map(self, alias: &query_source::Alias<S>) -> Self::Out {
157        Cast {
158            expr: self.expr.map(alias),
159            sql_type: self.sql_type,
160        }
161    }
162}
163
164/// Marker trait: this SQL type (`Self`) can be cast to the target SQL type, but some values can be invalid
165pub trait FallibleCastsTo<ST> {}
166
167impl<ST1, ST2> FallibleCastsTo<sql_types::Nullable<ST2>> for sql_types::Nullable<ST1> where
168    ST1: FallibleCastsTo<ST2>
169{
170}
171
172/// Marker trait: this SQL type (`Self`) can be cast to the target SQL type
173/// (`ST`) using `CAST(expr AS target_sql_type)`
174pub trait CastsTo<ST>: FallibleCastsTo<ST> {}
175
176impl<ST1, ST2> CastsTo<sql_types::Nullable<ST2>> for sql_types::Nullable<ST1> where ST1: CastsTo<ST2>
177{}
178
179macro_rules! casts_impl {
180    (
181        $(
182            $($feature: literal : )? ($to: tt <- $from: tt),
183        )+
184    ) => {
185        $(
186            $(#[cfg(feature = $feature)])?
187            impl FallibleCastsTo<sql_types::$to> for sql_types::$from {}
188            $(#[cfg(feature = $feature)])?
189            impl CastsTo<sql_types::$to> for sql_types::$from {}
190        )+
191    };
192}
193
194impl FallibleCastsTo<sql_types::Cidr> for sql_types::Inet { }
impl CastsTo<sql_types::Cidr> for sql_types::Inet { }casts_impl!(
195    (Bool <- Int4),
196    (Int4 <- Bool),
197    (Int4 <- Float4),
198    (Int8 <- Int4),
199    (Int8 <- Float4),
200    (Int8 <- Float8),
201    (Float4 <- Int4),
202    (Float4 <- Int8),
203    (Float8 <- Float4),
204    (Float8 <- Int4),
205    (Float8 <- Int8),
206    (Decimal <- Int4),
207    (Decimal <- Int8),
208    (Decimal <- Float4),
209    (Decimal <- Float8),
210    (Text <- Bool),
211    (Text <- Float4),
212    (Text <- Float8),
213    (Text <- Int4),
214    (Text <- Int8),
215    (Text <- Date),
216    (Text <- Json),
217    (Text <- Jsonb),
218    (Text <- Time),
219    (Json <- Jsonb),
220    (Jsonb <- Json),
221    "mysql_backend": (Text <- Datetime),
222    "postgres_backend": (Text <- Uuid),
223    "postgres_backend": (Text <- Inet),
224    "postgres_backend": (Text <- Cidr),
225    "postgres_backend": (Inet <- Cidr),
226    "postgres_backend": (Cidr <- Inet),
227);
228
229macro_rules! fallible_casts_impl {
230    (
231        $(
232            $($feature: literal : )? ($to: tt <- $from: tt),
233        )+
234    ) => {
235        $(
236            $(#[cfg(feature = $feature)])?
237            impl FallibleCastsTo<sql_types::$to> for sql_types::$from {}
238        )+
239    };
240}
241
242impl FallibleCastsTo<sql_types::Cidr> for sql_types::Text { }fallible_casts_impl!(
243    (Int4 <- Int8),
244    (Int4 <- Float8),
245    (Int4 <- Text),
246    (Int4 <- Decimal),
247    (Int8 <- Text),
248    (Int8 <- Decimal),
249    (Float4 <- Float8),
250    (Float4 <- Text),
251    (Float4 <- Decimal),
252    (Float8 <- Text),
253    (Float8 <- Decimal),
254    (Json <- Text),
255    (Jsonb <- Text),
256    (Bool <- Text),
257    (Date <- Text),
258    (Time <- Text),
259    (Decimal <- Text),
260    "mysql_backend": (Datetime <- Text),
261    "postgres_backend": (Uuid <- Text),
262    "postgres_backend": (Inet <- Text),
263    "postgres_backend": (Cidr <- Text),
264);