Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
andijcr committed Jun 27, 2024
1 parent dd368fe commit ff21fa8
Showing 1 changed file with 59 additions and 4 deletions.
63 changes: 59 additions & 4 deletions src/v/pandaproxy/schema_registry/json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ bool is_array_superset(json::Value const& older, json::Value const& newer) {
// in Draft4 for tuple, "items" can be the array of schemas and "additionalItems" is the additional schema
// after Draft4, "prefixItems" is the array of schemas and "items" is the additional schema.
// this superset function could validate both types at same time, but for readability reasons the checks are separated

// size checks are common to both types
if (!is_numeric_property_value_superset(
older, newer, "minItems", std::less_equal<>{})) {
Expand All @@ -833,7 +833,7 @@ bool is_array_superset(json::Value const& older, json::Value const& newer) {
return false;
}

// uniqueItems
// uniqueItems makes sense mostly for arrays, but it's also allowed for tuples, so the validation is done here
if (auto [maybe_gate_check, older_v_p, newer_v_p]
= extract_property_and_gate_check(older, newer, "uniqueItems");
maybe_gate_check.has_value()) {
Expand All @@ -859,11 +859,66 @@ bool is_array_superset(json::Value const& older, json::Value const& newer) {
}
}

if (!is_array_items_superset(older, newer)) {
auto is_tuple = [](json::Value const& v)->bool{
// TODO "prefixItems" is not in Draft4, it's from later drafts. if it's present, it's this is tuple schema
// if v.HasMember("prefixItems") -> return true
auto items_it=v.FindMember("items");
// default for items is `{}` so it's not a tuple schema
// v is a tuple schema if "items" is an array of schemas
return items_it!=v.MemberEnd() && items_it->value.IsArray();
};

auto older_is_tuple=is_tuple(older);
auto newer_is_tuple=is_tuple(newer);

if(older_is_tuple!=newer_is_tuple){
// one is a tuple and the other is not. not compatible
return false;
}
// both are tuples or both are arrays

if (!older_is_tuple) {
// both are array, only "items" is relevant and it's a schema
// TODO after draft 4 "items" can be also a boolean so this needs to account for that
// note that "additionalItems" can be defined, but it's not used by validation because every element is validated against "items"
return is_superset(get_object_or_empty(older, "items"), get_object_or_empty(newer,"items"));
}else{
// both are tuple schemas, validation is similar to object. one side effect is that the "items" key is present.

// first check is for "additionalItems" compatibility, it's cheaper and
if (!is_additional_superset(older, newer, additional_field_for::array)) {
return false;
}


auto older_tuple_schema=older["items"].GetArray();
auto newer_tuple_schema= newer["items"].GetArray();

auto [older_it, newer_it]=std::ranges::mismatch(older_tuple_schema, newer_tuple_schema, is_superset);
auto older_tuple_it=older_tuple_schema.Begin();
auto newer_tuple_it = newer_tuple_schema.Begin();
// std::views::zip would be nice
for(auto older_end=older_tuple_schema.End(), newer_end=newer_tuple_schema.End(); older_tuple_it==older_end|| newer_tuple_it==newer_end; ++older_tuple_it, ++ newer_tuple_it){
// schemas at the same index need to be compatible
if(!is_superset(*older_tuple_it, *newer_tuple_it)){
return false;
}
}

if(newer_tuple_it)


// if newer has more elements than older, excess elements will be checked against this
auto older_additional_schema=



}

// both are arrays

if (!is_additional_superset(older, newer, additional_field_for::array)) {

if (!is_array_items_superset(older, newer)) {
return false;
}

Expand Down

0 comments on commit ff21fa8

Please sign in to comment.