use crate::model::literal::{DataType, Literal};
use crate::model::statement::BlankNode;
use crate::model::statement::Statement;
use language_tags::LanguageTag;
use rdftk_iri::Iri;
use rdftk_names::rdf;
use std::collections::HashMap;
use std::str::FromStr;
use super::statement::{ObjectNode, SubjectNode};
#[derive(Clone, Debug)]
pub struct Resource {
subject: SubjectNode,
predicate_objects: HashMap<Iri, Vec<ResourceObject>>,
}
#[derive(Clone, Debug)]
pub struct Predicate {
name: Iri,
objects: Vec<ResourceObject>,
}
#[derive(Clone, Debug)]
enum ResourceObject {
Resource(Resource),
Resources(Container<Resource>),
Literal(Literal),
Literals(Container<Literal>),
}
#[derive(Clone, Debug)]
enum ContainerKind {
Alt,
Bag,
Seq,
Other(Iri),
}
#[derive(Clone, Debug)]
struct Container<T> {
kind: ContainerKind,
values: Vec<T>,
}
impl From<Resource> for Vec<Statement> {
fn from(resource: Resource) -> Self {
let mut sts = Vec::default();
flatten(&resource, &mut sts);
sts
}
}
impl Resource {
pub fn new(subject: SubjectNode) -> Self {
Self {
subject,
predicate_objects: Default::default(),
}
}
pub fn anonymous() -> Self {
Self::new(BlankNode::generate().into())
}
pub fn semi_anonymous(name: BlankNode) -> Self {
Self::new(name.into())
}
pub fn individual(name: Iri) -> Self {
Self::new(name.into())
}
#[inline]
pub fn is_a_resource(&self) -> bool {
self.subject.is_resource()
}
#[inline]
pub fn is_an_individual(&self) -> bool {
self.predicate_objects.keys().any(|p| p == rdf::a_type())
}
pub fn predicate(&mut self, predicate: Predicate) -> &mut Self {
for object in predicate.objects.into_iter() {
let _ = self.insert(predicate.name.clone(), object);
}
self
}
pub fn property(&mut self, predicate: Iri, value: Literal) -> &mut Self {
self.literal(predicate, value)
}
pub fn value_of(&mut self, predicate: Iri, value: Literal) -> &mut Self {
self.literal(predicate, value)
}
pub fn literal(&mut self, predicate: Iri, value: Literal) -> &mut Self {
self.insert(predicate, ResourceObject::Literal(value))
}
pub fn literal_str(&mut self, predicate: Iri, value: &str) -> &mut Self {
let value = Literal::plain(value);
self.insert(predicate, ResourceObject::Literal(value))
}
pub fn literal_typed_str(
&mut self,
predicate: Iri,
value: &str,
data_type: DataType,
) -> &mut Self {
let value = Literal::with_data_type(value, data_type);
self.insert(predicate, ResourceObject::Literal(value))
}
pub fn literal_language_str(
&mut self,
predicate: Iri,
value: &str,
language: LanguageTag,
) -> &mut Self {
let value = Literal::with_language(value, language);
self.insert(predicate, ResourceObject::Literal(value))
}
pub fn literal_language_str_str(
&mut self,
predicate: Iri,
value: &str,
language: &str,
) -> &mut Self {
let value = Literal::with_language(value, LanguageTag::from_str(language).unwrap());
self.insert(predicate, ResourceObject::Literal(value))
}
pub fn property_alternatives(&mut self, predicate: Iri, values: &[Literal]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Literals(Container {
kind: ContainerKind::Alt,
values: values.to_vec(),
}),
)
}
pub fn property_bag(&mut self, predicate: Iri, values: &[Literal]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Literals(Container {
kind: ContainerKind::Bag,
values: values.to_vec(),
}),
)
}
pub fn property_sequence(&mut self, predicate: Iri, values: &[Literal]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Literals(Container {
kind: ContainerKind::Seq,
values: values.to_vec(),
}),
)
}
pub fn property_container(
&mut self,
predicate: Iri,
values: &[Literal],
kind: Iri,
) -> &mut Self {
self.insert(
predicate,
ResourceObject::Literals(Container {
kind: ContainerKind::Other(kind),
values: values.to_vec(),
}),
)
}
pub fn resource_blank_named(&mut self, predicate: Iri, name: &BlankNode) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resource(Resource::semi_anonymous(name.clone())),
)
}
pub fn resource_named(&mut self, predicate: Iri, name: Iri) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resource(Resource::individual(name)),
)
}
pub fn resource(&mut self, predicate: Iri, resource: Resource) -> &mut Self {
self.insert(predicate, ResourceObject::Resource(resource))
}
pub fn resource_alternatives(&mut self, predicate: Iri, values: &[Resource]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resources(Container {
kind: ContainerKind::Alt,
values: values.to_vec(),
}),
)
}
pub fn resource_bag(&mut self, predicate: Iri, values: &[Resource]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resources(Container {
kind: ContainerKind::Bag,
values: values.to_vec(),
}),
)
}
pub fn resource_sequence(&mut self, predicate: Iri, values: &[Resource]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resources(Container {
kind: ContainerKind::Seq,
values: values.to_vec(),
}),
)
}
pub fn resource_container(
&mut self,
predicate: Iri,
values: &[Resource],
kind: Iri,
) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resources(Container {
kind: ContainerKind::Other(kind),
values: values.to_vec(),
}),
)
}
pub fn instance_of(&mut self, name: Iri) -> &mut Self {
self.insert(
rdf::a_type().clone(),
ResourceObject::Resource(Resource::individual(name)),
)
}
fn insert(&mut self, predicate: Iri, object: ResourceObject) -> &mut Self {
if !self.predicate_objects.contains_key(&predicate) {
let _ = self
.predicate_objects
.insert(predicate.clone(), Default::default());
}
let values = self.predicate_objects.get_mut(&predicate).unwrap();
values.push(object);
self
}
}
impl ResourceObject {
fn is_container(&self) -> bool {
matches!(
self,
ResourceObject::Resources(_) | ResourceObject::Literals(_)
)
}
}
impl Predicate {
pub fn new(name: Iri) -> Self {
Self {
name,
objects: Default::default(),
}
}
pub fn property(&mut self, value: Literal) -> &mut Self {
self.objects.push(ResourceObject::Literal(value));
self
}
pub fn property_alternatives(&mut self, values: &[Literal]) -> &mut Self {
self.objects.push(ResourceObject::Literals(Container {
kind: ContainerKind::Alt,
values: values.to_vec(),
}));
self
}
pub fn property_bag(&mut self, values: &[Literal]) -> &mut Self {
self.objects.push(ResourceObject::Literals(Container {
kind: ContainerKind::Bag,
values: values.to_vec(),
}));
self
}
pub fn property_sequence(&mut self, values: &[Literal]) -> &mut Self {
self.objects.push(ResourceObject::Literals(Container {
kind: ContainerKind::Seq,
values: values.to_vec(),
}));
self
}
pub fn property_container(&mut self, values: &[Literal], kind: Iri) -> &mut Self {
self.objects.push(ResourceObject::Literals(Container {
kind: ContainerKind::Other(kind),
values: values.to_vec(),
}));
self
}
pub fn resource_blank_named(&mut self, name: &BlankNode) -> &mut Self {
self.objects
.push(ResourceObject::Resource(Resource::semi_anonymous(
name.clone(),
)));
self
}
pub fn resource_named(&mut self, name: Iri) -> &mut Self {
self.objects
.push(ResourceObject::Resource(Resource::individual(name)));
self
}
pub fn resource(&mut self, resource: Resource) -> &mut Self {
self.objects.push(ResourceObject::Resource(resource));
self
}
pub fn resource_alternatives(&mut self, values: &[Resource]) -> &mut Self {
self.objects.push(ResourceObject::Resources(Container {
kind: ContainerKind::Alt,
values: values.to_vec(),
}));
self
}
pub fn resource_bag(&mut self, values: &[Resource]) -> &mut Self {
self.objects.push(ResourceObject::Resources(Container {
kind: ContainerKind::Bag,
values: values.to_vec(),
}));
self
}
pub fn resource_sequence(&mut self, values: &[Resource]) -> &mut Self {
self.objects.push(ResourceObject::Resources(Container {
kind: ContainerKind::Seq,
values: values.to_vec(),
}));
self
}
pub fn resource_container(&mut self, values: &[Resource], kind: Iri) -> &mut Self {
self.objects.push(ResourceObject::Resources(Container {
kind: ContainerKind::Other(kind),
values: values.to_vec(),
}));
self
}
}
fn flatten(resource: &Resource, sts: &mut Vec<Statement>) {
let subject = &resource.subject;
for (predicate, objects) in &resource.predicate_objects {
for object in objects.iter() {
if object.is_container() {
let kind = match object {
ResourceObject::Resources(rc) => &rc.kind,
ResourceObject::Literals(lc) => &lc.kind,
_ => unreachable!(),
};
let container = SubjectNode::from(BlankNode::generate());
sts.push(Statement::new(
subject.clone(),
predicate.clone(),
container.to_object(),
));
sts.push(Statement::new(
container.clone(),
rdf::a_type().clone(),
ObjectNode::from(match kind {
ContainerKind::Alt => rdf::alt().clone(),
ContainerKind::Bag => rdf::bag().clone(),
ContainerKind::Seq => rdf::seq().clone(),
ContainerKind::Other(iri) => iri.clone(),
}),
));
match object {
ResourceObject::Resources(rc) => {
for (index, resource) in rc.values.iter().enumerate() {
flatten(resource, sts);
sts.push(Statement::new(
container.clone(),
rdf::member(index),
resource.subject.to_object(),
));
}
}
ResourceObject::Literals(lc) => {
for (index, literal) in lc.values.iter().enumerate() {
sts.push(Statement::new(
container.clone(),
rdf::member(index),
literal,
));
}
}
_ => unreachable!(),
};
} else {
let statement = Statement::new(
subject.clone(),
predicate.clone(),
match object {
ResourceObject::Resource(resource) => {
flatten(resource, sts);
subject.to_object()
}
ResourceObject::Literal(literal) => ObjectNode::from(literal.clone()),
_ => unreachable!(),
},
);
sts.push(statement);
}
}
}
}