1use crate::dialect::DialectTypes;
15use crate::sql::{SQL, Token};
16use crate::traits::SQLParam;
17use crate::types::{DataType, Numeric, Temporal, Textual};
18use crate::{PostgresDialect, SQLiteDialect};
19use drizzle_types::postgres::types::{Timestamp as PgTimestamp, Timestamptz as PgTimestamptz};
20
21use super::{AggOr, Expr, NullOr, Nullability, SQLExpr, Scalar};
22
23#[diagnostic::on_unimplemented(
24 message = "this date/time function is not available for this dialect",
25 label = "use a dialect-specific alternative"
26)]
27pub trait SQLiteDateTimeSupport {}
28
29#[diagnostic::on_unimplemented(
30 message = "this date/time function is not available for this dialect",
31 label = "use a dialect-specific alternative"
32)]
33pub trait PostgresDateTimeSupport {}
34
35#[diagnostic::on_unimplemented(
36 message = "DATE_TRUNC output type is not defined for `{Self}` on this dialect",
37 label = "DATE_TRUNC accepts timestamp/timestamptz and preserves the timestamp flavor"
38)]
39pub trait DateTruncPolicy<D>: Temporal {
40 type Output: DataType;
41}
42
43impl SQLiteDateTimeSupport for SQLiteDialect {}
44impl PostgresDateTimeSupport for PostgresDialect {}
45
46impl DateTruncPolicy<PostgresDialect> for PgTimestamptz {
47 type Output = Self;
48}
49impl DateTruncPolicy<PostgresDialect> for PgTimestamp {
50 type Output = Self;
51}
52
53#[must_use]
72pub fn current_date<'a, V>()
73-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Date, super::NonNull, Scalar>
74where
75 V: SQLParam + 'a,
76{
77 SQLExpr::new(SQL::raw("CURRENT_DATE"))
78}
79
80#[must_use]
95pub fn current_time<'a, V>()
96-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Time, super::NonNull, Scalar>
97where
98 V: SQLParam + 'a,
99{
100 SQLExpr::new(SQL::raw("CURRENT_TIME"))
101}
102
103#[must_use]
121pub fn current_timestamp<'a, V>()
122-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::TimestampTz, super::NonNull, Scalar>
123where
124 V: SQLParam + 'a,
125{
126 SQLExpr::new(SQL::raw("CURRENT_TIMESTAMP"))
127}
128
129pub fn date<'a, V, E>(
148 expr: E,
149) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Date, E::Nullable, E::Aggregate>
150where
151 V: SQLParam + 'a,
152 V::DialectMarker: SQLiteDateTimeSupport,
153 E: Expr<'a, V>,
154 E::SQLType: Temporal,
155{
156 SQLExpr::new(SQL::func("DATE", expr.into_sql()))
157}
158
159pub fn time<'a, V, E>(
174 expr: E,
175) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Time, E::Nullable, E::Aggregate>
176where
177 V: SQLParam + 'a,
178 V::DialectMarker: SQLiteDateTimeSupport,
179 E: Expr<'a, V>,
180 E::SQLType: Temporal,
181{
182 SQLExpr::new(SQL::func("TIME", expr.into_sql()))
183}
184
185pub fn datetime<'a, V, E>(
200 expr: E,
201) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Timestamp, E::Nullable, E::Aggregate>
202where
203 V: SQLParam + 'a,
204 V::DialectMarker: SQLiteDateTimeSupport,
205 E: Expr<'a, V>,
206 E::SQLType: Temporal,
207{
208 SQLExpr::new(SQL::func("DATETIME", expr.into_sql()))
209}
210
211#[allow(clippy::type_complexity)]
238pub fn strftime<'a, V, F, E>(
239 format: F,
240 expr: E,
241) -> SQLExpr<
242 'a,
243 V,
244 <V::DialectMarker as DialectTypes>::Text,
245 E::Nullable,
246 <F::Aggregate as AggOr<E::Aggregate>>::Output,
247>
248where
249 V: SQLParam + 'a,
250 V::DialectMarker: SQLiteDateTimeSupport,
251 F: Expr<'a, V>,
252 F::SQLType: Textual,
253 E: Expr<'a, V>,
254 E::SQLType: Temporal,
255 F::Aggregate: AggOr<E::Aggregate>,
256{
257 SQLExpr::new(SQL::func(
258 "STRFTIME",
259 format.into_sql().push(Token::COMMA).append(expr.into_sql()),
260 ))
261}
262
263pub fn julianday<'a, V, E>(
278 expr: E,
279) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
280where
281 V: SQLParam + 'a,
282 V::DialectMarker: SQLiteDateTimeSupport,
283 E: Expr<'a, V>,
284 E::SQLType: Temporal,
285{
286 SQLExpr::new(SQL::func("JULIANDAY", expr.into_sql()))
287}
288
289pub fn unixepoch<'a, V, E>(
304 expr: E,
305) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::BigInt, E::Nullable, E::Aggregate>
306where
307 V: SQLParam + 'a,
308 V::DialectMarker: SQLiteDateTimeSupport,
309 E: Expr<'a, V>,
310 E::SQLType: Temporal,
311{
312 SQLExpr::new(SQL::func("UNIXEPOCH", expr.into_sql()))
313}
314
315#[must_use]
332pub fn now<'a, V>()
333-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::TimestampTz, super::NonNull, Scalar>
334where
335 V: SQLParam + 'a,
336 V::DialectMarker: PostgresDateTimeSupport,
337{
338 SQLExpr::new(SQL::raw("NOW()"))
339}
340
341#[allow(clippy::type_complexity)]
360pub fn date_trunc<'a, V, P, E>(
361 precision: P,
362 expr: E,
363) -> SQLExpr<
364 'a,
365 V,
366 <E::SQLType as DateTruncPolicy<V::DialectMarker>>::Output,
367 E::Nullable,
368 <P::Aggregate as AggOr<E::Aggregate>>::Output,
369>
370where
371 V: SQLParam + 'a,
372 V::DialectMarker: PostgresDateTimeSupport,
373 P: Expr<'a, V>,
374 P::SQLType: Textual,
375 E: Expr<'a, V>,
376 E::SQLType: DateTruncPolicy<V::DialectMarker>,
377 P::Aggregate: AggOr<E::Aggregate>,
378{
379 SQLExpr::new(SQL::func(
380 "DATE_TRUNC",
381 precision
382 .into_sql()
383 .push(Token::COMMA)
384 .append(expr.into_sql()),
385 ))
386}
387
388pub fn extract<'a, 'f, V, E>(
407 field: &'f str,
408 expr: E,
409) -> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Double, E::Nullable, E::Aggregate>
410where
411 'f: 'a,
412 V: SQLParam + 'a,
413 V::DialectMarker: PostgresDateTimeSupport,
414 E: Expr<'a, V>,
415 E::SQLType: Temporal,
416{
417 SQLExpr::new(
419 SQL::raw("EXTRACT(")
420 .append(SQL::raw(field))
421 .append(SQL::raw(" FROM "))
422 .append(expr.into_sql())
423 .push(Token::RPAREN),
424 )
425}
426
427#[allow(clippy::type_complexity)]
442pub fn age<'a, V, E1, E2>(
443 timestamp1: E1,
444 timestamp2: E2,
445) -> SQLExpr<
446 'a,
447 V,
448 drizzle_types::postgres::types::Interval,
449 <E1::Nullable as NullOr<E2::Nullable>>::Output,
450 <E1::Aggregate as AggOr<E2::Aggregate>>::Output,
451>
452where
453 V: SQLParam + 'a,
454 V::DialectMarker: PostgresDateTimeSupport,
455 E1: Expr<'a, V>,
456 E1::SQLType: Temporal,
457 E2: Expr<'a, V>,
458 E2::SQLType: Temporal,
459 E1::Nullable: NullOr<E2::Nullable>,
460 E2::Nullable: Nullability,
461 E1::Aggregate: AggOr<E2::Aggregate>,
462{
463 SQLExpr::new(SQL::func(
464 "AGE",
465 timestamp1
466 .into_sql()
467 .push(Token::COMMA)
468 .append(timestamp2.into_sql()),
469 ))
470}
471
472#[allow(clippy::type_complexity)]
498pub fn to_char<'a, V, E, F>(
499 expr: E,
500 format: F,
501) -> SQLExpr<
502 'a,
503 V,
504 <V::DialectMarker as DialectTypes>::Text,
505 E::Nullable,
506 <E::Aggregate as AggOr<F::Aggregate>>::Output,
507>
508where
509 V: SQLParam + 'a,
510 V::DialectMarker: PostgresDateTimeSupport,
511 E: Expr<'a, V>,
512 E::SQLType: Temporal,
513 F: Expr<'a, V>,
514 F::SQLType: Textual,
515 E::Aggregate: AggOr<F::Aggregate>,
516{
517 SQLExpr::new(SQL::func(
518 "TO_CHAR",
519 expr.into_sql().push(Token::COMMA).append(format.into_sql()),
520 ))
521}
522
523pub fn to_timestamp<'a, V, E>(expr: E) -> SQLExpr<'a, V, PgTimestamptz, E::Nullable, E::Aggregate>
538where
539 V: SQLParam + 'a,
540 V::DialectMarker: PostgresDateTimeSupport,
541 E: Expr<'a, V>,
542 E::SQLType: Numeric,
543{
544 SQLExpr::new(SQL::func("TO_TIMESTAMP", expr.into_sql()))
545}
546
547#[allow(clippy::type_complexity)]
566pub fn to_date<'a, V, E, F>(
567 expr: E,
568 format: F,
569) -> SQLExpr<
570 'a,
571 V,
572 <V::DialectMarker as DialectTypes>::Date,
573 E::Nullable,
574 <E::Aggregate as AggOr<F::Aggregate>>::Output,
575>
576where
577 V: SQLParam + 'a,
578 V::DialectMarker: PostgresDateTimeSupport,
579 E: Expr<'a, V>,
580 E::SQLType: Textual,
581 F: Expr<'a, V>,
582 F::SQLType: Textual,
583 E::Aggregate: AggOr<F::Aggregate>,
584{
585 SQLExpr::new(SQL::func(
586 "TO_DATE",
587 expr.into_sql().push(Token::COMMA).append(format.into_sql()),
588 ))
589}
590
591#[allow(clippy::type_complexity)]
606pub fn to_number<'a, V, E, F>(
607 expr: E,
608 format: F,
609) -> SQLExpr<
610 'a,
611 V,
612 drizzle_types::postgres::types::Numeric,
613 E::Nullable,
614 <E::Aggregate as AggOr<F::Aggregate>>::Output,
615>
616where
617 V: SQLParam + 'a,
618 V::DialectMarker: PostgresDateTimeSupport,
619 E: Expr<'a, V>,
620 E::SQLType: Textual,
621 F: Expr<'a, V>,
622 F::SQLType: Textual,
623 E::Aggregate: AggOr<F::Aggregate>,
624{
625 SQLExpr::new(SQL::func(
626 "TO_NUMBER",
627 expr.into_sql().push(Token::COMMA).append(format.into_sql()),
628 ))
629}
630
631#[allow(clippy::type_complexity)]
651pub fn date_bin<'a, V, S, E, O>(
652 stride: S,
653 source: E,
654 origin: O,
655) -> SQLExpr<
656 'a,
657 V,
658 E::SQLType,
659 <<S::Nullable as NullOr<E::Nullable>>::Output as NullOr<O::Nullable>>::Output,
660 <<S::Aggregate as AggOr<E::Aggregate>>::Output as AggOr<O::Aggregate>>::Output,
661>
662where
663 V: SQLParam + 'a,
664 V::DialectMarker: PostgresDateTimeSupport,
665 S: Expr<'a, V>,
666 E: Expr<'a, V>,
667 E::SQLType: Temporal,
668 O: Expr<'a, V>,
669 O::SQLType: Temporal,
670 S::Nullable: NullOr<E::Nullable>,
671 E::Nullable: Nullability,
672 <S::Nullable as NullOr<E::Nullable>>::Output: NullOr<O::Nullable>,
673 O::Nullable: Nullability,
674 S::Aggregate: AggOr<E::Aggregate>,
675 <S::Aggregate as AggOr<E::Aggregate>>::Output: AggOr<O::Aggregate>,
676 O::Aggregate: super::AggregateKind,
677{
678 SQLExpr::new(SQL::func(
679 "DATE_BIN",
680 stride
681 .into_sql()
682 .push(Token::COMMA)
683 .append(source.into_sql())
684 .push(Token::COMMA)
685 .append(origin.into_sql()),
686 ))
687}
688
689#[allow(clippy::type_complexity)]
706pub fn make_date<'a, V, Y, M, D>(
707 year: Y,
708 month: M,
709 day: D,
710) -> SQLExpr<
711 'a,
712 V,
713 <V::DialectMarker as DialectTypes>::Date,
714 <<Y::Nullable as NullOr<M::Nullable>>::Output as NullOr<D::Nullable>>::Output,
715 <<Y::Aggregate as AggOr<M::Aggregate>>::Output as AggOr<D::Aggregate>>::Output,
716>
717where
718 V: SQLParam + 'a,
719 V::DialectMarker: PostgresDateTimeSupport,
720 Y: Expr<'a, V>,
721 Y::SQLType: Numeric,
722 M: Expr<'a, V>,
723 M::SQLType: Numeric,
724 D: Expr<'a, V>,
725 D::SQLType: Numeric,
726 Y::Nullable: NullOr<M::Nullable>,
727 M::Nullable: Nullability,
728 <Y::Nullable as NullOr<M::Nullable>>::Output: NullOr<D::Nullable>,
729 D::Nullable: Nullability,
730 Y::Aggregate: AggOr<M::Aggregate>,
731 <Y::Aggregate as AggOr<M::Aggregate>>::Output: AggOr<D::Aggregate>,
732 D::Aggregate: super::AggregateKind,
733{
734 SQLExpr::new(SQL::func(
735 "MAKE_DATE",
736 year.into_sql()
737 .push(Token::COMMA)
738 .append(month.into_sql())
739 .push(Token::COMMA)
740 .append(day.into_sql()),
741 ))
742}
743
744#[allow(clippy::type_complexity)]
757pub fn make_timestamp<'a, V, Y, Mo, D, H, Mi, S>(
758 year: Y,
759 month: Mo,
760 day: D,
761 hour: H,
762 minute: Mi,
763 second: S,
764) -> SQLExpr<
765 'a,
766 V,
767 <V::DialectMarker as DialectTypes>::Timestamp,
768 <<<<Y::Nullable as NullOr<Mo::Nullable>>::Output as NullOr<D::Nullable>>::Output as NullOr<
769 H::Nullable,
770 >>::Output as NullOr<<Mi::Nullable as NullOr<S::Nullable>>::Output>>::Output,
771 <<<<Y::Aggregate as AggOr<Mo::Aggregate>>::Output as AggOr<D::Aggregate>>::Output as AggOr<
772 H::Aggregate,
773 >>::Output as AggOr<<Mi::Aggregate as AggOr<S::Aggregate>>::Output>>::Output,
774>
775where
776 V: SQLParam + 'a,
777 V::DialectMarker: PostgresDateTimeSupport,
778 Y: Expr<'a, V>,
779 Y::SQLType: Numeric,
780 Mo: Expr<'a, V>,
781 Mo::SQLType: Numeric,
782 D: Expr<'a, V>,
783 D::SQLType: Numeric,
784 H: Expr<'a, V>,
785 H::SQLType: Numeric,
786 Mi: Expr<'a, V>,
787 Mi::SQLType: Numeric,
788 S: Expr<'a, V>,
789 S::SQLType: Numeric,
790 Y::Nullable: NullOr<Mo::Nullable>,
791 <Y::Nullable as NullOr<Mo::Nullable>>::Output: NullOr<D::Nullable>,
792 <<Y::Nullable as NullOr<Mo::Nullable>>::Output as NullOr<D::Nullable>>::Output:
793 NullOr<H::Nullable>,
794 Mi::Nullable: NullOr<S::Nullable>,
795 <<<Y::Nullable as NullOr<Mo::Nullable>>::Output as NullOr<D::Nullable>>::Output as NullOr<
796 H::Nullable,
797 >>::Output: NullOr<<Mi::Nullable as NullOr<S::Nullable>>::Output>,
798 H::Nullable: Nullability,
799 D::Nullable: Nullability,
800 Mo::Nullable: Nullability,
801 S::Nullable: Nullability,
802 Y::Aggregate: AggOr<Mo::Aggregate>,
803 <Y::Aggregate as AggOr<Mo::Aggregate>>::Output: AggOr<D::Aggregate>,
804 <<Y::Aggregate as AggOr<Mo::Aggregate>>::Output as AggOr<D::Aggregate>>::Output:
805 AggOr<H::Aggregate>,
806 Mi::Aggregate: AggOr<S::Aggregate>,
807 <<<Y::Aggregate as AggOr<Mo::Aggregate>>::Output as AggOr<D::Aggregate>>::Output as AggOr<
808 H::Aggregate,
809 >>::Output: AggOr<<Mi::Aggregate as AggOr<S::Aggregate>>::Output>,
810 H::Aggregate: super::AggregateKind,
811 D::Aggregate: super::AggregateKind,
812 S::Aggregate: super::AggregateKind,
813{
814 SQLExpr::new(SQL::func(
815 "MAKE_TIMESTAMP",
816 year.into_sql()
817 .push(Token::COMMA)
818 .append(month.into_sql())
819 .push(Token::COMMA)
820 .append(day.into_sql())
821 .push(Token::COMMA)
822 .append(hour.into_sql())
823 .push(Token::COMMA)
824 .append(minute.into_sql())
825 .push(Token::COMMA)
826 .append(second.into_sql()),
827 ))
828}
829
830#[must_use]
847pub fn localtime<'a, V>()
848-> SQLExpr<'a, V, <V::DialectMarker as DialectTypes>::Time, super::NonNull, Scalar>
849where
850 V: SQLParam + 'a,
851 V::DialectMarker: PostgresDateTimeSupport,
852{
853 SQLExpr::new(SQL::raw("LOCALTIME"))
854}
855
856#[must_use]
869pub fn localtimestamp<'a, V>() -> SQLExpr<'a, V, PgTimestamp, super::NonNull, Scalar>
870where
871 V: SQLParam + 'a,
872 V::DialectMarker: PostgresDateTimeSupport,
873{
874 SQLExpr::new(SQL::raw("LOCALTIMESTAMP"))
875}
876
877#[must_use]
892pub fn clock_timestamp<'a, V>() -> SQLExpr<'a, V, PgTimestamptz, super::NonNull, Scalar>
893where
894 V: SQLParam + 'a,
895 V::DialectMarker: PostgresDateTimeSupport,
896{
897 SQLExpr::new(SQL::raw("CLOCK_TIMESTAMP()"))
898}
899
900#[allow(clippy::type_complexity)]
919pub fn timediff<'a, V, E1, E2>(
920 time1: E1,
921 time2: E2,
922) -> SQLExpr<
923 'a,
924 V,
925 <V::DialectMarker as DialectTypes>::Text,
926 <E1::Nullable as NullOr<E2::Nullable>>::Output,
927 <E1::Aggregate as AggOr<E2::Aggregate>>::Output,
928>
929where
930 V: SQLParam + 'a,
931 V::DialectMarker: SQLiteDateTimeSupport,
932 E1: Expr<'a, V>,
933 E1::SQLType: Temporal,
934 E2: Expr<'a, V>,
935 E2::SQLType: Temporal,
936 E1::Nullable: NullOr<E2::Nullable>,
937 E2::Nullable: Nullability,
938 E1::Aggregate: AggOr<E2::Aggregate>,
939{
940 SQLExpr::new(SQL::func(
941 "TIMEDIFF",
942 time1.into_sql().push(Token::COMMA).append(time2.into_sql()),
943 ))
944}