jmattheis / goverter

Generate type-safe Go converters by simply defining an interface
https://goverter.jmattheis.de/
MIT License
469 stars 44 forks source link

Duplicate case issue when mapping enums #150

Open kamilwilk opened 1 week ago

kamilwilk commented 1 week ago

Have you read the project documentation?

Describe your question I'm running into an issue with duplicate case when mapping enums and I'm not quite sure how to work around it. I've tried several configuration options with no dice, apologies if I missed something obvious!

Is there anyway to skip mapping DefaultStatus?

Source code

package example

// goverter:converter
// goverter:enum:unknown @error
type Converter interface {
    // goverter:enum:map DefaultStatus DefaultUserStatus
    // goverter:enum:transform regex Status(\w+) UserStatus${1}
    ExampleConvert(Status) (UserStatus, error)
}

type Status string

const DefaultStatus = StatusActive

const (
    StatusActive   Status = "active"
    StatusInactive Status = "inactive"
)

type UserStatus string

const DefaultUserStatus = UserStatusActive

const (
    UserStatusActive   UserStatus = "active"
    UserStatusInactive UserStatus = "inactive"
)

Errors

// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter

package generated

import (
    "fmt"

    example "github.com/kamilwilk/.../example"
)

type ConverterImpl struct{}

func (c *ConverterImpl) ExampleConvert(source example.Status) (example.UserStatus, error) {
    var exampleUserStatus example.UserStatus
    switch source {
    case example.DefaultStatus: <---- duplicate case (constant "active" of type example.Status) in expression switch
        exampleUserStatus = example.DefaultUserStatus
    case example.StatusActive: <---- duplicate case (constant "active" of type example.Status) in expression switch
        exampleUserStatus = example.UserStatusActive
    case example.StatusInactive:
        exampleUserStatus = example.UserStatusInactive
    default:
        return exampleUserStatus, fmt.Errorf("unexpected enum element: %v", source)
    }
    return exampleUserStatus, nil
}
jmattheis commented 1 week ago

Good catch, with the latest goverter release this is impossible to solve. Could you try out

This version makes the enum matching smarter by verifying that the source enum values aren't duplicated.

If the mapping is identical, E.g your DefaultStatus("active") -> DefaultUserStatus("active") and StatusActive("active") -> UserStatusActive("active") then one or the other case is omitted.

If the mapping is not identical. E.g.

type Status string
const DefaultStatus = StatusActive
const (
    StatusActive   Status = "active"
    StatusInactive Status = "inactive"
)

type UserStatus string
const DefaultUserStatus = UserStatusInactive
const (
    UserStatusActive   UserStatus = "active"
    UserStatusInactive UserStatus = "inactive"
)

Goverter will error with something like this

Error message (click to expand)

``` Error while creating converter method: /home/jm/src/jmattheis/goverter/example/simple/input.go:8 func (github.com/jmattheis/goverter/example/simple.Converter).ExampleConvert(github.com/jmattheis/goverter/example/simple.Status) (github.com/jmattheis/goverter/example/simple.UserStatus, error) | github.com/jmattheis/goverter/example/simple.Status | | | StatusActive(active) | | source.StatusActive target.UserStatusActive | | | | UserStatusActive(active) | | github.com/jmattheis/goverter/example/simple.UserStatus Detected multiple enum source members with the same value but different target values/actions. DefaultStatus(active) -> DefaultUserStatus(inactive) StatusActive(active) -> UserStatusActive(active) Explicitly define what the correct mapping is. E.g. by adding goverter:enum:map DefaultStatus DefaultUserStatus goverter:enum:map StatusActive DefaultUserStatus See https://goverter.jmattheis.de/guide/enum#mapping-enum-keys ```


Are your enums created manually or generated by another tool (if yes, which one)?