Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to interpret schemas that contains not keyword #19

Open
jonaslagoni opened this issue Oct 8, 2021 · 6 comments
Open

How to interpret schemas that contains not keyword #19

jonaslagoni opened this issue Oct 8, 2021 · 6 comments

Comments

@jonaslagoni
Copy link
Member

The not keyword actually has two purposes from the perspective of a data definition, which makes this issue kinda complex, however, let's start simple.

Restricting types

The not keywords primary role is to define subschemas which the instance data should not validate against. This means that if you have defined a schema such as the following:

{
  "$schema": "https://json-schema.org/draft/2020-12/idl-schema",
  "name": "SomeTitle",
  "type": "object",
  "properties": {
    "prop1": {
      "type": ["string", "number"]
    }
  },
  "not": {
    "properties": {
        "prop1": {
          "type": "string"
        }
     }
  }
}

The only object that will validate is {"prop1": 2} and not {"prop1": "string value"}. This means I would expect the following class:

class SomeTitle {
   prop1: number;
}

and not the loose type (even though it could be an option):

class SomeTitle {
   prop1: string | number;
}

Question is, should we infer such a strict type, or simply accept the broader type and ignore not?

Including types

If you nest not keywords, you can actually define new types. Given the following schema:

{
  "$schema": "https://json-schema.org/draft/2020-12/idl-schema",
  "name": "SomeTitle",
  "type": "object",
  "properties": {
    "prop1": {
      "type": "string"
    }
  },
  "not": {
    "not": {
      "properties": {
          "prop2": {
            "type": "string"
          }
       }
    }
  }
}

The following data is validated {"prop2": "string value"} and {"prop2": 2} is rejected. This means I would expect that the following class:

class SomeTitle {
   prop1: string;
   prop2: string;
}

Would we care about such a case?

@jonaslagoni jonaslagoni changed the title How to interpret simple schemas that contains not keyword How to interpret schemas that contains not keyword Oct 8, 2021
@jdesrosiers
Copy link
Member

I would love to say that not is a validation-only keyword and can be ignored, but it might not be that simple. It's important to me that the structure of a schema shouldn't effect the code gen results. There's a way to refactor each of those examples in such a way that they don't use not and validate exactly the same as the original. Therefore, I don't know that we can completely dismiss not as validation-only.

On the other hand, the refactored schemas would produce different annotation results, so if any of this process is defined based on annotations (which seems likely), you could argue that those schemas are not equivalent and we don't need to find a way to make the code output equivalent.

@jonaslagoni
Copy link
Member Author

On the other hand, the refactored schemas would produce different annotation results

I can only see that the refactored schema will always give the same output as the schema with not. Can you clarify what you mean by different annotation results? 🤔

@jdesrosiers
Copy link
Member

Annotations are a JSON Schema concept where information is gathered about an instances as it is validated. If a schema fails validation, it produces no annotations. Here's an example of what an annotations result might look like based on the first example given the instance { "prop1": "foo" }.

{
  "/": { "type": "object", "name": "SomeTitle" },
  "/prop1": { "type": ["string", "number"] }
}

The instance is validated against both the outer schema and the not schema. Since failed validations don't produce annotations, the information from the not is not represented.

However, I realized that that whole line of thought doesn't make sense in this case because annotations provide information about an instance and for code gen, we don't have an instance. So, still have no idea what we should do about not.

@gregsdennis
Copy link
Member

gregsdennis commented Sep 2, 2022

class SomeTitle {
   prop1: string | number;
}

This implies that the language supports unions. Many languages don't, like C#. I feel we need to stay within the intersection of language support as much as possible.

@gregsdennis
Copy link
Member

Is there any reason why we need to support not? I say we explicitly disallow it (or document that it's unsupported and ignore it) until we know what to do with it.

@jdesrosiers
Copy link
Member

This implies that the language supports unions.

Not necessarily. A language that doesn't support unions would just need to introduce a type that represents a union. For example, a type like Either<String, Number>.

Is there any reason why we need to support not?

One of our foundational principles is that people should be able to use the same schemas for code gen as they use for validation. Therefore, we don't want to disallow any keywords. However, ignoring not in the code-gen context is certainly an option and probably the best choice here even if it's not perfect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants