1use std::marker::PhantomData;
2
3use sea_query::IntoIden;
4
5use crate::{
6 Expr,
7 alias::MyAlias,
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 [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<T> {
234 pub(crate) expr: DynTyped<T>,
235}
236
237impl<T: MyTyp> SelectImpl for ColumnImpl<T> {
238 type Out = T::Out;
239 type Prepared = Cached<Self::Out>;
240
241 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
242 Cached {
243 idx: cacher.cache_erased(self.expr.erase()),
244 _p: PhantomData,
245 }
246 }
247}
248
249impl<'columns, S, T> IntoSelect<'columns, S> for Expr<'columns, S, T>
250where
251 T: MyTyp,
252{
253 type Out = T::Out;
254
255 fn into_select(self) -> Select<'columns, S, Self::Out> {
256 Select::new(ColumnImpl { expr: self.inner })
257 }
258}
259
260impl<'columns, S, T> IntoSelect<'columns, S> for &T
261where
262 T: IntoSelect<'columns, S> + Clone,
263{
264 type Out = T::Out;
265
266 fn into_select(self) -> Select<'columns, S, Self::Out> {
267 T::clone(self).into_select()
268 }
269}
270
271impl<A, B> Prepared for (A, B)
272where
273 A: Prepared,
274 B: Prepared,
275{
276 type Out = (A::Out, B::Out);
277
278 fn call(&mut self, row: Row<'_>) -> Self::Out {
279 (self.0.call(row), self.1.call(row))
280 }
281}
282
283impl<A, B> SelectImpl for (A, B)
284where
285 A: SelectImpl,
286 B: SelectImpl,
287{
288 type Out = (A::Out, B::Out);
289 type Prepared = (A::Prepared, B::Prepared);
290
291 fn prepare(self, cacher: &mut Cacher) -> Self::Prepared {
292 let prepared_a = self.0.prepare(cacher);
293 let prepared_b = self.1.prepare(cacher);
294 (prepared_a, prepared_b)
295 }
296}
297
298impl<'columns, S, A, B> IntoSelect<'columns, S> for (A, B)
299where
300 A: IntoSelect<'columns, S>,
301 B: IntoSelect<'columns, S>,
302{
303 type Out = (A::Out, B::Out);
304
305 fn into_select(self) -> Select<'columns, S, Self::Out> {
306 Select::new((self.0.into_select().inner, self.1.into_select().inner))
307 }
308}
309
310#[cfg(test)]
311#[allow(unused)]
312mod tests {
313 use crate::IntoExpr;
314
315 use super::*;
316
317 struct User {
318 a: i64,
319 b: String,
320 }
321
322 struct UserSelect<A, B> {
323 a: A,
324 b: B,
325 }
326
327 impl<'columns, S, A, B> IntoSelect<'columns, S> for UserSelect<A, B>
328 where
329 A: IntoExpr<'columns, S, Typ = i64>,
330 B: IntoExpr<'columns, S, Typ = String>,
331 {
332 type Out = User;
333
334 fn into_select(self) -> Select<'columns, S, Self::Out> {
335 (self.a.into_expr(), self.b.into_expr())
336 .into_select()
337 .map((|(a, b)| User { a, b }) as fn((i64, String)) -> User)
338 .into_select()
339 }
340 }
341}