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.
475pub trait CastTarget<'a, T: DataType, D> {
476    /// The SQL type name to cast to.
477    fn cast_type_name(self) -> &'a str;
478}
479
480/// Casts from `Source` to `Target` that dialect `D` allows.
481///
482/// On SQLite and PostgreSQL the two types must be compatible. On MySQL,
483/// `CAST` accepts a fixed set of targets (`SIGNED`, `DOUBLE`, `CHAR`,
484/// `DATE`, ...).
485#[diagnostic::on_unimplemented(
486    message = "cannot cast `{Source}` to `{Target}` for this dialect",
487    label = "cast target is incompatible with source type",
488    note = "use a supported target marker, or raw SQL when the conversion is intentionally dialect-specific"
489)]
490pub trait CastTypePolicy<D, Source: DataType, Target: DataType> {}
491
492/// Nullability of a cast to `Self` on dialect `D`. MySQL temporal casts give
493/// NULL for invalid input, so they are nullable.
494#[doc(hidden)]
495pub trait CastNullabilityPolicy<D, Input: Nullability>: DataType {
496    type Output: Nullability;
497}
498
499macro_rules! mysql_cast_policy {
500    (
501        preserving: [$($preserving:ty),+ $(,)?],
502        nullable: [$($nullable:ty),+ $(,)?],
503    ) => {
504        $(
505            impl<Source: DataType> CastTypePolicy<MySQLDialect, Source, $preserving> for () {}
506
507            impl<Input: Nullability> CastNullabilityPolicy<MySQLDialect, Input> for $preserving {
508                type Output = Input;
509            }
510        )+
511        $(
512            impl<Source: DataType> CastTypePolicy<MySQLDialect, Source, $nullable> for () {}
513
514            impl<Input: Nullability> CastNullabilityPolicy<MySQLDialect, Input> for $nullable {
515                type Output = Null;
516            }
517        )+
518    };
519}
520
521mysql_cast_policy! {
522    preserving: [
523        drizzle_types::mysql::types::BigInt,
524        drizzle_types::mysql::types::BigIntUnsigned,
525        drizzle_types::mysql::types::Float,
526        drizzle_types::mysql::types::Double,
527        drizzle_types::mysql::types::Decimal,
528        drizzle_types::mysql::types::Varchar,
529        drizzle_types::mysql::types::Varbinary,
530        drizzle_types::mysql::types::Json,
531    ],
532    nullable: [
533        drizzle_types::mysql::types::Date,
534        drizzle_types::mysql::types::Time,
535        drizzle_types::mysql::types::DateTime,
536        drizzle_types::mysql::types::Year,
537    ],
538}
539
540impl<Source: DataType + Compatible<Target>, Target: DataType>
541    CastTypePolicy<PostgresDialect, Source, Target> for ()
542{
543}
544
545impl<Input: Nullability, Target: DataType> CastNullabilityPolicy<PostgresDialect, Input>
546    for Target
547{
548    type Output = Input;
549}
550
551impl<Source: DataType + Compatible<Target>, Target: DataType>
552    CastTypePolicy<SQLiteDialect, Source, Target> for ()
553{
554}
555
556impl<Input: Nullability, Target: DataType> CastNullabilityPolicy<SQLiteDialect, Input> for Target {
557    type Output = Input;
558}
559
560impl<'a, T: DataType, D> CastTarget<'a, T, D> for &'a str {
561    fn cast_type_name(self) -> &'a str {
562        self
563    }
564}
565
566impl<'a, T, D> CastTarget<'a, T, D> for T
567where
568    T: DataType + DefaultCastTypeName,
569{
570    fn cast_type_name(self) -> &'a str {
571        T::CAST_TYPE_NAME
572    }
573}
574
575/// Converts an expression to another SQL type (`CAST(expr AS type)`).
576///
577/// The target is either a type marker value, such as
578/// `drizzle::sqlite::types::Text`, whose SQL name is used, or a SQL type
579/// name such as `"VARCHAR(255)"`. With a name, give the result type
580/// explicitly: `cast::<_, _, Text>(expr, "VARCHAR(255)")`.
581///
582/// On SQLite and PostgreSQL, source and target types must be compatible (see
583/// [`CastTypePolicy`]). The result has the target type and keeps the
584/// expression's aggregate kind. It keeps the expression's nullability,
585/// except for MySQL casts to temporal types, which can give NULL for invalid
586/// input and so are nullable.
587///
588/// # Examples
589///
590/// ```rust
591/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
592/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
593/// # #[derive(Clone, Debug)] struct Value(String);
594/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
595/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
596/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
597/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
598/// # 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))))) }
599/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
600/// # 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> }
601/// # 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") };
602/// // Integer to SQLite REAL, using the type marker.
603/// let real = cast(users.age, Real::default());
604/// assert_eq!(real.sql(), r#"CAST ("users"."age" AS REAL)"#);
605///
606/// // The same with an explicit type name.
607/// let real = cast::<_, _, Real>(users.age, "DOUBLE");
608/// assert_eq!(real.sql(), r#"CAST ("users"."age" AS DOUBLE)"#);
609/// ```
610#[allow(clippy::type_complexity)]
611pub fn cast<'a, V, E, Target>(
612    expr: E,
613    target_type: impl CastTarget<'a, Target, V::DialectMarker>,
614) -> SQLExpr<
615    'a,
616    V,
617    Target,
618    <Target as CastNullabilityPolicy<V::DialectMarker, E::Nullable>>::Output,
619    E::Aggregate,
620    E::Sources,
621>
622where
623    V: SQLParam + 'a,
624    E: Expr<'a, V>,
625    Target: DataType + CastNullabilityPolicy<V::DialectMarker, E::Nullable>,
626    (): CastTypePolicy<V::DialectMarker, E::SQLType, Target>,
627{
628    SQLExpr::new(SQL::func(
629        "CAST",
630        expr.into_expr_sql()
631            .push(Token::AS)
632            .append(SQL::raw(target_type.cast_type_name())),
633    ))
634}
635
636// =============================================================================
637// STRING CONCATENATION
638// =============================================================================
639
640/// Joins two text values; same as [`concat`](super::concat).
641///
642/// Renders `left || right` on SQLite and PostgreSQL and `CONCAT(left, right)`
643/// on MySQL. Both arguments must be text. The result is text, nullable if
644/// either argument is.
645///
646/// # Examples
647///
648/// ```rust
649/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
650/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
651/// # #[derive(Clone, Debug)] struct Value(String);
652/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
653/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
654/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
655/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
656/// # 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))))) }
657/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
658/// # 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> }
659/// # 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") };
660/// let label = string_concat(users.name, "!");
661/// assert_eq!(label.sql(), r#""users"."name" || ?"#);
662/// ```
663#[allow(clippy::type_complexity)]
664pub fn string_concat<'a, V, L, R>(
665    left: L,
666    right: R,
667) -> SQLExpr<
668    'a,
669    V,
670    <V::DialectMarker as crate::dialect::DialectTypes>::Text,
671    <L::Nullable as Nullability>::Or<R::Nullable>,
672    <L::Aggregate as AggregateKind>::Or<R::Aggregate>,
673    (L::Sources, R::Sources),
674>
675where
676    V: SQLParam + 'a,
677    L: Expr<'a, V>,
678    R: Expr<'a, V>,
679    L::SQLType: Textual,
680    R::SQLType: Textual,
681    R::Nullable: Nullability,
682    R::Aggregate: AggregateKind,
683{
684    super::concat(left, right)
685}
686
687// =============================================================================
688// RAW SQL Expression
689// =============================================================================
690
691/// A raw SQL fragment with a declared SQL type, typed as nullable.
692///
693/// The text is inserted into the query as is, so never build it from user
694/// input. The type system trusts the declared type `T` and cannot check the
695/// SQL. The result is nullable; use [`raw_non_null`] when the SQL can never be
696/// NULL.
697///
698/// # Examples
699///
700/// ```rust
701/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
702/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
703/// # #[derive(Clone, Debug)] struct Value(String);
704/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
705/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
706/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
707/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
708/// # 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))))) }
709/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
710/// # 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> }
711/// # 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") };
712/// let one = raw::<Value, Int>("1");
713/// assert_eq!(eq(users.id, one).sql(), r#""users"."id" = 1"#);
714/// ```
715#[must_use]
716pub fn raw<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar, ()>
717where
718    V: SQLParam + 'a,
719    T: DataType,
720{
721    SQLExpr::new(SQL::raw(sql))
722}
723
724/// A raw SQL fragment with a declared SQL type, typed as nullable; same as
725/// [`raw`].
726#[must_use]
727pub fn raw_nullable<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar, ()>
728where
729    V: SQLParam + 'a,
730    T: DataType,
731{
732    SQLExpr::new(SQL::raw(sql))
733}
734
735/// A raw SQL fragment with a declared SQL type, typed as non-null.
736///
737/// Like [`raw`], but the result is non-null. The type system trusts both the
738/// declared type `T` and the claim that the SQL is never NULL.
739///
740/// # Examples
741///
742/// ```rust
743/// # use drizzle_core::dialect::{Dialect, DialectTypes, SQLiteDialect as D};
744/// # use drizzle_core::{ColumnRef, SQL, SQLParam, expr::*};
745/// # #[derive(Clone, Debug)] struct Value(String);
746/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = D; }
747/// # impl<X: ToString> From<X> for Value { fn from(v: X) -> Self { Value(v.to_string()) } }
748/// # impl From<Value> for std::borrow::Cow<'_, Value> { fn from(v: Value) -> Self { Self::Owned(v) } }
749/// # type C<X, N = NonNull> = &'static SQLExpr<'static, Value, X, N>;
750/// # 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))))) }
751/// # type Int = <D as DialectTypes>::Int; type Text = <D as DialectTypes>::Text; type Real = <D as DialectTypes>::Double;
752/// # 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> }
753/// # 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") };
754/// let now = raw_non_null::<Value, Text>("CURRENT_TIMESTAMP");
755/// assert_eq!(now.sql(), "CURRENT_TIMESTAMP");
756/// ```
757#[must_use]
758pub fn raw_non_null<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, NonNull, Scalar, ()>
759where
760    V: SQLParam + 'a,
761    T: DataType,
762{
763    SQLExpr::new(SQL::raw(sql))
764}
765
766// =============================================================================
767// EXCLUDED (for ON CONFLICT DO UPDATE)
768// =============================================================================
769
770/// A column of the row that failed to insert (`EXCLUDED."column"`); created
771/// by [`excluded`].
772#[derive(Clone, Copy, Debug)]
773pub struct Excluded<C> {
774    column: C,
775}
776
777impl DialectSupports<feature::Excluded> for SQLiteDialect {}
778impl DialectSupports<feature::Excluded> for PostgresDialect {}
779
780/// Refers to the value a conflicting insert tried to write (`EXCLUDED."column"`).
781///
782/// Use it in `ON CONFLICT ... DO UPDATE SET` to copy the new value into the
783/// existing row. The argument must be a table column. The result has the
784/// column's SQL type and nullability. Available on SQLite and PostgreSQL.
785///
786/// # Examples
787///
788/// ```rust
789/// # use drizzle_core::dialect::{Dialect, SQLiteDialect};
790/// # use drizzle_core::{SQL, SQLColumnInfo, SQLParam, SQLTableInfo, ToSQL, expr::excluded};
791/// # #[derive(Clone, Debug)] struct Value;
792/// # impl SQLParam for Value { const DIALECT: Dialect = Dialect::SQLite; type DialectMarker = SQLiteDialect; }
793/// # struct NameColumn;
794/// # impl SQLColumnInfo for NameColumn {
795/// #     fn name(&self) -> &'static str { "name" }
796/// #     fn is_not_null(&self) -> bool { true }
797/// #     fn is_primary_key(&self) -> bool { false }
798/// #     fn is_unique(&self) -> bool { false }
799/// #     fn r#type(&self) -> &'static str { "TEXT" }
800/// #     fn has_default(&self) -> bool { false }
801/// #     fn table(&self) -> &'static dyn SQLTableInfo { unimplemented!() }
802/// # }
803/// // `NameColumn` stands in for a generated column such as `users.name`.
804/// let new_name: SQL<'_, Value> = excluded(NameColumn).to_sql();
805/// assert_eq!(new_name.sql(), r#"EXCLUDED."name""#);
806/// ```
807///
808/// In an upsert built with a dialect crate:
809///
810/// ```text
811/// // INSERT INTO "simple" ("id", "name") VALUES (?, ?)
812/// //   ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name"
813/// db.insert(simple)
814///     .values([InsertSimple::new("test").with_id(1)])
815///     .on_conflict(simple.id)
816///     .do_update(UpdateSimple::default().with_name(excluded(simple.name)));
817/// ```
818pub const fn excluded<C>(column: C) -> Excluded<C> {
819    Excluded { column }
820}
821
822/// `EXCLUDED` is the proposed insert row, not a FROM source.
823impl<C> super::ExprSources for Excluded<C> {
824    type Sources = ();
825}
826
827impl<'a, V, C> Expr<'a, V> for Excluded<C>
828where
829    V: SQLParam + 'a,
830    V::DialectMarker: DialectSupports<feature::Excluded>,
831    C: Expr<'a, V> + SQLColumnInfo,
832{
833    type SQLType = C::SQLType;
834    type Nullable = C::Nullable;
835    type Aggregate = C::Aggregate;
836}
837
838impl<'a, V, C> ToSQL<'a, V> for Excluded<C>
839where
840    V: SQLParam + 'a,
841    V::DialectMarker: DialectSupports<feature::Excluded>,
842    C: SQLColumnInfo,
843{
844    fn to_sql(&self) -> SQL<'a, V> {
845        SQL::empty()
846            .push(Token::EXCLUDED)
847            .push(Token::DOT)
848            .append(SQL::ident(self.column.name()))
849    }
850}