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