use std::borrow::Cow;
use indexmap::IndexMap;
use parse_rust_core::{ClassLevelPermissions, ParseError};
use parse_rust_schema::default_schema;
use parse_rust_storage::{ClassSchema, StorageAdapter};
#[derive(Debug, Clone, Default)]
pub struct SchemaSnapshot {
classes: IndexMap<String, ClassSchema>,
}
impl SchemaSnapshot {
pub async fn load<S: StorageAdapter>(storage: &S) -> Result<Self, ParseError> {
Ok(Self::from_classes(storage.all_schemas().await?))
}
pub fn from_classes(classes: Vec<ClassSchema>) -> Self {
Self {
classes: classes
.into_iter()
.map(|s| (s.class_name.clone(), s))
.collect(),
}
}
pub fn get(&self, class_name: &str) -> Option<&ClassSchema> {
self.classes.get(class_name)
}
pub fn contains(&self, class_name: &str) -> bool {
self.classes.contains_key(class_name)
}
pub fn get_or_default(&self, class_name: &str) -> Cow<'_, ClassSchema> {
match self.classes.get(class_name) {
Some(schema) => Cow::Borrowed(schema),
None => Cow::Owned(ClassSchema::new(class_name)),
}
}
pub fn resolve_for_write(&self, class_name: &str) -> ClassSchema {
match self.classes.get(class_name) {
Some(schema) => schema.clone(),
None => default_schema(class_name),
}
}
pub fn clp(&self, class_name: &str) -> Option<&ClassLevelPermissions> {
self.classes.get(class_name).and_then(|s| s.clp.as_ref())
}
pub fn insert(&mut self, schema: ClassSchema) {
self.classes.insert(schema.class_name.clone(), schema);
}
}
#[cfg(test)]
mod tests {
use super::*;
use parse_rust_storage::FieldType;
#[test]
fn a_missing_class_reads_as_empty_and_writes_as_the_default_schema() {
let snap = SchemaSnapshot::default();
assert!(snap.get("Post").is_none());
assert!(!snap.contains("Post"));
assert!(
snap.get_or_default("Post").fields.is_empty(),
"the read fallback is {{fields: {{}}}}, with no default columns"
);
assert!(
snap.resolve_for_write("Post").field("objectId").is_some(),
"the write fallback carries the default columns"
);
}
#[test]
fn a_present_class_is_returned_borrowed() {
let snap = SchemaSnapshot::from_classes(vec![
ClassSchema::new("Post").with_field("title", FieldType::String)
]);
assert!(matches!(snap.get_or_default("Post"), Cow::Borrowed(_)));
assert_eq!(
snap.get_or_default("Post").field("title"),
Some(&FieldType::String)
);
}
}