use super::prelude::*;
use nostr_sdk::prelude::*;
use std::time::Duration;
pub trait EventStateOperations {
fn mark_seen(
&self,
agent_pubk: &PublicKey,
event_id: &EventId,
seen: bool,
) -> Result<bool, RdfStoreError>;
fn mark_row_seen<T: Clone>(
&self,
agent_pubk: &PublicKey,
row: &TRdfResultRow<T>,
seen: bool,
) -> Result<bool, RdfStoreError>;
}
fn pred_user_seen_at() -> NamedNode {
nostr_vocab_nn("user_seen_at")
}
fn pred_user_seen_by() -> NamedNode {
nostr_vocab_nn("user_seen_by")
}
impl EventStateOperations for RdfEventsStore {
fn mark_seen(
&self,
agent_pubk: &PublicKey,
event_id: &EventId,
_seen: bool,
) -> Result<bool, RdfStoreError> {
let agent_nn = agent_pubk.named_node()?;
let event_nn = event_id.named_node()?;
let Ok(_) = self.store.insert(QuadRef::new(
&event_nn,
&pred_user_seen_at(),
&now_literal(),
&GraphName::DefaultGraph,
)) else {
return Err(RdfStoreError::QuadInsertError);
};
let Ok(_) = self.store.insert(QuadRef::new(
&event_nn,
&pred_user_seen_by(),
&agent_nn,
&GraphName::DefaultGraph,
)) else {
return Err(RdfStoreError::QuadInsertError);
};
Ok(true)
}
fn mark_row_seen<T: Clone>(
&self,
agent_pubk: &PublicKey,
row: &TRdfResultRow<T>,
_seen: bool,
) -> Result<bool, RdfStoreError> {
let agent_nn = agent_pubk.named_node()?;
let Some(event) = row.get(SPVars::EVENT) else {
return Err(RdfStoreError::BadEventError);
};
let event_nn = event.value.to_named_node()?;
if self.store.contains(
QuadRef::new(
&event_nn,
&pred_user_seen_by(),
&agent_nn,
&GraphName::DefaultGraph,
),
)? {
return Ok(false);
}
let Ok(_) = self.store.insert(QuadRef::new(
&event_nn,
&pred_user_seen_at(),
&now_literal(),
&GraphName::DefaultGraph,
)) else {
return Err(RdfStoreError::QuadInsertError);
};
let Ok(_) = self.store.insert(QuadRef::new(
&event_nn,
&pred_user_seen_by(),
&agent_nn,
&GraphName::DefaultGraph,
)) else {
return Err(RdfStoreError::QuadInsertError);
};
Ok(true)
}
}
pub trait EventStoreOperations {
fn sweep(&self, duration: Duration) -> Result<(), RdfStoreError>;
fn delete_events_older_than(
&self,
ts: Timestamp,
ekinds: Option<Vec<Kind>>,
pubkeys: Option<Vec<PublicKey>>,
) -> Result<(), RdfStoreError>;
}
impl EventStoreOperations for RdfEventsStore {
fn delete_events_older_than(
&self,
ts: Timestamp,
ekinds: Option<Vec<Kind>>,
pubkeys: Option<Vec<PublicKey>>,
) -> Result<(), RdfStoreError> {
let mut kf = String::new();
let mut pubkf = String::new();
if let Some(kinds) = ekinds {
let values = kinds
.iter()
.map(|kind| format!("(?kind = {})", kind.to_string()))
.collect::<Vec<_>>()
.join(" || ");
kf.push_str(&format!("FILTER({})", values));
}
if let Some(pubkl) = pubkeys {
let values = pubkl
.iter()
.map(|pk| format!("(?pubk = {})", pk.to_hex()))
.collect::<Vec<_>>()
.join(" || ");
pubkf.push_str(&format!("FILTER({})", values));
}
let q = self
.prepare_query(&nrq_get("delete_events_before")?)
.replace("@KIND_FILTER@", &kf)
.replace("@PUBK_FILTER@", &kf)
.replace("@TS@", &format!("{}", ts.as_u64()));
match self.store.update(
Update::parse(&q, None).map_err(|_| RdfStoreError::QueryError)?,
) {
Ok(_r) => Ok(()),
Err(_e) => Err(RdfStoreError::QueryError),
}
}
fn sweep(&self, duration_before: Duration) -> Result<(), RdfStoreError> {
let kinds = vec![
Kind::TextNote,
Kind::LongFormTextNote,
Kind::Repost,
Kind::GenericRepost,
Kind::Reaction,
];
self.delete_events_older_than(
Timestamp::now() - duration_before,
Some(kinds),
None,
)
}
}