1use std::marker::PhantomData;
2
3use sea_query::IntoIden;
4
5use crate::{
6 Expr,
7 alias::MyAlias,
8 value::{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 [MyAlias],
48}
49
50impl<'x> Row<'x> {
51 pub(crate) fn new(row: &'x rusqlite::Row<'x>, fields: &'x [MyAlias]) -> Self {
52 Self { row, fields }
53 }
54
55 pub fn get<T: SecretFromSql>(&self, val: Cached<T>) -> T {
56 let field = self.fields[val.idx].into_iden();
57 let idx = field.inner();
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, S, Out> {
74 pub(crate) inner: DynSelectImpl<Out>,
75 pub(crate) _p: PhantomData<&'columns ()>,
76 pub(crate) _p2: PhantomData<S>,
77}
78
79impl<'columns, S, Out: 'static> Select<'columns, S, Out> {
80 pub fn map<T>(self, f: impl 'static + FnMut(Out) -> T) -> Select<'columns, S, T> {
84 Select::new(MapImpl {
85 dummy: self.inner,
86 func: f,
87 })
88 }
89}
90
91pub struct DynSelectImpl<Out> {
92 inner: Box<dyn FnOnce(&mut Cacher) -> DynPrepared<Out>>,
93}
94
95impl<Out> SelectImpl for DynSelectImpl<Out> {
96 type Out = Out;
97 type Prepared = DynPrepared<Out>;
98
99 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
100 (self.inner)(cacher)
101 }
102}
103
104pub struct DynPrepared<Out> {
105 inner: Box<dyn Prepared<Out = Out>>,
106}
107
108impl<Out> Prepared for DynPrepared<Out> {
109 type Out = Out;
110 fn call(&mut self, row: Row<'_>) -> Self::Out {
111 self.inner.call(row)
112 }
113}
114
115impl<S, Out> Select<'_, S, Out> {
116 pub(crate) fn new(val: impl 'static + SelectImpl<Out = Out>) -> Self {
117 Self {
118 inner: DynSelectImpl {
119 inner: Box::new(|cacher| DynPrepared {
120 inner: Box::new(val.prepare(cacher)),
121 }),
122 },
123 _p: PhantomData,
124 _p2: PhantomData,
125 }
126 }
127}
128
129impl<'columns, S, Out: 'static> IntoSelect<'columns, S> for Select<'columns, S, Out> {
130 type Out = Out;
131
132 fn into_select(self) -> Select<'columns, S, Self::Out> {
133 self
134 }
135}
136
137pub trait SelectImpl {
138 type Out;
139 #[doc(hidden)]
140 type Prepared: Prepared<Out = Self::Out>;
141 #[doc(hidden)]
142 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared;
143}
144
145pub trait IntoSelect<'columns, S>: Sized {
161 type Out: 'static;
163
164 fn into_select(self) -> Select<'columns, S, Self::Out>;
170}
171
172pub struct MapImpl<D, F> {
177 dummy: D,
178 func: F,
179}
180
181impl<D, F, O> SelectImpl for MapImpl<D, F>
182where
183 D: SelectImpl,
184 F: FnMut(D::Out) -> O,
185{
186 type Out = O;
187 type Prepared = MapPrepared<D::Prepared, F>;
188
189 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
190 MapPrepared {
191 inner: self.dummy.prepare(cacher),
192 map: self.func,
193 }
194 }
195}
196
197pub struct MapPrepared<X, M> {
198 inner: X,
199 map: M,
200}
201
202impl<X, M, Out> Prepared for MapPrepared<X, M>
203where
204 X: Prepared,
205 M: FnMut(X::Out) -> Out,
206{
207 type Out = Out;
208
209 fn call(&mut self, row: Row<'_>) -> Self::Out {
210 (self.map)(self.inner.call(row))
211 }
212}
213
214impl Prepared for () {
215 type Out = ();
216
217 fn call(&mut self, _row: Row<'_>) -> Self::Out {}
218}
219
220impl SelectImpl for () {
221 type Out = ();
222 type Prepared = ();
223
224 fn prepare(self, _cacher: &mut Cacher) -> Self::Prepared {}
225}
226
227impl<'columns, S> IntoSelect<'columns, S> for () {
228 type Out = ();
229
230 fn into_select(self) -> Select<'columns, S, Self::Out> {
231 Select::new(())
232 }
233}
234
235impl<T: SecretFromSql> Prepared for Cached<T> {
236 type Out = T;
237
238 fn call(&mut self, row: Row<'_>) -> Self::Out {
239 row.get(*self)
240 }
241}
242
243pub struct ColumnImpl<Out> {
244 pub(crate) expr: DynTypedExpr,
245 pub(crate) _p: PhantomData<Out>,
246}
247
248impl<Out: SecretFromSql> SelectImpl for ColumnImpl<Out> {
249 type Out = Out;
250 type Prepared = Cached<Out>;
251
252 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
253 Cached {
254 idx: cacher.cache_erased(self.expr),
255 _p: PhantomData,
256 }
257 }
258}
259
260impl<'columns, S, T> IntoSelect<'columns, S> for Expr<'columns, S, T>
261where
262 T: MyTyp,
263{
264 type Out = T::Out;
265
266 fn into_select(self) -> Select<'columns, S, Self::Out> {
267 Select::new(ColumnImpl {
268 expr: DynTypedExpr::erase(self),
269 _p: PhantomData,
270 })
271 }
272}
273
274impl<'columns, S, T> IntoSelect<'columns, S> for &T
275where
276 T: IntoSelect<'columns, S> + Clone,
277{
278 type Out = T::Out;
279
280 fn into_select(self) -> Select<'columns, S, Self::Out> {
281 T::clone(self).into_select()
282 }
283}
284
285impl<A, B> Prepared for (A, B)
286where
287 A: Prepared,
288 B: Prepared,
289{
290 type Out = (A::Out, B::Out);
291
292 fn call(&mut self, row: Row<'_>) -> Self::Out {
293 (self.0.call(row), self.1.call(row))
294 }
295}
296
297impl<A, B> SelectImpl for (A, B)
298where
299 A: SelectImpl,
300 B: SelectImpl,
301{
302 type Out = (A::Out, B::Out);
303 type Prepared = (A::Prepared, B::Prepared);
304
305 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
306 let prepared_a = self.0.prepare(cacher);
307 let prepared_b = self.1.prepare(cacher);
308 (prepared_a, prepared_b)
309 }
310}
311
312impl<'columns, S, A, B> IntoSelect<'columns, S> for (A, B)
313where
314 A: IntoSelect<'columns, S>,
315 B: IntoSelect<'columns, S>,
316{
317 type Out = (A::Out, B::Out);
318
319 fn into_select(self) -> Select<'columns, S, Self::Out> {
320 Select::new((self.0.into_select().inner, self.1.into_select().inner))
321 }
322}
323
324#[cfg(test)]
325#[allow(unused)]
326mod tests {
327 use crate::IntoExpr;
328
329 use super::*;
330
331 struct User {
332 a: i64,
333 b: String,
334 }
335
336 struct UserSelect<A, B> {
337 a: A,
338 b: B,
339 }
340
341 impl<'columns, S, A, B> IntoSelect<'columns, S> for UserSelect<A, B>
342 where
343 A: IntoExpr<'columns, S, Typ = i64>,
344 B: IntoExpr<'columns, S, Typ = String>,
345 {
346 type Out = User;
347
348 fn into_select(self) -> Select<'columns, S, Self::Out> {
349 (self.a.into_expr(), self.b.into_expr())
350 .into_select()
351 .map((|(a, b)| User { a, b }) as fn((i64, String)) -> User)
352 .into_select()
353 }
354 }
355}