Input and output formats
Goverter supports three different input output format combinations. This guide is for you to decide the formats you want to use.
interface to struct
This is the default when using goverter:converter
.
Pros:
- All goverter features are supported
- The interface is usable before goverter generated the implementation.
- reduces the occurence of compile errors because of missing or outdated generated implementation.
- allows using generated methods in custom methods
Cons:
- You need to initialize the implementation.
- You need to call methods on the struct to execute conversions
Example (click me)
go
package house
import (
"database/sql"
"github.com/jmattheis/goverter/example/format/common"
)
// goverter:converter
// goverter:output:format struct
// goverter:extend SQLStringToPString
// goverter:extend ConvertToApartmentMap
type Converter interface {
ConvertHouse(source common.DBHouse) common.APIHouse
// goverter:map Owner.Name OwnerName
ConvertApartment(source common.DBApartment) common.APIApartment
// goverter:map Name FirstName
// goverter:ignore Age
ConvertPerson(source common.DBPerson) common.APIPerson
}
func SQLStringToPString(value sql.NullString) *string {
if value.Valid {
return &value.String
}
return nil
}
func ConvertToApartmentMap(c Converter, source []common.DBApartment) map[uint]common.APIApartment {
m := make(map[uint]common.APIApartment)
for _, apartment := range source {
m[apartment.Position] = c.ConvertApartment(apartment) // !! this is not supported in some formats
}
return m
}
go
package common
import "database/sql"
type DBHouse struct {
Address string
Apartments []DBApartment
}
type DBApartment struct {
Position uint
Owner DBPerson
CoResident []DBPerson
}
type DBPerson struct {
ID int
Name string
MiddleName sql.NullString
Friends []DBPerson
Info Info
}
type APIHouse struct {
Address string
Apartments map[uint]APIApartment
}
type APIApartment struct {
Position uint
Owner APIPerson
OwnerName string
CoResident []APIPerson
}
type APIPerson struct {
ID int
MiddleName *string
FirstName *string
Friends []APIPerson
Info Info
Age int
}
type Info struct {
Birthplace string
}
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter
package generated
import (
common "github.com/jmattheis/goverter/example/format/common"
interfacetostruct "github.com/jmattheis/goverter/example/format/interfacetostruct"
)
type ConverterImpl struct{}
func (c *ConverterImpl) ConvertApartment(source common.DBApartment) common.APIApartment {
var commonAPIApartment common.APIApartment
commonAPIApartment.Position = source.Position
commonAPIApartment.Owner = c.ConvertPerson(source.Owner)
commonAPIApartment.OwnerName = source.Owner.Name
if source.CoResident != nil {
commonAPIApartment.CoResident = make([]common.APIPerson, len(source.CoResident))
for i := 0; i < len(source.CoResident); i++ {
commonAPIApartment.CoResident[i] = c.ConvertPerson(source.CoResident[i])
}
}
return commonAPIApartment
}
func (c *ConverterImpl) ConvertHouse(source common.DBHouse) common.APIHouse {
var commonAPIHouse common.APIHouse
commonAPIHouse.Address = source.Address
commonAPIHouse.Apartments = interfacetostruct.ConvertToApartmentMap(c, source.Apartments)
return commonAPIHouse
}
func (c *ConverterImpl) ConvertPerson(source common.DBPerson) common.APIPerson {
var commonAPIPerson common.APIPerson
commonAPIPerson.ID = source.ID
commonAPIPerson.MiddleName = interfacetostruct.SQLStringToPString(source.MiddleName)
pString := source.Name
commonAPIPerson.FirstName = &pString
if source.Friends != nil {
commonAPIPerson.Friends = make([]common.APIPerson, len(source.Friends))
for i := 0; i < len(source.Friends); i++ {
commonAPIPerson.Friends[i] = c.ConvertPerson(source.Friends[i])
}
}
commonAPIPerson.Info = c.commonInfoToCommonInfo(source.Info)
return commonAPIPerson
}
func (c *ConverterImpl) commonInfoToCommonInfo(source common.Info) common.Info {
var commonInfo common.Info
commonInfo.Birthplace = source.Birthplace
return commonInfo
}
variables to assign-variable
This is the default when using goverter:variables
.
Pros:
- All goverter features are supported.
- The variables are usable before goverter generated the implementation.
- reduces the occurence of compile errors because of missing or outdated generated implementation.
- allows using generated functions in custom methods
- You can execute conversions directly without having to initializing a struct
Cons:
- Possible runtime overhead when Go cannot optimizen variables the same as functions. Benchmark your use-case, if speed is really important to you.
Example (click me)
go
package house
import (
"database/sql"
"github.com/jmattheis/goverter/example/format/common"
)
// goverter:variables
// goverter:output:format assign-variable
// goverter:extend SQLStringToPString
// goverter:extend ConvertToApartmentMap
var (
ConvertHouse func(source common.DBHouse) common.APIHouse
// goverter:map Name FirstName
// goverter:ignore Age
ConvertPerson func(source common.DBPerson) common.APIPerson
// goverter:map Owner.Name OwnerName
ConvertApartment func(source common.DBApartment) common.APIApartment
)
func SQLStringToPString(value sql.NullString) *string {
if value.Valid {
return &value.String
}
return nil
}
func ConvertToApartmentMap(source []common.DBApartment) map[uint]common.APIApartment {
m := make(map[uint]common.APIApartment)
for _, apartment := range source {
m[apartment.Position] = ConvertApartment(apartment) // !! this is not supported in some formats
}
return m
}
go
package common
import "database/sql"
type DBHouse struct {
Address string
Apartments []DBApartment
}
type DBApartment struct {
Position uint
Owner DBPerson
CoResident []DBPerson
}
type DBPerson struct {
ID int
Name string
MiddleName sql.NullString
Friends []DBPerson
Info Info
}
type APIHouse struct {
Address string
Apartments map[uint]APIApartment
}
type APIApartment struct {
Position uint
Owner APIPerson
OwnerName string
CoResident []APIPerson
}
type APIPerson struct {
ID int
MiddleName *string
FirstName *string
Friends []APIPerson
Info Info
Age int
}
type Info struct {
Birthplace string
}
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter
package house
import common "github.com/jmattheis/goverter/example/format/common"
func init() {
ConvertApartment = func(source common.DBApartment) common.APIApartment {
var commonAPIApartment common.APIApartment
commonAPIApartment.Position = source.Position
commonAPIApartment.Owner = ConvertPerson(source.Owner)
commonAPIApartment.OwnerName = source.Owner.Name
if source.CoResident != nil {
commonAPIApartment.CoResident = make([]common.APIPerson, len(source.CoResident))
for i := 0; i < len(source.CoResident); i++ {
commonAPIApartment.CoResident[i] = ConvertPerson(source.CoResident[i])
}
}
return commonAPIApartment
}
ConvertHouse = func(source common.DBHouse) common.APIHouse {
var commonAPIHouse common.APIHouse
commonAPIHouse.Address = source.Address
commonAPIHouse.Apartments = ConvertToApartmentMap(source.Apartments)
return commonAPIHouse
}
ConvertPerson = func(source common.DBPerson) common.APIPerson {
var commonAPIPerson common.APIPerson
commonAPIPerson.ID = source.ID
commonAPIPerson.MiddleName = SQLStringToPString(source.MiddleName)
pString := source.Name
commonAPIPerson.FirstName = &pString
if source.Friends != nil {
commonAPIPerson.Friends = make([]common.APIPerson, len(source.Friends))
for i := 0; i < len(source.Friends); i++ {
commonAPIPerson.Friends[i] = ConvertPerson(source.Friends[i])
}
}
commonAPIPerson.Info = commonInfoToCommonInfo(source.Info)
return commonAPIPerson
}
}
func commonInfoToCommonInfo(source common.Info) common.Info {
var commonInfo common.Info
commonInfo.Birthplace = source.Birthplace
return commonInfo
}
interface to functions
Pros:
- You can execute conversions directly without having to initializing a struct
Cons:
- The interface is only used for defining the conversions and is otherwise not usable
- The use-case
map
method with converter is unsupported without replacement.
Example (click me)
go
package house
import (
"database/sql"
"github.com/jmattheis/goverter/example/format/common"
)
// goverter:converter
// goverter:output:format function
// goverter:extend SQLStringToPString
type Converter interface {
// goverter:map Owner.Name OwnerName
ConvertApartment(source common.DBApartment) common.APIApartment
// goverter:map Name FirstName
// goverter:ignore Age
ConvertPerson(source common.DBPerson) common.APIPerson
}
func SQLStringToPString(value sql.NullString) *string {
if value.Valid {
return &value.String
}
return nil
}
go
package common
import "database/sql"
type DBHouse struct {
Address string
Apartments []DBApartment
}
type DBApartment struct {
Position uint
Owner DBPerson
CoResident []DBPerson
}
type DBPerson struct {
ID int
Name string
MiddleName sql.NullString
Friends []DBPerson
Info Info
}
type APIHouse struct {
Address string
Apartments map[uint]APIApartment
}
type APIApartment struct {
Position uint
Owner APIPerson
OwnerName string
CoResident []APIPerson
}
type APIPerson struct {
ID int
MiddleName *string
FirstName *string
Friends []APIPerson
Info Info
Age int
}
type Info struct {
Birthplace string
}
go
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
//go:build !goverter
package generated
import (
common "github.com/jmattheis/goverter/example/format/common"
interfacefunction "github.com/jmattheis/goverter/example/format/interfacefunction"
)
func ConvertApartment(source common.DBApartment) common.APIApartment {
var commonAPIApartment common.APIApartment
commonAPIApartment.Position = source.Position
commonAPIApartment.Owner = ConvertPerson(source.Owner)
commonAPIApartment.OwnerName = source.Owner.Name
if source.CoResident != nil {
commonAPIApartment.CoResident = make([]common.APIPerson, len(source.CoResident))
for i := 0; i < len(source.CoResident); i++ {
commonAPIApartment.CoResident[i] = ConvertPerson(source.CoResident[i])
}
}
return commonAPIApartment
}
func ConvertPerson(source common.DBPerson) common.APIPerson {
var commonAPIPerson common.APIPerson
commonAPIPerson.ID = source.ID
commonAPIPerson.MiddleName = interfacefunction.SQLStringToPString(source.MiddleName)
pString := source.Name
commonAPIPerson.FirstName = &pString
if source.Friends != nil {
commonAPIPerson.Friends = make([]common.APIPerson, len(source.Friends))
for i := 0; i < len(source.Friends); i++ {
commonAPIPerson.Friends[i] = ConvertPerson(source.Friends[i])
}
}
commonAPIPerson.Info = commonInfoToCommonInfo(source.Info)
return commonAPIPerson
}
func commonInfoToCommonInfo(source common.Info) common.Info {
var commonInfo common.Info
commonInfo.Birthplace = source.Birthplace
return commonInfo
}