Skip to main content

sofie_db/
read.rs

1use sofie_core::{ColumnReader, Result, SqlType, SqlValue, Uuid};
2
3use crate::{Db, Decoding, Dialect, RowSink};
4
5const MAX_RESERVED_ROWS: usize = 1000;
6
7/// Records without an owner stay readable.
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9pub enum Reach {
10    All,
11    /// As `All`, for a principal whose changes history and audit columns name.
12    AllAs(Uuid),
13    OwnedBy(Uuid),
14}
15
16impl Reach {
17    pub(crate) const fn owner(self) -> Option<Uuid> {
18        match self {
19            Self::All | Self::AllAs(_) => None,
20            Self::OwnedBy(owner) => Some(owner),
21        }
22    }
23
24    #[must_use]
25    pub const fn actor(self) -> Option<Uuid> {
26        match self {
27            Self::All => None,
28            Self::AllAs(actor) | Self::OwnedBy(actor) => Some(actor),
29        }
30    }
31}
32
33/// Has no way to write; its reach is fixed when made and cannot be widened.
34#[derive(Clone)]
35pub struct Read {
36    pub(crate) db: Db,
37    reach: Reach,
38}
39
40impl Read {
41    #[must_use]
42    pub fn within(db: &Db, reach: Reach) -> Self {
43        Self {
44            db: db.clone(),
45            reach,
46        }
47    }
48
49    pub(crate) fn owner(&self) -> Option<Uuid> {
50        self.reach.owner()
51    }
52
53    pub(crate) fn actor(&self) -> Option<Uuid> {
54        self.reach.actor()
55    }
56
57    pub(crate) fn across_owners(&self) -> Self {
58        let reach = self.reach.actor().map_or(Reach::All, Reach::AllAs);
59        Self::within(&self.db, reach)
60    }
61
62    pub(crate) fn dialect(&self) -> &dyn Dialect {
63        self.db.driver().dialect()
64    }
65
66    /// Reserves `expected_rows` up to `MAX_RESERVED_ROWS`, as few rows may match a large limit.
67    pub(crate) async fn decoded<T: Send>(
68        &self,
69        sql: &str,
70        params: &[SqlValue],
71        expected_rows: usize,
72        expects: Vec<Option<SqlType>>,
73        decode: impl FnMut(&mut dyn ColumnReader) -> Result<T> + Send,
74    ) -> Result<Vec<T>> {
75        let mut rows = Decoding::new(expects, decode);
76        rows.reserve(expected_rows.min(MAX_RESERVED_ROWS));
77        self.query(sql, params, &mut rows).await?;
78        Ok(rows.into_decoded())
79    }
80
81    async fn query(&self, sql: &str, params: &[SqlValue], rows: &mut dyn RowSink) -> Result<()> {
82        #[cfg(feature = "etag")]
83        if crate::read_versions::tracking() {
84            let mut fingerprinted = crate::read_versions::Fingerprinted::new(rows);
85            self.db
86                .driver()
87                .query(sql, params, &mut fingerprinted)
88                .await?;
89            fingerprinted.record();
90            return Ok(());
91        }
92        self.db.driver().query(sql, params, rows).await
93    }
94}