Skip to main content

sim_lib_doc_store/
evidence.rs

1//! Evidence-link storage through the checked relational session.
2use crate::{
3    DocStore,
4    store::{
5        StoreError, StoreResult, cell_i64, cell_optional_text, cell_text, integer, nullable_text,
6        text,
7    },
8};
9use sim_lib_doc_core::{DocId, Evidence, ExternalRef, LinkRole};
10use sim_relation_plan::OrderDirection;
11/// Attaches an evidence fact.
12pub fn attach(store: &DocStore, e: &Evidence) -> StoreResult<()> {
13    let object =
14        serde_json::to_string(&e.evidence).map_err(|x| StoreError::Codec(x.to_string()))?;
15    let seq = i64::try_from(e.captured_at_seq).map_err(|_| {
16        StoreError::Invalid(format!(
17            "evidence sequence {} exceeds signed relational domain",
18            e.captured_at_seq
19        ))
20    })?;
21    store.upsert(
22        "evidence_facts",
23        &[
24            "subject",
25            "predicate",
26            "object",
27            "captured_at_seq",
28            "immutable_hint",
29        ],
30        vec![
31            text(e.subject.as_str()),
32            text(e.predicate()),
33            text(object),
34            integer(seq),
35            nullable_text(e.immutable_hint.clone()),
36        ],
37    )
38}
39/// Returns evidence ordered by capture sequence and stable fact identity.
40pub fn evidence_for(store: &DocStore, subject: &DocId) -> StoreResult<Vec<Evidence>> {
41    store
42        .select(
43            "evidence_facts",
44            &["predicate", "object", "captured_at_seq", "immutable_hint"],
45            &[("subject", text(subject.as_str()))],
46            &[
47                ("captured_at_seq", OrderDirection::Asc),
48                ("predicate", OrderDirection::Asc),
49                ("object", OrderDirection::Asc),
50            ],
51            None,
52        )?
53        .into_iter()
54        .map(|r| {
55            let predicate = cell_text(&r, 0)?;
56            let role = LinkRole::from_predicate(predicate).ok_or_else(|| {
57                StoreError::Codec(format!("unknown evidence predicate {predicate}"))
58            })?;
59            let reference: ExternalRef = serde_json::from_str(cell_text(&r, 1)?)
60                .map_err(|e| StoreError::Codec(e.to_string()))?;
61            let seq = cell_i64(&r, 2)?;
62            let seq = u64::try_from(seq)
63                .map_err(|_| StoreError::Codec(format!("negative evidence sequence {seq}")))?;
64            Ok(Evidence::new(
65                subject.clone(),
66                reference,
67                role,
68                seq,
69                cell_optional_text(&r, 3)?.map(str::to_owned),
70            ))
71        })
72        .collect()
73}