Skip to main content

graphrecords_core/errors/
schema.rs

1use crate::graphrecord::{EdgeIndex, GraphRecordAttribute, Group, NodeIndex, datatypes::DataType};
2use std::{
3    error::Error,
4    fmt::{Display, Formatter, Result as FmtResult},
5};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum SchemaError {
9    GroupNotInSchema {
10        group: Group,
11    },
12    GroupAlreadyInSchema {
13        group: Group,
14    },
15    NodeAttributeMissing {
16        node_index: NodeIndex,
17        attribute: GraphRecordAttribute,
18        data_type: DataType,
19    },
20    EdgeAttributeMissing {
21        edge_index: EdgeIndex,
22        attribute: GraphRecordAttribute,
23        data_type: DataType,
24    },
25    NodeAttributeDataTypeMismatch {
26        node_index: NodeIndex,
27        attribute: GraphRecordAttribute,
28        data_type: DataType,
29        expected_data_type: DataType,
30    },
31    EdgeAttributeDataTypeMismatch {
32        edge_index: EdgeIndex,
33        attribute: GraphRecordAttribute,
34        data_type: DataType,
35        expected_data_type: DataType,
36    },
37    NodeAttributesNotInSchema {
38        node_index: NodeIndex,
39        attributes: Vec<GraphRecordAttribute>,
40    },
41    EdgeAttributesNotInSchema {
42        edge_index: EdgeIndex,
43        attributes: Vec<GraphRecordAttribute>,
44    },
45    ContinuousAttributeNotNumeric,
46    TemporalAttributeNotTemporal,
47}
48
49impl Error for SchemaError {}
50
51fn join_attributes(attributes: &[GraphRecordAttribute]) -> String {
52    attributes
53        .iter()
54        .map(ToString::to_string)
55        .collect::<Vec<_>>()
56        .join(", ")
57}
58
59impl Display for SchemaError {
60    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
61        match self {
62            Self::GroupNotInSchema { group } => {
63                write!(f, "Group `{group}` is not defined in the schema")
64            }
65            Self::GroupAlreadyInSchema { group } => {
66                write!(f, "Group `{group}` already exists in the schema")
67            }
68            Self::NodeAttributeMissing {
69                node_index,
70                attribute,
71                data_type,
72            } => write!(
73                f,
74                "Attribute `{attribute}` of type `{data_type}` not found on node with index `{node_index}`"
75            ),
76            Self::EdgeAttributeMissing {
77                edge_index,
78                attribute,
79                data_type,
80            } => write!(
81                f,
82                "Attribute `{attribute}` of type `{data_type}` not found on edge with index `{edge_index}`"
83            ),
84            Self::NodeAttributeDataTypeMismatch {
85                node_index,
86                attribute,
87                data_type,
88                expected_data_type,
89            } => write!(
90                f,
91                "Attribute `{attribute}` of node with index `{node_index}` is of type `{data_type}`. Expected `{expected_data_type}`."
92            ),
93            Self::EdgeAttributeDataTypeMismatch {
94                edge_index,
95                attribute,
96                data_type,
97                expected_data_type,
98            } => write!(
99                f,
100                "Attribute `{attribute}` of edge with index `{edge_index}` is of type `{data_type}`. Expected `{expected_data_type}`."
101            ),
102            Self::NodeAttributesNotInSchema {
103                node_index,
104                attributes,
105            } => write!(
106                f,
107                "Attributes [{}] of node with index `{node_index}` do not exist in schema.",
108                join_attributes(attributes)
109            ),
110            Self::EdgeAttributesNotInSchema {
111                edge_index,
112                attributes,
113            } => write!(
114                f,
115                "Attributes [{}] of edge with index `{edge_index}` do not exist in schema.",
116                join_attributes(attributes)
117            ),
118            Self::ContinuousAttributeNotNumeric => {
119                write!(
120                    f,
121                    "Continuous attribute must be of (sub-)type `Int` or `Float`."
122                )
123            }
124            Self::TemporalAttributeNotTemporal => {
125                write!(
126                    f,
127                    "Temporal attribute must be of (sub-)type `DateTime` or `Duration`."
128                )
129            }
130        }
131    }
132}
133
134#[cfg(test)]
135mod test {
136    use super::SchemaError;
137    use crate::graphrecord::datatypes::DataType;
138
139    #[test]
140    fn test_display_groups() {
141        assert_eq!(
142            "Group `\"test\"` is not defined in the schema",
143            SchemaError::GroupNotInSchema {
144                group: "test".into()
145            }
146            .to_string()
147        );
148        assert_eq!(
149            "Group `\"test\"` already exists in the schema",
150            SchemaError::GroupAlreadyInSchema {
151                group: "test".into()
152            }
153            .to_string()
154        );
155    }
156
157    #[test]
158    fn test_display_attributes() {
159        assert_eq!(
160            "Attribute `\"key\"` of type `Int` not found on node with index `\"0\"`",
161            SchemaError::NodeAttributeMissing {
162                node_index: "0".into(),
163                attribute: "key".into(),
164                data_type: DataType::Int,
165            }
166            .to_string()
167        );
168        assert_eq!(
169            "Attribute `\"key\"` of type `Int` not found on edge with index `0`",
170            SchemaError::EdgeAttributeMissing {
171                edge_index: 0,
172                attribute: "key".into(),
173                data_type: DataType::Int,
174            }
175            .to_string()
176        );
177        assert_eq!(
178            "Attribute `\"key\"` of node with index `\"0\"` is of type `Int`. Expected `Float`.",
179            SchemaError::NodeAttributeDataTypeMismatch {
180                node_index: "0".into(),
181                attribute: "key".into(),
182                data_type: DataType::Int,
183                expected_data_type: DataType::Float,
184            }
185            .to_string()
186        );
187        assert_eq!(
188            "Attribute `\"key\"` of edge with index `0` is of type `Int`. Expected `Float`.",
189            SchemaError::EdgeAttributeDataTypeMismatch {
190                edge_index: 0,
191                attribute: "key".into(),
192                data_type: DataType::Int,
193                expected_data_type: DataType::Float,
194            }
195            .to_string()
196        );
197        assert_eq!(
198            "Attributes [\"key1\", \"key2\"] of node with index `\"0\"` do not exist in schema.",
199            SchemaError::NodeAttributesNotInSchema {
200                node_index: "0".into(),
201                attributes: vec!["key1".into(), "key2".into()],
202            }
203            .to_string()
204        );
205        assert_eq!(
206            "Attributes [\"key1\", \"key2\"] of edge with index `0` do not exist in schema.",
207            SchemaError::EdgeAttributesNotInSchema {
208                edge_index: 0,
209                attributes: vec!["key1".into(), "key2".into()],
210            }
211            .to_string()
212        );
213    }
214
215    #[test]
216    fn test_display_attribute_types() {
217        assert_eq!(
218            "Continuous attribute must be of (sub-)type `Int` or `Float`.",
219            SchemaError::ContinuousAttributeNotNumeric.to_string()
220        );
221        assert_eq!(
222            "Temporal attribute must be of (sub-)type `DateTime` or `Duration`.",
223            SchemaError::TemporalAttributeNotTemporal.to_string()
224        );
225    }
226}