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 Value(Value),
37 BinOp {
38 op: BinOp,
39 lhs: Box<ExprKind>,
40 rhs: Box<ExprKind>,
41 },
42 And(Box<ExprKind>, Box<ExprKind>),
43 Or(Box<ExprKind>, Box<ExprKind>),
44 Always(bool),
47 Not(Box<ExprKind>),
48 IsNull {
51 expr: Box<ExprKind>,
52 negated: bool,
53 },
54 InList {
57 expr: Box<ExprKind>,
58 values: Vec<ExprKind>,
59 },
60 Exists {
64 body: Box<crate::select::SelectBody>,
65 selection: Vec<crate::render::SelectItem>,
66 negated: bool,
67 },
68 InSubquery {
73 lhs: Box<ExprKind>,
74 body: Box<crate::select::SelectBody>,
75 selection: Vec<crate::render::SelectItem>,
76 negated: bool,
77 },
78 Template {
83 head: String,
84 rest: Vec<(ExprKind, String)>,
85 },
86 Cast {
90 expr: Box<ExprKind>,
91 target: CastTarget,
92 },
93 Func {
99 name: &'static str,
100 arg: Option<Box<ExprKind>>,
101 },
102 StringAgg {
110 arg: Box<ExprKind>,
111 separator: &'static str,
112 },
113 Window {
119 func: &'static str,
120 partition_by: Vec<ExprKind>,
121 order_by: Vec<(ExprKind, SortDir)>,
122 },
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum SortDir {
130 Asc,
131 Desc,
132}
133
134#[doc(hidden)]
137#[derive(Debug, Clone, Copy, PartialEq, Eq)]
138pub enum CastTarget {
139 BigInt,
140 Double,
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144pub enum BinOp {
145 Eq,
146 Ne,
147 Lt,
148 Lte,
149 Gt,
150 Gte,
151 Like,
152}
153
154#[derive(Debug, Clone, PartialEq)]
159pub enum Value {
160 I32(i32),
161 I64(i64),
162 F64(f64),
163 Text(String),
164 Bool(bool),
165 Bytes(Vec<u8>),
166 NullI32,
172 NullI64,
173 NullF64,
174 NullText,
175 NullBool,
176 NullBytes,
177 #[cfg(feature = "chrono")]
178 Timestamptz(chrono::DateTime<chrono::Utc>),
179 #[cfg(feature = "chrono")]
180 NullTimestamptz,
181 #[cfg(feature = "chrono")]
182 Date(chrono::NaiveDate),
183 #[cfg(feature = "chrono")]
184 NullDate,
185 #[cfg(feature = "uuid")]
186 Uuid(uuid::Uuid),
187 #[cfg(feature = "uuid")]
188 NullUuid,
189 #[cfg(feature = "decimal")]
190 Numeric(rust_decimal::Decimal),
191 #[cfg(feature = "decimal")]
192 NullNumeric,
193 TextArray(Vec<String>),
196 NullTextArray,
197 IntegerArray(Vec<i32>),
198 NullIntegerArray,
199 BigIntArray(Vec<i64>),
200 NullBigIntArray,
201 #[cfg(feature = "uuid")]
202 UuidArray(Vec<uuid::Uuid>),
203 #[cfg(feature = "uuid")]
204 NullUuidArray,
205 #[cfg(feature = "json")]
208 Json(serde_json::Value),
209 #[cfg(feature = "json")]
210 NullJson,
211 Placeholder(&'static str),
217}
218
219#[cfg(feature = "json")]
225fn json_as_written(value: &serde_json::Value) -> String {
226 value.to_string()
227}
228
229impl Value {
230 pub fn type_name(&self) -> &'static str {
234 match self {
235 Value::I32(_) | Value::NullI32 => "Integer",
236 Value::I64(_) | Value::NullI64 => "BigInt",
237 Value::F64(_) | Value::NullF64 => "Real",
238 Value::Text(_) | Value::NullText => "Text",
239 Value::Bool(_) | Value::NullBool => "Bool",
240 Value::Bytes(_) | Value::NullBytes => "Bytes",
241 Value::TextArray(_) | Value::NullTextArray => "TextArray",
242 Value::IntegerArray(_) | Value::NullIntegerArray => "IntegerArray",
243 Value::BigIntArray(_) | Value::NullBigIntArray => "BigIntArray",
244 #[cfg(feature = "uuid")]
245 Value::UuidArray(_) | Value::NullUuidArray => "UuidArray",
246 #[cfg(feature = "json")]
247 Value::Json(_) | Value::NullJson => "Json",
248 Value::Placeholder(_) => "placeholder",
249 #[cfg(feature = "chrono")]
250 Value::Timestamptz(_) | Value::NullTimestamptz => "Timestamptz",
251 #[cfg(feature = "chrono")]
252 Value::Date(_) | Value::NullDate => "Date",
253 #[cfg(feature = "uuid")]
254 Value::Uuid(_) | Value::NullUuid => "Uuid",
255 #[cfg(feature = "decimal")]
256 Value::Numeric(_) | Value::NullNumeric => "Numeric",
257 }
258 }
259
260 pub(crate) fn binds_same_as(&self, other: &Value) -> bool {
268 match (self, other) {
269 (Value::F64(a), Value::F64(b)) => a.to_bits() == b.to_bits(),
270 #[cfg(feature = "decimal")]
271 (Value::Numeric(a), Value::Numeric(b)) => a.serialize() == b.serialize(),
272 #[cfg(feature = "json")]
273 (Value::Json(a), Value::Json(b)) => json_as_written(a) == json_as_written(b),
274 _ => self == other,
275 }
276 }
277
278 pub(crate) fn hash_into<H: std::hash::Hasher>(&self, hasher: &mut H) {
286 use std::hash::Hash as _;
287 std::mem::discriminant(self).hash(hasher);
288 match self {
289 Value::I32(v) => v.hash(hasher),
290 Value::I64(v) => v.hash(hasher),
291 Value::F64(v) => v.to_bits().hash(hasher),
292 Value::Text(v) => v.hash(hasher),
293 Value::Bool(v) => v.hash(hasher),
294 Value::Bytes(v) => v.hash(hasher),
295 Value::Placeholder(v) => v.hash(hasher),
296 Value::TextArray(v) => v.hash(hasher),
297 Value::IntegerArray(v) => v.hash(hasher),
298 Value::BigIntArray(v) => v.hash(hasher),
299 #[cfg(feature = "uuid")]
300 Value::UuidArray(v) => v.hash(hasher),
301 #[cfg(feature = "json")]
302 Value::Json(v) => json_as_written(v).hash(hasher),
303 #[cfg(feature = "chrono")]
304 Value::Timestamptz(v) => v.hash(hasher),
305 #[cfg(feature = "chrono")]
306 Value::Date(v) => v.hash(hasher),
307 #[cfg(feature = "uuid")]
308 Value::Uuid(v) => v.hash(hasher),
309 #[cfg(feature = "decimal")]
310 Value::Numeric(v) => v.serialize().hash(hasher),
311 Value::NullI32
312 | Value::NullI64
313 | Value::NullF64
314 | Value::NullText
315 | Value::NullBool
316 | Value::NullBytes
317 | Value::NullTextArray
318 | Value::NullIntegerArray
319 | Value::NullBigIntArray => {}
320 #[cfg(feature = "uuid")]
321 Value::NullUuidArray => {}
322 #[cfg(feature = "json")]
323 Value::NullJson => {}
324 #[cfg(feature = "chrono")]
325 Value::NullTimestamptz | Value::NullDate => {}
326 #[cfg(feature = "uuid")]
327 Value::NullUuid => {}
328 #[cfg(feature = "decimal")]
329 Value::NullNumeric => {}
330 }
331 }
332}
333
334macro_rules! value_from {
335 ($ty:ty, $variant:ident) => {
336 impl From<$ty> for Value {
337 fn from(v: $ty) -> Self {
338 Value::$variant(v)
339 }
340 }
341 };
342}
343value_from!(i32, I32);
344value_from!(i64, I64);
345value_from!(f64, F64);
346value_from!(String, Text);
347value_from!(bool, Bool);
348value_from!(Vec<u8>, Bytes);
349#[cfg(feature = "chrono")]
350value_from!(chrono::DateTime<chrono::Utc>, Timestamptz);
351#[cfg(feature = "chrono")]
352value_from!(chrono::NaiveDate, Date);
353#[cfg(feature = "uuid")]
354value_from!(uuid::Uuid, Uuid);
355#[cfg(feature = "decimal")]
356value_from!(rust_decimal::Decimal, Numeric);
357value_from!(Vec<String>, TextArray);
358value_from!(Vec<i32>, IntegerArray);
359value_from!(Vec<i64>, BigIntArray);
360#[cfg(feature = "uuid")]
361value_from!(Vec<uuid::Uuid>, UuidArray);
362#[cfg(feature = "json")]
363value_from!(serde_json::Value, Json);
364
365impl From<&str> for Value {
366 fn from(v: &str) -> Self {
367 Value::Text(v.to_string())
368 }
369}
370
371pub struct Expr<Req, S: SqlType> {
378 pub(crate) kind: ExprKind,
379 _marker: PhantomData<fn() -> (Req, S)>,
380}
381
382impl<Req, S: SqlType> Expr<Req, S> {
383 pub(crate) fn from_kind(kind: ExprKind) -> Self {
384 Expr {
385 kind,
386 _marker: PhantomData,
387 }
388 }
389}
390
391impl<Req, S: SqlType> Clone for Expr<Req, S> {
394 fn clone(&self) -> Self {
395 Expr::from_kind(self.kind.clone())
396 }
397}
398
399#[diagnostic::on_unimplemented(
403 message = "`{Self}` isn't a SQL expression",
404 label = "a column, a literal, an aggregate, or a `sql!{{}}` fragment is; a `label!` name is not",
405 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"
406)]
407pub trait IntoExpr {
408 type Sql: SqlType;
414 type Req;
415 fn into_expr(self) -> Expr<Self::Req, Self::Sql>;
416}
417
418impl<Req, S: SqlType> IntoExpr for Expr<Req, S> {
419 type Sql = S;
420 type Req = Req;
421 fn into_expr(self) -> Expr<Req, S> {
422 self
423 }
424}
425
426#[diagnostic::on_unimplemented(
432 message = "a `{Self}` expression can't be assigned to a `{Column}` column",
433 label = "the value has to fit the column: the same type, a narrower number, or a non-null value for a nullable column"
434)]
435pub trait AssignsTo<Column: SqlType>: SqlType {}
436
437impl<T: SqlType> AssignsTo<T> for T {}
438impl<T: SqlType> AssignsTo<crate::scope::Nullable<T>> for T {}
439
440mod writable {
441 pub trait Sealed {}
445}
446
447#[doc(hidden)]
448pub use writable::Sealed as WritableSealed;
449
450#[diagnostic::on_unimplemented(
454 message = "`{Self}` isn't a column a statement can assign to",
455 label = "a primary-key or generated column is the database's to write, which is why `*Update` leaves it out too"
456)]
457pub trait Writable: WritableSealed {}
458
459pub trait ColumnKey: crate::row::Spelled + Copy + 'static {
465 type Table: Table;
466 type Sql: SqlType;
467}
468
469pub struct Column<C: ColumnKey>(PhantomData<C>);
476
477impl<C: ColumnKey> Column<C> {
478 pub const fn new() -> Self {
479 Column(PhantomData)
480 }
481}
482
483impl<C: ColumnKey> Default for Column<C> {
484 fn default() -> Self {
485 Self::new()
486 }
487}
488
489impl<C: ColumnKey> Clone for Column<C> {
490 fn clone(&self) -> Self {
491 *self
492 }
493}
494impl<C: ColumnKey> Copy for Column<C> {}
495
496impl<C: ColumnKey> IntoExpr for Column<C> {
497 type Sql = C::Sql;
498 type Req = Cons<C::Table, Nil>;
499 fn into_expr(self) -> Expr<Self::Req, C::Sql> {
500 Expr::from_kind(ExprKind::Column {
501 table: <C::Table as Table>::NAME,
502 name: <C as crate::row::Named>::NAME,
503 })
504 }
505}
506
507pub struct Keyed<K, Req, S: SqlType> {
512 pub(crate) kind: ExprKind,
513 _marker: PhantomData<fn() -> (K, Req, S)>,
514}
515
516impl<K, Req, S: SqlType> Keyed<K, Req, S> {
517 pub(crate) fn from_kind(kind: ExprKind) -> Self {
518 Keyed {
519 kind,
520 _marker: PhantomData,
521 }
522 }
523}
524
525impl<K, Req, S: SqlType> Clone for Keyed<K, Req, S> {
526 fn clone(&self) -> Self {
527 Keyed::from_kind(self.kind.clone())
528 }
529}
530
531impl<K, Req, S: SqlType> IntoExpr for Keyed<K, Req, S> {
532 type Sql = S;
533 type Req = Req;
534 fn into_expr(self) -> Expr<Req, S> {
535 Expr::from_kind(self.kind)
536 }
537}
538
539#[diagnostic::on_unimplemented(
547 message = "`{Self}` and `{Other}` aren't comparable",
548 label = "both sides of a comparison must be the same SQL type, or two numeric ones",
549 note = "nullability doesn't matter here: a `Nullable<T>` compares with a `T`",
550 note = "an unannotated `vec![1, 2]` is an `integer[]`, since that is what an integer literal defaults to — a `bytea` takes `vec![1u8, 2]`"
551)]
552pub trait Comparable<Other: SqlType>: SqlType {}
553
554impl<T: SqlType> Comparable<T> for T {}
555impl<T: SqlType> Comparable<crate::scope::Nullable<T>> for T {}
556impl<T: SqlType> Comparable<T> for crate::scope::Nullable<T> {}
557
558macro_rules! comparable_across {
561 ($($a:ty => $b:ty),+ $(,)?) => {
562 $(
563 impl Comparable<$b> for $a {}
564 impl Comparable<$b> for crate::scope::Nullable<$a> {}
565 impl Comparable<crate::scope::Nullable<$b>> for $a {}
566 impl Comparable<crate::scope::Nullable<$b>> for crate::scope::Nullable<$a> {}
567 )+
568 };
569}
570comparable_across!(
571 Integer => BigInt,
572 BigInt => Integer,
573 Integer => Real,
574 Real => Integer,
575 BigInt => Real,
576 Real => BigInt,
577);
578
579macro_rules! assigns_across {
580 ($($from:ty => $to:ty),+ $(,)?) => {
581 $(
582 impl AssignsTo<$to> for $from {}
583 impl AssignsTo<crate::scope::Nullable<$to>> for $from {}
584 impl AssignsTo<crate::scope::Nullable<$to>> for crate::scope::Nullable<$from> {}
585 )+
586 };
587}
588assigns_across!(
591 Integer => BigInt,
592 Integer => Real,
593 BigInt => Real,
594);
595
596#[cfg(feature = "decimal")]
597assigns_across!(
598 Integer => Numeric,
599 BigInt => Numeric,
600 Real => Numeric,
601);
602
603#[cfg(feature = "decimal")]
607comparable_across!(
608 Numeric => Integer,
609 Integer => Numeric,
610 Numeric => BigInt,
611 BigInt => Numeric,
612 Numeric => Real,
613 Real => Numeric,
614);
615
616pub trait LabelKey: crate::row::Spelled + Copy + 'static {}
620
621pub type Declared<Req, S> = Keyed<crate::row::Anon, Req, S>;
626
627impl<Req, S: SqlType> Expr<Req, S> {
628 pub fn decodes_as<S2: SqlType>(self) -> Declared<Req, S2> {
632 Keyed {
633 kind: self.kind,
634 _marker: PhantomData,
635 }
636 }
637}
638
639pub struct Labeled<K, Inner> {
642 pub(crate) inner: Inner,
643 _key: PhantomData<fn() -> K>,
644}
645
646impl<K, Inner: Clone> Clone for Labeled<K, Inner> {
647 fn clone(&self) -> Self {
648 Labeled::new(self.inner.clone())
649 }
650}
651
652impl<K, Inner> Labeled<K, Inner> {
653 pub(crate) fn new(inner: Inner) -> Self {
654 Labeled {
655 inner,
656 _key: PhantomData,
657 }
658 }
659}
660
661pub trait LabelExt: Sized {
665 fn label<K: LabelKey>(self, _key: K) -> Labeled<K, Self> {
666 Labeled::new(self)
667 }
668}
669impl<C: ColumnKey> LabelExt for Column<C> {}
670impl<K, Req, S: SqlType> LabelExt for Keyed<K, Req, S> {}
671impl<Req, S: SqlType> LabelExt for Expr<Req, S> {}
676
677#[allow(clippy::wrong_self_convention)]
684pub trait ExprMethods: IntoExpr + Sized {
685 fn eq<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
686 where
687 Self::Sql: Comparable<Rhs::Sql>,
688 Self::Req: Concat<Rhs::Req>,
689 {
690 bin_op(BinOp::Eq, self, rhs)
691 }
692
693 fn ne<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
694 where
695 Self::Sql: Comparable<Rhs::Sql>,
696 Self::Req: Concat<Rhs::Req>,
697 {
698 bin_op(BinOp::Ne, self, rhs)
699 }
700
701 fn lt<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
702 where
703 Self::Sql: Comparable<Rhs::Sql>,
704 Self::Req: Concat<Rhs::Req>,
705 {
706 bin_op(BinOp::Lt, self, rhs)
707 }
708
709 fn lte<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
710 where
711 Self::Sql: Comparable<Rhs::Sql>,
712 Self::Req: Concat<Rhs::Req>,
713 {
714 bin_op(BinOp::Lte, self, rhs)
715 }
716
717 fn gt<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
718 where
719 Self::Sql: Comparable<Rhs::Sql>,
720 Self::Req: Concat<Rhs::Req>,
721 {
722 bin_op(BinOp::Gt, self, rhs)
723 }
724
725 fn gte<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
726 where
727 Self::Sql: Comparable<Rhs::Sql>,
728 Self::Req: Concat<Rhs::Req>,
729 {
730 bin_op(BinOp::Gte, self, rhs)
731 }
732
733 fn is_null(self) -> Expr<Self::Req, Bool> {
736 Expr::from_kind(ExprKind::IsNull {
737 expr: Box::new(self.into_expr().kind),
738 negated: false,
739 })
740 }
741
742 fn is_not_null(self) -> Expr<Self::Req, Bool> {
743 Expr::from_kind(ExprKind::IsNull {
744 expr: Box::new(self.into_expr().kind),
745 negated: true,
746 })
747 }
748
749 fn and<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
754 where
755 Self::Sql: BoolLike,
756 Rhs::Sql: BoolLike,
757 Self::Req: Concat<Rhs::Req>,
758 {
759 Expr::from_kind(ExprKind::And(
760 Box::new(self.into_expr().kind),
761 Box::new(rhs.into_expr().kind),
762 ))
763 }
764
765 fn or<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
767 where
768 Self::Sql: BoolLike,
769 Rhs::Sql: BoolLike,
770 Self::Req: Concat<Rhs::Req>,
771 {
772 Expr::from_kind(ExprKind::Or(
773 Box::new(self.into_expr().kind),
774 Box::new(rhs.into_expr().kind),
775 ))
776 }
777
778 fn like<Rhs: IntoExpr>(self, rhs: Rhs) -> Expr<<Self::Req as Concat<Rhs::Req>>::Output, Bool>
782 where
783 Self::Sql: TextLike,
784 Rhs::Sql: TextLike,
785 Self::Req: Concat<Rhs::Req>,
786 {
787 bin_op(BinOp::Like, self, rhs)
788 }
789
790 fn is_in<I>(self, values: I) -> Expr<Self::Req, Bool>
797 where
798 I: IntoIterator,
799 I::Item: IntoExpr<Req = Nil>,
800 Self::Sql: Comparable<<I::Item as IntoExpr>::Sql>,
801 {
802 let values: Vec<ExprKind> = values.into_iter().map(|v| v.into_expr().kind).collect();
803 if values.is_empty() {
805 return Expr::from_kind(ExprKind::Always(false));
806 }
807 Expr::from_kind(ExprKind::InList {
808 expr: Box::new(self.into_expr().kind),
809 values,
810 })
811 }
812}
813
814pub fn any_of<Req, C: IntoExpr<Req = Req>>(conds: impl IntoIterator<Item = C>) -> Expr<Req, Bool>
820where
821 C::Sql: BoolLike,
822{
823 combine(conds, false)
824}
825
826pub fn all_of<Req, C: IntoExpr<Req = Req>>(conds: impl IntoIterator<Item = C>) -> Expr<Req, Bool>
829where
830 C::Sql: BoolLike,
831{
832 combine(conds, true)
833}
834
835fn combine<Req, C: IntoExpr<Req = Req>>(
836 conds: impl IntoIterator<Item = C>,
837 all: bool,
838) -> Expr<Req, Bool>
839where
840 C::Sql: BoolLike,
841{
842 Expr::from_kind(fold_conditions(
843 conds.into_iter().map(|c| c.into_expr().kind),
844 all,
845 ))
846}
847
848pub(crate) fn fold_conditions(kinds: impl IntoIterator<Item = ExprKind>, all: bool) -> ExprKind {
853 let mut folded: Option<ExprKind> = None;
854 for kind in kinds {
855 folded = Some(match folded {
856 None => kind,
857 Some(acc) if all => ExprKind::And(Box::new(acc), Box::new(kind)),
858 Some(acc) => ExprKind::Or(Box::new(acc), Box::new(kind)),
859 });
860 }
861 folded.unwrap_or(ExprKind::Always(all))
862}
863
864impl<T: IntoExpr> ExprMethods for T {}
865
866fn bin_op<Lhs, Rhs>(
867 op: BinOp,
868 lhs: Lhs,
869 rhs: Rhs,
870) -> Expr<<Lhs::Req as Concat<Rhs::Req>>::Output, Bool>
871where
872 Lhs: IntoExpr,
873 Rhs: IntoExpr,
874 Lhs::Req: Concat<Rhs::Req>,
875{
876 Expr::from_kind(ExprKind::BinOp {
877 op,
878 lhs: Box::new(lhs.into_expr().kind),
879 rhs: Box::new(rhs.into_expr().kind),
880 })
881}
882
883#[diagnostic::on_unimplemented(
887 message = "`LIKE` needs a text expression, and `{Self}` isn't one",
888 label = "only `Text` and `Nullable<Text>` columns and expressions accept `.like(..)`"
889)]
890pub trait TextLike: SqlType {}
891
892impl TextLike for Text {}
893impl TextLike for crate::scope::Nullable<Text> {}
894
895#[diagnostic::on_unimplemented(
899 message = "a condition has to be a boolean expression, and `{Self}` isn't one",
900 label = "expected `Bool` or `Nullable<Bool>`"
901)]
902pub trait BoolLike: SqlType {}
903
904impl BoolLike for Bool {}
905impl BoolLike for crate::scope::Nullable<Bool> {}
906
907impl<Req, S: BoolLike> std::ops::Not for Expr<Req, S> {
913 type Output = Expr<Req, S>;
914 fn not(self) -> Self::Output {
915 Expr::from_kind(ExprKind::Not(Box::new(self.kind)))
916 }
917}
918
919impl<K, Req, S: BoolLike> std::ops::Not for Keyed<K, Req, S> {
920 type Output = Keyed<K, Req, S>;
921 fn not(self) -> Self::Output {
922 Keyed::from_kind(ExprKind::Not(Box::new(self.kind)))
923 }
924}
925
926impl<C: ColumnKey> std::ops::Not for Column<C>
927where
928 C::Sql: BoolLike,
929{
930 type Output = Expr<Cons<C::Table, Nil>, C::Sql>;
931 fn not(self) -> Self::Output {
932 Expr::from_kind(ExprKind::Not(Box::new(self.into_expr().kind)))
933 }
934}
935
936pub trait NullValue: SqlType {
939 const NULL_VALUE: Value;
940}
941
942pub fn null<S: NullValue>() -> Expr<Nil, crate::scope::Nullable<S>> {
947 Expr::from_kind(ExprKind::Value(S::NULL_VALUE))
948}
949
950mod raw_arg {
956 pub trait Sealed {}
961 impl<T: super::IntoExpr> Sealed for T {}
962}
963
964macro_rules! sql_leaf_type {
965 ($name:ident, $native:ty, $null_variant:ident) => {
966 pub struct $name;
967
968 impl sql_type::Sealed for $name {}
969
970 impl SqlType for $name {
971 type Native = $native;
972 }
973
974 impl crate::scope::wrap::Sealed<MaybeNull> for $name {}
975
976 impl crate::scope::WrapNullable<MaybeNull> for $name {
977 type Output = crate::scope::Nullable<$name>;
978 }
979
980 impl IntoExpr for $native {
981 type Sql = $name;
982 type Req = Nil;
983 fn into_expr(self) -> Expr<Nil, $name> {
984 Expr::from_kind(ExprKind::Value(Value::from(self)))
985 }
986 }
987
988 impl crate::select::SingleColumn for $native {}
989 impl crate::select::SingleColumn for ::std::option::Option<$native> {}
990
991 impl NullValue for $name {
992 const NULL_VALUE: Value = Value::$null_variant;
993 }
994
995 impl crate::insert::IntoColumnValue<$native> for $native {
996 fn into_column_value(self) -> $native {
997 self
998 }
999 }
1000
1001 impl crate::insert::IntoColumnValue<::std::option::Option<$native>> for $native {
1002 fn into_column_value(self) -> ::std::option::Option<$native> {
1003 ::std::option::Option::Some(self)
1004 }
1005 }
1006
1007 impl crate::insert::IntoColumnValue<::std::option::Option<$native>>
1008 for ::std::option::Option<$native>
1009 {
1010 fn into_column_value(self) -> ::std::option::Option<$native> {
1011 self
1012 }
1013 }
1014
1015 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<$native>> for $native {
1016 fn into_column_value(self) -> crate::insert::Defaultable<$native> {
1017 crate::insert::Defaultable::Value(self)
1018 }
1019 }
1020
1021 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<$native>>
1022 for ::std::option::Option<$native>
1023 {
1024 fn into_column_value(self) -> crate::insert::Defaultable<$native> {
1025 match self {
1026 ::std::option::Option::Some(v) => crate::insert::Defaultable::Value(v),
1027 ::std::option::Option::None => crate::insert::Defaultable::Default,
1028 }
1029 }
1030 }
1031
1032 impl
1033 crate::insert::IntoColumnValue<
1034 crate::insert::Defaultable<::std::option::Option<$native>>,
1035 > for $native
1036 {
1037 fn into_column_value(
1038 self,
1039 ) -> crate::insert::Defaultable<::std::option::Option<$native>> {
1040 crate::insert::Defaultable::Value(::std::option::Option::Some(self))
1041 }
1042 }
1043
1044 impl
1045 crate::insert::IntoColumnValue<
1046 crate::insert::Defaultable<::std::option::Option<$native>>,
1047 > for ::std::option::Option<$native>
1048 {
1049 fn into_column_value(
1050 self,
1051 ) -> crate::insert::Defaultable<::std::option::Option<$native>> {
1052 match self {
1053 ::std::option::Option::Some(v) => {
1054 crate::insert::Defaultable::Value(::std::option::Option::Some(v))
1055 }
1056 ::std::option::Option::None => crate::insert::Defaultable::Default,
1057 }
1058 }
1059 }
1060
1061 impl raw_arg::Sealed for ::std::option::Option<$native> {}
1062
1063 impl RawArg for ::std::option::Option<$native> {
1064 type Req = Nil;
1065 fn into_raw_arg(self) -> RawSlot {
1066 RawSlot(ExprKind::Value(Value::from(self)))
1067 }
1068 }
1069
1070 impl crate::row::SameShape<$native> for $native {}
1071 impl crate::row::SameShape<::std::option::Option<$native>>
1072 for ::std::option::Option<$native>
1073 {
1074 }
1075
1076 impl From<::std::option::Option<$native>> for Value {
1079 fn from(v: ::std::option::Option<$native>) -> Self {
1080 match v {
1081 ::std::option::Option::Some(x) => Value::from(x),
1082 ::std::option::Option::None => Value::$null_variant,
1083 }
1084 }
1085 }
1086 };
1087}
1088
1089sql_leaf_type!(Integer, i32, NullI32);
1090sql_leaf_type!(BigInt, i64, NullI64);
1091sql_leaf_type!(Real, f64, NullF64);
1092sql_leaf_type!(Text, String, NullText);
1093sql_leaf_type!(Bool, bool, NullBool);
1094sql_leaf_type!(Bytes, Vec<u8>, NullBytes);
1095
1096sql_leaf_type!(TextArray, Vec<String>, NullTextArray);
1106sql_leaf_type!(IntegerArray, Vec<i32>, NullIntegerArray);
1107sql_leaf_type!(BigIntArray, Vec<i64>, NullBigIntArray);
1108#[cfg(feature = "uuid")]
1109sql_leaf_type!(UuidArray, Vec<uuid::Uuid>, NullUuidArray);
1110
1111#[cfg(feature = "json")]
1122sql_leaf_type!(Json, serde_json::Value, NullJson);
1123
1124#[cfg(feature = "chrono")]
1128sql_leaf_type!(Timestamptz, chrono::DateTime<chrono::Utc>, NullTimestamptz);
1129#[cfg(feature = "chrono")]
1130sql_leaf_type!(Date, chrono::NaiveDate, NullDate);
1131#[cfg(feature = "uuid")]
1132sql_leaf_type!(Uuid, uuid::Uuid, NullUuid);
1133#[cfg(feature = "decimal")]
1134sql_leaf_type!(Numeric, rust_decimal::Decimal, NullNumeric);
1135
1136impl IntoExpr for &String {
1139 type Sql = Text;
1140 type Req = Nil;
1141 fn into_expr(self) -> Expr<Nil, Text> {
1142 Expr::from_kind(ExprKind::Value(Value::Text(self.clone())))
1143 }
1144}
1145
1146impl IntoExpr for &str {
1147 type Sql = Text;
1148 type Req = Nil;
1149 fn into_expr(self) -> Expr<Nil, Text> {
1150 Expr::from_kind(ExprKind::Value(Value::Text(self.to_string())))
1151 }
1152}
1153
1154macro_rules! text_column_value {
1157 ($borrowed:ty) => {
1158 impl crate::insert::IntoColumnValue<String> for $borrowed {
1159 fn into_column_value(self) -> String {
1160 self.to_string()
1161 }
1162 }
1163
1164 impl crate::insert::IntoColumnValue<Option<String>> for $borrowed {
1165 fn into_column_value(self) -> Option<String> {
1166 Some(self.to_string())
1167 }
1168 }
1169
1170 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<String>> for $borrowed {
1171 fn into_column_value(self) -> crate::insert::Defaultable<String> {
1172 crate::insert::Defaultable::Value(self.to_string())
1173 }
1174 }
1175
1176 impl crate::insert::IntoColumnValue<crate::insert::Defaultable<Option<String>>>
1177 for $borrowed
1178 {
1179 fn into_column_value(self) -> crate::insert::Defaultable<Option<String>> {
1180 crate::insert::Defaultable::Value(Some(self.to_string()))
1181 }
1182 }
1183 };
1184}
1185
1186text_column_value!(&str);
1187text_column_value!(&String);
1188
1189impl<S: SqlType> sql_type::Sealed for crate::scope::Nullable<S> {}
1190
1191impl<S: SqlType> SqlType for crate::scope::Nullable<S> {
1192 type Native = Option<S::Native>;
1193}
1194
1195crate::row::expr_key!(
1196 Count,
1197 HasCount,
1198 count,
1199 "The identity a selected `count(*)` is filed under in a row.",
1200 'c',
1201 'o',
1202 'u',
1203 'n',
1204 't'
1205);
1206
1207pub(crate) fn count_item() -> crate::render::SelectItem {
1209 crate::render::SelectItem::bare(count_star())
1210}
1211
1212fn count_star() -> ExprKind {
1213 ExprKind::Func {
1214 name: "count",
1215 arg: None,
1216 }
1217}
1218
1219pub fn count() -> Keyed<Count, Nil, BigInt> {
1222 Keyed::from_kind(count_star())
1223}
1224
1225#[diagnostic::on_unimplemented(
1233 message = "`min`/`max` need an ordered expression, and `{Self}` isn't one",
1234 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"
1235)]
1236pub trait Ordered: SqlType + WrapNullable<MaybeNull> {}
1237
1238impl Ordered for Integer {}
1239impl Ordered for BigInt {}
1240impl Ordered for Real {}
1241impl Ordered for Text {}
1242#[cfg(feature = "decimal")]
1243impl Ordered for Numeric {}
1244#[cfg(feature = "chrono")]
1245impl Ordered for Timestamptz {}
1246#[cfg(feature = "chrono")]
1247impl Ordered for Date {}
1248
1249impl<S: Ordered> Ordered for crate::scope::Nullable<S> {}
1252
1253#[diagnostic::on_unimplemented(
1259 message = "`sum`/`avg` need a numeric expression, and `{Self}` isn't one",
1260 label = "only `Integer`, `BigInt` and `Real` columns and expressions (and `Numeric`, with the `decimal` feature) can be summed or averaged"
1261)]
1262pub trait Summable: SqlType {
1263 type Sum: SqlType;
1264 const SUM_CAST: Option<CastTarget>;
1265 const AVG_CAST: Option<CastTarget> = Some(CastTarget::Double);
1266}
1267impl Summable for Integer {
1268 type Sum = crate::scope::Nullable<BigInt>;
1269 const SUM_CAST: Option<CastTarget> = None;
1270}
1271impl Summable for BigInt {
1272 type Sum = crate::scope::Nullable<BigInt>;
1273 const SUM_CAST: Option<CastTarget> = Some(CastTarget::BigInt);
1274}
1275impl Summable for Real {
1276 type Sum = crate::scope::Nullable<Real>;
1277 const SUM_CAST: Option<CastTarget> = None;
1278 const AVG_CAST: Option<CastTarget> = None;
1279}
1280#[cfg(feature = "decimal")]
1283impl Summable for Numeric {
1284 type Sum = crate::scope::Nullable<Numeric>;
1285 const SUM_CAST: Option<CastTarget> = None;
1286 const AVG_CAST: Option<CastTarget> = Some(CastTarget::Double);
1287}
1288impl<T: Summable> Summable for crate::scope::Nullable<T> {
1289 type Sum = T::Sum;
1290 const SUM_CAST: Option<CastTarget> = T::SUM_CAST;
1291 const AVG_CAST: Option<CastTarget> = T::AVG_CAST;
1292}
1293
1294pub struct Agg<Op, C>(PhantomData<fn() -> (Op, C)>);
1298
1299#[doc(hidden)]
1306impl<Op, C: crate::row::Named> crate::row::NamedSealed for Agg<Op, C> {}
1307
1308#[doc(hidden)]
1309impl<Op: 'static, C: crate::row::Named + 'static> crate::row::Named for Agg<Op, C> {
1310 type Name = <C as crate::row::Named>::Name;
1311 const NAME: &'static str = <C as crate::row::Named>::NAME;
1312}
1313
1314#[doc(hidden)]
1315impl<Op: 'static, C: crate::row::Spelled + 'static> crate::row::Spelled for Agg<Op, C> {}
1316
1317fn aggregate_kind<C: ColumnKey>(name: &'static str, cast: Option<CastTarget>) -> ExprKind {
1318 let call = ExprKind::Func {
1319 name,
1320 arg: Some(Box::new(ExprKind::Column {
1321 table: <C::Table as Table>::NAME,
1322 name: <C as crate::row::Named>::NAME,
1323 })),
1324 };
1325 match cast {
1326 Some(target) => ExprKind::Cast {
1327 expr: Box::new(call),
1328 target,
1329 },
1330 None => call,
1331 }
1332}
1333
1334macro_rules! aggregate {
1335 ($op:ident, $func:ident, $sql:literal, $out:ty, $bound:path, $cast:expr, $doc:literal) => {
1336 #[doc = $doc]
1337 pub struct $op;
1338
1339 #[doc = $doc]
1340 pub fn $func<C: ColumnKey>(
1341 _column: Column<C>,
1342 ) -> Keyed<Agg<$op, C>, Cons<C::Table, Nil>, $out>
1343 where
1344 C::Sql: $bound,
1345 $out: SqlType,
1346 {
1347 Keyed::from_kind(aggregate_kind::<C>($sql, $cast))
1348 }
1349 };
1350}
1351
1352aggregate!(
1353 Sum,
1354 sum,
1355 "sum",
1356 <C::Sql as Summable>::Sum,
1357 Summable,
1358 <C::Sql as Summable>::SUM_CAST,
1359 "`sum(column)`. NULL over zero rows, so the result is always nullable."
1360);
1361aggregate!(
1362 Min,
1363 min,
1364 "min",
1365 <C::Sql as WrapNullable<MaybeNull>>::Output,
1366 Ordered,
1367 None,
1368 "`min(column)`. NULL over zero rows."
1369);
1370aggregate!(
1371 Max,
1372 max,
1373 "max",
1374 <C::Sql as WrapNullable<MaybeNull>>::Output,
1375 Ordered,
1376 None,
1377 "`max(column)`. NULL over zero rows."
1378);
1379aggregate!(
1380 Avg,
1381 avg,
1382 "avg",
1383 crate::scope::Nullable<Real>,
1384 Summable,
1385 <C::Sql as Summable>::AVG_CAST,
1386 "`avg(column)`. NULL over zero rows."
1387);
1388aggregate!(
1389 CountOf,
1390 count_of,
1391 "count",
1392 BigInt,
1393 SqlType,
1394 None,
1395 "`count(column)` — non-NULL values, unlike `count()`'s `count(*)` rows."
1396);
1397
1398#[diagnostic::on_unimplemented(
1404 message = "`string_agg` concatenates text, and `{Self}` isn't text",
1405 label = "reach for a cast, or a raw fragment, in front of a column that isn't"
1406)]
1407pub trait Concatenable: SqlType {}
1408
1409impl Concatenable for Text {}
1410
1411impl<S: Concatenable> Concatenable for crate::scope::Nullable<S> {}
1414
1415pub struct StringAgg;
1438
1439pub fn string_agg<C: ColumnKey>(
1441 _column: Column<C>,
1442 separator: &'static str,
1443) -> Keyed<Agg<StringAgg, C>, Cons<C::Table, Nil>, crate::scope::Nullable<Text>>
1444where
1445 C::Sql: Concatenable,
1446{
1447 Keyed::from_kind(ExprKind::StringAgg {
1448 arg: Box::new(ExprKind::Column {
1449 table: <C::Table as Table>::NAME,
1450 name: <C as crate::row::Named>::NAME,
1451 }),
1452 separator,
1453 })
1454}
1455
1456pub trait RawArg: raw_arg::Sealed {
1461 type Req;
1462 #[doc(hidden)]
1463 fn into_raw_arg(self) -> RawSlot;
1464}
1465
1466impl<T: IntoExpr> RawArg for T {
1467 type Req = T::Req;
1468 fn into_raw_arg(self) -> RawSlot {
1469 RawSlot(self.into_expr().kind)
1470 }
1471}
1472
1473pub struct RawSlot(ExprKind);
1477
1478impl RawSlot {
1479 fn into_kind(self) -> ExprKind {
1480 self.0
1481 }
1482}
1483
1484#[diagnostic::on_unimplemented(
1487 message = "a `sql!` fragment takes at most 8 `?` slots",
1488 label = "split the fragment, or fold part of it into the builder"
1489)]
1490pub trait RawArgs {
1491 type Req;
1492 #[doc(hidden)]
1493 fn into_raw_args(self) -> Vec<RawSlot>;
1494}
1495
1496impl RawArgs for () {
1497 type Req = Nil;
1498 fn into_raw_args(self) -> Vec<RawSlot> {
1499 Vec::new()
1500 }
1501}
1502
1503macro_rules! raw_args_tuple {
1504 ($head:ident $(, $rest:ident)*) => {
1505 #[allow(non_snake_case)]
1506 impl<$head: RawArg $(, $rest: RawArg)*> RawArgs for ($head, $($rest,)*)
1507 where
1508 ($($rest,)*): RawArgs,
1509 $head::Req: Concat<<($($rest,)*) as RawArgs>::Req>,
1510 {
1511 type Req = <$head::Req as Concat<<($($rest,)*) as RawArgs>::Req>>::Output;
1512 fn into_raw_args(self) -> Vec<RawSlot> {
1513 let ($head, $($rest,)*) = self;
1514 let mut kinds = ::std::vec![RawArg::into_raw_arg($head)];
1515 kinds.extend(RawArgs::into_raw_args(($($rest,)*)));
1516 kinds
1517 }
1518 }
1519 };
1520}
1521raw_args_tuple!(A);
1522raw_args_tuple!(A, B);
1523raw_args_tuple!(A, B, C);
1524raw_args_tuple!(A, B, C, D);
1525raw_args_tuple!(A, B, C, D, E);
1526raw_args_tuple!(A, B, C, D, E, F);
1527raw_args_tuple!(A, B, C, D, E, F, G);
1528raw_args_tuple!(A, B, C, D, E, F, G, H);
1529
1530#[doc(hidden)]
1534pub const fn placeholder_count(sql: &str) -> usize {
1535 let bytes = sql.as_bytes();
1536 let mut i = 0;
1537 let mut count = 0;
1538 while i < bytes.len() {
1539 if bytes[i] == b'?' {
1540 count += 1;
1541 }
1542 i += 1;
1543 }
1544 count
1545}
1546
1547#[doc(hidden)]
1552pub fn raw_expr<S: SqlType, Args: RawArgs>(
1553 sql: &'static str,
1554 args: Args,
1555) -> Declared<Args::Req, S> {
1556 Keyed::from_kind(template(sql, args.into_raw_args()))
1557}
1558
1559fn template(sql: &'static str, args: Vec<RawSlot>) -> ExprKind {
1563 let mut pieces: Vec<String> = vec![String::new()];
1564 for c in sql.chars() {
1565 match c {
1566 '?' => pieces.push(String::new()),
1567 c => pieces.last_mut().expect("one piece to start").push(c),
1568 }
1569 }
1570
1571 let mut pieces = pieces.into_iter();
1572 let head = pieces.next().unwrap_or_default();
1573 let rest = args
1574 .into_iter()
1575 .map(RawSlot::into_kind)
1576 .zip(pieces)
1577 .collect();
1578 ExprKind::Template { head, rest }
1579}
1580
1581#[doc(hidden)]
1588pub fn placeholder<S: SqlType>(name: &'static str) -> Expr<Nil, S> {
1589 Expr::from_kind(ExprKind::Value(Value::Placeholder(name)))
1590}