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

Combine nested automap and fieldmap #80

Open
goghcrow opened this issue Aug 7, 2023 · 3 comments
Open

Combine nested automap and fieldmap #80

goghcrow opened this issue Aug 7, 2023 · 3 comments
Labels
feature New feature or request

Comments

@goghcrow
Copy link

goghcrow commented Aug 7, 2023

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
PR

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 any 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
}

Please 👍 this issue if you like this functionality. If you have a specific use-case in mind, feel free to comment it.

@jmattheis
Copy link
Owner

You can already achieve the same generated code by doing the following:

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

	// goverter:map Street StreetName
	ConvertAddress(FlatPerson) Address
}

Sadly your solution isn't that easy, because it can clash with other definitions, imagine a converter like this

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

	// goverter:map Name StreetName
	ConvertAddress(FlatPerson) Address
}

What should be the value for StreetName (Name or Street). I'm not fully against a change like this, but goverter must fail with a readable error when there are conflicting definitions.

@goghcrow
Copy link
Author

goghcrow commented Aug 9, 2023

It still don't work when FlatPerson is ptr. It's a simplified version of my actual scenario.

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

	// goverter:map Street StreetName
	ConvertAddress(*FlatPerson) Address
}
| *github.com/jmattheis/goverter/example/nested.FlatPerson
|
|     | 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
|
| *github.com/jmattheis/goverter/example/nested.Person

@jmattheis
Copy link
Owner

Try defining it as

// goverter:map Street StreetName
ConvertAddress(FlatPerson) Address

See the mapping in the error message. It first does source* which is a non pointer and then the goverter:map . Address is used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants