1pub mod aggregate;
2mod operations;
3pub mod optional;
4pub mod trivial;
5
6use std::{cell::OnceCell, fmt::Debug, marker::PhantomData, ops::Deref, rc::Rc};
7
8use sea_query::{Alias, JoinType, Nullable, SelectStatement};
9
10use crate::{
11 Lazy, Select, Table, Transaction,
12 alias::{Field, MyAlias, Scope},
13 ast::{MySelect, Source},
14 db::{Join, TableRow, TableRowInner},
15 mutable::Mutable,
16 mymap::MyMap,
17 private::Joinable,
18 schema::canonical,
19};
20
21#[derive(Default)]
22pub struct ValueBuilder {
23 pub(crate) from: Rc<MySelect>,
24 pub(super) scope: Scope,
26 pub(super) extra: MyMap<Source, MyAlias>,
28 pub(super) forwarded: MyMap<MyTableRef, (&'static str, DynTypedExpr, MyAlias)>,
30}
31
32impl ValueBuilder {
33 pub(crate) fn get_aggr(
34 &mut self,
35 aggr: Rc<SelectStatement>,
36 conds: Vec<sea_query::Expr>,
37 ) -> MyAlias {
38 let source = Source {
39 kind: crate::ast::SourceKind::Aggregate(aggr),
40 conds: conds
41 .into_iter()
42 .enumerate()
43 .map(|(idx, expr)| (Field::U64(MyAlias::new(idx)), expr))
44 .collect(),
45 };
46 let new_alias = || self.scope.new_alias();
47 *self.extra.get_or_init(source, new_alias)
48 }
49
50 pub(crate) fn get_join<T: Table>(
51 &mut self,
52 expr: sea_query::Expr,
53 possible_null: bool,
54 ) -> MyAlias {
55 let join_type = if possible_null {
56 JoinType::LeftJoin
57 } else {
58 JoinType::Join
59 };
60 let source = Source {
61 kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), join_type),
62 conds: vec![(Field::Str(T::ID), expr)],
63 };
64 let new_alias = || self.scope.new_alias();
65 *self.extra.get_or_init(source, new_alias)
66 }
67
68 pub fn get_unique<T: Table>(
69 &mut self,
70 conds: Box<[(&'static str, sea_query::Expr)]>,
71 ) -> sea_query::Expr {
72 let source = Source {
73 kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), JoinType::LeftJoin),
74 conds: conds.into_iter().map(|x| (Field::Str(x.0), x.1)).collect(),
75 };
76
77 let new_alias = || self.scope.new_alias();
78 let table = self.extra.get_or_init(source, new_alias);
79 sea_query::Expr::col((*table, Alias::new(T::ID))).into()
80 }
81
82 pub fn get_table<T: Table>(&mut self, table: MyTableRef) -> MyAlias {
83 if Rc::ptr_eq(&self.from.scope_rc, &table.scope_rc) {
84 MyAlias::new(table.idx)
85 } else {
86 let join = Join::<T>::new(table.clone());
87 self.forwarded
88 .get_or_init(table, || {
89 (
90 T::NAME,
91 DynTypedExpr::new(move |b| join.build_expr(b)),
92 self.scope.new_alias(),
93 )
94 })
95 .2
96 }
97 }
98}
99
100#[derive(Clone)]
101pub struct MyTableRef {
102 pub(crate) scope_rc: Rc<()>,
103 pub(crate) idx: usize,
104}
105
106impl PartialEq for MyTableRef {
107 fn eq(&self, other: &Self) -> bool {
108 Rc::ptr_eq(&self.scope_rc, &other.scope_rc) && self.idx == other.idx
109 }
110}
111
112pub trait NumTyp: OrdTyp + Clone + Copy {
113 const ZERO: Self;
114 fn into_sea_value(self) -> sea_query::Value;
115}
116
117impl NumTyp for i64 {
118 const ZERO: Self = 0;
119 fn into_sea_value(self) -> sea_query::Value {
120 sea_query::Value::BigInt(Some(self))
121 }
122}
123impl NumTyp for f64 {
124 const ZERO: Self = 0.;
125 fn into_sea_value(self) -> sea_query::Value {
126 sea_query::Value::Double(Some(self))
127 }
128}
129
130pub trait OrdTyp: EqTyp {}
131impl OrdTyp for String {}
132impl OrdTyp for Vec<u8> {}
133impl OrdTyp for i64 {}
134impl OrdTyp for f64 {}
135impl OrdTyp for bool {}
136
137pub trait BuffTyp: MyTyp {}
138impl BuffTyp for String {}
139impl BuffTyp for Vec<u8> {}
140
141#[diagnostic::on_unimplemented(
142 message = "Columns with type `{Self}` can not be checked for equality",
143 note = "`EqTyp` is also implemented for all table types"
144)]
145pub trait EqTyp: MyTyp {}
146
147impl EqTyp for String {}
148impl EqTyp for Vec<u8> {}
149impl EqTyp for i64 {}
150impl EqTyp for f64 {}
151impl EqTyp for bool {}
152#[diagnostic::do_not_recommend]
153impl<T: Table> EqTyp for T {}
154
155pub trait Typed {
157 type Typ;
158
159 fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr;
160 fn maybe_optional(&self) -> bool {
161 true
162 }
163
164 fn build_table(&self, b: &mut ValueBuilder) -> MyAlias
165 where
166 Self::Typ: Table,
167 {
168 let expr = self.build_expr(b);
169 b.get_join::<Self::Typ>(expr, self.maybe_optional())
170 }
171}
172
173pub trait IntoExpr<'column, S> {
175 type Typ: MyTyp;
177
178 fn into_expr(self) -> Expr<'column, S, Self::Typ>;
180}
181
182impl<X: MyTyp<Sql: Nullable>> Typed for Option<Rc<dyn Typed<Typ = X>>> {
183 type Typ = Option<X>;
184
185 fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
186 self.as_ref()
187 .map(|x| x.build_expr(b))
188 .unwrap_or(X::Sql::null().into())
189 }
190}
191
192impl<'column, S, T: IntoExpr<'column, S, Typ = X>, X: MyTyp<Sql: Nullable>> IntoExpr<'column, S>
193 for Option<T>
194{
195 type Typ = Option<X>;
196 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
197 Expr::new(self.map(|x| x.into_expr().inner))
198 }
199}
200
201impl Typed for String {
202 type Typ = String;
203 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
204 sea_query::Expr::from(self)
205 }
206}
207
208impl<'column, S> IntoExpr<'column, S> for String {
209 type Typ = String;
210 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
211 Expr::new(self)
212 }
213}
214
215impl<'column, S> IntoExpr<'column, S> for &str {
216 type Typ = String;
217 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
218 Expr::new(self.to_owned())
219 }
220}
221
222impl Typed for Vec<u8> {
223 type Typ = Vec<u8>;
224 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
225 sea_query::Expr::from(self.to_owned())
226 }
227}
228
229impl<'column, S> IntoExpr<'column, S> for Vec<u8> {
230 type Typ = Vec<u8>;
231 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
232 Expr::new(self)
233 }
234}
235
236impl<'column, S> IntoExpr<'column, S> for &[u8] {
237 type Typ = Vec<u8>;
238 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
239 Expr::new(self.to_owned())
240 }
241}
242
243impl Typed for bool {
244 type Typ = bool;
245 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
246 sea_query::Expr::from(*self)
247 }
248}
249
250impl<'column, S> IntoExpr<'column, S> for bool {
251 type Typ = bool;
252 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
253 Expr::new(self)
254 }
255}
256
257impl Typed for i64 {
258 type Typ = i64;
259 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
260 sea_query::Expr::from(*self)
261 }
262}
263
264impl<'column, S> IntoExpr<'column, S> for i64 {
265 type Typ = i64;
266 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
267 Expr::new(self)
268 }
269}
270
271impl Typed for f64 {
272 type Typ = f64;
273 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
274 sea_query::Expr::from(*self)
275 }
276}
277
278impl<'column, S> IntoExpr<'column, S> for f64 {
279 type Typ = f64;
280 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
281 Expr::new(self)
282 }
283}
284
285impl<T> Typed for &T
286where
287 T: Typed,
288{
289 type Typ = T::Typ;
290 fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
291 T::build_expr(self, b)
292 }
293 fn maybe_optional(&self) -> bool {
294 T::maybe_optional(self)
295 }
296 fn build_table(&self, b: &mut ValueBuilder) -> MyAlias
297 where
298 Self::Typ: Table,
299 {
300 T::build_table(self, b)
301 }
302}
303
304impl<'column, S, T> IntoExpr<'column, S> for &T
305where
306 T: IntoExpr<'column, S> + Clone,
307{
308 type Typ = T::Typ;
309 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
310 T::into_expr(self.clone())
311 }
312}
313
314#[derive(Clone, Copy)]
316#[deprecated = "Use `Expr::unix_epoch` instead"]
317pub struct UnixEpoch;
318
319#[expect(deprecated)]
320impl Typed for UnixEpoch {
321 type Typ = i64;
322 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
323 sea_query::Expr::cust("unixepoch('now')").into()
324 }
325}
326
327#[expect(deprecated)]
328impl<'column, S> IntoExpr<'column, S> for UnixEpoch {
329 type Typ = i64;
330 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
331 Expr::new(self)
332 }
333}
334
335pub trait OptTable: MyTyp {
336 type Schema;
337 type Select;
338 type Mutable<'t>;
339 fn select_opt_mutable(
340 val: Expr<'_, Self::Schema, Self>,
341 ) -> Select<'_, Self::Schema, Self::Select>;
342
343 fn into_mutable<'t>(val: Self::Select) -> Self::Mutable<'t>;
344}
345
346impl<T: Table> OptTable for T {
347 type Schema = T::Schema;
348 type Select = (T::Mutable, TableRow<T>);
349 type Mutable<'t> = Mutable<'t, T>;
350 fn select_opt_mutable(
351 val: Expr<'_, Self::Schema, Self>,
352 ) -> Select<'_, Self::Schema, Self::Select> {
353 T::select_mutable(val)
354 }
355
356 fn into_mutable<'t>((inner, row_id): Self::Select) -> Self::Mutable<'t> {
357 Mutable::new(inner, row_id)
358 }
359}
360
361impl<T: Table> OptTable for Option<T> {
362 type Schema = T::Schema;
363 type Select = Option<(T::Mutable, TableRow<T>)>;
364 type Mutable<'t> = Option<Mutable<'t, T>>;
365 fn select_opt_mutable(
366 val: Expr<'_, Self::Schema, Self>,
367 ) -> Select<'_, Self::Schema, Self::Select> {
368 crate::optional(|row| {
369 let val = row.and(val);
370 row.then_select(T::select_mutable(val))
371 })
372 }
373
374 fn into_mutable<'t>(val: Self::Select) -> Self::Mutable<'t> {
375 val.map(T::into_mutable)
376 }
377}
378
379pub trait MyTyp: Sized + 'static {
380 type Prev: MyTyp;
381 const NULLABLE: bool = false;
382 const TYP: canonical::ColumnType;
383 const FK: Option<(&'static str, &'static str)> = None;
384 type Out: SecretFromSql;
385 type Lazy<'t>;
386 type Ext<'t>;
387 type Sql;
388 fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t>;
389}
390
391pub(crate) trait SecretFromSql: Sized {
392 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self>;
393}
394
395#[diagnostic::do_not_recommend]
396impl<T: Table> MyTyp for T {
397 type Prev = T::MigrateFrom;
398 const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
399 const FK: Option<(&'static str, &'static str)> = Some((T::NAME, T::ID));
400 type Out = TableRow<T>;
401 type Lazy<'t> = Lazy<'t, T>;
402 type Ext<'t> = T::Ext2<'t>;
403 type Sql = i64;
404 fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
405 Lazy {
406 id: val,
407 lazy: OnceCell::new(),
408 txn: Transaction::new_ref(),
409 }
410 }
411}
412
413impl<T: Table> SecretFromSql for TableRow<T> {
414 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
415 Ok(TableRow {
416 _local: PhantomData,
417 inner: TableRowInner {
418 _p: PhantomData,
419 idx: value.as_i64()?,
420 },
421 })
422 }
423}
424
425impl MyTyp for i64 {
426 type Prev = Self;
427 const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
428 type Out = Self;
429 type Lazy<'t> = Self;
430 type Ext<'t> = ();
431 type Sql = i64;
432 fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
433 val
434 }
435}
436
437impl SecretFromSql for i64 {
438 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
439 value.as_i64()
440 }
441}
442
443impl MyTyp for f64 {
444 type Prev = Self;
445 const TYP: canonical::ColumnType = canonical::ColumnType::Real;
446 type Out = Self;
447 type Lazy<'t> = Self;
448 type Ext<'t> = ();
449 type Sql = f64;
450 fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
451 val
452 }
453}
454
455impl SecretFromSql for f64 {
456 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
457 value.as_f64()
458 }
459}
460
461impl MyTyp for bool {
462 type Prev = Self;
463 const TYP: canonical::ColumnType = canonical::ColumnType::Integer;
464 type Out = Self;
465 type Lazy<'t> = Self;
466 type Ext<'t> = ();
467 type Sql = bool;
468 fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
469 val
470 }
471}
472
473impl SecretFromSql for bool {
474 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
475 Ok(value.as_i64()? != 0)
476 }
477}
478
479impl MyTyp for String {
480 type Prev = Self;
481 const TYP: canonical::ColumnType = canonical::ColumnType::Text;
482 type Out = Self;
483 type Lazy<'t> = Self;
484 type Ext<'t> = ();
485 type Sql = String;
486 fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
487 val
488 }
489}
490assert_impl_all!(String: Nullable);
491
492impl SecretFromSql for String {
493 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
494 Ok(value.as_str()?.to_owned())
495 }
496}
497
498impl MyTyp for Vec<u8> {
499 type Prev = Self;
500 const TYP: canonical::ColumnType = canonical::ColumnType::Blob;
501 type Out = Self;
502 type Lazy<'t> = Self;
503 type Ext<'t> = ();
504 type Sql = Vec<u8>;
505 fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
506 val
507 }
508}
509assert_impl_all!(Vec<u8>: Nullable);
510
511impl SecretFromSql for Vec<u8> {
512 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
513 Ok(value.as_blob()?.to_owned())
514 }
515}
516
517impl<T: MyTyp> MyTyp for Option<T> {
518 type Prev = Option<T::Prev>;
519 const TYP: canonical::ColumnType = T::TYP;
520 const NULLABLE: bool = true;
521 const FK: Option<(&'static str, &'static str)> = T::FK;
522 type Out = Option<T::Out>;
523 type Lazy<'t> = Option<T::Lazy<'t>>;
524 type Ext<'t> = ();
525 type Sql = T::Sql;
526 fn out_to_lazy<'t>(val: Self::Out) -> Self::Lazy<'t> {
527 val.map(T::out_to_lazy)
528 }
529}
530
531impl<T: SecretFromSql> SecretFromSql for Option<T> {
532 fn from_sql(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
533 if value.data_type() == rusqlite::types::Type::Null {
534 Ok(None)
535 } else {
536 Ok(Some(T::from_sql(value)?))
537 }
538 }
539}
540
541pub struct Expr<'column, S, T: MyTyp> {
549 pub(crate) _local: PhantomData<*const ()>,
550 pub(crate) inner: Rc<dyn Typed<Typ = T>>,
551 pub(crate) _p: PhantomData<&'column ()>,
552 pub(crate) _p2: PhantomData<S>,
553 pub(crate) ext: OnceCell<Box<T::Ext<'static>>>,
554}
555
556impl<S, T: MyTyp> Debug for Expr<'_, S, T> {
557 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
558 write!(f, "Expr of type {}", std::any::type_name::<T>())
559 }
560}
561
562impl<'column, S, T: MyTyp> Expr<'column, S, T> {
563 #[doc(hidden)]
565 pub fn _migrate<OldS>(prev: impl IntoExpr<'column, OldS>) -> Self {
566 Self::new(MigratedExpr {
567 prev: DynTypedExpr::erase(prev),
568 _p: PhantomData,
569 })
570 }
571}
572
573pub fn adhoc_expr<S, T: MyTyp>(
574 f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr,
575) -> Expr<'static, S, T> {
576 Expr::adhoc(f)
577}
578
579pub fn new_column<'x, S, C: MyTyp, T: Table>(
580 table: impl IntoExpr<'x, S, Typ = T>,
581 name: &'static str,
582) -> Expr<'x, S, C> {
583 let table = table.into_expr().inner;
584 let possible_null = table.maybe_optional();
585 Expr::adhoc_promise(
586 move |b| sea_query::Expr::col((table.build_table(b), Field::Str(name))).into(),
587 possible_null,
588 )
589}
590
591pub fn unique_from_joinable<'inner, T: Table>(
592 j: impl Joinable<'inner, Typ = T>,
593) -> Expr<'inner, T::Schema, Option<T>> {
594 let list = j.conds();
595 ::rust_query::private::adhoc_expr(move |_b| {
596 let list = list
597 .iter()
598 .map(|(name, col)| (*name, (col.func)(_b)))
599 .collect();
600 _b.get_unique::<T>(list)
601 })
602}
603
604struct AdHoc<F, T> {
605 func: F,
606 maybe_optional: bool,
607 _p: PhantomData<T>,
608}
609impl<F: Fn(&mut ValueBuilder) -> sea_query::Expr, T> Typed for AdHoc<F, T> {
610 type Typ = T;
611
612 fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
613 (self.func)(b)
614 }
615 fn maybe_optional(&self) -> bool {
616 self.maybe_optional
617 }
618}
619
620impl<S, T: MyTyp> Expr<'_, S, T> {
621 pub(crate) fn adhoc(f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr) -> Self {
622 Self::new(AdHoc {
623 func: f,
624 maybe_optional: true,
625 _p: PhantomData,
626 })
627 }
628
629 pub(crate) fn adhoc_promise(
634 f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr,
635 maybe_optional: bool,
636 ) -> Self {
637 Self::new(AdHoc {
638 func: f,
639 maybe_optional,
640 _p: PhantomData,
641 })
642 }
643
644 pub(crate) fn new(val: impl Typed<Typ = T> + 'static) -> Self {
645 Self {
646 _local: PhantomData,
647 inner: Rc::new(val),
648 _p: PhantomData,
649 _p2: PhantomData,
650 ext: OnceCell::new(),
651 }
652 }
653}
654
655impl<S, T: MyTyp> Clone for Expr<'_, S, T> {
656 fn clone(&self) -> Self {
657 Self {
658 _local: PhantomData,
659 inner: self.inner.clone(),
660 _p: self._p,
661 _p2: self._p2,
662 ext: OnceCell::new(),
663 }
664 }
665}
666
667#[derive(Clone)]
668pub struct DynTypedExpr {
669 pub func: Rc<dyn Fn(&mut ValueBuilder) -> sea_query::Expr>,
670}
671
672impl DynTypedExpr {
673 pub fn new(f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr) -> Self {
674 Self { func: Rc::new(f) }
675 }
676 pub fn erase<'x, S>(expr: impl IntoExpr<'x, S>) -> Self {
677 let typed = expr.into_expr().inner;
678 Self::new(move |b| typed.build_expr(b))
679 }
680}
681
682pub struct MigratedExpr<Typ> {
683 prev: DynTypedExpr,
684 _p: PhantomData<Typ>,
685}
686
687impl<Typ> Typed for MigratedExpr<Typ> {
688 type Typ = Typ;
689 fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
690 (self.prev.func)(b)
691 }
692}
693
694impl<'column, S, T: MyTyp> IntoExpr<'column, S> for Expr<'column, S, T> {
695 type Typ = T;
696 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
697 self
698 }
699}
700
701impl<'t, T: Table> Deref for Expr<'t, T::Schema, T> {
702 type Target = T::Ext2<'t>;
703
704 fn deref(&self) -> &Self::Target {
705 T::covariant_ext(self.ext.get_or_init(|| {
706 let expr = Expr {
707 _local: PhantomData,
708 inner: self.inner.clone(),
709 _p: PhantomData::<&'static ()>,
710 _p2: PhantomData,
711 ext: OnceCell::new(),
712 };
713 Box::new(T::build_ext2(&expr))
714 }))
715 }
716}