1use std::fmt;
2use std::sync::Arc;
3
4use keelson_core::{Dialect, Expression, Mod, Query, QueryExtensions, QueryType, SqlWriter};
5use keelson_exec::{ExecError, ExecFuture, ExecHook, Execute as _, Executor, FromRow, Row};
6
7use crate::View;
8use crate::delegate::delegate_clause;
9
10pub type MapperMod<T> = Arc<dyn Fn(&mut Row, &mut T) -> Result<(), ExecError> + Send + Sync>;
20
21pub type Loader<T> = Arc<
30 dyn for<'a> Fn(&'a dyn Executor, &'a mut Vec<T>) -> ExecFuture<'a, Result<(), ExecError>>
31 + Send
32 + Sync,
33>;
34
35pub fn hook<F>(f: F) -> ExecHook
42where
43 F: for<'a> Fn(&'a dyn Executor) -> ExecFuture<'a, Result<(), ExecError>>
44 + Send
45 + Sync
46 + 'static,
47{
48 Arc::new(f)
49}
50
51pub fn mapper_mod<T, F>(f: F) -> MapperMod<T>
53where
54 F: Fn(&mut Row, &mut T) -> Result<(), ExecError> + Send + Sync + 'static,
55{
56 Arc::new(f)
57}
58
59pub fn loader<T, F>(f: F) -> Loader<T>
61where
62 F: for<'a> Fn(&'a dyn Executor, &'a mut Vec<T>) -> ExecFuture<'a, Result<(), ExecError>>
63 + Send
64 + Sync
65 + 'static,
66{
67 Arc::new(f)
68}
69
70pub struct ModelSelect<M: View> {
86 query: M::Select,
87 hooks: Vec<ExecHook>,
88 mapper_mods: Vec<MapperMod<M::Row>>,
89 loaders: Vec<Loader<M::Row>>,
90}
91
92impl<M: View> fmt::Debug for ModelSelect<M> {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 f.debug_struct("ModelSelect")
95 .field("query", &self.query)
96 .field("hooks", &self.hooks.len())
97 .field("mapper_mods", &self.mapper_mods.len())
98 .field("loaders", &self.loaders.len())
99 .finish()
100 }
101}
102
103impl<M: View> ModelSelect<M> {
104 pub(crate) fn new(query: M::Select) -> Self {
105 ModelSelect {
106 query,
107 hooks: Vec::new(),
108 mapper_mods: Vec::new(),
109 loaders: Vec::new(),
110 }
111 }
112
113 pub fn apply(&mut self, mods: impl Mod<M::Select>) {
118 mods.apply(&mut self.query);
119 }
120
121 pub fn as_select(&self) -> &M::Select {
123 &self.query
124 }
125
126 pub fn add_hook(&mut self, hook: ExecHook) {
129 self.hooks.push(hook);
130 }
131
132 pub fn add_mapper_mod(&mut self, mapper_mod: MapperMod<M::Row>) {
134 self.mapper_mods.push(mapper_mod);
135 }
136
137 pub fn add_loader(&mut self, loader: Loader<M::Row>) {
139 self.loaders.push(loader);
140 }
141
142 pub async fn all(&self, db: &dyn Executor) -> Result<Vec<M::Row>, ExecError> {
149 for h in self.hooks() {
150 h(db).await?;
151 }
152 let rows = self.query.fetch_rows(db).await?;
153 let mut models = Vec::with_capacity(rows.len());
154 for mut row in rows {
155 let mut model = M::Row::from_row(&mut row)?;
156 for mm in self.mapper_mods() {
157 mm(&mut row, &mut model)?;
158 }
159 models.push(model);
160 }
161 for l in self.loaders() {
162 l(db, &mut models).await?;
163 }
164 M::after_select(db, &mut models).await?;
165 Ok(models)
166 }
167
168 pub async fn one(&self, db: &dyn Executor) -> Result<M::Row, ExecError> {
172 let mut models = self.all(db).await?;
173 match models.len() {
174 0 => Err(ExecError::RowNotFound),
175 1 => Ok(models.pop().expect("len checked")),
176 _ => Err(ExecError::TooManyRows),
177 }
178 }
179
180 pub async fn optional(&self, db: &dyn Executor) -> Result<Option<M::Row>, ExecError> {
182 let mut models = self.all(db).await?;
183 match models.len() {
184 0 => Ok(None),
185 1 => Ok(models.pop()),
186 _ => Err(ExecError::TooManyRows),
187 }
188 }
189}
190
191impl<M: View> Expression for ModelSelect<M> {
192 fn write_sql(&self, w: &mut SqlWriter<'_>) {
193 self.query.write_sql(w);
194 }
195}
196
197impl<M: View> Query for ModelSelect<M> {
198 fn query_type(&self) -> QueryType {
199 self.query.query_type()
200 }
201
202 fn dialect(&self) -> &dyn Dialect {
203 self.query.dialect()
204 }
205}
206
207impl<M: View> QueryExtensions<ExecHook, Loader<M::Row>, MapperMod<M::Row>> for ModelSelect<M> {
210 fn hooks(&self) -> &[ExecHook] {
211 &self.hooks
212 }
213
214 fn loaders(&self) -> &[Loader<M::Row>] {
215 &self.loaders
216 }
217
218 fn mapper_mods(&self) -> &[MapperMod<M::Row>] {
219 &self.mapper_mods
220 }
221}
222
223delegate_clause!(
224 ModelSelect,
225 View,
226 Select,
227 HasWith,
228 with_mut,
229 keelson_core::clause::With
230);
231delegate_clause!(
232 ModelSelect,
233 View,
234 Select,
235 HasSelectList,
236 select_list_mut,
237 keelson_core::clause::SelectList
238);
239delegate_clause!(
240 ModelSelect,
241 View,
242 Select,
243 HasTableRef,
244 table_ref_mut,
245 keelson_core::clause::TableRef
246);
247delegate_clause!(
248 ModelSelect,
249 View,
250 Select,
251 HasJoins,
252 joins_mut,
253 Vec<keelson_core::clause::Join>
254);
255delegate_clause!(
256 ModelSelect,
257 View,
258 Select,
259 HasWhere,
260 where_mut,
261 keelson_core::clause::Where
262);
263delegate_clause!(
264 ModelSelect,
265 View,
266 Select,
267 HasGroupBy,
268 group_by_mut,
269 keelson_core::clause::GroupBy
270);
271delegate_clause!(
272 ModelSelect,
273 View,
274 Select,
275 HasHaving,
276 having_mut,
277 keelson_core::clause::Having
278);
279delegate_clause!(
280 ModelSelect,
281 View,
282 Select,
283 HasWindows,
284 windows_mut,
285 keelson_core::clause::Windows
286);
287delegate_clause!(
288 ModelSelect,
289 View,
290 Select,
291 HasOrderBy,
292 order_by_mut,
293 keelson_core::clause::OrderBy
294);
295delegate_clause!(
296 ModelSelect,
297 View,
298 Select,
299 HasLimit,
300 limit_mut,
301 keelson_core::clause::Limit
302);
303delegate_clause!(
304 ModelSelect,
305 View,
306 Select,
307 HasOffset,
308 offset_mut,
309 keelson_core::clause::Offset
310);
311delegate_clause!(
312 ModelSelect,
313 View,
314 Select,
315 HasFetch,
316 fetch_mut,
317 keelson_core::clause::Fetch
318);
319delegate_clause!(
320 ModelSelect,
321 View,
322 Select,
323 HasLocks,
324 locks_mut,
325 keelson_core::clause::Locks
326);
327delegate_clause!(
328 ModelSelect,
329 View,
330 Select,
331 HasCombines,
332 combines_mut,
333 keelson_core::clause::Combines
334);