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