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, JoinableTable, MyAlias, Scope},
13 ast::{MySelect, Source},
14 db::{TableRow, TableRowInner},
15 mutable::Mutable,
16 mymap::MyMap,
17 private::IntoJoinable,
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, MyAlias>,
30}
31
32impl ValueBuilder {
33 pub(crate) fn get_aggr(
34 &mut self,
35 aggr: Rc<SelectStatement>,
36 conds: Vec<MyTableRef>,
37 ) -> MyAlias {
38 let source = Source {
39 kind: crate::ast::SourceKind::Aggregate(aggr),
40 conds: conds
41 .into_iter()
42 .enumerate()
43 .map(|(idx, join)| {
44 (
45 Field::U64(MyAlias::new(idx)),
46 sea_query::Expr::col((self.get_table(join), Alias::new("id"))),
47 )
48 })
49 .collect(),
50 };
51 let new_alias = || self.scope.new_alias();
52 *self.extra.get_or_init(source, new_alias)
53 }
54
55 pub(crate) fn get_join<T: Table>(
56 &mut self,
57 expr: sea_query::Expr,
58 possible_null: bool,
59 ) -> MyAlias {
60 let join_type = if possible_null {
61 JoinType::LeftJoin
62 } else {
63 JoinType::Join
64 };
65 let source = Source {
66 kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), join_type),
67 conds: vec![(Field::Str(T::ID), expr)],
68 };
69 let new_alias = || self.scope.new_alias();
70
71 *self.extra.get_or_init(source, new_alias)
74 }
75
76 pub fn get_unique<T: Table>(
77 &mut self,
78 conds: Box<[(&'static str, sea_query::Expr)]>,
79 ) -> sea_query::Expr {
80 let source = Source {
81 kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), JoinType::LeftJoin),
82 conds: conds.into_iter().map(|x| (Field::Str(x.0), x.1)).collect(),
83 };
84
85 let new_alias = || self.scope.new_alias();
86 let table = self.extra.get_or_init(source, new_alias);
87 sea_query::Expr::col((*table, Alias::new(T::ID))).into()
88 }
89
90 pub fn get_table(&mut self, table: MyTableRef) -> MyAlias {
91 if Rc::ptr_eq(&self.from.scope_rc, &table.scope_rc) {
92 MyAlias::new(table.idx)
93 } else {
94 *self.forwarded.get_or_init(table, || self.scope.new_alias())
95 }
96 }
97}
98
99#[derive(Clone)]
103pub struct MyTableRef {
104 pub(crate) scope_rc: Rc<()>,
107 pub(crate) idx: usize,
108 pub(crate) table_name: JoinableTable,
109}
110
111impl PartialEq for MyTableRef {
112 fn eq(&self, other: &Self) -> bool {
113 Rc::ptr_eq(&self.scope_rc, &other.scope_rc) && self.idx == other.idx
114 }
115}
116
117pub trait NumTyp: OrdTyp + Clone + Copy {
118 const ZERO: Self;
119 fn into_sea_value(self) -> sea_query::Value;
120}
121
122impl NumTyp for i64 {
123 const ZERO: Self = 0;
124 fn into_sea_value(self) -> sea_query::Value {
125 sea_query::Value::BigInt(Some(self))
126 }
127}
128impl NumTyp for f64 {
129 const ZERO: Self = 0.;
130 fn into_sea_value(self) -> sea_query::Value {
131 sea_query::Value::Double(Some(self))
132 }
133}
134
135pub trait OrdTyp: EqTyp {}
136impl OrdTyp for String {}
137impl OrdTyp for Vec<u8> {}
138impl OrdTyp for i64 {}
139impl OrdTyp for f64 {}
140impl OrdTyp for bool {}
141
142pub trait BuffTyp: MyTyp {}
143impl BuffTyp for String {}
144impl BuffTyp for Vec<u8> {}
145
146#[diagnostic::on_unimplemented(
147 message = "Columns with type `{Self}` can not be checked for equality",
148 note = "`EqTyp` is also implemented for all table types"
149)]
150pub trait EqTyp: MyTyp {}
151
152impl EqTyp for String {}
153impl EqTyp for Vec<u8> {}
154impl EqTyp for i64 {}
155impl EqTyp for f64 {}
156impl EqTyp for bool {}
157#[diagnostic::do_not_recommend]
158impl<T: Table> EqTyp for T {}
159
160pub trait Typed {
162 type Typ;
163
164 fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr;
165 fn maybe_optional(&self) -> bool {
166 true
167 }
168
169 fn build_table(&self, b: &mut ValueBuilder) -> MyAlias
170 where
171 Self::Typ: Table,
172 {
173 let expr = self.build_expr(b);
174 b.get_join::<Self::Typ>(expr, self.maybe_optional())
175 }
176}
177
178pub trait IntoExpr<'column, S> {
194 type Typ: MyTyp;
196
197 fn into_expr(self) -> Expr<'column, S, Self::Typ>;
199}
200
201impl<X: MyTyp<Sql: Nullable>> Typed for Option<Rc<dyn Typed<Typ = X>>> {
202 type Typ = Option<X>;
203
204 fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
205 self.as_ref()
206 .map(|x| x.build_expr(b))
207 .unwrap_or(X::Sql::null().into())
208 }
209}
210
211impl<'column, S, T: IntoExpr<'column, S, Typ = X>, X: MyTyp<Sql: Nullable>> IntoExpr<'column, S>
212 for Option<T>
213{
214 type Typ = Option<X>;
215 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
216 Expr::new(self.map(|x| x.into_expr().inner))
217 }
218}
219
220impl Typed for String {
221 type Typ = String;
222 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
223 sea_query::Expr::from(self)
224 }
225}
226
227impl<'column, S> IntoExpr<'column, S> for String {
228 type Typ = String;
229 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
230 Expr::new(self)
231 }
232}
233
234impl<'column, S> IntoExpr<'column, S> for &str {
235 type Typ = String;
236 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
237 Expr::new(self.to_owned())
238 }
239}
240
241impl Typed for Vec<u8> {
242 type Typ = Vec<u8>;
243 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
244 sea_query::Expr::from(self.to_owned())
245 }
246}
247
248impl<'column, S> IntoExpr<'column, S> for Vec<u8> {
249 type Typ = Vec<u8>;
250 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
251 Expr::new(self)
252 }
253}
254
255impl<'column, S> IntoExpr<'column, S> for &[u8] {
256 type Typ = Vec<u8>;
257 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
258 Expr::new(self.to_owned())
259 }
260}
261
262impl Typed for bool {
263 type Typ = bool;
264 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
265 sea_query::Expr::from(*self)
266 }
267}
268
269impl<'column, S> IntoExpr<'column, S> for bool {
270 type Typ = bool;
271 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
272 Expr::new(self)
273 }
274}
275
276impl Typed for i64 {
277 type Typ = i64;
278 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
279 sea_query::Expr::from(*self)
280 }
281}
282
283impl<'column, S> IntoExpr<'column, S> for i64 {
284 type Typ = i64;
285 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
286 Expr::new(self)
287 }
288}
289
290impl Typed for f64 {
291 type Typ = f64;
292 fn build_expr(&self, _: &mut ValueBuilder) -> sea_query::Expr {
293 sea_query::Expr::from(*self)
294 }
295}
296
297impl<'column, S> IntoExpr<'column, S> for f64 {
298 type Typ = f64;
299 fn into_expr(self) -> Expr<'column, S, Self::Typ> {
300 Expr::new(self)
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.clone()), val).into_select()
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.clone()), 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 IntoJoinable<'inner, T::Schema, Typ = T>,
593) -> Expr<'inner, T::Schema, Option<T>> {
594 let list = j.into_joinable().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}