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