use crate::{
error::{Error, Result},
types::{TypeDesc, parse_type_desc},
value::Value,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Field {
pub name: String,
pub ty: TypeDesc,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Schema {
fields: Vec<Field>,
}
impl Schema {
#[must_use]
pub fn new(fields: Vec<Field>) -> Self {
Self { fields }
}
#[must_use]
pub fn fields(&self) -> &[Field] {
&self.fields
}
#[must_use]
pub fn len(&self) -> usize {
self.fields.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
pub fn from_names_and_types<I, S>(pairs: I) -> Self
where
I: IntoIterator<Item = (S, TypeDesc)>,
S: Into<String>,
{
let fields = pairs
.into_iter()
.map(|(name, ty)| Field {
name: name.into(),
ty,
})
.collect();
Self { fields }
}
pub fn from_type_strings(pairs: &[(&str, &str)]) -> Result<Self> {
let mut fields = Vec::with_capacity(pairs.len());
for (name, ty) in pairs {
fields.push(Field {
name: (*name).to_string(),
ty: parse_type_desc(ty)?,
});
}
Ok(Self { fields })
}
}
pub type Row = Vec<Value>;
pub(crate) fn expand_schema_for_writing(schema: &Schema) -> Schema {
let mut fields = Vec::new();
for field in &schema.fields {
match &field.ty {
TypeDesc::Nested(items) => {
for item in items {
let name = item.name.as_deref().unwrap_or("");
fields.push(Field {
name: format!("{}.{}", field.name, name),
ty: TypeDesc::Array(Box::new(item.ty.clone())),
});
}
}
_ => fields.push(field.clone()),
}
}
Schema::new(fields)
}
pub(crate) fn ensure_nested_names(schema: &Schema) -> Result<()> {
for field in &schema.fields {
if let TypeDesc::Nested(items) = &field.ty {
for item in items {
if item.name.as_deref().unwrap_or("").is_empty() {
return Err(Error::InvalidValue(
"Nested fields must have names when writing",
));
}
}
}
}
Ok(())
}