1use crate::dialect::{MySQLDialect, PostgresDialect, SQLiteDialect};
4use crate::sql::{SQL, Token};
5use crate::traits::{SQLColumnInfo, SQLParam, ToSQL};
6use crate::types::{Compatible, DataType, Textual};
7
8use super::{AggOr, AggregateKind, Expr, NonNull, Null, NullOr, Nullability, SQLExpr, Scalar};
9
10#[derive(Clone, Copy, Debug)]
20pub struct AliasedExpr<E> {
21 pub(crate) expr: E,
22 pub(crate) name: &'static str,
23}
24
25impl<'a, V, E> ToSQL<'a, V> for AliasedExpr<E>
26where
27 V: SQLParam + 'a,
28 E: ToSQL<'a, V>,
29{
30 fn to_sql(&self) -> SQL<'a, V> {
31 self.expr.to_sql().alias(self.name)
32 }
33
34 fn into_sql(self) -> SQL<'a, V> {
35 self.expr.into_sql().alias(self.name)
36 }
37}
38
39impl<'a, V, E> Expr<'a, V> for AliasedExpr<E>
40where
41 V: SQLParam + 'a,
42 E: Expr<'a, V>,
43{
44 type SQLType = E::SQLType;
45 type Nullable = E::Nullable;
46 type Aggregate = E::Aggregate;
47
48 fn to_expr_sql(&self) -> SQL<'a, V> {
49 self.expr.to_expr_sql().alias(self.name)
50 }
51
52 fn into_expr_sql(self) -> SQL<'a, V> {
53 self.expr.into_expr_sql().alias(self.name)
54 }
55}
56
57impl<E: super::HasAggStatus> super::HasAggStatus for AliasedExpr<E> {
58 type Status = E::Status;
59}
60
61impl<E: crate::row::ExprValueType> crate::row::ExprValueType for AliasedExpr<E> {
62 type ValueType = E::ValueType;
63}
64
65impl<E> crate::row::IntoSelectTarget for AliasedExpr<E>
66where
67 E: crate::row::ExprValueType,
68{
69 type Marker = crate::row::SelectCols<(Self,)>;
70}
71
72pub trait AliasExt: Sized {
81 fn alias(self, name: &'static str) -> AliasedExpr<Self> {
82 AliasedExpr { expr: self, name }
83 }
84}
85
86impl<T: Sized> AliasExt for T {}
87
88pub const fn alias<E>(expr: E, name: &'static str) -> AliasedExpr<E> {
101 AliasedExpr { expr, name }
102}
103
104#[derive(Clone, Copy, Debug)]
109pub struct NamedExpr<E, Name> {
110 pub(crate) expr: E,
111 pub(crate) name: core::marker::PhantomData<Name>,
112}
113
114impl<E, Name> NamedExpr<E, Name> {
115 pub const fn expression(&self) -> &E {
117 &self.expr
118 }
119
120 pub fn into_expression(self) -> E {
122 self.expr
123 }
124}
125
126impl<'a, V, E, Name> ToSQL<'a, V> for NamedExpr<E, Name>
127where
128 V: SQLParam + 'a,
129 E: ToSQL<'a, V>,
130 Name: crate::Tag,
131{
132 fn to_sql(&self) -> SQL<'a, V> {
133 self.expr.to_sql().alias(Name::NAME)
134 }
135
136 fn into_sql(self) -> SQL<'a, V> {
137 self.expr.into_sql().alias(Name::NAME)
138 }
139}
140
141impl<'a, V, E, Name> Expr<'a, V> for NamedExpr<E, Name>
142where
143 V: SQLParam + 'a,
144 E: Expr<'a, V>,
145 Name: crate::Tag,
146{
147 type SQLType = E::SQLType;
148 type Nullable = E::Nullable;
149 type Aggregate = E::Aggregate;
150
151 fn to_expr_sql(&self) -> SQL<'a, V> {
152 self.expr.to_expr_sql().alias(Name::NAME)
153 }
154
155 fn into_expr_sql(self) -> SQL<'a, V> {
156 self.expr.into_expr_sql().alias(Name::NAME)
157 }
158}
159
160impl<E, Name> super::HasAggStatus for NamedExpr<E, Name>
161where
162 E: super::HasAggStatus,
163{
164 type Status = E::Status;
165}
166
167impl<E, Name> crate::row::ExprValueType for NamedExpr<E, Name>
168where
169 E: crate::row::ExprValueType,
170{
171 type ValueType = E::ValueType;
172}
173
174impl<E, Name> crate::row::IntoSelectTarget for NamedExpr<E, Name>
175where
176 E: crate::row::ExprValueType,
177{
178 type Marker = crate::row::SelectCols<(Self,)>;
179}
180
181impl<E, Name> crate::row::GroupByIdentity for NamedExpr<E, Name>
182where
183 E: crate::row::GroupByIdentity,
184{
185 type Identity = E::Identity;
186}
187
188pub trait NamedExt: Sized {
190 fn named<Name: crate::Tag>(self) -> NamedExpr<Self, Name> {
192 NamedExpr {
193 expr: self,
194 name: core::marker::PhantomData,
195 }
196 }
197}
198
199impl<T: crate::row::ExprValueType> NamedExt for T {}
200
201#[diagnostic::on_unimplemented(
206 message = "TYPEOF is not available for this dialect",
207 label = "use a dialect-specific type inspection expression"
208)]
209pub trait TypeofSupport {}
210
211impl TypeofSupport for SQLiteDialect {}
212
213pub fn typeof_<'a, V, E>(
228 expr: E,
229) -> SQLExpr<'a, V, <V::DialectMarker as crate::dialect::DialectTypes>::Text, NonNull, E::Aggregate>
230where
231 V: SQLParam + 'a,
232 V::DialectMarker: TypeofSupport,
233 E: Expr<'a, V>,
234{
235 SQLExpr::new(SQL::func("TYPEOF", expr.into_expr_sql()))
236}
237
238pub fn r#typeof<'a, V, E>(
240 expr: E,
241) -> SQLExpr<'a, V, <V::DialectMarker as crate::dialect::DialectTypes>::Text, NonNull, E::Aggregate>
242where
243 V: SQLParam + 'a,
244 V::DialectMarker: TypeofSupport,
245 E: Expr<'a, V>,
246{
247 typeof_(expr)
248}
249
250pub trait DefaultCastTypeName: DataType {
256 const CAST_TYPE_NAME: &'static str;
257}
258
259impl DefaultCastTypeName for drizzle_types::sqlite::types::Integer {
260 const CAST_TYPE_NAME: &'static str = "INTEGER";
261}
262impl DefaultCastTypeName for drizzle_types::sqlite::types::Text {
263 const CAST_TYPE_NAME: &'static str = "TEXT";
264}
265impl DefaultCastTypeName for drizzle_types::sqlite::types::Real {
266 const CAST_TYPE_NAME: &'static str = "REAL";
267}
268impl DefaultCastTypeName for drizzle_types::sqlite::types::Blob {
269 const CAST_TYPE_NAME: &'static str = "BLOB";
270}
271impl DefaultCastTypeName for drizzle_types::sqlite::types::Numeric {
272 const CAST_TYPE_NAME: &'static str = "NUMERIC";
273}
274impl DefaultCastTypeName for drizzle_types::sqlite::types::Any {
275 const CAST_TYPE_NAME: &'static str = "ANY";
276}
277
278impl DefaultCastTypeName for drizzle_types::postgres::types::Int2 {
279 const CAST_TYPE_NAME: &'static str = "SMALLINT";
280}
281impl DefaultCastTypeName for drizzle_types::postgres::types::Int4 {
282 const CAST_TYPE_NAME: &'static str = "INTEGER";
283}
284impl DefaultCastTypeName for drizzle_types::postgres::types::Int8 {
285 const CAST_TYPE_NAME: &'static str = "BIGINT";
286}
287impl DefaultCastTypeName for drizzle_types::postgres::types::Float4 {
288 const CAST_TYPE_NAME: &'static str = "REAL";
289}
290impl DefaultCastTypeName for drizzle_types::postgres::types::Float8 {
291 const CAST_TYPE_NAME: &'static str = "DOUBLE PRECISION";
292}
293impl DefaultCastTypeName for drizzle_types::postgres::types::Varchar {
294 const CAST_TYPE_NAME: &'static str = "VARCHAR";
295}
296impl DefaultCastTypeName for drizzle_types::postgres::types::Text {
297 const CAST_TYPE_NAME: &'static str = "TEXT";
298}
299impl DefaultCastTypeName for drizzle_types::postgres::types::Char {
300 const CAST_TYPE_NAME: &'static str = "CHAR";
301}
302impl DefaultCastTypeName for drizzle_types::postgres::types::Bytea {
303 const CAST_TYPE_NAME: &'static str = "BYTEA";
304}
305impl DefaultCastTypeName for drizzle_types::postgres::types::Boolean {
306 const CAST_TYPE_NAME: &'static str = "BOOLEAN";
307}
308impl DefaultCastTypeName for drizzle_types::postgres::types::Timestamptz {
309 const CAST_TYPE_NAME: &'static str = "TIMESTAMPTZ";
310}
311impl DefaultCastTypeName for drizzle_types::postgres::types::Timestamp {
312 const CAST_TYPE_NAME: &'static str = "TIMESTAMP";
313}
314impl DefaultCastTypeName for drizzle_types::postgres::types::Date {
315 const CAST_TYPE_NAME: &'static str = "DATE";
316}
317impl DefaultCastTypeName for drizzle_types::postgres::types::Time {
318 const CAST_TYPE_NAME: &'static str = "TIME";
319}
320impl DefaultCastTypeName for drizzle_types::postgres::types::Timetz {
321 const CAST_TYPE_NAME: &'static str = "TIMETZ";
322}
323impl DefaultCastTypeName for drizzle_types::postgres::types::Numeric {
324 const CAST_TYPE_NAME: &'static str = "NUMERIC";
325}
326impl DefaultCastTypeName for drizzle_types::postgres::types::Uuid {
327 const CAST_TYPE_NAME: &'static str = "UUID";
328}
329impl DefaultCastTypeName for drizzle_types::postgres::types::Json {
330 const CAST_TYPE_NAME: &'static str = "JSON";
331}
332impl DefaultCastTypeName for drizzle_types::postgres::types::Jsonb {
333 const CAST_TYPE_NAME: &'static str = "JSONB";
334}
335impl DefaultCastTypeName for drizzle_types::postgres::types::Any {
336 const CAST_TYPE_NAME: &'static str = "ANY";
337}
338impl DefaultCastTypeName for drizzle_types::postgres::types::Interval {
339 const CAST_TYPE_NAME: &'static str = "INTERVAL";
340}
341impl DefaultCastTypeName for drizzle_types::postgres::types::Inet {
342 const CAST_TYPE_NAME: &'static str = "INET";
343}
344impl DefaultCastTypeName for drizzle_types::postgres::types::Cidr {
345 const CAST_TYPE_NAME: &'static str = "CIDR";
346}
347impl DefaultCastTypeName for drizzle_types::postgres::types::MacAddr {
348 const CAST_TYPE_NAME: &'static str = "MACADDR";
349}
350impl DefaultCastTypeName for drizzle_types::postgres::types::MacAddr8 {
351 const CAST_TYPE_NAME: &'static str = "MACADDR8";
352}
353impl DefaultCastTypeName for drizzle_types::postgres::types::Point {
354 const CAST_TYPE_NAME: &'static str = "POINT";
355}
356impl DefaultCastTypeName for drizzle_types::postgres::types::LineString {
357 const CAST_TYPE_NAME: &'static str = "PATH";
358}
359impl DefaultCastTypeName for drizzle_types::postgres::types::Rect {
360 const CAST_TYPE_NAME: &'static str = "BOX";
361}
362impl DefaultCastTypeName for drizzle_types::postgres::types::BitString {
363 const CAST_TYPE_NAME: &'static str = "BIT VARYING";
364}
365impl DefaultCastTypeName for drizzle_types::postgres::types::Line {
366 const CAST_TYPE_NAME: &'static str = "LINE";
367}
368impl DefaultCastTypeName for drizzle_types::postgres::types::LineSegment {
369 const CAST_TYPE_NAME: &'static str = "LSEG";
370}
371impl DefaultCastTypeName for drizzle_types::postgres::types::Polygon {
372 const CAST_TYPE_NAME: &'static str = "POLYGON";
373}
374impl DefaultCastTypeName for drizzle_types::postgres::types::Circle {
375 const CAST_TYPE_NAME: &'static str = "CIRCLE";
376}
377impl DefaultCastTypeName for drizzle_types::postgres::types::Enum {
378 const CAST_TYPE_NAME: &'static str = "TEXT";
379}
380
381impl DefaultCastTypeName for drizzle_types::mysql::types::BigInt {
382 const CAST_TYPE_NAME: &'static str = "SIGNED";
383}
384impl DefaultCastTypeName for drizzle_types::mysql::types::BigIntUnsigned {
385 const CAST_TYPE_NAME: &'static str = "UNSIGNED";
386}
387impl DefaultCastTypeName for drizzle_types::mysql::types::Float {
388 const CAST_TYPE_NAME: &'static str = "FLOAT";
389}
390impl DefaultCastTypeName for drizzle_types::mysql::types::Double {
391 const CAST_TYPE_NAME: &'static str = "DOUBLE";
392}
393impl DefaultCastTypeName for drizzle_types::mysql::types::Decimal {
394 const CAST_TYPE_NAME: &'static str = "DECIMAL";
395}
396impl DefaultCastTypeName for drizzle_types::mysql::types::Varchar {
397 const CAST_TYPE_NAME: &'static str = "CHAR";
398}
399impl DefaultCastTypeName for drizzle_types::mysql::types::Varbinary {
400 const CAST_TYPE_NAME: &'static str = "BINARY";
401}
402impl DefaultCastTypeName for drizzle_types::mysql::types::Json {
403 const CAST_TYPE_NAME: &'static str = "JSON";
404}
405impl DefaultCastTypeName for drizzle_types::mysql::types::Date {
406 const CAST_TYPE_NAME: &'static str = "DATE";
407}
408impl DefaultCastTypeName for drizzle_types::mysql::types::Time {
409 const CAST_TYPE_NAME: &'static str = "TIME";
410}
411impl DefaultCastTypeName for drizzle_types::mysql::types::DateTime {
412 const CAST_TYPE_NAME: &'static str = "DATETIME";
413}
414impl DefaultCastTypeName for drizzle_types::mysql::types::Year {
415 const CAST_TYPE_NAME: &'static str = "YEAR";
416}
417
418pub trait CastTarget<'a, T: DataType, D> {
424 fn cast_type_name(self) -> &'a str;
425}
426
427#[diagnostic::on_unimplemented(
429 message = "cannot cast `{Source}` to `{Target}` for this dialect",
430 label = "cast target is incompatible with source type",
431 note = "use a supported target marker, or raw SQL when the conversion is intentionally dialect-specific"
432)]
433pub trait CastTypePolicy<D, Source: DataType, Target: DataType> {}
434
435#[doc(hidden)]
437pub trait CastNullabilityPolicy<D, Input: Nullability>: DataType {
438 type Output: Nullability;
439}
440
441macro_rules! mysql_cast_policy {
442 (
443 preserving: [$($preserving:ty),+ $(,)?],
444 nullable: [$($nullable:ty),+ $(,)?],
445 ) => {
446 $(
447 impl<Source: DataType> CastTypePolicy<MySQLDialect, Source, $preserving> for () {}
448
449 impl<Input: Nullability> CastNullabilityPolicy<MySQLDialect, Input> for $preserving {
450 type Output = Input;
451 }
452 )+
453 $(
454 impl<Source: DataType> CastTypePolicy<MySQLDialect, Source, $nullable> for () {}
455
456 impl<Input: Nullability> CastNullabilityPolicy<MySQLDialect, Input> for $nullable {
457 type Output = Null;
458 }
459 )+
460 };
461}
462
463mysql_cast_policy! {
464 preserving: [
465 drizzle_types::mysql::types::BigInt,
466 drizzle_types::mysql::types::BigIntUnsigned,
467 drizzle_types::mysql::types::Float,
468 drizzle_types::mysql::types::Double,
469 drizzle_types::mysql::types::Decimal,
470 drizzle_types::mysql::types::Varchar,
471 drizzle_types::mysql::types::Varbinary,
472 drizzle_types::mysql::types::Json,
473 ],
474 nullable: [
475 drizzle_types::mysql::types::Date,
476 drizzle_types::mysql::types::Time,
477 drizzle_types::mysql::types::DateTime,
478 drizzle_types::mysql::types::Year,
479 ],
480}
481
482impl<Source: DataType + Compatible<Target>, Target: DataType>
483 CastTypePolicy<PostgresDialect, Source, Target> for ()
484{
485}
486
487impl<Input: Nullability, Target: DataType> CastNullabilityPolicy<PostgresDialect, Input>
488 for Target
489{
490 type Output = Input;
491}
492
493impl<Source: DataType + Compatible<Target>, Target: DataType>
494 CastTypePolicy<SQLiteDialect, Source, Target> for ()
495{
496}
497
498impl<Input: Nullability, Target: DataType> CastNullabilityPolicy<SQLiteDialect, Input> for Target {
499 type Output = Input;
500}
501
502impl<'a, T: DataType, D> CastTarget<'a, T, D> for &'a str {
503 fn cast_type_name(self) -> &'a str {
504 self
505 }
506}
507
508impl<'a, T, D> CastTarget<'a, T, D> for T
509where
510 T: DataType + DefaultCastTypeName,
511{
512 fn cast_type_name(self) -> &'a str {
513 T::CAST_TYPE_NAME
514 }
515}
516
517#[allow(clippy::type_complexity)]
544pub fn cast<'a, V, E, Target>(
545 expr: E,
546 target_type: impl CastTarget<'a, Target, V::DialectMarker>,
547) -> SQLExpr<
548 'a,
549 V,
550 Target,
551 <Target as CastNullabilityPolicy<V::DialectMarker, E::Nullable>>::Output,
552 E::Aggregate,
553>
554where
555 V: SQLParam + 'a,
556 E: Expr<'a, V>,
557 Target: DataType + CastNullabilityPolicy<V::DialectMarker, E::Nullable>,
558 (): CastTypePolicy<V::DialectMarker, E::SQLType, Target>,
559{
560 SQLExpr::new(SQL::func(
561 "CAST",
562 expr.into_expr_sql()
563 .push(Token::AS)
564 .append(SQL::raw(target_type.cast_type_name())),
565 ))
566}
567
568#[allow(clippy::type_complexity)]
606pub fn string_concat<'a, V, L, R>(
607 left: L,
608 right: R,
609) -> SQLExpr<
610 'a,
611 V,
612 <V::DialectMarker as crate::dialect::DialectTypes>::Text,
613 <L::Nullable as NullOr<R::Nullable>>::Output,
614 <L::Aggregate as AggOr<R::Aggregate>>::Output,
615>
616where
617 V: SQLParam + 'a,
618 L: Expr<'a, V>,
619 R: Expr<'a, V>,
620 L::SQLType: Textual,
621 R::SQLType: Textual,
622 L::Nullable: NullOr<R::Nullable>,
623 R::Nullable: Nullability,
624 L::Aggregate: AggOr<R::Aggregate>,
625 R::Aggregate: AggregateKind,
626{
627 super::concat(left, right)
628}
629
630#[must_use]
654pub fn raw<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar>
655where
656 V: SQLParam + 'a,
657 T: DataType,
658{
659 SQLExpr::new(SQL::raw(sql))
660}
661
662#[must_use]
664pub fn raw_nullable<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar>
665where
666 V: SQLParam + 'a,
667 T: DataType,
668{
669 SQLExpr::new(SQL::raw(sql))
670}
671
672#[must_use]
674pub fn raw_non_null<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, NonNull, Scalar>
675where
676 V: SQLParam + 'a,
677 T: DataType,
678{
679 SQLExpr::new(SQL::raw(sql))
680}
681
682#[derive(Clone, Copy, Debug)]
689pub struct Excluded<C> {
690 column: C,
691}
692
693pub trait ExcludedSupport {}
695
696impl ExcludedSupport for SQLiteDialect {}
697impl ExcludedSupport for PostgresDialect {}
698
699pub const fn excluded<C>(column: C) -> Excluded<C> {
715 Excluded { column }
716}
717
718impl<'a, V, C> Expr<'a, V> for Excluded<C>
719where
720 V: SQLParam + 'a,
721 V::DialectMarker: ExcludedSupport,
722 C: Expr<'a, V> + SQLColumnInfo,
723{
724 type SQLType = C::SQLType;
725 type Nullable = C::Nullable;
726 type Aggregate = C::Aggregate;
727}
728
729impl<'a, V, C> ToSQL<'a, V> for Excluded<C>
730where
731 V: SQLParam + 'a,
732 V::DialectMarker: ExcludedSupport,
733 C: SQLColumnInfo,
734{
735 fn to_sql(&self) -> SQL<'a, V> {
736 SQL::empty()
737 .push(Token::EXCLUDED)
738 .push(Token::DOT)
739 .append(SQL::ident(self.column.name()))
740 }
741}