use super::vars as Vars;
use crate::err::LDError;
use language::Language;
use nostr::{
event::EventId, types::url::Error as RelayUrlError,
types::url::ParseError as RelayUrlParseError, PublicKey, RelayUrl,
Timestamp,
};
use oxigraph::model::{IriParseError, NamedNode};
use oxiri::Iri;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::convert::TryInto;
use std::fmt;
use std::marker::PhantomData;
use std::time::SystemTime;
use url::Url;
pub trait RowExtractor {
fn event_id(&self) -> Result<EventId, nostr::event::Error> {
Err(nostr::event::Error::InvalidId)
}
fn public_key(&self) -> Result<PublicKey, nostr::key::Error> {
Err(nostr::key::Error::InvalidPublicKey)
}
fn seen_at(&self) -> Option<Timestamp> {
None
}
fn content_type(&self) -> Option<String> {
None
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum RdfCellValue {
Int(i32),
Float(f64),
Text(String),
Node(String),
Blank(),
}
impl TryInto<i32> for RdfCellValue {
type Error = ();
fn try_into(self) -> Result<i32, Self::Error> {
match self {
RdfCellValue::Int(value) => Ok(value),
_ => todo!(),
}
}
}
impl TryInto<u64> for RdfCellValue {
type Error = &'static str;
fn try_into(self) -> Result<u64, Self::Error> {
match self {
RdfCellValue::Int(value) => {
let v: u64 = value as u64;
Ok(v)
}
_ => todo!(),
}
}
}
impl TryInto<PublicKey> for RdfCellValue {
type Error = nostr::key::Error;
fn try_into(self) -> Result<PublicKey, Self::Error> {
match self {
RdfCellValue::Text(value) => Ok(PublicKey::parse(&value)?),
_ => Err(Self::Error::InvalidPublicKey),
}
}
}
impl fmt::Display for RdfCellValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RdfCellValue::Int(value) => {
write!(f, "{}", value)
}
RdfCellValue::Float(value) => {
write!(f, "{}", value)
}
RdfCellValue::Text(value) => {
write!(f, "{}", value)
}
RdfCellValue::Node(value) => {
write!(f, "{}", value)
}
_ => {
write!(f, "NA")
}
}
}
}
impl RdfCellValue {
pub fn to_named_node(&self) -> Result<NamedNode, IriParseError> {
match self {
RdfCellValue::Node(value) => {
Ok(NamedNode::from(Iri::parse(value.to_string())?))
}
RdfCellValue::Text(value) => {
Ok(NamedNode::from(Iri::parse(value.to_string())?))
}
_ => todo!(),
}
}
pub fn to_event_id(&self) -> Result<EventId, nostr::event::Error> {
match self {
RdfCellValue::Text(value) => Ok(EventId::parse(value)?),
_ => Err(nostr::event::Error::InvalidId),
}
}
pub fn to_public_key(&self) -> Result<PublicKey, nostr::key::Error> {
match self {
RdfCellValue::Text(value) => Ok(PublicKey::parse(value)?),
_ => Err(nostr::key::Error::InvalidPublicKey),
}
}
pub fn to_language(&self) -> Result<Language, Box<dyn std::error::Error>> {
match self {
RdfCellValue::Text(value) => {
match Language::from_tag(value.as_str()) {
Some(lang) => Ok(lang),
None => Err(Box::from("No such language")),
}
}
_ => Err(Box::from("Invalid cell")),
}
}
}
impl TryInto<i32> for RdfCell {
type Error = ();
fn try_into(self) -> Result<i32, Self::Error> {
Ok(self.value.try_into()?)
}
}
impl TryInto<u64> for RdfCell {
type Error = &'static str;
fn try_into(self) -> Result<u64, Self::Error> {
Ok(self.value.try_into()?)
}
}
impl TryInto<String> for &RdfCell {
type Error = &'static str;
fn try_into(self) -> Result<String, Self::Error> {
Ok(format!("{}", self.value))
}
}
impl TryInto<Timestamp> for &RdfCell {
type Error = LDError;
fn try_into(self) -> Result<Timestamp, Self::Error> {
match self.value {
RdfCellValue::Int(value) => Ok(Timestamp::from_secs(
value
.try_into()
.map_err(|_| LDError::InvalidTimestampError)?,
)),
_ => Err(LDError::CellValueError),
}
}
}
impl TryInto<PublicKey> for &RdfCell {
type Error = nostr::key::Error;
fn try_into(self) -> Result<PublicKey, Self::Error> {
match &self.value {
RdfCellValue::Text(value) => Ok(PublicKey::parse(&value)?),
_ => Err(Self::Error::InvalidPublicKey),
}
}
}
impl TryInto<RelayUrl> for &RdfCell {
type Error = RelayUrlError;
fn try_into(self) -> Result<RelayUrl, Self::Error> {
match &self.value {
RdfCellValue::Text(value) => {
let vals = value.to_string();
Ok(RelayUrl::parse(vals.as_str())?)
}
_ => Err(RelayUrlError::Url(RelayUrlParseError::EmptyHost)),
}
}
}
impl RdfCell {
pub fn new(name: String, value: RdfCellValue) -> Self {
Self { name, value }
}
pub fn new_text(name: &str, s: String) -> Self {
Self {
name: name.to_string(),
value: RdfCellValue::Text(s),
}
}
pub fn to_string(&self) -> String {
format!("{}", self.value)
}
pub fn to_int(&self) -> Option<i32> {
match self.value {
RdfCellValue::Int(value) => Some(value),
_ => None,
}
}
pub fn to_ts(&self) -> Result<Timestamp, LDError> {
match self.value {
RdfCellValue::Int(value) => Ok(Timestamp::from_secs(
value
.try_into()
.map_err(|_| LDError::InvalidTimestampError)?,
)),
_ => Err(LDError::CellValueError),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RdfCell {
pub name: String,
pub value: RdfCellValue,
}
pub type RdfResultRow = HashMap<String, RdfCell>;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TRdfResultRow<T>(pub HashMap<String, RdfCell>, pub PhantomData<T>)
where
T: std::clone::Clone;
impl<T: std::clone::Clone> From<TRdfResultRow<T>> for RdfResultRow {
fn from(row: TRdfResultRow<T>) -> Self {
row.0
}
}
pub const CONCAT_SEP: &str = ",";
impl<T: std::clone::Clone> TRdfResultRow<T> {
pub fn get(&self, key: &str) -> Option<&RdfCell> {
self.0.get(key)
}
pub fn get_string(&self, key: &str) -> Option<String> {
self.0.get(key).and_then(|cell| Some(cell.to_string()))
}
pub fn get_url(&self, key: &str) -> Option<Url> {
self.0.get(key).and_then(|cell| {
if let Ok(url) = Url::parse(&cell.to_string()) {
return Some(url);
}
None
})
}
pub fn get_deconcat(&self, key: &str) -> Option<RdfCell> {
if let Some(cell) = self.0.get(key) {
let values: Vec<String> = cell
.to_string()
.split(CONCAT_SEP)
.map(str::to_string)
.collect();
if let Some(val) = values.last() {
return Some(RdfCell {
name: cell.name.clone(),
value: RdfCellValue::Text(val.to_string()),
});
}
}
None
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RdfResultSet {
pub when: SystemTime,
pub column_headings: Vec<String>,
pub rows: Vec<RdfResultRow>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TRdfResultSet<T: std::clone::Clone> {
pub when: SystemTime,
pub column_headings: Vec<String>,
pub rows: Vec<TRdfResultRow<T>>,
}
impl<T: std::clone::Clone> Into<TRdfResultRow<T>> for RdfResultRow {
fn into(self) -> TRdfResultRow<T> {
TRdfResultRow::<T>(self, PhantomData)
}
}
impl<T: std::clone::Clone> Into<TRdfResultSet<T>> for RdfResultSet {
fn into(self) -> TRdfResultSet<T> {
TRdfResultSet::<T> {
when: self.when,
column_headings: self.column_headings,
rows: self.rows.iter().map(|r| r.clone().into()).collect(),
}
}
}
impl<T: std::clone::Clone> TRdfResultSet<T> {
pub fn count(&self) -> usize {
self.rows.len()
}
pub fn first(&self) -> Option<TRdfResultRow<T>> {
if self.count() > 0 {
return Some(self.rows[0].clone());
}
None
}
}
impl RdfResultSet {
pub fn count(&self) -> usize {
self.rows.len()
}
pub fn first(&self) -> Option<RdfResultRow> {
if self.count() > 0 {
return Some(self.rows[0].clone());
}
None
}
}
impl<T: std::clone::Clone> RowExtractor for TRdfResultRow<T> {
fn event_id(&self) -> Result<EventId, nostr::event::Error> {
match self.get(Vars::EVENT_ID) {
Some(ev_id) => Ok(ev_id.value.to_event_id()?),
None => Err(nostr::event::Error::InvalidId),
}
}
fn public_key(&self) -> Result<PublicKey, nostr::key::Error> {
match self.get(Vars::PUBK) {
Some(pubk) => Ok(pubk.value.to_public_key()?),
None => Err(nostr::key::Error::InvalidPublicKey),
}
}
fn seen_at(&self) -> Option<Timestamp> {
match self.get(Vars::EVENT_SEEN_AT) {
Some(cell) => match cell.try_into() {
Ok(ts) => Some(ts),
Err(_e) => None,
},
None => None,
}
}
fn content_type(&self) -> Option<String> {
match self.get(Vars::CONTENT_TYPE) {
Some(cell) => Some(cell.to_string()),
None => None,
}
}
}