significantly simplified the validator and work continues on query

This commit is contained in:
2026-03-03 17:58:31 -05:00
parent 3898c43742
commit e7f20e2cb6
58 changed files with 5446 additions and 5693 deletions

View File

@ -1,5 +1,4 @@
use serde_json::Value;
use std::collections::HashSet;
use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError;
@ -53,6 +52,7 @@ impl<'a> ValidationContext<'a> {
contains_schema,
child_instance,
&self.path,
std::collections::HashSet::new(),
self.extensible,
false,
);
@ -91,7 +91,14 @@ impl<'a> ValidationContext<'a> {
if i < len {
let path = format!("{}/{}", self.path, i);
if let Some(child_instance) = arr.get(i) {
let derived = self.derive(sub_schema, child_instance, &path, self.extensible, false);
let derived = self.derive(
sub_schema,
child_instance,
&path,
std::collections::HashSet::new(),
self.extensible,
false,
);
let item_res = derived.validate()?;
result.merge(item_res);
result.evaluated_indices.insert(i);
@ -105,7 +112,14 @@ impl<'a> ValidationContext<'a> {
for i in validation_index..len {
let path = format!("{}/{}", self.path, i);
if let Some(child_instance) = arr.get(i) {
let derived = self.derive(items_schema, child_instance, &path, self.extensible, false);
let derived = self.derive(
items_schema,
child_instance,
&path,
std::collections::HashSet::new(),
self.extensible,
false,
);
let item_res = derived.validate()?;
result.merge(item_res);
result.evaluated_indices.insert(i);

View File

@ -42,7 +42,7 @@ impl<'a> ValidationContext<'a> {
if let Some(obj) = self.instance.as_object() {
for key in obj.keys() {
if !result.evaluated_keys.contains(key) {
if !result.evaluated_keys.contains(key) && !self.overrides.contains(key) {
result.errors.push(ValidationError {
code: "STRICT_PROPERTY_VIOLATION".to_string(),
message: format!("Unexpected property '{}'", key),

View File

@ -1,5 +1,3 @@
use serde_json::Value;
use std::collections::HashSet;
use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError;

View File

@ -1,5 +1,4 @@
use serde_json::Value;
use std::collections::HashSet;
use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError;
@ -13,7 +12,7 @@ impl<'a> ValidationContext<'a> {
let current = self.instance;
if let Some(obj) = current.as_object() {
// Entity Bound Implicit Type Validation
if let Some(allowed_types) = &self.schema.obj.compiled_allowed_types {
if let Some(allowed_types) = &self.schema.obj.compiled_variations {
if let Some(type_val) = obj.get("type") {
if let Some(type_str) = type_val.as_str() {
if allowed_types.contains(type_str) {
@ -62,8 +61,38 @@ impl<'a> ValidationContext<'a> {
}
}
if let Some(ref deps) = self.schema.dependencies {
for (prop, dep) in deps {
if obj.contains_key(prop) {
match dep {
crate::database::schema::Dependency::Props(required_props) => {
for req_prop in required_props {
if !obj.contains_key(req_prop) {
result.errors.push(ValidationError {
code: "DEPENDENCY_MISSING".to_string(),
message: format!("Property '{}' requires property '{}'", prop, req_prop),
path: self.path.to_string(),
});
}
}
}
crate::database::schema::Dependency::Schema(dep_schema) => {
let derived = self.derive_for_schema(dep_schema, false);
let dep_res = derived.validate()?;
result.evaluated_keys.extend(dep_res.evaluated_keys.clone());
result.merge(dep_res);
}
}
}
}
}
if let Some(props) = &self.schema.properties {
for (key, sub_schema) in props {
if self.overrides.contains(key) {
continue; // Skip validation if exactly this property was overridden by a child
}
if let Some(child_instance) = obj.get(key) {
let new_path = format!("{}/{}", self.path, key);
let is_ref = sub_schema.ref_string.is_some() || sub_schema.obj.compiled_ref.is_some();
@ -73,6 +102,7 @@ impl<'a> ValidationContext<'a> {
sub_schema,
child_instance,
&new_path,
std::collections::HashSet::new(),
next_extensible,
false,
);
@ -80,7 +110,7 @@ impl<'a> ValidationContext<'a> {
// Entity Bound Implicit Type Interception
if key == "type" {
if let Some(allowed_types) = &self.schema.obj.compiled_allowed_types {
if let Some(allowed_types) = &self.schema.obj.compiled_variations {
if let Some(instance_type) = child_instance.as_str() {
if allowed_types.contains(instance_type) {
item_res
@ -109,6 +139,7 @@ impl<'a> ValidationContext<'a> {
sub_schema,
child_instance,
&new_path,
std::collections::HashSet::new(),
next_extensible,
false,
);
@ -149,6 +180,7 @@ impl<'a> ValidationContext<'a> {
additional_schema,
child_instance,
&new_path,
std::collections::HashSet::new(),
next_extensible,
false,
);
@ -169,6 +201,7 @@ impl<'a> ValidationContext<'a> {
self.root,
property_names,
&val_str,
std::collections::HashSet::new(),
self.extensible,
self.reporter,
);

View File

@ -39,22 +39,31 @@ impl<'a> ValidationContext<'a> {
&self,
result: &mut ValidationResult,
) -> Result<bool, ValidationError> {
// 1. Core $ref logic fully transitioned to memory pointer resolutions.
if let Some(_ref_str) = &self.schema.ref_string {
if let Some(global_schema) = &self.schema.compiled_ref {
// 1. Core $ref logic relies on the fast O(1) map to allow cycles and proper nesting
if let Some(ref_str) = &self.schema.ref_string {
if let Some(global_schema) = self.schemas.get(ref_str) {
let mut new_overrides = self.overrides.clone();
if let Some(props) = &self.schema.properties {
new_overrides.extend(props.keys().map(|k| k.to_string()));
}
let mut shadow = self.derive(
global_schema,
self.instance,
&self.path,
new_overrides,
self.extensible,
false,
true,
);
shadow.root = global_schema;
result.merge(shadow.validate()?);
} else {
result.errors.push(ValidationError {
code: "REF_RESOLUTION_FAILED".to_string(),
message: format!("Reference pointer was not compiled inside Database graph"),
message: format!(
"Reference pointer to '{}' was not found in schema registry",
ref_str
),
path: self.path.to_string(),
});
}