Skip to main content

persistant_relational/
backend.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2use crate::{Dialect, RelError, Row, Value};
3use std::future::Future;
4
5/// The isolation level a transaction asks for. A backend gives the level asked for or a stronger one;
6/// which it can actually show is what the `rel.isolation.*` leaves certify.
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
8#[non_exhaustive]
9pub enum Isolation {
10    /// No dirty reads: the backend's usual level for a transaction here.
11    #[default]
12    ReadCommitted,
13    /// A row or count read twice in the transaction reads the same.
14    RepeatableRead,
15    /// Concurrent transactions behave as if they ran one at a time (a conflicting one fails with
16    /// [`RelError::Serialization`], or waits).
17    Serializable,
18}
19
20/// A relational database, as small as it can be.
21///
22/// Statements are written in the backend's own [`Dialect`]; parameters are positional and written
23/// as that dialect writes them (`$1` for PostgreSQL). Nothing here translates SQL.
24pub trait RelationalBackend: Send + Sync {
25    /// A transaction on this backend. Dropping it without `commit` rolls it back.
26    type Tx<'a>: RelationalTx + 'a
27    where
28        Self: 'a;
29
30    /// The backend's name as it appears in matrix rows (`postgres`).
31    fn backend(&self) -> &str;
32
33    /// The server version string as it appears in matrix rows (`16.15`).
34    fn version(&self) -> &str;
35
36    /// The dialect statements must be written in.
37    fn dialect(&self) -> Dialect;
38
39    /// Run a statement that returns no rows; the result is the number of rows affected.
40    fn execute(
41        &self,
42        sql: &str,
43        params: &[Value],
44    ) -> impl Future<Output = Result<u64, RelError>> + Send;
45
46    /// Run a statement and return its rows.
47    fn query(
48        &self,
49        sql: &str,
50        params: &[Value],
51    ) -> impl Future<Output = Result<Vec<Row>, RelError>> + Send;
52
53    /// Begin a transaction at (at least) `isolation`.
54    fn begin(
55        &self,
56        isolation: Isolation,
57    ) -> impl Future<Output = Result<Self::Tx<'_>, RelError>> + Send;
58}
59
60/// A transaction. Statements run inside it are committed or rolled back together.
61pub trait RelationalTx: Send {
62    /// As [`RelationalBackend::execute`], inside the transaction.
63    fn execute(
64        &mut self,
65        sql: &str,
66        params: &[Value],
67    ) -> impl Future<Output = Result<u64, RelError>> + Send;
68
69    /// As [`RelationalBackend::query`], inside the transaction.
70    fn query(
71        &mut self,
72        sql: &str,
73        params: &[Value],
74    ) -> impl Future<Output = Result<Vec<Row>, RelError>> + Send;
75
76    /// Commit.
77    fn commit(self) -> impl Future<Output = Result<(), RelError>> + Send;
78
79    /// Roll back.
80    fn rollback(self) -> impl Future<Output = Result<(), RelError>> + Send;
81}