jmattheis / goverter

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

add sub context to support combining nested automap and rename #79

Closed goghcrow closed 12 months ago

goghcrow commented 1 year ago

When I Combine automap and fieldmap, it doesn't work

// goverter:converter
type Converter interface {
    // goverter:map . Address
    // goverter:map Street Address.StreetName
    Convert(FlatPerson) Person
}

type FlatPerson struct {
    Name    string
    Age     int
    Street  string
    ZipCode string
}

type Person struct {
    Name string
    Age  int
    Address
}
type Address struct {
    StreetName string
    ZipCode    string
}

the error message was as follows

| github.com/jmattheis/goverter/example/nested.FlatPerson
|
|      | goverter:map . Address
|      |
|      |
|      |
source.       .???
target.Address.StreetName
|      |       |
|      |       | string
|      |
|      | github.com/jmattheis/goverter/example/nested.Address
|
| github.com/jmattheis/goverter/example/nested.Person

Cannot match the target field with the source entry: "StreetName" does not exist.

The solution might be to add the sub context when createing subMethod

It works fine.

package generated

import nested "github.com/jmattheis/goverter/example/nested"

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source nested.FlatPerson) nested.Person {
    var nestedPerson nested.Person
    nestedPerson.Name = source.Name
    nestedPerson.Age = source.Age
    nestedPerson.Address = c.nestedFlatPersonToNestedAddress(source)
    return nestedPerson
}
func (c *ConverterImpl) nestedFlatPersonToNestedAddress(source nested.FlatPerson) nested.Address {
    var nestedAddress nested.Address
    nestedAddress.StreetName = source.Street
    nestedAddress.ZipCode = source.ZipCode
    return nestedAddress
}

It works fine, too, and even handles nested cases. But I don't know if there are other problems

// goverter:converter
type Converter interface {
    // goverter:map . Address
    // goverter:map . Address.StreetInfo
    // goverter:map Street Address.StreetInfo.Name
    Convert(FlatPerson) Person
}

type FlatPerson struct {
    Name    string
    Age     int
    Street  string
    ZipCode string
}

type Person struct {
    Name string
    Age  int
    Address
}
type Address struct {
    StreetInfo
    ZipCode string
}
type StreetInfo struct {
    Name string
}

generated

package generated

import nested "github.com/jmattheis/goverter/example/nested"

type ConverterImpl struct{}

func (c *ConverterImpl) Convert(source nested.FlatPerson) nested.Person {
    var nestedPerson nested.Person
    nestedPerson.Name = source.Name
    nestedPerson.Age = source.Age
    nestedPerson.Address = c.nestedFlatPersonToNestedAddress(source)
    return nestedPerson
}
func (c *ConverterImpl) nestedFlatPersonToNestedAddress(source nested.FlatPerson) nested.Address {
    var nestedAddress nested.Address
    nestedAddress.StreetInfo = c.nestedFlatPersonToNestedStreetInfo(source)
    nestedAddress.ZipCode = source.ZipCode
    return nestedAddress
}
func (c *ConverterImpl) nestedFlatPersonToNestedStreetInfo(source nested.FlatPerson) nested.StreetInfo {
    var nestedStreetInfo nested.StreetInfo
    nestedStreetInfo.Name = source.Street
    return nestedStreetInfo
}
jmattheis commented 12 months ago

As described in https://github.com/jmattheis/goverter/issues/80#issuecomment-1669831502. The changes have some edge-cases that aren't properly handled