Skip to content

Commit b9ea447

Browse files
committed
perf: validate only use evaluate() which walks the full schema tree when required, otherwise, use is_valid()
1 parent c7ad5d2 commit b9ea447

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

src/cmd/validate.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,7 +1230,7 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
12301230
// parse and compile supplied JSON Schema
12311231
let json_schema_path =
12321232
json_schema_path.unwrap_or_else(|| PathBuf::from(json_schema_arg.as_ref().unwrap()));
1233-
let (schema_json, schema_compiled): (Value, Validator) =
1233+
let (schema_json, schema_compiled, has_unique_combined): (Value, Validator, bool) =
12341234
// safety: we know the schema is_some() because we checked above
12351235
match load_json(&json_schema_path.to_string_lossy()) {
12361236
Ok(s) => {
@@ -1281,7 +1281,7 @@ pub fn run(argv: &[&str]) -> CliResult<()> {
12811281
}
12821282

12831283
match validator_options.build(&json) {
1284-
Ok(schema) => (json, schema),
1284+
Ok(schema) => (json, schema, has_unique_combined),
12851285
Err(e) => {
12861286
return fail_clierror!(r#"Cannot compile JSONschema. error: {e}
12871287
Try running `qsv validate schema {}` to check the JSON Schema file."#, json_schema_path.to_string_lossy());
@@ -1380,7 +1380,16 @@ Try running `qsv validate schema {}` to check the JSON Schema file."#, json_sche
13801380
};
13811381

13821382
// validate JSON instance against JSON Schema
1383-
let evaluation = schema_compiled.evaluate(&json_instance);
1383+
// if the schema has no stateful validators (like uniqueCombinedWith),
1384+
// and the record is valid, then short-circuit and return None
1385+
let evaluation = if !has_unique_combined && schema_compiled.is_valid(&json_instance)
1386+
{
1387+
return None;
1388+
} else {
1389+
// otherwise, fully evaluate the record
1390+
schema_compiled.evaluate(&json_instance)
1391+
};
1392+
13841393
if evaluation.flag().valid {
13851394
None
13861395
} else {
@@ -2084,12 +2093,14 @@ fn validate_json_instance(
20842093
instance: &Value,
20852094
schema_compiled: &Validator,
20862095
) -> Option<Vec<(String, String)>> {
2087-
let evaluation = schema_compiled.evaluate(instance);
2088-
if evaluation.flag().valid {
2096+
// Use is_valid() for fast boolean check on valid records (doesn't walk full tree)
2097+
// Only call evaluate() when invalid to get detailed errors
2098+
if schema_compiled.is_valid(instance) {
20892099
None
20902100
} else {
20912101
Some(
2092-
evaluation
2102+
schema_compiled
2103+
.evaluate(instance)
20932104
.iter_errors()
20942105
.map(|e| (e.instance_location.to_string(), e.error.to_string()))
20952106
.collect(),

0 commit comments

Comments
 (0)