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 {
151 type Out: 'static;
153
154 fn into_select(self) -> Select<'columns, S, Self::Out>;
160}
161
162pub struct MapImpl<D, F> {
167 dummy: D,
168 func: F,
169}
170
171impl<D, F, O> SelectImpl for MapImpl<D, F>
172where
173 D: SelectImpl,
174 F: FnMut(D::Out) -> O,
175{
176 type Out = O;
177 type Prepared = MapPrepared<D::Prepared, F>;
178
179 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
180 MapPrepared {
181 inner: self.dummy.prepare(cacher),
182 map: self.func,
183 }
184 }
185}
186
187pub struct MapPrepared<X, M> {
188 inner: X,
189 map: M,
190}
191
192impl<X, M, Out> Prepared for MapPrepared<X, M>
193where
194 X: Prepared,
195 M: FnMut(X::Out) -> Out,
196{
197 type Out = Out;
198
199 fn call(&mut self, row: Row<'_>) -> Self::Out {
200 (self.map)(self.inner.call(row))
201 }
202}
203
204impl Prepared for () {
205 type Out = ();
206
207 fn call(&mut self, _row: Row<'_>) -> Self::Out {}
208}
209
210impl SelectImpl for () {
211 type Out = ();
212 type Prepared = ();
213
214 fn prepare(self, _cacher: &mut Cacher) -> Self::Prepared {}
215}
216
217impl<'columns, S> IntoSelect<'columns, S> for () {
218 type Out = ();
219
220 fn into_select(self) -> Select<'columns, S, Self::Out> {
221 Select::new(())
222 }
223}
224
225impl<T: SecretFromSql> Prepared for Cached<T> {
226 type Out = T;
227
228 fn call(&mut self, row: Row<'_>) -> Self::Out {
229 row.get(*self)
230 }
231}
232
233pub struct ColumnImpl<Out> {
234 pub(crate) expr: DynTypedExpr,
235 pub(crate) _p: PhantomData<Out>,
236}
237
238impl<Out: SecretFromSql> SelectImpl for ColumnImpl<Out> {
239 type Out = Out;
240 type Prepared = Cached<Out>;
241
242 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
243 Cached {
244 idx: cacher.cache_erased(self.expr),
245 _p: PhantomData,
246 }
247 }
248}
249
250impl<'columns, S, T> IntoSelect<'columns, S> for Expr<'columns, S, T>
251where
252 T: MyTyp,
253{
254 type Out = T::Out;
255
256 fn into_select(self) -> Select<'columns, S, Self::Out> {
257 Select::new(ColumnImpl {
258 expr: DynTypedExpr::erase(self),
259 _p: PhantomData,
260 })
261 }
262}
263
264impl<'columns, S, T> IntoSelect<'columns, S> for &T
265where
266 T: IntoSelect<'columns, S> + Clone,
267{
268 type Out = T::Out;
269
270 fn into_select(self) -> Select<'columns, S, Self::Out> {
271 T::clone(self).into_select()
272 }
273}
274
275impl<A, B> Prepared for (A, B)
276where
277 A: Prepared,
278 B: Prepared,
279{
280 type Out = (A::Out, B::Out);
281
282 fn call(&mut self, row: Row<'_>) -> Self::Out {
283 (self.0.call(row), self.1.call(row))
284 }
285}
286
287impl<A, B> SelectImpl for (A, B)
288where
289 A: SelectImpl,
290 B: SelectImpl,
291{
292 type Out = (A::Out, B::Out);
293 type Prepared = (A::Prepared, B::Prepared);
294
295 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
296 let prepared_a = self.0.prepare(cacher);
297 let prepared_b = self.1.prepare(cacher);
298 (prepared_a, prepared_b)
299 }
300}
301
302impl<'columns, S, A, B> IntoSelect<'columns, S> for (A, B)
303where
304 A: IntoSelect<'columns, S>,
305 B: IntoSelect<'columns, S>,
306{
307 type Out = (A::Out, B::Out);
308
309 fn into_select(self) -> Select<'columns, S, Self::Out> {
310 Select::new((self.0.into_select().inner, self.1.into_select().inner))
311 }
312}
313
314#[cfg(test)]
315#[allow(unused)]
316mod tests {
317 use crate::IntoExpr;
318
319 use super::*;
320
321 struct User {
322 a: i64,
323 b: String,
324 }
325
326 struct UserSelect<A, B> {
327 a: A,
328 b: B,
329 }
330
331 impl<'columns, S, A, B> IntoSelect<'columns, S> for UserSelect<A, B>
332 where
333 A: IntoExpr<'columns, S, Typ = i64>,
334 B: IntoExpr<'columns, S, Typ = String>,
335 {
336 type Out = User;
337
338 fn into_select(self) -> Select<'columns, S, Self::Out> {
339 (self.a.into_expr(), self.b.into_expr())
340 .into_select()
341 .map((|(a, b)| User { a, b }) as fn((i64, String)) -> User)
342 .into_select()
343 }
344 }
345}