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