1use std::collections::{BTreeMap, BTreeSet};
4
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 Catalog, DbError, ElementId, IncidenceId, IndexId, LabelId, ProjectionDefinition, ProjectionId,
9 PropertyKeyId, RelationId, RelationTypeId, RoleId,
10 catalog::{IndexDefinition, PropertyFamily, PropertyKeyDefinition},
11 value::PropertyValue,
12};
13
14#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
20pub struct ElementRecord {
21 pub id: ElementId,
23 pub labels: BTreeSet<LabelId>,
25}
26
27#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
33pub struct RelationRecord {
34 pub id: RelationId,
36 pub relation_type: Option<RelationTypeId>,
38 pub labels: BTreeSet<LabelId>,
40}
41
42#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
48pub struct IncidenceRecord {
49 pub id: IncidenceId,
51 pub relation: RelationId,
53 pub element: ElementId,
55 pub role: RoleId,
57}
58
59#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
65pub enum PropertySubject {
66 Element(ElementId),
68 Relation(RelationId),
70 Incidence(IncidenceId),
72}
73
74impl PropertySubject {
75 #[must_use]
81 pub const fn family(self) -> PropertyFamily {
82 match self {
83 Self::Element(_id) => PropertyFamily::Element,
84 Self::Relation(_id) => PropertyFamily::Relation,
85 Self::Incidence(_id) => PropertyFamily::Incidence,
86 }
87 }
88}
89
90#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
92pub(crate) struct DatabaseState {
93 #[serde(with = "crate::serde_map")]
95 elements: BTreeMap<ElementId, ElementRecord>,
96 #[serde(with = "crate::serde_map")]
98 relations: BTreeMap<RelationId, RelationRecord>,
99 #[serde(with = "crate::serde_map")]
101 incidences: BTreeMap<IncidenceId, IncidenceRecord>,
102 #[serde(with = "crate::serde_map::nested")]
104 properties: BTreeMap<PropertySubject, BTreeMap<PropertyKeyId, PropertyValue>>,
105 catalog: Catalog,
107 next_element: ElementId,
109 next_relation: RelationId,
111 next_incidence: IncidenceId,
113 next_role: RoleId,
115 next_label: LabelId,
117 next_relation_type: RelationTypeId,
119 next_property_key: PropertyKeyId,
121 next_projection: ProjectionId,
123 next_index: IndexId,
125}
126
127impl DatabaseState {
128 #[must_use]
134 pub(crate) const fn empty() -> Self {
135 Self {
136 elements: BTreeMap::new(),
137 relations: BTreeMap::new(),
138 incidences: BTreeMap::new(),
139 properties: BTreeMap::new(),
140 catalog: Catalog::empty(),
141 next_element: ElementId::new(1),
142 next_relation: RelationId::new(1),
143 next_incidence: IncidenceId::new(1),
144 next_role: RoleId::new(1),
145 next_label: LabelId::new(1),
146 next_relation_type: RelationTypeId::new(1),
147 next_property_key: PropertyKeyId::new(1),
148 next_projection: ProjectionId::new(1),
149 next_index: IndexId::new(1),
150 }
151 }
152
153 #[must_use]
159 pub(crate) const fn catalog(&self) -> &Catalog {
160 &self.catalog
161 }
162
163 #[must_use]
169 pub(crate) fn contains_element(&self, id: ElementId) -> bool {
170 self.elements.contains_key(&id)
171 }
172
173 #[must_use]
179 pub(crate) fn contains_relation(&self, id: RelationId) -> bool {
180 self.relations.contains_key(&id)
181 }
182
183 #[must_use]
189 pub(crate) fn contains_incidence(&self, id: IncidenceId) -> bool {
190 self.incidences.contains_key(&id)
191 }
192
193 #[must_use]
199 pub(crate) fn element_count(&self) -> usize {
200 self.elements.len()
201 }
202
203 #[must_use]
209 pub(crate) fn relation_count(&self) -> usize {
210 self.relations.len()
211 }
212
213 #[must_use]
219 pub(crate) fn incidence_count(&self) -> usize {
220 self.incidences.len()
221 }
222
223 pub(crate) fn elements(&self) -> impl Iterator<Item = &ElementRecord> {
229 self.elements.values()
230 }
231
232 pub(crate) fn relations(&self) -> impl Iterator<Item = &RelationRecord> {
238 self.relations.values()
239 }
240
241 pub(crate) fn incidences(&self) -> impl Iterator<Item = &IncidenceRecord> {
247 self.incidences.values()
248 }
249
250 #[must_use]
256 pub(crate) fn element(&self, id: ElementId) -> Option<&ElementRecord> {
257 self.elements.get(&id)
258 }
259
260 #[must_use]
266 pub(crate) fn relation(&self, id: RelationId) -> Option<&RelationRecord> {
267 self.relations.get(&id)
268 }
269
270 #[must_use]
276 pub(crate) fn incidence(&self, id: IncidenceId) -> Option<&IncidenceRecord> {
277 self.incidences.get(&id)
278 }
279
280 pub(crate) fn relation_incidences(
286 &self,
287 id: RelationId,
288 ) -> impl Iterator<Item = &IncidenceRecord> {
289 self.incidences
290 .values()
291 .filter(move |record| record.relation == id)
292 }
293
294 pub(crate) fn element_incidences(
300 &self,
301 id: ElementId,
302 ) -> impl Iterator<Item = &IncidenceRecord> {
303 self.incidences
304 .values()
305 .filter(move |record| record.element == id)
306 }
307
308 pub(crate) fn create_element(&mut self) -> Result<ElementId, DbError> {
310 let id = self.next_element;
311 self.next_element = id.checked_next().ok_or(DbError::IdOverflow)?;
312 let previous = self.elements.insert(
313 id,
314 ElementRecord {
315 id,
316 labels: BTreeSet::new(),
317 },
318 );
319 if previous.is_some() {
320 return Err(DbError::DuplicateId);
321 }
322 Ok(id)
323 }
324
325 pub(crate) fn create_relation(&mut self) -> Result<RelationId, DbError> {
327 let id = self.next_relation;
328 self.next_relation = id.checked_next().ok_or(DbError::IdOverflow)?;
329 let previous = self.relations.insert(
330 id,
331 RelationRecord {
332 id,
333 relation_type: None,
334 labels: BTreeSet::new(),
335 },
336 );
337 if previous.is_some() {
338 return Err(DbError::DuplicateId);
339 }
340 Ok(id)
341 }
342
343 pub(crate) fn create_incidence(
345 &mut self,
346 relation: RelationId,
347 element: ElementId,
348 role: RoleId,
349 ) -> Result<IncidenceId, DbError> {
350 self.require_relation(relation)?;
351 self.require_element(element)?;
352 self.require_role(role)?;
353 let id = self.next_incidence;
354 self.next_incidence = id.checked_next().ok_or(DbError::IdOverflow)?;
355 let previous = self.incidences.insert(
356 id,
357 IncidenceRecord {
358 id,
359 relation,
360 element,
361 role,
362 },
363 );
364 if previous.is_some() {
365 return Err(DbError::DuplicateId);
366 }
367 Ok(id)
368 }
369
370 pub(crate) fn tombstone_element(&mut self, id: ElementId) -> Result<(), DbError> {
372 self.elements
373 .remove(&id)
374 .ok_or(DbError::UnknownElement { id })?;
375 self.properties.remove(&PropertySubject::Element(id));
376 self.remove_incidences(|record| record.element == id);
377 Ok(())
378 }
379
380 pub(crate) fn tombstone_relation(&mut self, id: RelationId) -> Result<(), DbError> {
382 self.relations
383 .remove(&id)
384 .ok_or(DbError::UnknownRelation { id })?;
385 self.properties.remove(&PropertySubject::Relation(id));
386 self.remove_incidences(|record| record.relation == id);
387 Ok(())
388 }
389
390 pub(crate) fn tombstone_incidence(&mut self, id: IncidenceId) -> Result<(), DbError> {
392 self.incidences
393 .remove(&id)
394 .ok_or(DbError::UnknownIncidence { id })?;
395 self.properties.remove(&PropertySubject::Incidence(id));
396 Ok(())
397 }
398
399 pub(crate) fn register_role(&mut self, name: String) -> Result<RoleId, DbError> {
401 let id = self.next_role;
402 self.next_role = id.checked_next().ok_or(DbError::IdOverflow)?;
403 self.catalog.insert_role(id, name)?;
404 Ok(id)
405 }
406
407 pub(crate) fn register_label(&mut self, name: String) -> Result<LabelId, DbError> {
409 let id = self.next_label;
410 self.next_label = id.checked_next().ok_or(DbError::IdOverflow)?;
411 self.catalog.insert_label(id, name)?;
412 Ok(id)
413 }
414
415 pub(crate) fn register_relation_type(
417 &mut self,
418 name: String,
419 ) -> Result<RelationTypeId, DbError> {
420 let id = self.next_relation_type;
421 self.next_relation_type = id.checked_next().ok_or(DbError::IdOverflow)?;
422 self.catalog.insert_relation_type(id, name)?;
423 Ok(id)
424 }
425
426 pub(crate) fn register_property_key(
428 &mut self,
429 name: String,
430 family: PropertyFamily,
431 value_type: crate::PropertyType,
432 ) -> Result<PropertyKeyId, DbError> {
433 let id = self.next_property_key;
434 self.next_property_key = id.checked_next().ok_or(DbError::IdOverflow)?;
435 self.catalog.insert_property_key(PropertyKeyDefinition {
436 id,
437 name,
438 family,
439 value_type,
440 })?;
441 Ok(id)
442 }
443
444 pub(crate) fn define_projection(
446 &mut self,
447 definition: ProjectionDefinition,
448 ) -> Result<ProjectionId, DbError> {
449 self.validate_projection_definition(&definition)?;
450 let id = self.next_projection;
451 self.next_projection = id.checked_next().ok_or(DbError::IdOverflow)?;
452 self.catalog.insert_projection(id, definition)?;
453 Ok(id)
454 }
455
456 pub(crate) fn define_index(
458 &mut self,
459 name: String,
460 definition: IndexDefinition,
461 ) -> Result<IndexId, DbError> {
462 self.validate_index_definition(&definition)?;
463 let id = self.next_index;
464 self.next_index = id.checked_next().ok_or(DbError::IdOverflow)?;
465 self.catalog.insert_index(id, name, definition)?;
466 Ok(id)
467 }
468
469 pub(crate) fn add_element_label(
471 &mut self,
472 element: ElementId,
473 label: LabelId,
474 ) -> Result<(), DbError> {
475 self.require_label(label)?;
476 let record = self
477 .elements
478 .get_mut(&element)
479 .ok_or(DbError::UnknownElement { id: element })?;
480 record.labels.insert(label);
481 Ok(())
482 }
483
484 pub(crate) fn add_relation_label(
486 &mut self,
487 relation: RelationId,
488 label: LabelId,
489 ) -> Result<(), DbError> {
490 self.require_label(label)?;
491 let record = self
492 .relations
493 .get_mut(&relation)
494 .ok_or(DbError::UnknownRelation { id: relation })?;
495 record.labels.insert(label);
496 Ok(())
497 }
498
499 pub(crate) fn set_relation_type(
501 &mut self,
502 relation: RelationId,
503 relation_type: RelationTypeId,
504 ) -> Result<(), DbError> {
505 self.require_relation_type(relation_type)?;
506 let record = self
507 .relations
508 .get_mut(&relation)
509 .ok_or(DbError::UnknownRelation { id: relation })?;
510 record.relation_type = Some(relation_type);
511 Ok(())
512 }
513
514 pub(crate) fn set_property(
516 &mut self,
517 subject: PropertySubject,
518 key: PropertyKeyId,
519 value: PropertyValue,
520 ) -> Result<(), DbError> {
521 self.require_subject(subject)?;
522 let definition = self
523 .catalog
524 .property_key(key)
525 .ok_or(DbError::UnknownPropertyKey { id: key })?;
526 if definition.family != subject.family() {
527 return Err(DbError::WrongPropertyFamily {
528 expected: definition.family,
529 actual: subject.family(),
530 });
531 }
532 if definition.value_type != value.value_type() {
533 return Err(DbError::PropertyTypeMismatch {
534 expected: definition.value_type,
535 actual: value.value_type(),
536 });
537 }
538 self.properties
539 .entry(subject)
540 .or_default()
541 .insert(key, value);
542 Ok(())
543 }
544
545 pub(crate) fn remove_property(
547 &mut self,
548 subject: PropertySubject,
549 key: PropertyKeyId,
550 ) -> Result<(), DbError> {
551 self.require_subject(subject)?;
552 self.require_property_key(key)?;
553 if let Some(values) = self.properties.get_mut(&subject) {
554 values.remove(&key);
555 if values.is_empty() {
556 self.properties.remove(&subject);
557 }
558 }
559 Ok(())
560 }
561
562 #[must_use]
564 pub(crate) fn property(
565 &self,
566 subject: PropertySubject,
567 key: PropertyKeyId,
568 ) -> Option<&PropertyValue> {
569 self.properties
570 .get(&subject)
571 .and_then(|values| values.get(&key))
572 }
573
574 pub(crate) fn property_equal(
576 &self,
577 key: PropertyKeyId,
578 value: &PropertyValue,
579 ) -> Vec<PropertySubject> {
580 self.properties
581 .iter()
582 .filter_map(|(subject, values)| (values.get(&key) == Some(value)).then_some(*subject))
583 .collect()
584 }
585
586 pub(crate) fn typed_property_equal(
588 &self,
589 key: PropertyKeyId,
590 value: &PropertyValue,
591 ) -> Result<Vec<PropertySubject>, DbError> {
592 self.validate_lookup_value(key, value)?;
593 Ok(self.property_equal(key, value))
594 }
595
596 pub(crate) fn typed_property_equal_for_family(
598 &self,
599 key: PropertyKeyId,
600 family: PropertyFamily,
601 value: &PropertyValue,
602 ) -> Result<Vec<PropertySubject>, DbError> {
603 self.validate_lookup_value_for_family(key, family, value)?;
604 Ok(self.property_equal(key, value))
605 }
606
607 pub(crate) fn property_range(
609 &self,
610 key: PropertyKeyId,
611 min: &PropertyValue,
612 max: &PropertyValue,
613 ) -> Vec<PropertySubject> {
614 self.properties
615 .iter()
616 .filter_map(|(subject, values)| {
617 let value = values.get(&key)?;
618 (value >= min && value <= max).then_some(*subject)
619 })
620 .collect()
621 }
622
623 pub(crate) fn typed_property_range(
625 &self,
626 key: PropertyKeyId,
627 min: &PropertyValue,
628 max: &PropertyValue,
629 ) -> Result<Vec<PropertySubject>, DbError> {
630 self.validate_lookup_value(key, min)?;
631 self.validate_lookup_value(key, max)?;
632 if min > max {
633 return Ok(Vec::new());
634 }
635 Ok(self.property_range(key, min, max))
636 }
637
638 pub(crate) fn typed_property_composite_equal(
640 &self,
641 keys: &[PropertyKeyId],
642 values: &[PropertyValue],
643 ) -> Result<Vec<PropertySubject>, DbError> {
644 if keys.len() != values.len() {
645 return Err(DbError::unsupported(
646 "composite equality tuple arity mismatch",
647 ));
648 }
649 for (key, value) in keys.iter().copied().zip(values) {
650 self.validate_lookup_value(key, value)?;
651 }
652 Ok(self
653 .properties
654 .iter()
655 .filter_map(|(subject, property_values)| {
656 keys.iter()
657 .copied()
658 .zip(values)
659 .all(|(key, value)| property_values.get(&key) == Some(value))
660 .then_some(*subject)
661 })
662 .collect())
663 }
664
665 pub(crate) fn elements_with_label(&self, label: LabelId) -> Vec<ElementId> {
667 self.elements
668 .values()
669 .filter_map(|record| record.labels.contains(&label).then_some(record.id))
670 .collect()
671 }
672
673 pub(crate) fn relations_with_type(&self, relation_type: RelationTypeId) -> Vec<RelationId> {
675 self.relations
676 .values()
677 .filter_map(|record| (record.relation_type == Some(relation_type)).then_some(record.id))
678 .collect()
679 }
680
681 pub(crate) fn validate(&self) -> Result<(), DbError> {
683 for record in self.incidences.values() {
684 self.require_relation(record.relation)?;
685 self.require_element(record.element)?;
686 self.require_role(record.role)?;
687 }
688 for record in self.elements.values() {
689 self.require_labels(&record.labels)?;
690 }
691 for record in self.relations.values() {
692 self.require_labels(&record.labels)?;
693 if let Some(relation_type) = record.relation_type {
694 self.require_relation_type(relation_type)?;
695 }
696 }
697 self.validate_properties()?;
698 self.validate_catalog_definitions()
699 }
700
701 fn require_element(&self, id: ElementId) -> Result<(), DbError> {
703 self.elements
704 .contains_key(&id)
705 .then_some(())
706 .ok_or(DbError::UnknownElement { id })
707 }
708
709 fn require_relation(&self, id: RelationId) -> Result<(), DbError> {
711 self.relations
712 .contains_key(&id)
713 .then_some(())
714 .ok_or(DbError::UnknownRelation { id })
715 }
716
717 fn require_incidence(&self, id: IncidenceId) -> Result<(), DbError> {
719 self.incidences
720 .contains_key(&id)
721 .then_some(())
722 .ok_or(DbError::UnknownIncidence { id })
723 }
724
725 fn require_role(&self, id: RoleId) -> Result<(), DbError> {
727 self.catalog
728 .role(id)
729 .is_some()
730 .then_some(())
731 .ok_or(DbError::UnknownRole { id })
732 }
733
734 fn require_label(&self, id: LabelId) -> Result<(), DbError> {
736 self.catalog
737 .label(id)
738 .is_some()
739 .then_some(())
740 .ok_or(DbError::UnknownLabel { id })
741 }
742
743 fn require_relation_type(&self, id: RelationTypeId) -> Result<(), DbError> {
745 self.catalog
746 .relation_type(id)
747 .is_some()
748 .then_some(())
749 .ok_or(DbError::UnknownRelationType { id })
750 }
751
752 fn require_property_key(&self, id: PropertyKeyId) -> Result<(), DbError> {
754 self.catalog
755 .property_key(id)
756 .is_some()
757 .then_some(())
758 .ok_or(DbError::UnknownPropertyKey { id })
759 }
760
761 fn require_subject(&self, subject: PropertySubject) -> Result<(), DbError> {
763 match subject {
764 PropertySubject::Element(id) => self.require_element(id),
765 PropertySubject::Relation(id) => self.require_relation(id),
766 PropertySubject::Incidence(id) => self.require_incidence(id),
767 }
768 }
769
770 fn require_labels(&self, labels: &BTreeSet<LabelId>) -> Result<(), DbError> {
772 for label in labels {
773 self.require_label(*label)?;
774 }
775 Ok(())
776 }
777
778 fn remove_incidences(&mut self, mut should_remove: impl FnMut(&IncidenceRecord) -> bool) {
780 let removed: Vec<_> = self
781 .incidences
782 .values()
783 .filter_map(|record| should_remove(record).then_some(record.id))
784 .collect();
785 for id in removed {
786 self.incidences.remove(&id);
787 self.properties.remove(&PropertySubject::Incidence(id));
788 }
789 }
790
791 fn validate_projection_definition(
793 &self,
794 definition: &ProjectionDefinition,
795 ) -> Result<(), DbError> {
796 match definition {
797 ProjectionDefinition::Graph(graph) => {
798 self.require_role(graph.source_role)?;
799 self.require_role(graph.target_role)?;
800 self.require_relation_types(&graph.relation_types)
801 }
802 ProjectionDefinition::Hypergraph(hypergraph) => {
803 self.require_roles(&hypergraph.source_roles)?;
804 self.require_roles(&hypergraph.target_roles)?;
805 self.require_relation_types(&hypergraph.relation_types)
806 }
807 }
808 }
809
810 fn validate_index_definition(&self, definition: &IndexDefinition) -> Result<(), DbError> {
812 match definition {
813 IndexDefinition::Label { label } => self.require_label(*label),
814 IndexDefinition::RelationType { relation_type } => {
815 self.require_relation_type(*relation_type)
816 }
817 IndexDefinition::PropertyEquality { key } | IndexDefinition::PropertyRange { key } => {
818 self.require_property_key(*key)
819 }
820 IndexDefinition::CompositeEquality { keys } => {
821 if keys.is_empty() {
822 return Err(DbError::unsupported(
823 "composite equality index requires at least one key",
824 ));
825 }
826 for key in keys {
827 self.require_property_key(*key)?;
828 }
829 Ok(())
830 }
831 IndexDefinition::Projection { projection } => self
832 .catalog
833 .projection(*projection)
834 .is_some()
835 .then_some(())
836 .ok_or(DbError::UnknownProjection { id: *projection }),
837 }
838 }
839
840 fn require_roles(&self, roles: &BTreeSet<RoleId>) -> Result<(), DbError> {
842 for role in roles {
843 self.require_role(*role)?;
844 }
845 Ok(())
846 }
847
848 fn require_relation_types(
850 &self,
851 relation_types: &BTreeSet<RelationTypeId>,
852 ) -> Result<(), DbError> {
853 for relation_type in relation_types {
854 self.require_relation_type(*relation_type)?;
855 }
856 Ok(())
857 }
858
859 fn validate_properties(&self) -> Result<(), DbError> {
861 for (subject, values) in &self.properties {
862 self.require_subject(*subject)?;
863 for (key, value) in values {
864 self.validate_property_value(*subject, *key, value)?;
865 }
866 }
867 Ok(())
868 }
869
870 fn validate_lookup_value(
872 &self,
873 key: PropertyKeyId,
874 value: &PropertyValue,
875 ) -> Result<(), DbError> {
876 let definition = self
877 .catalog
878 .property_key(key)
879 .ok_or(DbError::UnknownPropertyKey { id: key })?;
880 let actual = value.value_type();
881 if definition.value_type != actual {
882 return Err(DbError::PropertyTypeMismatch {
883 expected: definition.value_type,
884 actual,
885 });
886 }
887 Ok(())
888 }
889
890 pub(crate) fn validate_lookup_value_for_family(
892 &self,
893 key: PropertyKeyId,
894 family: PropertyFamily,
895 value: &PropertyValue,
896 ) -> Result<(), DbError> {
897 let definition = self
898 .catalog
899 .property_key(key)
900 .ok_or(DbError::UnknownPropertyKey { id: key })?;
901 if definition.family != family {
902 return Err(DbError::WrongPropertyFamily {
903 expected: definition.family,
904 actual: family,
905 });
906 }
907 if definition.value_type != value.value_type() {
908 return Err(DbError::PropertyTypeMismatch {
909 expected: definition.value_type,
910 actual: value.value_type(),
911 });
912 }
913 Ok(())
914 }
915
916 fn validate_property_value(
918 &self,
919 subject: PropertySubject,
920 key: PropertyKeyId,
921 value: &PropertyValue,
922 ) -> Result<(), DbError> {
923 let definition = self
924 .catalog
925 .property_key(key)
926 .ok_or(DbError::UnknownPropertyKey { id: key })?;
927 if definition.family != subject.family() {
928 return Err(DbError::WrongPropertyFamily {
929 expected: definition.family,
930 actual: subject.family(),
931 });
932 }
933 if definition.value_type != value.value_type() {
934 return Err(DbError::PropertyTypeMismatch {
935 expected: definition.value_type,
936 actual: value.value_type(),
937 });
938 }
939 Ok(())
940 }
941
942 fn validate_catalog_definitions(&self) -> Result<(), DbError> {
944 for entry in self.catalog.projections() {
945 self.validate_projection_definition(&entry.definition)?;
946 }
947 for entry in self.catalog.indexes() {
948 self.validate_index_definition(&entry.definition)?;
949 }
950 Ok(())
951 }
952}