sim_lib_doc_store/
evidence.rs1use 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;
11pub 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}
39pub 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}