oxidecomputer / typify

compiler from JSON Schema into idiomatic Rust types
Apache License 2.0
401 stars 57 forks source link

Option to control behaviour of `allOf`? #670

Open vlad-ivanov-name opened 1 week ago

vlad-ivanov-name commented 1 week ago

Consider the following schema:

https://unpkg.com/@octokit/webhooks-schemas@7.3.1/schema.json

it contains a definition:

    "pull_request$closed": {
      "$schema": "http://json-schema.org/draft-07/schema",
      "type": "object",
      "required": ["action", "number", "pull_request", "repository", "sender"],
      "properties": {
        "action": { "type": "string", "enum": ["closed"] },
        "number": {
          "type": "integer",
          "description": "The pull request number."
        },
        "pull_request": {
          "allOf": [
            { "$ref": "#/definitions/pull-request" },
            {
              "type": "object",
              "required": ["state", "closed_at", "merged"],
              "properties": {
                "state": {
                  "type": "string",
                  "enum": ["closed"],
                  "description": "State of this Pull Request. Either `open` or `closed`."
                },
                "closed_at": { "type": "string", "format": "date-time" },
                "merged": { "type": "boolean" }
              },
              "tsAdditionalProperties": false
            }
          ]
        },
        "repository": { "$ref": "#/definitions/repository" },
        "installation": { "$ref": "#/definitions/installation-lite" },
        "organization": { "$ref": "#/definitions/organization" },
        "sender": { "$ref": "#/definitions/user" }
      },
      "additionalProperties": false,
      "title": "pull_request closed event"
    },

allOf inside pull_request would result of generation of type PullRequestClosedPullRequest which is almost the same as normal PullRequest but has one extra field. This creates a problem for consuming those types: let's say you need a field from inside pull_request -- you would have to account for all of the variations of it.

In languages like TS this would be solved by structural subtyping; in rust, while there's nothing like that built-in, perhaps there's a way to adjust behaviour of anyOf to generate some code that would be able to return common parts? e. g. via a generated trait for example. Right now this needs a lot of boilerplate code, for example to extract any pull_request field form PullRequestEvent

ahl commented 6 days ago

My intention here (that I think is relevant to what you're asking) is to have a From impl for allOf constructions such as this. For example, we'd do something like this:

impl From<PullRequestClosedPullRequest> for PullRequest {
..
}

Do you think that would address your use case?

vlad-ivanov-name commented 2 days ago

to an extent yes 🤔 although this would still require writing a match for the outer enum