use super::manager::{RdfEventsStore, RdfStoreError};
use nostr::event::EventId;
use oxigraph::model::*;
use std::str::FromStr;
use std::time::{SystemTime, UNIX_EPOCH};
use urn::Urn;
pub trait EventBookmarks {
fn bookmark(
&self,
event_uri: NamedNode,
title: String,
) -> Result<(), RdfStoreError>;
fn get_bookmarks(
&self,
) -> Result<Vec<(NamedNode, EventId, String)>, RdfStoreError>;
}
fn bookmarks_graph1() -> NamedNode {
NamedNode::new("urn:nostr-bookmarks:1").unwrap()
}
fn bookmarks_root() -> NamedNode {
NamedNode::new("urn:nostr-bookmarks:root").unwrap()
}
fn pred_bookmark_event() -> NamedNode {
NamedNode::new("https://w3id.org/nostr#eventBookmark").unwrap()
}
fn pred_bookmark_title() -> NamedNode {
NamedNode::new("https://w3id.org/nostr#bookmarkTitle").unwrap()
}
fn pred_bookmark_dateadded() -> NamedNode {
NamedNode::new("https://w3id.org/nostr#bookmarkDateAdded").unwrap()
}
fn evuri_to_eventid(node: NamedNode) -> Result<EventId, RdfStoreError> {
let urn = Urn::from_str(node.into_string().as_str())
.map_err(|_| RdfStoreError::URNError)?;
Ok(EventId::parse(urn.nss()).map_err(|_| RdfStoreError::URNError)?)
}
const BQUERY: &str = "
SELECT ?root ?event ?title ?date_added
FROM <urn:nostr-bookmarks:1>
WHERE {
?root nostr:eventBookmark ?event .
?event nostr:bookmarkTitle ?title .
?event nostr:bookmarkDateAdded ?date_added .
}
ORDER BY DESC(?date_added)
";
fn get_epoch_ms() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
}
impl EventBookmarks for RdfEventsStore {
fn bookmark(
&self,
event_uri: NamedNode,
title: String,
) -> Result<(), RdfStoreError> {
let pred_b = pred_bookmark_event();
let pred_title = pred_bookmark_title();
let root = bookmarks_root();
let bnode = bookmarks_graph1();
let _ = self
.store
.insert(QuadRef::new(&root, &pred_b, &event_uri, &bnode));
let _ = self.store.insert(QuadRef::new(
&event_uri,
&pred_title,
&Literal::from(title),
&bnode,
));
let _ = self.store.insert(QuadRef::new(
&event_uri,
&pred_bookmark_dateadded(),
&Literal::from(get_epoch_ms()),
&bnode,
));
Ok(())
}
fn get_bookmarks(
&self,
) -> Result<Vec<(NamedNode, EventId, String)>, RdfStoreError> {
let subs = [(
Variable::new("root").unwrap(),
Term::NamedNode(bookmarks_root()),
)];
let results = self
.run_query(&BQUERY.to_string(), subs, None)
.map_err(|_| RdfStoreError::QueryError)?;
let mut v = Vec::new();
for row in &results.rows {
let event = row.get("event").unwrap();
let title = row.get("title").unwrap();
let event_uri = event
.value
.to_named_node()
.map_err(|_| RdfStoreError::NamedNodeError)?;
let evid = evuri_to_eventid(event_uri.clone())
.map_err(|_| RdfStoreError::URNError)
.unwrap();
v.push((event_uri.clone(), evid, title.to_string()));
}
Ok(v)
}
}