1use std::marker::PhantomData;
2
3use sea_query::Iden;
4
5use crate::{
6 Expr,
7 alias::Field,
8 value::{DynTyped, DynTypedExpr, MyTyp, SecretFromSql},
9};
10
11pub(crate) struct Cacher {
13 pub(crate) columns: Vec<DynTypedExpr>,
14}
15
16impl Cacher {
17 pub(crate) fn new() -> Self {
18 Self {
19 columns: Vec::new(),
20 }
21 }
22}
23
24pub struct Cached<T> {
25 pub(crate) idx: usize,
26 _p: PhantomData<T>,
27}
28
29impl<T> Clone for Cached<T> {
30 fn clone(&self) -> Self {
31 *self
32 }
33}
34impl<T> Copy for Cached<T> {}
35
36impl Cacher {
37 pub(crate) fn cache_erased(&mut self, val: DynTypedExpr) -> usize {
38 let idx = self.columns.len();
39 self.columns.push(val);
40 idx
41 }
42}
43
44#[derive(Clone, Copy)]
45pub(crate) struct Row<'x> {
46 pub(crate) row: &'x rusqlite::Row<'x>,
47 pub(crate) fields: &'x [Field],
48}
49
50impl<'x> Row<'x> {
51 pub(crate) fn new(row: &'x rusqlite::Row<'x>, fields: &'x [Field]) -> Self {
52 Self { row, fields }
53 }
54
55 pub fn get<'transaction, T: SecretFromSql<'transaction>>(&self, val: Cached<T>) -> T {
56 let field = self.fields[val.idx];
57 let idx = &*field.to_string();
58 T::from_sql(self.row.get_ref_unwrap(idx)).unwrap()
59 }
60}
61
62pub(crate) trait Prepared {
63 type Out;
64
65 fn call(&mut self, row: Row<'_>) -> Self::Out;
66}
67
68pub struct Select<'columns, 'transaction, S, Out> {
74 pub(crate) inner: DynSelectImpl<'transaction, Out>,
75 pub(crate) _p: PhantomData<&'columns ()>,
76 pub(crate) _p2: PhantomData<S>,
77}
78
79pub struct DynSelectImpl<'transaction, Out> {
80 inner: Box<dyn 'transaction + FnOnce(&mut Cacher) -> DynPrepared<'transaction, Out>>,
81}
82
83impl<'transaction, Out> SelectImpl<'transaction> for DynSelectImpl<'transaction, Out> {
84 type Out = Out;
85 type Prepared = DynPrepared<'transaction, Out>;
86
87 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
88 (self.inner)(cacher)
89 }
90}
91
92pub struct DynPrepared<'transaction, Out> {
93 inner: Box<dyn 'transaction + Prepared<Out = Out>>,
94}
95
96impl<Out> Prepared for DynPrepared<'_, Out> {
97 type Out = Out;
98 fn call(&mut self, row: Row<'_>) -> Self::Out {
99 self.inner.call(row)
100 }
101}
102
103impl<'transaction, S, Out> Select<'_, 'transaction, S, Out> {
104 pub(crate) fn new(val: impl 'transaction + SelectImpl<'transaction, Out = Out>) -> Self {
105 Self {
106 inner: DynSelectImpl {
107 inner: Box::new(|cacher| DynPrepared {
108 inner: Box::new(val.prepare(cacher)),
109 }),
110 },
111 _p: PhantomData,
112 _p2: PhantomData,
113 }
114 }
115}
116
117impl<'columns, 'transaction, S, Out: 'transaction> IntoSelect<'columns, 'transaction, S>
118 for Select<'columns, 'transaction, S, Out>
119{
120 type Out = Out;
121
122 fn into_select(self) -> Select<'columns, 'transaction, S, Self::Out> {
123 self
124 }
125}
126
127pub trait SelectImpl<'transaction> {
128 type Out;
129 #[doc(hidden)]
130 type Prepared: Prepared<Out = Self::Out>;
131 #[doc(hidden)]
132 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared;
133}
134
135pub trait IntoSelect<'columns, 'transaction, S>: Sized {
139 type Out: 'transaction;
141
142 fn into_select(self) -> Select<'columns, 'transaction, S, Self::Out>;
148}
149
150pub trait IntoSelectExt<'columns, 'transaction, S>: IntoSelect<'columns, 'transaction, S> {
152 fn map_select<T>(
157 self,
158 f: impl 'transaction + FnMut(Self::Out) -> T,
159 ) -> Select<'columns, 'transaction, S, T>;
160}
161
162impl<'columns, 'transaction, S, X> IntoSelectExt<'columns, 'transaction, S> for X
163where
164 X: IntoSelect<'columns, 'transaction, S>,
165{
166 fn map_select<T>(
167 self,
168 f: impl 'transaction + FnMut(Self::Out) -> T,
169 ) -> Select<'columns, 'transaction, S, T> {
170 Select::new(MapImpl {
171 dummy: self.into_select().inner,
172 func: f,
173 })
174 }
175}
176
177pub struct MapImpl<D, F> {
182 dummy: D,
183 func: F,
184}
185
186impl<'transaction, D, F, O> SelectImpl<'transaction> for MapImpl<D, F>
187where
188 D: SelectImpl<'transaction>,
189 F: FnMut(D::Out) -> O,
190{
191 type Out = O;
192 type Prepared = MapPrepared<D::Prepared, F>;
193
194 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
195 MapPrepared {
196 inner: self.dummy.prepare(cacher),
197 map: self.func,
198 }
199 }
200}
201
202pub struct MapPrepared<X, M> {
203 inner: X,
204 map: M,
205}
206
207impl<X, M, Out> Prepared for MapPrepared<X, M>
208where
209 X: Prepared,
210 M: FnMut(X::Out) -> Out,
211{
212 type Out = Out;
213
214 fn call(&mut self, row: Row<'_>) -> Self::Out {
215 (self.map)(self.inner.call(row))
216 }
217}
218
219impl Prepared for () {
220 type Out = ();
221
222 fn call(&mut self, _row: Row<'_>) -> Self::Out {}
223}
224
225impl SelectImpl<'_> for () {
226 type Out = ();
227 type Prepared = ();
228
229 fn prepare(self, _cacher: &mut Cacher) -> Self::Prepared {}
230}
231
232impl<'columns, 'transaction, S> IntoSelect<'columns, 'transaction, S> for () {
233 type Out = ();
234
235 fn into_select(self) -> Select<'columns, 'transaction, S, Self::Out> {
236 Select::new(())
237 }
238}
239
240impl<'transaction, T: SecretFromSql<'transaction>> Prepared for Cached<T> {
241 type Out = T;
242
243 fn call(&mut self, row: Row<'_>) -> Self::Out {
244 row.get(*self)
245 }
246}
247
248pub struct ColumnImpl<T> {
249 pub(crate) expr: DynTyped<T>,
250}
251
252impl<'transaction, T: MyTyp> SelectImpl<'transaction> for ColumnImpl<T> {
253 type Out = T::Out<'transaction>;
254 type Prepared = Cached<Self::Out>;
255
256 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
257 Cached {
258 idx: cacher.cache_erased(self.expr.erase()),
259 _p: PhantomData,
260 }
261 }
262}
263
264impl<'columns, 'transaction, S, T> IntoSelect<'columns, 'transaction, S> for Expr<'columns, S, T>
265where
266 T: MyTyp,
267{
268 type Out = T::Out<'transaction>;
269
270 fn into_select(self) -> Select<'columns, 'transaction, S, Self::Out> {
271 Select::new(ColumnImpl { expr: self.inner })
272 }
273}
274
275impl<'columns, 'transaction, S, T> IntoSelect<'columns, 'transaction, S> for &T
276where
277 T: IntoSelect<'columns, 'transaction, S> + Clone,
278{
279 type Out = T::Out;
280
281 fn into_select(self) -> Select<'columns, 'transaction, S, Self::Out> {
282 T::clone(self).into_select()
283 }
284}
285
286impl<'transaction, A, B> Prepared for (A, B)
287where
288 A: Prepared,
289 B: Prepared,
290{
291 type Out = (A::Out, B::Out);
292
293 fn call(&mut self, row: Row<'_>) -> Self::Out {
294 (self.0.call(row), self.1.call(row))
295 }
296}
297
298impl<'transaction, A, B> SelectImpl<'transaction> for (A, B)
299where
300 A: SelectImpl<'transaction>,
301 B: SelectImpl<'transaction>,
302{
303 type Out = (A::Out, B::Out);
304 type Prepared = (A::Prepared, B::Prepared);
305
306 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
307 let prepared_a = self.0.prepare(cacher);
308 let prepared_b = self.1.prepare(cacher);
309 (prepared_a, prepared_b)
310 }
311}
312
313impl<'columns, 'transaction, S, A, B> IntoSelect<'columns, 'transaction, S> for (A, B)
314where
315 A: IntoSelect<'columns, 'transaction, S>,
316 B: IntoSelect<'columns, 'transaction, S>,
317{
318 type Out = (A::Out, B::Out);
319
320 fn into_select(self) -> Select<'columns, 'transaction, S, Self::Out> {
321 Select::new((self.0.into_select().inner, self.1.into_select().inner))
322 }
323}
324
325#[cfg(test)]
326#[allow(unused)]
327mod tests {
328 use crate::IntoExpr;
329
330 use super::*;
331
332 struct User {
333 a: i64,
334 b: String,
335 }
336
337 struct UserSelect<A, B> {
338 a: A,
339 b: B,
340 }
341
342 impl<'columns, 'transaction, S, A, B> IntoSelect<'columns, 'transaction, S> for UserSelect<A, B>
343 where
344 A: IntoExpr<'columns, S, Typ = i64>,
345 B: IntoExpr<'columns, S, Typ = String>,
346 {
347 type Out = User;
348
349 fn into_select(self) -> Select<'columns, 'transaction, S, Self::Out> {
350 (self.a.into_expr(), self.b.into_expr())
351 .map_select((|(a, b)| User { a, b }) as fn((i64, String)) -> User)
352 .into_select()
353 }
354 }
355}