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_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>;
}
fn pred_follows() -> NamedNode {
NamedNode::new_unchecked("https://w3id.org/nostr#follows")
}
fn pred_fpack_follow() -> NamedNode {
NamedNode::new_unchecked("https://w3id.org/nostr#follows_pack")
}
#[allow(dead_code)]
fn pred_fl_owner() -> NamedNode {
NamedNode::new_unchecked("https://w3id.org/nostr#followListOwner")
}
fn list_type() -> NamedNode {
NamedNode::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,
&list_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()).into()),
Some((&followee_nn).into()),
None,
)
.collect::<Result<Vec<_>, _>>()
.map_err(|_| RdfStoreError::QueryError)?;
Ok(results.len() > 0)
}
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())];
Ok(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()).into()),
None,
None,
)
.collect::<Result<Vec<_>, _>>()
.map_err(|_| RdfStoreError::QueryError)?;
Ok(results
.iter()
.filter_map(|quad| match &quad.object {
Term::NamedNode(node) => match node.from_named_node() {
Ok(pubk) => Some(pubk),
Err(_) => None,
},
_ => 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_follow(),
&Literal::from(uuid),
&GraphName::DefaultGraph,
));
Ok(())
}
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();
match m_pubk.value.to_public_key() {
Ok(pubk) => Some(pubk),
Err(_) => None,
}
})
.collect())
}
fn fpack_sync(
&self,
follower_pubk: &PublicKey,
uuid: &str,
) -> Result<(), RdfStoreError> {
for pubk in self.fpack_members(uuid)? {
let _ = 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_follow()).into()),
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())
}
}