use purrdf_rdf::native_codecs::jsonld::StatementMetadataVocab;
use purrdf_shapes::json_schema::Namespaces;
use purrdf_slice::SliceVocab;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReifierVocab {
pub statement_metadata: String,
pub q_subject: String,
pub q_predicate: String,
pub q_object: String,
pub q_object_literal: String,
}
impl ReifierVocab {
#[must_use]
pub fn for_namespace(ns: &str) -> Self {
Self {
statement_metadata: format!("{ns}StatementMetadata"),
q_subject: format!("{ns}qSubject"),
q_predicate: format!("{ns}qPredicate"),
q_object: format!("{ns}qObject"),
q_object_literal: format!("{ns}qObjectLiteral"),
}
}
#[must_use]
pub fn as_statement_metadata_vocab(&self) -> StatementMetadataVocab<'_> {
StatementMetadataVocab {
statement_metadata: &self.statement_metadata,
q_subject: &self.q_subject,
q_predicate: &self.q_predicate,
q_object: &self.q_object,
q_object_literal: &self.q_object_literal,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OntologyProfile {
pub namespace: String,
pub prefix: String,
pub prefixes: Vec<(String, String)>,
pub reifier: ReifierVocab,
}
impl OntologyProfile {
#[must_use]
pub fn for_namespace(namespace: &str) -> Self {
let prefix = SliceVocab::for_namespace(namespace)
.prefix_name()
.to_owned();
Self {
namespace: namespace.to_owned(),
prefix,
prefixes: Vec::new(),
reifier: ReifierVocab::for_namespace(namespace),
}
}
#[must_use]
pub fn with_prefix(mut self, prefix: &str) -> Self {
prefix.clone_into(&mut self.prefix);
self
}
#[must_use]
pub fn with_prefixes(mut self, prefixes: Vec<(String, String)>) -> Self {
self.prefixes = prefixes;
self
}
#[must_use]
pub fn with_reifier(mut self, reifier: ReifierVocab) -> Self {
self.reifier = reifier;
self
}
#[must_use]
pub fn slice_vocab(&self) -> SliceVocab {
SliceVocab::for_namespace(&self.namespace).with_prefix_name(&self.prefix)
}
pub fn namespaces(&self) -> Result<Namespaces, String> {
let mut declarations = Vec::with_capacity(self.prefixes.len() + 1);
declarations.push((self.prefix.clone(), self.namespace.clone()));
declarations.extend(self.prefixes.iter().cloned());
Namespaces::new(&self.prefix, &declarations)
}
#[must_use]
pub fn statement_metadata_vocab(&self) -> StatementMetadataVocab<'_> {
self.reifier.as_statement_metadata_vocab()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn derives_prefix_and_reifier_from_namespace() {
let p = OntologyProfile::for_namespace("https://example.org/vocab/");
assert_eq!(p.namespace, "https://example.org/vocab/");
assert_eq!(p.prefix, "vocab");
assert_eq!(
p.reifier.statement_metadata,
"https://example.org/vocab/StatementMetadata"
);
assert_eq!(
p.reifier.q_object_literal,
"https://example.org/vocab/qObjectLiteral"
);
}
#[test]
fn projects_into_every_native_config() {
let p = OntologyProfile::for_namespace("https://example.org/vocab/").with_prefix("ex");
let sv = p.slice_vocab();
assert_eq!(sv.slice_class(), "https://example.org/vocab/Slice");
assert_eq!(sv.prefix_name(), "ex");
let ns = p.namespaces().expect("primary prefix resolves");
assert_eq!(ns.compact_iri("https://example.org/vocab/Cat"), "ex:Cat");
let smv = p.statement_metadata_vocab();
assert_eq!(smv.q_predicate, "https://example.org/vocab/qPredicate");
}
#[test]
fn extra_prefixes_are_carried_into_the_namespace_table() {
let p = OntologyProfile::for_namespace("https://example.org/vocab/").with_prefixes(vec![(
"friend".to_owned(),
"https://example.org/friend/".to_owned(),
)]);
let ns = p.namespaces().expect("primary prefix resolves");
assert_eq!(
ns.compact_iri("https://example.org/friend/Dog"),
"friend:Dog"
);
}
}