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