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

Merging oneOf with many compatible enums of a single value #567

Closed
benjaminleonard opened this issue Apr 23, 2024 · 10 comments
Closed

Merging oneOf with many compatible enums of a single value #567

benjaminleonard opened this issue Apr 23, 2024 · 10 comments
Labels
kind/support Adopter support requests.

Comments

@benjaminleonard
Copy link

benjaminleonard commented Apr 23, 2024

Question

I'm no expert in Swift nor OpenAPI, so forgive any sizeable gaps in my understanding.

I'm working with a schema that has a group of oneOf enums. It's structured like that to allow annotations directly on the enum (OAI/OpenAPI-Specification#348 (comment)).

Unfortunately the current implementation of swift-openapi-generator generates somewhat verbose and less intuitive usage types for these.

Input:

"InstanceState": {
  "oneOf": [
    {
      "description": "The instance is being created.",
      "type": "string",
      "enum": [
        "creating"
      ]
    },
  ]
}

Output:

@frozen internal enum InstanceState: Codable, Hashable, Sendable {
    /// The instance is being created.
    ///
    /// - Remark: Generated from `#/components/schemas/InstanceState/case1`.
    @frozen internal enum Case1Payload: String, Codable, Hashable, Sendable, CaseIterable {
        case creating = "creating"
    }

Which means I end up needing to write something like: run_state: .case1(.created) or run_state: .case9(.failed).

Is this something that the generator can handle? Or should I be using it differently?

@benjaminleonard benjaminleonard added kind/support Adopter support requests. status/triage Collecting information required to triage the issue. labels Apr 23, 2024
@simonjbeaumont
Copy link
Collaborator

The generator doesn't have any special logic for the enum-of-one-case pattern and, for enums, it generates number-based symbol names.

In an ideal world, what would you like the code to look like? If this is a common pattern we can consider proposals for generating but it needs to be generalisable.

@czechboy0
Copy link
Collaborator

What does this give you over just this?

"InstanceState": {
      "description": "The instance is being created.",
      "type": "string",
      "enum": [
        "creating"
      ]
}

@benjaminleonard
Copy link
Author

benjaminleonard commented Apr 23, 2024

In an ideal world, what would you like the code to look like?

Ideally I'd be able to use the enum directly, e.g. run_state: .failed. This is the same issue in a Rust type generator: oxidecomputer/typify#497

What does this give you over just this?

I should of provided more context, this has many oneOfs with a single enum.

"InstanceState": {
    "description": "Running state of an Instance (primarily: booted or stopped)\n\nThis typically reflects whether it's starting, running, stopping, or stopped, but also includes states related to the Instance's lifecycle",
    "oneOf": [
      {
        "description": "The instance is being created.",
        "type": "string",
        "enum": [
          "creating"
        ]
      },
      {
        "description": "The instance is currently starting up.",
        "type": "string",
        "enum": [
          "starting"
        ]
      },
      {
        "description": "The instance is currently running.",
        "type": "string",
        "enum": [
          "running"
        ]
      },
      {
        "description": "The instance has been requested to stop and a transition to \"Stopped\" is imminent.",
        "type": "string",
        "enum": [
          "stopping"
        ]
      },
      {
        "description": "The instance is currently stopped.",
        "type": "string",
        "enum": [
          "stopped"
        ]
      },
      {
        "description": "The instance is in the process of rebooting - it will remain in the \"rebooting\" state until the VM is starting once more.",
        "type": "string",
        "enum": [
          "rebooting"
        ]
      },
      {
        "description": "The instance is in the process of migrating - it will remain in the \"migrating\" state until the migration process is complete and the destination propolis is ready to continue execution.",
        "type": "string",
        "enum": [
          "migrating"
        ]
      },
      {
        "description": "The instance is attempting to recover from a failure.",
        "type": "string",
        "enum": [
          "repairing"
        ]
      },
      {
        "description": "The instance has encountered a failure.",
        "type": "string",
        "enum": [
          "failed"
        ]
      },
      {
        "description": "The instance has been deleted.",
        "type": "string",
        "enum": [
          "destroyed"
        ]
      }
    ]
  },

@czechboy0
Copy link
Collaborator

Why are they split this way? You can spell the same with a single string enum that contains all those cases. Is it a workaround to add the descriptions?

@ahl
Copy link

ahl commented Apr 23, 2024

That's right: a simple enum doesn't let us have descriptions for each value.

@czechboy0
Copy link
Collaborator

Yeah that's unfortunate, one way you can work around it is to add the description to the enum itself, and document each case there. That'll make the code much easier to work with. But otherwise there's not much we can do, the oneOf is there, so the generator emits code for it.

@simonjbeaumont
Copy link
Collaborator

OOI, is this pattern of oneOf-of-enums-all-with-just-one-case entirely isomorphic to an enum when it comes to the HTTP representation?

I'm asking because we're not likely to change how oneOfs are generated, you could consider preprocessing the document here.

@ahl
Copy link

ahl commented Apr 24, 2024

If I understand correctly, it sounds like the philosophy of this SDK generator is for simple and predictable transformations from, say, a oneOf construction into an enum rather than deeper inspection for idiomatic code generation. If that focus changes such that you're amenable to special cases for improved codegen, this might be a case you'd consider.

@czechboy0
Copy link
Collaborator

it sounds like the philosophy of this SDK generator is for simple and predictable transformations from, say, a oneOf construction into an enum rather than deeper inspection for idiomatic code generation.

Exactly, we even call out the tradeoffs in more detail here: https://swiftpackageindex.com/apple/swift-openapi-generator/1.2.1/documentation/swift-openapi-generator/project-scope-and-goals

Thanks for understanding 🙂

@czechboy0 czechboy0 closed this as not planned Won't fix, can't repro, duplicate, stale Apr 25, 2024
@czechboy0 czechboy0 removed the status/triage Collecting information required to triage the issue. label Apr 25, 2024
@benjaminleonard
Copy link
Author

Nonetheless, thanks for considering. 👍🏻

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

No branches or pull requests

4 participants