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