1pub mod aggregate;
2mod db_typ;
3pub mod from_expr;
4pub mod into_expr;
5#[cfg(feature = "jiff-02")]
6mod jiff_operations;
7mod operations;
8pub mod optional;
9
10use std::{
11 cell::{Cell, OnceCell},
12 fmt::Debug,
13 marker::PhantomData,
14 ops::Deref,
15 rc::Rc,
16};
17
18use crate::{
19 IntoExpr, Table,
20 db::TableRow,
21 lower,
22 mutable::Mutable,
23 private::IntoJoinable,
24 scoped_transaction::{MutTemp, TransactionScope},
25};
26pub use db_typ::{DbTyp, StorableTyp};
27
28pub trait NumTyp: OrdTyp + Clone + Copy {
29 const ZERO: &str;
30}
31
32impl NumTyp for i64 {
33 const ZERO: &str = "0";
34}
35impl NumTyp for f64 {
36 const ZERO: &str = "0.0";
37}
38
39pub trait OrdTyp: EqTyp {}
40impl OrdTyp for String {}
41impl OrdTyp for Vec<u8> {}
42impl OrdTyp for i64 {}
43impl OrdTyp for f64 {}
44impl OrdTyp for bool {}
45#[cfg(feature = "jiff-02")]
46impl OrdTyp for jiff::Timestamp {}
47#[cfg(feature = "jiff-02")]
48impl OrdTyp for jiff::civil::Date {}
49
50pub trait BuffTyp: DbTyp {}
51impl BuffTyp for String {}
52impl BuffTyp for Vec<u8> {}
53
54#[diagnostic::on_unimplemented(
55 message = "Columns with type `{Self}` can not be checked for equality",
56 note = "`EqTyp` is also implemented for all table types"
57)]
58pub trait EqTyp: DbTyp {}
59
60impl EqTyp for String {}
61impl EqTyp for Vec<u8> {}
62impl EqTyp for i64 {}
63impl EqTyp for f64 {}
64impl EqTyp for bool {}
65#[cfg(feature = "jiff-02")]
66impl EqTyp for jiff::Timestamp {}
67#[cfg(feature = "jiff-02")]
68impl EqTyp for jiff::civil::Date {}
69#[diagnostic::do_not_recommend]
70impl<T: Table> EqTyp for TableRow<T> {}
71
72pub trait OptTable: DbTyp {
74 type Schema;
75 type Mutable<'t>;
76
77 fn into_mutable<'t>(
78 txn: &'t mut TransactionScope<Self::Schema>,
79 val: Self,
80 ) -> Self::Mutable<'t>;
81}
82
83impl<T: Table> OptTable for TableRow<T> {
84 type Schema = T::Schema;
85 type Mutable<'t> = Mutable<'t, T>;
86
87 fn into_mutable<'t>(
88 txn: &'t mut TransactionScope<Self::Schema>,
89 inp: Self,
90 ) -> Self::Mutable<'t> {
91 txn.tmp = Cell::new(vec![MutTemp::new(inp)]);
92 Mutable::new(&mut *Cell::get_mut(&mut txn.tmp)[0])
93 }
94}
95
96impl<T: Table> OptTable for Option<TableRow<T>> {
97 type Schema = T::Schema;
98 type Mutable<'t> = Option<Mutable<'t, T>>;
99
100 fn into_mutable<'t>(
101 txn: &'t mut TransactionScope<Self::Schema>,
102 val: Self,
103 ) -> Self::Mutable<'t> {
104 val.map(|x| TableRow::<T>::into_mutable(txn, x))
105 }
106}
107
108pub struct Expr<'column, S, T: DbTyp> {
116 pub(crate) _local: PhantomData<*const ()>,
117 pub(crate) inner: Rc<lower::Expr>,
118 pub(crate) _p: PhantomData<&'column ()>,
119 pub(crate) _p2: PhantomData<S>,
120 pub(crate) ext: OnceCell<Box<T::Ext<'static>>>,
121 pub(crate) not_null_key: bool,
123}
124
125#[cfg_attr(false, mutants::skip)]
126impl<S, T: DbTyp> Debug for Expr<'_, S, T> {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 write!(f, "Expr of type {}", std::any::type_name::<T>())
129 }
130}
131
132impl<'column, S, T: DbTyp> Expr<'column, S, T> {
133 #[doc(hidden)]
135 pub fn _migrate<OldS>(prev: impl IntoExpr<'column, OldS>) -> Self {
136 let prev = prev.into_expr().inner;
137 Self::new(prev)
138 }
139}
140
141pub fn adhoc_expr<S, T: DbTyp>(f: lower::Expr) -> Expr<'static, S, T> {
142 Expr::adhoc(f)
143}
144
145pub fn new_column<'x, S, C: DbTyp, T: Table>(
146 table: impl IntoExpr<'x, S, Typ = TableRow<T>>,
147 name: &'static str,
148) -> Expr<'x, S, C> {
149 let table = table.into_expr();
150 Expr::new_inner(
151 table.inner.col(T::NAME, name, T::ID, table.not_null_key),
152 table.not_null_key && !C::NULLABLE,
153 )
154}
155
156pub fn unique_from_joinable<'inner, T: Table>(
157 j: impl IntoJoinable<'inner, T::Schema, Typ = TableRow<T>>,
158) -> Expr<'inner, T::Schema, Option<TableRow<T>>> {
159 let joinable = j.into_joinable();
160 let unique = Rc::new(lower::Unique {
161 table: joinable.table.name,
162 conds: joinable.conds,
163 guaranteed: false,
164 });
165 Expr::adhoc(lower::Expr::RowIndex(lower::RowLike::Unique(unique), T::ID))
166}
167
168impl<S, T: DbTyp> Expr<'_, S, T> {
169 pub(crate) fn adhoc(e: lower::Expr) -> Self {
170 Self::new(Rc::new(e))
171 }
172
173 pub(crate) fn new(val: Rc<lower::Expr>) -> Self {
174 Self::new_inner(val, false)
175 }
176
177 pub(crate) fn new_inner(val: Rc<lower::Expr>, not_null_key: bool) -> Self {
178 Self {
179 _local: PhantomData,
180 inner: val,
181 _p: PhantomData,
182 _p2: PhantomData,
183 ext: OnceCell::new(),
184 not_null_key,
185 }
186 }
187}
188
189impl<S, T: DbTyp> Clone for Expr<'_, S, T> {
190 fn clone(&self) -> Self {
191 Self {
192 _local: PhantomData,
193 inner: self.inner.clone(),
194 _p: self._p,
195 _p2: self._p2,
196 ext: OnceCell::new(),
197 not_null_key: self.not_null_key,
198 }
199 }
200}
201
202impl<'t, T: Table> Deref for Expr<'t, T::Schema, TableRow<T>> {
203 type Target = T::Ext2<'t>;
204
205 fn deref(&self) -> &Self::Target {
206 T::covariant_ext(self.ext.get_or_init(|| {
207 let expr = Expr {
208 _local: PhantomData,
209 inner: self.inner.clone(),
210 _p: PhantomData::<&'static ()>,
211 _p2: PhantomData,
212 ext: OnceCell::new(),
213 not_null_key: self.not_null_key,
214 };
215 Box::new(T::build_ext2(&expr))
216 }))
217 }
218}