Skip to content

Failed generation on enum struct with same property name #99

@bdeneux

Description

@bdeneux

Following a comment on my last PR (#98), I've encountered an issue when generating schema types from our smart contract JSON schema.

To illustrate the problem, consider the following Rust code snippet:

/// # Value
#[cw_serde]
#[serde(tag = "type")]
pub enum Value {
    /// # String
    String { value: String },
    /// # Number
    Number { value: i64 },
}
**Whole JSON Schema for example**

{
  "contract_name": "nested-enum-same-name",
  "contract_version": "0.0.1",
  "idl_version": "1.0.0",
  "instantiate": {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "InstantiateMsg",
    "description": "Instantiate message",
    "type": "object",
    "additionalProperties": false
  },
  "execute": {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "ExecuteMsg",
    "description": "Execute messages",
    "oneOf": [
      {
        "title": "Foo",
        "type": "object",
        "required": [
          "foo"
        ],
        "properties": {
          "foo": {
            "type": "object",
            "required": [
              "value"
            ],
            "properties": {
              "value": {
                "$ref": "#/definitions/Value"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      }
    ],
    "definitions": {
      "Value": {
        "title": "Value",
        "oneOf": [
          {
            "title": "String",
            "type": "object",
            "required": [
              "type",
              "value"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "string"
                ]
              },
              "value": {
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          {
            "title": "Number",
            "type": "object",
            "required": [
              "type",
              "value"
            ],
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "number"
                ]
              },
              "value": {
                "type": "integer",
                "format": "int64"
              }
            },
            "additionalProperties": false
          }
        ]
      }
    }
  },
  "query": {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "QueryMsg",
    "description": "Query messages",
    "oneOf": [
      {
        "title": "Bar",
        "type": "object",
        "required": [
          "bar"
        ],
        "properties": {
          "bar": {
            "type": "object",
            "required": [
              "foo"
            ],
            "properties": {
              "foo": {
                "type": "string"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      }
    ]
  },
  "migrate": null,
  "sudo": null,
  "responses": {
    "bar": {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "title": "BarResponse",
      "type": "object",
      "required": [
        "foo"
      ],
      "properties": {
        "foo": {
          "description": "The foo value",
          "type": "string"
        }
      },
      "additionalProperties": false
    }
  },
  "description": "# nested-enum-same-same",
  "title": "nested-enum-same-same"
}

Internally tagged enum

In this code, we're using the serde tag #[serde(tag="type")] to transform the representation of our enum into an internally tagged format, as described in the serde documentation. This results in a generated JSON schema with an enum Type that can take string or number as a value.

Here's a snippet of the generated JSON schema:

<...>
       {
            "title": "String",
           <...>
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "string"
                ]
              },
              "value": {
                "type": "string"
              }
            },
          },
          {
            "title": "Number",
          <...>
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "number"
                ]
              },
              "value": {
                "type": "integer",
                "format": "int64"
              }
            },
          }

I've created a branch on a fork that includes a fix for merging multiple enums with the same name in the definition registry. This situation arises here because the possible values of the Type enum are defined in each definition of the Value enum. You can find the fix in this commit: d210cad.

Struct enum with same attribute name

Another issue arises because each enumeration struct variant contains a value property with a different type. When generating code with go-codegen, this leads to the following error:

duplicate definition `Value_Value` with differing implementations: different types [string] != [integer]

The issue arises due to a conflict in the type registration of Value_Value in the definition registry. Initially, Value_Value was registered as a string type. However, an attempt to register it again as an integer type has led to this problem.

For a more comprehensive understanding of the issue, you can refer to the original JSON schema that triggered this problem. It is available here. The corresponding representation in the Rust contract can be found here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions