1use crate::sqlx;
2
3use cratestack_core::{CoolContext, CoolError};
4
5use crate::{
6 BatchCreate, BatchDelete, BatchGet, BatchUpdate, BatchUpdateItem, BatchUpsert,
7 CreateModelInput, CreateRecord, DeleteRecord, Filter, FilterExpr, FindMany, FindUnique,
8 ModelDescriptor, OrderClause, SqlxRuntime, UpdateModelInput, UpdateRecord, UpdateRecordSet,
9 UpsertModelInput, UpsertRecord,
10};
11
12#[derive(Debug, Clone, Copy)]
13pub struct ModelDelegate<'a, M: 'static, PK: 'static> {
14 runtime: &'a SqlxRuntime,
15 descriptor: &'static ModelDescriptor<M, PK>,
16}
17
18impl<'a, M: 'static, PK: 'static> ModelDelegate<'a, M, PK> {
19 pub fn new(runtime: &'a SqlxRuntime, descriptor: &'static ModelDescriptor<M, PK>) -> Self {
20 Self {
21 runtime,
22 descriptor,
23 }
24 }
25
26 pub fn descriptor(&self) -> &'static ModelDescriptor<M, PK> {
27 self.descriptor
28 }
29
30 pub fn bind(self, ctx: CoolContext) -> ScopedModelDelegate<'a, M, PK> {
31 ScopedModelDelegate {
32 delegate: self,
33 ctx,
34 }
35 }
36
37 pub fn find_many(&self) -> FindMany<'a, M, PK> {
38 FindMany {
39 runtime: self.runtime,
40 descriptor: self.descriptor,
41 filters: Vec::new(),
42 order_by: Vec::new(),
43 limit: None,
44 offset: None,
45 }
46 }
47
48 pub fn find_unique(&self, id: PK) -> FindUnique<'a, M, PK> {
49 FindUnique {
50 runtime: self.runtime,
51 descriptor: self.descriptor,
52 id,
53 }
54 }
55
56 pub fn create<I>(&self, input: I) -> CreateRecord<'a, M, PK, I> {
57 CreateRecord {
58 runtime: self.runtime,
59 descriptor: self.descriptor,
60 input,
61 }
62 }
63
64 pub fn upsert<I>(&self, input: I) -> UpsertRecord<'a, M, PK, I> {
68 UpsertRecord {
69 runtime: self.runtime,
70 descriptor: self.descriptor,
71 input,
72 }
73 }
74
75 pub fn update(&self, id: PK) -> UpdateRecord<'a, M, PK> {
76 UpdateRecord {
77 runtime: self.runtime,
78 descriptor: self.descriptor,
79 id,
80 }
81 }
82
83 pub fn delete(&self, id: PK) -> DeleteRecord<'a, M, PK> {
84 DeleteRecord {
85 runtime: self.runtime,
86 descriptor: self.descriptor,
87 id,
88 }
89 }
90
91 pub fn batch_get(&self, ids: Vec<PK>) -> BatchGet<'a, M, PK> {
94 BatchGet {
95 runtime: self.runtime,
96 descriptor: self.descriptor,
97 ids,
98 }
99 }
100
101 pub fn batch_create<I>(&self, inputs: Vec<I>) -> BatchCreate<'a, M, PK, I> {
105 BatchCreate {
106 runtime: self.runtime,
107 descriptor: self.descriptor,
108 inputs,
109 }
110 }
111
112 pub fn batch_update<I>(
116 &self,
117 items: Vec<BatchUpdateItem<PK, I>>,
118 ) -> BatchUpdate<'a, M, PK, I> {
119 BatchUpdate {
120 runtime: self.runtime,
121 descriptor: self.descriptor,
122 items,
123 }
124 }
125
126 pub fn batch_delete(&self, ids: Vec<PK>) -> BatchDelete<'a, M, PK> {
129 BatchDelete {
130 runtime: self.runtime,
131 descriptor: self.descriptor,
132 ids,
133 }
134 }
135
136 pub fn batch_upsert<I>(&self, inputs: Vec<I>) -> BatchUpsert<'a, M, PK, I> {
140 BatchUpsert {
141 runtime: self.runtime,
142 descriptor: self.descriptor,
143 inputs,
144 }
145 }
146
147 pub async fn authorize_detail(&self, id: PK, ctx: &CoolContext) -> Result<(), CoolError>
148 where
149 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
150 {
151 crate::query::authorize_record_action(
152 self.runtime,
153 self.descriptor,
154 id,
155 self.descriptor.detail_allow_policies,
156 self.descriptor.detail_deny_policies,
157 ctx,
158 "detail",
159 )
160 .await
161 }
162
163 pub async fn authorize_update(&self, id: PK, ctx: &CoolContext) -> Result<(), CoolError>
164 where
165 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
166 {
167 crate::query::authorize_record_action(
168 self.runtime,
169 self.descriptor,
170 id,
171 self.descriptor.update_allow_policies,
172 self.descriptor.update_deny_policies,
173 ctx,
174 "update",
175 )
176 .await
177 }
178
179 pub async fn authorize_delete(&self, id: PK, ctx: &CoolContext) -> Result<(), CoolError>
180 where
181 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
182 {
183 crate::query::authorize_record_action(
184 self.runtime,
185 self.descriptor,
186 id,
187 self.descriptor.delete_allow_policies,
188 self.descriptor.delete_deny_policies,
189 ctx,
190 "delete",
191 )
192 .await
193 }
194}
195
196#[derive(Debug, Clone)]
197pub struct ScopedModelDelegate<'a, M: 'static, PK: 'static> {
198 delegate: ModelDelegate<'a, M, PK>,
199 ctx: CoolContext,
200}
201
202impl<'a, M: 'static, PK: 'static> ScopedModelDelegate<'a, M, PK> {
203 pub fn descriptor(&self) -> &'static ModelDescriptor<M, PK> {
204 self.delegate.descriptor()
205 }
206
207 pub fn context(&self) -> &CoolContext {
208 &self.ctx
209 }
210
211 pub fn find_many(&self) -> ScopedFindMany<'a, M, PK> {
212 ScopedFindMany {
213 request: self.delegate.find_many(),
214 ctx: self.ctx.clone(),
215 }
216 }
217
218 pub fn find_unique(&self, id: PK) -> ScopedFindUnique<'a, M, PK> {
219 ScopedFindUnique {
220 request: self.delegate.find_unique(id),
221 ctx: self.ctx.clone(),
222 }
223 }
224
225 pub fn create<I>(&self, input: I) -> ScopedCreateRecord<'a, M, PK, I> {
226 ScopedCreateRecord {
227 request: self.delegate.create(input),
228 ctx: self.ctx.clone(),
229 }
230 }
231
232 pub fn upsert<I>(&self, input: I) -> ScopedUpsertRecord<'a, M, PK, I> {
233 ScopedUpsertRecord {
234 request: self.delegate.upsert(input),
235 ctx: self.ctx.clone(),
236 }
237 }
238
239 pub fn update(&self, id: PK) -> ScopedUpdateRecord<'a, M, PK> {
240 ScopedUpdateRecord {
241 request: self.delegate.update(id),
242 ctx: self.ctx.clone(),
243 }
244 }
245
246 pub fn delete(&self, id: PK) -> ScopedDeleteRecord<'a, M, PK> {
247 ScopedDeleteRecord {
248 request: self.delegate.delete(id),
249 ctx: self.ctx.clone(),
250 }
251 }
252
253 pub fn batch_get(&self, ids: Vec<PK>) -> ScopedBatchGet<'a, M, PK> {
254 ScopedBatchGet {
255 request: self.delegate.batch_get(ids),
256 ctx: self.ctx.clone(),
257 }
258 }
259
260 pub fn batch_create<I>(&self, inputs: Vec<I>) -> ScopedBatchCreate<'a, M, PK, I> {
261 ScopedBatchCreate {
262 request: self.delegate.batch_create(inputs),
263 ctx: self.ctx.clone(),
264 }
265 }
266
267 pub fn batch_update<I>(
268 &self,
269 items: Vec<BatchUpdateItem<PK, I>>,
270 ) -> ScopedBatchUpdate<'a, M, PK, I> {
271 ScopedBatchUpdate {
272 request: self.delegate.batch_update(items),
273 ctx: self.ctx.clone(),
274 }
275 }
276
277 pub fn batch_delete(&self, ids: Vec<PK>) -> ScopedBatchDelete<'a, M, PK> {
278 ScopedBatchDelete {
279 request: self.delegate.batch_delete(ids),
280 ctx: self.ctx.clone(),
281 }
282 }
283
284 pub fn batch_upsert<I>(&self, inputs: Vec<I>) -> ScopedBatchUpsert<'a, M, PK, I> {
285 ScopedBatchUpsert {
286 request: self.delegate.batch_upsert(inputs),
287 ctx: self.ctx.clone(),
288 }
289 }
290}
291
292#[derive(Debug, Clone)]
293pub struct ScopedFindMany<'a, M: 'static, PK: 'static> {
294 request: FindMany<'a, M, PK>,
295 ctx: CoolContext,
296}
297
298impl<'a, M: 'static, PK: 'static> ScopedFindMany<'a, M, PK> {
299 pub fn where_(mut self, filter: Filter) -> Self {
300 self.request = self.request.where_(filter);
301 self
302 }
303
304 pub fn where_expr(mut self, filter: FilterExpr) -> Self {
305 self.request = self.request.where_expr(filter);
306 self
307 }
308
309 pub fn where_any(mut self, filters: impl IntoIterator<Item = FilterExpr>) -> Self {
310 self.request = self.request.where_any(filters);
311 self
312 }
313
314 pub fn order_by(mut self, clause: OrderClause) -> Self {
315 self.request = self.request.order_by(clause);
316 self
317 }
318
319 pub fn limit(mut self, limit: i64) -> Self {
320 self.request = self.request.limit(limit);
321 self
322 }
323
324 pub fn offset(mut self, offset: i64) -> Self {
325 self.request = self.request.offset(offset);
326 self
327 }
328
329 pub fn preview_sql(&self) -> String {
330 self.request.preview_sql()
331 }
332
333 pub fn preview_scoped_sql(&self) -> String {
334 self.request.preview_scoped_sql(&self.ctx)
335 }
336
337 pub async fn run(self) -> Result<Vec<M>, CoolError>
338 where
339 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow>,
340 {
341 self.request.run(&self.ctx).await
342 }
343}
344
345#[derive(Debug, Clone)]
346pub struct ScopedFindUnique<'a, M: 'static, PK: 'static> {
347 request: FindUnique<'a, M, PK>,
348 ctx: CoolContext,
349}
350
351impl<'a, M: 'static, PK: 'static> ScopedFindUnique<'a, M, PK> {
352 pub fn preview_sql(&self) -> String {
353 self.request.preview_sql()
354 }
355
356 pub fn preview_scoped_sql(&self) -> String {
357 self.request.preview_scoped_sql(&self.ctx)
358 }
359
360 pub async fn run(self) -> Result<Option<M>, CoolError>
361 where
362 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow>,
363 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
364 {
365 self.request.run(&self.ctx).await
366 }
367}
368
369#[derive(Debug, Clone)]
370pub struct ScopedCreateRecord<'a, M: 'static, PK: 'static, I> {
371 request: CreateRecord<'a, M, PK, I>,
372 ctx: CoolContext,
373}
374
375impl<'a, M: 'static, PK: 'static, I> ScopedCreateRecord<'a, M, PK, I>
376where
377 I: CreateModelInput<M>,
378{
379 pub fn preview_sql(&self) -> String {
380 self.request.preview_sql()
381 }
382
383 pub async fn run(self) -> Result<M, CoolError>
384 where
385 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
386 {
387 self.request.run(&self.ctx).await
388 }
389}
390
391#[derive(Debug, Clone)]
392pub struct ScopedUpsertRecord<'a, M: 'static, PK: 'static, I> {
393 request: UpsertRecord<'a, M, PK, I>,
394 ctx: CoolContext,
395}
396
397impl<'a, M: 'static, PK: 'static, I> ScopedUpsertRecord<'a, M, PK, I>
398where
399 I: UpsertModelInput<M>,
400{
401 pub fn preview_sql(&self) -> String {
402 self.request.preview_sql()
403 }
404
405 pub async fn run(self) -> Result<M, CoolError>
406 where
407 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
408 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
409 {
410 self.request.run(&self.ctx).await
411 }
412}
413
414#[derive(Debug, Clone)]
415pub struct ScopedUpdateRecord<'a, M: 'static, PK: 'static> {
416 request: UpdateRecord<'a, M, PK>,
417 ctx: CoolContext,
418}
419
420impl<'a, M: 'static, PK: 'static> ScopedUpdateRecord<'a, M, PK> {
421 pub fn set<I>(self, input: I) -> ScopedUpdateRecordSet<'a, M, PK, I> {
422 ScopedUpdateRecordSet {
423 request: self.request.set(input),
424 ctx: self.ctx,
425 }
426 }
427}
428
429#[derive(Debug, Clone)]
430pub struct ScopedUpdateRecordSet<'a, M: 'static, PK: 'static, I> {
431 request: UpdateRecordSet<'a, M, PK, I>,
432 ctx: CoolContext,
433}
434
435impl<'a, M: 'static, PK: 'static, I> ScopedUpdateRecordSet<'a, M, PK, I>
436where
437 I: UpdateModelInput<M>,
438{
439 pub fn preview_sql(&self) -> String {
440 self.request.preview_sql()
441 }
442
443 pub async fn run(self) -> Result<M, CoolError>
444 where
445 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
446 PK: Send + Clone + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
447 {
448 self.request.run(&self.ctx).await
449 }
450
451 pub fn if_match(mut self, expected: i64) -> Self {
454 self.request = self.request.if_match(expected);
455 self
456 }
457}
458
459#[derive(Debug, Clone)]
460pub struct ScopedDeleteRecord<'a, M: 'static, PK: 'static> {
461 request: DeleteRecord<'a, M, PK>,
462 ctx: CoolContext,
463}
464
465impl<'a, M: 'static, PK: 'static> ScopedDeleteRecord<'a, M, PK> {
466 pub fn preview_sql(&self) -> String {
467 self.request.preview_sql()
468 }
469
470 pub async fn run(self) -> Result<M, CoolError>
471 where
472 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
473 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
474 {
475 self.request.run(&self.ctx).await
476 }
477}
478
479use std::hash::Hash;
487
488use cratestack_core::BatchResponse;
489
490#[derive(Debug, Clone)]
491pub struct ScopedBatchGet<'a, M: 'static, PK: 'static> {
492 request: BatchGet<'a, M, PK>,
493 ctx: CoolContext,
494}
495
496impl<'a, M: 'static, PK: 'static> ScopedBatchGet<'a, M, PK> {
497 pub async fn run(self) -> Result<BatchResponse<M>, CoolError>
498 where
499 for<'r> M:
500 Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + crate::ModelPrimaryKey<PK>,
501 PK: Clone
502 + Eq
503 + Hash
504 + Send
505 + sqlx::Type<sqlx::Postgres>
506 + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
507 {
508 self.request.run(&self.ctx).await
509 }
510}
511
512#[derive(Debug, Clone)]
513pub struct ScopedBatchCreate<'a, M: 'static, PK: 'static, I> {
514 request: BatchCreate<'a, M, PK, I>,
515 ctx: CoolContext,
516}
517
518impl<'a, M: 'static, PK: 'static, I> ScopedBatchCreate<'a, M, PK, I>
519where
520 I: CreateModelInput<M> + Send,
521{
522 pub async fn run(self) -> Result<BatchResponse<M>, CoolError>
523 where
524 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
525 {
526 self.request.run(&self.ctx).await
527 }
528}
529
530#[derive(Debug, Clone)]
531pub struct ScopedBatchUpdate<'a, M: 'static, PK: 'static, I> {
532 request: BatchUpdate<'a, M, PK, I>,
533 ctx: CoolContext,
534}
535
536impl<'a, M: 'static, PK: 'static, I> ScopedBatchUpdate<'a, M, PK, I>
537where
538 I: UpdateModelInput<M> + Send,
539{
540 pub async fn run(self) -> Result<BatchResponse<M>, CoolError>
541 where
542 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
543 PK: Clone
544 + Eq
545 + Hash
546 + Send
547 + sqlx::Type<sqlx::Postgres>
548 + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
549 {
550 self.request.run(&self.ctx).await
551 }
552}
553
554#[derive(Debug, Clone)]
555pub struct ScopedBatchDelete<'a, M: 'static, PK: 'static> {
556 request: BatchDelete<'a, M, PK>,
557 ctx: CoolContext,
558}
559
560impl<'a, M: 'static, PK: 'static> ScopedBatchDelete<'a, M, PK> {
561 pub async fn run(self) -> Result<BatchResponse<M>, CoolError>
562 where
563 for<'r> M: Send
564 + Unpin
565 + sqlx::FromRow<'r, sqlx::postgres::PgRow>
566 + crate::ModelPrimaryKey<PK>
567 + serde::Serialize,
568 PK: Clone
569 + Eq
570 + Hash
571 + Send
572 + sqlx::Type<sqlx::Postgres>
573 + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
574 {
575 self.request.run(&self.ctx).await
576 }
577}
578
579#[derive(Debug, Clone)]
580pub struct ScopedBatchUpsert<'a, M: 'static, PK: 'static, I> {
581 request: BatchUpsert<'a, M, PK, I>,
582 ctx: CoolContext,
583}
584
585impl<'a, M: 'static, PK: 'static, I> ScopedBatchUpsert<'a, M, PK, I>
586where
587 I: UpsertModelInput<M>,
588{
589 pub async fn run(self) -> Result<BatchResponse<M>, CoolError>
590 where
591 for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
592 PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
593 {
594 self.request.run(&self.ctx).await
595 }
596}