1pub mod aggregate;
2mod db_typ;
3pub mod from_expr;
4pub mod into_expr;
5mod operations;
6pub mod optional;
7
8use std::{cell::OnceCell, fmt::Debug, marker::PhantomData, ops::Deref, rc::Rc};
9
10use sea_query::{Alias, JoinType, SelectStatement};
11
12use crate::{
13 IntoExpr, IntoSelect, Select, Table,
14 alias::{Field, JoinableTable, MyAlias, Scope},
15 ast::{MySelect, Source},
16 db::TableRow,
17 mutable::Mutable,
18 mymap::MyMap,
19 private::IntoJoinable,
20};
21pub use db_typ::{DbTyp, StorableTyp};
22
23#[derive(Default)]
24pub struct ValueBuilder {
25 pub(crate) from: Rc<MySelect>,
26 pub(super) scope: Scope,
28 pub(super) extra: MyMap<Source, MyAlias>,
30 pub(super) forwarded: MyMap<MyTableRef, MyAlias>,
32}
33
34impl ValueBuilder {
35 pub(crate) fn get_aggr(
36 &mut self,
37 aggr: Rc<SelectStatement>,
38 conds: Vec<MyTableRef>,
39 ) -> MyAlias {
40 let source = Source {
41 kind: crate::ast::SourceKind::Aggregate(aggr),
42 conds: conds
43 .into_iter()
44 .enumerate()
45 .map(|(idx, join)| {
46 let alias = Alias::new(join.table_name.main_column());
47 (
48 Field::U64(MyAlias::new(idx)),
49 sea_query::Expr::col((self.get_table(join), alias)),
50 )
51 })
52 .collect(),
53 };
54 let new_alias = || self.scope.new_alias();
55 *self.extra.get_or_init(source, new_alias)
56 }
57
58 pub(crate) fn get_join<T: Table>(
59 &mut self,
60 expr: sea_query::Expr,
61 possible_null: bool,
62 new_col: &'static str,
63 ) -> sea_query::Expr {
64 match &expr {
65 sea_query::Expr::Column(sea_query::ColumnRef::Column(sea_query::ColumnName(
69 Some(sea_query::TableName(None, table)),
70 col,
71 ))) => {
72 if let Some(alias) = MyAlias::try_from(table)
74 && let Some(from) = self.from.tables.get(alias.idx)
75 && from.main_column() == col.inner().as_ref()
76 {
77 return sea_query::Expr::col((alias, new_col));
79 }
80 }
81 _ => (),
82 };
83
84 let join_type = if possible_null {
85 JoinType::LeftJoin
86 } else {
87 JoinType::Join
88 };
89 let source = Source {
90 kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), join_type),
91 conds: vec![(Field::Str(T::ID), expr)],
92 };
93 let new_alias = || self.scope.new_alias();
94
95 let alias = *self.extra.get_or_init(source, new_alias);
98
99 sea_query::Expr::col((alias, new_col))
100 }
101
102 pub fn get_unique<T: Table>(
103 &mut self,
104 conds: Box<[(&'static str, sea_query::Expr)]>,
105 ) -> sea_query::Expr {
106 let source = Source {
107 kind: crate::ast::SourceKind::Implicit(T::NAME.to_owned(), JoinType::LeftJoin),
108 conds: conds.into_iter().map(|x| (Field::Str(x.0), x.1)).collect(),
109 };
110
111 let new_alias = || self.scope.new_alias();
112 let table = self.extra.get_or_init(source, new_alias);
113 sea_query::Expr::col((*table, Alias::new(T::ID)))
114 }
115
116 pub fn get_table(&mut self, table: MyTableRef) -> MyAlias {
117 if Rc::ptr_eq(&self.from.scope_rc, &table.scope_rc) {
118 MyAlias::new(table.idx)
119 } else {
120 *self.forwarded.get_or_init(table, || self.scope.new_alias())
121 }
122 }
123}
124
125#[derive(Clone)]
129pub struct MyTableRef {
130 pub(crate) scope_rc: Rc<()>,
133 pub(crate) idx: usize,
134 pub(crate) table_name: JoinableTable,
135}
136
137impl PartialEq for MyTableRef {
138 fn eq(&self, other: &Self) -> bool {
139 Rc::ptr_eq(&self.scope_rc, &other.scope_rc) && self.idx == other.idx
140 }
141}
142
143pub trait NumTyp: OrdTyp + Clone + Copy {
144 const ZERO: sea_query::Value;
145}
146
147impl NumTyp for i64 {
148 const ZERO: sea_query::Value = sea_query::Value::BigInt(Some(0));
149}
150impl NumTyp for f64 {
151 const ZERO: sea_query::Value = sea_query::Value::Double(Some(0.));
152}
153
154pub trait OrdTyp: EqTyp {}
155impl OrdTyp for String {}
156impl OrdTyp for Vec<u8> {}
157impl OrdTyp for i64 {}
158impl OrdTyp for f64 {}
159impl OrdTyp for bool {}
160
161pub trait BuffTyp: DbTyp {}
162impl BuffTyp for String {}
163impl BuffTyp for Vec<u8> {}
164
165#[diagnostic::on_unimplemented(
166 message = "Columns with type `{Self}` can not be checked for equality",
167 note = "`EqTyp` is also implemented for all table types"
168)]
169pub trait EqTyp: DbTyp {}
170
171impl EqTyp for String {}
172impl EqTyp for Vec<u8> {}
173impl EqTyp for i64 {}
174impl EqTyp for f64 {}
175impl EqTyp for bool {}
176#[diagnostic::do_not_recommend]
177impl<T: Table> EqTyp for TableRow<T> {}
178
179pub trait OptTable: DbTyp {
180 type Schema;
181 type Select;
182 type Mutable<'t>;
183 fn select_opt_mutable(
184 val: Expr<'_, Self::Schema, Self>,
185 ) -> Select<'_, Self::Schema, Self::Select>;
186
187 fn into_mutable<'t>(val: Self::Select) -> Self::Mutable<'t>;
188}
189
190impl<T: Table> OptTable for TableRow<T> {
191 type Schema = T::Schema;
192 type Select = (T::Select, TableRow<T>);
193 type Mutable<'t> = Mutable<'t, T>;
194 fn select_opt_mutable(
195 val: Expr<'_, Self::Schema, Self>,
196 ) -> Select<'_, Self::Schema, Self::Select> {
197 (T::into_select(val.clone()), val).into_select()
198 }
199
200 fn into_mutable<'t>((inner, row_id): Self::Select) -> Self::Mutable<'t> {
201 Mutable::new(T::select_mutable(inner), row_id)
202 }
203}
204
205impl<T: Table> OptTable for Option<TableRow<T>> {
206 type Schema = T::Schema;
207 type Select = Option<(T::Select, TableRow<T>)>;
208 type Mutable<'t> = Option<Mutable<'t, T>>;
209 fn select_opt_mutable(
210 val: Expr<'_, Self::Schema, Self>,
211 ) -> Select<'_, Self::Schema, Self::Select> {
212 crate::optional(|row| {
213 let val = row.and(val);
214 row.then_select((T::into_select(val.clone()), val))
215 })
216 }
217
218 fn into_mutable<'t>(val: Self::Select) -> Self::Mutable<'t> {
219 val.map(TableRow::<T>::into_mutable)
220 }
221}
222
223pub struct Expr<'column, S, T: DbTyp> {
231 pub(crate) _local: PhantomData<*const ()>,
232 pub(crate) inner: Rc<AdHoc<dyn Fn(&mut ValueBuilder) -> sea_query::Expr, T>>,
233 pub(crate) _p: PhantomData<&'column ()>,
234 pub(crate) _p2: PhantomData<S>,
235 pub(crate) ext: OnceCell<Box<T::Ext<'static>>>,
236}
237
238impl<S, T: DbTyp> Debug for Expr<'_, S, T> {
239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240 write!(f, "Expr of type {}", std::any::type_name::<T>())
241 }
242}
243
244impl<'column, S, T: DbTyp> Expr<'column, S, T> {
245 #[doc(hidden)]
247 pub fn _migrate<OldS>(prev: impl IntoExpr<'column, OldS>) -> Self {
248 let prev = DynTypedExpr::erase(prev);
249 Self::adhoc(move |b| (prev.func)(b))
250 }
251}
252
253pub fn adhoc_expr<S, T: DbTyp>(
254 f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr,
255) -> Expr<'static, S, T> {
256 Expr::adhoc(f)
257}
258
259pub fn new_column<'x, S, C: DbTyp, T: Table>(
260 table: impl IntoExpr<'x, S, Typ = TableRow<T>>,
261 name: &'static str,
262) -> Expr<'x, S, C> {
263 let table = table.into_expr().inner;
264 let possible_null = table.maybe_optional;
265 Expr::adhoc_promise(
266 move |b| {
267 let main_column = table.build_expr(b);
268 b.get_join::<T>(main_column, table.maybe_optional, name)
269 },
270 possible_null,
271 )
272}
273
274pub fn unique_from_joinable<'inner, T: Table>(
275 j: impl IntoJoinable<'inner, T::Schema, Typ = TableRow<T>>,
276) -> Expr<'inner, T::Schema, Option<TableRow<T>>> {
277 let list = j.into_joinable().conds;
278 ::rust_query::private::adhoc_expr(move |_b| {
279 let list = list
280 .iter()
281 .map(|(name, col)| (*name, (col.func)(_b)))
282 .collect();
283 _b.get_unique::<T>(list)
284 })
285}
286
287pub struct AdHoc<F: ?Sized, T: ?Sized> {
288 maybe_optional: bool,
289 _p: PhantomData<T>,
290 func: F,
291}
292
293impl<F: ?Sized + Fn(&mut ValueBuilder) -> sea_query::Expr, T> AdHoc<F, T> {
294 pub fn build_expr(&self, b: &mut ValueBuilder) -> sea_query::Expr {
295 (self.func)(b)
296 }
297}
298
299impl<S, T: DbTyp> Expr<'_, S, T> {
300 pub(crate) fn adhoc(f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr) -> Self {
301 Self::adhoc_promise(f, true)
302 }
303
304 pub(crate) fn adhoc_promise(
309 f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr,
310 maybe_optional: bool,
311 ) -> Self {
312 Self::new(Rc::new(AdHoc {
313 func: f,
314 maybe_optional,
315 _p: PhantomData,
316 }))
317 }
318
319 pub(crate) fn new(val: Rc<AdHoc<dyn Fn(&mut ValueBuilder) -> sea_query::Expr, T>>) -> Self {
320 Self {
321 _local: PhantomData,
322 inner: val,
323 _p: PhantomData,
324 _p2: PhantomData,
325 ext: OnceCell::new(),
326 }
327 }
328}
329
330impl<S, T: DbTyp> Clone for Expr<'_, S, T> {
331 fn clone(&self) -> Self {
332 Self {
333 _local: PhantomData,
334 inner: self.inner.clone(),
335 _p: self._p,
336 _p2: self._p2,
337 ext: OnceCell::new(),
338 }
339 }
340}
341
342#[derive(Clone)]
343pub struct DynTypedExpr {
344 pub func: Rc<dyn Fn(&mut ValueBuilder) -> sea_query::Expr>,
345}
346
347impl DynTypedExpr {
348 pub fn new(f: impl 'static + Fn(&mut ValueBuilder) -> sea_query::Expr) -> Self {
349 Self { func: Rc::new(f) }
350 }
351 pub fn erase<'x, S>(expr: impl IntoExpr<'x, S>) -> Self {
352 let typed = expr.into_expr().inner;
353 Self::new(move |b| typed.build_expr(b))
354 }
355}
356
357impl<'t, T: Table> Deref for Expr<'t, T::Schema, TableRow<T>> {
358 type Target = T::Ext2<'t>;
359
360 fn deref(&self) -> &Self::Target {
361 T::covariant_ext(self.ext.get_or_init(|| {
362 let expr = Expr {
363 _local: PhantomData,
364 inner: self.inner.clone(),
365 _p: PhantomData::<&'static ()>,
366 _p2: PhantomData,
367 ext: OnceCell::new(),
368 };
369 Box::new(T::build_ext2(&expr))
370 }))
371 }
372}