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()`, and assigning it is `null::<Text>()` — `= NULL` is never true in SQL"
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>;
672
673impl<Req, S: SqlType> Expr<Req, S> {
674 pub fn decodes_as<S2: SqlType>(self) -> Declared<Req, S2> {
678 Keyed {
679 kind: self.kind,
680 _marker: PhantomData,
681 }
682 }
683}
684
685pub struct Labeled<K, Inner> {
688 pub(crate) inner: Inner,
689 _key: PhantomData<fn() -> K>,
690}
691
692impl<K, Inner: Clone> Clone for Labeled<K, Inner> {
693 fn clone(&self) -> Self {
694 Labeled::new(self.inner.clone())
695 }
696}
697
698impl<K, Inner> Labeled<K, Inner> {
699 pub(crate) fn new(inner: Inner) -> Self {
700 Labeled {
701 inner,
702 _key: PhantomData,
703 }
704 }
705}
706
707pub trait LabelExt: Sized {
711 fn label<K: LabelKey>(self, _key: K) -> Labeled<K, Self> {
712 Labeled::new(self)
713 }
714}
715impl<C: ColumnKey> LabelExt for Column<C> {}
716impl<K, Req, S: SqlType> LabelExt for Keyed<K, Req, S> {}
717impl<Req, S: SqlType> LabelExt for Expr<Req, S> {}
722
723#[allow(clippy::wrong_self_convention)]
730pub trait ExprMethods: IntoExpr + Sized {
731 fn eq<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
732 where
733 Self::Sql: Comparable<Rhs::Sql>,
734 Self::Req: Concat<Rhs::Req>,
735 {
736 bin_op(BinOp::Eq, self, rhs)
737 }
738
739 fn ne<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
740 where
741 Self::Sql: Comparable<Rhs::Sql>,
742 Self::Req: Concat<Rhs::Req>,
743 {
744 bin_op(BinOp::Ne, self, rhs)
745 }
746
747 fn lt<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
748 where
749 Self::Sql: Comparable<Rhs::Sql>,
750 Self::Req: Concat<Rhs::Req>,
751 {
752 bin_op(BinOp::Lt, self, rhs)
753 }
754
755 fn lte<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
756 where
757 Self::Sql: Comparable<Rhs::Sql>,
758 Self::Req: Concat<Rhs::Req>,
759 {
760 bin_op(BinOp::Lte, self, rhs)
761 }
762
763 fn gt<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
764 where
765 Self::Sql: Comparable<Rhs::Sql>,
766 Self::Req: Concat<Rhs::Req>,
767 {
768 bin_op(BinOp::Gt, self, rhs)
769 }
770
771 fn gte<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
772 where
773 Self::Sql: Comparable<Rhs::Sql>,
774 Self::Req: Concat<Rhs::Req>,
775 {
776 bin_op(BinOp::Gte, self, rhs)
777 }
778
779 fn is_null(self) -> Expr<Self::Req, Bool> {
782 Expr::from_kind(ExprKind::IsNull {
783 expr: Box::new(self.into_expr().kind),
784 negated: false,
785 })
786 }
787
788 fn is_not_null(self) -> Expr<Self::Req, Bool> {
789 Expr::from_kind(ExprKind::IsNull {
790 expr: Box::new(self.into_expr().kind),
791 negated: true,
792 })
793 }
794
795 fn and<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
800 where
801 Self::Sql: BoolLike,
802 Rhs::Sql: BoolLike,
803 Self::Req: Concat<Rhs::Req>,
804 {
805 Expr::from_kind(ExprKind::And(
806 Box::new(self.into_expr().kind),
807 Box::new(rhs.into_expr().kind),
808 ))
809 }
810
811 fn or<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
813 where
814 Self::Sql: BoolLike,
815 Rhs::Sql: BoolLike,
816 Self::Req: Concat<Rhs::Req>,
817 {
818 Expr::from_kind(ExprKind::Or(
819 Box::new(self.into_expr().kind),
820 Box::new(rhs.into_expr().kind),
821 ))
822 }
823
824 fn like<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
828 where
829 Self::Sql: TextLike,
830 Rhs::Sql: TextLike,
831 Self::Req: Concat<Rhs::Req>,
832 {
833 bin_op(BinOp::Like, self, rhs)
834 }
835
836 fn is_in<I>(self, values: I) -> Expr<Self::Req, Bool>
843 where
844 I: IntoIterator,
845 I::Item: IntoExpr<Req = Nil>,
846 Self::Sql: Comparable<<I::Item as IntoExpr>::Sql>,
847 {
848 let values: Vec<ExprKind> = values.into_iter().map(|v| v.into_expr().kind).collect();
849 if values.is_empty() {
851 return Expr::from_kind(ExprKind::Always(false));
852 }
853 Expr::from_kind(ExprKind::InList {
854 expr: Box::new(self.into_expr().kind),
855 values,
856 })
857 }
858
859 fn eq_any<Rhs: IntoExpr>(
868 self,
869 array: Rhs,
870 ) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
871 where
872 Rhs::Sql: ArrayOf<Self::Sql>,
873 Self::Req: Concat<Rhs::Req>,
874 {
875 Expr::from_kind(ExprKind::EqAny {
876 expr: Box::new(self.into_expr().kind),
877 array: Box::new(array.into_expr().kind),
878 })
879 }
880}
881
882pub fn any_of<Req, C: IntoExpr<Req = Req>>(conds: impl IntoIterator<Item = C>) -> Expr<Req, Bool>
888where
889 C::Sql: BoolLike,
890{
891 combine(conds, false)
892}
893
894pub fn all_of<Req, C: IntoExpr<Req = Req>>(conds: impl IntoIterator<Item = C>) -> Expr<Req, Bool>
897where
898 C::Sql: BoolLike,
899{
900 combine(conds, true)
901}
902
903fn combine<Req, C: IntoExpr<Req = Req>>(
904 conds: impl IntoIterator<Item = C>,
905 all: bool,
906) -> Expr<Req, Bool>
907where
908 C::Sql: BoolLike,
909{
910 Expr::from_kind(fold_conditions(
911 conds.into_iter().map(|c| c.into_expr().kind),
912 all,
913 ))
914}
915
916pub(crate) fn fold_conditions(kinds: impl IntoIterator<Item = ExprKind>, all: bool) -> ExprKind {
921 let mut folded: Option<ExprKind> = None;
922 for kind in kinds {
923 folded = Some(match folded {
924 None => kind,
925 Some(acc) if all => ExprKind::And(Box::new(acc), Box::new(kind)),
926 Some(acc) => ExprKind::Or(Box::new(acc), Box::new(kind)),
927 });
928 }
929 folded.unwrap_or(ExprKind::Always(all))
930}
931
932impl<T: IntoExpr> ExprMethods for T {}
933
934fn bin_op<Lhs, Rhs>(
935 op: BinOp,
936 lhs: Lhs,
937 rhs: Rhs,
938) -> Expr<<Lhs::Req as Concat<Rhs::Req>>::Output, Bool>
939where
940 Lhs: IntoExpr,
941 Rhs: IntoExpr,
942 Lhs::Req: Concat<Rhs::Req>,
943{
944 Expr::from_kind(ExprKind::BinOp {
945 op,
946 lhs: Box::new(lhs.into_expr().kind),
947 rhs: Box::new(rhs.into_expr().kind),
948 })
949}
950
951#[diagnostic::on_unimplemented(
955 message = "`LIKE` needs a text expression, and `{Self}` isn't one",
956 label = "only `Text` and `Nullable<Text>` columns and expressions accept `.like(..)`"
957)]
958pub trait TextLike: SqlType {}
959
960impl TextLike for Text {}
961impl TextLike for crate::scope::Nullable<Text> {}
962
963#[diagnostic::on_unimplemented(
967 message = "a condition has to be a boolean expression, and `{Self}` isn't one",
968 label = "expected `Bool` or `Nullable<Bool>`"
969)]
970pub trait BoolLike: SqlType {}
971
972impl BoolLike for Bool {}
973impl BoolLike for crate::scope::Nullable<Bool> {}
974
975impl<Req, S: BoolLike> std::ops::Not for Expr<Req, S> {
981 type Output = Expr<Req, S>;
982 fn not(self) -> Self::Output {
983 Expr::from_kind(ExprKind::Not(Box::new(self.kind)))
984 }
985}
986
987impl<K, Req, S: BoolLike> std::ops::Not for Keyed<K, Req, S> {
988 type Output = Keyed<K, Req, S>;
989 fn not(self) -> Self::Output {
990 Keyed::from_kind(ExprKind::Not(Box::new(self.kind)))
991 }
992}
993
994impl<C: ColumnKey> std::ops::Not for Column<C>
995where
996 C::Sql: BoolLike,
997{
998 type Output = Expr<Cons<C::Table, Nil>, C::Sql>;
999 fn not(self) -> Self::Output {
1000 Expr::from_kind(ExprKind::Not(Box::new(self.into_expr().kind)))
1001 }
1002}
1003
1004pub trait NullValue: SqlType {
1007 const NULL_VALUE: Value;
1008}
1009
1010pub fn null<S: NullValue>() -> Expr<Nil, crate::scope::Nullable<S>> {
1015 Expr::from_kind(ExprKind::Value(S::NULL_VALUE))
1016}
1017
1018mod raw_arg {
1024 pub trait Sealed {}
1029 impl<T: super::IntoExpr> Sealed for T {}
1030}
1031
1032macro_rules! sql_leaf_type {
1033 ($name:ident, $native:ty, $null_variant:ident) => {
1034 pub struct $name;
1035
1036 impl sql_type::Sealed for $name {}
1037
1038 impl SqlType for $name {
1039 type Native = $native;
1040 }
1041
1042 impl crate::scope::wrap::Sealed<MaybeNull> for $name {}
1043
1044 impl crate::scope::WrapNullable<MaybeNull> for $name {
1045 type Output = crate::scope::Nullable<$name>;
1046 }
1047
1048 impl IntoExpr for $native {
1049 type Sql = $name;
1050 type Req = Nil;
1051 fn into_expr(self) -> Expr<Nil, $name> {
1052 Expr::from_kind(ExprKind::Value(Value::from(self)))
1053 }
1054 }
1055
1056 impl crate::select::SingleColumn for $native {}
1057 impl crate::select::SingleColumn for ::std::option::Option<$native> {}
1058
1059 impl NullValue for $name {
1060 const NULL_VALUE: Value = Value::$null_variant;
1061 }
1062
1063 impl crate::insert::IntoColumnValue<$native> for $native {
1064 fn into_column_value(self) -> $native {
1065 self
1066 }
1067 }
1068
1069 impl crate::insert::IntoColumnValue<::std::option::Option<$native>> for $native {
1070 fn into_column_value(self) -> ::std::option::Option<$native> {
1071 ::std::option::Option::Some(self)
1072 }
1073 }
1074
1075 impl crate::insert::IntoColumnValue<::std::option::Option<$native>>
1076 for ::std::option::Option<$native>
1077 {
1078 fn into_column_value(self) -> ::std::option::Option<$native> {
1079 self
1080 }
1081 }
1082
1083 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<$native>> for $native {
1084 fn into_column_value(self) -> crate::insert::Defaultable<$native> {
1085 crate::insert::Defaultable::Value(self)
1086 }
1087 }
1088
1089 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<$native>>
1090 for ::std::option::Option<$native>
1091 {
1092 fn into_column_value(self) -> crate::insert::Defaultable<$native> {
1093 match self {
1094 ::std::option::Option::Some(v) => crate::insert::Defaultable::Value(v),
1095 ::std::option::Option::None => crate::insert::Defaultable::Default,
1096 }
1097 }
1098 }
1099
1100 impl
1101 crate::insert::IntoColumnValue<
1102 crate::insert::Defaultable<::std::option::Option<$native>>,
1103 > for $native
1104 {
1105 fn into_column_value(
1106 self,
1107 ) -> crate::insert::Defaultable<::std::option::Option<$native>> {
1108 crate::insert::Defaultable::Value(::std::option::Option::Some(self))
1109 }
1110 }
1111
1112 impl
1113 crate::insert::IntoColumnValue<
1114 crate::insert::Defaultable<::std::option::Option<$native>>,
1115 > for ::std::option::Option<$native>
1116 {
1117 fn into_column_value(
1118 self,
1119 ) -> crate::insert::Defaultable<::std::option::Option<$native>> {
1120 match self {
1121 ::std::option::Option::Some(v) => {
1122 crate::insert::Defaultable::Value(::std::option::Option::Some(v))
1123 }
1124 ::std::option::Option::None => crate::insert::Defaultable::Default,
1125 }
1126 }
1127 }
1128
1129 impl raw_arg::Sealed for ::std::option::Option<$native> {}
1130
1131 impl RawArg for ::std::option::Option<$native> {
1132 type Req = Nil;
1133 fn into_raw_arg(self) -> RawSlot {
1134 RawSlot(ExprKind::Value(Value::from(self)))
1135 }
1136 }
1137
1138 impl crate::row::SameShape<$native> for $native {}
1139 impl crate::row::SameShape<::std::option::Option<$native>>
1140 for ::std::option::Option<$native>
1141 {
1142 }
1143
1144 impl From<::std::option::Option<$native>> for Value {
1147 fn from(v: ::std::option::Option<$native>) -> Self {
1148 match v {
1149 ::std::option::Option::Some(x) => Value::from(x),
1150 ::std::option::Option::None => Value::$null_variant,
1151 }
1152 }
1153 }
1154 };
1155}
1156
1157sql_leaf_type!(Integer, i32, NullI32);
1158sql_leaf_type!(BigInt, i64, NullI64);
1159sql_leaf_type!(Real, f64, NullF64);
1160sql_leaf_type!(Text, String, NullText);
1161sql_leaf_type!(Bool, bool, NullBool);
1162sql_leaf_type!(Bytes, Vec<u8>, NullBytes);
1163
1164sql_leaf_type!(TextArray, Vec<String>, NullTextArray);
1174sql_leaf_type!(IntegerArray, Vec<i32>, NullIntegerArray);
1175sql_leaf_type!(BigIntArray, Vec<i64>, NullBigIntArray);
1176#[cfg(feature = "uuid")]
1177sql_leaf_type!(UuidArray, Vec<uuid::Uuid>, NullUuidArray);
1178
1179#[cfg(feature = "json")]
1190sql_leaf_type!(Json, serde_json::Value, NullJson);
1191
1192#[cfg(feature = "chrono")]
1196sql_leaf_type!(Timestamptz, chrono::DateTime<chrono::Utc>, NullTimestamptz);
1197#[cfg(feature = "chrono")]
1198sql_leaf_type!(Date, chrono::NaiveDate, NullDate);
1199#[cfg(feature = "uuid")]
1200sql_leaf_type!(Uuid, uuid::Uuid, NullUuid);
1201#[cfg(feature = "decimal")]
1202sql_leaf_type!(Numeric, rust_decimal::Decimal, NullNumeric);
1203
1204impl IntoExpr for &String {
1207 type Sql = Text;
1208 type Req = Nil;
1209 fn into_expr(self) -> Expr<Nil, Text> {
1210 Expr::from_kind(ExprKind::Value(Value::Text(self.clone())))
1211 }
1212}
1213
1214impl IntoExpr for &str {
1215 type Sql = Text;
1216 type Req = Nil;
1217 fn into_expr(self) -> Expr<Nil, Text> {
1218 Expr::from_kind(ExprKind::Value(Value::Text(self.to_string())))
1219 }
1220}
1221
1222macro_rules! text_column_value {
1225 ($borrowed:ty) => {
1226 impl crate::insert::IntoColumnValue<String> for $borrowed {
1227 fn into_column_value(self) -> String {
1228 self.to_string()
1229 }
1230 }
1231
1232 impl crate::insert::IntoColumnValue<Option<String>> for $borrowed {
1233 fn into_column_value(self) -> Option<String> {
1234 Some(self.to_string())
1235 }
1236 }
1237
1238 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<String>> for $borrowed {
1239 fn into_column_value(self) -> crate::insert::Defaultable<String> {
1240 crate::insert::Defaultable::Value(self.to_string())
1241 }
1242 }
1243
1244 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<Option<String>>>
1245 for $borrowed
1246 {
1247 fn into_column_value(self) -> crate::insert::Defaultable<Option<String>> {
1248 crate::insert::Defaultable::Value(Some(self.to_string()))
1249 }
1250 }
1251 };
1252}
1253
1254text_column_value!(&str);
1255text_column_value!(&String);
1256
1257impl<S: SqlType> sql_type::Sealed for crate::scope::Nullable<S> {}
1258
1259impl<S: SqlType> SqlType for crate::scope::Nullable<S> {
1260 type Native = Option<S::Native>;
1261}
1262
1263crate::row::expr_key!(
1264 Count,
1265 HasCount,
1266 count,
1267 "The identity a selected `count(*)` is filed under in a row.",
1268 'c',
1269 'o',
1270 'u',
1271 'n',
1272 't'
1273);
1274
1275pub(crate) fn count_item() -> crate::render::SelectItem {
1277 crate::render::SelectItem::bare(count_star())
1278}
1279
1280fn count_star() -> ExprKind {
1281 ExprKind::Func {
1282 name: "count",
1283 arg: None,
1284 }
1285}
1286
1287pub fn count() -> Keyed<Count, Nil, BigInt> {
1290 Keyed::from_kind(count_star())
1291}
1292
1293#[diagnostic::on_unimplemented(
1301 message = "`min`/`max` need an ordered expression, and `{Self}` isn't one",
1302 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"
1303)]
1304pub trait Ordered: SqlType + WrapNullable<MaybeNull> {}
1305
1306impl Ordered for Integer {}
1307impl Ordered for BigInt {}
1308impl Ordered for Real {}
1309impl Ordered for Text {}
1310#[cfg(feature = "decimal")]
1311impl Ordered for Numeric {}
1312#[cfg(feature = "chrono")]
1313impl Ordered for Timestamptz {}
1314#[cfg(feature = "chrono")]
1315impl Ordered for Date {}
1316
1317impl<S: Ordered> Ordered for crate::scope::Nullable<S> {}
1320
1321#[diagnostic::on_unimplemented(
1327 message = "`sum`/`avg` need a numeric expression, and `{Self}` isn't one",
1328 label = "only `Integer`, `BigInt` and `Real` columns and expressions (and `Numeric`, with the `decimal` feature) can be summed or averaged"
1329)]
1330pub trait Summable: SqlType {
1331 type Sum: SqlType;
1332 const SUM_CAST: Option<CastTarget>;
1333 const AVG_CAST: Option<CastTarget> = Some(CastTarget::Double);
1334}
1335impl Summable for Integer {
1336 type Sum = crate::scope::Nullable<BigInt>;
1337 const SUM_CAST: Option<CastTarget> = None;
1338}
1339impl Summable for BigInt {
1340 type Sum = crate::scope::Nullable<BigInt>;
1341 const SUM_CAST: Option<CastTarget> = Some(CastTarget::BigInt);
1342}
1343impl Summable for Real {
1344 type Sum = crate::scope::Nullable<Real>;
1345 const SUM_CAST: Option<CastTarget> = None;
1346 const AVG_CAST: Option<CastTarget> = None;
1347}
1348#[cfg(feature = "decimal")]
1351impl Summable for Numeric {
1352 type Sum = crate::scope::Nullable<Numeric>;
1353 const SUM_CAST: Option<CastTarget> = None;
1354 const AVG_CAST: Option<CastTarget> = Some(CastTarget::Double);
1355}
1356impl<T: Summable> Summable for crate::scope::Nullable<T> {
1357 type Sum = T::Sum;
1358 const SUM_CAST: Option<CastTarget> = T::SUM_CAST;
1359 const AVG_CAST: Option<CastTarget> = T::AVG_CAST;
1360}
1361
1362pub struct Agg<Op, C>(PhantomData<fn() -> (Op, C)>);
1366
1367#[doc(hidden)]
1374impl<Op, C: crate::row::Named> crate::row::NamedSealed for Agg<Op, C> {}
1375
1376#[doc(hidden)]
1377impl<Op: 'static, C: crate::row::Named + 'static> crate::row::Named for Agg<Op, C> {
1378 type Name = <C as crate::row::Named>::Name;
1379 const NAME: &'static str = <C as crate::row::Named>::NAME;
1380}
1381
1382#[doc(hidden)]
1383impl<Op: 'static, C: crate::row::Spelled + 'static> crate::row::Spelled for Agg<Op, C> {}
1384
1385fn aggregate_kind<C: ColumnKey>(name: &'static str, cast: Option<CastTarget>) -> ExprKind {
1386 let call = ExprKind::Func {
1387 name,
1388 arg: Some(Box::new(ExprKind::Column {
1389 table: <C::Table as Table>::NAME,
1390 name: <C as crate::row::Named>::NAME,
1391 })),
1392 };
1393 match cast {
1394 Some(target) => ExprKind::Cast {
1395 expr: Box::new(call),
1396 target,
1397 },
1398 None => call,
1399 }
1400}
1401
1402macro_rules! aggregate {
1403 ($op:ident, $func:ident, $sql:literal, $out:ty, $bound:path, $cast:expr, $doc:literal) => {
1404 #[doc = $doc]
1405 pub struct $op;
1406
1407 #[doc = $doc]
1408 pub fn $func<C: ColumnKey>(
1409 _column: Column<C>,
1410 ) -> Keyed<Agg<$op, C>, Cons<C::Table, Nil>, $out>
1411 where
1412 C::Sql: $bound,
1413 $out: SqlType,
1414 {
1415 Keyed::from_kind(aggregate_kind::<C>($sql, $cast))
1416 }
1417 };
1418}
1419
1420aggregate!(
1421 Sum,
1422 sum,
1423 "sum",
1424 <C::Sql as Summable>::Sum,
1425 Summable,
1426 <C::Sql as Summable>::SUM_CAST,
1427 "`sum(column)`. NULL over zero rows, so the result is always nullable."
1428);
1429aggregate!(
1430 Min,
1431 min,
1432 "min",
1433 <C::Sql as WrapNullable<MaybeNull>>::Output,
1434 Ordered,
1435 None,
1436 "`min(column)`. NULL over zero rows."
1437);
1438aggregate!(
1439 Max,
1440 max,
1441 "max",
1442 <C::Sql as WrapNullable<MaybeNull>>::Output,
1443 Ordered,
1444 None,
1445 "`max(column)`. NULL over zero rows."
1446);
1447aggregate!(
1448 Avg,
1449 avg,
1450 "avg",
1451 crate::scope::Nullable<Real>,
1452 Summable,
1453 <C::Sql as Summable>::AVG_CAST,
1454 "`avg(column)`. NULL over zero rows."
1455);
1456aggregate!(
1457 CountOf,
1458 count_of,
1459 "count",
1460 BigInt,
1461 SqlType,
1462 None,
1463 "`count(column)` — non-NULL values, unlike `count()`'s `count(*)` rows."
1464);
1465
1466#[diagnostic::on_unimplemented(
1472 message = "`string_agg` concatenates text, and `{Self}` isn't text",
1473 label = "reach for a cast, or a raw fragment, in front of a column that isn't"
1474)]
1475pub trait Concatenable: SqlType {}
1476
1477impl Concatenable for Text {}
1478
1479impl<S: Concatenable> Concatenable for crate::scope::Nullable<S> {}
1482
1483pub struct StringAgg;
1506
1507pub fn string_agg<C: ColumnKey>(
1509 _column: Column<C>,
1510 separator: &'static str,
1511) -> Keyed<Agg<StringAgg, C>, Cons<C::Table, Nil>, crate::scope::Nullable<Text>>
1512where
1513 C::Sql: Concatenable,
1514{
1515 Keyed::from_kind(ExprKind::StringAgg {
1516 arg: Box::new(ExprKind::Column {
1517 table: <C::Table as Table>::NAME,
1518 name: <C as crate::row::Named>::NAME,
1519 }),
1520 separator,
1521 })
1522}
1523
1524pub trait RawArg: raw_arg::Sealed {
1529 type Req;
1530 #[doc(hidden)]
1531 fn into_raw_arg(self) -> RawSlot;
1532}
1533
1534impl<T: IntoExpr> RawArg for T {
1535 type Req = T::Req;
1536 fn into_raw_arg(self) -> RawSlot {
1537 RawSlot(self.into_expr().kind)
1538 }
1539}
1540
1541pub struct RawSlot(ExprKind);
1545
1546impl RawSlot {
1547 fn into_kind(self) -> ExprKind {
1548 self.0
1549 }
1550}
1551
1552#[diagnostic::on_unimplemented(
1555 message = "a `sql!` fragment takes at most 8 `?` slots",
1556 label = "split the fragment, or fold part of it into the builder"
1557)]
1558pub trait RawArgs {
1559 type Req;
1560 #[doc(hidden)]
1561 fn into_raw_args(self) -> Vec<RawSlot>;
1562}
1563
1564impl RawArgs for () {
1565 type Req = Nil;
1566 fn into_raw_args(self) -> Vec<RawSlot> {
1567 Vec::new()
1568 }
1569}
1570
1571macro_rules! raw_args_tuple {
1572 ($head:ident $(, $rest:ident)*) => {
1573 #[allow(non_snake_case)]
1574 impl<$head: RawArg $(, $rest: RawArg)*> RawArgs for ($head, $($rest,)*)
1575 where
1576 ($($rest,)*): RawArgs,
1577 $head::Req: Concat<<($($rest,)*) as RawArgs>::Req>,
1578 {
1579 type Req = <$head::Req as Concat<<($($rest,)*) as RawArgs>::Req>>::Output;
1580 fn into_raw_args(self) -> Vec<RawSlot> {
1581 let ($head, $($rest,)*) = self;
1582 let mut kinds = ::std::vec![RawArg::into_raw_arg($head)];
1583 kinds.extend(RawArgs::into_raw_args(($($rest,)*)));
1584 kinds
1585 }
1586 }
1587 };
1588}
1589raw_args_tuple!(A);
1590raw_args_tuple!(A, B);
1591raw_args_tuple!(A, B, C);
1592raw_args_tuple!(A, B, C, D);
1593raw_args_tuple!(A, B, C, D, E);
1594raw_args_tuple!(A, B, C, D, E, F);
1595raw_args_tuple!(A, B, C, D, E, F, G);
1596raw_args_tuple!(A, B, C, D, E, F, G, H);
1597
1598#[doc(hidden)]
1602pub const fn placeholder_count(sql: &str) -> usize {
1603 let bytes = sql.as_bytes();
1604 let mut i = 0;
1605 let mut count = 0;
1606 while i < bytes.len() {
1607 if bytes[i] == b'?' {
1608 count += 1;
1609 }
1610 i += 1;
1611 }
1612 count
1613}
1614
1615#[doc(hidden)]
1620pub fn raw_expr<S: SqlType, Args: RawArgs>(
1621 sql: &'static str,
1622 args: Args,
1623) -> Declared<Args::Req, S> {
1624 Keyed::from_kind(template(sql, args.into_raw_args()))
1625}
1626
1627fn template(sql: &'static str, args: Vec<RawSlot>) -> ExprKind {
1631 let mut pieces: Vec<String> = vec![String::new()];
1632 for c in sql.chars() {
1633 match c {
1634 '?' => pieces.push(String::new()),
1635 c => pieces.last_mut().expect("one piece to start").push(c),
1636 }
1637 }
1638
1639 let mut pieces = pieces.into_iter();
1640 let head = pieces.next().unwrap_or_default();
1641 let rest = args
1642 .into_iter()
1643 .map(RawSlot::into_kind)
1644 .zip(pieces)
1645 .collect();
1646 ExprKind::Template { head, rest }
1647}
1648
1649#[doc(hidden)]
1656pub fn placeholder<S: SqlType>(name: &'static str) -> Expr<Nil, S> {
1657 Expr::from_kind(ExprKind::Value(Value::Placeholder(name)))
1658}