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 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
104pub fn typeof_<'a, V, E>(
123 expr: E,
124) -> SQLExpr<'a, V, <V::DialectMarker as crate::dialect::DialectTypes>::Text, NonNull, E::Aggregate>
125where
126 V: SQLParam + 'a,
127 E: Expr<'a, V>,
128{
129 SQLExpr::new(SQL::func("TYPEOF", expr.into_expr_sql()))
130}
131
132pub fn r#typeof<'a, V, E>(
134 expr: E,
135) -> SQLExpr<'a, V, <V::DialectMarker as crate::dialect::DialectTypes>::Text, NonNull, E::Aggregate>
136where
137 V: SQLParam + 'a,
138 E: Expr<'a, V>,
139{
140 typeof_(expr)
141}
142
143pub trait DefaultCastTypeName: DataType {
149 const CAST_TYPE_NAME: &'static str;
150}
151
152impl DefaultCastTypeName for drizzle_types::sqlite::types::Integer {
153 const CAST_TYPE_NAME: &'static str = "INTEGER";
154}
155impl DefaultCastTypeName for drizzle_types::sqlite::types::Text {
156 const CAST_TYPE_NAME: &'static str = "TEXT";
157}
158impl DefaultCastTypeName for drizzle_types::sqlite::types::Real {
159 const CAST_TYPE_NAME: &'static str = "REAL";
160}
161impl DefaultCastTypeName for drizzle_types::sqlite::types::Blob {
162 const CAST_TYPE_NAME: &'static str = "BLOB";
163}
164impl DefaultCastTypeName for drizzle_types::sqlite::types::Numeric {
165 const CAST_TYPE_NAME: &'static str = "NUMERIC";
166}
167impl DefaultCastTypeName for drizzle_types::sqlite::types::Any {
168 const CAST_TYPE_NAME: &'static str = "ANY";
169}
170
171impl DefaultCastTypeName for drizzle_types::postgres::types::Int2 {
172 const CAST_TYPE_NAME: &'static str = "SMALLINT";
173}
174impl DefaultCastTypeName for drizzle_types::postgres::types::Int4 {
175 const CAST_TYPE_NAME: &'static str = "INTEGER";
176}
177impl DefaultCastTypeName for drizzle_types::postgres::types::Int8 {
178 const CAST_TYPE_NAME: &'static str = "BIGINT";
179}
180impl DefaultCastTypeName for drizzle_types::postgres::types::Float4 {
181 const CAST_TYPE_NAME: &'static str = "REAL";
182}
183impl DefaultCastTypeName for drizzle_types::postgres::types::Float8 {
184 const CAST_TYPE_NAME: &'static str = "DOUBLE PRECISION";
185}
186impl DefaultCastTypeName for drizzle_types::postgres::types::Varchar {
187 const CAST_TYPE_NAME: &'static str = "VARCHAR";
188}
189impl DefaultCastTypeName for drizzle_types::postgres::types::Text {
190 const CAST_TYPE_NAME: &'static str = "TEXT";
191}
192impl DefaultCastTypeName for drizzle_types::postgres::types::Char {
193 const CAST_TYPE_NAME: &'static str = "CHAR";
194}
195impl DefaultCastTypeName for drizzle_types::postgres::types::Bytea {
196 const CAST_TYPE_NAME: &'static str = "BYTEA";
197}
198impl DefaultCastTypeName for drizzle_types::postgres::types::Boolean {
199 const CAST_TYPE_NAME: &'static str = "BOOLEAN";
200}
201impl DefaultCastTypeName for drizzle_types::postgres::types::Timestamptz {
202 const CAST_TYPE_NAME: &'static str = "TIMESTAMPTZ";
203}
204impl DefaultCastTypeName for drizzle_types::postgres::types::Timestamp {
205 const CAST_TYPE_NAME: &'static str = "TIMESTAMP";
206}
207impl DefaultCastTypeName for drizzle_types::postgres::types::Date {
208 const CAST_TYPE_NAME: &'static str = "DATE";
209}
210impl DefaultCastTypeName for drizzle_types::postgres::types::Time {
211 const CAST_TYPE_NAME: &'static str = "TIME";
212}
213impl DefaultCastTypeName for drizzle_types::postgres::types::Timetz {
214 const CAST_TYPE_NAME: &'static str = "TIMETZ";
215}
216impl DefaultCastTypeName for drizzle_types::postgres::types::Numeric {
217 const CAST_TYPE_NAME: &'static str = "NUMERIC";
218}
219impl DefaultCastTypeName for drizzle_types::postgres::types::Uuid {
220 const CAST_TYPE_NAME: &'static str = "UUID";
221}
222impl DefaultCastTypeName for drizzle_types::postgres::types::Json {
223 const CAST_TYPE_NAME: &'static str = "JSON";
224}
225impl DefaultCastTypeName for drizzle_types::postgres::types::Jsonb {
226 const CAST_TYPE_NAME: &'static str = "JSONB";
227}
228impl DefaultCastTypeName for drizzle_types::postgres::types::Any {
229 const CAST_TYPE_NAME: &'static str = "ANY";
230}
231impl DefaultCastTypeName for drizzle_types::postgres::types::Interval {
232 const CAST_TYPE_NAME: &'static str = "INTERVAL";
233}
234impl DefaultCastTypeName for drizzle_types::postgres::types::Inet {
235 const CAST_TYPE_NAME: &'static str = "INET";
236}
237impl DefaultCastTypeName for drizzle_types::postgres::types::Cidr {
238 const CAST_TYPE_NAME: &'static str = "CIDR";
239}
240impl DefaultCastTypeName for drizzle_types::postgres::types::MacAddr {
241 const CAST_TYPE_NAME: &'static str = "MACADDR";
242}
243impl DefaultCastTypeName for drizzle_types::postgres::types::MacAddr8 {
244 const CAST_TYPE_NAME: &'static str = "MACADDR8";
245}
246impl DefaultCastTypeName for drizzle_types::postgres::types::Point {
247 const CAST_TYPE_NAME: &'static str = "POINT";
248}
249impl DefaultCastTypeName for drizzle_types::postgres::types::LineString {
250 const CAST_TYPE_NAME: &'static str = "PATH";
251}
252impl DefaultCastTypeName for drizzle_types::postgres::types::Rect {
253 const CAST_TYPE_NAME: &'static str = "BOX";
254}
255impl DefaultCastTypeName for drizzle_types::postgres::types::BitString {
256 const CAST_TYPE_NAME: &'static str = "BIT VARYING";
257}
258impl DefaultCastTypeName for drizzle_types::postgres::types::Line {
259 const CAST_TYPE_NAME: &'static str = "LINE";
260}
261impl DefaultCastTypeName for drizzle_types::postgres::types::LineSegment {
262 const CAST_TYPE_NAME: &'static str = "LSEG";
263}
264impl DefaultCastTypeName for drizzle_types::postgres::types::Polygon {
265 const CAST_TYPE_NAME: &'static str = "POLYGON";
266}
267impl DefaultCastTypeName for drizzle_types::postgres::types::Circle {
268 const CAST_TYPE_NAME: &'static str = "CIRCLE";
269}
270impl DefaultCastTypeName for drizzle_types::postgres::types::Enum {
271 const CAST_TYPE_NAME: &'static str = "TEXT";
272}
273
274pub trait CastTarget<'a, T: DataType, D> {
280 fn cast_type_name(self) -> &'a str;
281}
282
283#[diagnostic::on_unimplemented(
285 message = "cannot cast `{Source}` to `{Target}` for this dialect",
286 label = "cast target is incompatible with source type",
287 note = "for SQLite strict typing, use a compatible cast target or cast through ANY/raw sql intentionally"
288)]
289pub trait CastTypePolicy<D, Source: DataType, Target: DataType> {}
290
291impl<Source: DataType + Compatible<Target>, Target: DataType>
292 CastTypePolicy<PostgresDialect, Source, Target> for ()
293{
294}
295
296impl<Source: DataType + Compatible<Target>, Target: DataType>
297 CastTypePolicy<SQLiteDialect, Source, Target> for ()
298{
299}
300
301impl<'a, T: DataType, D> CastTarget<'a, T, D> for &'a str {
302 fn cast_type_name(self) -> &'a str {
303 self
304 }
305}
306
307impl<'a, T, D> CastTarget<'a, T, D> for T
308where
309 T: DataType + DefaultCastTypeName,
310{
311 fn cast_type_name(self) -> &'a str {
312 T::CAST_TYPE_NAME
313 }
314}
315
316pub fn cast<'a, V, E, Target>(
341 expr: E,
342 target_type: impl CastTarget<'a, Target, V::DialectMarker>,
343) -> SQLExpr<'a, V, Target, E::Nullable, E::Aggregate>
344where
345 V: SQLParam + 'a,
346 E: Expr<'a, V>,
347 Target: DataType,
348 (): CastTypePolicy<V::DialectMarker, E::SQLType, Target>,
349{
350 SQLExpr::new(SQL::func(
351 "CAST",
352 expr.into_expr_sql()
353 .push(Token::AS)
354 .append(SQL::raw(target_type.cast_type_name())),
355 ))
356}
357
358#[allow(clippy::type_complexity)]
393pub fn string_concat<'a, V, L, R>(
394 left: L,
395 right: R,
396) -> SQLExpr<
397 'a,
398 V,
399 <V::DialectMarker as crate::dialect::DialectTypes>::Text,
400 <L::Nullable as NullOr<R::Nullable>>::Output,
401 <L::Aggregate as AggOr<R::Aggregate>>::Output,
402>
403where
404 V: SQLParam + 'a,
405 L: Expr<'a, V>,
406 R: Expr<'a, V>,
407 L::SQLType: Textual,
408 R::SQLType: Textual,
409 L::Nullable: NullOr<R::Nullable>,
410 R::Nullable: Nullability,
411 L::Aggregate: AggOr<R::Aggregate>,
412 R::Aggregate: AggregateKind,
413{
414 super::concat(left, right)
415}
416
417#[must_use]
441pub fn raw<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar>
442where
443 V: SQLParam + 'a,
444 T: DataType,
445{
446 SQLExpr::new(SQL::raw(sql))
447}
448
449#[must_use]
451pub fn raw_nullable<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, Null, Scalar>
452where
453 V: SQLParam + 'a,
454 T: DataType,
455{
456 SQLExpr::new(SQL::raw(sql))
457}
458
459#[must_use]
461pub fn raw_non_null<'a, V, T>(sql: &'a str) -> SQLExpr<'a, V, T, NonNull, Scalar>
462where
463 V: SQLParam + 'a,
464 T: DataType,
465{
466 SQLExpr::new(SQL::raw(sql))
467}
468
469#[derive(Clone, Copy, Debug)]
476pub struct Excluded<C> {
477 column: C,
478}
479
480pub const fn excluded<C>(column: C) -> Excluded<C> {
496 Excluded { column }
497}
498
499impl<'a, V, C> Expr<'a, V> for Excluded<C>
500where
501 V: SQLParam + 'a,
502 C: Expr<'a, V> + SQLColumnInfo,
503{
504 type SQLType = C::SQLType;
505 type Nullable = C::Nullable;
506 type Aggregate = C::Aggregate;
507}
508
509impl<'a, V, C> ToSQL<'a, V> for Excluded<C>
510where
511 V: SQLParam + 'a,
512 C: SQLColumnInfo,
513{
514 fn to_sql(&self) -> SQL<'a, V> {
515 SQL::empty()
516 .push(Token::EXCLUDED)
517 .push(Token::DOT)
518 .append(SQL::ident(self.column.name()))
519 }
520}