use std::collections::HashMap;
use std::sync::Arc;
use typed_builder::TypedBuilder;
use super::{FormatVersion, ManifestContentType, PartitionSpec, Schema};
use crate::error::Result;
use crate::spec::{PartitionField, SchemaId, SchemaRef};
use crate::{Error, ErrorKind};
#[derive(Debug, PartialEq, Clone, Eq, TypedBuilder)]
pub struct ManifestMetadata {
pub schema: SchemaRef,
pub schema_id: SchemaId,
pub partition_spec: PartitionSpec,
pub format_version: FormatVersion,
pub content: ManifestContentType,
}
impl ManifestMetadata {
pub fn parse(meta: &HashMap<String, Vec<u8>>) -> Result<Self> {
let schema = Arc::new({
let bs = meta.get("schema").ok_or_else(|| {
Error::new(
ErrorKind::DataInvalid,
"schema is required in manifest metadata but not found",
)
})?;
serde_json::from_slice::<Schema>(bs).map_err(|err| {
Error::new(
ErrorKind::DataInvalid,
"Fail to parse schema in manifest metadata",
)
.with_source(err)
})?
});
let schema_id: i32 = meta
.get("schema-id")
.map(|bs| {
String::from_utf8_lossy(bs).parse().map_err(|err| {
Error::new(
ErrorKind::DataInvalid,
"Fail to parse schema id in manifest metadata",
)
.with_source(err)
})
})
.transpose()?
.unwrap_or(0);
let partition_spec = {
let fields = {
let bs = meta.get("partition-spec").ok_or_else(|| {
Error::new(
ErrorKind::DataInvalid,
"partition-spec is required in manifest metadata but not found",
)
})?;
serde_json::from_slice::<Vec<PartitionField>>(bs).map_err(|err| {
Error::new(
ErrorKind::DataInvalid,
"Fail to parse partition spec in manifest metadata",
)
.with_source(err)
})?
};
let spec_id = meta
.get("partition-spec-id")
.map(|bs| {
String::from_utf8_lossy(bs).parse().map_err(|err| {
Error::new(
ErrorKind::DataInvalid,
"Fail to parse partition spec id in manifest metadata",
)
.with_source(err)
})
})
.transpose()?
.unwrap_or(0);
PartitionSpec::builder(schema.clone())
.with_spec_id(spec_id)
.add_unbound_fields(fields.into_iter().map(|f| f.into_unbound()))?
.build()?
};
let format_version = if let Some(bs) = meta.get("format-version") {
serde_json::from_slice::<FormatVersion>(bs).map_err(|err| {
Error::new(
ErrorKind::DataInvalid,
"Fail to parse format version in manifest metadata",
)
.with_source(err)
})?
} else {
FormatVersion::V1
};
let content = if let Some(v) = meta.get("content") {
let v = String::from_utf8_lossy(v);
v.parse()?
} else {
ManifestContentType::Data
};
Ok(ManifestMetadata {
schema,
schema_id,
partition_spec,
format_version,
content,
})
}
pub fn schema(&self) -> &SchemaRef {
&self.schema
}
pub fn schema_id(&self) -> SchemaId {
self.schema_id
}
pub fn partition_spec(&self) -> &PartitionSpec {
&self.partition_spec
}
pub fn format_version(&self) -> &FormatVersion {
&self.format_version
}
pub fn content(&self) -> &ManifestContentType {
&self.content
}
}