use std::collections::btree_map::Iter;
use std::collections::BTreeMap;
use crate::schema::error::SchemaFieldError;
use crate::schema::validate::validate_field_name;
use crate::schema::FieldType;
use crate::Validate;
#[derive(Clone, Debug, PartialEq, Default, Eq)]
pub struct SchemaFields(BTreeMap<String, FieldType>);
impl SchemaFields {
pub fn new(fields: &[(&str, FieldType)]) -> Result<Self, SchemaFieldError> {
let mut keys: Vec<&str> = fields.iter().map(|(key, _)| *key).collect();
keys.dedup();
if keys.len() != fields.len() {
return Err(SchemaFieldError::DuplicateFields);
}
let mut schema_fields = BTreeMap::new();
for (key, value) in fields {
schema_fields.insert(key.to_string(), value.to_owned());
}
let schema_fields = Self(schema_fields);
schema_fields.validate()?;
Ok(schema_fields)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get(&self, name: &str) -> Option<&FieldType> {
if !self.0.contains_key(name) {
return None;
}
self.0.get(name)
}
pub fn keys(&self) -> Vec<String> {
self.0.keys().cloned().collect()
}
pub fn iter(&self) -> Iter<String, FieldType> {
self.0.iter()
}
}
impl Validate for SchemaFields {
type Error = SchemaFieldError;
fn validate(&self) -> Result<(), Self::Error> {
for name in self.keys() {
if !validate_field_name(&name) {
return Err(SchemaFieldError::MalformedSchemaFieldName);
}
}
if self.0.len() > 1024 {
return Err(SchemaFieldError::TooManyFields);
}
if self.is_empty() {
return Err(SchemaFieldError::ZeroFields);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use crate::schema::FieldType;
use super::SchemaFields;
#[rstest]
#[case(vec![("message", FieldType::String)])]
#[should_panic(expected = "Schema fields cannot contain duplicate field names")]
#[case(vec![("message", FieldType::String), ("message", FieldType::String)])]
#[should_panic(expected = "Schema fields must contain at least one entry")]
#[case(vec![])]
#[should_panic(expected = "Schema field found with invalid name")]
#[case(vec![("123", FieldType::String)])]
#[should_panic(expected = "Schema field found with invalid name")]
#[case(vec![("$$$", FieldType::String)])]
#[should_panic(expected = "Schema field found with invalid name")]
#[case(vec![("why spaces", FieldType::String)])]
#[should_panic(expected = "Schema field found with invalid name")]
#[case(vec![("a_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_long_name", FieldType::String)])]
fn validates_fields(#[case] fields: Vec<(&str, FieldType)>) {
SchemaFields::new(&fields)
.map_err(|err| err.to_string())
.unwrap();
}
#[test]
fn validates_when_too_many_fields() {
let keys: Vec<String> = (0..2000_u32).map(|key| format!("field_{key}")).collect();
let fields: Vec<(&str, FieldType)> = keys
.iter()
.map(|key| (key.as_str(), FieldType::String))
.collect();
let result = SchemaFields::new(&fields);
assert_eq!(
&result.unwrap_err().to_string(),
"Schema fields contains more than 1024 fields"
);
}
}