use crate::store::Store;
use crate::AsyncStore;
use oxilite_core::registry::{self, SchemaGraph, SchemaRole};
use oxilite_core::shapes::ShapeIndex;
use oxilite_core::{AsyncBackend, Error, QueryOptions, QueryOutput, Result, SyncBackend};
use oxrdf::{GraphName, GraphNameRef, NamedNode, Term};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Registration {
pub iri: Option<NamedNode>,
pub version: Option<String>,
pub sha256: Option<String>,
pub imports: Vec<NamedNode>,
pub applies_to: Vec<GraphName>,
pub active: bool,
}
impl Registration {
pub fn new() -> Self {
Self {
active: true,
..Default::default()
}
}
pub fn with_iri(mut self, iri: NamedNode) -> Self {
self.iri = Some(iri);
self
}
pub fn with_version(mut self, version: impl Into<String>) -> Self {
self.version = Some(version.into());
self
}
pub fn with_sha256(mut self, sha256: impl Into<String>) -> Self {
self.sha256 = Some(sha256.into());
self
}
pub fn with_imports(mut self, imports: impl IntoIterator<Item = NamedNode>) -> Self {
self.imports = imports.into_iter().collect();
self
}
pub fn applies_to(mut self, graphs: impl IntoIterator<Item = GraphName>) -> Self {
self.applies_to = graphs.into_iter().collect();
self
}
pub fn inactive(mut self) -> Self {
self.active = false;
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RegisteredGraph {
pub graph: GraphName,
pub role: SchemaRole,
pub registration: Registration,
pub loaded_at: Option<String>,
}
impl RegisteredGraph {
pub fn to_entry(&self) -> SchemaGraph {
let mut e = entry(self.graph.as_ref(), self.role, &self.registration);
e.loaded_at = self.loaded_at.clone();
e
}
pub fn applies(&self, target: GraphNameRef<'_>) -> bool {
let a = &self.registration.applies_to;
a.is_empty() || a.iter().any(|g| g.as_ref() == target)
}
}
fn entry(graph: GraphNameRef<'_>, role: SchemaRole, r: &Registration) -> SchemaGraph {
SchemaGraph {
graph: graph.into_owned(),
role,
iri: r.iri.clone(),
version: r.version.clone(),
sha256: r.sha256.clone(),
imports: r.imports.clone(),
applies_to: r.applies_to.clone(),
active: r.active,
loaded_at: None,
}
}
fn from_entry(e: SchemaGraph) -> RegisteredGraph {
RegisteredGraph {
graph: e.graph,
role: e.role,
registration: Registration {
iri: e.iri,
version: e.version,
sha256: e.sha256,
imports: e.imports,
applies_to: e.applies_to,
active: e.active,
},
loaded_at: e.loaded_at,
}
}
fn entries(out: QueryOutput) -> Vec<RegisteredGraph> {
match out {
QueryOutput::Solutions { rows, .. } => registry::entries_from_rows(&rows)
.into_iter()
.map(from_entry)
.collect(),
_ => Vec::new(),
}
}
fn problems(out: QueryOutput) -> Vec<String> {
match out {
QueryOutput::Solutions { rows, .. } => registry::problems(&rows),
_ => Vec::new(),
}
}
fn boolean(out: QueryOutput) -> bool {
matches!(out, QueryOutput::Boolean(true))
}
fn count(out: QueryOutput) -> u64 {
match out {
QueryOutput::Solutions { rows, .. } => rows
.first()
.and_then(|r| r.first().cloned().flatten())
.and_then(|t| match t {
Term::Literal(l) => l.value().parse().ok(),
_ => None,
})
.unwrap_or(0),
_ => 0,
}
}
fn applying(
all: Vec<RegisteredGraph>,
target: GraphNameRef<'_>,
role: SchemaRole,
) -> Vec<GraphName> {
all.into_iter()
.filter(|e| e.role == role && e.registration.active && e.applies(target))
.map(|e| e.graph)
.collect()
}
fn parse_error(e: impl std::fmt::Display) -> Error {
Error::Other(e.to_string())
}
impl<B: SyncBackend + Send + Sync + 'static> Store<B> {
fn registry_query(&self, sparql: &str) -> Result<QueryOutput> {
let q = spargebra::SparqlParser::new()
.parse_query(sparql)
.map_err(parse_error)?;
self.query_output(q, &QueryOptions::default())
}
fn registry_update(&self, sparql: &str) -> Result<()> {
let u = spargebra::SparqlParser::new()
.parse_update(sparql)
.map_err(parse_error)?;
self.update(u)
}
pub fn register_schema_graph<'a>(
&self,
graph: impl Into<GraphNameRef<'a>>,
role: SchemaRole,
registration: &Registration,
) -> Result<()> {
let e = entry(graph.into(), role, registration);
self.registry_update(®istry::register_update(&e)?)
}
pub fn schema_graphs(&self) -> Result<Vec<RegisteredGraph>> {
Ok(entries(self.registry_query(®istry::entries_query())?))
}
pub fn schema_graphs_for<'a>(
&self,
target: impl Into<GraphNameRef<'a>>,
role: SchemaRole,
) -> Result<Vec<GraphName>> {
Ok(applying(self.schema_graphs()?, target.into(), role))
}
fn is_registered(&self, graph: GraphNameRef<'_>) -> Result<bool> {
Ok(boolean(
self.registry_query(®istry::registered_query(graph)?)?,
))
}
pub fn set_schema_graph_targets<'a>(
&self,
graph: impl Into<GraphNameRef<'a>>,
applies_to: &[GraphName],
) -> Result<bool> {
let graph = graph.into();
if !self.is_registered(graph)? {
return Ok(false);
}
self.registry_update(®istry::remap_update(graph, applies_to)?)?;
Ok(true)
}
pub fn registry_problems(&self) -> Result<Vec<String>> {
Ok(problems(self.registry_query(®istry::entries_query())?))
}
pub fn set_schema_graph_active<'a>(
&self,
graph: impl Into<GraphNameRef<'a>>,
active: bool,
) -> Result<bool> {
let graph = graph.into();
if !self.is_registered(graph)? {
return Ok(false);
}
self.registry_update(®istry::set_active_update(graph, active)?)?;
Ok(true)
}
pub fn unregister_schema_graph<'a>(&self, graph: impl Into<GraphNameRef<'a>>) -> Result<bool> {
let graph = graph.into();
if !self.is_registered(graph)? {
return Ok(false);
}
self.registry_update(®istry::unregister_update(graph)?)?;
Ok(true)
}
pub fn drop_schema_graph<'a>(&self, graph: impl Into<GraphNameRef<'a>>) -> Result<u64> {
let graph = graph.into();
let n = count(self.registry_query(®istry::size_query(graph))?);
self.registry_update(®istry::drop_update(graph)?)?;
Ok(n)
}
pub fn system_graphs_installed(&self) -> Result<bool> {
Ok(boolean(
self.registry_query(®istry::system_graphs_ready_query())?,
))
}
pub fn install_system_graphs(&self) -> Result<bool> {
if self.system_graphs_installed()? {
return Ok(false);
}
self.registry_update(®istry::system_graphs_update())?;
Ok(true)
}
pub fn shape_index(&self) -> Result<ShapeIndex> {
self.run(oxilite_core::ops::shape_index_job(self.caps()))
}
}
impl<B: AsyncBackend> AsyncStore<B> {
async fn registry_query(&self, sparql: &str) -> Result<QueryOutput> {
let q = spargebra::SparqlParser::new()
.parse_query(sparql)
.map_err(parse_error)?;
self.query_output(q, &QueryOptions::default()).await
}
async fn registry_update(&self, sparql: &str) -> Result<()> {
let u = spargebra::SparqlParser::new()
.parse_update(sparql)
.map_err(parse_error)?;
self.update(u).await
}
pub async fn register_schema_graph<'a>(
&self,
graph: impl Into<GraphNameRef<'a>>,
role: SchemaRole,
registration: &Registration,
) -> Result<()> {
let e = entry(graph.into(), role, registration);
self.registry_update(®istry::register_update(&e)?).await
}
pub async fn schema_graphs(&self) -> Result<Vec<RegisteredGraph>> {
Ok(entries(
self.registry_query(®istry::entries_query()).await?,
))
}
pub async fn schema_graphs_for<'a>(
&self,
target: impl Into<GraphNameRef<'a>>,
role: SchemaRole,
) -> Result<Vec<GraphName>> {
let target = target.into().into_owned();
Ok(applying(self.schema_graphs().await?, target.as_ref(), role))
}
async fn is_registered(&self, graph: GraphNameRef<'_>) -> Result<bool> {
Ok(boolean(
self.registry_query(®istry::registered_query(graph)?)
.await?,
))
}
pub async fn set_schema_graph_targets<'a>(
&self,
graph: impl Into<GraphNameRef<'a>>,
applies_to: &[GraphName],
) -> Result<bool> {
let graph = graph.into().into_owned();
if !self.is_registered(graph.as_ref()).await? {
return Ok(false);
}
self.registry_update(®istry::remap_update(graph.as_ref(), applies_to)?)
.await?;
Ok(true)
}
pub async fn registry_problems(&self) -> Result<Vec<String>> {
Ok(problems(
self.registry_query(®istry::entries_query()).await?,
))
}
pub async fn set_schema_graph_active<'a>(
&self,
graph: impl Into<GraphNameRef<'a>>,
active: bool,
) -> Result<bool> {
let graph = graph.into().into_owned();
if !self.is_registered(graph.as_ref()).await? {
return Ok(false);
}
self.registry_update(®istry::set_active_update(graph.as_ref(), active)?)
.await?;
Ok(true)
}
pub async fn unregister_schema_graph<'a>(
&self,
graph: impl Into<GraphNameRef<'a>>,
) -> Result<bool> {
let graph = graph.into().into_owned();
if !self.is_registered(graph.as_ref()).await? {
return Ok(false);
}
self.registry_update(®istry::unregister_update(graph.as_ref())?)
.await?;
Ok(true)
}
pub async fn drop_schema_graph<'a>(&self, graph: impl Into<GraphNameRef<'a>>) -> Result<u64> {
let graph = graph.into().into_owned();
let n = count(
self.registry_query(®istry::size_query(graph.as_ref()))
.await?,
);
self.registry_update(®istry::drop_update(graph.as_ref())?)
.await?;
Ok(n)
}
pub async fn system_graphs_installed(&self) -> Result<bool> {
Ok(boolean(
self.registry_query(®istry::system_graphs_ready_query())
.await?,
))
}
pub async fn install_system_graphs(&self) -> Result<bool> {
if self.system_graphs_installed().await? {
return Ok(false);
}
self.registry_update(®istry::system_graphs_update())
.await?;
Ok(true)
}
pub async fn shape_index(&self) -> Result<ShapeIndex> {
oxilite_core::job::run_async(
&self.backend,
oxilite_core::ops::shape_index_job(self.caps()),
)
.await
}
}