1use crate::sqlx;
2
3use cratestack_core::{CoolContext, CoolError};
4
5use crate::{
6 CreateModelInput, CreateRecord, DeleteRecord, Filter, FilterExpr, FindMany, FindUnique,
7 ModelDescriptor, OrderClause, SqlxRuntime, UpdateModelInput, UpdateRecord, UpdateRecordSet,
8 UpsertModelInput, UpsertRecord,
9};
10
11#[derive(Debug, Clone, Copy)]
12pub struct ModelDelegate<'a, M: 'static, PK: 'static> {
13 runtime: &'a SqlxRuntime,
14 descriptor: &'static ModelDescriptor<M, PK>,
15}
16
17impl<'a, M: 'static, PK: 'static> ModelDelegate<'a, M, PK> {
18 pub fn new(runtime: &'a SqlxRuntime, descriptor: &'static ModelDescriptor<M, PK>) -> Self {
19 Self {
20 runtime,
21 descriptor,
22 }
23 }
24
25 pub fn descriptor(&self) -> &'static ModelDescriptor<M, PK> {
26 self.descriptor
27 }
28
29 pub fn bind(self, ctx: CoolContext) -> ScopedModelDelegate<'a, M, PK> {
30 ScopedModelDelegate {
31 delegate: self,
32 ctx,
33 }
34 }
35
36 pub fn find_many(&self) -> FindMany<'a, M, PK> {
37 FindMany {
38 runtime: self.runtime,
39 descriptor: self.descriptor,
40 filters: Vec::new(),
41 order_by: Vec::new(),
42 limit: None,
43 offset: None,
44 }
45 }
46
47 pub fn find_unique(&self, id: PK) -> FindUnique<'a, M, PK> {
48 FindUnique {
49 runtime: self.runtime,
50 descriptor: self.descriptor,
51 id,
52 }
53 }
54
55 pub fn create<I>(&self, input: I) -> CreateRecord<'a, M, PK, I> {
56 CreateRecord {
57 runtime: self.runtime,
58 descriptor: self.descriptor,
59 input,
60 }
61 }
62
63 pub fn upsert<I>(&self, input: I) -> UpsertRecord<'a, M, PK, I> {
67 UpsertRecord {
68 runtime: self.runtime,
69 descriptor: self.descriptor,
70 input,
71 }
72 }
73
74 pub fn update(&self, id: PK) -> UpdateRecord<'a, M, PK> {
75 UpdateRecord {
76 runtime: self.runtime,
77 descriptor: self.descriptor,
78 id,
79 }
80 }
81
82 pub fn delete(&self, id: PK) -> DeleteRecord<'a, M, PK> {
83 DeleteRecord {
84 runtime: self.runtime,
85 descriptor: self.descriptor,
86 id,
87 }
88 }
89
90 pub async fn authorize_detail(&self, id: PK, ctx: &CoolContext) -> Result<(), CoolError>
91 where
92 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
93 {
94 crate::query::authorize_record_action(
95 self.runtime,
96 self.descriptor,
97 id,
98 self.descriptor.detail_allow_policies,
99 self.descriptor.detail_deny_policies,
100 ctx,
101 "detail",
102 )
103 .await
104 }
105
106 pub async fn authorize_update(&self, id: PK, ctx: &CoolContext) -> Result<(), CoolError>
107 where
108 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
109 {
110 crate::query::authorize_record_action(
111 self.runtime,
112 self.descriptor,
113 id,
114 self.descriptor.update_allow_policies,
115 self.descriptor.update_deny_policies,
116 ctx,
117 "update",
118 )
119 .await
120 }
121
122 pub async fn authorize_delete(&self, id: PK, ctx: &CoolContext) -> Result<(), CoolError>
123 where
124 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
125 {
126 crate::query::authorize_record_action(
127 self.runtime,
128 self.descriptor,
129 id,
130 self.descriptor.delete_allow_policies,
131 self.descriptor.delete_deny_policies,
132 ctx,
133 "delete",
134 )
135 .await
136 }
137}
138
139#[derive(Debug, Clone)]
140pub struct ScopedModelDelegate<'a, M: 'static, PK: 'static> {
141 delegate: ModelDelegate<'a, M, PK>,
142 ctx: CoolContext,
143}
144
145impl<'a, M: 'static, PK: 'static> ScopedModelDelegate<'a, M, PK> {
146 pub fn descriptor(&self) -> &'static ModelDescriptor<M, PK> {
147 self.delegate.descriptor()
148 }
149
150 pub fn context(&self) -> &CoolContext {
151 &self.ctx
152 }
153
154 pub fn find_many(&self) -> ScopedFindMany<'a, M, PK> {
155 ScopedFindMany {
156 request: self.delegate.find_many(),
157 ctx: self.ctx.clone(),
158 }
159 }
160
161 pub fn find_unique(&self, id: PK) -> ScopedFindUnique<'a, M, PK> {
162 ScopedFindUnique {
163 request: self.delegate.find_unique(id),
164 ctx: self.ctx.clone(),
165 }
166 }
167
168 pub fn create<I>(&self, input: I) -> ScopedCreateRecord<'a, M, PK, I> {
169 ScopedCreateRecord {
170 request: self.delegate.create(input),
171 ctx: self.ctx.clone(),
172 }
173 }
174
175 pub fn upsert<I>(&self, input: I) -> ScopedUpsertRecord<'a, M, PK, I> {
176 ScopedUpsertRecord {
177 request: self.delegate.upsert(input),
178 ctx: self.ctx.clone(),
179 }
180 }
181
182 pub fn update(&self, id: PK) -> ScopedUpdateRecord<'a, M, PK> {
183 ScopedUpdateRecord {
184 request: self.delegate.update(id),
185 ctx: self.ctx.clone(),
186 }
187 }
188
189 pub fn delete(&self, id: PK) -> ScopedDeleteRecord<'a, M, PK> {
190 ScopedDeleteRecord {
191 request: self.delegate.delete(id),
192 ctx: self.ctx.clone(),
193 }
194 }
195}
196
197#[derive(Debug, Clone)]
198pub struct ScopedFindMany<'a, M: 'static, PK: 'static> {
199 request: FindMany<'a, M, PK>,
200 ctx: CoolContext,
201}
202
203impl<'a, M: 'static, PK: 'static> ScopedFindMany<'a, M, PK> {
204 pub fn where_(mut self, filter: Filter) -> Self {
205 self.request = self.request.where_(filter);
206 self
207 }
208
209 pub fn where_expr(mut self, filter: FilterExpr) -> Self {
210 self.request = self.request.where_expr(filter);
211 self
212 }
213
214 pub fn where_any(mut self, filters: impl IntoIterator<Item = FilterExpr>) -> Self {
215 self.request = self.request.where_any(filters);
216 self
217 }
218
219 pub fn order_by(mut self, clause: OrderClause) -> Self {
220 self.request = self.request.order_by(clause);
221 self
222 }
223
224 pub fn limit(mut self, limit: i64) -> Self {
225 self.request = self.request.limit(limit);
226 self
227 }
228
229 pub fn offset(mut self, offset: i64) -> Self {
230 self.request = self.request.offset(offset);
231 self
232 }
233
234 pub fn preview_sql(&self) -> String {
235 self.request.preview_sql()
236 }
237
238 pub fn preview_scoped_sql(&self) -> String {
239 self.request.preview_scoped_sql(&self.ctx)
240 }
241
242 pub async fn run(self) -> Result<Vec<M>, CoolError>
243 where
244 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow>,
245 {
246 self.request.run(&self.ctx).await
247 }
248}
249
250#[derive(Debug, Clone)]
251pub struct ScopedFindUnique<'a, M: 'static, PK: 'static> {
252 request: FindUnique<'a, M, PK>,
253 ctx: CoolContext,
254}
255
256impl<'a, M: 'static, PK: 'static> ScopedFindUnique<'a, M, PK> {
257 pub fn preview_sql(&self) -> String {
258 self.request.preview_sql()
259 }
260
261 pub fn preview_scoped_sql(&self) -> String {
262 self.request.preview_scoped_sql(&self.ctx)
263 }
264
265 pub async fn run(self) -> Result<Option<M>, CoolError>
266 where
267 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow>,
268 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
269 {
270 self.request.run(&self.ctx).await
271 }
272}
273
274#[derive(Debug, Clone)]
275pub struct ScopedCreateRecord<'a, M: 'static, PK: 'static, I> {
276 request: CreateRecord<'a, M, PK, I>,
277 ctx: CoolContext,
278}
279
280impl<'a, M: 'static, PK: 'static, I> ScopedCreateRecord<'a, M, PK, I>
281where
282 I: CreateModelInput<M>,
283{
284 pub fn preview_sql(&self) -> String {
285 self.request.preview_sql()
286 }
287
288 pub async fn run(self) -> Result<M, CoolError>
289 where
290 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
291 {
292 self.request.run(&self.ctx).await
293 }
294}
295
296#[derive(Debug, Clone)]
297pub struct ScopedUpsertRecord<'a, M: 'static, PK: 'static, I> {
298 request: UpsertRecord<'a, M, PK, I>,
299 ctx: CoolContext,
300}
301
302impl<'a, M: 'static, PK: 'static, I> ScopedUpsertRecord<'a, M, PK, I>
303where
304 I: UpsertModelInput<M>,
305{
306 pub fn preview_sql(&self) -> String {
307 self.request.preview_sql()
308 }
309
310 pub async fn run(self) -> Result<M, CoolError>
311 where
312 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
313 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
314 {
315 self.request.run(&self.ctx).await
316 }
317}
318
319#[derive(Debug, Clone)]
320pub struct ScopedUpdateRecord<'a, M: 'static, PK: 'static> {
321 request: UpdateRecord<'a, M, PK>,
322 ctx: CoolContext,
323}
324
325impl<'a, M: 'static, PK: 'static> ScopedUpdateRecord<'a, M, PK> {
326 pub fn set<I>(self, input: I) -> ScopedUpdateRecordSet<'a, M, PK, I> {
327 ScopedUpdateRecordSet {
328 request: self.request.set(input),
329 ctx: self.ctx,
330 }
331 }
332}
333
334#[derive(Debug, Clone)]
335pub struct ScopedUpdateRecordSet<'a, M: 'static, PK: 'static, I> {
336 request: UpdateRecordSet<'a, M, PK, I>,
337 ctx: CoolContext,
338}
339
340impl<'a, M: 'static, PK: 'static, I> ScopedUpdateRecordSet<'a, M, PK, I>
341where
342 I: UpdateModelInput<M>,
343{
344 pub fn preview_sql(&self) -> String {
345 self.request.preview_sql()
346 }
347
348 pub async fn run(self) -> Result<M, CoolError>
349 where
350 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
351 PK: Send + Clone + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
352 {
353 self.request.run(&self.ctx).await
354 }
355
356 pub fn if_match(mut self, expected: i64) -> Self {
359 self.request = self.request.if_match(expected);
360 self
361 }
362}
363
364#[derive(Debug, Clone)]
365pub struct ScopedDeleteRecord<'a, M: 'static, PK: 'static> {
366 request: DeleteRecord<'a, M, PK>,
367 ctx: CoolContext,
368}
369
370impl<'a, M: 'static, PK: 'static> ScopedDeleteRecord<'a, M, PK> {
371 pub fn preview_sql(&self) -> String {
372 self.request.preview_sql()
373 }
374
375 pub async fn run(self) -> Result<M, CoolError>
376 where
377 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
378 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
379 {
380 self.request.run(&self.ctx).await
381 }
382}