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 = "serde_btree_map_vec")]
95 elements: BTreeMap<ElementId, ElementRecord>,
96 #[serde(with = "serde_btree_map_vec")]
98 relations: BTreeMap<RelationId, RelationRecord>,
99 #[serde(with = "serde_btree_map_vec")]
101 incidences: BTreeMap<IncidenceId, IncidenceRecord>,
102 #[serde(with = "serde_properties_vec")]
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
127mod serde_btree_map_vec {
129 pub(super) fn serialize<S, K, V>(
131 map: &std::collections::BTreeMap<K, V>,
132 serializer: S,
133 ) -> Result<S::Ok, S::Error>
134 where
135 S: serde::Serializer,
136 K: serde::Serialize,
137 V: serde::Serialize,
138 {
139 serde::Serialize::serialize(&map.iter().collect::<Vec<_>>(), serializer)
140 }
141
142 pub(super) fn deserialize<'de, D, K, V>(
144 deserializer: D,
145 ) -> Result<std::collections::BTreeMap<K, V>, D::Error>
146 where
147 D: serde::Deserializer<'de>,
148 K: Ord + serde::de::DeserializeOwned,
149 V: serde::de::DeserializeOwned,
150 {
151 <Vec<(K, V)> as serde::Deserialize>::deserialize(deserializer)
152 .map(|entries| entries.into_iter().collect())
153 }
154}
155
156mod serde_properties_vec {
158 use super::{PropertyKeyId, PropertySubject, PropertyValue};
159
160 type PropertyEntries = Vec<(PropertySubject, Vec<(PropertyKeyId, PropertyValue)>)>;
162 type PropertyValueMap = std::collections::BTreeMap<PropertyKeyId, PropertyValue>;
164 type PropertyMap = std::collections::BTreeMap<PropertySubject, PropertyValueMap>;
166
167 pub(super) fn serialize<S>(map: &PropertyMap, serializer: S) -> Result<S::Ok, S::Error>
169 where
170 S: serde::Serializer,
171 {
172 let entries = map
173 .iter()
174 .map(|(subject, values)| {
175 (
176 *subject,
177 values
178 .iter()
179 .map(|(key, value)| (*key, value.clone()))
180 .collect::<Vec<_>>(),
181 )
182 })
183 .collect::<Vec<_>>();
184 serde::Serialize::serialize(&entries, serializer)
185 }
186
187 pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<PropertyMap, D::Error>
189 where
190 D: serde::Deserializer<'de>,
191 {
192 <PropertyEntries as serde::Deserialize>::deserialize(deserializer).map(|entries| {
193 entries
194 .into_iter()
195 .map(|(subject, values)| (subject, values.into_iter().collect()))
196 .collect()
197 })
198 }
199}
200
201impl DatabaseState {
202 #[must_use]
208 pub(crate) const fn empty() -> Self {
209 Self {
210 elements: BTreeMap::new(),
211 relations: BTreeMap::new(),
212 incidences: BTreeMap::new(),
213 properties: BTreeMap::new(),
214 catalog: Catalog::empty(),
215 next_element: ElementId::new(1),
216 next_relation: RelationId::new(1),
217 next_incidence: IncidenceId::new(1),
218 next_role: RoleId::new(1),
219 next_label: LabelId::new(1),
220 next_relation_type: RelationTypeId::new(1),
221 next_property_key: PropertyKeyId::new(1),
222 next_projection: ProjectionId::new(1),
223 next_index: IndexId::new(1),
224 }
225 }
226
227 #[must_use]
233 pub(crate) const fn catalog(&self) -> &Catalog {
234 &self.catalog
235 }
236
237 #[must_use]
243 pub(crate) fn contains_element(&self, id: ElementId) -> bool {
244 self.elements.contains_key(&id)
245 }
246
247 #[must_use]
253 pub(crate) fn contains_relation(&self, id: RelationId) -> bool {
254 self.relations.contains_key(&id)
255 }
256
257 #[must_use]
263 pub(crate) fn contains_incidence(&self, id: IncidenceId) -> bool {
264 self.incidences.contains_key(&id)
265 }
266
267 #[must_use]
273 pub(crate) fn element_count(&self) -> usize {
274 self.elements.len()
275 }
276
277 #[must_use]
283 pub(crate) fn relation_count(&self) -> usize {
284 self.relations.len()
285 }
286
287 #[must_use]
293 pub(crate) fn incidence_count(&self) -> usize {
294 self.incidences.len()
295 }
296
297 pub(crate) fn elements(&self) -> impl Iterator<Item = &ElementRecord> {
303 self.elements.values()
304 }
305
306 pub(crate) fn relations(&self) -> impl Iterator<Item = &RelationRecord> {
312 self.relations.values()
313 }
314
315 pub(crate) fn incidences(&self) -> impl Iterator<Item = &IncidenceRecord> {
321 self.incidences.values()
322 }
323
324 #[must_use]
330 pub(crate) fn element(&self, id: ElementId) -> Option<&ElementRecord> {
331 self.elements.get(&id)
332 }
333
334 #[must_use]
340 pub(crate) fn relation(&self, id: RelationId) -> Option<&RelationRecord> {
341 self.relations.get(&id)
342 }
343
344 #[must_use]
350 pub(crate) fn incidence(&self, id: IncidenceId) -> Option<&IncidenceRecord> {
351 self.incidences.get(&id)
352 }
353
354 pub(crate) fn relation_incidences(
360 &self,
361 id: RelationId,
362 ) -> impl Iterator<Item = &IncidenceRecord> {
363 self.incidences
364 .values()
365 .filter(move |record| record.relation == id)
366 }
367
368 pub(crate) fn element_incidences(
374 &self,
375 id: ElementId,
376 ) -> impl Iterator<Item = &IncidenceRecord> {
377 self.incidences
378 .values()
379 .filter(move |record| record.element == id)
380 }
381
382 pub(crate) fn create_element(&mut self) -> Result<ElementId, DbError> {
384 let id = self.next_element;
385 self.next_element = id.checked_next().ok_or(DbError::IdOverflow)?;
386 let previous = self.elements.insert(
387 id,
388 ElementRecord {
389 id,
390 labels: BTreeSet::new(),
391 },
392 );
393 if previous.is_some() {
394 return Err(DbError::DuplicateId);
395 }
396 Ok(id)
397 }
398
399 pub(crate) fn create_relation(&mut self) -> Result<RelationId, DbError> {
401 let id = self.next_relation;
402 self.next_relation = id.checked_next().ok_or(DbError::IdOverflow)?;
403 let previous = self.relations.insert(
404 id,
405 RelationRecord {
406 id,
407 relation_type: None,
408 labels: BTreeSet::new(),
409 },
410 );
411 if previous.is_some() {
412 return Err(DbError::DuplicateId);
413 }
414 Ok(id)
415 }
416
417 pub(crate) fn create_incidence(
419 &mut self,
420 relation: RelationId,
421 element: ElementId,
422 role: RoleId,
423 ) -> Result<IncidenceId, DbError> {
424 self.require_relation(relation)?;
425 self.require_element(element)?;
426 self.require_role(role)?;
427 let id = self.next_incidence;
428 self.next_incidence = id.checked_next().ok_or(DbError::IdOverflow)?;
429 let previous = self.incidences.insert(
430 id,
431 IncidenceRecord {
432 id,
433 relation,
434 element,
435 role,
436 },
437 );
438 if previous.is_some() {
439 return Err(DbError::DuplicateId);
440 }
441 Ok(id)
442 }
443
444 pub(crate) fn tombstone_element(&mut self, id: ElementId) -> Result<(), DbError> {
446 self.elements
447 .remove(&id)
448 .ok_or(DbError::UnknownElement { id })?;
449 self.properties.remove(&PropertySubject::Element(id));
450 self.remove_incidences(|record| record.element == id);
451 Ok(())
452 }
453
454 pub(crate) fn tombstone_relation(&mut self, id: RelationId) -> Result<(), DbError> {
456 self.relations
457 .remove(&id)
458 .ok_or(DbError::UnknownRelation { id })?;
459 self.properties.remove(&PropertySubject::Relation(id));
460 self.remove_incidences(|record| record.relation == id);
461 Ok(())
462 }
463
464 pub(crate) fn tombstone_incidence(&mut self, id: IncidenceId) -> Result<(), DbError> {
466 self.incidences
467 .remove(&id)
468 .ok_or(DbError::UnknownIncidence { id })?;
469 self.properties.remove(&PropertySubject::Incidence(id));
470 Ok(())
471 }
472
473 pub(crate) fn register_role(&mut self, name: String) -> Result<RoleId, DbError> {
475 let id = self.next_role;
476 self.next_role = id.checked_next().ok_or(DbError::IdOverflow)?;
477 self.catalog.insert_role(id, name)?;
478 Ok(id)
479 }
480
481 pub(crate) fn register_label(&mut self, name: String) -> Result<LabelId, DbError> {
483 let id = self.next_label;
484 self.next_label = id.checked_next().ok_or(DbError::IdOverflow)?;
485 self.catalog.insert_label(id, name)?;
486 Ok(id)
487 }
488
489 pub(crate) fn register_relation_type(
491 &mut self,
492 name: String,
493 ) -> Result<RelationTypeId, DbError> {
494 let id = self.next_relation_type;
495 self.next_relation_type = id.checked_next().ok_or(DbError::IdOverflow)?;
496 self.catalog.insert_relation_type(id, name)?;
497 Ok(id)
498 }
499
500 pub(crate) fn register_property_key(
502 &mut self,
503 name: String,
504 family: PropertyFamily,
505 value_type: crate::PropertyType,
506 ) -> Result<PropertyKeyId, DbError> {
507 let id = self.next_property_key;
508 self.next_property_key = id.checked_next().ok_or(DbError::IdOverflow)?;
509 self.catalog.insert_property_key(PropertyKeyDefinition {
510 id,
511 name,
512 family,
513 value_type,
514 })?;
515 Ok(id)
516 }
517
518 pub(crate) fn define_projection(
520 &mut self,
521 definition: ProjectionDefinition,
522 ) -> Result<ProjectionId, DbError> {
523 self.validate_projection_definition(&definition)?;
524 let id = self.next_projection;
525 self.next_projection = id.checked_next().ok_or(DbError::IdOverflow)?;
526 self.catalog.insert_projection(id, definition)?;
527 Ok(id)
528 }
529
530 pub(crate) fn define_index(
532 &mut self,
533 name: String,
534 definition: IndexDefinition,
535 ) -> Result<IndexId, DbError> {
536 self.validate_index_definition(&definition)?;
537 let id = self.next_index;
538 self.next_index = id.checked_next().ok_or(DbError::IdOverflow)?;
539 self.catalog.insert_index(id, name, definition)?;
540 Ok(id)
541 }
542
543 pub(crate) fn add_element_label(
545 &mut self,
546 element: ElementId,
547 label: LabelId,
548 ) -> Result<(), DbError> {
549 self.require_label(label)?;
550 let record = self
551 .elements
552 .get_mut(&element)
553 .ok_or(DbError::UnknownElement { id: element })?;
554 record.labels.insert(label);
555 Ok(())
556 }
557
558 pub(crate) fn add_relation_label(
560 &mut self,
561 relation: RelationId,
562 label: LabelId,
563 ) -> Result<(), DbError> {
564 self.require_label(label)?;
565 let record = self
566 .relations
567 .get_mut(&relation)
568 .ok_or(DbError::UnknownRelation { id: relation })?;
569 record.labels.insert(label);
570 Ok(())
571 }
572
573 pub(crate) fn set_relation_type(
575 &mut self,
576 relation: RelationId,
577 relation_type: RelationTypeId,
578 ) -> Result<(), DbError> {
579 self.require_relation_type(relation_type)?;
580 let record = self
581 .relations
582 .get_mut(&relation)
583 .ok_or(DbError::UnknownRelation { id: relation })?;
584 record.relation_type = Some(relation_type);
585 Ok(())
586 }
587
588 pub(crate) fn set_property(
590 &mut self,
591 subject: PropertySubject,
592 key: PropertyKeyId,
593 value: PropertyValue,
594 ) -> Result<(), DbError> {
595 self.require_subject(subject)?;
596 let definition = self
597 .catalog
598 .property_key(key)
599 .ok_or(DbError::UnknownPropertyKey { id: key })?;
600 if definition.family != subject.family() {
601 return Err(DbError::WrongPropertyFamily {
602 expected: definition.family,
603 actual: subject.family(),
604 });
605 }
606 if definition.value_type != value.value_type() {
607 return Err(DbError::PropertyTypeMismatch {
608 expected: definition.value_type,
609 actual: value.value_type(),
610 });
611 }
612 self.properties
613 .entry(subject)
614 .or_default()
615 .insert(key, value);
616 Ok(())
617 }
618
619 pub(crate) fn remove_property(
621 &mut self,
622 subject: PropertySubject,
623 key: PropertyKeyId,
624 ) -> Result<(), DbError> {
625 self.require_subject(subject)?;
626 self.require_property_key(key)?;
627 if let Some(values) = self.properties.get_mut(&subject) {
628 values.remove(&key);
629 if values.is_empty() {
630 self.properties.remove(&subject);
631 }
632 }
633 Ok(())
634 }
635
636 #[must_use]
638 pub(crate) fn property(
639 &self,
640 subject: PropertySubject,
641 key: PropertyKeyId,
642 ) -> Option<&PropertyValue> {
643 self.properties
644 .get(&subject)
645 .and_then(|values| values.get(&key))
646 }
647
648 pub(crate) fn property_equal(
650 &self,
651 key: PropertyKeyId,
652 value: &PropertyValue,
653 ) -> Vec<PropertySubject> {
654 self.properties
655 .iter()
656 .filter_map(|(subject, values)| (values.get(&key) == Some(value)).then_some(*subject))
657 .collect()
658 }
659
660 pub(crate) fn typed_property_equal(
662 &self,
663 key: PropertyKeyId,
664 value: &PropertyValue,
665 ) -> Result<Vec<PropertySubject>, DbError> {
666 self.validate_lookup_value(key, value)?;
667 Ok(self.property_equal(key, value))
668 }
669
670 pub(crate) fn typed_property_equal_for_family(
672 &self,
673 key: PropertyKeyId,
674 family: PropertyFamily,
675 value: &PropertyValue,
676 ) -> Result<Vec<PropertySubject>, DbError> {
677 self.validate_lookup_value_for_family(key, family, value)?;
678 Ok(self.property_equal(key, value))
679 }
680
681 pub(crate) fn property_range(
683 &self,
684 key: PropertyKeyId,
685 min: &PropertyValue,
686 max: &PropertyValue,
687 ) -> Vec<PropertySubject> {
688 self.properties
689 .iter()
690 .filter_map(|(subject, values)| {
691 let value = values.get(&key)?;
692 (value >= min && value <= max).then_some(*subject)
693 })
694 .collect()
695 }
696
697 pub(crate) fn typed_property_range(
699 &self,
700 key: PropertyKeyId,
701 min: &PropertyValue,
702 max: &PropertyValue,
703 ) -> Result<Vec<PropertySubject>, DbError> {
704 self.validate_lookup_value(key, min)?;
705 self.validate_lookup_value(key, max)?;
706 if min > max {
707 return Ok(Vec::new());
708 }
709 Ok(self.property_range(key, min, max))
710 }
711
712 pub(crate) fn typed_property_composite_equal(
714 &self,
715 keys: &[PropertyKeyId],
716 values: &[PropertyValue],
717 ) -> Result<Vec<PropertySubject>, DbError> {
718 if keys.len() != values.len() {
719 return Err(DbError::unsupported(
720 "composite equality tuple arity mismatch",
721 ));
722 }
723 for (key, value) in keys.iter().copied().zip(values) {
724 self.validate_lookup_value(key, value)?;
725 }
726 Ok(self
727 .properties
728 .iter()
729 .filter_map(|(subject, property_values)| {
730 keys.iter()
731 .copied()
732 .zip(values)
733 .all(|(key, value)| property_values.get(&key) == Some(value))
734 .then_some(*subject)
735 })
736 .collect())
737 }
738
739 pub(crate) fn elements_with_label(&self, label: LabelId) -> Vec<ElementId> {
741 self.elements
742 .values()
743 .filter_map(|record| record.labels.contains(&label).then_some(record.id))
744 .collect()
745 }
746
747 pub(crate) fn relations_with_type(&self, relation_type: RelationTypeId) -> Vec<RelationId> {
749 self.relations
750 .values()
751 .filter_map(|record| (record.relation_type == Some(relation_type)).then_some(record.id))
752 .collect()
753 }
754
755 pub(crate) fn validate(&self) -> Result<(), DbError> {
757 for record in self.incidences.values() {
758 self.require_relation(record.relation)?;
759 self.require_element(record.element)?;
760 self.require_role(record.role)?;
761 }
762 for record in self.elements.values() {
763 self.require_labels(&record.labels)?;
764 }
765 for record in self.relations.values() {
766 self.require_labels(&record.labels)?;
767 if let Some(relation_type) = record.relation_type {
768 self.require_relation_type(relation_type)?;
769 }
770 }
771 self.validate_properties()?;
772 self.validate_catalog_definitions()
773 }
774
775 fn require_element(&self, id: ElementId) -> Result<(), DbError> {
777 self.elements
778 .contains_key(&id)
779 .then_some(())
780 .ok_or(DbError::UnknownElement { id })
781 }
782
783 fn require_relation(&self, id: RelationId) -> Result<(), DbError> {
785 self.relations
786 .contains_key(&id)
787 .then_some(())
788 .ok_or(DbError::UnknownRelation { id })
789 }
790
791 fn require_incidence(&self, id: IncidenceId) -> Result<(), DbError> {
793 self.incidences
794 .contains_key(&id)
795 .then_some(())
796 .ok_or(DbError::UnknownIncidence { id })
797 }
798
799 fn require_role(&self, id: RoleId) -> Result<(), DbError> {
801 self.catalog
802 .role(id)
803 .is_some()
804 .then_some(())
805 .ok_or(DbError::UnknownRole { id })
806 }
807
808 fn require_label(&self, id: LabelId) -> Result<(), DbError> {
810 self.catalog
811 .label(id)
812 .is_some()
813 .then_some(())
814 .ok_or(DbError::UnknownLabel { id })
815 }
816
817 fn require_relation_type(&self, id: RelationTypeId) -> Result<(), DbError> {
819 self.catalog
820 .relation_type(id)
821 .is_some()
822 .then_some(())
823 .ok_or(DbError::UnknownRelationType { id })
824 }
825
826 fn require_property_key(&self, id: PropertyKeyId) -> Result<(), DbError> {
828 self.catalog
829 .property_key(id)
830 .is_some()
831 .then_some(())
832 .ok_or(DbError::UnknownPropertyKey { id })
833 }
834
835 fn require_subject(&self, subject: PropertySubject) -> Result<(), DbError> {
837 match subject {
838 PropertySubject::Element(id) => self.require_element(id),
839 PropertySubject::Relation(id) => self.require_relation(id),
840 PropertySubject::Incidence(id) => self.require_incidence(id),
841 }
842 }
843
844 fn require_labels(&self, labels: &BTreeSet<LabelId>) -> Result<(), DbError> {
846 for label in labels {
847 self.require_label(*label)?;
848 }
849 Ok(())
850 }
851
852 fn remove_incidences(&mut self, mut should_remove: impl FnMut(&IncidenceRecord) -> bool) {
854 let removed: Vec<_> = self
855 .incidences
856 .values()
857 .filter_map(|record| should_remove(record).then_some(record.id))
858 .collect();
859 for id in removed {
860 self.incidences.remove(&id);
861 self.properties.remove(&PropertySubject::Incidence(id));
862 }
863 }
864
865 fn validate_projection_definition(
867 &self,
868 definition: &ProjectionDefinition,
869 ) -> Result<(), DbError> {
870 match definition {
871 ProjectionDefinition::Graph(graph) => {
872 self.require_role(graph.source_role)?;
873 self.require_role(graph.target_role)?;
874 self.require_relation_types(&graph.relation_types)
875 }
876 ProjectionDefinition::Hypergraph(hypergraph) => {
877 self.require_roles(&hypergraph.source_roles)?;
878 self.require_roles(&hypergraph.target_roles)?;
879 self.require_relation_types(&hypergraph.relation_types)
880 }
881 }
882 }
883
884 fn validate_index_definition(&self, definition: &IndexDefinition) -> Result<(), DbError> {
886 match definition {
887 IndexDefinition::Label { label } => self.require_label(*label),
888 IndexDefinition::RelationType { relation_type } => {
889 self.require_relation_type(*relation_type)
890 }
891 IndexDefinition::PropertyEquality { key } | IndexDefinition::PropertyRange { key } => {
892 self.require_property_key(*key)
893 }
894 IndexDefinition::CompositeEquality { keys } => {
895 if keys.is_empty() {
896 return Err(DbError::unsupported(
897 "composite equality index requires at least one key",
898 ));
899 }
900 for key in keys {
901 self.require_property_key(*key)?;
902 }
903 Ok(())
904 }
905 IndexDefinition::Projection { projection } => self
906 .catalog
907 .projection(*projection)
908 .is_some()
909 .then_some(())
910 .ok_or(DbError::UnknownProjection { id: *projection }),
911 }
912 }
913
914 fn require_roles(&self, roles: &BTreeSet<RoleId>) -> Result<(), DbError> {
916 for role in roles {
917 self.require_role(*role)?;
918 }
919 Ok(())
920 }
921
922 fn require_relation_types(
924 &self,
925 relation_types: &BTreeSet<RelationTypeId>,
926 ) -> Result<(), DbError> {
927 for relation_type in relation_types {
928 self.require_relation_type(*relation_type)?;
929 }
930 Ok(())
931 }
932
933 fn validate_properties(&self) -> Result<(), DbError> {
935 for (subject, values) in &self.properties {
936 self.require_subject(*subject)?;
937 for (key, value) in values {
938 self.validate_property_value(*subject, *key, value)?;
939 }
940 }
941 Ok(())
942 }
943
944 fn validate_lookup_value(
946 &self,
947 key: PropertyKeyId,
948 value: &PropertyValue,
949 ) -> Result<(), DbError> {
950 let definition = self
951 .catalog
952 .property_key(key)
953 .ok_or(DbError::UnknownPropertyKey { id: key })?;
954 let actual = value.value_type();
955 if definition.value_type != actual {
956 return Err(DbError::PropertyTypeMismatch {
957 expected: definition.value_type,
958 actual,
959 });
960 }
961 Ok(())
962 }
963
964 pub(crate) fn validate_lookup_value_for_family(
966 &self,
967 key: PropertyKeyId,
968 family: PropertyFamily,
969 value: &PropertyValue,
970 ) -> Result<(), DbError> {
971 let definition = self
972 .catalog
973 .property_key(key)
974 .ok_or(DbError::UnknownPropertyKey { id: key })?;
975 if definition.family != family {
976 return Err(DbError::WrongPropertyFamily {
977 expected: definition.family,
978 actual: family,
979 });
980 }
981 if definition.value_type != value.value_type() {
982 return Err(DbError::PropertyTypeMismatch {
983 expected: definition.value_type,
984 actual: value.value_type(),
985 });
986 }
987 Ok(())
988 }
989
990 fn validate_property_value(
992 &self,
993 subject: PropertySubject,
994 key: PropertyKeyId,
995 value: &PropertyValue,
996 ) -> Result<(), DbError> {
997 let definition = self
998 .catalog
999 .property_key(key)
1000 .ok_or(DbError::UnknownPropertyKey { id: key })?;
1001 if definition.family != subject.family() {
1002 return Err(DbError::WrongPropertyFamily {
1003 expected: definition.family,
1004 actual: subject.family(),
1005 });
1006 }
1007 if definition.value_type != value.value_type() {
1008 return Err(DbError::PropertyTypeMismatch {
1009 expected: definition.value_type,
1010 actual: value.value_type(),
1011 });
1012 }
1013 Ok(())
1014 }
1015
1016 fn validate_catalog_definitions(&self) -> Result<(), DbError> {
1018 for entry in self.catalog.projections() {
1019 self.validate_projection_definition(&entry.definition)?;
1020 }
1021 for entry in self.catalog.indexes() {
1022 self.validate_index_definition(&entry.definition)?;
1023 }
1024 Ok(())
1025 }
1026}