Skip to main content

coven_database/
prerequisite_rows.rs

1//! The rows whose commits can change what a waiting operation needs (§6.7,
2//! §21.2; IO `WaitingEvidence`). A commit changing one of a wait's rows
3//! is evidence for that wait; no other commit is. The rows are exactly what
4//! the waiting work reads, including advancement of the shared prefix.
5
6use crate::observation::TableRead;
7use crate::row_scope::RowScope;
8use crate::sql_value::SqlValue;
9use crate::WriteId;
10use coven_foundation::id_source::DeviceId;
11use coven_merge::Audience;
12
13/// Committed state a waiting operation names.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub enum PrerequisiteRows {
16    /// The applied store prefix.
17    Slot,
18    /// This installation's active claim and settlement.
19    Claim,
20    /// An original write's queue and counted prefix.
21    Write(WriteId),
22    /// An audience's pending reload.
23    Reload(Audience),
24    /// A provider account's access record.
25    ProviderAccess(String),
26    /// Another operation's journal row: it advances or finishes.
27    Operation(crate::OperationId),
28}
29
30fn blob(value: impl Into<Vec<u8>>) -> SqlValue {
31    SqlValue::Blob(value.into())
32}
33
34fn text(value: &str) -> SqlValue {
35    SqlValue::Text(value.as_bytes().to_vec())
36}
37
38fn device(device: DeviceId) -> SqlValue {
39    blob(device.0.to_be_bytes())
40}
41
42fn number(number: u64) -> SqlValue {
43    blob(number.to_be_bytes())
44}
45
46/// Rows of `table` whose primary key holds `key`, through every listed
47/// column: its non-key columns, so an update to any of them counts.
48fn rows(table: &str, key: &[(&str, SqlValue)], columns: &[&str]) -> TableRead {
49    let scope = key
50        .iter()
51        .map(|(column, value)| RowScope::equal((*column).into(), vec![value.clone()]))
52        .fold(RowScope::All, RowScope::and);
53    TableRead {
54        table: table.into(),
55        columns: columns.iter().map(|column| (*column).into()).collect(),
56        scope,
57        inserted_only: false,
58    }
59}
60
61const UPLOADS: &[&str] = &["record"];
62const UPLOAD_KEYS: &[&str] = &["sealing_keys"];
63const UPLOAD_CLAIMS: &[&str] = &["claim"];
64const DATA_RELOADS: &[&str] = &["subject"];
65const PROVIDER_ACCESS: &[&str] = &["intended", "granted", "invitation", "operation", "target"];
66const OPERATIONS: &[&str] = &["kind", "last_step", "data", "started_by"];
67
68impl PrerequisiteRows {
69    pub(crate) fn reads(&self) -> Vec<TableRead> {
70        match self {
71            Self::Slot => vec![rows("_coven_sequence", &[], &["applied"])],
72            Self::Claim => vec![rows(
73                "_coven_claim_journal",
74                &[],
75                &["through", "operation", "settlement", "singleton"],
76            )],
77            Self::Write(write) => {
78                let at = [("device", device(write.device)), ("number", number(write.number))];
79                vec![
80                    rows("_coven_sequence", &[], &["applied"]),
81                    rows("_coven_uploads", &at, UPLOADS),
82                    rows("_coven_upload_keys", &at, UPLOAD_KEYS),
83                    rows("_coven_upload_claims", &at, UPLOAD_CLAIMS),
84                ]
85            }
86            Self::Reload(audience) => vec![rows(
87                "_coven_data_reloads",
88                &[("audience", text(&audience.to_string()))],
89                DATA_RELOADS,
90            )],
91            Self::ProviderAccess(account) => {
92                vec![rows("_coven_provider_access", &[("account", text(account))], PROVIDER_ACCESS)]
93            }
94            Self::Operation(id) => {
95                vec![rows("_coven_operations", &[("id", SqlValue::Integer(id.0))], OPERATIONS)]
96            }
97        }
98    }
99}
100
101#[cfg(test)]
102#[path = "prerequisite_rows_tests.rs"]
103mod tests;