nodedb_array/schema/validation/
attrs.rs1use std::collections::HashSet;
13
14use crate::error::{ArrayError, ArrayResult};
15use crate::schema::attr_spec::AttrSpec;
16
17pub fn check(array: &str, attrs: &[AttrSpec]) -> ArrayResult<()> {
18 if attrs.is_empty() {
19 return Err(ArrayError::InvalidSchema {
20 array: array.to_string(),
21 detail: "at least one attribute is required".to_string(),
22 });
23 }
24 let mut seen = HashSet::with_capacity(attrs.len());
25 for a in attrs {
26 if !seen.insert(a.name.as_str()) {
27 return Err(ArrayError::InvalidAttr {
28 array: array.to_string(),
29 attr: a.name.clone(),
30 detail: "duplicate attribute name".to_string(),
31 });
32 }
33 }
34 Ok(())
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use crate::schema::attr_spec::AttrType;
41
42 #[test]
43 fn rejects_empty_attr_list() {
44 assert!(check("a", &[]).is_err());
45 }
46
47 #[test]
48 fn rejects_duplicate_attr_names() {
49 let attrs = vec![
50 AttrSpec::new("v", AttrType::Int64, false),
51 AttrSpec::new("v", AttrType::Int64, false),
52 ];
53 assert!(check("a", &attrs).is_err());
54 }
55
56 #[test]
57 fn accepts_well_formed_attrs() {
58 let attrs = vec![
59 AttrSpec::new("variant", AttrType::String, false),
60 AttrSpec::new("qual", AttrType::Float64, true),
61 ];
62 assert!(check("a", &attrs).is_ok());
63 }
64}