use crate::object_value::ObjectValue;
use crate::shapemap::Pattern;
use crate::shapemap::SHACLPathRef;
use crate::shapemap::ShapemapError;
use prefixmap::DerefIri;
use prefixmap::IriRef;
use prefixmap::PrefixMap;
use prefixmap::error::PrefixMapError;
use rudof_iri::IriS;
use rudof_rdf::rdf_core::{NeighsRDF, query::QueryRDF, term::literal::ConcreteLiteral};
use serde::Serialize;
use std::fmt::Display;
use thiserror::Error;
use tracing::trace;
#[derive(Debug, PartialEq, Clone, Serialize)]
pub enum NodeSelector {
Node(ObjectValue),
TriplePattern {
subject: Pattern,
path: SHACLPathRef,
object: Pattern,
},
Sparql {
query: String,
},
Generic {
iri: IriS,
param: String,
},
}
impl NodeSelector {
pub fn triple_pattern(subject: Pattern, path: SHACLPathRef, object: Pattern) -> NodeSelector {
NodeSelector::TriplePattern { subject, path, object }
}
pub fn iri_unchecked(str: &str) -> NodeSelector {
NodeSelector::Node(ObjectValue::iri(IriS::new_unchecked(str)))
}
pub fn iri_ref(iri: IriRef) -> NodeSelector {
NodeSelector::Node(ObjectValue::iri_ref(iri))
}
pub fn literal(lit: ConcreteLiteral) -> NodeSelector {
NodeSelector::Node(ObjectValue::literal(lit))
}
pub fn prefixed(alias: &str, local: &str) -> NodeSelector {
NodeSelector::Node(ObjectValue::prefixed(alias, local))
}
pub fn nodes<R>(&self, rdf: &R) -> Result<Vec<R::Term>, ShapemapError>
where
R: QueryRDF,
{
match self {
NodeSelector::Node(value) => {
let term = match value {
ObjectValue::IriRef(iri_ref) => {
let iri = iri_ref
.get_iri_prefixmap(&rdf.prefixmap().unwrap_or_default())
.map_err(|e| ShapemapError::ResolvingIriRef {
prefixmap: rdf.prefixmap().unwrap_or_default().to_string(),
iri_ref: iri_ref.to_string(),
error: e.to_string(),
})?;
let iri_term = R::Term::from(iri.into_owned());
Ok(iri_term.clone())
},
ObjectValue::Literal(sliteral) => {
let lit: R::Literal = sliteral.clone().into();
Ok(lit.into())
},
}?;
Ok(vec![term])
},
NodeSelector::Sparql { query } => {
let nodes = resolve_query(rdf, query)?;
Ok(nodes)
},
NodeSelector::TriplePattern { subject, path, object } => {
let subj_str = mk_vble(subject, &rdf.prefixmap().unwrap_or_default()).map_err(|e| {
ShapemapError::PrefixMapError {
node: subject.to_string(),
error: e.to_string(),
}
})?;
let path_str = mk_path_str(path, &rdf.prefixmap().unwrap_or_default())?;
let obj_str = mk_vble(object, &rdf.prefixmap().unwrap_or_default()).map_err(|e| {
ShapemapError::PrefixMapError {
node: object.to_string(),
error: e.to_string(),
}
})?;
let query = format!("SELECT ?focus WHERE {{ {subj_str} {path_str} {obj_str} }}");
let nodes = resolve_query(rdf, &query)?;
Ok(nodes)
},
_ => todo!(),
}
}
pub fn sparql(query: &str) -> NodeSelector {
NodeSelector::Sparql {
query: query.to_string(),
}
}
}
fn mk_path_str(path: &SHACLPathRef, prefixmap: &PrefixMap) -> Result<String, ShapemapError> {
match path {
SHACLPathRef::Predicate { pred } => {
let pred_resolved = prefixmap
.resolve_iriref(pred.clone())
.map_err(|e| ShapemapError::PrefixMapError {
node: pred.to_string(),
error: e.to_string(),
})?;
Ok(format!("<{pred_resolved}>"))
},
_ => todo!(),
}
}
fn mk_vble(p: &Pattern, prefixmap: &PrefixMap) -> Result<String, PrefixMapError> {
match p {
Pattern::Node(object_value) => match object_value {
ObjectValue::IriRef(iri_ref) => {
let iri = prefixmap.resolve_iriref(iri_ref.clone())?;
Ok(format!("<{iri}>"))
},
ObjectValue::Literal(sliteral) => Ok(sliteral.to_string()),
},
Pattern::Wildcard => Ok("?any".to_string()),
Pattern::Focus => Ok("?focus".to_string()),
}
}
#[derive(Debug, Error)]
pub enum NodeSelectorError {}
impl NodeSelect for NodeSelector {
fn select<S>(&self, _rdf: S) -> Result<Vec<S::Term>, NodeSelectorError>
where
S: NeighsRDF,
{
match self {
NodeSelector::Node(_node) => {
todo!()
},
NodeSelector::TriplePattern { subject, path, object } => match (subject, path, object) {
(Pattern::Focus, _pred, Pattern::Wildcard) => todo!(),
(Pattern::Focus, _pred, Pattern::Node(_node)) => todo!(),
(Pattern::Wildcard, _pred, Pattern::Focus) => todo!(),
(Pattern::Node(_n), _pred, Pattern::Focus) => todo!(),
(_, _, _) => todo!(),
},
NodeSelector::Sparql { .. } => todo!(),
NodeSelector::Generic { .. } => todo!(),
}
}
}
#[allow(dead_code)]
trait NodeSelect {
fn select<S>(&self, rdf: S) -> Result<Vec<S::Term>, NodeSelectorError>
where
S: NeighsRDF;
}
fn resolve_query<R>(rdf: &R, query: &str) -> Result<Vec<R::Term>, ShapemapError>
where
R: QueryRDF,
{
let mut results = Vec::new();
trace!("Resolving SPARQL NodeSelector query for rdf\nQuery:\n{query}");
let query_solutions = rdf
.query_select(query)
.map_err(|e| ShapemapError::NodeSelectorQueryError {
query: query.to_string(),
error: e.to_string(),
})?;
trace!("SPARQL NodeSelector query solutions: {}", query_solutions.count());
for solution in query_solutions.iter() {
let variables = solution.variables();
trace!("SPARQL NodeSelector variables: {:?}", variables);
if let Some(variable) = variables.first()
&& let Some(value) = solution.find_solution(variable)
{
results.push(value.clone())
}
}
Ok(results)
}
impl Display for NodeSelector {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NodeSelector::Node(object_value) => {
write!(f, "{object_value}")?;
Ok(())
},
NodeSelector::TriplePattern { subject, path, object } => {
write!(
f,
"TriplePattern {{ subject: {}, path: {}, object: {} }}",
subject, path, object
)?;
Ok(())
},
NodeSelector::Sparql { query } => {
write!(f, "SPARQL \"\"\"{query}\"\"\"")?;
Ok(())
},
NodeSelector::Generic { iri: _, param: _ } => todo!(),
}
}
}
impl DerefIri for NodeSelector {
fn deref_iri(self, base: Option<&IriS>, prefixmap: Option<&PrefixMap>) -> Result<Self, prefixmap::DerefError>
where
Self: Sized,
{
match self {
NodeSelector::Node(object_value) => {
let deref = object_value.deref_iri(base, prefixmap)?;
Ok(NodeSelector::Node(deref))
},
NodeSelector::TriplePattern { subject, path, object } => {
let subject = subject.deref_iri(base, prefixmap)?;
let path = path.deref_iri(base, prefixmap)?;
let object = object.deref_iri(base, prefixmap)?;
Ok(NodeSelector::TriplePattern { subject, path, object })
},
NodeSelector::Sparql { query } => {
Ok(NodeSelector::Sparql { query })
},
NodeSelector::Generic { iri, param } => Ok(NodeSelector::Generic { iri, param }),
}
}
}