use std::collections::{BTreeMap, BTreeSet};
use serde::{Deserialize, Serialize};
use crate::{
DbError, IndexId, LabelId, ProjectionId, PropertyKeyId, RelationTypeId, RoleId,
value::PropertyType,
};
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct RoleDefinition {
pub id: RoleId,
pub name: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct LabelDefinition {
pub id: LabelId,
pub name: String,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct RelationTypeDefinition {
pub id: RelationTypeId,
pub name: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum PropertyFamily {
Element,
Relation,
Incidence,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct PropertyKeyDefinition {
pub id: PropertyKeyId,
pub name: String,
pub family: PropertyFamily,
pub value_type: PropertyType,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct GraphProjectionDefinition {
pub name: String,
pub relation_types: BTreeSet<RelationTypeId>,
pub source_role: RoleId,
pub target_role: RoleId,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct HypergraphProjectionDefinition {
pub name: String,
pub relation_types: BTreeSet<RelationTypeId>,
pub source_roles: BTreeSet<RoleId>,
pub target_roles: BTreeSet<RoleId>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum ProjectionDefinition {
Graph(GraphProjectionDefinition),
Hypergraph(HypergraphProjectionDefinition),
}
impl ProjectionDefinition {
#[must_use]
pub fn name(&self) -> &str {
match self {
Self::Graph(definition) => &definition.name,
Self::Hypergraph(definition) => &definition.name,
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum IndexDefinition {
Label {
label: LabelId,
},
RelationType {
relation_type: RelationTypeId,
},
PropertyEquality {
key: PropertyKeyId,
},
PropertyRange {
key: PropertyKeyId,
},
CompositeEquality {
keys: Vec<PropertyKeyId>,
},
Projection {
projection: ProjectionId,
},
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct IndexEntry {
pub id: IndexId,
pub name: String,
pub definition: IndexDefinition,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ProjectionEntry {
pub id: ProjectionId,
pub definition: ProjectionDefinition,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Catalog {
roles: BTreeMap<RoleId, RoleDefinition>,
role_names: BTreeMap<String, RoleId>,
labels: BTreeMap<LabelId, LabelDefinition>,
label_names: BTreeMap<String, LabelId>,
relation_types: BTreeMap<RelationTypeId, RelationTypeDefinition>,
relation_type_names: BTreeMap<String, RelationTypeId>,
property_keys: BTreeMap<PropertyKeyId, PropertyKeyDefinition>,
property_key_names: BTreeMap<String, PropertyKeyId>,
projections: BTreeMap<ProjectionId, ProjectionEntry>,
projection_names: BTreeMap<String, ProjectionId>,
indexes: BTreeMap<IndexId, IndexEntry>,
index_names: BTreeMap<String, IndexId>,
}
impl Catalog {
#[must_use]
pub(crate) const fn empty() -> Self {
Self {
roles: BTreeMap::new(),
role_names: BTreeMap::new(),
labels: BTreeMap::new(),
label_names: BTreeMap::new(),
relation_types: BTreeMap::new(),
relation_type_names: BTreeMap::new(),
property_keys: BTreeMap::new(),
property_key_names: BTreeMap::new(),
projections: BTreeMap::new(),
projection_names: BTreeMap::new(),
indexes: BTreeMap::new(),
index_names: BTreeMap::new(),
}
}
#[must_use]
pub fn role(&self, id: RoleId) -> Option<&RoleDefinition> {
self.roles.get(&id)
}
#[must_use]
pub fn label(&self, id: LabelId) -> Option<&LabelDefinition> {
self.labels.get(&id)
}
#[must_use]
pub fn relation_type(&self, id: RelationTypeId) -> Option<&RelationTypeDefinition> {
self.relation_types.get(&id)
}
#[must_use]
pub fn property_key(&self, id: PropertyKeyId) -> Option<&PropertyKeyDefinition> {
self.property_keys.get(&id)
}
#[must_use]
pub fn projection(&self, id: ProjectionId) -> Option<&ProjectionEntry> {
self.projections.get(&id)
}
#[must_use]
pub fn index(&self, id: IndexId) -> Option<&IndexEntry> {
self.indexes.get(&id)
}
#[must_use]
pub fn role_id(&self, name: &str) -> Option<RoleId> {
self.role_names.get(name).copied()
}
#[must_use]
pub fn label_id(&self, name: &str) -> Option<LabelId> {
self.label_names.get(name).copied()
}
#[must_use]
pub fn relation_type_id(&self, name: &str) -> Option<RelationTypeId> {
self.relation_type_names.get(name).copied()
}
#[must_use]
pub fn property_key_id(&self, name: &str) -> Option<PropertyKeyId> {
self.property_key_names.get(name).copied()
}
#[must_use]
pub fn projection_id(&self, name: &str) -> Option<ProjectionId> {
self.projection_names.get(name).copied()
}
#[must_use]
pub fn index_id(&self, name: &str) -> Option<IndexId> {
self.index_names.get(name).copied()
}
pub fn roles(&self) -> impl Iterator<Item = &RoleDefinition> {
self.roles.values()
}
pub fn labels(&self) -> impl Iterator<Item = &LabelDefinition> {
self.labels.values()
}
pub fn relation_types(&self) -> impl Iterator<Item = &RelationTypeDefinition> {
self.relation_types.values()
}
pub fn property_keys(&self) -> impl Iterator<Item = &PropertyKeyDefinition> {
self.property_keys.values()
}
pub fn projections(&self) -> impl Iterator<Item = &ProjectionEntry> {
self.projections.values()
}
pub fn indexes(&self) -> impl Iterator<Item = &IndexEntry> {
self.indexes.values()
}
pub(crate) fn insert_role(&mut self, id: RoleId, name: String) -> Result<(), DbError> {
insert_named(&mut self.role_names, &name, id)?;
self.roles.insert(id, RoleDefinition { id, name });
Ok(())
}
pub(crate) fn insert_label(&mut self, id: LabelId, name: String) -> Result<(), DbError> {
insert_named(&mut self.label_names, &name, id)?;
self.labels.insert(id, LabelDefinition { id, name });
Ok(())
}
pub(crate) fn insert_relation_type(
&mut self,
id: RelationTypeId,
name: String,
) -> Result<(), DbError> {
insert_named(&mut self.relation_type_names, &name, id)?;
self.relation_types
.insert(id, RelationTypeDefinition { id, name });
Ok(())
}
pub(crate) fn insert_property_key(
&mut self,
definition: PropertyKeyDefinition,
) -> Result<(), DbError> {
insert_named(
&mut self.property_key_names,
&definition.name,
definition.id,
)?;
self.property_keys.insert(definition.id, definition);
Ok(())
}
pub(crate) fn insert_projection(
&mut self,
id: ProjectionId,
definition: ProjectionDefinition,
) -> Result<(), DbError> {
insert_named(&mut self.projection_names, definition.name(), id)?;
self.projections
.insert(id, ProjectionEntry { id, definition });
Ok(())
}
pub(crate) fn insert_index(
&mut self,
id: IndexId,
name: String,
definition: IndexDefinition,
) -> Result<(), DbError> {
insert_named(&mut self.index_names, &name, id)?;
self.indexes.insert(
id,
IndexEntry {
id,
name,
definition,
},
);
Ok(())
}
}
fn insert_named<Id: Copy>(
names: &mut BTreeMap<String, Id>,
name: &str,
id: Id,
) -> Result<(), DbError> {
if names.contains_key(name) {
return Err(DbError::DuplicateCatalogName);
}
names.insert(name.to_owned(), id);
Ok(())
}