goverter icon indicating copy to clipboard operation
goverter copied to clipboard

mapping consts

Open soniah opened this issue 2 years ago • 3 comments

Hi Jannis, this is part question, part feature request, part "should I write this?".

If my target field should be set to a const, how would I do that? For example:

       const ageOfConsent = 18 
   
        type Input struct {
            Name string
        }

        type Output struct {
            Name2 string
            Age int
        }

Desired field mappings:

Input.Name -> OutPut.Name2
ageOfConsent -> Output.Age

I was wondering if I should attempt to write this (as a feature), but I'd be interested in your ideas. Here's a possible syntax:

        // goverter:converter
        type Converter interface {
            // goverter:const ageOfConsent:Age
            Convert(source Input) Output
        }

soniah avatar Jan 11 '22 04:01 soniah

Hey Sonia,

currently it should be possible to extend with a custom the converter with a custom method and set all the required fields and the missing one.

Regardless, I think a similar feature could improve the usage of this library a lot. I feel like a constant is too restricting.I propose something similar to the existing goverter:extend, but instead it targets the property of a struct.

type Input struct { Name string }

type Output struct { Name string; Age int }

// goverter:converter
type Converter interface {
    // goverter:mapExtend Age DefaultAge
    Convert(source Input) Output
}

func DefaultAge() int {
    return 18
}

At first glance, this may seem like a more verbose version of your proposal, but the benefit is that is can cover much more use-cases. F.ex, we could allow passing the source object into this function, then the /example/error could be improved. Currently, it works like this:

// goverter:converter
// goverter:extend ToAPIPerson
type Converter interface {
	ToAPIApartment(source DBApartment) APIApartment
}

func ToAPIPerson(value DBPerson) APIPerson {
	return APIPerson{
		ID:       value.ID,
		FullName: fmt.Sprintf("%s %s", value.FirstName, value.LastName),
	}
}

We define an extension function for the whole *Person object. With the new goverter:mapExtend it could be written like this:

// goverter:converter
type Converter interface {
    ToAPIApartment(source DBApartment) APIApartment
    // goverter:mapExtend FullName GetFullName
    ToAPIPerson(source DBPerson) APIPerson
}

func GetFullName(value DBPerson) string {
    return fmt.Sprintf("%s %s", value.FirstName, value.LastName)
}

This looks much better.

You could even use it to convert values, without the need to write the entire custom extension method.

type Input struct {
	Percent100Based float64
	// ... other fields
}

type Output struct {
	Percent1Based float64
	// ... other fields
}

// goverter:converter
type Converter interface {
	// goverter:mapExtend Percent1Based DivideBy100
	ToOutput(source Input) Output
}

func DivideBy100(source Input) float64 {
	return source.Percent100Based / 100
}

The first step would be to add goverter:mapExtend with support for only defining a method without arguments and one return value, which must be the same as the return type of the parameter that is defined inside goverter:mapExtend. The optional passing of the source value as first parameter should be done later. Maybe we could even allow passing a Converter instance, like it can be done in goverter:extend (https://github.com/jmattheis/goverter#reuse-generated-converter)

Also, I'm not fully satisfied with the name goverter:mapExtend maybe you've something better?

jmattheis avatar Jan 11 '22 19:01 jmattheis

@soniah This is possible to do in copygen:

  • Use the const as a parameter for the conversion method directly OR
  • Use the map directive: example OR
  • Use customized functions OR
  • Use converter functions, etc.

switchupcb avatar Feb 17 '22 03:02 switchupcb

Thanks @switchupcb that looks good. Sorry @jmattheis I haven't had time to work on the stuff above - work, family, etc...

soniah avatar Feb 19 '22 07:02 soniah