use crate::ro_crate::constraints::EntityValue;
use crate::ro_crate::context::{ContextItem, RoCrateContext};
use crate::ro_crate::graph_vector::GraphVector;
use crate::ro_crate::modify::DynamicEntityManipulation;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
#[derive(Serialize, Deserialize, Debug)]
pub struct RoCrate {
#[serde(rename = "@context")]
pub context: RoCrateContext,
#[serde(rename = "@graph")]
pub graph: Vec<GraphVector>,
}
impl RoCrate {
pub fn new(context: RoCrateContext, _graph: Vec<GraphVector>) -> RoCrate {
RoCrate {
context,
graph: Vec::new(),
}
}
pub fn get_context_items(&self) -> Vec<String> {
let mut valid_context: Vec<String> = Vec::new();
match &self.context {
RoCrateContext::EmbeddedContext(context) => {
for map in context {
for key in map.keys() {
valid_context.push(key.to_string());
}
}
}
RoCrateContext::ExtendedContext(context) => {
for map in context {
if let ContextItem::EmbeddedContext(context) = map {
for key in context.keys() {
valid_context.push(key.to_string());
}
}
}
}
RoCrateContext::ReferenceContext(context) => {
valid_context.push(context.to_string());
}
}
valid_context
}
pub fn add_context(&self) {}
pub fn get_entity(&self, id: &str) -> Option<&GraphVector> {
for entity in &self.graph {
if let Some(matching_entity) = entity.get_entity(id) {
return Some(matching_entity);
}
}
None
}
pub fn get_entity_mutable(&mut self, id: &str) -> Option<&mut GraphVector> {
for entity in &mut self.graph {
if let Some(matching_entity) = entity.get_entity_mutable(id) {
return Some(matching_entity);
}
}
None
}
pub fn get_all_ids(&self) -> Vec<&String> {
let mut id_vec: Vec<&String> = Vec::new();
for graph_vector in self.graph.iter() {
id_vec.push(graph_vector.get_id());
}
id_vec
}
pub fn find_entity_index(&mut self, id: &str) -> Option<usize> {
self.graph
.iter()
.enumerate()
.find_map(|(index, graph_vector)| {
if graph_vector.get_id() == id {
Some(index)
} else {
None
}
})
}
pub fn find_entity(&mut self, id: &str) -> Option<&GraphVector> {
self.find_entity_index(id)
.and_then(|index| self.graph.get(index))
}
pub fn remove_by_id(&mut self, id_to_remove: &str, rec: bool) {
self.graph
.retain(|graph_vector: &GraphVector| match graph_vector {
GraphVector::MetadataDescriptor(descriptor) => descriptor.id != id_to_remove,
GraphVector::RootDataEntity(entity) => entity.id != id_to_remove,
GraphVector::DataEntity(entity) => entity.id != id_to_remove,
GraphVector::ContextualEntity(entity) => entity.id != id_to_remove,
});
if rec {
self.remove_id_recursive(id_to_remove)
}
}
fn remove_id_recursive(&mut self, id: &str) {
for graph_vector in &mut self.graph {
if let GraphVector::RootDataEntity(data_entity) = graph_vector {
data_entity.remove_matching_value(id);
}
if let GraphVector::MetadataDescriptor(data_entity) = graph_vector {
data_entity.remove_matching_value(id);
}
if let GraphVector::DataEntity(data_entity) = graph_vector {
data_entity.remove_matching_value(id);
}
if let GraphVector::ContextualEntity(data_entity) = graph_vector {
data_entity.remove_matching_value(id);
}
}
}
pub fn update_id_recursive(&mut self, id_old: &str, id_new: &str) {
for graph_vector in &mut self.graph {
if graph_vector.get_id() == id_old {
graph_vector.update_id(id_new.to_string());
graph_vector.update_id_link(id_old, id_new);
} else {
graph_vector.update_id_link(id_old, id_new);
};
}
}
pub fn add_data_to_partof_root(&mut self, id: &str) {
if let Some(GraphVector::RootDataEntity(root)) = self.get_entity_mutable(id) {
root.add_entity_to_partof(id.to_string());
};
}
pub fn get_all_properties(&self) -> Vec<String> {
let mut properties: Vec<String> = Vec::new();
for graph_vector in &self.graph {
let keys = graph_vector.get_all_properties();
properties.extend(keys);
}
dedup_vec(&mut properties);
properties
}
pub fn get_all_property_values(&self, property: &str) -> Vec<(String, EntityValue)> {
let mut property_values: Vec<(String, EntityValue)> = Vec::new();
for graph_vector in &self.graph {
match graph_vector.get_specific_property(property) {
None => {}
Some(value) => property_values.push(value),
}
}
property_values
}
pub fn get_specific_value(&self, value: &str) -> Vec<(String, String)> {
let mut property_values: Vec<(String, String)> = Vec::new();
for graph_vector in &self.graph {
match graph_vector.get_specific_value(value) {
None => {}
Some(value) => property_values.push(value),
}
}
property_values
}
pub fn overwrite_by_id(&mut self, id: &str, entity: GraphVector) -> bool {
if let Some(index) = self.find_entity_index(id) {
self.graph[index] = entity;
true
} else {
false
}
}
pub fn add_dynamic_entity_property(
&mut self,
id: &str,
property: HashMap<String, EntityValue>,
) -> bool {
if let Some(index) = self.find_entity_index(id) {
self.graph[index].add_dynamic_entity_field(property);
true
} else {
false
}
}
pub fn remove_dynamic_entity_property(&mut self, id: &str, property: &str) -> bool {
if let Some(index) = self.find_entity_index(id) {
self.graph[index].remove_dynamic_entity_field(property);
true
} else {
false
}
}
pub fn to_parquet(&mut self) {}
}
impl Default for RoCrate {
fn default() -> Self {
RoCrate {
context: RoCrateContext::ReferenceContext(String::from(
"https://w3id.org/ro/crate/1.1/context",
)),
graph: Vec::new(),
}
}
}
impl fmt::Display for RoCrate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"RO-Crate: context={:?}, graph={:?}",
self.context, self.graph
)
}
}
fn dedup_vec<T: Ord>(vec: &mut Vec<T>) {
vec.sort();
vec.dedup();
}