jsonschema-rs icon indicating copy to clipboard operation
jsonschema-rs copied to clipboard

Refactor keywords into "basic" keywords and "composite" keywords

Open macisamuele opened this issue 4 years ago • 3 comments

The goal of this issue is to track the effort needed to create a well defined structure for:

  • "basic" keywords: keywords that should be validated in isolation
  • "composite" keywords": multiple keywords that can be validated together

At the current stage (9767a9f921a85bc8295b0405f19ee64f48953b4c) we already a single case of composite keywords:

  • contentEncoding and contentMediaType

The idea of creating such structure would allow us to:

  • extend the set of composite keywords as needed (#79)
  • keep better code separation between the keyword implementation and a "macro-keyword" one

Ideally the compile_validators should be looking like

let mut validators = Vec::with_capacity(object.len());
/* START NEW */
let mut object_keywords = object.keys().collect::<HashSet<_>>();
for (keywords, compilation_func) in get_all_composite_validators_for_draft(context.draft) {
    if ! object_keywords contains all keywords ! {
        if let Some(validator) = compilation_func(object, subschema, &context) {
                validators.push(validator?);
                ! Discard used keywords !
            }
        }
    }
}
/* END NEW */
for keyword in object_keywords { // object_keywords will contain the not used keywords
    if let Some(compilation_func) = context.draft.get_validator(keyword) {
        if let Some(validator) = compilation_func(object, object.get(keyword).unwrap(), &context) {
            validators.push(validator?)
        }
    }
}
Ok(validators)

This is just a rough idea, and I'm looking for feedbacks before trying something in this regard. I think that having a better structure would allow us

  • to easily tackle #79 as hooking the logic into the code would be simpler
  • eventually allow us to enable/disable the composite keywords concept via cargo features or JSONSchema::compile flags

macisamuele avatar May 25 '20 23:05 macisamuele

I'll try to provide some feedback tomorrow

Stranger6667 avatar May 26 '20 17:05 Stranger6667

Yep, it does sound right to me! :) However, I think that in the end there will be no "basic" keywords - probably all keywords can be combined and at maximum, there will be 2 validators - 1 for all types (e.g. type + allOf) and 1 type-specific, so 1-keyword validators will be the same as composite ones, i.e. they are special cases. At least it feels this way at the moment, but I think we should move in this direction. I can imagine that the perfect case for dynamic validator creation might look like this - the minimum dispatching case I see is possible is to have 2 validators, one is applied unconditionally since it is for any type and one is applied conditionally, depends on the input type.

Let me know what do you think

Stranger6667 avatar May 29 '20 11:05 Stranger6667

I see your point on "there will be no basic keywords", the aspect that I would highlight in here is that using composite keywords is a way of improving performances but at the same time increase complexity and so it might expose us to potential bugs. By still implementing the handling of 1-keyword validators we could allow to enable-disable the composite keywords concept at library compile time (via Cargo-feature) or at JSONSchema compile time (via a flag on the compile_validators method). Doing this would allow us to buy some time in case of a new bug is discovered (NOTE: This assumes that we're fairly confident with the 1-keywords implementations 😎 )

I'll try to make some progress on this, I'm aware that this is not top-priority but it would enable us to start creating n-keywords validators that would allow to enhance performances

macisamuele avatar May 29 '20 20:05 macisamuele