nostralink 0.2.3

Linked data library for nostr
Documentation
//! Helpers to build sparql substitutions

use super::vars as SPVars;
use crate::err::LDError;
use crate::niri::ToNamedNode;
use derive_builder::Builder;
use language::Language;
use nostr::{EventId, PublicKey, Timestamp};
use oxigraph::model::*;
use std::time::Duration;

pub fn subl(
    varname: &str,
    literal: Literal,
) -> Result<(Variable, Term), LDError> {
    Ok((
        Variable::new(varname).map_err(|_| LDError::SubstitutionError)?,
        literal.into(),
    ))
}

pub fn subnn(
    varname: &str,
    nn: NamedNode,
) -> Result<(Variable, Term), LDError> {
    Ok((
        Variable::new(varname).map_err(|_| LDError::SubstitutionError)?,
        nn.into(),
    ))
}

#[derive(Builder, Debug, Default)]
#[builder(default)]
pub struct QuerySubs {
    #[builder(setter(strip_option))]
    event_id: Option<EventId>,
    #[builder(setter(strip_option))]
    replies_to_event_id: Option<EventId>,
    #[builder(setter(strip_option))]
    in_forum: Option<EventId>,
    #[builder(setter(strip_option))]
    since: Option<Duration>,
    #[builder(setter(strip_option))]
    author: Option<PublicKey>,
    #[builder(setter(strip_option))]
    identity_nip21: Option<PublicKey>,
    #[builder(setter(strip_option))]
    lang: Option<Language>,
    #[builder(setter(strip_option))]
    hashtag: Option<String>,
    #[builder(setter(strip_option))]
    only_followees: Option<i16>,
}

impl QuerySubs {
    #[deprecated]
    pub fn subs(&self) -> Result<Vec<(Variable, Term)>, LDError> {
        let mut subs_v = Vec::new();
        if let Some(id) = self.event_id {
            subs_v.push(subl(SPVars::EVENT_ID, id.to_hex().into())?);
        }
        Ok(subs_v)
    }

    pub fn subs_with_ckey(
        &self,
    ) -> Result<(Vec<(Variable, Term)>, String), LDError> {
        let mut cache_key = String::new();
        let mut subs_v = Vec::new();

        if let Some(pk) = self.identity_nip21 {
            subs_v.push(subnn("identity_nip21", pk.named_node().unwrap())?);
        }

        if let Some(id) = self.event_id {
            subs_v.push(subl(SPVars::EVENT_ID, id.to_hex().into())?);
            cache_key.push_str(&format!("ev_{}", id.to_hex()));
        }

        if let Some(ev_id) = self.replies_to_event_id {
            subs_v.push(subl("e_tag_value", Literal::from(ev_id.to_hex()))?);
            subs_v.push(subl("filter_e_tag", Literal::from(1))?);
            cache_key.push_str(&format!("_etag_{}", ev_id.to_hex()));
        } else {
            subs_v.push(subl("filter_e_tag", Literal::from(0))?);
        }

        if let Some(since_dur) = self.since {
            let created_since = Timestamp::now() - since_dur;
            subs_v.push(subl(
                "created_at_since",
                Literal::from(created_since.as_u64()),
            )?);
            cache_key.push_str(&format!("since_{}", since_dur.as_secs()));
        }

        if let Some(ref hashtag) = self.hashtag {
            subs_v.push(subl("query_hashtag", Literal::from(hashtag.clone()))?);
            cache_key.push_str(&format!("_ht{}", hashtag));
        }

        if let Some(lang) = self.lang {
            let lang_tag = lang.as_tag();

            subs_v.push(subl(
                "lang_tag_filter",
                Literal::from(lang_tag.to_string()),
            )?);
        } else {
            subs_v.push(subl("lang_tag_filter", Literal::from(""))?);
        }

        if let Some(event_id) = &self.in_forum {
            subs_v.push(subl("f_tag_value", Literal::from(event_id.to_hex()))?);
            subs_v.push(subl("filter_f_tag", Literal::from(1))?);
            cache_key.push_str(&format!("_ftag_{}", event_id.to_hex()));
        } else {
            subs_v.push(subl("filter_f_tag", Literal::from(0))?);
        }

        if let Some(only_f) = self.only_followees {
            subs_v.push(subl("only_followees", Literal::from(only_f))?);
        }

        Ok((subs_v, cache_key))
    }
}

#[test]
fn test_subs() -> Result<(), LDError> {
    let (_, _) = QuerySubsBuilder::default()
        .event_id(EventId::parse("5d35413cad64e6c4e9cd9788b1d82b935744a36582239d753cd4dadca045580a").unwrap())
        .lang(Language::EnGb)
        .build().map_err(|_| LDError::EventBuildError)?
        .subs_with_ckey()?;

    Ok(())
}