1use std::marker::PhantomData;
2
3use sea_query::Iden;
4
5use crate::{alias::Field, ast::MySelect, value::MyTyp, IntoColumn};
6
7pub struct Cacher<'x, 't, S> {
8 pub(crate) _p: PhantomData<fn(&'t S) -> &'t S>,
9 pub(crate) ast: &'x MySelect,
10}
11
12impl<S> Copy for Cacher<'_, '_, S> {}
13
14impl<S> Clone for Cacher<'_, '_, S> {
15 fn clone(&self) -> Self {
16 *self
17 }
18}
19
20pub struct Cached<'t, T> {
21 _p: PhantomData<fn(&'t T) -> &'t T>,
22 field: Field,
23}
24
25impl<'t, T> Clone for Cached<'t, T> {
26 fn clone(&self) -> Self {
27 *self
28 }
29}
30impl<'t, T> Copy for Cached<'t, T> {}
31
32impl<'t, S> Cacher<'_, 't, S> {
33 pub fn cache<T>(&mut self, val: impl IntoColumn<'t, S, Typ = T>) -> Cached<'t, T> {
34 let expr = val.build_expr(self.ast.builder());
35 let new_field = || self.ast.scope.new_field();
36 let field = *self.ast.select.get_or_init(expr, new_field);
37 Cached {
38 _p: PhantomData,
39 field,
40 }
41 }
42}
43
44#[derive(Clone, Copy)]
45pub struct Row<'x, 't, 'a> {
46 pub(crate) _p: PhantomData<fn(&'t ()) -> &'t ()>,
47 pub(crate) _p2: PhantomData<fn(&'a ()) -> &'a ()>,
48 pub(crate) row: &'x rusqlite::Row<'x>,
49}
50
51impl<'t, 'a> Row<'_, 't, 'a> {
52 pub fn get<T: MyTyp>(&self, val: Cached<'t, T>) -> T::Out<'a> {
53 let idx = &*val.field.to_string();
54 T::from_sql(self.row.get_ref_unwrap(idx)).unwrap()
55 }
56}
57
58pub trait Dummy<'t, 'a, S>: Sized {
62 type Out;
64
65 #[doc(hidden)]
66 fn prepare(self, cacher: Cacher<'_, 't, S>) -> impl FnMut(Row<'_, 't, 'a>) -> Self::Out + 't;
67
68 fn map_dummy<T>(self, f: impl FnMut(Self::Out) -> T + 't) -> impl Dummy<'t, 'a, S, Out = T> {
73 DummyMap(self, f)
74 }
75}
76
77struct DummyMap<A, F>(A, F);
78
79impl<'t, 'a, S, A, F, T> Dummy<'t, 'a, S> for DummyMap<A, F>
80where
81 A: Dummy<'t, 'a, S>,
82 F: FnMut(A::Out) -> T + 't,
83{
84 type Out = T;
85
86 fn prepare(
87 mut self,
88 cacher: Cacher<'_, 't, S>,
89 ) -> impl FnMut(Row<'_, 't, 'a>) -> Self::Out + 't {
90 let mut cached = self.0.prepare(cacher);
91 move |row| self.1(cached(row))
92 }
93}
94
95impl<'t, 'a, S, T: IntoColumn<'t, S, Typ: MyTyp>> Dummy<'t, 'a, S> for T {
96 type Out = <T::Typ as MyTyp>::Out<'a>;
97
98 fn prepare(
99 self,
100 mut cacher: Cacher<'_, 't, S>,
101 ) -> impl FnMut(Row<'_, 't, 'a>) -> Self::Out + 't {
102 let cached = cacher.cache(self);
103 move |row| row.get(cached)
104 }
105}
106
107impl<'t, 'a, S, A: Dummy<'t, 'a, S>, B: Dummy<'t, 'a, S>> Dummy<'t, 'a, S> for (A, B) {
108 type Out = (A::Out, B::Out);
109
110 fn prepare(self, cacher: Cacher<'_, 't, S>) -> impl FnMut(Row<'_, 't, 'a>) -> Self::Out + 't {
111 let mut prepared_a = self.0.prepare(cacher);
112 let mut prepared_b = self.1.prepare(cacher);
113 move |row| (prepared_a(row), prepared_b(row))
114 }
115}
116
117#[cfg(test)]
118#[allow(unused)]
119mod tests {
120 use super::*;
121
122 struct User {
123 a: i64,
124 b: String,
125 }
126
127 struct UserDummy<A, B> {
128 a: A,
129 b: B,
130 }
131
132 impl<'t, 'a, S, A, B> Dummy<'t, 'a, S> for UserDummy<A, B>
133 where
134 A: IntoColumn<'t, S, Typ = i64>,
135 B: IntoColumn<'t, S, Typ = String>,
136 {
137 type Out = User;
138
139 fn prepare(
140 self,
141 mut cacher: Cacher<'_, 't, S>,
142 ) -> impl FnMut(Row<'_, 't, 'a>) -> Self::Out + 't {
143 let a = cacher.cache(self.a);
144 let b = cacher.cache(self.b);
145 move |row| User {
146 a: row.get(a),
147 b: row.get(b),
148 }
149 }
150 }
151}