use crate::{GraphDb, Result, RuleDef, ViewDef};
use core_storage::{fs::Fs, GraphError};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Default, Debug)]
pub struct Schema {
#[serde(default)]
pub fulltext: Vec<(String, String)>,
#[serde(default)]
pub rules: Vec<RuleDef>,
#[serde(default)]
pub views: Vec<ViewDef>,
}
#[derive(Debug, PartialEq)]
pub struct SchemaDiff {
pub created: Vec<String>,
pub updated: Vec<String>,
pub unchanged: Vec<String>,
}
impl<F: Fs> GraphDb<F> {
pub fn apply_schema(&mut self, schema: &Schema) -> Result<SchemaDiff> {
let live_views = self.views();
let live_rules = self.rules();
for view_def in &schema.views {
let would_mutate = live_views
.iter()
.find(|v| v.name == view_def.name)
.is_none_or(|live| live != view_def);
if would_mutate {
view_def
.validate()
.map_err(|e| GraphError::RuleInvalid { detail: e })?;
}
}
for rule_def in &schema.rules {
let would_mutate = live_rules
.iter()
.find(|r| r.name == rule_def.name)
.is_none_or(|live| live != rule_def);
if would_mutate {
rule_def
.validate()
.map_err(|e| GraphError::RuleInvalid { detail: e })?;
}
}
let mut created = Vec::new();
let mut updated = Vec::new();
let mut unchanged = Vec::new();
for (label, field) in &schema.fulltext {
let key = format!("fulltext:{label}.{field}");
if self.is_fulltext_enabled(label, field) {
unchanged.push(key);
} else {
self.enable_fulltext(label, field)?;
created.push(key);
}
}
for view_def in &schema.views {
let key = format!("view:{}", view_def.name);
if let Some(live) = live_views.iter().find(|v| v.name == view_def.name) {
if live == view_def {
unchanged.push(key);
} else {
self.delete_view(&view_def.name)?;
self.create_view(view_def.clone())?;
updated.push(key);
}
} else {
self.create_view(view_def.clone())?;
created.push(key);
}
}
for rule_def in &schema.rules {
let key = format!("rule:{}", rule_def.name);
if let Some(live) = live_rules.iter().find(|r| r.name == rule_def.name) {
if live == rule_def {
unchanged.push(key);
} else {
self.delete_rule(&rule_def.name)?;
self.create_rule(rule_def.clone())?;
updated.push(key);
}
} else {
self.create_rule(rule_def.clone())?;
created.push(key);
}
}
Ok(SchemaDiff {
created,
updated,
unchanged,
})
}
}