Skip to main content

cratestack_sqlx/delegate/
scoped_writes.rs

1//! Single-row write wrappers: create / upsert / update.
2
3use cratestack_core::{CoolContext, CoolError};
4
5use crate::{
6    CreateModelInput, CreateRecord, UpdateModelInput, UpdateRecord, UpdateRecordSet,
7    UpsertModelInput, UpsertRecord, sqlx,
8};
9
10#[derive(Debug, Clone)]
11pub struct ScopedCreateRecord<'a, M: 'static, PK: 'static, I> {
12    request: CreateRecord<'a, M, PK, I>,
13    ctx: CoolContext,
14}
15
16impl<'a, M: 'static, PK: 'static, I> ScopedCreateRecord<'a, M, PK, I> {
17    pub(super) fn new(request: CreateRecord<'a, M, PK, I>, ctx: CoolContext) -> Self {
18        Self { request, ctx }
19    }
20}
21
22impl<'a, M: 'static, PK: 'static, I> ScopedCreateRecord<'a, M, PK, I>
23where
24    I: CreateModelInput<M>,
25{
26    pub fn preview_sql(&self) -> String {
27        self.request.preview_sql()
28    }
29
30    pub async fn run(self) -> Result<M, CoolError>
31    where
32        for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
33    {
34        self.request.run(&self.ctx).await
35    }
36
37    pub async fn run_in_tx<'tx>(
38        self,
39        tx: &mut sqlx::Transaction<'tx, sqlx::Postgres>,
40    ) -> Result<M, CoolError>
41    where
42        for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
43    {
44        self.request.run_in_tx(tx, &self.ctx).await
45    }
46}
47
48#[derive(Debug, Clone)]
49pub struct ScopedUpsertRecord<'a, M: 'static, PK: 'static, I> {
50    request: UpsertRecord<'a, M, PK, I>,
51    ctx: CoolContext,
52}
53
54impl<'a, M: 'static, PK: 'static, I> ScopedUpsertRecord<'a, M, PK, I> {
55    pub(super) fn new(request: UpsertRecord<'a, M, PK, I>, ctx: CoolContext) -> Self {
56        Self { request, ctx }
57    }
58}
59
60impl<'a, M: 'static, PK: 'static, I> ScopedUpsertRecord<'a, M, PK, I>
61where
62    I: UpsertModelInput<M>,
63{
64    /// See [`UpsertRecord::on_conflict`].
65    pub fn on_conflict(mut self, target: cratestack_sql::ConflictTarget) -> Self {
66        self.request = self.request.on_conflict(target);
67        self
68    }
69
70    pub fn preview_sql(&self) -> String {
71        self.request.preview_sql()
72    }
73
74    pub async fn run(self) -> Result<M, CoolError>
75    where
76        for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
77        PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
78    {
79        self.request.run(&self.ctx).await
80    }
81
82    pub async fn run_in_tx<'tx>(
83        self,
84        tx: &mut sqlx::Transaction<'tx, sqlx::Postgres>,
85    ) -> Result<M, CoolError>
86    where
87        for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
88        PK: Send + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
89    {
90        self.request.run_in_tx(tx, &self.ctx).await
91    }
92}
93
94#[derive(Debug, Clone)]
95pub struct ScopedUpdateRecord<'a, M: 'static, PK: 'static> {
96    request: UpdateRecord<'a, M, PK>,
97    ctx: CoolContext,
98}
99
100impl<'a, M: 'static, PK: 'static> ScopedUpdateRecord<'a, M, PK> {
101    pub(super) fn new(request: UpdateRecord<'a, M, PK>, ctx: CoolContext) -> Self {
102        Self { request, ctx }
103    }
104
105    pub fn set<I>(self, input: I) -> ScopedUpdateRecordSet<'a, M, PK, I> {
106        ScopedUpdateRecordSet {
107            request: self.request.set(input),
108            ctx: self.ctx,
109        }
110    }
111}
112
113#[derive(Debug, Clone)]
114pub struct ScopedUpdateRecordSet<'a, M: 'static, PK: 'static, I> {
115    request: UpdateRecordSet<'a, M, PK, I>,
116    ctx: CoolContext,
117}
118
119impl<'a, M: 'static, PK: 'static, I> ScopedUpdateRecordSet<'a, M, PK, I>
120where
121    I: UpdateModelInput<M>,
122{
123    pub fn preview_sql(&self) -> String {
124        self.request.preview_sql()
125    }
126
127    pub async fn run(self) -> Result<M, CoolError>
128    where
129        for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
130        PK: Send + Clone + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
131    {
132        self.request.run(&self.ctx).await
133    }
134
135    pub async fn run_in_tx<'tx>(
136        self,
137        tx: &mut sqlx::Transaction<'tx, sqlx::Postgres>,
138    ) -> Result<M, CoolError>
139    where
140        for<'r> M: Send + Unpin + sqlx::FromRow<'r, sqlx::postgres::PgRow> + serde::Serialize,
141        PK: Send + Clone + sqlx::Type<sqlx::Postgres> + for<'q> sqlx::Encode<'q, sqlx::Postgres>,
142    {
143        self.request.run_in_tx(tx, &self.ctx).await
144    }
145
146    /// Attach an expected version for optimistic locking. See
147    /// [`UpdateRecordSet::if_match`].
148    pub fn if_match(mut self, expected: i64) -> Self {
149        self.request = self.request.if_match(expected);
150        self
151    }
152}