.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
use oxigraph::model::{NamedNode, Quad, Term};
|
||||
use oxigraph::model::vocab::{rdf, xsd};
|
||||
|
||||
fn quad_to_term(quad: &Quad) -> &Term {
|
||||
&quad.object
|
||||
}
|
||||
|
||||
fn term_to_named_node(term: &Term) -> Option<&NamedNode> {
|
||||
if let Term::NamedNode(node) = term {
|
||||
Some(node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn term_to_string(term: &Term) -> Option<&str> {
|
||||
if let Term::Literal(literal) = term {
|
||||
match literal.datatype() {
|
||||
xsd::STRING | xsd::NORMALIZED_STRING | rdf::LANG_STRING | rdf::DIR_LANG_STRING => {
|
||||
Some(literal.value())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn term_to_boolean(term: &Term) -> Option<bool> {
|
||||
if let Term::Literal(literal) = term {
|
||||
if literal.datatype() == xsd::BOOLEAN {
|
||||
literal.value().parse().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn term_to_u64(term: &Term) -> Option<u64> {
|
||||
if let Term::Literal(literal) = term &&
|
||||
literal.datatype() == xsd::NON_NEGATIVE_INTEGER {
|
||||
let value: u64 = literal.value().parse().expect("Failed to parse u64 from ontology. It ought to be a non-negative integer.");
|
||||
Some(value)
|
||||
} else { None }
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
use oxigraph::model::{Dataset, GraphName, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term};
|
||||
use oxigraph::sparql::{QueryResults, SparqlEvaluator};
|
||||
use oxigraph::store::Store;
|
||||
use crate::error;
|
||||
use crate::rdf::vocab::owl;
|
||||
|
||||
pub fn same_as(store: Store) -> error::Result<Store> {
|
||||
let additional_quads = store
|
||||
.quads_for_pattern(None, Some(owl::SAME_AS), None, None)
|
||||
.filter_map(Result::ok)
|
||||
.fold(Dataset::new(), |mut new_dataset, alias| {
|
||||
if let NamedOrBlankNode::NamedNode(x) = alias.subject
|
||||
&& let Term::NamedNode(y) = alias.object
|
||||
{
|
||||
for mut quad in store.quads_for_pattern(
|
||||
Some(NamedOrBlankNodeRef::NamedNode(x.as_ref())),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
).filter_map(Result::ok) {
|
||||
quad.subject = NamedOrBlankNode::NamedNode(y.clone());
|
||||
new_dataset.insert(quad.as_ref());
|
||||
}
|
||||
|
||||
for mut quad in store.quads_for_pattern(
|
||||
Some(NamedOrBlankNodeRef::NamedNode(y.as_ref())),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
).filter_map(Result::ok) {
|
||||
quad.subject = NamedOrBlankNode::NamedNode(x.clone());
|
||||
new_dataset.insert(quad.as_ref());
|
||||
}
|
||||
}
|
||||
new_dataset
|
||||
});
|
||||
|
||||
let old_size = store.len()?;
|
||||
store.extend(&additional_quads)?;
|
||||
let new_size = store.len()?;
|
||||
|
||||
if new_size > old_size {
|
||||
same_as(store)
|
||||
} else {
|
||||
Ok(store)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn super_classes(dataset: &mut Dataset) {
|
||||
let query = SparqlEvaluator::new()
|
||||
.parse_query(
|
||||
r#"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
|
||||
CONSTRUCT {
|
||||
?item a ?parent
|
||||
} WHERE {
|
||||
?item a ?class .
|
||||
?class rdfs:subClassOf ?parent .
|
||||
}"#,
|
||||
)
|
||||
.expect("Unable to parse superclass query");
|
||||
|
||||
let mut additional_quads = Dataset::new();
|
||||
if let QueryResults::Graph(graph) = query.on_queryable_dataset(&*dataset).execute().unwrap()
|
||||
{
|
||||
additional_quads.extend(graph.filter_map(Result::ok).map(|triple| {
|
||||
Quad::new(
|
||||
triple.subject,
|
||||
triple.predicate,
|
||||
triple.object,
|
||||
GraphName::DefaultGraph,
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
let old_size = dataset.len();
|
||||
dataset.extend(&additional_quads);
|
||||
let new_size = dataset.len();
|
||||
|
||||
if new_size > old_size {
|
||||
super_classes(dataset)
|
||||
}
|
||||
}
|
||||
|
||||
/*fn iri_information(dataset: &Dataset) -> HashMap<NamedNode, IriInformation> {
|
||||
let query = SparqlEvaluator::new()
|
||||
.parse_query(
|
||||
r#"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
PREFIX gl: <https://graphofliberty.org/2026/04/ont/>
|
||||
|
||||
SELECT DISTINCT ?class ?subject ?label ?comment ?read_only {
|
||||
VALUES ?class { rdf:Property rdfs:Class }
|
||||
?subject a ?class .
|
||||
OPTIONAL {
|
||||
?subject rdfs:label ?label
|
||||
FILTER (langMATCHES(LANG(?label), "en") || !hasLANG(?label))
|
||||
}
|
||||
OPTIONAL {
|
||||
?subject rdfs:comment ?comment
|
||||
FILTER (langMATCHES(LANG(?label), "en") || !hasLANG(?comment))
|
||||
}
|
||||
OPTIONAL { ?subject gl:readOnly ?read_only }
|
||||
}"#,
|
||||
)
|
||||
.expect("Unable to parse property query");
|
||||
|
||||
let mut results = HashMap::new();
|
||||
if let QueryResults::Solutions(solutions) =
|
||||
query.on_queryable_dataset(dataset).execute().unwrap()
|
||||
{
|
||||
for solution in solutions.filter_map(Result::ok) {
|
||||
let type_ = solution.get("class").and_then(crate::rdf::ontology::term_to_named_node);
|
||||
let subject = solution.get("subject").and_then(crate::rdf::ontology::term_to_named_node);
|
||||
let label = solution.get("label").and_then(crate::rdf::ontology::term_to_string);
|
||||
let comment = solution.get("comment").and_then(crate::rdf::ontology::term_to_string);
|
||||
let read_only = solution
|
||||
.get("read_only")
|
||||
.and_then(crate::rdf::ontology::term_to_boolean)
|
||||
.unwrap_or(false);
|
||||
|
||||
if let Some(subject) = subject && let Some(type_) = type_ {
|
||||
let info = IriInformation {
|
||||
type_: type_.clone(),
|
||||
label: label.map(String::from),
|
||||
comment: comment.map(String::from),
|
||||
read_only,
|
||||
};
|
||||
results.insert(subject.to_owned(), info);
|
||||
}
|
||||
}
|
||||
}
|
||||
results
|
||||
}*/
|
||||
@@ -1,3 +1,5 @@
|
||||
pub(crate) mod ontology;
|
||||
pub(crate) mod term_helper;
|
||||
pub mod vocab;
|
||||
pub(crate) mod materialize;
|
||||
pub(crate) mod conversion;
|
||||
|
||||
@@ -83,20 +83,8 @@ xsd:unsignedShort rdf:type rdfs:Datatype ;
|
||||
# Object Properties
|
||||
#################################################################
|
||||
|
||||
### http://rdaregistry.info/Elements/a/P50094
|
||||
rdaa:P50094 rdf:type owl:ObjectProperty .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/identifierForPerson.en
|
||||
rdaa:identifierForPerson.en rdf:type owl:ObjectProperty .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/m/P30154
|
||||
rdam:P30154 rdf:type owl:ObjectProperty .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/m/uniformResourceLocator.en
|
||||
rdam:uniformResourceLocator.en rdf:type owl:ObjectProperty .
|
||||
### http://fedora.info/definitions/v4/repository#hasParent
|
||||
fedora:hasParent rdf:type owl:ObjectProperty .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/associatedProperty
|
||||
@@ -106,8 +94,7 @@ rdam:uniformResourceLocator.en rdf:type owl:ObjectProperty .
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/indexedByField
|
||||
:indexedByField rdf:type owl:ObjectProperty ;
|
||||
rdfs:domain owl:DatatypeProperty ;
|
||||
rdfs:range :IndexField ;
|
||||
rdfs:range :IndexDocumentField ;
|
||||
rdfs:comment "The property is associated with the given field in a full-text search database."@en ;
|
||||
rdfs:label "indexed by field"@en .
|
||||
|
||||
@@ -140,22 +127,6 @@ fedora:lastModified rdf:type owl:DatatypeProperty .
|
||||
fedora:lastModifiedBy rdf:type owl:DatatypeProperty .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/P50291
|
||||
rdaa:P50291 rdf:type owl:DatatypeProperty .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/P50292
|
||||
rdaa:P50292 rdf:type owl:DatatypeProperty .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/givenName.en
|
||||
rdaa:givenName.en rdf:type owl:DatatypeProperty .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/surname.en
|
||||
rdaa:surname.en rdf:type owl:DatatypeProperty .
|
||||
|
||||
|
||||
### http://www.w3.org/ns/ldp#contains
|
||||
ldp:contains rdf:type owl:DatatypeProperty ;
|
||||
rdfs:subPropertyOf owl:topDataProperty .
|
||||
@@ -163,19 +134,20 @@ ldp:contains rdf:type owl:DatatypeProperty ;
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/catalogId
|
||||
:catalogId rdf:type owl:DatatypeProperty ;
|
||||
rdfs:domain owl:Class ;
|
||||
rdfs:comment "An integer associated with the class for fast lookup in a database."@en ;
|
||||
rdfs:label "catalog id" .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/fieldLabel
|
||||
:fieldLabel rdf:type owl:DatatypeProperty ;
|
||||
rdfs:domain :IndexDocumentField ;
|
||||
rdfs:comment "The label of a field, which shall be displayed to the user."@en ;
|
||||
rdfs:label "field label"@en .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/fieldName
|
||||
:fieldName rdf:type owl:DatatypeProperty ;
|
||||
rdfs:domain :IndexDocumentField ;
|
||||
rdfs:comment "The name of the field, as defined in the full-text search document schema."@en ;
|
||||
rdfs:label "field name"@en .
|
||||
|
||||
@@ -190,122 +162,15 @@ ldp:contains rdf:type owl:DatatypeProperty ;
|
||||
# Classes
|
||||
#################################################################
|
||||
|
||||
### http://fedora.info/definitions/v4/repository#Container
|
||||
fedora:Container rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://fedora.info/definitions/v4/repository#Resource
|
||||
fedora:Resource rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/c/C10001
|
||||
rdac:C10001 rdf:type owl:Class ;
|
||||
rdfs:subClassOf rdac:C10013 ;
|
||||
rdfs:label "Work"@en .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/c/C10002
|
||||
rdac:C10002 rdf:type owl:Class ;
|
||||
rdfs:subClassOf rdac:C10013 ;
|
||||
rdfs:label "Agent"@en .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/c/C10004
|
||||
rdac:C10004 rdf:type owl:Class ;
|
||||
rdfs:subClassOf rdac:C10002 .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/c/C10007
|
||||
rdac:C10007 rdf:type owl:Class ;
|
||||
rdfs:subClassOf rdac:C10013 .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/c/C10013
|
||||
rdac:C10013 rdf:type owl:Class ;
|
||||
rdfs:label "RDA Entity"@en .
|
||||
|
||||
|
||||
### http://www.w3.org/1999/02/22-rdf-syntax-ns#Property
|
||||
rdf:Property rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://www.w3.org/2000/01/rdf-schema#Class
|
||||
rdfs:Class rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://www.w3.org/2002/07/owl#Class
|
||||
owl:Class rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://www.w3.org/2002/07/owl#DatatypeProperty
|
||||
owl:DatatypeProperty rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://www.w3.org/ns/ldp#BasicContainer
|
||||
ldp:BasicContainer rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://www.w3.org/ns/ldp#Container
|
||||
ldp:Container rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://www.w3.org/ns/ldp#RDFSource
|
||||
ldp:RDFSource rdf:type owl:Class .
|
||||
|
||||
|
||||
### http://www.w3.org/ns/ldp#Resource
|
||||
ldp:Resource rdf:type owl:Class .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/AudioBook
|
||||
:AudioBook rdf:type owl:Class ;
|
||||
rdfs:subClassOf :Entity .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Book
|
||||
:Book rdf:type owl:Class ;
|
||||
rdfs:subClassOf :Entity .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Document
|
||||
:Document rdf:type owl:Class ;
|
||||
rdfs:subClassOf :Entity .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Entity
|
||||
:Entity rdf:type owl:Class ;
|
||||
rdfs:label "Graph of Liberty Entity"@en .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/IndexField
|
||||
:IndexField rdf:type owl:Class ;
|
||||
rdfs:comment "Describes a single field present within a larger document that is passed to a full-text search database."@en ;
|
||||
rdfs:label "Index Field"@en .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Meme
|
||||
:Meme rdf:type owl:Class ;
|
||||
rdfs:subClassOf :Entity .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Movie
|
||||
:Movie rdf:type owl:Class ;
|
||||
rdfs:subClassOf :Entity .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Music
|
||||
:Music rdf:type owl:Class ;
|
||||
rdfs:subClassOf :Entity .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Podcast
|
||||
:Podcast rdf:type owl:Class ;
|
||||
rdfs:subClassOf :Entity .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/TVShow
|
||||
:TVShow rdf:type owl:Class ;
|
||||
rdfs:subClassOf :Entity .
|
||||
### https://graphofliberty.org/2026/04/ont/IndexDocumentField
|
||||
:IndexDocumentField rdf:type owl:Class ;
|
||||
rdfs:comment "Describes a single field present within a document that is indexed in a full-text search database."@en ;
|
||||
rdfs:label "Index Document Field"@en .
|
||||
|
||||
|
||||
#################################################################
|
||||
@@ -332,6 +197,11 @@ fedora:createdBy rdf:type owl:NamedIndividual ;
|
||||
:readOnly "true"^^xsd:boolean .
|
||||
|
||||
|
||||
### http://fedora.info/definitions/v4/repository#hasParent
|
||||
fedora:hasParent rdf:type owl:NamedIndividual ;
|
||||
:readOnly "true"^^xsd:boolean .
|
||||
|
||||
|
||||
### http://fedora.info/definitions/v4/repository#lastModified
|
||||
fedora:lastModified rdf:type owl:NamedIndividual ;
|
||||
:readOnly "true"^^xsd:boolean .
|
||||
@@ -342,89 +212,16 @@ fedora:lastModifiedBy rdf:type owl:NamedIndividual ;
|
||||
:readOnly "true"^^xsd:boolean .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/P50094
|
||||
rdaa:P50094 rdf:type owl:NamedIndividual ;
|
||||
owl:sameAs rdaa:identifierForPerson.en .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/identifierForPerson.en
|
||||
|
||||
### http://rdaregistry.info/Elements/a/P50291
|
||||
rdaa:P50291 rdf:type owl:NamedIndividual ;
|
||||
owl:sameAs rdaa:surname.en ;
|
||||
:indexedByField :surname .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/surname.en
|
||||
|
||||
### http://rdaregistry.info/Elements/a/P50292
|
||||
rdaa:P50292 rdf:type owl:NamedIndividual ;
|
||||
owl:sameAs rdaa:givenName.en ;
|
||||
:indexedByField :givenName .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/givenName.en
|
||||
|
||||
### http://rdaregistry.info/Elements/a/givenName.en
|
||||
rdaa:givenName.en rdf:type owl:NamedIndividual .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/identifierForPerson.en
|
||||
rdaa:identifierForPerson.en rdf:type owl:NamedIndividual .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/a/surname.en
|
||||
rdaa:surname.en rdf:type owl:NamedIndividual .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/c/C10004
|
||||
rdac:C10004 rdf:type owl:NamedIndividual ;
|
||||
:associatedProperty rdaa:P50291 ,
|
||||
rdaa:P50292 ;
|
||||
:catalogId "8"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/c/C10007
|
||||
rdac:C10007 rdf:type owl:NamedIndividual ;
|
||||
:template [ rdf:type rdac:C10007
|
||||
] .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/m/P30154
|
||||
rdam:P30154 rdf:type owl:NamedIndividual ;
|
||||
owl:sameAs rdam:uniformResourceLocator.en .
|
||||
|
||||
|
||||
### http://rdaregistry.info/Elements/m/uniformResourceLocator.en
|
||||
|
||||
### http://rdaregistry.info/Elements/m/uniformResourceLocator.en
|
||||
rdam:uniformResourceLocator.en rdf:type owl:NamedIndividual .
|
||||
|
||||
|
||||
### http://www.w3.org/1999/02/22-rdf-syntax-ns#Property
|
||||
rdf:Property rdf:type owl:NamedIndividual ;
|
||||
:associatedProperty rdfs:comment ,
|
||||
rdfs:label ;
|
||||
:catalogId "0"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### http://www.w3.org/2000/01/rdf-schema#Class
|
||||
rdfs:Class rdf:type owl:NamedIndividual ;
|
||||
:associatedProperty rdfs:comment ,
|
||||
rdfs:label ;
|
||||
:catalogId "1"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### http://www.w3.org/2000/01/rdf-schema#comment
|
||||
rdfs:comment rdf:type owl:NamedIndividual ;
|
||||
:indexedByField :comment .
|
||||
|
||||
|
||||
### http://www.w3.org/2000/01/rdf-schema#label
|
||||
rdfs:label rdf:type owl:NamedIndividual ;
|
||||
:indexedByField :label .
|
||||
|
||||
|
||||
### http://www.w3.org/ns/ldp#BasicContainer
|
||||
ldp:BasicContainer rdf:type owl:NamedIndividual ;
|
||||
:readOnly "true"^^xsd:boolean .
|
||||
@@ -450,134 +247,20 @@ ldp:contains rdf:type owl:NamedIndividual ;
|
||||
:readOnly "true"^^xsd:boolean .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/AudioBook
|
||||
:AudioBook rdf:type owl:NamedIndividual ;
|
||||
:catalogId "2"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Book
|
||||
:Book rdf:type owl:NamedIndividual ;
|
||||
:catalogId "3"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Document
|
||||
:Document rdf:type owl:NamedIndividual ;
|
||||
:catalogId "4"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Meme
|
||||
:Meme rdf:type owl:NamedIndividual ;
|
||||
:catalogId "5"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Movie
|
||||
:Movie rdf:type owl:NamedIndividual ;
|
||||
:catalogId "6"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Music
|
||||
:Music rdf:type owl:NamedIndividual ;
|
||||
:catalogId "7"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/Podcast
|
||||
:Podcast rdf:type owl:NamedIndividual ;
|
||||
:catalogId "9"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/TVShow
|
||||
:TVShow rdf:type owl:NamedIndividual ;
|
||||
:catalogId "10"^^xsd:nonNegativeInteger .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/comment
|
||||
:comment rdf:type owl:NamedIndividual ,
|
||||
:IndexField ;
|
||||
:IndexDocumentField ;
|
||||
:fieldLabel "Comment"@en ;
|
||||
:fieldName "comment" ;
|
||||
rdfs:label "Comment Field"@en .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/givenName
|
||||
:givenName rdf:type owl:NamedIndividual ,
|
||||
:IndexField ;
|
||||
:fieldLabel "Given Name"@en ;
|
||||
:fieldName "givenName" ;
|
||||
rdfs:label "Given Name Field"@en .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/label
|
||||
:label rdf:type owl:NamedIndividual ,
|
||||
:IndexField ;
|
||||
:IndexDocumentField ;
|
||||
:fieldLabel "Label"@en ;
|
||||
:fieldName "label" ;
|
||||
rdfs:label "Label Field"@en .
|
||||
|
||||
|
||||
### https://graphofliberty.org/2026/04/ont/surname
|
||||
:surname rdf:type owl:NamedIndividual ,
|
||||
:IndexField ;
|
||||
:fieldLabel "Surname"@en ;
|
||||
:fieldName "surname" ;
|
||||
rdfs:label "Surname Field"@en .
|
||||
|
||||
|
||||
#################################################################
|
||||
# Annotations
|
||||
#################################################################
|
||||
|
||||
rdaa:P50094 rdfs:label "has identifier for person"@en .
|
||||
|
||||
|
||||
rdaa:P50291 rdfs:label "has surname"@en .
|
||||
|
||||
|
||||
rdaa:P50292 rdfs:label "has given name"@en .
|
||||
|
||||
|
||||
rdac:C10004 rdfs:label "Person"@en .
|
||||
|
||||
|
||||
rdac:C10007 rdfs:label "Manifestation"@en .
|
||||
|
||||
|
||||
rdam:P30154 rdfs:label "has uniform resource locator"@en .
|
||||
|
||||
|
||||
rdf:Property rdfs:label "Property"@en .
|
||||
|
||||
|
||||
rdfs:Class rdfs:label "Class"@en .
|
||||
|
||||
|
||||
rdfs:comment rdfs:label "Comment Property"@en .
|
||||
|
||||
|
||||
rdfs:label rdfs:label "Label Property"@en .
|
||||
|
||||
|
||||
:AudioBook rdfs:label "Audio Book"@en .
|
||||
|
||||
|
||||
:Book rdfs:label "Book"@en .
|
||||
|
||||
|
||||
:Document rdfs:label "Document"@en .
|
||||
|
||||
|
||||
:Meme rdfs:label "Meme"@en .
|
||||
|
||||
|
||||
:Movie rdfs:label "Movie"@en .
|
||||
|
||||
|
||||
:Music rdfs:label "Music"@en .
|
||||
|
||||
|
||||
:Podcast rdfs:label "Podcast"@en .
|
||||
|
||||
|
||||
:TVShow rdfs:label "TV Show"@en .
|
||||
|
||||
|
||||
### Generated by the OWL API (version 4.5.29.2024-05-13T12:11:03Z) https://github.com/owlcs/owlapi
|
||||
|
||||
+113
-301
@@ -2,15 +2,13 @@ use crate::error;
|
||||
use crate::rdf::vocab::{gl, owl, rda};
|
||||
use oxigraph::io::{RdfFormat, RdfParser};
|
||||
use oxigraph::model::vocab::{rdf, rdfs, xsd};
|
||||
use oxigraph::model::{
|
||||
Dataset, GraphName, NamedNode, NamedNodeRef, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term,
|
||||
TermRef, Triple, TripleRef,
|
||||
};
|
||||
use oxigraph::model::{Dataset, GraphName, LiteralRef, NamedNode, NamedNodeRef, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term, TermRef, Triple, TripleRef};
|
||||
use oxigraph::sparql::{QueryResults, SparqlEvaluator};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Display;
|
||||
use iced::widget::sensor::Key;
|
||||
use tracing::{debug, info};
|
||||
use std::path::{Path, PathBuf};
|
||||
use oxigraph::store::Store;
|
||||
use crate::rdf::materialize;
|
||||
|
||||
const PREFIXES: &[(&str, &str)] = &[
|
||||
("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"),
|
||||
@@ -29,6 +27,7 @@ const PREFIXES: &[(&str, &str)] = &[
|
||||
("dcterms", "http://purl.org/dc/terms/"),
|
||||
("fedora", "http://fedora.info/definitions/v4/repository#"),
|
||||
("rdaa", "http://rdaregistry.info/Elements/a/"),
|
||||
("rdaad", "http://rdaregistry.info/Elements/a/datatype/"),
|
||||
("rdac", "http://rdaregistry.info/Elements/c/"),
|
||||
("rdae", "http://rdaregistry.info/Elements/e/"),
|
||||
("rdai", "http://rdaregistry.info/Elements/i/"),
|
||||
@@ -43,159 +42,93 @@ const PREFIXES: &[(&str, &str)] = &[
|
||||
("gl", "https://graphofliberty.org/2026/04/ont/"),
|
||||
];
|
||||
|
||||
const RDF_ONT: &[u8] = include_bytes!("ontologies/22-rdf-syntax-ns.ttl");
|
||||
const RDFS_ONT: &[u8] = include_bytes!("ontologies/rdf-schema.ttl");
|
||||
const OWL_ONT: &[u8] = include_bytes!("ontologies/owl.ttl");
|
||||
const LDP_ONT: &[u8] = include_bytes!("ontologies/ldp.ttl");
|
||||
const FEDORA_ONT: &[u8] = include_bytes!("ontologies/fedora.xml");
|
||||
const GL_ONT: &[u8] = include_bytes!("ontologies/ontology.ttl");
|
||||
|
||||
pub struct OntologyBuilder<'a> {
|
||||
ontologies: Vec<(RdfFormat, &'a [u8])>,
|
||||
pub struct OntologyBuilder {
|
||||
path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl<'a> OntologyBuilder<'a> {
|
||||
pub fn with_ontology_bytes(mut self, format: RdfFormat, bytes: &'a [u8]) -> Self {
|
||||
self.ontologies.push((format, bytes));
|
||||
impl OntologyBuilder {
|
||||
pub fn with_path(mut self, path: impl AsRef<Path>) -> Self {
|
||||
let path = path.as_ref().to_owned();
|
||||
self.path = Some(path);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_default_ontologies(self) -> Self {
|
||||
self.with_ontology_bytes(RdfFormat::Turtle, RDF_ONT)
|
||||
.with_ontology_bytes(RdfFormat::Turtle, RDFS_ONT)
|
||||
.with_ontology_bytes(RdfFormat::Turtle, OWL_ONT)
|
||||
.with_ontology_bytes(RdfFormat::Turtle, LDP_ONT)
|
||||
.with_ontology_bytes(RdfFormat::RdfXml, FEDORA_ONT)
|
||||
.with_ontology_bytes(RdfFormat::Turtle, GL_ONT)
|
||||
}
|
||||
pub fn build(self) -> error::Result<Ontology> {
|
||||
let store = if let Some(path) = self.path {
|
||||
Store::open(path)
|
||||
} else {
|
||||
Store::new()
|
||||
}?;
|
||||
|
||||
fn materialize_same_as(dataset: &mut Dataset) {
|
||||
let additional_quads = dataset
|
||||
.quads_for_pattern(None, Some(owl::SAME_AS), None, None)
|
||||
.fold(Dataset::new(), |mut new_dataset, alias| {
|
||||
if let NamedOrBlankNodeRef::NamedNode(x) = alias.subject
|
||||
&& let TermRef::NamedNode(y) = alias.object
|
||||
{
|
||||
for mut quad in dataset.quads_for_pattern(
|
||||
Some(NamedOrBlankNodeRef::NamedNode(x)),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
quad.subject = NamedOrBlankNodeRef::NamedNode(y);
|
||||
new_dataset.insert(quad);
|
||||
}
|
||||
let prefixes = PREFIXES
|
||||
.iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||
.collect::<HashMap<String, String>>();
|
||||
|
||||
for mut quad in dataset.quads_for_pattern(
|
||||
Some(NamedOrBlankNodeRef::NamedNode(y)),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
quad.subject = NamedOrBlankNodeRef::NamedNode(x);
|
||||
new_dataset.insert(quad);
|
||||
let store = materialize::same_as(store)?;
|
||||
//materialize::super_classes(&mut dataset);
|
||||
|
||||
// Full-text search index field names
|
||||
//let fields = Self::fields(&dataset);
|
||||
|
||||
/*let mut entities: HashMap<NamedNode, Entity> = HashMap::new();
|
||||
let entity_iris = Self::subclass_of(&dataset, gl::ENTITY)
|
||||
.chain(Self::subclass_of(&dataset, rda::ENTITY))
|
||||
.chain([
|
||||
rdf::PROPERTY.into_owned(),
|
||||
rdfs::CLASS.into_owned(),
|
||||
]);
|
||||
|
||||
for iri in entity_iris {
|
||||
let subject = iri.as_ref().into();
|
||||
|
||||
let label = dataset.quads_for_pattern(Some(subject), Some(rdfs::LABEL), None, None)
|
||||
.filter_map(|quad| term_to_string(&quad.object.into_owned()).map(String::from))
|
||||
.next();
|
||||
|
||||
let catalog_id = dataset.quads_for_pattern(Some(subject), Some(gl::CATALOG_ID), None, None)
|
||||
.filter_map(|quad| term_to_u64(&quad.object.into_owned()))
|
||||
.next();
|
||||
|
||||
if let Some(catalog_id) = catalog_id {
|
||||
let mut properties = HashSet::new();
|
||||
for quad in dataset.quads_for_pattern(Some(subject), Some(gl::ASSOCIATED_PROPERTY), None, None) {
|
||||
if let NamedOrBlankNodeRef::NamedNode(subject) = quad.subject
|
||||
&& let TermRef::NamedNode(property) = quad.object {
|
||||
properties.insert(property.into_owned());
|
||||
}
|
||||
}
|
||||
new_dataset
|
||||
});
|
||||
|
||||
let old_size = dataset.len();
|
||||
dataset.extend(&additional_quads);
|
||||
let new_size = dataset.len();
|
||||
|
||||
if new_size > old_size {
|
||||
Self::materialize_same_as(dataset)
|
||||
}
|
||||
}
|
||||
|
||||
fn materialize_super_classes(dataset: &mut Dataset) {
|
||||
let query = SparqlEvaluator::new()
|
||||
.parse_query(
|
||||
r#"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
|
||||
CONSTRUCT {
|
||||
?item a ?parent
|
||||
} WHERE {
|
||||
?item a ?class .
|
||||
?class rdfs:subClassOf ?parent .
|
||||
}"#,
|
||||
)
|
||||
.expect("Unable to parse superclass query");
|
||||
|
||||
let mut additional_quads = Dataset::new();
|
||||
if let QueryResults::Graph(graph) = query.on_queryable_dataset(&*dataset).execute().unwrap()
|
||||
{
|
||||
additional_quads.extend(graph.filter_map(Result::ok).map(|triple| {
|
||||
Quad::new(
|
||||
triple.subject,
|
||||
triple.predicate,
|
||||
triple.object,
|
||||
GraphName::DefaultGraph,
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
let old_size = dataset.len();
|
||||
dataset.extend(&additional_quads);
|
||||
let new_size = dataset.len();
|
||||
|
||||
if new_size > old_size {
|
||||
Self::materialize_super_classes(dataset)
|
||||
}
|
||||
}
|
||||
|
||||
fn iri_information(dataset: &Dataset) -> HashMap<NamedNode, IriInformation> {
|
||||
let query = SparqlEvaluator::new()
|
||||
.parse_query(
|
||||
r#"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
|
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
PREFIX gl: <https://graphofliberty.org/2026/04/ont/>
|
||||
|
||||
SELECT DISTINCT ?class ?subject ?label ?comment ?read_only {
|
||||
VALUES ?class { rdf:Property rdfs:Class }
|
||||
?subject a ?class .
|
||||
OPTIONAL {
|
||||
?subject rdfs:label ?label
|
||||
FILTER (langMATCHES(LANG(?label), "en") || !hasLANG(?label))
|
||||
}
|
||||
OPTIONAL {
|
||||
?subject rdfs:comment ?comment
|
||||
FILTER (langMATCHES(LANG(?label), "en") || !hasLANG(?comment))
|
||||
}
|
||||
OPTIONAL { ?subject gl:readOnly ?read_only }
|
||||
}"#,
|
||||
)
|
||||
.expect("Unable to parse property query");
|
||||
|
||||
let mut results = HashMap::new();
|
||||
if let QueryResults::Solutions(solutions) =
|
||||
query.on_queryable_dataset(dataset).execute().unwrap()
|
||||
{
|
||||
for solution in solutions.filter_map(Result::ok) {
|
||||
let type_ = solution.get("class").and_then(term_to_named_node);
|
||||
let subject = solution.get("subject").and_then(term_to_named_node);
|
||||
let label = solution.get("label").and_then(term_to_string);
|
||||
let comment = solution.get("comment").and_then(term_to_string);
|
||||
let read_only = solution
|
||||
.get("read_only")
|
||||
.and_then(term_to_boolean)
|
||||
.unwrap_or(false);
|
||||
|
||||
if let Some(subject) = subject && let Some(type_) = type_ {
|
||||
let info = IriInformation {
|
||||
type_: type_.clone(),
|
||||
label: label.map(String::from),
|
||||
comment: comment.map(String::from),
|
||||
read_only,
|
||||
};
|
||||
results.insert(subject.to_owned(), info);
|
||||
}
|
||||
entities.insert(iri, Entity {
|
||||
label: label.unwrap_or(catalog_id.to_string()),
|
||||
catalog_id,
|
||||
properties,
|
||||
});
|
||||
}
|
||||
}
|
||||
results
|
||||
|
||||
let mut indexed_by = HashMap::new();
|
||||
for quad in dataset.quads_for_pattern(None, Some(gl::INDEXED_BY_FIELD), None, None) {
|
||||
if let NamedOrBlankNodeRef::NamedNode(subject) = quad.subject
|
||||
&& let TermRef::NamedNode(field) = quad.object
|
||||
{
|
||||
indexed_by.insert(subject.into_owned(), field.into_owned());
|
||||
}
|
||||
}*/
|
||||
|
||||
Ok(Ontology {
|
||||
store,
|
||||
prefixes,
|
||||
fields: HashMap::new(),
|
||||
entities: HashMap::from_iter([(rdf::PROPERTY.into_owned(), Entity {
|
||||
label: "property".to_string(),
|
||||
catalog_id: 0,
|
||||
properties: HashSet::new(),
|
||||
})]),
|
||||
indexed_by: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn fields(dataset: &Dataset) -> HashMap<NamedNode, IndexField> {
|
||||
/*fn fields(dataset: &Dataset) -> HashMap<NamedNode, IndexField> {
|
||||
let query = SparqlEvaluator::new()
|
||||
.parse_query(
|
||||
r#"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
@@ -257,82 +190,7 @@ SELECT ?class {{
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&mut self) -> error::Result<Ontology> {
|
||||
let prefixes = PREFIXES
|
||||
.iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||
.collect::<HashMap<String, String>>();
|
||||
|
||||
let mut dataset = Dataset::new();
|
||||
for (format, bytes) in &self.ontologies {
|
||||
let quads = RdfParser::from_format(*format)
|
||||
.for_slice(bytes)
|
||||
.filter_map(Result::ok);
|
||||
dataset.extend(quads);
|
||||
}
|
||||
Self::materialize_same_as(&mut dataset);
|
||||
Self::materialize_super_classes(&mut dataset);
|
||||
|
||||
let iri_info = Self::iri_information(&mut dataset);
|
||||
|
||||
// Full-text search index field names
|
||||
let fields = Self::fields(&dataset);
|
||||
|
||||
let mut entities: HashMap<NamedNode, Entity> = HashMap::new();
|
||||
let entity_iris = Self::subclass_of(&dataset, gl::ENTITY)
|
||||
.chain(Self::subclass_of(&dataset, rda::ENTITY))
|
||||
.chain([
|
||||
rdf::PROPERTY.into_owned(),
|
||||
rdfs::CLASS.into_owned(),
|
||||
]);
|
||||
|
||||
for iri in entity_iris {
|
||||
let subject = iri.as_ref().into();
|
||||
|
||||
let label = dataset.quads_for_pattern(Some(subject), Some(rdfs::LABEL), None, None)
|
||||
.filter_map(|quad| term_to_string(&quad.object.into_owned()).map(String::from))
|
||||
.next();
|
||||
|
||||
let catalog_id = dataset.quads_for_pattern(Some(subject), Some(gl::CATALOG_ID), None, None)
|
||||
.filter_map(|quad| term_to_u64(&quad.object.into_owned()))
|
||||
.next();
|
||||
|
||||
if let Some(catalog_id) = catalog_id {
|
||||
let mut properties = HashSet::new();
|
||||
for quad in dataset.quads_for_pattern(Some(subject), Some(gl::ASSOCIATED_PROPERTY), None, None) {
|
||||
if let NamedOrBlankNodeRef::NamedNode(subject) = quad.subject
|
||||
&& let TermRef::NamedNode(property) = quad.object {
|
||||
properties.insert(property.into_owned());
|
||||
}
|
||||
}
|
||||
entities.insert(iri, Entity {
|
||||
label: label.unwrap_or(catalog_id.to_string()),
|
||||
catalog_id,
|
||||
properties,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let mut indexed_by = HashMap::new();
|
||||
for quad in dataset.quads_for_pattern(None, Some(gl::INDEXED_BY_FIELD), None, None) {
|
||||
if let NamedOrBlankNodeRef::NamedNode(subject) = quad.subject
|
||||
&& let TermRef::NamedNode(field) = quad.object
|
||||
{
|
||||
indexed_by.insert(subject.into_owned(), field.into_owned());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Ontology {
|
||||
dataset,
|
||||
prefixes,
|
||||
iri_info,
|
||||
fields,
|
||||
entities,
|
||||
indexed_by,
|
||||
})
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -375,11 +233,11 @@ pub struct IndexField {
|
||||
}
|
||||
|
||||
pub struct Ontology {
|
||||
dataset: Dataset,
|
||||
store: Store,
|
||||
prefixes: HashMap<String, String>,
|
||||
|
||||
// Resource (Property or Class) -> Rust Type
|
||||
iri_info: HashMap<NamedNode, IriInformation>,
|
||||
//iri_info: HashMap<NamedNode, IriInformation>,
|
||||
|
||||
// NamedIndividual of class IndexField -> Rust Type
|
||||
fields: HashMap<NamedNode, IndexField>,
|
||||
@@ -391,58 +249,17 @@ pub struct Ontology {
|
||||
indexed_by: HashMap<NamedNode, NamedNode>,
|
||||
}
|
||||
|
||||
fn term_to_named_node(term: &Term) -> Option<&NamedNode> {
|
||||
if let Term::NamedNode(node) = term {
|
||||
Some(node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn term_to_string(term: &Term) -> Option<&str> {
|
||||
if let Term::Literal(literal) = term {
|
||||
match literal.datatype() {
|
||||
xsd::STRING | xsd::NORMALIZED_STRING | rdf::LANG_STRING | rdf::DIR_LANG_STRING => {
|
||||
Some(literal.value())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn term_to_boolean(term: &Term) -> Option<bool> {
|
||||
if let Term::Literal(literal) = term {
|
||||
if literal.datatype() == xsd::BOOLEAN {
|
||||
literal.value().parse().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn term_to_u64(term: &Term) -> Option<u64> {
|
||||
if let Term::Literal(literal) = term &&
|
||||
literal.datatype() == xsd::NON_NEGATIVE_INTEGER {
|
||||
let value: u64 = literal.value().parse().expect("Failed to parse u64 from ontology. It ought to be a non-negative integer.");
|
||||
Some(value)
|
||||
} else { None }
|
||||
}
|
||||
|
||||
impl Ontology {
|
||||
pub fn builder<'a>() -> OntologyBuilder<'a> {
|
||||
pub fn builder() -> OntologyBuilder {
|
||||
OntologyBuilder {
|
||||
ontologies: Vec::new(),
|
||||
path: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn info(&self, node: NamedNodeRef<'_>) -> Option<&IriInformation> {
|
||||
/*pub fn info(&self, node: NamedNodeRef<'_>) -> Option<&IriInformation> {
|
||||
let node = node.into_owned();
|
||||
self.iri_info.get(&node)
|
||||
}
|
||||
}*/
|
||||
|
||||
pub fn abbreviate(&self, node: NamedNodeRef<'_>) -> String {
|
||||
for (prefix_name, prefix_iri) in &self.prefixes {
|
||||
@@ -501,67 +318,62 @@ impl Ontology {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn iri_info(&self) -> &HashMap<NamedNode, IriInformation> {
|
||||
&self.iri_info
|
||||
}
|
||||
|
||||
pub fn datatypes(&self) -> impl Iterator<Item = NamedNodeRef<'_>> {
|
||||
self.dataset
|
||||
pub fn datatypes(&self) -> impl Iterator<Item = NamedNode> {
|
||||
self.store
|
||||
.quads_for_pattern(
|
||||
None,
|
||||
Some(rdf::TYPE),
|
||||
Some(TermRef::NamedNode(rdfs::DATATYPE)),
|
||||
None,
|
||||
)
|
||||
.filter_map(Result::ok)
|
||||
.filter_map(|quad| match quad.subject {
|
||||
NamedOrBlankNodeRef::NamedNode(subject) => Some(subject),
|
||||
NamedOrBlankNode::NamedNode(subject) => Some(subject),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn is_read_only_impl<'a>(iri_info: &HashMap<NamedNode, IriInformation>, triple: impl Into<TripleRef<'a>>) -> bool {
|
||||
let triple = triple.into();
|
||||
match (triple.predicate, triple.object) {
|
||||
(rdf::TYPE, TermRef::NamedNode(node)) => iri_info
|
||||
.get(&node.into_owned())
|
||||
.map(|info| info.read_only)
|
||||
.unwrap_or(false),
|
||||
(predicate, _) => iri_info
|
||||
.get(&predicate.into_owned())
|
||||
.map(|info| info.read_only)
|
||||
.unwrap_or(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exclude_read_only(&self) -> impl Fn(TripleRef<'_>) -> bool + 'static {
|
||||
let iri_info = self.iri_info.clone();
|
||||
move |triple| { Self::is_read_only_impl(&iri_info, triple) }
|
||||
}
|
||||
|
||||
pub fn is_read_only<'a>(&self, triple: impl Into<TripleRef<'a>>) -> bool {
|
||||
Self::is_read_only_impl(&self.iri_info, triple)
|
||||
let triple = triple.into();
|
||||
let true_term = TermRef::Literal(LiteralRef::new_typed_literal("true", xsd::BOOLEAN));
|
||||
|
||||
let subject = match (triple.predicate, triple.object) {
|
||||
(rdf::TYPE, TermRef::NamedNode(class)) => class,
|
||||
(predicate, _) => predicate,
|
||||
};
|
||||
|
||||
self.store
|
||||
.quads_for_pattern(Some(NamedOrBlankNodeRef::NamedNode(subject)), Some(gl::READ_ONLY), Some(true_term), None)
|
||||
.filter_map(Result::ok)
|
||||
.count() >= 1
|
||||
}
|
||||
|
||||
/*pub fn for_each_annotated_(&self) -> impl Iterator<Item = TripleRef<'_>> {
|
||||
self.store
|
||||
.quads_for_pattern()
|
||||
}*/
|
||||
|
||||
pub fn template_triples<'a>(
|
||||
&'a self,
|
||||
class: NamedNodeRef<'a>,
|
||||
subject: NamedNodeRef<'_>,
|
||||
) -> Option<impl Iterator<Item = Triple>> {
|
||||
if let Some(quad) = self
|
||||
.dataset
|
||||
.store
|
||||
.quads_for_pattern(
|
||||
Some(NamedOrBlankNodeRef::NamedNode(class)),
|
||||
Some(gl::TEMPLATE),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.filter_map(Result::ok)
|
||||
.next()
|
||||
{
|
||||
if let TermRef::BlankNode(blank_node) = quad.object {
|
||||
if let Term::BlankNode(blank_node) = quad.object {
|
||||
let iter = self
|
||||
.dataset
|
||||
.quads_for_subject(blank_node)
|
||||
.map(|quad| quad.into_owned())
|
||||
.store
|
||||
.quads_for_pattern(Some(NamedOrBlankNodeRef::BlankNode(blank_node.as_ref())), None, None, None)
|
||||
.filter_map(Result::ok)
|
||||
.map(Triple::from)
|
||||
.map(move |mut triple| {
|
||||
triple.subject = NamedOrBlankNode::NamedNode(subject.into_owned());
|
||||
|
||||
@@ -16,6 +16,9 @@ pub mod gl {
|
||||
pub const ASSOCIATED_PROPERTY: NamedNodeRef =
|
||||
NamedNodeRef::new_unchecked("https://graphofliberty.org/2026/04/ont/associatedProperty");
|
||||
|
||||
pub const READ_ONLY: NamedNodeRef =
|
||||
NamedNodeRef::new_unchecked("https://graphofliberty.org/2026/04/ont/readOnly");
|
||||
|
||||
/*pub const INDEX_FIELD: NamedNodeRef =
|
||||
NamedNodeRef::new_unchecked("https://graphofliberty.org/2026/04/ont/IndexField");*/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user