use oxrdf::{NamedNode, Quad, Term, Triple};
use crate::error::StoreError;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum RdfCapability {
Rdf12,
Rdf11,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GraphCapabilities {
pub rdf: RdfCapability,
pub union_default_graph: bool,
pub reserved_namespaces: Vec<String>,
}
impl GraphCapabilities {
pub fn plain(rdf: RdfCapability) -> Self {
GraphCapabilities {
rdf,
union_default_graph: false,
reserved_namespaces: Vec::new(),
}
}
pub fn is_reserved(&self, predicate: &str) -> bool {
self.reserved_namespaces
.iter()
.any(|ns| predicate.starts_with(ns.as_str()))
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Solutions {
pub variables: Vec<String>,
pub rows: Vec<Vec<Option<Term>>>,
}
impl Solutions {
pub fn column(&self, var: &str) -> Option<usize> {
self.variables.iter().position(|v| v == var)
}
pub fn get(&self, row: usize, var: &str) -> Option<&Term> {
let c = self.column(var)?;
self.rows.get(row)?.get(c)?.as_ref()
}
pub fn values(&self, var: &str) -> Vec<Term> {
let Some(c) = self.column(var) else {
return Vec::new();
};
self.rows
.iter()
.filter_map(|r| r.get(c).cloned().flatten())
.collect()
}
pub fn len(&self) -> usize {
self.rows.len()
}
pub fn is_empty(&self) -> bool {
self.rows.is_empty()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum QueryResults {
Solutions(Solutions),
Boolean(bool),
Graph(Vec<Triple>),
}
impl QueryResults {
pub fn into_solutions(self) -> Result<Solutions, StoreError> {
match self {
QueryResults::Solutions(s) => Ok(s),
_ => Err(StoreError::invalid("expected SELECT solutions")),
}
}
pub fn into_boolean(self) -> Result<bool, StoreError> {
match self {
QueryResults::Boolean(b) => Ok(b),
_ => Err(StoreError::invalid("expected an ASK answer")),
}
}
pub fn into_graph(self) -> Result<Vec<Triple>, StoreError> {
match self {
QueryResults::Graph(g) => Ok(g),
_ => Err(StoreError::invalid("expected a CONSTRUCT graph")),
}
}
}
pub trait GraphStore: Send + Sync {
fn capabilities(&self) -> GraphCapabilities;
fn rdf_capability(&self) -> RdfCapability {
self.capabilities().rdf
}
fn insert_quads(&self, quads: &[Quad]) -> Result<(), StoreError>;
fn remove_quads(&self, quads: &[Quad]) -> Result<(), StoreError>;
fn clear_graph(&self, graph: &NamedNode) -> Result<(), StoreError>;
fn query(&self, sparql: &str) -> Result<QueryResults, StoreError>;
}
impl<G: GraphStore + ?Sized> GraphStore for std::sync::Arc<G> {
fn capabilities(&self) -> GraphCapabilities {
(**self).capabilities()
}
fn insert_quads(&self, quads: &[Quad]) -> Result<(), StoreError> {
(**self).insert_quads(quads)
}
fn remove_quads(&self, quads: &[Quad]) -> Result<(), StoreError> {
(**self).remove_quads(quads)
}
fn clear_graph(&self, graph: &NamedNode) -> Result<(), StoreError> {
(**self).clear_graph(graph)
}
fn query(&self, sparql: &str) -> Result<QueryResults, StoreError> {
(**self).query(sparql)
}
}