use super::manager::{RdfEventsStore, RdfStoreError};
use super::util::subl;
use crate::niri::{FromNamedNode, ToNamedNode};
use crate::oxistore::result_set::*;
use crate::querydb::nrq_get;
use nostr::PublicKey;
use oxigraph::model::vocab::rdf;
use oxigraph::model::*;
use std::sync::Arc;
pub trait FollowListManager {
fn follow_list_node(
&self,
pubk: PublicKey,
name: Option<&str>,
) -> Result<NamedNode, RdfStoreError>;
fn follow_list_add(
&self,
flist_node: NamedNode,
followed_pubk: PublicKey,
) -> Result<(), RdfStoreError>;
}
pub trait FollowPackManager {
fn fpack_follow(
&self,
follower_pubk: &PublicKey,
uuid: &str,
) -> Result<(), RdfStoreError>;
fn fpack_unfollow(
&self,
follower_pubk: &PublicKey,
uuid: &str,
unfollow_members: bool,
) -> Result<bool, RdfStoreError>;
fn fpack_followed(
&self,
follower_pubk: &PublicKey,
uuid: &str,
) -> Result<bool, RdfStoreError>;
fn fpack_members(
&self,
uuid: &str,
) -> Result<Vec<PublicKey>, RdfStoreError>;
fn fpack_sync(
&self,
follower_pubk: &PublicKey,
uuid: &str,
) -> Result<(), RdfStoreError>;
fn fpack_following(
&self,
follower_pubk: &PublicKey,
) -> Result<Vec<String>, RdfStoreError>;
}
pub trait FolloweesManager {
fn follow(
&self,
follower_pubk: PublicKey,
followed_pubk: PublicKey,
) -> Result<(), RdfStoreError>;
fn following(
&self,
follower_pubk: PublicKey,
followed_pubk: PublicKey,
) -> Result<bool, RdfStoreError>;
fn unfollow(
&self,
follower_pubk: PublicKey,
followed_pubk: PublicKey,
) -> Result<(), RdfStoreError>;
fn get_followees(
&self,
follower_pubk: PublicKey,
) -> Result<Arc<RdfResultSet>, RdfStoreError>;
fn followees_pubkeys(
&self,
follower_pubk: PublicKey,
) -> Result<Vec<PublicKey>, RdfStoreError>;
}
const PRED_FOLLOWS: NamedNodeRef<'static> =
NamedNodeRef::new_unchecked("https://w3id.org/nostr#follows");
const PRED_FPACK_FOLLOWS: NamedNodeRef<'static> =
NamedNodeRef::new_unchecked("https://w3id.org/nostr#follows_pack");
const PRED_FLIST_TYPE: NamedNodeRef<'static> =
NamedNodeRef::new_unchecked("http://nostralink.org/FollowList");
impl FollowListManager for RdfEventsStore {
fn follow_list_node(
&self,
pubk: PublicKey,
name: Option<&str>,
) -> Result<NamedNode, RdfStoreError> {
let fl_nn = pubk.named_node_with_f(name.unwrap_or("fl-default"))?;
let _ = self.store.insert(QuadRef::new(
&fl_nn,
rdf::TYPE,
PRED_FLIST_TYPE,
&GraphName::DefaultGraph,
));
Ok(fl_nn)
}
fn follow_list_add(
&self,
flist_node: NamedNode,
followed_pubk: PublicKey,
) -> Result<(), RdfStoreError> {
let followed_nn = followed_pubk.named_node()?;
let _ = self.store.insert(QuadRef::new(
&flist_node,
PRED_FOLLOWS,
&followed_nn,
&GraphName::DefaultGraph,
));
Ok(())
}
}
impl FolloweesManager for RdfEventsStore {
fn follow(
&self,
follower_pubk: PublicKey,
followee_pubk: PublicKey,
) -> Result<(), RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
let followee_nn = followee_pubk.named_node()?;
let _ = self.store.insert(QuadRef::new(
&follower_nn,
PRED_FOLLOWS,
&followee_nn,
&GraphName::DefaultGraph,
));
Ok(())
}
fn following(
&self,
follower_pubk: PublicKey,
followee_pubk: PublicKey,
) -> Result<bool, RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
let followee_nn = followee_pubk.named_node()?;
let results = self
.store
.quads_for_pattern(
Some((&follower_nn).into()),
Some(PRED_FOLLOWS),
Some((&followee_nn).into()),
None,
)
.collect::<Result<Vec<_>, _>>()
.map_err(|_| RdfStoreError::QueryError)?;
Ok(!results.is_empty())
}
fn unfollow(
&self,
follower_pubk: PublicKey,
followee_pubk: PublicKey,
) -> Result<(), RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
let followee_nn = followee_pubk.named_node()?;
let _ = self.store.remove(QuadRef::new(
&follower_nn,
PRED_FOLLOWS,
&followee_nn,
&GraphName::DefaultGraph,
));
Ok(())
}
fn get_followees(
&self,
follower_pubk: PublicKey,
) -> Result<Arc<RdfResultSet>, RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
let subs = [(Variable::new("follower").unwrap(), follower_nn.into())];
self.run_query(&nrq_get("followees").unwrap(), subs, None)
.map_err(|_| RdfStoreError::QueryError)
}
fn followees_pubkeys(
&self,
follower_pubk: PublicKey,
) -> Result<Vec<PublicKey>, RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
let results = self
.store
.quads_for_pattern(
Some((&follower_nn).into()),
Some(PRED_FOLLOWS),
None,
None,
)
.collect::<Result<Vec<_>, _>>()
.map_err(|_| RdfStoreError::QueryError)?;
Ok(results
.iter()
.filter_map(|quad| match &quad.object {
Term::NamedNode(node) => node.from_named_node().ok(),
_ => None,
})
.collect())
}
}
impl FollowPackManager for RdfEventsStore {
fn fpack_follow(
&self,
follower_pubk: &PublicKey,
uuid: &str,
) -> Result<(), RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
let _ = self.store.insert(QuadRef::new(
&follower_nn,
PRED_FPACK_FOLLOWS,
&Literal::from(uuid),
&GraphName::DefaultGraph,
));
self.fpack_sync(follower_pubk, uuid)
}
fn fpack_unfollow(
&self,
follower_pubk: &PublicKey,
uuid: &str,
unfollow_members: bool,
) -> Result<bool, RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
if unfollow_members {
for pubk in self.fpack_members(uuid)? {
self.unfollow(*follower_pubk, pubk)?;
}
}
self.store
.remove(QuadRef::new(
&follower_nn,
PRED_FPACK_FOLLOWS,
&Literal::from(uuid),
&GraphName::DefaultGraph,
))
.map_err(|_| RdfStoreError::QueryError)
}
fn fpack_followed(
&self,
follower_pubk: &PublicKey,
uuid: &str,
) -> Result<bool, RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
self.store
.contains(QuadRef::new(
&follower_nn,
PRED_FPACK_FOLLOWS,
&Literal::from(uuid),
&GraphName::DefaultGraph,
))
.map_err(|_| RdfStoreError::QueryError)
}
fn fpack_members(
&self,
uuid: &str,
) -> Result<Vec<PublicKey>, RdfStoreError> {
let subs = [subl("uuid", Literal::from(uuid))?];
Ok(self
.run_query(&nrq_get("follow_pack_members").unwrap(), subs, None)
.map_err(|_| RdfStoreError::QueryError)?
.rows
.iter()
.filter_map(|row| {
let m_pubk = row.get("member_pubk").unwrap();
m_pubk.value.to_public_key().ok()
})
.collect())
}
fn fpack_sync(
&self,
follower_pubk: &PublicKey,
uuid: &str,
) -> Result<(), RdfStoreError> {
for pubk in self.fpack_members(uuid)? {
self.follow(*follower_pubk, pubk)?;
}
Ok(())
}
fn fpack_following(
&self,
follower_pubk: &PublicKey,
) -> Result<Vec<String>, RdfStoreError> {
let follower_nn = follower_pubk.named_node()?;
let results = self
.store
.quads_for_pattern(
Some((&follower_nn).into()),
Some(PRED_FPACK_FOLLOWS),
None,
None,
)
.collect::<Result<Vec<_>, _>>()
.map_err(|_| RdfStoreError::QueryError)?;
Ok(results
.iter()
.filter_map(|quad| match &quad.object {
Term::Literal(uuid) => Some(uuid.value().to_string()),
_ => None,
})
.collect())
}
}