hydrate_data/
schema_set.rs

1use crate::value::ValueEnum;
2use crate::{
3    DataSetError, DataSetResult, HashMap, SchemaFingerprint, SchemaLinker, SchemaLinkerResult,
4    SchemaNamedType, Value,
5};
6use std::sync::Arc;
7use uuid::Uuid;
8
9/// Accumulates linked types and can be used to create a schema. This allows validation of types
10/// and some work that can be pre-cached, such as generating default values for enums. (Values
11/// are not a concept that exists in the hydrate-schema crate)
12#[derive(Default)]
13pub struct SchemaSetBuilder {
14    schemas_by_type_uuid: HashMap<Uuid, SchemaFingerprint>,
15    schemas_by_name: HashMap<String, SchemaFingerprint>,
16    schemas: HashMap<SchemaFingerprint, SchemaNamedType>,
17    default_enum_values: HashMap<SchemaFingerprint, Value>,
18}
19
20impl SchemaSetBuilder {
21    pub fn build(self) -> SchemaSet {
22        let inner = SchemaSetInner {
23            schemas_by_type_uuid: self.schemas_by_type_uuid,
24            schemas_by_name: self.schemas_by_name,
25            schemas: self.schemas,
26            default_enum_values: self.default_enum_values,
27        };
28
29        SchemaSet {
30            inner: Arc::new(inner),
31        }
32    }
33
34    pub fn add_linked_types(
35        &mut self,
36        linker: SchemaLinker,
37    ) -> SchemaLinkerResult<()> {
38        let linked = linker.link_schemas()?;
39
40        //TODO: check no name collisions and merge with DB
41
42        for (k, v) in linked.schemas {
43            if let Some(enum_schema) = v.try_as_enum() {
44                let default_value = Value::Enum(ValueEnum::new(
45                    enum_schema.default_value().name().to_string(),
46                ));
47                let old = self.default_enum_values.insert(k, default_value.clone());
48                if let Some(old) = old {
49                    assert_eq!(old.as_enum().unwrap(), default_value.as_enum().unwrap());
50                }
51            }
52            let v_fingerprint = v.fingerprint();
53            let old = self.schemas.insert(k, v);
54            if let Some(old) = old {
55                assert_eq!(old.fingerprint(), v_fingerprint);
56            }
57        }
58
59        for (k, v) in linked.schemas_by_name {
60            let old = self.schemas_by_name.insert(k, v);
61            assert!(old.is_none());
62        }
63
64        for (k, v) in linked.schemas_by_type_uuid {
65            let old = self.schemas_by_type_uuid.insert(k, v);
66            assert!(old.is_none());
67        }
68
69        Ok(())
70    }
71
72    pub fn restore_named_types(
73        &mut self,
74        named_types: Vec<SchemaNamedType>,
75    ) {
76        for named_type in named_types {
77            self.schemas.insert(named_type.fingerprint(), named_type);
78        }
79    }
80}
81
82pub struct SchemaSetInner {
83    schemas_by_type_uuid: HashMap<Uuid, SchemaFingerprint>,
84    schemas_by_name: HashMap<String, SchemaFingerprint>,
85    schemas: HashMap<SchemaFingerprint, SchemaNamedType>,
86    default_enum_values: HashMap<SchemaFingerprint, Value>,
87}
88
89#[derive(Clone)]
90pub struct SchemaSet {
91    inner: Arc<SchemaSetInner>,
92}
93
94impl SchemaSet {
95    pub fn schemas(&self) -> &HashMap<SchemaFingerprint, SchemaNamedType> {
96        &self.inner.schemas
97    }
98
99    pub fn schemas_by_type_uuid(&self) -> &HashMap<Uuid, SchemaFingerprint> {
100        &self.inner.schemas_by_type_uuid
101    }
102
103    pub fn default_value_for_enum(
104        &self,
105        fingerprint: SchemaFingerprint,
106    ) -> Option<&Value> {
107        self.inner.default_enum_values.get(&fingerprint)
108    }
109
110    pub fn find_named_type_by_type_uuid(
111        &self,
112        type_uuid: Uuid,
113    ) -> DataSetResult<&SchemaNamedType> {
114        Ok(self
115            .try_find_named_type_by_type_uuid(type_uuid)
116            .ok_or(DataSetError::SchemaNotFound)?)
117    }
118
119    pub fn try_find_named_type_by_type_uuid(
120        &self,
121        type_uuid: Uuid,
122    ) -> Option<&SchemaNamedType> {
123        self.inner
124            .schemas_by_type_uuid
125            .get(&type_uuid)
126            .map(|fingerprint| self.find_named_type_by_fingerprint(*fingerprint))
127            .flatten()
128    }
129
130    pub fn find_named_type(
131        &self,
132        name: impl AsRef<str>,
133    ) -> DataSetResult<&SchemaNamedType> {
134        Ok(self
135            .try_find_named_type(name)
136            .ok_or(DataSetError::SchemaNotFound)?)
137    }
138
139    pub fn try_find_named_type(
140        &self,
141        name: impl AsRef<str>,
142    ) -> Option<&SchemaNamedType> {
143        self.inner
144            .schemas_by_name
145            .get(name.as_ref())
146            .map(|fingerprint| self.find_named_type_by_fingerprint(*fingerprint))
147            .flatten()
148    }
149
150    pub fn find_named_type_by_fingerprint(
151        &self,
152        fingerprint: SchemaFingerprint,
153    ) -> Option<&SchemaNamedType> {
154        self.inner.schemas.get(&fingerprint)
155    }
156}