beefed up schema compiled properties with cases properties and added tests with cases to queryer and merger

This commit is contained in:
2026-04-16 11:00:26 -04:00
parent cd85a8a2c3
commit 77af67aef5
6 changed files with 351 additions and 53 deletions

View File

@ -154,7 +154,7 @@ pub struct SchemaObject {
#[serde(skip_serializing_if = "Option::is_none")]
pub extensible: Option<bool>,
#[serde(rename = "compiledProperties")]
#[serde(rename = "compiledPropertyNames")]
#[serde(skip_deserializing)]
#[serde(skip_serializing_if = "crate::database::object::is_once_lock_vec_empty")]
#[serde(serialize_with = "crate::database::object::serialize_once_lock")]

View File

@ -117,13 +117,34 @@ impl Schema {
}
}
// 3. Set the OnceLock!
// 3. Add cases conditionally-defined properties recursively
if let Some(cases) = &self.obj.cases {
for (i, c) in cases.iter().enumerate() {
if let Some(child) = &c.when {
child.compile(db, root_id, format!("{}/cases/{}/when", path, i), errors);
}
if let Some(child) = &c.then {
child.compile(db, root_id, format!("{}/cases/{}/then", path, i), errors);
if let Some(t_props) = child.obj.compiled_properties.get() {
props.extend(t_props.clone());
}
}
if let Some(child) = &c.else_ {
child.compile(db, root_id, format!("{}/cases/{}/else", path, i), errors);
if let Some(e_props) = child.obj.compiled_properties.get() {
props.extend(e_props.clone());
}
}
}
}
// 4. Set the OnceLock!
let _ = self.obj.compiled_properties.set(props.clone());
let mut names: Vec<String> = props.keys().cloned().collect();
names.sort();
let _ = self.obj.compiled_property_names.set(names);
// 4. Compute Edges natively
// 5. Compute Edges natively
let schema_edges = self.compile_edges(db, root_id, &path, &props, errors);
let _ = self.obj.compiled_edges.set(schema_edges);
@ -151,22 +172,12 @@ impl Schema {
}
if let Some(one_of) = &self.obj.one_of {
for (i, child) in one_of.iter().enumerate() {
child.compile(
db,
root_id,
format!("{}/oneOf/{}", path, i),
errors,
);
child.compile(db, root_id, format!("{}/oneOf/{}", path, i), errors);
}
}
if let Some(arr) = &self.obj.prefix_items {
for (i, child) in arr.iter().enumerate() {
child.compile(
db,
root_id,
format!("{}/prefixItems/{}", path, i),
errors,
);
child.compile(db, root_id, format!("{}/prefixItems/{}", path, i), errors);
}
}
if let Some(child) = &self.obj.not {
@ -175,34 +186,6 @@ impl Schema {
if let Some(child) = &self.obj.contains {
child.compile(db, root_id, format!("{}/contains", path), errors);
}
if let Some(cases) = &self.obj.cases {
for (i, c) in cases.iter().enumerate() {
if let Some(child) = &c.when {
child.compile(
db,
root_id,
format!("{}/cases/{}/when", path, i),
errors,
);
}
if let Some(child) = &c.then {
child.compile(
db,
root_id,
format!("{}/cases/{}/then", path, i),
errors,
);
}
if let Some(child) = &c.else_ {
child.compile(
db,
root_id,
format!("{}/cases/{}/else", path, i),
errors,
);
}
}
}
self.compile_polymorphism(db, root_id, &path, errors);
}
@ -285,7 +268,9 @@ impl Schema {
if let Some(c_type) = child_type_name {
// Skip edge compilation for JSONB columns — they store data inline, not relationally.
// The physical column type from field_types is the single source of truth.
if let Some(ft) = type_def.field_types.as_ref()
if let Some(ft) = type_def
.field_types
.as_ref()
.and_then(|v| v.get(prop_name.as_str()))
.and_then(|v| v.as_str())
{
@ -296,12 +281,7 @@ impl Schema {
if db.types.contains_key(&c_type) {
// Ensure the child Schema's AST has accurately compiled its own physical property keys so we can
// inject them securely for Many-to-Many Twin Deduction disambiguation matching.
target_schema.compile(
db,
root_id,
format!("{}/{}", path, prop_name),
errors,
);
target_schema.compile(db, root_id, format!("{}/{}", path, prop_name), errors);
if let Some(compiled_target_props) = target_schema.obj.compiled_properties.get() {
let keys_for_ambiguity: Vec<String> =