1use std::marker::PhantomData;
10
11use crate::scope::{Concat, Cons, MaybeNull, Nil, Table, WrapNullable};
12
13mod sql_type {
14 pub trait Sealed {}
19}
20
21pub trait SqlType: 'static + sql_type::Sealed {
24 type Native;
25}
26
27#[derive(Debug, Clone)]
31pub(crate) enum ExprKind {
32 Column {
33 table: &'static str,
34 name: &'static str,
35 },
36 Excluded {
39 name: &'static str,
40 },
41 Value(Value),
42 BinOp {
43 op: BinOp,
44 lhs: Box<ExprKind>,
45 rhs: Box<ExprKind>,
46 },
47 And(Box<ExprKind>, Box<ExprKind>),
48 Or(Box<ExprKind>, Box<ExprKind>),
49 Always(bool),
52 Not(Box<ExprKind>),
53 IsNull {
56 expr: Box<ExprKind>,
57 negated: bool,
58 },
59 InList {
62 expr: Box<ExprKind>,
63 values: Vec<ExprKind>,
64 },
65 EqAny {
69 expr: Box<ExprKind>,
70 array: Box<ExprKind>,
71 },
72 Exists {
76 body: Box<crate::select::SelectBody>,
77 selection: Vec<crate::render::SelectItem>,
78 negated: bool,
79 },
80 InSubquery {
85 lhs: Box<ExprKind>,
86 body: Box<crate::select::SelectBody>,
87 selection: Vec<crate::render::SelectItem>,
88 negated: bool,
89 },
90 Template {
95 head: String,
96 rest: Vec<(ExprKind, String)>,
97 },
98 Cast {
102 expr: Box<ExprKind>,
103 target: CastTarget,
104 },
105 Func {
111 name: &'static str,
112 arg: Option<Box<ExprKind>>,
113 },
114 StringAgg {
122 arg: Box<ExprKind>,
123 separator: &'static str,
124 },
125 Window {
131 func: &'static str,
132 partition_by: Vec<ExprKind>,
133 order_by: Vec<(ExprKind, SortDir)>,
134 },
135}
136
137#[derive(Debug, Clone, Copy, PartialEq, Eq)]
141pub enum SortDir {
142 Asc,
143 Desc,
144}
145
146#[doc(hidden)]
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub enum CastTarget {
151 BigInt,
152 Double,
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub enum BinOp {
157 Eq,
158 Ne,
159 Lt,
160 Lte,
161 Gt,
162 Gte,
163 Like,
164}
165
166#[derive(Debug, Clone, PartialEq)]
171pub enum Value {
172 I32(i32),
173 I64(i64),
174 F64(f64),
175 Text(String),
176 Bool(bool),
177 Bytes(Vec<u8>),
178 NullI32,
184 NullI64,
185 NullF64,
186 NullText,
187 NullBool,
188 NullBytes,
189 #[cfg(feature = "chrono")]
190 Timestamptz(chrono::DateTime<chrono::Utc>),
191 #[cfg(feature = "chrono")]
192 NullTimestamptz,
193 #[cfg(feature = "chrono")]
194 Date(chrono::NaiveDate),
195 #[cfg(feature = "chrono")]
196 NullDate,
197 #[cfg(feature = "uuid")]
198 Uuid(uuid::Uuid),
199 #[cfg(feature = "uuid")]
200 NullUuid,
201 #[cfg(feature = "decimal")]
202 Numeric(rust_decimal::Decimal),
203 #[cfg(feature = "decimal")]
204 NullNumeric,
205 TextArray(Vec<String>),
208 NullTextArray,
209 IntegerArray(Vec<i32>),
210 NullIntegerArray,
211 BigIntArray(Vec<i64>),
212 NullBigIntArray,
213 #[cfg(feature = "uuid")]
214 UuidArray(Vec<uuid::Uuid>),
215 #[cfg(feature = "uuid")]
216 NullUuidArray,
217 #[cfg(feature = "json")]
220 Json(serde_json::Value),
221 #[cfg(feature = "json")]
222 NullJson,
223 Placeholder(&'static str),
229}
230
231#[cfg(feature = "json")]
237fn json_as_written(value: &serde_json::Value) -> String {
238 value.to_string()
239}
240
241impl Value {
242 pub fn type_name(&self) -> &'static str {
246 match self {
247 Value::I32(_) | Value::NullI32 => "Integer",
248 Value::I64(_) | Value::NullI64 => "BigInt",
249 Value::F64(_) | Value::NullF64 => "Real",
250 Value::Text(_) | Value::NullText => "Text",
251 Value::Bool(_) | Value::NullBool => "Bool",
252 Value::Bytes(_) | Value::NullBytes => "Bytes",
253 Value::TextArray(_) | Value::NullTextArray => "TextArray",
254 Value::IntegerArray(_) | Value::NullIntegerArray => "IntegerArray",
255 Value::BigIntArray(_) | Value::NullBigIntArray => "BigIntArray",
256 #[cfg(feature = "uuid")]
257 Value::UuidArray(_) | Value::NullUuidArray => "UuidArray",
258 #[cfg(feature = "json")]
259 Value::Json(_) | Value::NullJson => "Json",
260 Value::Placeholder(_) => "placeholder",
261 #[cfg(feature = "chrono")]
262 Value::Timestamptz(_) | Value::NullTimestamptz => "Timestamptz",
263 #[cfg(feature = "chrono")]
264 Value::Date(_) | Value::NullDate => "Date",
265 #[cfg(feature = "uuid")]
266 Value::Uuid(_) | Value::NullUuid => "Uuid",
267 #[cfg(feature = "decimal")]
268 Value::Numeric(_) | Value::NullNumeric => "Numeric",
269 }
270 }
271
272 pub(crate) fn binds_same_as(&self, other: &Value) -> bool {
280 match (self, other) {
281 (Value::F64(a), Value::F64(b)) => a.to_bits() == b.to_bits(),
282 #[cfg(feature = "decimal")]
283 (Value::Numeric(a), Value::Numeric(b)) => a.serialize() == b.serialize(),
284 #[cfg(feature = "json")]
285 (Value::Json(a), Value::Json(b)) => json_as_written(a) == json_as_written(b),
286 _ => self == other,
287 }
288 }
289
290 pub(crate) fn hash_into<H: std::hash::Hasher>(&self, hasher: &mut H) {
298 use std::hash::Hash as _;
299 std::mem::discriminant(self).hash(hasher);
300 match self {
301 Value::I32(v) => v.hash(hasher),
302 Value::I64(v) => v.hash(hasher),
303 Value::F64(v) => v.to_bits().hash(hasher),
304 Value::Text(v) => v.hash(hasher),
305 Value::Bool(v) => v.hash(hasher),
306 Value::Bytes(v) => v.hash(hasher),
307 Value::Placeholder(v) => v.hash(hasher),
308 Value::TextArray(v) => v.hash(hasher),
309 Value::IntegerArray(v) => v.hash(hasher),
310 Value::BigIntArray(v) => v.hash(hasher),
311 #[cfg(feature = "uuid")]
312 Value::UuidArray(v) => v.hash(hasher),
313 #[cfg(feature = "json")]
314 Value::Json(v) => json_as_written(v).hash(hasher),
315 #[cfg(feature = "chrono")]
316 Value::Timestamptz(v) => v.hash(hasher),
317 #[cfg(feature = "chrono")]
318 Value::Date(v) => v.hash(hasher),
319 #[cfg(feature = "uuid")]
320 Value::Uuid(v) => v.hash(hasher),
321 #[cfg(feature = "decimal")]
322 Value::Numeric(v) => v.serialize().hash(hasher),
323 Value::NullI32
324 | Value::NullI64
325 | Value::NullF64
326 | Value::NullText
327 | Value::NullBool
328 | Value::NullBytes
329 | Value::NullTextArray
330 | Value::NullIntegerArray
331 | Value::NullBigIntArray => {}
332 #[cfg(feature = "uuid")]
333 Value::NullUuidArray => {}
334 #[cfg(feature = "json")]
335 Value::NullJson => {}
336 #[cfg(feature = "chrono")]
337 Value::NullTimestamptz | Value::NullDate => {}
338 #[cfg(feature = "uuid")]
339 Value::NullUuid => {}
340 #[cfg(feature = "decimal")]
341 Value::NullNumeric => {}
342 }
343 }
344}
345
346macro_rules! value_from {
347 ($ty:ty, $variant:ident) => {
348 impl From<$ty> for Value {
349 fn from(v: $ty) -> Self {
350 Value::$variant(v)
351 }
352 }
353 };
354}
355value_from!(i32, I32);
356value_from!(i64, I64);
357value_from!(f64, F64);
358value_from!(String, Text);
359value_from!(bool, Bool);
360value_from!(Vec<u8>, Bytes);
361#[cfg(feature = "chrono")]
362value_from!(chrono::DateTime<chrono::Utc>, Timestamptz);
363#[cfg(feature = "chrono")]
364value_from!(chrono::NaiveDate, Date);
365#[cfg(feature = "uuid")]
366value_from!(uuid::Uuid, Uuid);
367#[cfg(feature = "decimal")]
368value_from!(rust_decimal::Decimal, Numeric);
369value_from!(Vec<String>, TextArray);
370value_from!(Vec<i32>, IntegerArray);
371value_from!(Vec<i64>, BigIntArray);
372#[cfg(feature = "uuid")]
373value_from!(Vec<uuid::Uuid>, UuidArray);
374#[cfg(feature = "json")]
375value_from!(serde_json::Value, Json);
376
377impl From<&str> for Value {
378 fn from(v: &str) -> Self {
379 Value::Text(v.to_string())
380 }
381}
382
383pub struct Expr<Req, S: SqlType> {
390 pub(crate) kind: ExprKind,
391 _marker: PhantomData<fn() -> (Req, S)>,
392}
393
394impl<Req, S: SqlType> Expr<Req, S> {
395 pub(crate) fn from_kind(kind: ExprKind) -> Self {
396 Expr {
397 kind,
398 _marker: PhantomData,
399 }
400 }
401}
402
403impl<Req, S: SqlType> Clone for Expr<Req, S> {
406 fn clone(&self) -> Self {
407 Expr::from_kind(self.kind.clone())
408 }
409}
410
411#[diagnostic::on_unimplemented(
415 message = "`{Self}` isn't a SQL expression",
416 label = "a column, a literal, an aggregate, or a `sql!{{}}` fragment is; a `label!` name is not",
417 note = "an `Option` isn't one either: asking about NULL is `.is_null()`, since `= NULL` is never true in SQL, and assigning it is `null::<Text>()`"
418)]
419pub trait IntoExpr {
420 type Sql: SqlType;
426 type Req;
427 fn into_expr(self) -> Expr<Self::Req, Self::Sql>;
428}
429
430impl<Req, S: SqlType> IntoExpr for Expr<Req, S> {
431 type Sql = S;
432 type Req = Req;
433 fn into_expr(self) -> Expr<Req, S> {
434 self
435 }
436}
437
438#[diagnostic::on_unimplemented(
444 message = "a `{Self}` expression can't be assigned to a `{Column}` column",
445 label = "the value has to fit the column: the same type, a narrower number, or a non-null value for a nullable column"
446)]
447pub trait AssignsTo<Column: SqlType>: SqlType {}
448
449impl<T: SqlType> AssignsTo<T> for T {}
450impl<T: SqlType> AssignsTo<crate::scope::Nullable<T>> for T {}
451
452mod writable {
453 pub trait Sealed {}
457}
458
459#[doc(hidden)]
460pub use writable::Sealed as WritableSealed;
461
462#[diagnostic::on_unimplemented(
466 message = "`{Self}` isn't a column a statement can assign to",
467 label = "a primary-key or generated column is the database's to write, which is why `*Update` leaves it out too"
468)]
469pub trait Writable: WritableSealed {}
470
471pub trait ColumnKey: crate::row::Spelled + Copy + 'static {
477 type Table: Table;
478 type Sql: SqlType;
479}
480
481pub struct Column<C: ColumnKey>(PhantomData<C>);
488
489impl<C: ColumnKey> Column<C> {
490 pub const fn new() -> Self {
491 Column(PhantomData)
492 }
493}
494
495impl<C: ColumnKey> Default for Column<C> {
496 fn default() -> Self {
497 Self::new()
498 }
499}
500
501impl<C: ColumnKey> Clone for Column<C> {
502 fn clone(&self) -> Self {
503 *self
504 }
505}
506impl<C: ColumnKey> Copy for Column<C> {}
507
508impl<C: ColumnKey> IntoExpr for Column<C> {
509 type Sql = C::Sql;
510 type Req = Cons<C::Table, Nil>;
511 fn into_expr(self) -> Expr<Self::Req, C::Sql> {
512 Expr::from_kind(ExprKind::Column {
513 table: <C::Table as Table>::NAME,
514 name: <C as crate::row::Named>::NAME,
515 })
516 }
517}
518
519pub struct Keyed<K, Req, S: SqlType> {
524 pub(crate) kind: ExprKind,
525 _marker: PhantomData<fn() -> (K, Req, S)>,
526}
527
528impl<K, Req, S: SqlType> Keyed<K, Req, S> {
529 pub(crate) fn from_kind(kind: ExprKind) -> Self {
530 Keyed {
531 kind,
532 _marker: PhantomData,
533 }
534 }
535}
536
537impl<K, Req, S: SqlType> Clone for Keyed<K, Req, S> {
538 fn clone(&self) -> Self {
539 Keyed::from_kind(self.kind.clone())
540 }
541}
542
543impl<K, Req, S: SqlType> IntoExpr for Keyed<K, Req, S> {
544 type Sql = S;
545 type Req = Req;
546 fn into_expr(self) -> Expr<Req, S> {
547 Expr::from_kind(self.kind)
548 }
549}
550
551#[diagnostic::on_unimplemented(
559 message = "`{Self}` and `{Other}` aren't comparable",
560 label = "both sides of a comparison must be the same SQL type, or two numeric ones",
561 note = "nullability doesn't matter here: a `Nullable<T>` compares with a `T`",
562 note = "an unannotated `vec![1, 2]` is an `integer[]`, since that is what an integer literal defaults to; a `bytea` takes `vec![1u8, 2]`"
563)]
564pub trait Comparable<Other: SqlType>: SqlType {}
565
566impl<T: SqlType> Comparable<T> for T {}
567impl<T: SqlType> Comparable<crate::scope::Nullable<T>> for T {}
568impl<T: SqlType> Comparable<T> for crate::scope::Nullable<T> {}
569
570macro_rules! comparable_across {
573 ($($a:ty => $b:ty),+ $(,)?) => {
574 $(
575 impl Comparable<$b> for $a {}
576 impl Comparable<$b> for crate::scope::Nullable<$a> {}
577 impl Comparable<crate::scope::Nullable<$b>> for $a {}
578 impl Comparable<crate::scope::Nullable<$b>> for crate::scope::Nullable<$a> {}
579 )+
580 };
581}
582comparable_across!(
583 Integer => BigInt,
584 BigInt => Integer,
585 Integer => Real,
586 Real => Integer,
587 BigInt => Real,
588 Real => BigInt,
589);
590
591#[diagnostic::on_unimplemented(
601 message = "`{Self}` isn't an array of `{Element}`",
602 label = "the right side of `= ANY(..)` is an array whose elements are the left side's type",
603 note = "nullability doesn't matter here, on either side"
604)]
605pub trait ArrayOf<Element: SqlType>: SqlType {}
606
607macro_rules! array_of {
608 ($($array:ty => $element:ty),+ $(,)?) => {
609 $(
610 impl ArrayOf<$element> for $array {}
611 impl ArrayOf<$element> for crate::scope::Nullable<$array> {}
612 impl ArrayOf<crate::scope::Nullable<$element>> for $array {}
613 impl ArrayOf<crate::scope::Nullable<$element>> for crate::scope::Nullable<$array> {}
614 )+
615 };
616}
617array_of!(
618 TextArray => Text,
619 IntegerArray => Integer,
620 BigIntArray => BigInt,
621);
622#[cfg(feature = "uuid")]
623array_of!(UuidArray => Uuid);
624
625macro_rules! assigns_across {
626 ($($from:ty => $to:ty),+ $(,)?) => {
627 $(
628 impl AssignsTo<$to> for $from {}
629 impl AssignsTo<crate::scope::Nullable<$to>> for $from {}
630 impl AssignsTo<crate::scope::Nullable<$to>> for crate::scope::Nullable<$from> {}
631 )+
632 };
633}
634assigns_across!(
637 Integer => BigInt,
638 Integer => Real,
639 BigInt => Real,
640);
641
642#[cfg(feature = "decimal")]
643assigns_across!(
644 Integer => Numeric,
645 BigInt => Numeric,
646 Real => Numeric,
647);
648
649#[cfg(feature = "decimal")]
653comparable_across!(
654 Numeric => Integer,
655 Integer => Numeric,
656 Numeric => BigInt,
657 BigInt => Numeric,
658 Numeric => Real,
659 Real => Numeric,
660);
661
662pub trait LabelKey: crate::row::Spelled + Copy + 'static {}
666
667pub type Declared<Req, S> = Keyed<crate::row::Anon, Req, S>;
673
674impl<Req, S: SqlType> Expr<Req, S> {
675 pub fn decodes_as<S2: SqlType>(self) -> Declared<Req, S2> {
679 Keyed {
680 kind: self.kind,
681 _marker: PhantomData,
682 }
683 }
684}
685
686pub struct Labeled<K, Inner> {
689 pub(crate) inner: Inner,
690 _key: PhantomData<fn() -> K>,
691}
692
693impl<K, Inner: Clone> Clone for Labeled<K, Inner> {
694 fn clone(&self) -> Self {
695 Labeled::new(self.inner.clone())
696 }
697}
698
699impl<K, Inner> Labeled<K, Inner> {
700 pub(crate) fn new(inner: Inner) -> Self {
701 Labeled {
702 inner,
703 _key: PhantomData,
704 }
705 }
706}
707
708pub trait LabelExt: Sized {
712 fn label<K: LabelKey>(self, _key: K) -> Labeled<K, Self> {
713 Labeled::new(self)
714 }
715}
716impl<C: ColumnKey> LabelExt for Column<C> {}
717impl<K, Req, S: SqlType> LabelExt for Keyed<K, Req, S> {}
718impl<Req, S: SqlType> LabelExt for Expr<Req, S> {}
723
724#[allow(clippy::wrong_self_convention)]
731pub trait ExprMethods: IntoExpr + Sized {
732 fn eq<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
733 where
734 Self::Sql: Comparable<Rhs::Sql>,
735 Self::Req: Concat<Rhs::Req>,
736 {
737 bin_op(BinOp::Eq, self, rhs)
738 }
739
740 fn ne<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
741 where
742 Self::Sql: Comparable<Rhs::Sql>,
743 Self::Req: Concat<Rhs::Req>,
744 {
745 bin_op(BinOp::Ne, self, rhs)
746 }
747
748 fn lt<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
749 where
750 Self::Sql: Comparable<Rhs::Sql>,
751 Self::Req: Concat<Rhs::Req>,
752 {
753 bin_op(BinOp::Lt, self, rhs)
754 }
755
756 fn lte<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
757 where
758 Self::Sql: Comparable<Rhs::Sql>,
759 Self::Req: Concat<Rhs::Req>,
760 {
761 bin_op(BinOp::Lte, self, rhs)
762 }
763
764 fn gt<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
765 where
766 Self::Sql: Comparable<Rhs::Sql>,
767 Self::Req: Concat<Rhs::Req>,
768 {
769 bin_op(BinOp::Gt, self, rhs)
770 }
771
772 fn gte<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
773 where
774 Self::Sql: Comparable<Rhs::Sql>,
775 Self::Req: Concat<Rhs::Req>,
776 {
777 bin_op(BinOp::Gte, self, rhs)
778 }
779
780 fn is_null(self) -> Expr<Self::Req, Bool> {
783 Expr::from_kind(ExprKind::IsNull {
784 expr: Box::new(self.into_expr().kind),
785 negated: false,
786 })
787 }
788
789 fn is_not_null(self) -> Expr<Self::Req, Bool> {
790 Expr::from_kind(ExprKind::IsNull {
791 expr: Box::new(self.into_expr().kind),
792 negated: true,
793 })
794 }
795
796 fn and<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
801 where
802 Self::Sql: BoolLike,
803 Rhs::Sql: BoolLike,
804 Self::Req: Concat<Rhs::Req>,
805 {
806 Expr::from_kind(ExprKind::And(
807 Box::new(self.into_expr().kind),
808 Box::new(rhs.into_expr().kind),
809 ))
810 }
811
812 fn or<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
814 where
815 Self::Sql: BoolLike,
816 Rhs::Sql: BoolLike,
817 Self::Req: Concat<Rhs::Req>,
818 {
819 Expr::from_kind(ExprKind::Or(
820 Box::new(self.into_expr().kind),
821 Box::new(rhs.into_expr().kind),
822 ))
823 }
824
825 fn like<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
829 where
830 Self::Sql: TextLike,
831 Rhs::Sql: TextLike,
832 Self::Req: Concat<Rhs::Req>,
833 {
834 bin_op(BinOp::Like, self, rhs)
835 }
836
837 fn is_in<I>(self, values: I) -> Expr<Self::Req, Bool>
844 where
845 I: IntoIterator,
846 I::Item: IntoExpr<Req = Nil>,
847 Self::Sql: Comparable<<I::Item as IntoExpr>::Sql>,
848 {
849 let values: Vec<ExprKind> = values.into_iter().map(|v| v.into_expr().kind).collect();
850 if values.is_empty() {
852 return Expr::from_kind(ExprKind::Always(false));
853 }
854 Expr::from_kind(ExprKind::InList {
855 expr: Box::new(self.into_expr().kind),
856 values,
857 })
858 }
859
860 fn eq_any<Rhs: IntoExpr>(
869 self,
870 array: Rhs,
871 ) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
872 where
873 Rhs::Sql: ArrayOf<Self::Sql>,
874 Self::Req: Concat<Rhs::Req>,
875 {
876 Expr::from_kind(ExprKind::EqAny {
877 expr: Box::new(self.into_expr().kind),
878 array: Box::new(array.into_expr().kind),
879 })
880 }
881}
882
883pub fn any_of<Req, C: IntoExpr<Req = Req>>(conds: impl IntoIterator<Item = C>) -> Expr<Req, Bool>
889where
890 C::Sql: BoolLike,
891{
892 combine(conds, false)
893}
894
895pub fn all_of<Req, C: IntoExpr<Req = Req>>(conds: impl IntoIterator<Item = C>) -> Expr<Req, Bool>
898where
899 C::Sql: BoolLike,
900{
901 combine(conds, true)
902}
903
904fn combine<Req, C: IntoExpr<Req = Req>>(
905 conds: impl IntoIterator<Item = C>,
906 all: bool,
907) -> Expr<Req, Bool>
908where
909 C::Sql: BoolLike,
910{
911 Expr::from_kind(fold_conditions(
912 conds.into_iter().map(|c| c.into_expr().kind),
913 all,
914 ))
915}
916
917pub(crate) fn fold_conditions(kinds: impl IntoIterator<Item = ExprKind>, all: bool) -> ExprKind {
922 let mut folded: Option<ExprKind> = None;
923 for kind in kinds {
924 folded = Some(match folded {
925 None => kind,
926 Some(acc) if all => ExprKind::And(Box::new(acc), Box::new(kind)),
927 Some(acc) => ExprKind::Or(Box::new(acc), Box::new(kind)),
928 });
929 }
930 folded.unwrap_or(ExprKind::Always(all))
931}
932
933impl<T: IntoExpr> ExprMethods for T {}
934
935fn bin_op<Lhs, Rhs>(
936 op: BinOp,
937 lhs: Lhs,
938 rhs: Rhs,
939) -> Expr<<Lhs::Req as Concat<Rhs::Req>>::Output, Bool>
940where
941 Lhs: IntoExpr,
942 Rhs: IntoExpr,
943 Lhs::Req: Concat<Rhs::Req>,
944{
945 Expr::from_kind(ExprKind::BinOp {
946 op,
947 lhs: Box::new(lhs.into_expr().kind),
948 rhs: Box::new(rhs.into_expr().kind),
949 })
950}
951
952#[diagnostic::on_unimplemented(
956 message = "`LIKE` needs a text expression, and `{Self}` isn't one",
957 label = "only `Text` and `Nullable<Text>` columns and expressions accept `.like(..)`"
958)]
959pub trait TextLike: SqlType {}
960
961impl TextLike for Text {}
962impl TextLike for crate::scope::Nullable<Text> {}
963
964#[diagnostic::on_unimplemented(
968 message = "a condition has to be a boolean expression, and `{Self}` isn't one",
969 label = "expected `Bool` or `Nullable<Bool>`"
970)]
971pub trait BoolLike: SqlType {}
972
973impl BoolLike for Bool {}
974impl BoolLike for crate::scope::Nullable<Bool> {}
975
976impl<Req, S: BoolLike> std::ops::Not for Expr<Req, S> {
982 type Output = Expr<Req, S>;
983 fn not(self) -> Self::Output {
984 Expr::from_kind(ExprKind::Not(Box::new(self.kind)))
985 }
986}
987
988impl<K, Req, S: BoolLike> std::ops::Not for Keyed<K, Req, S> {
989 type Output = Keyed<K, Req, S>;
990 fn not(self) -> Self::Output {
991 Keyed::from_kind(ExprKind::Not(Box::new(self.kind)))
992 }
993}
994
995impl<C: ColumnKey> std::ops::Not for Column<C>
996where
997 C::Sql: BoolLike,
998{
999 type Output = Expr<Cons<C::Table, Nil>, C::Sql>;
1000 fn not(self) -> Self::Output {
1001 Expr::from_kind(ExprKind::Not(Box::new(self.into_expr().kind)))
1002 }
1003}
1004
1005pub trait NullValue: SqlType {
1008 const NULL_VALUE: Value;
1009}
1010
1011pub fn null<S: NullValue>() -> Expr<Nil, crate::scope::Nullable<S>> {
1016 Expr::from_kind(ExprKind::Value(S::NULL_VALUE))
1017}
1018
1019mod raw_arg {
1025 pub trait Sealed {}
1030 impl<T: super::IntoExpr> Sealed for T {}
1031}
1032
1033macro_rules! sql_leaf_type {
1034 ($name:ident, $native:ty, $null_variant:ident) => {
1037 pub struct $name;
1038
1039 sql_leaf_type!(@of $name, $native, $null_variant);
1040 };
1041 (native $native:ty, $null_variant:ident) => {
1047 sql_leaf_type!(@of $native, $native, $null_variant);
1048 };
1049 (@of $name:ty, $native:ty, $null_variant:ident) => {
1050 impl sql_type::Sealed for $name {}
1051
1052 impl SqlType for $name {
1053 type Native = $native;
1054 }
1055
1056 impl crate::scope::wrap::Sealed<MaybeNull> for $name {}
1057
1058 impl crate::scope::WrapNullable<MaybeNull> for $name {
1059 type Output = crate::scope::Nullable<$name>;
1060 }
1061
1062 impl IntoExpr for $native {
1063 type Sql = $name;
1064 type Req = Nil;
1065 fn into_expr(self) -> Expr<Nil, $name> {
1066 Expr::from_kind(ExprKind::Value(Value::from(self)))
1067 }
1068 }
1069
1070 impl crate::select::SingleColumn for $native {}
1071 impl crate::select::SingleColumn for ::std::option::Option<$native> {}
1072
1073 impl NullValue for $name {
1074 const NULL_VALUE: Value = Value::$null_variant;
1075 }
1076
1077 impl crate::insert::IntoColumnValue<$native> for $native {
1078 fn into_column_value(self) -> $native {
1079 self
1080 }
1081 }
1082
1083 impl crate::insert::IntoColumnValue<::std::option::Option<$native>> for $native {
1084 fn into_column_value(self) -> ::std::option::Option<$native> {
1085 ::std::option::Option::Some(self)
1086 }
1087 }
1088
1089 impl crate::insert::IntoColumnValue<::std::option::Option<$native>>
1090 for ::std::option::Option<$native>
1091 {
1092 fn into_column_value(self) -> ::std::option::Option<$native> {
1093 self
1094 }
1095 }
1096
1097 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<$native>> for $native {
1098 fn into_column_value(self) -> crate::insert::Defaultable<$native> {
1099 crate::insert::Defaultable::Value(self)
1100 }
1101 }
1102
1103 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<$native>>
1104 for ::std::option::Option<$native>
1105 {
1106 fn into_column_value(self) -> crate::insert::Defaultable<$native> {
1107 match self {
1108 ::std::option::Option::Some(v) => crate::insert::Defaultable::Value(v),
1109 ::std::option::Option::None => crate::insert::Defaultable::Default,
1110 }
1111 }
1112 }
1113
1114 impl
1115 crate::insert::IntoColumnValue<
1116 crate::insert::Defaultable<::std::option::Option<$native>>,
1117 > for $native
1118 {
1119 fn into_column_value(
1120 self,
1121 ) -> crate::insert::Defaultable<::std::option::Option<$native>> {
1122 crate::insert::Defaultable::Value(::std::option::Option::Some(self))
1123 }
1124 }
1125
1126 impl
1127 crate::insert::IntoColumnValue<
1128 crate::insert::Defaultable<::std::option::Option<$native>>,
1129 > for ::std::option::Option<$native>
1130 {
1131 fn into_column_value(
1132 self,
1133 ) -> crate::insert::Defaultable<::std::option::Option<$native>> {
1134 match self {
1135 ::std::option::Option::Some(v) => {
1136 crate::insert::Defaultable::Value(::std::option::Option::Some(v))
1137 }
1138 ::std::option::Option::None => crate::insert::Defaultable::Default,
1139 }
1140 }
1141 }
1142
1143 impl raw_arg::Sealed for ::std::option::Option<$native> {}
1144
1145 impl RawArg for ::std::option::Option<$native> {
1146 type Req = Nil;
1147 fn into_raw_arg(self) -> RawSlot {
1148 RawSlot(ExprKind::Value(Value::from(self)))
1149 }
1150 }
1151
1152 impl crate::row::SameShape<$native> for $native {}
1153 impl crate::row::SameShape<::std::option::Option<$native>>
1154 for ::std::option::Option<$native>
1155 {
1156 }
1157
1158 impl From<::std::option::Option<$native>> for Value {
1161 fn from(v: ::std::option::Option<$native>) -> Self {
1162 match v {
1163 ::std::option::Option::Some(x) => Value::from(x),
1164 ::std::option::Option::None => Value::$null_variant,
1165 }
1166 }
1167 }
1168 };
1169}
1170
1171sql_leaf_type!(Integer, i32, NullI32);
1172sql_leaf_type!(BigInt, i64, NullI64);
1173sql_leaf_type!(Real, f64, NullF64);
1174sql_leaf_type!(Text, String, NullText);
1175sql_leaf_type!(Bool, bool, NullBool);
1176sql_leaf_type!(Bytes, Vec<u8>, NullBytes);
1177
1178sql_leaf_type!(TextArray, Vec<String>, NullTextArray);
1188sql_leaf_type!(IntegerArray, Vec<i32>, NullIntegerArray);
1189sql_leaf_type!(BigIntArray, Vec<i64>, NullBigIntArray);
1190#[cfg(feature = "uuid")]
1191sql_leaf_type!(UuidArray, Vec<uuid::Uuid>, NullUuidArray);
1192
1193#[cfg(feature = "json")]
1204sql_leaf_type!(Json, serde_json::Value, NullJson);
1205
1206#[cfg(feature = "chrono")]
1210sql_leaf_type!(Timestamptz, chrono::DateTime<chrono::Utc>, NullTimestamptz);
1211#[cfg(feature = "chrono")]
1212sql_leaf_type!(Date, chrono::NaiveDate, NullDate);
1213#[cfg(feature = "uuid")]
1214pub use uuid::Uuid;
1215#[cfg(feature = "uuid")]
1216sql_leaf_type!(native uuid::Uuid, NullUuid);
1217#[cfg(feature = "decimal")]
1218sql_leaf_type!(Numeric, rust_decimal::Decimal, NullNumeric);
1219
1220impl IntoExpr for &String {
1223 type Sql = Text;
1224 type Req = Nil;
1225 fn into_expr(self) -> Expr<Nil, Text> {
1226 Expr::from_kind(ExprKind::Value(Value::Text(self.clone())))
1227 }
1228}
1229
1230impl IntoExpr for &str {
1231 type Sql = Text;
1232 type Req = Nil;
1233 fn into_expr(self) -> Expr<Nil, Text> {
1234 Expr::from_kind(ExprKind::Value(Value::Text(self.to_string())))
1235 }
1236}
1237
1238macro_rules! text_column_value {
1241 ($borrowed:ty) => {
1242 impl crate::insert::IntoColumnValue<String> for $borrowed {
1243 fn into_column_value(self) -> String {
1244 self.to_string()
1245 }
1246 }
1247
1248 impl crate::insert::IntoColumnValue<Option<String>> for $borrowed {
1249 fn into_column_value(self) -> Option<String> {
1250 Some(self.to_string())
1251 }
1252 }
1253
1254 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<String>> for $borrowed {
1255 fn into_column_value(self) -> crate::insert::Defaultable<String> {
1256 crate::insert::Defaultable::Value(self.to_string())
1257 }
1258 }
1259
1260 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<Option<String>>>
1261 for $borrowed
1262 {
1263 fn into_column_value(self) -> crate::insert::Defaultable<Option<String>> {
1264 crate::insert::Defaultable::Value(Some(self.to_string()))
1265 }
1266 }
1267 };
1268}
1269
1270text_column_value!(&str);
1271text_column_value!(&String);
1272
1273impl<S: SqlType> sql_type::Sealed for crate::scope::Nullable<S> {}
1274
1275impl<S: SqlType> SqlType for crate::scope::Nullable<S> {
1276 type Native = Option<S::Native>;
1277}
1278
1279crate::row::expr_key!(
1280 Count,
1281 HasCount,
1282 count,
1283 "The identity a selected `count(*)` is filed under in a row.",
1284 'c',
1285 'o',
1286 'u',
1287 'n',
1288 't'
1289);
1290
1291pub(crate) fn count_item() -> crate::render::SelectItem {
1293 crate::render::SelectItem::bare(count_star())
1294}
1295
1296fn count_star() -> ExprKind {
1297 ExprKind::Func {
1298 name: "count",
1299 arg: None,
1300 }
1301}
1302
1303pub fn count() -> Keyed<Count, Nil, BigInt> {
1306 Keyed::from_kind(count_star())
1307}
1308
1309#[diagnostic::on_unimplemented(
1317 message = "`min`/`max` need an ordered expression, and `{Self}` isn't one",
1318 label = "numbers, text, and dates/timestamps are ordered; booleans, bytes and UUIDs are not. `bool_or`/`bool_and` are the aggregate a flag wants, and aren't built yet"
1319)]
1320pub trait Ordered: SqlType + WrapNullable<MaybeNull> {}
1321
1322impl Ordered for Integer {}
1323impl Ordered for BigInt {}
1324impl Ordered for Real {}
1325impl Ordered for Text {}
1326#[cfg(feature = "decimal")]
1327impl Ordered for Numeric {}
1328#[cfg(feature = "chrono")]
1329impl Ordered for Timestamptz {}
1330#[cfg(feature = "chrono")]
1331impl Ordered for Date {}
1332
1333impl<S: Ordered> Ordered for crate::scope::Nullable<S> {}
1336
1337#[diagnostic::on_unimplemented(
1343 message = "`sum`/`avg` need a numeric expression, and `{Self}` isn't one",
1344 label = "only `Integer`, `BigInt` and `Real` columns and expressions (and `Numeric`, with the `decimal` feature) can be summed or averaged"
1345)]
1346pub trait Summable: SqlType {
1347 type Sum: SqlType;
1348 const SUM_CAST: Option<CastTarget>;
1349 const AVG_CAST: Option<CastTarget> = Some(CastTarget::Double);
1350}
1351impl Summable for Integer {
1352 type Sum = crate::scope::Nullable<BigInt>;
1353 const SUM_CAST: Option<CastTarget> = None;
1354}
1355impl Summable for BigInt {
1356 type Sum = crate::scope::Nullable<BigInt>;
1357 const SUM_CAST: Option<CastTarget> = Some(CastTarget::BigInt);
1358}
1359impl Summable for Real {
1360 type Sum = crate::scope::Nullable<Real>;
1361 const SUM_CAST: Option<CastTarget> = None;
1362 const AVG_CAST: Option<CastTarget> = None;
1363}
1364#[cfg(feature = "decimal")]
1367impl Summable for Numeric {
1368 type Sum = crate::scope::Nullable<Numeric>;
1369 const SUM_CAST: Option<CastTarget> = None;
1370 const AVG_CAST: Option<CastTarget> = Some(CastTarget::Double);
1371}
1372impl<T: Summable> Summable for crate::scope::Nullable<T> {
1373 type Sum = T::Sum;
1374 const SUM_CAST: Option<CastTarget> = T::SUM_CAST;
1375 const AVG_CAST: Option<CastTarget> = T::AVG_CAST;
1376}
1377
1378pub struct Agg<Op, C>(PhantomData<fn() -> (Op, C)>);
1382
1383#[doc(hidden)]
1390impl<Op, C: crate::row::Named> crate::row::NamedSealed for Agg<Op, C> {}
1391
1392#[doc(hidden)]
1393impl<Op: 'static, C: crate::row::Named + 'static> crate::row::Named for Agg<Op, C> {
1394 type Name = <C as crate::row::Named>::Name;
1395 const NAME: &'static str = <C as crate::row::Named>::NAME;
1396}
1397
1398#[doc(hidden)]
1399impl<Op: 'static, C: crate::row::Spelled + 'static> crate::row::Spelled for Agg<Op, C> {}
1400
1401fn aggregate_kind<C: ColumnKey>(name: &'static str, cast: Option<CastTarget>) -> ExprKind {
1402 let call = ExprKind::Func {
1403 name,
1404 arg: Some(Box::new(ExprKind::Column {
1405 table: <C::Table as Table>::NAME,
1406 name: <C as crate::row::Named>::NAME,
1407 })),
1408 };
1409 match cast {
1410 Some(target) => ExprKind::Cast {
1411 expr: Box::new(call),
1412 target,
1413 },
1414 None => call,
1415 }
1416}
1417
1418macro_rules! aggregate {
1419 ($op:ident, $func:ident, $sql:literal, $out:ty, $bound:path, $cast:expr, $doc:literal) => {
1420 #[doc = $doc]
1421 pub struct $op;
1422
1423 #[doc = $doc]
1424 pub fn $func<C: ColumnKey>(
1425 _column: Column<C>,
1426 ) -> Keyed<Agg<$op, C>, Cons<C::Table, Nil>, $out>
1427 where
1428 C::Sql: $bound,
1429 $out: SqlType,
1430 {
1431 Keyed::from_kind(aggregate_kind::<C>($sql, $cast))
1432 }
1433 };
1434}
1435
1436aggregate!(
1437 Sum,
1438 sum,
1439 "sum",
1440 <C::Sql as Summable>::Sum,
1441 Summable,
1442 <C::Sql as Summable>::SUM_CAST,
1443 "`sum(column)`. NULL over zero rows, so the result is always nullable."
1444);
1445aggregate!(
1446 Min,
1447 min,
1448 "min",
1449 <C::Sql as WrapNullable<MaybeNull>>::Output,
1450 Ordered,
1451 None,
1452 "`min(column)`. NULL over zero rows."
1453);
1454aggregate!(
1455 Max,
1456 max,
1457 "max",
1458 <C::Sql as WrapNullable<MaybeNull>>::Output,
1459 Ordered,
1460 None,
1461 "`max(column)`. NULL over zero rows."
1462);
1463aggregate!(
1464 Avg,
1465 avg,
1466 "avg",
1467 crate::scope::Nullable<Real>,
1468 Summable,
1469 <C::Sql as Summable>::AVG_CAST,
1470 "`avg(column)`. NULL over zero rows."
1471);
1472aggregate!(
1473 CountOf,
1474 count_of,
1475 "count",
1476 BigInt,
1477 SqlType,
1478 None,
1479 "`count(column)`: non-NULL values, unlike `count()`'s `count(*)` rows."
1480);
1481
1482#[diagnostic::on_unimplemented(
1488 message = "`string_agg` concatenates text, and `{Self}` isn't text",
1489 label = "reach for a cast, or a raw fragment, in front of a column that isn't"
1490)]
1491pub trait Concatenable: SqlType {}
1492
1493impl Concatenable for Text {}
1494
1495impl<S: Concatenable> Concatenable for crate::scope::Nullable<S> {}
1498
1499pub struct StringAgg;
1522
1523pub fn string_agg<C: ColumnKey>(
1525 _column: Column<C>,
1526 separator: &'static str,
1527) -> Keyed<Agg<StringAgg, C>, Cons<C::Table, Nil>, crate::scope::Nullable<Text>>
1528where
1529 C::Sql: Concatenable,
1530{
1531 Keyed::from_kind(ExprKind::StringAgg {
1532 arg: Box::new(ExprKind::Column {
1533 table: <C::Table as Table>::NAME,
1534 name: <C as crate::row::Named>::NAME,
1535 }),
1536 separator,
1537 })
1538}
1539
1540pub trait RawArg: raw_arg::Sealed {
1545 type Req;
1546 #[doc(hidden)]
1547 fn into_raw_arg(self) -> RawSlot;
1548}
1549
1550impl<T: IntoExpr> RawArg for T {
1551 type Req = T::Req;
1552 fn into_raw_arg(self) -> RawSlot {
1553 RawSlot(self.into_expr().kind)
1554 }
1555}
1556
1557pub struct RawSlot(ExprKind);
1561
1562impl RawSlot {
1563 fn into_kind(self) -> ExprKind {
1564 self.0
1565 }
1566}
1567
1568#[diagnostic::on_unimplemented(
1571 message = "a `sql!` fragment takes at most 8 `?` slots",
1572 label = "split the fragment, or fold part of it into the builder"
1573)]
1574pub trait RawArgs {
1575 type Req;
1576 #[doc(hidden)]
1577 fn into_raw_args(self) -> Vec<RawSlot>;
1578}
1579
1580impl RawArgs for () {
1581 type Req = Nil;
1582 fn into_raw_args(self) -> Vec<RawSlot> {
1583 Vec::new()
1584 }
1585}
1586
1587macro_rules! raw_args_tuple {
1588 ($head:ident $(, $rest:ident)*) => {
1589 #[allow(non_snake_case)]
1590 impl<$head: RawArg $(, $rest: RawArg)*> RawArgs for ($head, $($rest,)*)
1591 where
1592 ($($rest,)*): RawArgs,
1593 $head::Req: Concat<<($($rest,)*) as RawArgs>::Req>,
1594 {
1595 type Req = <$head::Req as Concat<<($($rest,)*) as RawArgs>::Req>>::Output;
1596 fn into_raw_args(self) -> Vec<RawSlot> {
1597 let ($head, $($rest,)*) = self;
1598 let mut kinds = ::std::vec![RawArg::into_raw_arg($head)];
1599 kinds.extend(RawArgs::into_raw_args(($($rest,)*)));
1600 kinds
1601 }
1602 }
1603 };
1604}
1605raw_args_tuple!(A);
1606raw_args_tuple!(A, B);
1607raw_args_tuple!(A, B, C);
1608raw_args_tuple!(A, B, C, D);
1609raw_args_tuple!(A, B, C, D, E);
1610raw_args_tuple!(A, B, C, D, E, F);
1611raw_args_tuple!(A, B, C, D, E, F, G);
1612raw_args_tuple!(A, B, C, D, E, F, G, H);
1613
1614#[doc(hidden)]
1618pub const fn placeholder_count(sql: &str) -> usize {
1619 let bytes = sql.as_bytes();
1620 let mut i = 0;
1621 let mut count = 0;
1622 while i < bytes.len() {
1623 if bytes[i] == b'?' {
1624 count += 1;
1625 }
1626 i += 1;
1627 }
1628 count
1629}
1630
1631#[doc(hidden)]
1636pub fn raw_expr<S: SqlType, Args: RawArgs>(
1637 sql: &'static str,
1638 args: Args,
1639) -> Declared<Args::Req, S> {
1640 Keyed::from_kind(template(sql, args.into_raw_args()))
1641}
1642
1643fn template(sql: &'static str, args: Vec<RawSlot>) -> ExprKind {
1647 let mut pieces: Vec<String> = vec![String::new()];
1648 for c in sql.chars() {
1649 match c {
1650 '?' => pieces.push(String::new()),
1651 c => pieces.last_mut().expect("one piece to start").push(c),
1652 }
1653 }
1654
1655 let mut pieces = pieces.into_iter();
1656 let head = pieces.next().unwrap_or_default();
1657 let rest = args
1658 .into_iter()
1659 .map(RawSlot::into_kind)
1660 .zip(pieces)
1661 .collect();
1662 ExprKind::Template { head, rest }
1663}
1664
1665#[doc(hidden)]
1672pub fn placeholder<S: SqlType>(name: &'static str) -> Expr<Nil, S> {
1673 Expr::from_kind(ExprKind::Value(Value::Placeholder(name)))
1674}