removed schema realms, fixed fixture generations, added dynamic type resolution for validation based on type and kind discriminators for filters

This commit is contained in:
2026-04-21 10:50:01 -04:00
parent a1e6ac8cb0
commit 4e2cb488cc
25 changed files with 440 additions and 331 deletions

View File

@ -74,8 +74,8 @@ impl Schema {
);
let mut wrapper_obj = SchemaObject::default();
// Conceptually link this directly into the STI lineage of the base `filter` object
wrapper_obj.type_ = Some(SchemaTypeOrArray::Single("filter".to_string()));
// Filters are just plain objects containing conditions, no inheritance required
wrapper_obj.type_ = Some(SchemaTypeOrArray::Single("object".to_string()));
wrapper_obj.properties = Some(filter_props);
return Some(Schema {

View File

@ -51,8 +51,8 @@ impl Schema {
// 1. Resolve INHERITANCE dependencies first
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ {
if !crate::database::object::is_primitive_type(t) {
if let Some(parent) = db.get_scoped_schema(crate::database::realm::SchemaRealm::Type, t) {
if !crate::database::object::is_primitive_type(t) && !t.starts_with('$') {
if let Some(parent) = db.schemas.get(t).cloned() {
parent.as_ref().compile(db, t, t.clone(), errors);
if let Some(p_props) = parent.obj.compiled_properties.get() {
props.extend(p_props.clone());
@ -85,8 +85,8 @@ impl Schema {
}
for t in types {
if !crate::database::object::is_primitive_type(t) {
if let Some(parent) = db.get_scoped_schema(crate::database::realm::SchemaRealm::Type, t) {
if !crate::database::object::is_primitive_type(t) && !t.starts_with('$') {
if let Some(parent) = db.schemas.get(t).cloned() {
parent.as_ref().compile(db, t, t.clone(), errors);
}
}

View File

@ -12,7 +12,10 @@ impl Schema {
let mut strategy = String::new();
if let Some(family) = &self.obj.family {
// Formalize the <Variant>.<Base> topology
// family_base extracts the 'Base' (e.g. 'widget', 'person')
let family_base = family.split('.').next_back().unwrap_or(family).to_string();
// family_prefix extracts the 'Variant' (e.g. 'stock', 'light')
let family_prefix = family
.strip_suffix(&family_base)
.unwrap_or("")
@ -29,7 +32,7 @@ impl Schema {
format!("{}.{}", family_prefix, var)
};
if db.get_scoped_schema(crate::database::realm::SchemaRealm::Type, &target_id).is_some() {
if db.schemas.get(&target_id).is_some() {
options.insert(var.to_string(), (None, Some(target_id)));
}
}

View File

@ -6,7 +6,6 @@ pub mod formats;
pub mod object;
pub mod page;
pub mod punc;
pub mod realm;
pub mod relation;
pub mod schema;
pub mod r#type;
@ -21,7 +20,6 @@ use executors::pgrx::SpiExecutor;
use executors::mock::MockExecutor;
use punc::Punc;
use realm::SchemaRealm;
use relation::Relation;
use schema::Schema;
use serde_json::Value;
@ -36,6 +34,8 @@ pub struct Database {
pub puncs: HashMap<String, Punc>,
pub relations: HashMap<String, Relation>,
#[serde(skip)]
pub schemas: HashMap<String, Arc<Schema>>,
#[serde(skip)]
pub executor: Box<dyn DatabaseExecutor + Send + Sync>,
}
@ -46,6 +46,7 @@ impl Database {
types: HashMap::new(),
relations: HashMap::new(),
puncs: HashMap::new(),
schemas: HashMap::new(),
#[cfg(not(test))]
executor: Box::new(SpiExecutor::new()),
#[cfg(test)]
@ -194,22 +195,28 @@ impl Database {
// Formally evaluate properties with strict 3-pass Ordered Graph execution natively
for (_, enum_def) in &self.enums {
for (schema_id, schema_arc) in &enum_def.schemas {
let root_id = schema_id.split('/').next().unwrap_or(schema_id);
schema_arc.as_ref().compile(self, root_id, schema_id.clone(), errors);
}
for (schema_id, schema_arc) in &enum_def.schemas {
let root_id = schema_id.split('/').next().unwrap_or(schema_id);
schema_arc
.as_ref()
.compile(self, root_id, schema_id.clone(), errors);
}
}
for (_, type_def) in &self.types {
for (schema_id, schema_arc) in &type_def.schemas {
let root_id = schema_id.split('/').next().unwrap_or(schema_id);
schema_arc.as_ref().compile(self, root_id, schema_id.clone(), errors);
}
for (schema_id, schema_arc) in &type_def.schemas {
let root_id = schema_id.split('/').next().unwrap_or(schema_id);
schema_arc
.as_ref()
.compile(self, root_id, schema_id.clone(), errors);
}
}
for (_, punc_def) in &self.puncs {
for (schema_id, schema_arc) in &punc_def.schemas {
let root_id = schema_id.split('/').next().unwrap_or(schema_id);
schema_arc.as_ref().compile(self, root_id, schema_id.clone(), errors);
}
for (schema_id, schema_arc) in &punc_def.schemas {
let root_id = schema_id.split('/').next().unwrap_or(schema_id);
schema_arc
.as_ref()
.compile(self, root_id, schema_id.clone(), errors);
}
}
// Phase 2: Synthesize Composed Filter References
@ -234,6 +241,7 @@ impl Database {
let mut filter_ids = Vec::new();
for (type_name, id, filter_arc) in filter_schemas {
filter_ids.push((type_name.clone(), id.clone()));
self.schemas.insert(id.clone(), filter_arc.clone());
if let Some(t) = self.types.get_mut(&type_name) {
t.schemas.insert(id, filter_arc);
}
@ -241,7 +249,12 @@ impl Database {
// Now actively compile the newly injected filters to lock all nested compose references natively
for (type_name, id) in filter_ids {
if let Some(filter_arc) = self.types.get(&type_name).and_then(|t| t.schemas.get(&id)).cloned() {
if let Some(filter_arc) = self
.types
.get(&type_name)
.and_then(|t| t.schemas.get(&id))
.cloned()
{
let root_id = id.split('/').next().unwrap_or(&id);
filter_arc
.as_ref()
@ -259,6 +272,7 @@ impl Database {
// Validate every node recursively via string filters natively!
for (type_name, type_def) in &self.types {
for (id, schema_arc) in &type_def.schemas {
self.schemas.insert(id.clone(), Arc::clone(schema_arc));
let mut local_insert = Vec::new();
crate::database::schema::Schema::collect_schemas(
schema_arc,
@ -275,6 +289,7 @@ impl Database {
for (punc_name, punc_def) in &self.puncs {
for (id, schema_arc) in &punc_def.schemas {
self.schemas.insert(id.clone(), Arc::clone(schema_arc));
let mut local_insert = Vec::new();
crate::database::schema::Schema::collect_schemas(
schema_arc,
@ -291,6 +306,7 @@ impl Database {
for (enum_name, enum_def) in &self.enums {
for (id, schema_arc) in &enum_def.schemas {
self.schemas.insert(id.clone(), Arc::clone(schema_arc));
let mut local_insert = Vec::new();
crate::database::schema::Schema::collect_schemas(
schema_arc,
@ -305,57 +321,27 @@ impl Database {
}
}
// Apply local scopes
// Apply local scopes and global schema map
for (origin_name, id, schema_arc) in type_insert {
self.schemas.insert(id.clone(), schema_arc.clone());
if let Some(t) = self.types.get_mut(&origin_name) {
t.schemas.insert(id, schema_arc);
}
}
for (origin_name, id, schema_arc) in punc_insert {
self.schemas.insert(id.clone(), schema_arc.clone());
if let Some(p) = self.puncs.get_mut(&origin_name) {
p.schemas.insert(id, schema_arc);
}
}
for (origin_name, id, schema_arc) in enum_insert {
self.schemas.insert(id.clone(), schema_arc.clone());
if let Some(e) = self.enums.get_mut(&origin_name) {
e.schemas.insert(id, schema_arc);
}
}
}
pub fn get_scoped_schema(&self, realm: SchemaRealm, schema_id: &str) -> Option<Arc<Schema>> {
// Punc Realm natively maps mathematically to `.request` and `.response` shapes
if realm == SchemaRealm::Punc {
if schema_id.ends_with(".request") || schema_id.ends_with(".response") {
let punc_name = schema_id
.trim_end_matches(".request")
.trim_end_matches(".response");
return self.puncs.get(punc_name).and_then(|p| p.schemas.get(schema_id).cloned());
}
}
let clean_id = schema_id.trim_end_matches(".filter");
let root_id = clean_id.split('/').next().unwrap_or(clean_id);
let base_name = root_id.split('.').next_back().unwrap_or(root_id);
// Puncs and Types can lookup Table boundaries
if realm == SchemaRealm::Type || realm == SchemaRealm::Punc {
if let Some(type_def) = self.types.get(base_name) {
if let Some(schema) = type_def.schemas.get(schema_id) {
return Some(schema.clone());
}
}
}
// All realms can intrinsically look up enumerations
if let Some(enum_def) = self.enums.get(base_name) {
if let Some(schema) = enum_def.schemas.get(schema_id) {
return Some(schema.clone());
}
}
None
}
/// Inspects the Postgres pg_constraint relations catalog to securely identify
/// the precise Foreign Key connecting a parent and child hierarchy path.

View File

@ -1,6 +0,0 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SchemaRealm {
Enum,
Type,
Punc,
}

View File

@ -22,6 +22,27 @@ impl std::ops::DerefMut for Schema {
}
}
impl Schema {
/// Returns true if the schema acts purely as a type pointer (composition without overriding constraints)
pub fn is_proxy(&self) -> bool {
self.obj.properties.is_none()
&& self.obj.pattern_properties.is_none()
&& self.obj.additional_properties.is_none()
&& self.obj.required.is_none()
&& self.obj.dependencies.is_none()
&& self.obj.items.is_none()
&& self.obj.prefix_items.is_none()
&& self.obj.contains.is_none()
&& self.obj.format.is_none()
&& self.obj.enum_.is_none()
&& self.obj.const_.is_none()
&& self.obj.cases.is_none()
&& self.obj.one_of.is_none()
&& self.obj.not.is_none()
&& self.obj.family.is_none()
}
}
impl<'de> Deserialize<'de> for Schema {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where