1pub mod aggregate;
2mod operations;
3pub mod optional;
4pub mod trivial;
5
6use std::{fmt::Debug, marker::PhantomData, ops::Deref, rc::Rc};
7
8use ref_cast::RefCast;
9use sea_query::{Alias, Nullable, SelectStatement, SimpleExpr};
10
11use crate::{
12 IntoSelect, Select, Table,
13 alias::{Field, MyAlias, RawAlias},
14 ast::{MySelect, Source},
15 db::{TableRow, TableRowInner},
16 hash,
17};
18
19#[derive(Clone, Copy)]
20pub struct ValueBuilder<'x> {
21 pub(crate) inner: &'x MySelect,
22}
23
24impl<'x> ValueBuilder<'x> {
25 pub(crate) fn get_aggr(
26 self,
27 aggr: SelectStatement,
28 conds: Vec<(Field, SimpleExpr)>,
29 ) -> MyAlias {
30 let source = Source {
31 kind: crate::ast::SourceKind::Aggregate(aggr),
32 conds,
33 };
34 let new_alias = || self.inner.scope.new_alias();
35 *self.inner.extra.get_or_init(source, new_alias)
36 }
37
38 pub(crate) fn get_join<T: Table>(self, expr: SimpleExpr) -> MyAlias {
39 let source = Source {
40 kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned()),
41 conds: vec![(Field::Str(T::ID), expr)],
42 };
43 let new_alias = || self.inner.scope.new_alias();
44 *self.inner.extra.get_or_init(source, new_alias)
45 }
46
47 pub fn get_unique<T: Table>(self, conds: Vec<(&'static str, SimpleExpr)>) -> SimpleExpr {
48 let source = Source {
49 kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned()),
50 conds: conds.into_iter().map(|x| (Field::Str(x.0), x.1)).collect(),
51 };
52
53 let new_alias = || self.inner.scope.new_alias();
54 let table = self.inner.extra.get_or_init(source, new_alias);
55 sea_query::Expr::col((*table, Alias::new(T::ID))).into()
56 }
57}
58
59pub trait NumTyp: MyTyp + Clone + Copy {
60 const ZERO: Self;
61 fn into_sea_value(self) -> sea_query::Value;
62}
63
64impl NumTyp for i64 {
65 const ZERO: Self = 0;
66 fn into_sea_value(self) -> sea_query::Value {
67 sea_query::Value::BigInt(Some(self))
68 }
69}
70impl NumTyp for f64 {
71 const ZERO: Self = 0.;
72 fn into_sea_value(self) -> sea_query::Value {
73 sea_query::Value::Double(Some(self))
74 }
75}
76
77#[diagnostic::on_unimplemented(
78 message = "Columns with type `{Self}` can not be checked for equality",
79 note = "`EqTyp` is also implemented for all table types"
80)]
81pub trait EqTyp {}
82
83impl EqTyp for String {}
84impl EqTyp for Vec<u8> {}
85impl EqTyp for i64 {}
86impl EqTyp for f64 {}
87impl EqTyp for bool {}
88#[diagnostic::do_not_recommend]
89impl<T: Table> EqTyp for T {}
90
91pub trait Typed {
93 type Typ;
94
95 #[doc(hidden)]
96 fn build_expr(&self, b: ValueBuilder) -> SimpleExpr;
97 #[doc(hidden)]
98 fn build_table(&self, b: ValueBuilder) -> MyAlias
99 where
100 Self::Typ: Table,
101 {
102 b.get_join::<Self::Typ>(self.build_expr(b))
103 }
104}
105
106pub trait IntoExpr<'column, S>: Clone {
108 type Typ: MyTyp;
110
111 fn into_expr(self) -> Expr<'column, S, Self::Typ>;
113}
114
115impl<T: Typed<Typ = X>, X: MyTyp<Sql: Nullable>> Typed for Option<T> {
116 type Typ = Option<T::Typ>;
117
118 fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
119 self.as_ref()
120 .map(|x| T::build_expr(x, b))
121 .unwrap_or(X::Sql::null().into())
122 }
123}
124
125impl<'column, S, T: IntoExpr<'column, S, Typ = X>, X: MyTyp<Sql: Nullable>> IntoExpr<'column, S>
126 for Option<T>
127{
128 type Typ = Option<X>;
129 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
130 Expr::new(self.map(|x| x.into_expr().inner))
131 }
132}
133
134impl Typed for String {
135 type Typ = String;
136 fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
137 SimpleExpr::from(self)
138 }
139}
140
141impl<'column, S> IntoExpr<'column, S> for String {
142 type Typ = String;
143 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
144 Expr::new(self)
145 }
146}
147
148impl<'column, S> IntoExpr<'column, S> for &str {
149 type Typ = String;
150 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
151 Expr::new(self.to_owned())
152 }
153}
154
155impl Typed for Vec<u8> {
156 type Typ = Vec<u8>;
157 fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
158 SimpleExpr::from(self.to_owned())
159 }
160}
161
162impl<'column, S> IntoExpr<'column, S> for Vec<u8> {
163 type Typ = Vec<u8>;
164 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
165 Expr::new(self)
166 }
167}
168
169impl<'column, S> IntoExpr<'column, S> for &[u8] {
170 type Typ = Vec<u8>;
171 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
172 Expr::new(self.to_owned())
173 }
174}
175
176impl Typed for bool {
177 type Typ = bool;
178 fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
179 SimpleExpr::from(*self)
180 }
181}
182
183impl<'column, S> IntoExpr<'column, S> for bool {
184 type Typ = bool;
185 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
186 Expr::new(self)
187 }
188}
189
190impl Typed for i64 {
191 type Typ = i64;
192 fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
193 SimpleExpr::from(*self)
194 }
195}
196
197impl<'column, S> IntoExpr<'column, S> for i64 {
198 type Typ = i64;
199 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
200 Expr::new(self)
201 }
202}
203
204impl Typed for f64 {
205 type Typ = f64;
206 fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
207 SimpleExpr::from(*self)
208 }
209}
210
211impl<'column, S> IntoExpr<'column, S> for f64 {
212 type Typ = f64;
213 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
214 Expr::new(self)
215 }
216}
217
218impl<T> Typed for &T
219where
220 T: Typed,
221{
222 type Typ = T::Typ;
223 fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
224 T::build_expr(self, b)
225 }
226 fn build_table(&self, b: crate::value::ValueBuilder) -> MyAlias
227 where
228 Self::Typ: Table,
229 {
230 T::build_table(self, b)
231 }
232}
233
234impl<'column, S, T> IntoExpr<'column, S> for &T
235where
236 T: IntoExpr<'column, S>,
237{
238 type Typ = T::Typ;
239 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
240 T::into_expr(self.clone())
241 }
242}
243
244#[derive(Clone, Copy)]
246pub struct UnixEpoch;
247
248impl Typed for UnixEpoch {
249 type Typ = i64;
250 fn build_expr(&self, _: ValueBuilder) -> SimpleExpr {
251 sea_query::Expr::col(RawAlias("unixepoch('now')".to_owned())).into()
252 }
253}
254
255impl<'column, S> IntoExpr<'column, S> for UnixEpoch {
256 type Typ = i64;
257 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
258 Expr::new(self)
259 }
260}
261
262pub trait MyTyp: 'static {
263 type Prev: MyTyp;
264 const NULLABLE: bool = false;
265 const TYP: hash::ColumnType;
266 const FK: Option<(&'static str, &'static str)> = None;
267 type Out<'t>: SecretFromSql<'t>;
268 type Sql;
269}
270
271pub(crate) trait SecretFromSql<'t>: Sized {
272 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self>;
273}
274
275#[diagnostic::do_not_recommend]
276impl<T: Table> MyTyp for T {
277 type Prev = T::MigrateFrom;
278 const TYP: hash::ColumnType = hash::ColumnType::Integer;
279 const FK: Option<(&'static str, &'static str)> = Some((T::NAME, T::ID));
280 type Out<'t> = TableRow<'t, Self>;
281 type Sql = i64;
282}
283
284impl<'t, T> SecretFromSql<'t> for TableRow<'t, T> {
285 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
286 Ok(TableRow {
287 _p: PhantomData,
288 _local: PhantomData,
289 inner: TableRowInner {
290 _p: PhantomData,
291 idx: value.as_i64()?,
292 },
293 })
294 }
295}
296
297impl MyTyp for i64 {
298 type Prev = Self;
299 const TYP: hash::ColumnType = hash::ColumnType::Integer;
300 type Out<'t> = Self;
301 type Sql = i64;
302}
303
304impl SecretFromSql<'_> for i64 {
305 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
306 value.as_i64()
307 }
308}
309
310impl MyTyp for f64 {
311 type Prev = Self;
312 const TYP: hash::ColumnType = hash::ColumnType::Float;
313 type Out<'t> = Self;
314 type Sql = f64;
315}
316
317impl SecretFromSql<'_> for f64 {
318 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
319 value.as_f64()
320 }
321}
322
323impl MyTyp for bool {
324 type Prev = Self;
325 const TYP: hash::ColumnType = hash::ColumnType::Integer;
326 type Out<'t> = Self;
327 type Sql = bool;
328}
329
330impl SecretFromSql<'_> for bool {
331 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
332 Ok(value.as_i64()? != 0)
333 }
334}
335
336impl MyTyp for String {
337 type Prev = Self;
338 const TYP: hash::ColumnType = hash::ColumnType::String;
339 type Out<'t> = Self;
340 type Sql = String;
341}
342assert_impl_all!(String: Nullable);
343
344impl SecretFromSql<'_> for String {
345 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
346 Ok(value.as_str()?.to_owned())
347 }
348}
349
350impl MyTyp for Vec<u8> {
351 type Prev = Self;
352 const TYP: hash::ColumnType = hash::ColumnType::Blob;
353 type Out<'t> = Self;
354 type Sql = Vec<u8>;
355}
356assert_impl_all!(Vec<u8>: Nullable);
357
358impl SecretFromSql<'_> for Vec<u8> {
359 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
360 Ok(value.as_blob()?.to_owned())
361 }
362}
363
364impl<T: MyTyp> MyTyp for Option<T> {
365 type Prev = Option<T::Prev>;
366 const TYP: hash::ColumnType = T::TYP;
367 const NULLABLE: bool = true;
368 const FK: Option<(&'static str, &'static str)> = T::FK;
369 type Out<'t> = Option<T::Out<'t>>;
370 type Sql = T::Sql;
371}
372
373impl<'t, T: SecretFromSql<'t>> SecretFromSql<'t> for Option<T> {
374 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
375 if value.data_type() == rusqlite::types::Type::Null {
376 Ok(None)
377 } else {
378 Ok(Some(T::from_sql(value)?))
379 }
380 }
381}
382
383pub struct Expr<'column, S, T> {
391 pub(crate) inner: DynTyped<T>,
392 pub(crate) _p: PhantomData<&'column ()>,
393 pub(crate) _p2: PhantomData<S>,
394}
395
396impl<'column, S, T> Debug for Expr<'column, S, T> {
397 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
398 write!(f, "Expr of type {}", std::any::type_name::<T>())
399 }
400}
401
402impl<'column, S, T: 'static> Expr<'column, S, T> {
403 #[doc(hidden)]
405 pub fn _migrate<OldS>(prev: impl IntoExpr<'column, OldS>) -> Self {
406 Self::new(MigratedExpr {
407 prev: prev.into_expr().inner.erase(),
408 _p: PhantomData,
409 })
410 }
411}
412
413pub fn adhoc_expr<S, T: 'static>(
414 f: impl 'static + Fn(ValueBuilder) -> SimpleExpr,
415) -> Expr<'static, S, T> {
416 Expr::adhoc(f)
417}
418
419pub fn new_column<'x, S, T: 'static>(val: impl Typed<Typ = T> + 'static) -> Expr<'x, S, T> {
420 Expr::new(val)
421}
422
423pub fn assume_expr<S, T: 'static>(e: Expr<S, Option<T>>) -> Expr<S, T> {
424 let inner = e.inner;
425 Expr::adhoc(move |b| inner.build_expr(b))
426}
427
428pub fn new_dummy<'x, S, T: MyTyp>(
429 val: impl Typed<Typ = T> + 'static,
430) -> Select<'x, 'x, S, T::Out<'x>> {
431 IntoSelect::into_select(Expr::new(val))
432}
433
434pub fn into_owned<'x, S, T>(val: impl IntoExpr<'x, S, Typ = T>) -> DynTyped<T> {
435 val.into_expr().inner
436}
437
438struct AdHoc<F, T>(F, PhantomData<T>);
439impl<F: Fn(ValueBuilder) -> SimpleExpr, T> Typed for AdHoc<F, T> {
440 type Typ = T;
441
442 fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
443 (self.0)(b)
444 }
445}
446
447impl<S, T: 'static> Expr<'_, S, T> {
448 pub(crate) fn adhoc(f: impl 'static + Fn(ValueBuilder) -> SimpleExpr) -> Self {
449 Self::new(AdHoc(f, PhantomData))
450 }
451
452 pub(crate) fn new(val: impl Typed<Typ = T> + 'static) -> Self {
453 Self {
454 inner: DynTyped(Rc::new(val)),
455 _p: PhantomData,
456 _p2: PhantomData,
457 }
458 }
459}
460
461impl<'column, S, T> Clone for Expr<'column, S, T> {
462 fn clone(&self) -> Self {
463 Self {
464 inner: self.inner.clone(),
465 _p: self._p.clone(),
466 _p2: self._p2.clone(),
467 }
468 }
469}
470
471impl<'column, S, T: 'static> Typed for Expr<'column, S, T> {
473 type Typ = T;
474
475 fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
476 self.inner.0.as_ref().build_expr(b)
477 }
478
479 fn build_table(&self, b: crate::value::ValueBuilder) -> MyAlias
480 where
481 Self::Typ: Table,
482 {
483 self.inner.0.as_ref().build_table(b)
484 }
485}
486
487pub struct DynTypedExpr(pub(crate) Box<dyn Fn(ValueBuilder) -> SimpleExpr>);
488
489impl<Typ: 'static> DynTyped<Typ> {
490 pub fn erase(self) -> DynTypedExpr {
491 DynTypedExpr(Box::new(move |b| self.build_expr(b)))
492 }
493}
494
495pub struct MigratedExpr<Typ> {
496 prev: DynTypedExpr,
497 _p: PhantomData<Typ>,
498}
499
500impl<Typ> Typed for MigratedExpr<Typ> {
501 type Typ = Typ;
502 fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
503 self.prev.0(b)
504 }
505}
506
507pub struct DynTyped<Typ>(pub(crate) Rc<dyn Typed<Typ = Typ>>);
508
509impl<T> Clone for DynTyped<T> {
510 fn clone(&self) -> Self {
511 Self(self.0.clone())
512 }
513}
514
515impl<Typ: 'static> Typed for DynTyped<Typ> {
516 type Typ = Typ;
517
518 fn build_expr(&self, b: ValueBuilder) -> SimpleExpr {
519 self.0.build_expr(b)
520 }
521
522 fn build_table(&self, b: crate::value::ValueBuilder) -> MyAlias
523 where
524 Self::Typ: Table,
525 {
526 self.0.build_table(b)
527 }
528}
529
530impl<'column, S, T: MyTyp> IntoExpr<'column, S> for Expr<'column, S, T> {
531 type Typ = T;
532 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
533 self
534 }
535}
536
537impl<'column, S, T: Table> Deref for Expr<'column, S, T> {
538 type Target = T::Ext<Self>;
539
540 fn deref(&self) -> &Self::Target {
541 RefCast::ref_cast(self)
542 }
543}