1use anyhow::Result;
2use oxigraph::model::*;
3use oxigraph::store::Store;
4use std::collections::HashMap;
5use std::path::PathBuf;
6use std::sync::RwLock;
7
8pub struct SynapseStore {
9 pub store: Store,
10 pub namespace: String,
11 pub id_to_uri: RwLock<HashMap<u32, String>>,
13 pub uri_to_id: RwLock<HashMap<String, u32>>,
14 pub next_id: std::sync::atomic::AtomicU32,
15}
16
17impl SynapseStore {
18 pub fn open(namespace: &str, storage_path: &str) -> Result<Self> {
19 let path = PathBuf::from(storage_path).join(namespace);
20 let store = Store::open(path)?;
21
22 Ok(Self {
23 store,
24 namespace: namespace.to_string(),
25 id_to_uri: RwLock::new(HashMap::new()),
26 uri_to_id: RwLock::new(HashMap::new()),
27 next_id: std::sync::atomic::AtomicU32::new(1),
28 })
29 }
30
31 pub fn get_or_create_id(&self, uri: &str) -> u32 {
32 {
33 let map = self.uri_to_id.read().unwrap();
34 if let Some(&id) = map.get(uri) {
35 return id;
36 }
37 }
38
39 let mut uri_map = self.uri_to_id.write().unwrap();
40 let mut id_map = self.id_to_uri.write().unwrap();
41
42 if let Some(&id) = uri_map.get(uri) {
43 return id;
44 }
45
46 let id = self.next_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
47 uri_map.insert(uri.to_string(), id);
48 id_map.insert(id, uri.to_string());
49 id
50 }
51
52 pub fn get_uri(&self, id: u32) -> Option<String> {
53 self.id_to_uri.read().unwrap().get(&id).cloned()
54 }
55
56 pub fn ingest_triples(&self, triples: Vec<(String, String, String)>) -> Result<(u32, u32)> {
57 let mut added = 0;
58
59 for (s, p, o) in triples {
60 let subject_uri = self.ensure_uri(&s);
61 let predicate_uri = self.ensure_uri(&p);
62 let object_uri = self.ensure_uri(&o);
63
64 let subject = Subject::NamedNode(NamedNode::new_unchecked(&subject_uri));
65 let predicate = NamedNode::new_unchecked(&predicate_uri);
66 let object = Term::NamedNode(NamedNode::new_unchecked(&object_uri));
67
68 let quad = Quad::new(subject, predicate, object, GraphName::DefaultGraph);
69 if self.store.insert(&quad)? {
70 added += 1;
71 }
72 }
73
74 Ok((added, 0))
75 }
76
77 fn ensure_uri(&self, s: &str) -> String {
78 if s.starts_with("http") {
79 s.to_string()
80 } else {
81 format!("http://synapse.os/{}", s)
82 }
83 }
84}