Skip to main content

drizzle_core/expr/
util.rs

1//! Helpers: aliases (`AS`), `CAST`, `TYPEOF`, raw typed SQL and `EXCLUDED`.
2
3use crate::dialect::{DialectSupports, feature};
4use crate::dialect::{MySQLDialect, PostgresDialect, SQLiteDialect};
5use crate::sql::{SQL, Token};
6use crate::traits::{SQLColumnInfo, SQLParam, ToSQL};
7use crate::types::{Compatible, DataType, Textual};
8
9use super::{AggregateKind, Expr, NonNull, Null, Nullability, SQLExpr, Scalar};
10use crate::scope::ScopeOnly;
11
12// =============================================================================
13// ALIAS
14// =============================================================================
15
16/// An expression renamed with `AS "name"`; created by [`alias`] or
17/// [`AliasExt::alias`].
18///
19/// Keeps the inner expression's SQL type, nullability and decoded Rust type,
20/// so an aliased column in a SELECT list still decodes to the right type.
21#[derive(Clone, Copy, Debug)]
22pub struct AliasedExpr<E> {
23    pub(crate) expr: E,
24    pub(crate) name: &'static str,
25}
26
27impl<'a, V, E> ToSQL<'a, V> for AliasedExpr<E>
28where
29    V: SQLParam + 'a,
30    E: ToSQL<'a, V>,
31{
32    fn to_sql(&self) -> SQL<'a, V> {
33        self.expr.to_sql().alias(self.name)
34    }
35
36    fn into_sql(self) -> SQL<'a, V> {
37        self.expr.into_sql().alias(self.name)
38    }
39}
40
41impl<'a, V, E> Expr<'a, V> for AliasedExpr<E>
42where
43    V: SQLParam + 'a,
44    E: Expr<'a, V>,
45{
46    type SQLType = E::SQLType;
47    type Nullable = E::Nullable;
48    type Aggregate = E::Aggregate;
49
50    fn to_expr_sql(&self) -> SQL<'a, V> {
51        self.expr.to_expr_sql().alias(self.name)
52    }
53
54    fn into_expr_sql(self) -> SQL<'a, V> {
55        self.expr.into_expr_sql().alias(self.name)
56    }
57}
58
59impl<E: super::ExprSources> super::ExprSources for AliasedExpr<E> {
60    type Sources = E::Sources;
61}
62
63impl<E: super::HasAggStatus> super::HasAggStatus for AliasedExpr<E> {
64    type Status = E::Status;
65}
66
67impl<E: crate::row::ExprValueType> crate::row::ExprValueType for AliasedExpr<E> {
68    type ValueType = E::ValueType;
69}
70
71impl<E> crate::row::IntoSelectTarget for AliasedExpr<E>
72where
73    E: crate::row::ExprValueType,
74{
75    type Marker = crate::row::SelectCols<(Self,)>;
76}
77
78/// Method syntax for naming a selected expression.
79///
80/// - `.alias("name")` sets a name at run time ([`AliasedExpr`]).
81/// - `.named::<Tag>()` sets a name in the type ([`NamedExpr`]), so a derived
82///   table built from the query can refer to the column.
83///
84/// Implemented for every expression with a known Rust type. On raw [`SQL`],
85/// the inherent [`SQL::alias`] method is called instead and returns `SQL`.
86///
87/// # Examples
88///
89/// ```rust
90/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
91/// # use drizzle_core::{ColumnRef, SQL, SQLParam, ToSQL, expr::*};
92/// # #[derive(Clone, Debug)] struct Value(String);
93/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
94/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
95/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
96/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
97/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
98/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
99/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
100/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
101/// let n = count(users.id).alias("user_count");
102/// assert_eq!(n.to_sql().sql(), r#"COUNT ("users"."id") AS "user_count""#);
103/// ```
104pub trait AliasExt: Sized {
105    /// Renames this expression: `expr AS "name"`.
106    fn alias(self, name: &'static str) -> AliasedExpr<Self> {
107        AliasedExpr { expr: self, name }
108    }
109
110    /// Names this expression with a type-level [`Tag`](crate::Tag), rendered
111    /// as `expr AS "<Tag::NAME>"`.
112    fn named<Name: crate::Tag>(self) -> NamedExpr<Self, Name> {
113        NamedExpr {
114            expr: self,
115            name: core::marker::PhantomData,
116        }
117    }
118}
119
120impl<T: crate::row::ExprValueType> AliasExt for T {}
121
122/// Renames an expression: `expr AS "name"`.
123///
124/// The result keeps the expression's SQL type, nullability and decoded Rust
125/// type. Same as [`AliasExt::alias`].
126///
127/// # Examples
128///
129/// ```rust
130/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
131/// # use drizzle_core::{ColumnRef, SQL, SQLParam, ToSQL, expr::*};
132/// # #[derive(Clone, Debug)] struct Value(String);
133/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
134/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
135/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
136/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
137/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
138/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
139/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
140/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
141/// let label = alias(upper(users.name), "label");
142/// assert_eq!(label.to_sql().sql(), r#"UPPER ("users"."name") AS "label""#);
143/// ```
144pub const fn alias<E>(expr: E, name: &'static str) -> AliasedExpr<E> {
145    AliasedExpr { expr, name }
146}
147
148/// An expression whose output name is a type-level [`Tag`](crate::Tag);
149/// created by [`AliasExt::named`].
150///
151/// Unlike [`AliasedExpr`], the name is part of the type, so a derived table
152/// built from the query can select this column by name.
153#[derive(Clone, Copy, Debug)]
154pub struct NamedExpr<E, Name> {
155    pub(crate) expr: E,
156    pub(crate) name: core::marker::PhantomData<Name>,
157}
158
159impl<E, Name> NamedExpr<E, Name> {
160    /// Returns the wrapped expression.
161    pub const fn expression(&self) -> &E {
162        &self.expr
163    }
164
165    /// Returns the wrapped expression by value.
166    pub fn into_expression(self) -> E {
167        self.expr
168    }
169}
170
171impl<'a, V, E, Name> ToSQL<'a, V> for NamedExpr<E, Name>
172where
173    V: SQLParam + 'a,
174    E: ToSQL<'a, V>,
175    Name: crate::Tag,
176{
177    fn to_sql(&self) -> SQL<'a, V> {
178        self.expr.to_sql().alias(Name::NAME)
179    }
180
181    fn into_sql(self) -> SQL<'a, V> {
182        self.expr.into_sql().alias(Name::NAME)
183    }
184}
185
186impl<E: super::ExprSources, Name> super::ExprSources for NamedExpr<E, Name> {
187    type Sources = E::Sources;
188}
189
190impl<'a, V, E, Name> Expr<'a, V> for NamedExpr<E, Name>
191where
192    V: SQLParam + 'a,
193    E: Expr<'a, V>,
194    Name: crate::Tag,
195{
196    type SQLType = E::SQLType;
197    type Nullable = E::Nullable;
198    type Aggregate = E::Aggregate;
199
200    fn to_expr_sql(&self) -> SQL<'a, V> {
201        self.expr.to_expr_sql().alias(Name::NAME)
202    }
203
204    fn into_expr_sql(self) -> SQL<'a, V> {
205        self.expr.into_expr_sql().alias(Name::NAME)
206    }
207}
208
209impl<E, Name> super::HasAggStatus for NamedExpr<E, Name>
210where
211    E: super::HasAggStatus,
212{
213    type Status = E::Status;
214}
215
216impl<E, Name> crate::row::ExprValueType for NamedExpr<E, Name>
217where
218    E: crate::row::ExprValueType,
219{
220    type ValueType = E::ValueType;
221}
222
223impl<E, Name> crate::row::IntoSelectTarget for NamedExpr<E, Name>
224where
225    E: crate::row::ExprValueType,
226{
227    type Marker = crate::row::SelectCols<(Self,)>;
228}
229
230impl<E, Name> crate::row::GroupByIdentity for NamedExpr<E, Name>
231where
232    E: crate::row::GroupByIdentity,
233{
234    type Identity = E::Identity;
235}
236
237// =============================================================================
238// TYPEOF
239// =============================================================================
240
241impl DialectSupports<feature::Typeof> for SQLiteDialect {}
242
243/// The storage class of a value as text (`TYPEOF`), on SQLite.
244///
245/// Returns `'null'`, `'integer'`, `'real'`, `'text'` or `'blob'`. Accepts any
246/// expression. The result is text and never NULL.
247///
248/// # Examples
249///
250/// ```rust
251/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
252/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
253/// # #[derive(Clone, Debug)] struct Value(String);
254/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
255/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
256/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
257/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
258/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
259/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
260/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
261/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
262/// assert_eq!(typeof_(users.age).sql(), r#"TYPEOF ("users"."age")"#);
263/// ```
264#[allow(clippy::type_complexity)]
265pub fn typeof_<'a, V, E>(
266    expr: E,
267) -> SQLExpr<
268    'a,
269    V,
270    <V::DialectMarker as crate::dialect::DialectTypes>::Text,
271    NonNull,
272    E::Aggregate,
273    ScopeOnly<E::Sources>,
274>
275where
276    V: SQLParam + 'a,
277    V::DialectMarker: DialectSupports<feature::Typeof>,
278    E: Expr<'a, V>,
279{
280    SQLExpr::new(SQL::func("TYPEOF", expr.into_expr_sql()))
281}
282
283/// Same as [`typeof_`], spelled with a raw identifier.
284#[allow(clippy::type_complexity)]
285pub fn r#typeof<'a, V, E>(
286    expr: E,
287) -> SQLExpr<
288    'a,
289    V,
290    <V::DialectMarker as crate::dialect::DialectTypes>::Text,
291    NonNull,
292    E::Aggregate,
293    ScopeOnly<E::Sources>,
294>
295where
296    V: SQLParam + 'a,
297    V::DialectMarker: DialectSupports<feature::Typeof>,
298    E: Expr<'a, V>,
299{
300    typeof_(expr)
301}
302
303// =============================================================================
304// CAST
305// =============================================================================
306
307/// The SQL type name [`cast`] writes when given a type marker, such as
308/// `"INTEGER"` for SQLite's `Integer`.
309pub trait DefaultCastTypeName: DataType {
310    /// The type name used in `CAST(expr AS <name>)`.
311    const CAST_TYPE_NAME: &'static str;
312}
313
314impl DefaultCastTypeName for drizzle_types::sqlite::types::Integer {
315    const CAST_TYPE_NAME: &'static str = "INTEGER";
316}
317impl DefaultCastTypeName for drizzle_types::sqlite::types::Text {
318    const CAST_TYPE_NAME: &'static str = "TEXT";
319}
320impl DefaultCastTypeName for drizzle_types::sqlite::types::Real {
321    const CAST_TYPE_NAME: &'static str = "REAL";
322}
323impl DefaultCastTypeName for drizzle_types::sqlite::types::Blob {
324    const CAST_TYPE_NAME: &'static str = "BLOB";
325}
326impl DefaultCastTypeName for drizzle_types::sqlite::types::Numeric {
327    const CAST_TYPE_NAME: &'static str = "NUMERIC";
328}
329impl DefaultCastTypeName for drizzle_types::sqlite::types::Any {
330    const CAST_TYPE_NAME: &'static str = "ANY";
331}
332
333impl DefaultCastTypeName for drizzle_types::postgres::types::Int2 {
334    const CAST_TYPE_NAME: &'static str = "SMALLINT";
335}
336impl DefaultCastTypeName for drizzle_types::postgres::types::Int4 {
337    const CAST_TYPE_NAME: &'static str = "INTEGER";
338}
339impl DefaultCastTypeName for drizzle_types::postgres::types::Int8 {
340    const CAST_TYPE_NAME: &'static str = "BIGINT";
341}
342impl DefaultCastTypeName for drizzle_types::postgres::types::Float4 {
343    const CAST_TYPE_NAME: &'static str = "REAL";
344}
345impl DefaultCastTypeName for drizzle_types::postgres::types::Float8 {
346    const CAST_TYPE_NAME: &'static str = "DOUBLE PRECISION";
347}
348impl DefaultCastTypeName for drizzle_types::postgres::types::Varchar {
349    const CAST_TYPE_NAME: &'static str = "VARCHAR";
350}
351impl DefaultCastTypeName for drizzle_types::postgres::types::Text {
352    const CAST_TYPE_NAME: &'static str = "TEXT";
353}
354impl DefaultCastTypeName for drizzle_types::postgres::types::Char {
355    const CAST_TYPE_NAME: &'static str = "CHAR";
356}
357impl DefaultCastTypeName for drizzle_types::postgres::types::Bytea {
358    const CAST_TYPE_NAME: &'static str = "BYTEA";
359}
360impl DefaultCastTypeName for drizzle_types::postgres::types::Boolean {
361    const CAST_TYPE_NAME: &'static str = "BOOLEAN";
362}
363impl DefaultCastTypeName for drizzle_types::postgres::types::Timestamptz {
364    const CAST_TYPE_NAME: &'static str = "TIMESTAMPTZ";
365}
366impl DefaultCastTypeName for drizzle_types::postgres::types::Timestamp {
367    const CAST_TYPE_NAME: &'static str = "TIMESTAMP";
368}
369impl DefaultCastTypeName for drizzle_types::postgres::types::Date {
370    const CAST_TYPE_NAME: &'static str = "DATE";
371}
372impl DefaultCastTypeName for drizzle_types::postgres::types::Time {
373    const CAST_TYPE_NAME: &'static str = "TIME";
374}
375impl DefaultCastTypeName for drizzle_types::postgres::types::Timetz {
376    const CAST_TYPE_NAME: &'static str = "TIMETZ";
377}
378impl DefaultCastTypeName for drizzle_types::postgres::types::Numeric {
379    const CAST_TYPE_NAME: &'static str = "NUMERIC";
380}
381impl DefaultCastTypeName for drizzle_types::postgres::types::Uuid {
382    const CAST_TYPE_NAME: &'static str = "UUID";
383}
384impl DefaultCastTypeName for drizzle_types::postgres::types::Json {
385    const CAST_TYPE_NAME: &'static str = "JSON";
386}
387impl DefaultCastTypeName for drizzle_types::postgres::types::Jsonb {
388    const CAST_TYPE_NAME: &'static str = "JSONB";
389}
390impl DefaultCastTypeName for drizzle_types::postgres::types::Any {
391    const CAST_TYPE_NAME: &'static str = "ANY";
392}
393impl DefaultCastTypeName for drizzle_types::postgres::types::Interval {
394    const CAST_TYPE_NAME: &'static str = "INTERVAL";
395}
396impl DefaultCastTypeName for drizzle_types::postgres::types::Inet {
397    const CAST_TYPE_NAME: &'static str = "INET";
398}
399impl DefaultCastTypeName for drizzle_types::postgres::types::Cidr {
400    const CAST_TYPE_NAME: &'static str = "CIDR";
401}
402impl DefaultCastTypeName for drizzle_types::postgres::types::MacAddr {
403    const CAST_TYPE_NAME: &'static str = "MACADDR";
404}
405impl DefaultCastTypeName for drizzle_types::postgres::types::MacAddr8 {
406    const CAST_TYPE_NAME: &'static str = "MACADDR8";
407}
408impl DefaultCastTypeName for drizzle_types::postgres::types::Point {
409    const CAST_TYPE_NAME: &'static str = "POINT";
410}
411impl DefaultCastTypeName for drizzle_types::postgres::types::LineString {
412    const CAST_TYPE_NAME: &'static str = "PATH";
413}
414impl DefaultCastTypeName for drizzle_types::postgres::types::Rect {
415    const CAST_TYPE_NAME: &'static str = "BOX";
416}
417impl DefaultCastTypeName for drizzle_types::postgres::types::BitString {
418    const CAST_TYPE_NAME: &'static str = "BIT VARYING";
419}
420impl DefaultCastTypeName for drizzle_types::postgres::types::Line {
421    const CAST_TYPE_NAME: &'static str = "LINE";
422}
423impl DefaultCastTypeName for drizzle_types::postgres::types::LineSegment {
424    const CAST_TYPE_NAME: &'static str = "LSEG";
425}
426impl DefaultCastTypeName for drizzle_types::postgres::types::Polygon {
427    const CAST_TYPE_NAME: &'static str = "POLYGON";
428}
429impl DefaultCastTypeName for drizzle_types::postgres::types::Circle {
430    const CAST_TYPE_NAME: &'static str = "CIRCLE";
431}
432impl DefaultCastTypeName for drizzle_types::postgres::types::Enum {
433    const CAST_TYPE_NAME: &'static str = "TEXT";
434}
435
436impl DefaultCastTypeName for drizzle_types::mysql::types::BigInt {
437    const CAST_TYPE_NAME: &'static str = "SIGNED";
438}
439impl DefaultCastTypeName for drizzle_types::mysql::types::BigIntUnsigned {
440    const CAST_TYPE_NAME: &'static str = "UNSIGNED";
441}
442impl DefaultCastTypeName for drizzle_types::mysql::types::Float {
443    const CAST_TYPE_NAME: &'static str = "FLOAT";
444}
445impl DefaultCastTypeName for drizzle_types::mysql::types::Double {
446    const CAST_TYPE_NAME: &'static str = "DOUBLE";
447}
448impl DefaultCastTypeName for drizzle_types::mysql::types::Decimal {
449    const CAST_TYPE_NAME: &'static str = "DECIMAL";
450}
451impl DefaultCastTypeName for drizzle_types::mysql::types::Varchar {
452    const CAST_TYPE_NAME: &'static str = "CHAR";
453}
454impl DefaultCastTypeName for drizzle_types::mysql::types::Varbinary {
455    const CAST_TYPE_NAME: &'static str = "BINARY";
456}
457impl DefaultCastTypeName for drizzle_types::mysql::types::Json {
458    const CAST_TYPE_NAME: &'static str = "JSON";
459}
460impl DefaultCastTypeName for drizzle_types::mysql::types::Date {
461    const CAST_TYPE_NAME: &'static str = "DATE";
462}
463impl DefaultCastTypeName for drizzle_types::mysql::types::Time {
464    const CAST_TYPE_NAME: &'static str = "TIME";
465}
466impl DefaultCastTypeName for drizzle_types::mysql::types::DateTime {
467    const CAST_TYPE_NAME: &'static str = "DATETIME";
468}
469impl DefaultCastTypeName for drizzle_types::mysql::types::Year {
470    const CAST_TYPE_NAME: &'static str = "YEAR";
471}
472
473/// The target argument of [`cast`]: a SQL type name such as `"VARCHAR(255)"`,
474/// or a type marker value whose [`DefaultCastTypeName`] is used.
475#[diagnostic::on_unimplemented(
476    message = "`{Self}` is not a cast target for `{T}` here",
477    label = "a type marker target must be the cast's result type, from this dialect",
478    note = "or pass the SQL type name as a string, such as `\"VARCHAR(255)\"`"
479)]
480pub trait CastTarget<'a, T: DataType, D> {
481    /// The SQL type name to cast to.
482    fn cast_type_name(self) -> &'a str;
483}
484
485/// Casts from `Source` to `Target` that dialect `D` allows.
486///
487/// On SQLite and PostgreSQL the two types must be compatible. On MySQL,
488/// `CAST` accepts a fixed set of targets (`SIGNED`, `DOUBLE`, `CHAR`,
489/// `DATE`, ...).
490#[diagnostic::on_unimplemented(
491    message = "cannot cast `{Source}` to `{Target}` for this dialect",
492    label = "cast target is incompatible with source type",
493    note = "use a supported target marker, or raw SQL when the conversion is intentionally dialect-specific"
494)]
495pub trait CastTypePolicy<D, Source: DataType, Target: DataType> {}
496
497/// Nullability of a cast to `Self` on dialect `D`. MySQL temporal casts give
498/// NULL for invalid input, so they are nullable.
499#[doc(hidden)]
500pub trait CastNullabilityPolicy<D, Input: Nullability>: DataType {
501    type Output: Nullability;
502}
503
504macro_rules! mysql_cast_policy {
505    (
506        preserving: [$($preserving:ty),+ $(,)?],
507        nullable: [$($nullable:ty),+ $(,)?],
508    ) => {
509        $(
510            impl<Source: DataType> CastTypePolicy<MySQLDialect, Source, $preserving> for () {}
511
512            impl<Input: Nullability> CastNullabilityPolicy<MySQLDialect, Input> for $preserving {
513                type Output = Input;
514            }
515        )+
516        $(
517            impl<Source: DataType> CastTypePolicy<MySQLDialect, Source, $nullable> for () {}
518
519            impl<Input: Nullability> CastNullabilityPolicy<MySQLDialect, Input> for $nullable {
520                type Output = Null;
521            }
522        )+
523    };
524}
525
526mysql_cast_policy! {
527    preserving: [
528        drizzle_types::mysql::types::BigInt,
529        drizzle_types::mysql::types::BigIntUnsigned,
530        drizzle_types::mysql::types::Float,
531        drizzle_types::mysql::types::Double,
532        drizzle_types::mysql::types::Decimal,
533        drizzle_types::mysql::types::Varchar,
534        drizzle_types::mysql::types::Varbinary,
535        drizzle_types::mysql::types::Json,
536    ],
537    nullable: [
538        drizzle_types::mysql::types::Date,
539        drizzle_types::mysql::types::Time,
540        drizzle_types::mysql::types::DateTime,
541        drizzle_types::mysql::types::Year,
542    ],
543}
544
545impl<Source: DataType + Compatible<Target>, Target: DataType>
546    CastTypePolicy<PostgresDialect, Source, Target> for ()
547{
548}
549
550impl<Input: Nullability, Target: DataType> CastNullabilityPolicy<PostgresDialect, Input>
551    for Target
552{
553    type Output = Input;
554}
555
556impl<Source: DataType + Compatible<Target>, Target: DataType>
557    CastTypePolicy<SQLiteDialect, Source, Target> for ()
558{
559}
560
561impl<Input: Nullability, Target: DataType> CastNullabilityPolicy<SQLiteDialect, Input> for Target {
562    type Output = Input;
563}
564
565impl<'a, T: DataType, D> CastTarget<'a, T, D> for &'a str {
566    fn cast_type_name(self) -> &'a str {
567        self
568    }
569}
570
571impl<'a, T, D> CastTarget<'a, T, D> for T
572where
573    T: DataType + DefaultCastTypeName,
574{
575    fn cast_type_name(self) -> &'a str {
576        T::CAST_TYPE_NAME
577    }
578}
579
580/// Converts an expression to another SQL type (`CAST(expr AS type)`).
581///
582/// The target is either a type marker value, such as
583/// `drizzle::sqlite::types::Text`, whose SQL name is used, or a SQL type
584/// name such as `"VARCHAR(255)"`. With a name, give the result type
585/// explicitly: `cast::<_, _, Text>(expr, "VARCHAR(255)")`.
586///
587/// On SQLite and PostgreSQL, source and target types must be compatible (see
588/// [`CastTypePolicy`]). The result has the target type and keeps the
589/// expression's aggregate kind. It keeps the expression's nullability,
590/// except for MySQL casts to temporal types, which can give NULL for invalid
591/// input and so are nullable.
592///
593/// # Examples
594///
595/// ```rust
596/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
597/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
598/// # #[derive(Clone, Debug)] struct Value(String);
599/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
600/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
601/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
602/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
603/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
604/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
605/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
606/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
607/// // Integer to SQLite REAL, using the type marker.
608/// let real = cast(users.age, Real::default());
609/// assert_eq!(real.sql(), r#"CAST ("users"."age" AS REAL)"#);
610///
611/// // The same with an explicit type name.
612/// let real = cast::<_, _, Real>(users.age, "DOUBLE");
613/// assert_eq!(real.sql(), r#"CAST ("users"."age" AS DOUBLE)"#);
614/// ```
615#[allow(clippy::type_complexity)]
616pub fn cast<'a, V, E, Target>(
617    expr: E,
618    target_type: impl CastTarget<'a, Target, V::DialectMarker>,
619) -> SQLExpr<
620    'a,
621    V,
622    Target,
623    <Target as CastNullabilityPolicy<V::DialectMarker, E::Nullable>>::Output,
624    E::Aggregate,
625    E::Sources,
626>
627where
628    V: SQLParam + 'a,
629    E: Expr<'a, V>,
630    Target: DataType + CastNullabilityPolicy<V::DialectMarker, E::Nullable>,
631    (): CastTypePolicy<V::DialectMarker, E::SQLType, Target>,
632{
633    SQLExpr::new(SQL::func(
634        "CAST",
635        expr.into_expr_sql()
636            .push(Token::AS)
637            .append(SQL::raw(target_type.cast_type_name())),
638    ))
639}
640
641// =============================================================================
642// STRING CONCATENATION
643// =============================================================================
644
645/// Joins two text values; same as [`concat`](super::concat).
646///
647/// Renders `left || right` on SQLite and PostgreSQL and `CONCAT(left, right)`
648/// on MySQL. Both arguments must be text. The result is text, nullable if
649/// either argument is.
650///
651/// # Examples
652///
653/// ```rust
654/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
655/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
656/// # #[derive(Clone, Debug)] struct Value(String);
657/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
658/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
659/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
660/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
661/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
662/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
663/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
664/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
665/// let label = string_concat(users.name, "!");
666/// assert_eq!(label.sql(), r#""users"."name" || ?"#);
667/// ```
668#[allow(clippy::type_complexity)]
669pub fn string_concat<'a, V, L, R>(
670    left: L,
671    right: R,
672) -> SQLExpr<
673    'a,
674    V,
675    <V::DialectMarker as crate::dialect::DialectTypes>::Text,
676    <L::Nullable as Nullability>::Or<R::Nullable>,
677    <L::Aggregate as AggregateKind>::Or<R::Aggregate>,
678    (L::Sources, R::Sources),
679>
680where
681    V: SQLParam + 'a,
682    L: Expr<'a, V>,
683    R: Expr<'a, V>,
684    L::SQLType: Textual,
685    R::SQLType: Textual,
686    R::Nullable: Nullability,
687    R::Aggregate: AggregateKind,
688{
689    super::concat(left, right)
690}
691
692// =============================================================================
693// RAW SQL Expression
694// =============================================================================
695
696/// A raw SQL fragment with a declared SQL type, typed as nullable.
697///
698/// The text is inserted into the query as is, so never build it from user
699/// input. The type system trusts the declared type `T` and cannot check the
700/// SQL. The result is nullable; use [`raw_non_null`] when the SQL can never be
701/// NULL.
702///
703/// # Examples
704///
705/// ```rust
706/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
707/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
708/// # #[derive(Clone, Debug)] struct Value(String);
709/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
710/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
711/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
712/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
713/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
714/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
715/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
716/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
717/// let one = raw::<Value, Int>("1");
718/// assert_eq!(eq(users.id, one).sql(), r#""users"."id" = 1"#);
719/// ```
720#[must_use]
721pub fn raw<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar, ()>
722where
723    V: SQLParam + 'a,
724    T: DataType,
725{
726    SQLExpr::new(SQL::raw(sql))
727}
728
729/// A raw SQL fragment with a declared SQL type, typed as nullable; same as
730/// [`raw`].
731#[must_use]
732pub fn raw_nullable<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar, ()>
733where
734    V: SQLParam + 'a,
735    T: DataType,
736{
737    SQLExpr::new(SQL::raw(sql))
738}
739
740/// A raw SQL fragment with a declared SQL type, typed as non-null.
741///
742/// Like [`raw`], but the result is non-null. The type system trusts both the
743/// declared type `T` and the claim that the SQL is never NULL.
744///
745/// # Examples
746///
747/// ```rust
748/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
749/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
750/// # #[derive(Clone, Debug)] struct Value(String);
751/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
752/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
753/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
754/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
755/// # fn col<X: drizzle_core::types::DataType, N: Nullability>(c: &'static str) -> C<X, N> { Box::leak(Box::new(SQLExpr::new(SQL::column(ColumnRef::sql("users", c))))) }
756/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
757/// # struct Users { id: C<Int>, age: C<Int>, name: C<Text>, email: C<Text, Null>, score: C<Real, Null>, active: C<<D as DialectTypes>::Bool>, created_at: C<<D as DialectTypes>::Timestamp> }
758/// # let users = Users { id: col("id"), age: col("age"), name: col("name"), email: col("email"), score: col("score"), active: col("active"), created_at: col("created_at") };
759/// let now = raw_non_null::<Value, Text>("CURRENT_TIMESTAMP");
760/// assert_eq!(now.sql(), "CURRENT_TIMESTAMP");
761/// ```
762#[must_use]
763pub fn raw_non_null<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, NonNull, Scalar, ()>
764where
765    V: SQLParam + 'a,
766    T: DataType,
767{
768    SQLExpr::new(SQL::raw(sql))
769}
770
771// =============================================================================
772// EXCLUDED (for ON CONFLICT DO UPDATE)
773// =============================================================================
774
775/// A column of the row that failed to insert (`EXCLUDED."column"`); created
776/// by [`excluded`].
777#[derive(Clone, Copy, Debug)]
778pub struct Excluded<C> {
779    column: C,
780}
781
782impl DialectSupports<feature::Excluded> for SQLiteDialect {}
783impl DialectSupports<feature::Excluded> for PostgresDialect {}
784
785/// Refers to the value a conflicting insert tried to write (`EXCLUDED."column"`).
786///
787/// Use it in `ON CONFLICT ... DO UPDATE SET` to copy the new value into the
788/// existing row. The argument must be a table column. The result has the
789/// column's SQL type and nullability. Available on SQLite and PostgreSQL.
790///
791/// # Examples
792///
793/// ```rust
794/// # use drizzle_core::dialect::{Dialect, SQLiteDialect};
795/// # use drizzle_core::{SQL, SQLColumnInfo, SQLParam, SQLTableInfo, ToSQL, expr::excluded};
796/// # #[derive(Clone, Debug)] struct Value;
797/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = SQLiteDialect; }
798/// # struct NameColumn;
799/// # impl SQLColumnInfo for NameColumn {
800/// #     fn name(&self) -> &'static str { "name" }
801/// #     fn is_not_null(&self) -> bool { true }
802/// #     fn is_primary_key(&self) -> bool { false }
803/// #     fn is_unique(&self) -> bool { false }
804/// #     fn r#type(&self) -> &'static str { "TEXT" }
805/// #     fn has_default(&self) -> bool { false }
806/// #     fn table(&self) -> &'static dyn SQLTableInfo { unimplemented!() }
807/// # }
808/// // `NameColumn` stands in for a generated column such as `users.name`.
809/// let new_name: SQL<'_, Value> = excluded(NameColumn).to_sql();
810/// assert_eq!(new_name.sql(), r#"EXCLUDED."name""#);
811/// ```
812///
813/// In an upsert built with a dialect crate:
814///
815/// ```text
816/// // INSERT INTO "simple" ("id", "name") VALUES (?, ?)
817/// //   ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name"
818/// db.insert(simple)
819///     .values([InsertSimple::new("test").with_id(1)])
820///     .on_conflict(simple.id)
821///     .do_update(UpdateSimple::default().with_name(excluded(simple.name)));
822/// ```
823pub const fn excluded<C>(column: C) -> Excluded<C> {
824    Excluded { column }
825}
826
827/// `EXCLUDED` is the proposed insert row, not a FROM source.
828impl<C> super::ExprSources for Excluded<C> {
829    type Sources = ();
830}
831
832impl<'a, V, C> Expr<'a, V> for Excluded<C>
833where
834    V: SQLParam + 'a,
835    V::DialectMarker: DialectSupports<feature::Excluded>,
836    C: Expr<'a, V> + SQLColumnInfo,
837{
838    type SQLType = C::SQLType;
839    type Nullable = C::Nullable;
840    type Aggregate = C::Aggregate;
841}
842
843impl<'a, V, C> ToSQL<'a, V> for Excluded<C>
844where
845    V: SQLParam + 'a,
846    V::DialectMarker: DialectSupports<feature::Excluded>,
847    C: SQLColumnInfo,
848{
849    fn to_sql(&self) -> SQL<'a, V> {
850        SQL::empty()
851            .push(Token::EXCLUDED)
852            .push(Token::DOT)
853            .append(SQL::ident(self.column.name()))
854    }
855}