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