1use crate::dialect::{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
49impl<E: super::HasAggStatus> super::HasAggStatus for AliasedExpr<E> {
50 type Status = E::Status;
51}
52
53impl<E: crate::row::ExprValueType> crate::row::ExprValueType for AliasedExpr<E> {
54 type ValueType = E::ValueType;
55}
56
57impl<E> crate::row::IntoSelectTarget for AliasedExpr<E>
58where
59 E: crate::row::ExprValueType,
60{
61 type Marker = crate::row::SelectCols<(Self,)>;
62}
63
64pub trait AliasExt: Sized {
73 fn alias(self, name: &'static str) -> AliasedExpr<Self> {
74 AliasedExpr { expr: self, name }
75 }
76}
77
78impl<T: Sized> AliasExt for T {}
79
80pub const fn alias<E>(expr: E, name: &'static str) -> AliasedExpr<E> {
93 AliasedExpr { expr, name }
94}
95
96pub fn typeof_<'a, V, E>(
115 expr: E,
116) -> SQLExpr<'a, V, <V::DialectMarker as crate::dialect::DialectTypes>::Text, NonNull, E::Aggregate>
117where
118 V: SQLParam + 'a,
119 E: Expr<'a, V>,
120{
121 SQLExpr::new(SQL::func("TYPEOF", expr.into_sql()))
122}
123
124pub fn r#typeof<'a, V, E>(
126 expr: E,
127) -> SQLExpr<'a, V, <V::DialectMarker as crate::dialect::DialectTypes>::Text, NonNull, E::Aggregate>
128where
129 V: SQLParam + 'a,
130 E: Expr<'a, V>,
131{
132 typeof_(expr)
133}
134
135pub trait DefaultCastTypeName: DataType {
141 const CAST_TYPE_NAME: &'static str;
142}
143
144impl DefaultCastTypeName for drizzle_types::sqlite::types::Integer {
145 const CAST_TYPE_NAME: &'static str = "INTEGER";
146}
147impl DefaultCastTypeName for drizzle_types::sqlite::types::Text {
148 const CAST_TYPE_NAME: &'static str = "TEXT";
149}
150impl DefaultCastTypeName for drizzle_types::sqlite::types::Real {
151 const CAST_TYPE_NAME: &'static str = "REAL";
152}
153impl DefaultCastTypeName for drizzle_types::sqlite::types::Blob {
154 const CAST_TYPE_NAME: &'static str = "BLOB";
155}
156impl DefaultCastTypeName for drizzle_types::sqlite::types::Numeric {
157 const CAST_TYPE_NAME: &'static str = "NUMERIC";
158}
159impl DefaultCastTypeName for drizzle_types::sqlite::types::Any {
160 const CAST_TYPE_NAME: &'static str = "ANY";
161}
162
163impl DefaultCastTypeName for drizzle_types::postgres::types::Int2 {
164 const CAST_TYPE_NAME: &'static str = "SMALLINT";
165}
166impl DefaultCastTypeName for drizzle_types::postgres::types::Int4 {
167 const CAST_TYPE_NAME: &'static str = "INTEGER";
168}
169impl DefaultCastTypeName for drizzle_types::postgres::types::Int8 {
170 const CAST_TYPE_NAME: &'static str = "BIGINT";
171}
172impl DefaultCastTypeName for drizzle_types::postgres::types::Float4 {
173 const CAST_TYPE_NAME: &'static str = "REAL";
174}
175impl DefaultCastTypeName for drizzle_types::postgres::types::Float8 {
176 const CAST_TYPE_NAME: &'static str = "DOUBLE PRECISION";
177}
178impl DefaultCastTypeName for drizzle_types::postgres::types::Varchar {
179 const CAST_TYPE_NAME: &'static str = "VARCHAR";
180}
181impl DefaultCastTypeName for drizzle_types::postgres::types::Text {
182 const CAST_TYPE_NAME: &'static str = "TEXT";
183}
184impl DefaultCastTypeName for drizzle_types::postgres::types::Char {
185 const CAST_TYPE_NAME: &'static str = "CHAR";
186}
187impl DefaultCastTypeName for drizzle_types::postgres::types::Bytea {
188 const CAST_TYPE_NAME: &'static str = "BYTEA";
189}
190impl DefaultCastTypeName for drizzle_types::postgres::types::Boolean {
191 const CAST_TYPE_NAME: &'static str = "BOOLEAN";
192}
193impl DefaultCastTypeName for drizzle_types::postgres::types::Timestamptz {
194 const CAST_TYPE_NAME: &'static str = "TIMESTAMPTZ";
195}
196impl DefaultCastTypeName for drizzle_types::postgres::types::Timestamp {
197 const CAST_TYPE_NAME: &'static str = "TIMESTAMP";
198}
199impl DefaultCastTypeName for drizzle_types::postgres::types::Date {
200 const CAST_TYPE_NAME: &'static str = "DATE";
201}
202impl DefaultCastTypeName for drizzle_types::postgres::types::Time {
203 const CAST_TYPE_NAME: &'static str = "TIME";
204}
205impl DefaultCastTypeName for drizzle_types::postgres::types::Timetz {
206 const CAST_TYPE_NAME: &'static str = "TIMETZ";
207}
208impl DefaultCastTypeName for drizzle_types::postgres::types::Numeric {
209 const CAST_TYPE_NAME: &'static str = "NUMERIC";
210}
211impl DefaultCastTypeName for drizzle_types::postgres::types::Uuid {
212 const CAST_TYPE_NAME: &'static str = "UUID";
213}
214impl DefaultCastTypeName for drizzle_types::postgres::types::Json {
215 const CAST_TYPE_NAME: &'static str = "JSON";
216}
217impl DefaultCastTypeName for drizzle_types::postgres::types::Jsonb {
218 const CAST_TYPE_NAME: &'static str = "JSONB";
219}
220impl DefaultCastTypeName for drizzle_types::postgres::types::Any {
221 const CAST_TYPE_NAME: &'static str = "ANY";
222}
223impl DefaultCastTypeName for drizzle_types::postgres::types::Interval {
224 const CAST_TYPE_NAME: &'static str = "INTERVAL";
225}
226impl DefaultCastTypeName for drizzle_types::postgres::types::Inet {
227 const CAST_TYPE_NAME: &'static str = "INET";
228}
229impl DefaultCastTypeName for drizzle_types::postgres::types::Cidr {
230 const CAST_TYPE_NAME: &'static str = "CIDR";
231}
232impl DefaultCastTypeName for drizzle_types::postgres::types::MacAddr {
233 const CAST_TYPE_NAME: &'static str = "MACADDR";
234}
235impl DefaultCastTypeName for drizzle_types::postgres::types::MacAddr8 {
236 const CAST_TYPE_NAME: &'static str = "MACADDR8";
237}
238impl DefaultCastTypeName for drizzle_types::postgres::types::Point {
239 const CAST_TYPE_NAME: &'static str = "POINT";
240}
241impl DefaultCastTypeName for drizzle_types::postgres::types::LineString {
242 const CAST_TYPE_NAME: &'static str = "PATH";
243}
244impl DefaultCastTypeName for drizzle_types::postgres::types::Rect {
245 const CAST_TYPE_NAME: &'static str = "BOX";
246}
247impl DefaultCastTypeName for drizzle_types::postgres::types::BitString {
248 const CAST_TYPE_NAME: &'static str = "BIT VARYING";
249}
250impl DefaultCastTypeName for drizzle_types::postgres::types::Line {
251 const CAST_TYPE_NAME: &'static str = "LINE";
252}
253impl DefaultCastTypeName for drizzle_types::postgres::types::LineSegment {
254 const CAST_TYPE_NAME: &'static str = "LSEG";
255}
256impl DefaultCastTypeName for drizzle_types::postgres::types::Polygon {
257 const CAST_TYPE_NAME: &'static str = "POLYGON";
258}
259impl DefaultCastTypeName for drizzle_types::postgres::types::Circle {
260 const CAST_TYPE_NAME: &'static str = "CIRCLE";
261}
262impl DefaultCastTypeName for drizzle_types::postgres::types::Enum {
263 const CAST_TYPE_NAME: &'static str = "TEXT";
264}
265
266pub trait CastTarget<'a, T: DataType, D> {
272 fn cast_type_name(self) -> &'a str;
273}
274
275#[diagnostic::on_unimplemented(
277 message = "cannot cast `{Source}` to `{Target}` for this dialect",
278 label = "cast target is incompatible with source type",
279 note = "for SQLite strict typing, use a compatible cast target or cast through ANY/raw sql intentionally"
280)]
281pub trait CastTypePolicy<D, Source: DataType, Target: DataType> {}
282
283impl<Source: DataType + Compatible<Target>, Target: DataType>
284 CastTypePolicy<PostgresDialect, Source, Target> for ()
285{
286}
287
288impl<Source: DataType + Compatible<Target>, Target: DataType>
289 CastTypePolicy<SQLiteDialect, Source, Target> for ()
290{
291}
292
293impl<'a, T: DataType, D> CastTarget<'a, T, D> for &'a str {
294 fn cast_type_name(self) -> &'a str {
295 self
296 }
297}
298
299impl<'a, T, D> CastTarget<'a, T, D> for T
300where
301 T: DataType + DefaultCastTypeName,
302{
303 fn cast_type_name(self) -> &'a str {
304 T::CAST_TYPE_NAME
305 }
306}
307
308pub fn cast<'a, V, E, Target>(
333 expr: E,
334 target_type: impl CastTarget<'a, Target, V::DialectMarker>,
335) -> SQLExpr<'a, V, Target, E::Nullable, E::Aggregate>
336where
337 V: SQLParam + 'a,
338 E: Expr<'a, V>,
339 Target: DataType,
340 (): CastTypePolicy<V::DialectMarker, E::SQLType, Target>,
341{
342 SQLExpr::new(SQL::func(
343 "CAST",
344 expr.into_sql()
345 .push(Token::AS)
346 .append(SQL::raw(target_type.cast_type_name())),
347 ))
348}
349
350#[allow(clippy::type_complexity)]
385pub fn string_concat<'a, V, L, R>(
386 left: L,
387 right: R,
388) -> SQLExpr<
389 'a,
390 V,
391 <V::DialectMarker as crate::dialect::DialectTypes>::Text,
392 <L::Nullable as NullOr<R::Nullable>>::Output,
393 <L::Aggregate as AggOr<R::Aggregate>>::Output,
394>
395where
396 V: SQLParam + 'a,
397 L: Expr<'a, V>,
398 R: Expr<'a, V>,
399 L::SQLType: Textual,
400 R::SQLType: Textual,
401 L::Nullable: NullOr<R::Nullable>,
402 R::Nullable: Nullability,
403 L::Aggregate: AggOr<R::Aggregate>,
404 R::Aggregate: AggregateKind,
405{
406 super::concat(left, right)
407}
408
409#[must_use]
433pub fn raw<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar>
434where
435 V: SQLParam + 'a,
436 T: DataType,
437{
438 SQLExpr::new(SQL::raw(sql))
439}
440
441#[must_use]
443pub fn raw_non_null<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, NonNull, Scalar>
444where
445 V: SQLParam + 'a,
446 T: DataType,
447{
448 SQLExpr::new(SQL::raw(sql))
449}
450
451#[derive(Clone, Copy, Debug)]
458pub struct Excluded<C> {
459 column: C,
460}
461
462pub const fn excluded<C>(column: C) -> Excluded<C> {
478 Excluded { column }
479}
480
481impl<'a, V, C> Expr<'a, V> for Excluded<C>
482where
483 V: SQLParam + 'a,
484 C: Expr<'a, V> + SQLColumnInfo,
485{
486 type SQLType = C::SQLType;
487 type Nullable = C::Nullable;
488 type Aggregate = C::Aggregate;
489}
490
491impl<'a, V, C> ToSQL<'a, V> for Excluded<C>
492where
493 V: SQLParam + 'a,
494 C: SQLColumnInfo,
495{
496 fn to_sql(&self) -> SQL<'a, V> {
497 SQL::empty()
498 .push(Token::EXCLUDED)
499 .push(Token::DOT)
500 .append(SQL::ident(self.column.name()))
501 }
502}