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, Copy, Debug)]
97pub(crate) struct NextIds {
98 pub(crate) element: ElementId,
100 pub(crate) relation: RelationId,
102 pub(crate) incidence: IncidenceId,
104 pub(crate) role: RoleId,
106 pub(crate) label: LabelId,
108 pub(crate) relation_type: RelationTypeId,
110 pub(crate) property_key: PropertyKeyId,
112 pub(crate) projection: ProjectionId,
114 pub(crate) index: IndexId,
116}
117
118pub(crate) struct DatabaseParts {
121 pub(crate) elements: BTreeMap<ElementId, ElementRecord>,
123 pub(crate) relations: BTreeMap<RelationId, RelationRecord>,
125 pub(crate) incidences: BTreeMap<IncidenceId, IncidenceRecord>,
127 pub(crate) properties: BTreeMap<PropertySubject, BTreeMap<PropertyKeyId, PropertyValue>>,
129 pub(crate) catalog: Catalog,
131 pub(crate) next: NextIds,
133}
134
135#[derive(Clone, Debug)]
137pub(crate) struct DatabaseState {
138 elements: BTreeMap<ElementId, ElementRecord>,
140 relations: BTreeMap<RelationId, RelationRecord>,
142 incidences: BTreeMap<IncidenceId, IncidenceRecord>,
144 properties: BTreeMap<PropertySubject, BTreeMap<PropertyKeyId, PropertyValue>>,
146 catalog: Catalog,
148 next_element: ElementId,
150 next_relation: RelationId,
152 next_incidence: IncidenceId,
154 next_role: RoleId,
156 next_label: LabelId,
158 next_relation_type: RelationTypeId,
160 next_property_key: PropertyKeyId,
162 next_projection: ProjectionId,
164 next_index: IndexId,
166 label_members: BTreeMap<LabelId, BTreeSet<ElementId>>,
168 relation_type_members: BTreeMap<RelationTypeId, BTreeSet<RelationId>>,
170}
171
172impl PartialEq for DatabaseState {
173 fn eq(&self, other: &Self) -> bool {
174 self.elements == other.elements
177 && self.relations == other.relations
178 && self.incidences == other.incidences
179 && self.properties == other.properties
180 && self.catalog == other.catalog
181 && self.next_element == other.next_element
182 && self.next_relation == other.next_relation
183 && self.next_incidence == other.next_incidence
184 && self.next_role == other.next_role
185 && self.next_label == other.next_label
186 && self.next_relation_type == other.next_relation_type
187 && self.next_property_key == other.next_property_key
188 && self.next_projection == other.next_projection
189 && self.next_index == other.next_index
190 }
191}
192
193impl Eq for DatabaseState {}
194
195impl DatabaseState {
196 #[must_use]
202 pub(crate) const fn empty() -> Self {
203 Self {
204 elements: BTreeMap::new(),
205 relations: BTreeMap::new(),
206 incidences: BTreeMap::new(),
207 properties: BTreeMap::new(),
208 catalog: Catalog::empty(),
209 next_element: ElementId::new(1),
210 next_relation: RelationId::new(1),
211 next_incidence: IncidenceId::new(1),
212 next_role: RoleId::new(1),
213 next_label: LabelId::new(1),
214 next_relation_type: RelationTypeId::new(1),
215 next_property_key: PropertyKeyId::new(1),
216 next_projection: ProjectionId::new(1),
217 next_index: IndexId::new(1),
218 label_members: BTreeMap::new(),
219 relation_type_members: BTreeMap::new(),
220 }
221 }
222
223 pub(crate) fn from_parts(parts: DatabaseParts) -> Self {
230 let mut state = Self {
231 elements: parts.elements,
232 relations: parts.relations,
233 incidences: parts.incidences,
234 properties: parts.properties,
235 catalog: parts.catalog,
236 next_element: parts.next.element,
237 next_relation: parts.next.relation,
238 next_incidence: parts.next.incidence,
239 next_role: parts.next.role,
240 next_label: parts.next.label,
241 next_relation_type: parts.next.relation_type,
242 next_property_key: parts.next.property_key,
243 next_projection: parts.next.projection,
244 next_index: parts.next.index,
245 label_members: BTreeMap::new(),
246 relation_type_members: BTreeMap::new(),
247 };
248 state.rebuild_membership_indexes();
249 state
250 }
251
252 pub(crate) fn rebuild_membership_indexes(&mut self) {
259 let mut label_members: BTreeMap<LabelId, BTreeSet<ElementId>> = BTreeMap::new();
260 for record in self.elements.values() {
261 for label in &record.labels {
262 label_members.entry(*label).or_default().insert(record.id);
263 }
264 }
265 let mut relation_type_members: BTreeMap<RelationTypeId, BTreeSet<RelationId>> =
266 BTreeMap::new();
267 for record in self.relations.values() {
268 if let Some(relation_type) = record.relation_type {
269 relation_type_members
270 .entry(relation_type)
271 .or_default()
272 .insert(record.id);
273 }
274 }
275 self.label_members = label_members;
276 self.relation_type_members = relation_type_members;
277 }
278
279 pub(crate) const fn next_ids(&self) -> NextIds {
285 NextIds {
286 element: self.next_element,
287 relation: self.next_relation,
288 incidence: self.next_incidence,
289 role: self.next_role,
290 label: self.next_label,
291 relation_type: self.next_relation_type,
292 property_key: self.next_property_key,
293 projection: self.next_projection,
294 index: self.next_index,
295 }
296 }
297
298 pub(crate) fn property_iter(
305 &self,
306 ) -> impl Iterator<Item = (PropertySubject, PropertyKeyId, &PropertyValue)> {
307 self.properties.iter().flat_map(|(subject, values)| {
308 values
309 .iter()
310 .map(move |(key, value)| (*subject, *key, value))
311 })
312 }
313
314 #[must_use]
320 pub(crate) const fn catalog(&self) -> &Catalog {
321 &self.catalog
322 }
323
324 #[must_use]
330 pub(crate) fn contains_element(&self, id: ElementId) -> bool {
331 self.elements.contains_key(&id)
332 }
333
334 #[must_use]
340 pub(crate) fn contains_relation(&self, id: RelationId) -> bool {
341 self.relations.contains_key(&id)
342 }
343
344 #[must_use]
350 pub(crate) fn contains_incidence(&self, id: IncidenceId) -> bool {
351 self.incidences.contains_key(&id)
352 }
353
354 #[must_use]
360 pub(crate) fn element_count(&self) -> usize {
361 self.elements.len()
362 }
363
364 #[must_use]
370 pub(crate) fn relation_count(&self) -> usize {
371 self.relations.len()
372 }
373
374 #[must_use]
380 pub(crate) fn incidence_count(&self) -> usize {
381 self.incidences.len()
382 }
383
384 pub(crate) fn elements(&self) -> impl Iterator<Item = &ElementRecord> {
390 self.elements.values()
391 }
392
393 pub(crate) fn relations(&self) -> impl Iterator<Item = &RelationRecord> {
399 self.relations.values()
400 }
401
402 pub(crate) fn incidences(&self) -> impl Iterator<Item = &IncidenceRecord> {
408 self.incidences.values()
409 }
410
411 #[must_use]
417 pub(crate) fn element(&self, id: ElementId) -> Option<&ElementRecord> {
418 self.elements.get(&id)
419 }
420
421 #[must_use]
427 pub(crate) fn relation(&self, id: RelationId) -> Option<&RelationRecord> {
428 self.relations.get(&id)
429 }
430
431 #[must_use]
437 pub(crate) fn incidence(&self, id: IncidenceId) -> Option<&IncidenceRecord> {
438 self.incidences.get(&id)
439 }
440
441 pub(crate) fn relation_incidences(
447 &self,
448 id: RelationId,
449 ) -> impl Iterator<Item = &IncidenceRecord> {
450 self.incidences
451 .values()
452 .filter(move |record| record.relation == id)
453 }
454
455 pub(crate) fn element_incidences(
461 &self,
462 id: ElementId,
463 ) -> impl Iterator<Item = &IncidenceRecord> {
464 self.incidences
465 .values()
466 .filter(move |record| record.element == id)
467 }
468
469 pub(crate) fn create_element(&mut self) -> Result<ElementId, DbError> {
471 let id = self.next_element;
472 self.next_element = id.checked_next().ok_or(DbError::IdOverflow)?;
473 let previous = self.elements.insert(
474 id,
475 ElementRecord {
476 id,
477 labels: BTreeSet::new(),
478 },
479 );
480 if previous.is_some() {
481 return Err(DbError::DuplicateId);
482 }
483 Ok(id)
484 }
485
486 pub(crate) fn create_relation(&mut self) -> Result<RelationId, DbError> {
488 let id = self.next_relation;
489 self.next_relation = id.checked_next().ok_or(DbError::IdOverflow)?;
490 let previous = self.relations.insert(
491 id,
492 RelationRecord {
493 id,
494 relation_type: None,
495 labels: BTreeSet::new(),
496 },
497 );
498 if previous.is_some() {
499 return Err(DbError::DuplicateId);
500 }
501 Ok(id)
502 }
503
504 pub(crate) fn create_incidence(
506 &mut self,
507 relation: RelationId,
508 element: ElementId,
509 role: RoleId,
510 ) -> Result<IncidenceId, DbError> {
511 self.require_relation(relation)?;
512 self.require_element(element)?;
513 self.require_role(role)?;
514 let id = self.next_incidence;
515 self.next_incidence = id.checked_next().ok_or(DbError::IdOverflow)?;
516 let previous = self.incidences.insert(
517 id,
518 IncidenceRecord {
519 id,
520 relation,
521 element,
522 role,
523 },
524 );
525 if previous.is_some() {
526 return Err(DbError::DuplicateId);
527 }
528 Ok(id)
529 }
530
531 pub(crate) fn tombstone_element(&mut self, id: ElementId) -> Result<(), DbError> {
533 self.elements
534 .remove(&id)
535 .ok_or(DbError::UnknownElement { id })?;
536 self.properties.remove(&PropertySubject::Element(id));
537 self.remove_incidences(|record| record.element == id);
538 Ok(())
539 }
540
541 pub(crate) fn tombstone_relation(&mut self, id: RelationId) -> Result<(), DbError> {
543 self.relations
544 .remove(&id)
545 .ok_or(DbError::UnknownRelation { id })?;
546 self.properties.remove(&PropertySubject::Relation(id));
547 self.remove_incidences(|record| record.relation == id);
548 Ok(())
549 }
550
551 pub(crate) fn tombstone_incidence(&mut self, id: IncidenceId) -> Result<(), DbError> {
553 self.incidences
554 .remove(&id)
555 .ok_or(DbError::UnknownIncidence { id })?;
556 self.properties.remove(&PropertySubject::Incidence(id));
557 Ok(())
558 }
559
560 pub(crate) fn register_role(&mut self, name: String) -> Result<RoleId, DbError> {
562 let id = self.next_role;
563 self.next_role = id.checked_next().ok_or(DbError::IdOverflow)?;
564 self.catalog.insert_role(id, name)?;
565 Ok(id)
566 }
567
568 pub(crate) fn register_label(&mut self, name: String) -> Result<LabelId, DbError> {
570 let id = self.next_label;
571 self.next_label = id.checked_next().ok_or(DbError::IdOverflow)?;
572 self.catalog.insert_label(id, name)?;
573 Ok(id)
574 }
575
576 pub(crate) fn register_relation_type(
578 &mut self,
579 name: String,
580 ) -> Result<RelationTypeId, DbError> {
581 let id = self.next_relation_type;
582 self.next_relation_type = id.checked_next().ok_or(DbError::IdOverflow)?;
583 self.catalog.insert_relation_type(id, name)?;
584 Ok(id)
585 }
586
587 pub(crate) fn register_property_key(
589 &mut self,
590 name: String,
591 family: PropertyFamily,
592 value_type: crate::PropertyType,
593 ) -> Result<PropertyKeyId, DbError> {
594 let id = self.next_property_key;
595 self.next_property_key = id.checked_next().ok_or(DbError::IdOverflow)?;
596 self.catalog.insert_property_key(PropertyKeyDefinition {
597 id,
598 name,
599 family,
600 value_type,
601 })?;
602 Ok(id)
603 }
604
605 pub(crate) fn define_projection(
607 &mut self,
608 definition: ProjectionDefinition,
609 ) -> Result<ProjectionId, DbError> {
610 self.validate_projection_definition(&definition)?;
611 let id = self.next_projection;
612 self.next_projection = id.checked_next().ok_or(DbError::IdOverflow)?;
613 self.catalog.insert_projection(id, definition)?;
614 Ok(id)
615 }
616
617 pub(crate) fn define_index(
619 &mut self,
620 name: String,
621 definition: IndexDefinition,
622 ) -> Result<IndexId, DbError> {
623 self.validate_index_definition(&definition)?;
624 let id = self.next_index;
625 self.next_index = id.checked_next().ok_or(DbError::IdOverflow)?;
626 self.catalog.insert_index(id, name, definition)?;
627 Ok(id)
628 }
629
630 pub(crate) fn add_element_label(
632 &mut self,
633 element: ElementId,
634 label: LabelId,
635 ) -> Result<(), DbError> {
636 self.require_label(label)?;
637 let record = self
638 .elements
639 .get_mut(&element)
640 .ok_or(DbError::UnknownElement { id: element })?;
641 record.labels.insert(label);
642 Ok(())
643 }
644
645 pub(crate) fn add_relation_label(
647 &mut self,
648 relation: RelationId,
649 label: LabelId,
650 ) -> Result<(), DbError> {
651 self.require_label(label)?;
652 let record = self
653 .relations
654 .get_mut(&relation)
655 .ok_or(DbError::UnknownRelation { id: relation })?;
656 record.labels.insert(label);
657 Ok(())
658 }
659
660 pub(crate) fn set_relation_type(
662 &mut self,
663 relation: RelationId,
664 relation_type: RelationTypeId,
665 ) -> Result<(), DbError> {
666 self.require_relation_type(relation_type)?;
667 let record = self
668 .relations
669 .get_mut(&relation)
670 .ok_or(DbError::UnknownRelation { id: relation })?;
671 record.relation_type = Some(relation_type);
672 Ok(())
673 }
674
675 pub(crate) fn set_property(
677 &mut self,
678 subject: PropertySubject,
679 key: PropertyKeyId,
680 value: PropertyValue,
681 ) -> Result<(), DbError> {
682 self.require_subject(subject)?;
683 let definition = self
684 .catalog
685 .property_key(key)
686 .ok_or(DbError::UnknownPropertyKey { id: key })?;
687 if definition.family != subject.family() {
688 return Err(DbError::WrongPropertyFamily {
689 expected: definition.family,
690 actual: subject.family(),
691 });
692 }
693 if definition.value_type != value.value_type() {
694 return Err(DbError::PropertyTypeMismatch {
695 expected: definition.value_type,
696 actual: value.value_type(),
697 });
698 }
699 self.properties
700 .entry(subject)
701 .or_default()
702 .insert(key, value);
703 Ok(())
704 }
705
706 pub(crate) fn remove_property(
708 &mut self,
709 subject: PropertySubject,
710 key: PropertyKeyId,
711 ) -> Result<(), DbError> {
712 self.require_subject(subject)?;
713 self.require_property_key(key)?;
714 if let Some(values) = self.properties.get_mut(&subject) {
715 values.remove(&key);
716 if values.is_empty() {
717 self.properties.remove(&subject);
718 }
719 }
720 Ok(())
721 }
722
723 #[must_use]
725 pub(crate) fn property(
726 &self,
727 subject: PropertySubject,
728 key: PropertyKeyId,
729 ) -> Option<&PropertyValue> {
730 self.properties
731 .get(&subject)
732 .and_then(|values| values.get(&key))
733 }
734
735 pub(crate) fn property_equal(
737 &self,
738 key: PropertyKeyId,
739 value: &PropertyValue,
740 ) -> Vec<PropertySubject> {
741 self.properties
742 .iter()
743 .filter_map(|(subject, values)| (values.get(&key) == Some(value)).then_some(*subject))
744 .collect()
745 }
746
747 pub(crate) fn typed_property_equal(
749 &self,
750 key: PropertyKeyId,
751 value: &PropertyValue,
752 ) -> Result<Vec<PropertySubject>, DbError> {
753 self.validate_lookup_value(key, value)?;
754 Ok(self.property_equal(key, value))
755 }
756
757 pub(crate) fn typed_property_equal_for_family(
759 &self,
760 key: PropertyKeyId,
761 family: PropertyFamily,
762 value: &PropertyValue,
763 ) -> Result<Vec<PropertySubject>, DbError> {
764 self.validate_lookup_value_for_family(key, family, value)?;
765 Ok(self.property_equal(key, value))
766 }
767
768 pub(crate) fn property_range(
770 &self,
771 key: PropertyKeyId,
772 min: &PropertyValue,
773 max: &PropertyValue,
774 ) -> Vec<PropertySubject> {
775 self.properties
776 .iter()
777 .filter_map(|(subject, values)| {
778 let value = values.get(&key)?;
779 (value >= min && value <= max).then_some(*subject)
780 })
781 .collect()
782 }
783
784 pub(crate) fn typed_property_range(
786 &self,
787 key: PropertyKeyId,
788 min: &PropertyValue,
789 max: &PropertyValue,
790 ) -> Result<Vec<PropertySubject>, DbError> {
791 self.validate_lookup_value(key, min)?;
792 self.validate_lookup_value(key, max)?;
793 if min > max {
794 return Ok(Vec::new());
795 }
796 Ok(self.property_range(key, min, max))
797 }
798
799 pub(crate) fn typed_property_composite_equal(
801 &self,
802 keys: &[PropertyKeyId],
803 values: &[PropertyValue],
804 ) -> Result<Vec<PropertySubject>, DbError> {
805 if keys.len() != values.len() {
806 return Err(DbError::unsupported(
807 "composite equality tuple arity mismatch",
808 ));
809 }
810 for (key, value) in keys.iter().copied().zip(values) {
811 self.validate_lookup_value(key, value)?;
812 }
813 Ok(self
814 .properties
815 .iter()
816 .filter_map(|(subject, property_values)| {
817 keys.iter()
818 .copied()
819 .zip(values)
820 .all(|(key, value)| property_values.get(&key) == Some(value))
821 .then_some(*subject)
822 })
823 .collect())
824 }
825
826 pub(crate) fn elements_with_label(&self, label: LabelId) -> Vec<ElementId> {
828 self.label_members
829 .get(&label)
830 .map(|members| members.iter().copied().collect())
831 .unwrap_or_default()
832 }
833
834 pub(crate) fn relations_with_type(&self, relation_type: RelationTypeId) -> Vec<RelationId> {
836 self.relation_type_members
837 .get(&relation_type)
838 .map(|members| members.iter().copied().collect())
839 .unwrap_or_default()
840 }
841
842 pub(crate) fn validate(&self) -> Result<(), DbError> {
844 for record in self.incidences.values() {
845 self.require_relation(record.relation)?;
846 self.require_element(record.element)?;
847 self.require_role(record.role)?;
848 }
849 for record in self.elements.values() {
850 self.require_labels(&record.labels)?;
851 }
852 for record in self.relations.values() {
853 self.require_labels(&record.labels)?;
854 if let Some(relation_type) = record.relation_type {
855 self.require_relation_type(relation_type)?;
856 }
857 }
858 self.validate_properties()?;
859 self.validate_catalog_definitions()
860 }
861
862 fn require_element(&self, id: ElementId) -> Result<(), DbError> {
864 self.elements
865 .contains_key(&id)
866 .then_some(())
867 .ok_or(DbError::UnknownElement { id })
868 }
869
870 fn require_relation(&self, id: RelationId) -> Result<(), DbError> {
872 self.relations
873 .contains_key(&id)
874 .then_some(())
875 .ok_or(DbError::UnknownRelation { id })
876 }
877
878 fn require_incidence(&self, id: IncidenceId) -> Result<(), DbError> {
880 self.incidences
881 .contains_key(&id)
882 .then_some(())
883 .ok_or(DbError::UnknownIncidence { id })
884 }
885
886 fn require_role(&self, id: RoleId) -> Result<(), DbError> {
888 self.catalog
889 .role(id)
890 .is_some()
891 .then_some(())
892 .ok_or(DbError::UnknownRole { id })
893 }
894
895 fn require_label(&self, id: LabelId) -> Result<(), DbError> {
897 self.catalog
898 .label(id)
899 .is_some()
900 .then_some(())
901 .ok_or(DbError::UnknownLabel { id })
902 }
903
904 fn require_relation_type(&self, id: RelationTypeId) -> Result<(), DbError> {
906 self.catalog
907 .relation_type(id)
908 .is_some()
909 .then_some(())
910 .ok_or(DbError::UnknownRelationType { id })
911 }
912
913 fn require_property_key(&self, id: PropertyKeyId) -> Result<(), DbError> {
915 self.catalog
916 .property_key(id)
917 .is_some()
918 .then_some(())
919 .ok_or(DbError::UnknownPropertyKey { id })
920 }
921
922 fn require_subject(&self, subject: PropertySubject) -> Result<(), DbError> {
924 match subject {
925 PropertySubject::Element(id) => self.require_element(id),
926 PropertySubject::Relation(id) => self.require_relation(id),
927 PropertySubject::Incidence(id) => self.require_incidence(id),
928 }
929 }
930
931 fn require_labels(&self, labels: &BTreeSet<LabelId>) -> Result<(), DbError> {
933 for label in labels {
934 self.require_label(*label)?;
935 }
936 Ok(())
937 }
938
939 fn remove_incidences(&mut self, mut should_remove: impl FnMut(&IncidenceRecord) -> bool) {
941 let removed: Vec<_> = self
942 .incidences
943 .values()
944 .filter_map(|record| should_remove(record).then_some(record.id))
945 .collect();
946 for id in removed {
947 self.incidences.remove(&id);
948 self.properties.remove(&PropertySubject::Incidence(id));
949 }
950 }
951
952 fn validate_projection_definition(
954 &self,
955 definition: &ProjectionDefinition,
956 ) -> Result<(), DbError> {
957 match definition {
958 ProjectionDefinition::Graph(graph) => {
959 self.require_role(graph.source_role)?;
960 self.require_role(graph.target_role)?;
961 self.require_relation_types(&graph.relation_types)
962 }
963 ProjectionDefinition::Hypergraph(hypergraph) => {
964 self.require_roles(&hypergraph.source_roles)?;
965 self.require_roles(&hypergraph.target_roles)?;
966 self.require_relation_types(&hypergraph.relation_types)
967 }
968 }
969 }
970
971 fn validate_index_definition(&self, definition: &IndexDefinition) -> Result<(), DbError> {
973 match definition {
974 IndexDefinition::Label { label } => self.require_label(*label),
975 IndexDefinition::RelationType { relation_type } => {
976 self.require_relation_type(*relation_type)
977 }
978 IndexDefinition::PropertyEquality { key } | IndexDefinition::PropertyRange { key } => {
979 self.require_property_key(*key)
980 }
981 IndexDefinition::CompositeEquality { keys } => {
982 if keys.is_empty() {
983 return Err(DbError::unsupported(
984 "composite equality index requires at least one key",
985 ));
986 }
987 for key in keys {
988 self.require_property_key(*key)?;
989 }
990 Ok(())
991 }
992 IndexDefinition::Projection { projection } => self
993 .catalog
994 .projection(*projection)
995 .is_some()
996 .then_some(())
997 .ok_or(DbError::UnknownProjection { id: *projection }),
998 }
999 }
1000
1001 fn require_roles(&self, roles: &BTreeSet<RoleId>) -> Result<(), DbError> {
1003 for role in roles {
1004 self.require_role(*role)?;
1005 }
1006 Ok(())
1007 }
1008
1009 fn require_relation_types(
1011 &self,
1012 relation_types: &BTreeSet<RelationTypeId>,
1013 ) -> Result<(), DbError> {
1014 for relation_type in relation_types {
1015 self.require_relation_type(*relation_type)?;
1016 }
1017 Ok(())
1018 }
1019
1020 fn validate_properties(&self) -> Result<(), DbError> {
1022 for (subject, values) in &self.properties {
1023 self.require_subject(*subject)?;
1024 for (key, value) in values {
1025 self.validate_property_value(*subject, *key, value)?;
1026 }
1027 }
1028 Ok(())
1029 }
1030
1031 fn validate_lookup_value(
1033 &self,
1034 key: PropertyKeyId,
1035 value: &PropertyValue,
1036 ) -> Result<(), DbError> {
1037 let definition = self
1038 .catalog
1039 .property_key(key)
1040 .ok_or(DbError::UnknownPropertyKey { id: key })?;
1041 let actual = value.value_type();
1042 if definition.value_type != actual {
1043 return Err(DbError::PropertyTypeMismatch {
1044 expected: definition.value_type,
1045 actual,
1046 });
1047 }
1048 Ok(())
1049 }
1050
1051 pub(crate) fn validate_lookup_value_for_family(
1053 &self,
1054 key: PropertyKeyId,
1055 family: PropertyFamily,
1056 value: &PropertyValue,
1057 ) -> Result<(), DbError> {
1058 let definition = self
1059 .catalog
1060 .property_key(key)
1061 .ok_or(DbError::UnknownPropertyKey { id: key })?;
1062 if definition.family != family {
1063 return Err(DbError::WrongPropertyFamily {
1064 expected: definition.family,
1065 actual: family,
1066 });
1067 }
1068 if definition.value_type != value.value_type() {
1069 return Err(DbError::PropertyTypeMismatch {
1070 expected: definition.value_type,
1071 actual: value.value_type(),
1072 });
1073 }
1074 Ok(())
1075 }
1076
1077 fn validate_property_value(
1079 &self,
1080 subject: PropertySubject,
1081 key: PropertyKeyId,
1082 value: &PropertyValue,
1083 ) -> Result<(), DbError> {
1084 let definition = self
1085 .catalog
1086 .property_key(key)
1087 .ok_or(DbError::UnknownPropertyKey { id: key })?;
1088 if definition.family != subject.family() {
1089 return Err(DbError::WrongPropertyFamily {
1090 expected: definition.family,
1091 actual: subject.family(),
1092 });
1093 }
1094 if definition.value_type != value.value_type() {
1095 return Err(DbError::PropertyTypeMismatch {
1096 expected: definition.value_type,
1097 actual: value.value_type(),
1098 });
1099 }
1100 Ok(())
1101 }
1102
1103 fn validate_catalog_definitions(&self) -> Result<(), DbError> {
1105 for entry in self.catalog.projections() {
1106 self.validate_projection_definition(&entry.definition)?;
1107 }
1108 for entry in self.catalog.indexes() {
1109 self.validate_index_definition(&entry.definition)?;
1110 }
1111 Ok(())
1112 }
1113}