Skip to main content

sim_lib_doc_store/
web.rs

1//! Typed persistence rows for web captures and evidence anchors.
2use crate::{
3    DocStore,
4    store::{StoreError, StoreResult, bytes, cell_bytes, cell_text, text},
5};
6/// Serialized immutable capture row.
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct WebCaptureRow {
9    /// Stable raw capture id.
10    pub capture_id: String,
11    /// Normalized retrieval URI.
12    pub source_uri: String,
13    /// Exact response bytes.
14    pub body: Vec<u8>,
15    /// Versioned exchange metadata.
16    pub exchange_json: String,
17}
18/// Serialized normalized representation row.
19#[derive(Clone, Debug, PartialEq, Eq)]
20pub struct WebRepresentationRow {
21    /// Stable representation id.
22    pub representation_id: String,
23    /// Referenced raw capture id.
24    pub capture_id: String,
25    /// Immutable normalized Unicode text.
26    pub text: String,
27    /// Versioned codec and fidelity metadata.
28    pub metadata_json: String,
29}
30/// Serialized evidence anchor row.
31#[derive(Clone, Debug, PartialEq, Eq)]
32pub struct WebAnchorRow {
33    /// Stable anchor id.
34    pub anchor_id: String,
35    /// Office evidence subject id.
36    pub subject: String,
37    /// Addressed representation id.
38    pub representation_id: String,
39    /// Complete versioned anchor record.
40    pub record_json: String,
41}
42impl DocStore {
43    /// Saves a capture, rejecting an id already bound to different bytes.
44    pub fn save_web_capture(&mut self, row: &WebCaptureRow) -> StoreResult<()> {
45        if let Some(old) = self.load_web_capture(&row.capture_id)? {
46            if old.body != row.body {
47                return Err(StoreError::Invalid(
48                    "capture id already names different bytes".into(),
49                ));
50            }
51            return Ok(());
52        }
53        self.insert(
54            "web_captures",
55            &["capture_id", "source_uri", "body", "exchange_json"],
56            vec![
57                text(&row.capture_id),
58                text(&row.source_uri),
59                bytes(row.body.clone()),
60                text(&row.exchange_json),
61            ],
62        )
63    }
64    /// Saves a representation whose capture must already exist.
65    pub fn save_web_representation(&mut self, row: &WebRepresentationRow) -> StoreResult<()> {
66        self.upsert(
67            "web_representations",
68            &["representation_id", "capture_id", "text", "metadata_json"],
69            vec![
70                text(&row.representation_id),
71                text(&row.capture_id),
72                text(&row.text),
73                text(&row.metadata_json),
74            ],
75        )
76    }
77    /// Loads representation fields used to revalidate an anchor.
78    pub fn load_web_representation(&self, id: &str) -> StoreResult<Option<WebRepresentationRow>> {
79        self.select(
80            "web_representations",
81            &["capture_id", "text", "metadata_json"],
82            &[("representation_id", text(id))],
83            &[],
84            Some(1),
85        )?
86        .into_iter()
87        .next()
88        .map(|r| {
89            Ok(WebRepresentationRow {
90                representation_id: id.into(),
91                capture_id: cell_text(&r, 0)?.into(),
92                text: cell_text(&r, 1)?.into(),
93                metadata_json: cell_text(&r, 2)?.into(),
94            })
95        })
96        .transpose()
97    }
98    /// Loads capture provenance fields.
99    pub fn load_web_capture(&self, id: &str) -> StoreResult<Option<WebCaptureRow>> {
100        self.select(
101            "web_captures",
102            &["source_uri", "body", "exchange_json"],
103            &[("capture_id", text(id))],
104            &[],
105            Some(1),
106        )?
107        .into_iter()
108        .next()
109        .map(|r| {
110            Ok(WebCaptureRow {
111                capture_id: id.into(),
112                source_uri: cell_text(&r, 0)?.into(),
113                body: cell_bytes(&r, 1)?.to_vec(),
114                exchange_json: cell_text(&r, 2)?.into(),
115            })
116        })
117        .transpose()
118    }
119    /// Makes a validated anchor visible.
120    pub fn save_web_anchor(&mut self, row: &WebAnchorRow) -> StoreResult<()> {
121        self.upsert(
122            "web_evidence_anchors",
123            &["anchor_id", "subject", "representation_id", "record_json"],
124            vec![
125                text(&row.anchor_id),
126                text(&row.subject),
127                text(&row.representation_id),
128                text(&row.record_json),
129            ],
130        )
131    }
132    /// Loads an anchor row.
133    pub fn load_web_anchor(&self, id: &str) -> StoreResult<Option<WebAnchorRow>> {
134        self.select(
135            "web_evidence_anchors",
136            &["subject", "representation_id", "record_json"],
137            &[("anchor_id", text(id))],
138            &[],
139            Some(1),
140        )?
141        .into_iter()
142        .next()
143        .map(|r| {
144            Ok(WebAnchorRow {
145                anchor_id: id.into(),
146                subject: cell_text(&r, 0)?.into(),
147                representation_id: cell_text(&r, 1)?.into(),
148                record_json: cell_text(&r, 2)?.into(),
149            })
150        })
151        .transpose()
152    }
153}