use super::descriptor::ProductGroupDescriptor;
use super::error::CatalogError;
struct EmbeddedManifest {
key: &'static str,
json: &'static str,
}
const EMBEDDED: &[EmbeddedManifest] = &[
EmbeddedManifest {
key: "battery",
json: include_str!("../../product-groups/battery.json"),
},
EmbeddedManifest {
key: "electronics",
json: include_str!("../../product-groups/electronics.json"),
},
EmbeddedManifest {
key: "unsold-goods",
json: include_str!("../../product-groups/unsold-goods.json"),
},
EmbeddedManifest {
key: "textile",
json: include_str!("../../product-groups/textile.json"),
},
EmbeddedManifest {
key: "steel",
json: include_str!("../../product-groups/steel.json"),
},
EmbeddedManifest {
key: "construction",
json: include_str!("../../product-groups/construction.json"),
},
EmbeddedManifest {
key: "tyre",
json: include_str!("../../product-groups/tyre.json"),
},
EmbeddedManifest {
key: "toy",
json: include_str!("../../product-groups/toy.json"),
},
EmbeddedManifest {
key: "aluminium",
json: include_str!("../../product-groups/aluminium.json"),
},
EmbeddedManifest {
key: "furniture",
json: include_str!("../../product-groups/furniture.json"),
},
EmbeddedManifest {
key: "detergent",
json: include_str!("../../product-groups/detergent.json"),
},
EmbeddedManifest {
key: "mattress",
json: include_str!("../../product-groups/mattress.json"),
},
];
pub struct ProductGroupCatalog {
entries: Vec<ProductGroupDescriptor>,
}
impl ProductGroupCatalog {
#[must_use]
pub fn new() -> Self {
let entries = EMBEDDED
.iter()
.map(|m| {
let descriptor: ProductGroupDescriptor = serde_json::from_str(m.json)
.unwrap_or_else(|e| {
panic!(
"embedded product_group manifest '{}' is invalid: {e}",
m.key
)
});
assert_eq!(
descriptor.key, m.key,
"manifest key '{}' does not match its file key '{}'",
descriptor.key, m.key
);
descriptor
})
.collect();
Self { entries }
}
#[must_use]
pub fn get(&self, key: &str) -> Option<&ProductGroupDescriptor> {
self.entries.iter().find(|d| d.key == key)
}
#[must_use]
pub fn all(&self) -> &[ProductGroupDescriptor] {
&self.entries
}
#[must_use]
pub fn current_schema_version(&self, key: &str) -> Option<&str> {
self.get(key).map(|d| d.current_schema_version.as_str())
}
#[must_use]
pub fn resolve_schema_version(&self, key: &str, stored: Option<&str>) -> Option<String> {
match stored {
Some(v) => Some(v.to_owned()),
None => self.current_schema_version(key).map(ToOwned::to_owned),
}
}
#[must_use]
pub fn keys(&self) -> Vec<&str> {
let mut keys: Vec<&str> = self.entries.iter().map(|d| d.key.as_str()).collect();
keys.sort_unstable();
keys
}
pub fn register(&mut self, descriptor: ProductGroupDescriptor) -> Result<(), CatalogError> {
if self.get(&descriptor.key).is_some() {
return Err(CatalogError::AlreadyExists(descriptor.key));
}
if descriptor
.current_schema_version
.parse::<semver::Version>()
.is_err()
{
return Err(CatalogError::InvalidSchemaVersion {
key: descriptor.key,
version: descriptor.current_schema_version,
});
}
if !descriptor
.schema_versions
.contains(&descriptor.current_schema_version)
{
return Err(CatalogError::CurrentVersionNotListed {
key: descriptor.key,
version: descriptor.current_schema_version,
});
}
self.entries.push(descriptor);
Ok(())
}
#[must_use]
pub fn len(&self) -> usize {
self.entries.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
impl Default for ProductGroupCatalog {
fn default() -> Self {
Self::new()
}
}