checkpoint

This commit is contained in:
2026-04-09 18:39:52 -04:00
parent 9387152859
commit 5f45df6c11
11 changed files with 677 additions and 467 deletions

View File

@ -32,7 +32,6 @@ pub struct Database {
pub puncs: HashMap<String, Punc>,
pub relations: HashMap<String, Relation>,
pub schemas: HashMap<String, Schema>,
pub descendants: HashMap<String, Vec<String>>,
pub depths: HashMap<String, usize>,
pub executor: Box<dyn DatabaseExecutor + Send + Sync>,
}
@ -45,7 +44,6 @@ impl Database {
relations: HashMap::new(),
puncs: HashMap::new(),
schemas: HashMap::new(),
descendants: HashMap::new(),
depths: HashMap::new(),
#[cfg(not(test))]
executor: Box::new(SpiExecutor::new()),
@ -194,7 +192,6 @@ impl Database {
self.collect_schemas(errors);
self.collect_depths();
self.collect_descendants();
// Mathematically evaluate all property inheritances, formats, schemas, and foreign key edges topographically over OnceLocks
let mut visited = std::collections::HashSet::new();
@ -256,43 +253,4 @@ impl Database {
self.depths = depths;
}
fn collect_descendants(&mut self) {
let mut direct_refs: HashMap<String, Vec<String>> = HashMap::new();
for (id, schema) in &self.schemas {
if let Some(crate::database::schema::SchemaTypeOrArray::Single(t)) = &schema.obj.type_ {
if !crate::database::schema::is_primitive_type(t) {
direct_refs
.entry(t.clone())
.or_default()
.push(id.clone());
}
}
}
// Cache exhaustive descendants matrix for generic $family string lookups natively
let mut descendants = HashMap::new();
for id in self.schemas.keys() {
let mut desc_set = HashSet::new();
Self::collect_descendants_recursively(id, &direct_refs, &mut desc_set);
let mut desc_vec: Vec<String> = desc_set.into_iter().collect();
desc_vec.sort();
descendants.insert(id.clone(), desc_vec);
}
self.descendants = descendants;
}
fn collect_descendants_recursively(
target: &str,
direct_refs: &std::collections::HashMap<String, Vec<String>>,
descendants: &mut std::collections::HashSet<String>,
) {
if let Some(children) = direct_refs.get(target) {
for child in children {
if descendants.insert(child.clone()) {
Self::collect_descendants_recursively(child, direct_refs, descendants);
}
}
}
}
}

View File

@ -23,6 +23,10 @@ pub fn is_once_lock_vec_empty<T>(lock: &OnceLock<Vec<T>>) -> bool {
lock.get().map_or(true, |v| v.is_empty())
}
pub fn is_once_lock_string_empty(lock: &OnceLock<String>) -> bool {
lock.get().map_or(true, |s| s.is_empty())
}
// Schema mirrors the Go Punc Generator's schema struct for consistency.
// It is an order-preserving representation of a JSON Schema.
pub fn deserialize_some<'de, D>(deserializer: D) -> Result<Option<Value>, D::Error>
@ -201,6 +205,18 @@ pub struct SchemaObject {
#[serde(skip)]
pub compiled_properties: OnceLock<BTreeMap<String, Arc<Schema>>>,
#[serde(rename = "compiledDiscriminator")]
#[serde(skip_deserializing)]
#[serde(skip_serializing_if = "crate::database::schema::is_once_lock_string_empty")]
#[serde(serialize_with = "crate::database::schema::serialize_once_lock")]
pub compiled_discriminator: OnceLock<String>,
#[serde(rename = "compiledOptions")]
#[serde(skip_deserializing)]
#[serde(skip_serializing_if = "crate::database::schema::is_once_lock_map_empty")]
#[serde(serialize_with = "crate::database::schema::serialize_once_lock")]
pub compiled_options: OnceLock<BTreeMap<String, String>>,
#[serde(rename = "compiledEdges")]
#[serde(skip_deserializing)]
#[serde(skip_serializing_if = "crate::database::schema::is_once_lock_map_empty")]
@ -411,11 +427,140 @@ impl Schema {
}
}
self.compile_polymorphism(db, errors);
if let Some(id) = &self.obj.id {
visited.remove(id);
}
}
pub fn compile_polymorphism(
&self,
db: &crate::database::Database,
errors: &mut Vec<crate::drop::Error>,
) {
let mut options = std::collections::BTreeMap::new();
let mut strategy = String::new();
if let Some(family) = &self.obj.family {
let family_base = family.split('.').next_back().unwrap_or(family).to_string();
let family_prefix = family.strip_suffix(&family_base).unwrap_or("").trim_end_matches('.');
if let Some(type_def) = db.types.get(&family_base) {
if type_def.variations.len() > 1 && type_def.variations.iter().any(|v| v != &family_base) {
// Scenario A / B: Table Variations
strategy = "type".to_string();
for var in &type_def.variations {
let target_id = if family_prefix.is_empty() {
var.to_string()
} else {
format!("{}.{}", family_prefix, var)
};
if db.schemas.contains_key(&target_id) {
options.insert(var.to_string(), target_id);
}
}
} else {
// Scenario C: Single Table Inheritance (Horizontal)
strategy = "kind".to_string();
let mut target_family_ids = std::collections::HashSet::new();
target_family_ids.insert(family.clone());
// Iteratively build local descendants since db.descendants is removed natively
let mut added = true;
while added {
added = false;
for schema in &type_def.schemas {
if let Some(id) = &schema.obj.id {
if !target_family_ids.contains(id) {
if let Some(crate::database::schema::SchemaTypeOrArray::Single(t)) = &schema.obj.type_ {
if target_family_ids.contains(t) {
target_family_ids.insert(id.clone());
added = true;
}
}
}
}
}
}
for schema in &type_def.schemas {
if let Some(id) = &schema.obj.id {
if target_family_ids.contains(id) {
if let Some(kind_val) = schema.obj.get_discriminator_value("kind") {
options.insert(kind_val, id.to_string());
}
}
}
}
}
}
} else if let Some(one_of) = &self.obj.one_of {
let mut type_vals = std::collections::HashSet::new();
let mut kind_vals = std::collections::HashSet::new();
for c in one_of {
if let Some(t_val) = c.obj.get_discriminator_value("type") {
type_vals.insert(t_val);
}
if let Some(k_val) = c.obj.get_discriminator_value("kind") {
kind_vals.insert(k_val);
}
}
strategy = if type_vals.len() > 1 && type_vals.len() == one_of.len() {
"type".to_string()
} else if kind_vals.len() > 1 && kind_vals.len() == one_of.len() {
"kind".to_string()
} else {
"".to_string()
};
if strategy.is_empty() {
return;
}
for c in one_of {
if let Some(val) = c.obj.get_discriminator_value(&strategy) {
if options.contains_key(&val) {
errors.push(crate::drop::Error {
code: "POLYMORPHIC_COLLISION".to_string(),
message: format!("Polymorphic boundary defines multiple candidates mapped to the identical discriminator value '{}'.", val),
details: crate::drop::ErrorDetails::default()
});
continue;
}
let mut target_id = c.obj.id.clone();
if target_id.is_none() {
if let Some(crate::database::schema::SchemaTypeOrArray::Single(t)) = &c.obj.type_ {
if !crate::database::schema::is_primitive_type(t) {
target_id = Some(t.clone());
}
}
}
if let Some(tid) = target_id {
options.insert(val, tid);
}
}
}
} else {
return;
}
if let Some(id) = &self.obj.id {
println!("[DEBUG POLYMORPHISM] ID: {}, Strategy: {}, Options: {:?}", id, strategy, options);
}
if !options.is_empty() {
let _ = self.obj.compiled_discriminator.set(strategy);
let _ = self.obj.compiled_options.set(options);
}
}
#[allow(unused_variables)]
fn validate_identifier(id: &str, field_name: &str, errors: &mut Vec<crate::drop::Error>) {
#[cfg(not(test))]
@ -893,6 +1038,72 @@ impl SchemaObject {
}
None
}
pub fn get_discriminator_value(&self, dim: &str) -> Option<String> {
let is_split = self.compiled_properties.get().map_or(false, |p| p.contains_key("kind"));
if let Some(id) = &self.id {
if id.contains("light.person") || id.contains("light.organization") {
println!("[DEBUG SPLIT] ID: {}, dim: {}, is_split: {:?}, props: {:?}", id, dim, is_split, self.compiled_properties.get().map(|p| p.keys().cloned().collect::<Vec<_>>()));
}
}
if let Some(props) = self.compiled_properties.get() {
if let Some(prop_schema) = props.get(dim) {
if let Some(c) = &prop_schema.obj.const_ {
if let Some(s) = c.as_str() {
return Some(s.to_string());
}
}
if let Some(e) = &prop_schema.obj.enum_ {
if e.len() == 1 {
if let Some(s) = e[0].as_str() {
return Some(s.to_string());
}
}
}
}
}
if dim == "kind" {
if let Some(id) = &self.id {
let base = id.split('/').last().unwrap_or(id);
if let Some(idx) = base.rfind('.') {
return Some(base[..idx].to_string());
}
}
if let Some(crate::database::schema::SchemaTypeOrArray::Single(t)) = &self.type_ {
if !crate::database::schema::is_primitive_type(t) {
let base = t.split('/').last().unwrap_or(t);
if let Some(idx) = base.rfind('.') {
return Some(base[..idx].to_string());
}
}
}
}
if dim == "type" {
if let Some(id) = &self.id {
let base = id.split('/').last().unwrap_or(id);
if is_split {
return Some(base.split('.').next_back().unwrap_or(base).to_string());
} else {
return Some(base.to_string());
}
}
if let Some(crate::database::schema::SchemaTypeOrArray::Single(t)) = &self.type_ {
if !crate::database::schema::is_primitive_type(t) {
let base = t.split('/').last().unwrap_or(t);
if is_split {
return Some(base.split('.').next_back().unwrap_or(base).to_string());
} else {
return Some(base.to_string());
}
}
}
}
None
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]