gomappergen

package module
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2026 License: MIT Imports: 30 Imported by: 0

README

go-mapper-gen

Go Report Card


go-mapper-gen is a type-safe code generator for Go that automates mappings between different struct types such as domain entities ↔︎ database models or API ↔︎ internal representations.

It uses pkl as a modern, schema-driven configuration language, providing strong validation, clear semantics, and IDE auto-completion when defining mappings.

Highlights

  • 🔒 Type-safe code generation with compile-time guarantees.
  • 🧘 Flexible output: functions or interface/implementation pairs.
  • 💪 Strongly typed pkl configuration schema with IDE support.
  • 🧰 Built-in support for common field types, extensible via custom functions.
  • 🛠️ Can be used as a standalone CLI or embedded as a Go library.

Quickstart

Firstly, let set up a project which uses sqlc and pgtype

module github.com/toniphan21/go-mapper-gen/basic

go 1.25

require github.com/jackc/pgx/v5 v5.7.6

the go.sum file is

github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=

Given that you have an entity located in your domain package:

// file: domain/entity.go
//go:generate go run github.com/toniphan21/go-mapper-gen/cmd/generator

package domain

type User struct {
    ID        string
    FirstName string
    LastName  string
    Email     string
    Password  *string
}

and another struct perhaps generated from your database using tool such as sqlc located in db

// file: db/models.go

package db

import "github.com/jackc/pgx/v5/pgtype"

type User struct {
    ID        string
    Email     string
    FirstName string
    LastName  string
    Password  pgtype.Text
}

Default mode: types (interface + implementation)

With this minimal configuration, go-mapper-gen generates an unexported interface and implementation with methods to convert both ways.

// file: mapper.pkl
amends "https://github.com/toniphan21/go-mapper-gen/releases/download/current/Config.pkl"

local function package(path: String) = "github.com/toniphan21/go-mapper-gen/basic/" + path

packages {
	[package("db")] {
		source_pkg = package("domain")

		structs {
			["User"] {}
		}
	}
}

To generate code:

  • Run go generate ./..., or
  • Invoke directly: go run github.com/toniphan21/go-mapper-gen/cmd/generator (from the module root)

This produces mapping code (by default in the target package) and keeps names unexported to avoid polluting your API surface.

// golden-file: db/gen_mapper.go
// Code generated by github.com/toniphan21/go-mapper-gen - test, DO NOT EDIT.

package db

import (
	pgtype "github.com/jackc/pgx/v5/pgtype"
	domain "github.com/toniphan21/go-mapper-gen/basic/domain"
)

type iMapper interface {
	// ToUser converts a domain.User value into a User value.
	ToUser(in domain.User) User

	// FromUser converts a User value into a domain.User value.
	FromUser(in User) domain.User
}

func new_iMapper() iMapper {
	return &iMapperImpl{}
}

type iMapperImpl struct{}

func (m *iMapperImpl) ToUser(in domain.User) User {
	var out User

	out.ID = in.ID
	out.Email = in.Email
	out.FirstName = in.FirstName
	out.LastName = in.LastName
	if in.Password != nil {
		out.Password = pgtype.Text{
			String: *in.Password,
			Valid:  true,
		}
	}

	return out
}

func (m *iMapperImpl) FromUser(in User) domain.User {
	var out domain.User

	out.ID = in.ID
	out.FirstName = in.FirstName
	out.LastName = in.LastName
	out.Email = in.Email
	if in.Password.Valid {
		out.Password = &in.Password.String
	}

	return out
}

var _ iMapper = (*iMapperImpl)(nil)

Use via composition to keep your API clean:

// file: db/mapper.go
var mapper = new_iMapper()

func demo() {
    _ = mapper.ToUser(/* ... */)
}

// Or expose your own interface that embeds the generated one
type Mapper interface { iMapper }

You can customize names (interface, implementation, constructor) in the Pkl config. See Config.pkl, mapper.pkl for all options.


Functional mode: package-level functions

Switch to functions mode to emit only functions:

// file: mapper.pkl
amends "https://github.com/toniphan21/go-mapper-gen/releases/download/current/Config.pkl"

local function package(path: String) = "github.com/toniphan21/go-mapper-gen/basic/" + path

packages {
	[package("db")] {
		mode = "functions"
		source_pkg = package("domain")

		structs {
			["User"] {}
		}
	}
}

This yields functions like ToUser and FromUser in the target package:

// golden-file: db/gen_mapper.go
// Code generated by github.com/toniphan21/go-mapper-gen - test, DO NOT EDIT.

package db

import (
	pgtype "github.com/jackc/pgx/v5/pgtype"
	domain "github.com/toniphan21/go-mapper-gen/basic/domain"
)

// ToUser converts a domain.User value into a User value.
func ToUser(in domain.User) User {
	var out User

	out.ID = in.ID
	out.Email = in.Email
	out.FirstName = in.FirstName
	out.LastName = in.LastName
	if in.Password != nil {
		out.Password = pgtype.Text{
			String: *in.Password,
			Valid:  true,
		}
	}

	return out
}

// FromUser converts a User value into a domain.User value.
func FromUser(in User) domain.User {
	var out domain.User

	out.ID = in.ID
	out.FirstName = in.FirstName
	out.LastName = in.LastName
	out.Email = in.Email
	if in.Password.Valid {
		out.Password = &in.Password.String
	}

	return out
}

Next Steps

Take a look at examples of how to:


Contributing & Licence

PRs are welcome! See the CONTRIBUTING. Distributed under the MIT License.

❤️ Like the project? Buy me a coffee ☕. Thank you!

Documentation

Index

Constants

View Source
const BinaryName = "github.com/toniphan21/go-mapper-gen"
View Source
const CommentWidth = 80

Variables

View Source
var BuiltinConverters = builtinConverters{
	IdenticalType:   &identicalTypeConverter{},
	Slice:           &sliceConverter{},
	TypeToPointer:   &typeToPointerConverter{},
	PointerToType:   &pointerToTypeConverter{},
	Numeric:         &numericConverter{},
	Functions:       &functionsConverter{},
	FunctionsStrict: &strictFunctionsConverter{},
}
View Source
var BuiltinFieldInterceptor = builtinFieldInterceptor{
	NilIfZero: &nilIfZeroFieldInterceptor{},
	UseFunction: func(symbol string) FieldInterceptor {
		return &useFunctionFieldInterceptor{
			symbol: symbol,
		}
	},
	UseMethod: func(variableSymbol string, methodName string) FieldInterceptor {
		return &useFunctionFieldInterceptor{
			symbol: variableSymbol,
			method: methodName,
		}
	},
}
View Source
var Default = defaultCfValue{
	Output: Output{
		PkgName:      Placeholder.CurrentPackageName,
		FileName:     "gen_mapper.go",
		TestFileName: "gen_mapper_test.go",
	},
	Mode:                     ModeTypes,
	InterfaceName:            "iMapper",
	ImplementationName:       "iMapperImpl",
	ConstructorName:          "new_iMapper",
	SourceToTargetFuncName:   "To{TargetStructName}",
	SourceFromTargetFuncName: "From{TargetStructName}",
	DecoratorMode:            DecoratorModeAdaptive,
	DecoratorInterfaceName:   "iMapperDecorator",
	DecoratorNoOpName:        "iMapperDecoratorNoOp",
	DecorateFuncName:         "decorate{FunctionName}",
	TargetPkgPath:            Placeholder.CurrentPackage,
}
View Source
var GeneratorUtil = &genUtil{}
View Source
var LookUpTotalHits uint64
View Source
var Placeholder = cfPlaceHolder{
	TargetStructName:   "{TargetStructName}",
	SourceStructName:   "{SourceStructName}",
	CurrentPackage:     "{CurrentPackage}",
	CurrentPackageName: "{CurrentPackageName}",
	FunctionName:       "{FunctionName}",
}
View Source
var Test = &testHelper{
	goldenTest:    &goldenTest{},
	converterTest: &converterTest{},
	bddTest:       &bddTest{},
}
View Source
var TypeUtil = &typeUtil{}

Functions

func ClearAllRegisteredConverters

func ClearAllRegisteredConverters()

func EnableLookUpCache

func EnableLookUpCache()

func NewNoopLogger

func NewNoopLogger() *slog.Logger

func PrintRegisteredConverters

func PrintRegisteredConverters(logger *slog.Logger)

func RegisterAllBuiltinConverters

func RegisterAllBuiltinConverters()

func RegisterBuiltinConverters

func RegisterBuiltinConverters(config BuiltInConverterConfig)

func RegisterConverter

func RegisterConverter(converter Converter)

RegisterConverter adds a new Converter to the global converter registry.

Converters are selected by the mapper generator based on:

  1. Whether they report true from CanConvert(...)
  2. Their assigned priority (use converter { priority = List(...) } config)

The priority determines via converter { priority } configuration. The ordering between converters that can handle the same source and target types.

Registering a converter does not trigger any generation work. It merely appends the converter to the internal registry so that the code generator can discover it later.

Converters should be stateless and safe for repeated reuse. The registry is typically read during generator initialization or when resolving the appropriate converter for a given assignment.

Example:

RegisterConverter(&StringToIntConverter{})

Passing the same converter instance multiple times is allowed but generally discouraged unless intentional.

func UseTestVersion

func UseTestVersion()

func Version

func Version() string

Types

type BuiltInConverterConfig

type BuiltInConverterConfig struct {
	UseIdentical       bool
	UseSlice           bool
	UseTypeToPointer   bool
	UsePointerToType   bool
	UseNumeric         bool
	UseFunctions       bool
	UseFunctionsStrict bool
}

func (*BuiltInConverterConfig) EnableAll

func (c *BuiltInConverterConfig) EnableAll()

type Config

type Config struct {
	BuiltInConverters   BuiltInConverterConfig
	LibraryConverters   LibraryConverterConfig
	ConverterFunctions  []ConvertFunctionConfig
	ConverterPriorities []string
	Packages            map[string][]PackageConfig
}

func MakeConfig added in v0.4.0

func MakeConfig(cfg pkl.Config, provider FieldInterceptorProvider) (*Config, error)

func ParseConfig

func ParseConfig(path string, provider FieldInterceptorProvider) (*Config, error)

type ConfigMapper added in v0.7.0

type ConfigMapper struct {
	Provider FieldInterceptorProvider
}

func (*ConfigMapper) MapBuiltInConverterConfig added in v0.7.0

func (m *ConfigMapper) MapBuiltInConverterConfig(in mapper.BuiltInConverter) BuiltInConverterConfig

func (*ConfigMapper) MapConverterFunctions added in v0.7.0

func (m *ConfigMapper) MapConverterFunctions(list *[]string) []ConvertFunctionConfig

func (*ConfigMapper) MapLibraryConverterConfig added in v0.7.0

func (m *ConfigMapper) MapLibraryConverterConfig(in mapper.BuiltInConverter) LibraryConverterConfig

func (*ConfigMapper) MapPackagesConfig added in v0.7.0

func (m *ConfigMapper) MapPackagesConfig(packages map[string]pkl.Package, all pkl.All) (map[string][]PackageConfig, error)

type ConvertFunctionConfig

type ConvertFunctionConfig struct {
	PackagePath string
	TypeName    string
}

type Converter

type Converter interface {
	// Init is called once before code generation starts.
	// It allows the converter to initialize internal state, validate assumptions,
	// or prepare data required during code generation. Init must not emit code.
	// If no initialization is required, the implementation may be a no-op.
	Init(parser Parser, config Config, logger *slog.Logger)

	// Info returns metadata describing the converter.
	Info() ConverterInfo

	// CanConvert reports whether this converter can convert a value of
	// sourceType into a value of targetType. Implementations typically use
	// TypeUtil to perform type analysis.
	//
	// CanConvert must be pure and must not modify file state.
	CanConvert(ctx LookupContext, targetType, sourceType types.Type) bool

	// ConvertField emits the assignment code that writes the converted value from
	// source into target. Returning nil suppresses emission.
	//
	// GeneratorUtil may be used to build complex expression trees.
	ConvertField(ctx ConverterContext, target, source Symbol) jen.Code
}

Converter defines the contract for converting a source value or field into a target value or field during code generation.

type ConverterContext

type ConverterContext interface {
	context.Context
	LookupContext

	// JenFile returns the current jennifer file used for code generation.
	// Converters may append generated code to this file.
	JenFile() *jen.File

	// Parser returns the type parser used to inspect and analyze Go types
	// during conversion.
	Parser() Parser

	// NextVarName returns a unique variable name for use in generated code.
	// It guarantees no name collisions within the current generation scope.
	NextVarName() string

	// Run executes runner if the context has not been cancelled.
	// If the context is done, Run returns nil and runner is not executed.
	// This allows converters to respect generator-defined timeouts without
	// explicitly checking ctx.Done().
	Run(converter Converter, runner func() jen.Code) jen.Code

	// EmitTraceComments indicates whether the converter should emit trace comments
	// for debugging or inspection purposes. It returns false by default.
	EmitTraceComments() bool
}

ConverterContext provides shared capabilities and state for converters during code generation. It embeds context.Context to support cancellation and timeouts defined by the generator.

type ConverterInfo

type ConverterInfo struct {
	Name                 string
	ShortForm            string
	ShortFormDescription string
}

ConverterInfo describes metadata about a Converter. It is primarily used for debugging, logging, and trace comments in generated code.

type ConverterTestCase

type ConverterTestCase struct {
	Name                         string
	AdditionalCode               []string
	Config                       *Config
	Imports                      map[string]string
	GoModGoVersion               string
	GoModRequires                map[string]string
	GoModModule                  string
	TargetType                   string
	SourceType                   string
	EmitTraceComments            bool
	TargetSymbolWithoutFieldName bool
	SourceSymbolWithoutFieldName bool
	TargetSymbolMetadata         SymbolMetadata
	SourceSymbolMetadata         SymbolMetadata
	ExpectedCanConvert           bool
	ExpectedImports              []string
	ExpectedCode                 []string
	PrintSetUp                   bool
}

type DecoratorMode

type DecoratorMode int
const (
	DecoratorModeAdaptive DecoratorMode = iota
	DecoratorModeNever
	DecoratorModeAlways
)

type Descriptor added in v0.5.0

type Descriptor struct {
	// contains filtered or unexported fields
}

func (*Descriptor) FieldIndex added in v0.5.0

func (d *Descriptor) FieldIndex() int

func (*Descriptor) FieldName added in v0.5.0

func (d *Descriptor) FieldName() string

func (*Descriptor) FieldType added in v0.5.0

func (d *Descriptor) FieldType() types.Type

func (*Descriptor) StructFields added in v0.5.0

func (d *Descriptor) StructFields() map[string]StructFieldInfo

func (*Descriptor) StructType added in v0.5.0

func (d *Descriptor) StructType() types.Type

type FieldConfig

type FieldConfig struct {
	NameMatch NameMatch
	ManualMap map[string]string
}

func (FieldConfig) Flip

func (c FieldConfig) Flip() FieldConfig

type FieldInterceptor added in v0.5.0

type FieldInterceptor interface {
	GetType() string

	GetOptions() map[string]any

	Init(parser Parser, logger *slog.Logger)

	InterceptCanConvert(converter Converter, ctx LookupContext, targetType, sourceType types.Type) bool

	InterceptConvertField(converter Converter, ctx ConverterContext, target, source Symbol) jen.Code
}

type FieldInterceptorProvider added in v0.5.0

type FieldInterceptorProvider interface {
	MakeFieldInterceptor(typ string, options map[string]any) FieldInterceptor
}

func DefaultFieldInterceptorProvider added in v0.5.0

func DefaultFieldInterceptorProvider() FieldInterceptorProvider

type FileManager

type FileManager interface {
	MakeJenFile(parser Parser, currentPkg *packages.Package, config PackageConfig) *jen.File

	JenFiles() map[string]*jen.File
}

func DefaultFileManager

func DefaultFileManager() FileManager

type FuncInfo

type FuncInfo struct {
	Name        string
	PackagePath string
	Params      []types.Type
	Results     []types.Type
}

type GeneratedTypeOrchestrator

type GeneratedTypeOrchestrator struct {
	Generated TypeInfo
	Target    TypeInfo

	GeneratedToTarget        func(ctx ConverterContext, target, source Symbol) jen.Code
	GeneratedToTargetToOther func(ctx ConverterContext, target, source Symbol, targetToOther Converter) jen.Code
	TargetToGenerated        func(ctx ConverterContext, target, source Symbol) jen.Code
	OtherToTargetToGenerated func(ctx ConverterContext, target, source Symbol, otherToTarget Converter) jen.Code
	// contains filtered or unexported fields
}

GeneratedTypeOrchestrator is simpler version of StandardConversionOrchestrator which one side is fixed. It provides 4 ways of conversion

For example: Given you want to convert A -> B, A is a generated type which usually provided via a generated tool such as grpc or sqlc. GeneratedTypeOrchestrator provides 4 routing ways:

  1. GeneratedToTarget A -> B
  2. GeneratedToTargetToOther A -> B -> T if B -> T possible
  3. TargetToGenerated B -> A
  4. OtherToTargetToGenerated T -> B -> A if T -> B possible

Usage: In your Converter.Init():

```

 	// similar to StandardConversionOrchestrator, you can simply set nil if you don't want to match the route
	c.orchestrator = gen.GeneratedTypeOrchestrator{
			Generated:					Generated type, aka. A's type info,
			Target:                		B's type info,
			GeneratedToTarget:			func to emit code when match route 1) A -> B
			GeneratedToTargetToOther:	func to emit code when match route 2) A -> B -> T
			TargetToGenerated:			func to emit code when match route 3) B -> A
			OtherToTargetToGenerated:	func to emit code when match route 4) T -> B -> A
	}

``` Then in your Converter.CanConvert() ```

return c.orchestrator.CanConvert(c, ctx, targetType, sourceType)

``` and in your Converter.ConvertField()

```

return ctx.Run(c, opts, func() jen.Code {
	return c.orchestrator.PerformConvert(c, ctx, target, source, opts)
})

``` The GeneratedTypeOrchestrator actually just a wrapper of StandardConversionOrchestrator.

func (*GeneratedTypeOrchestrator) CanConvert

func (o *GeneratedTypeOrchestrator) CanConvert(c Converter, ctx LookupContext, targetType, sourceType types.Type) bool

func (*GeneratedTypeOrchestrator) PerformConvert

func (o *GeneratedTypeOrchestrator) PerformConvert(c Converter, ctx ConverterContext, target, source Symbol) jen.Code

type Generator

type Generator interface {
	Generate(currentPkg *packages.Package, configs []PackageConfig) error
}

func New

func New(parser Parser, config Config, options ...OptionFunc) Generator

type GoldenTestCase

type GoldenTestCase struct {
	Name                     string
	GoModFileContent         []byte
	GoSumFileContent         []byte
	PklDevFileContent        []byte
	SourceFiles              map[string][]byte
	GoldenFiles              map[string][]byte
	PrintSetup               bool
	PrintActual              bool
	PrintDiff                bool
	FieldInterceptorProvider FieldInterceptorProvider
}

type GoldenTestCaseFromTestData

type GoldenTestCaseFromTestData struct {
	Name             string
	PkgPath          string
	GoModGoVersion   string
	GoModRequires    map[string]string
	GoModModule      string
	GoSumFileContent []byte
	SourceFiles      map[string]string
	PklFile          string
	GoldenFile       string
	OutputFileName   string
	PrintSetup       bool
	PrintActual      bool
	PrintDiff        bool
}

func (*GoldenTestCaseFromTestData) ToGoldenTestCase

func (g *GoldenTestCaseFromTestData) ToGoldenTestCase() GoldenTestCase

type GoldenTestCaseRunOptions

type GoldenTestCaseRunOptions struct {
	SetupConverter func()
}

type GoldenTestCaseRunOptionsFunc

type GoldenTestCaseRunOptionsFunc func(opts *GoldenTestCaseRunOptions)

func TestWithSetupConverter

func TestWithSetupConverter(fn func()) GoldenTestCaseRunOptionsFunc

type LibraryConverterConfig

type LibraryConverterConfig struct {
	UseGRPC   bool
	UsePGType bool
	UseSQL    bool
}

type LookupContext

type LookupContext interface {
	// LookUp searches the global converter registry for a converter that
	// can convert a value of sourceType to targetType, excluding the provided
	// currentConverter (if non-nil).
	//
	// This helper is intended for converter implementations that need to
	// delegate or reuse existing conversion rules. A common use-case is a
	// SliceConverter that converts []T -> []V by looking up a converter for
	// T -> V and then generating per-element conversion code.
	//
	// Selection rules (implementation contract):
	//  1. The registry is scanned for converters c where c.CanConvert(targetType, sourceType)
	//     returns true.
	//  2. The currentConverter parameter is excluded from consideration to avoid
	//     trivial self-selection (if currentConverter == nil, no exclusion occurs).
	//  3. From the remaining candidates, the converter with the highest priority
	//     (your package's ordering rule: lower numeric value = higher priority)
	//     is chosen. If multiple converters share the same priority, the selection
	//     must be deterministic (for example: registration order or stable sorting).
	//
	// Return value:
	//   - (Converter, true) if a matching converter was found.
	//   - (nil, false) if no converter in the registry can perform the conversion.
	LookUp(current Converter, targetType, sourceType types.Type) (Converter, error)

	TargetDescriptor() *Descriptor

	SourceDescriptor() *Descriptor

	// Logger returns a slog handler that can be used for logging during
	// code generation.
	Logger() *slog.Logger
}

type MarkdownTestCase

type MarkdownTestCase struct {
	Name              string
	Content           string
	Headers           []string
	SourceFiles       map[string][]byte
	GoldenFiles       map[string][]byte
	GoModFileContent  []byte
	GoSumFileContent  []byte
	PklDevFileContent []byte
}

func (*MarkdownTestCase) IsNameMatch

func (tc *MarkdownTestCase) IsNameMatch(term string) bool

func (*MarkdownTestCase) ToGoldenTestCase

func (tc *MarkdownTestCase) ToGoldenTestCase() GoldenTestCase

type Mode

type Mode int
const (
	ModeTypes Mode = iota
	ModeFunctions
)

type NameMatch

type NameMatch int
const (
	NameMatchIgnoreCase NameMatch = iota
	NameMatchExact
)

type OptionFunc

type OptionFunc func(*Options)

func WithFileManager

func WithFileManager(fileManager FileManager) OptionFunc

func WithLogger

func WithLogger(logger *slog.Logger) OptionFunc

type Options

type Options struct {
	Parser      Parser
	FileManager FileManager
	Logger      *slog.Logger
}

type Output

type Output struct {
	PkgName      string
	FileName     string
	TestFileName string
}

type PackageConfig

type PackageConfig struct {
	Mode                   Mode
	Output                 Output
	InterfaceName          string
	ImplementationName     string
	ConstructorName        string
	DecoratorInterfaceName string
	DecoratorNoOpName      string
	Structs                []StructConfig
	GenerateGoDoc          bool
}

type Parser

type Parser interface {
	SourceDir() string

	SourcePackages() []*packages.Package

	FindStruct(pkgPath string, name string) (StructInfo, bool)

	FindFunction(pkgPath string, name string) (FuncInfo, bool)

	FindVariableMethods(pkgPath string, name string) []FuncInfo
}

func DefaultParser

func DefaultParser(dir string) (Parser, error)

type Pointer

type Pointer int
const (
	PointerNone Pointer = iota
	PointerSourceOnly
	PointerTargetOnly
	PointerBoth
)

type StandardConversionOrchestrator

type StandardConversionOrchestrator struct {
	Source TypeInfo
	Target TypeInfo

	SourceToTarget               func(ctx ConverterContext, target, source Symbol) jen.Code
	OtherToSourceToTarget        func(ctx ConverterContext, target, source Symbol, otherToSource Converter) jen.Code
	SourceToTargetToOther        func(ctx ConverterContext, target, source Symbol, targetToOther Converter) jen.Code
	OtherToSourceToTargetToOther func(ctx ConverterContext, target, source Symbol, otherToSource, targetToOther Converter) jen.Code

	TargetToSource               func(ctx ConverterContext, target, source Symbol) jen.Code
	OtherToTargetToSource        func(ctx ConverterContext, target, source Symbol, otherToTarget Converter) jen.Code
	TargetToSourceToOther        func(ctx ConverterContext, target, source Symbol, sourceToOther Converter) jen.Code
	OtherToTargetToSourceToOther func(ctx ConverterContext, target, source Symbol, otherToTarget, sourceToOther Converter) jen.Code
}

StandardConversionOrchestrator provide a framework to a converter want to convert A -> B. it provides 8 routes check and invoke function to emit code.

For example: Given you want to convert A -> B, there are 8 standard routes:

  1. SourceToTarget A -> B
  2. OtherToSourceToTarget T -> A -> B if T -> A possible
  3. SourceToTargetToOther A -> B -> T if B -> T possible
  4. OtherToSourceToTargetToOther T -> A -> B -> V if T -> A and B -> V possible

flipped cases:

  1. TargetToSource B -> A
  2. OtherToTargetToSource T -> B -> A if T -> B possible
  3. TargetToSourceToOther B -> A -> T if A -> T possible
  4. OtherToTargetToSourceToOther T -> B -> A -> V if T -> B and A -> V possible

Usage: In your Converter.Init():

```

c.orchestrator = gen.StandardConversionOrchestrator{
		Source:                			A's type info,
		Target:                			B's type info,
		SourceToTarget:        			func to emit code when match route 1) A -> B
		OtherToSourceToTarget: 			nil if you don't want route 2)
		SourceToTargetToOther: 			func to emit code when match route 3) A -> B -> T
		OtherToSourceToTargetToOther:	nil if you don't want route 4)
		TargetToSource:        			func to emit code when match route 5) B -> A
		OtherToTargetToSource: 			func to emit code when match route 6) T -> B -> A
		TargetToSourceToOther: 			nil if you don't want route 7)
		OtherToTargetToSourceToOther:	nil if you don't want route 8)
}

``` Then in your Converter.CanConvert() ```

return c.orchestrator.CanConvert(c, ctx, targetType, sourceType)

``` and in your Converter.ConvertField()

```

return ctx.Run(c, opts, func() jen.Code {
	return c.orchestrator.PerformConvert(c, ctx, target, source, opts)
})

``` There is a simpler version of StandardConversionOrchestrator called GeneratedTypeOrchestrator which one side is fixed, it means you only have 4 cases.

func (*StandardConversionOrchestrator) CanConvert

func (o *StandardConversionOrchestrator) CanConvert(c Converter, ctx LookupContext, targetType, sourceType types.Type) bool

func (*StandardConversionOrchestrator) PerformConvert

func (o *StandardConversionOrchestrator) PerformConvert(c Converter, ctx ConverterContext, target, source Symbol) jen.Code

type StructConfig

type StructConfig struct {
	MapperName       string
	TargetPkgPath    string
	TargetStructName string
	SourcePkgPath    string
	SourceStructName string

	SourceToTargetFuncName   string
	SourceFromTargetFuncName string

	DecoratorMode    DecoratorMode
	DecorateFuncName string

	Pointer Pointer
	Fields  FieldConfig

	SourceFieldInterceptors map[string]FieldInterceptor
	TargetFieldInterceptors map[string]FieldInterceptor

	UseGetter bool

	GenerateSourceToTarget   bool
	GenerateSourceFromTarget bool
}

type StructFieldInfo

type StructFieldInfo struct {
	Name       string
	Getter     *string
	Tag        *string
	Comment    *string
	Doc        *string
	Type       types.Type
	Index      int
	IsExported bool
}

type StructInfo

type StructInfo struct {
	Type   types.Type
	Fields map[string]StructFieldInfo
}

type Symbol

type Symbol struct {
	VarName   string
	FieldName *string
	Type      types.Type
	Metadata  SymbolMetadata
}

Symbol represents a reference to either a variable or a field expression used during code generation.

VarName is the name of the local variable (e.g. "src"). FieldName is optional. If nil, the Symbol refers to the entire variable (e.g. "src"). If non-nil, the Symbol refers to a field of that variable (e.g. "src.Field"). This allows converters to handle both top-level assignments and assignments targeting specific struct fields.

Type is the Go type of the referenced value. Converters use this when determining whether they can perform a conversion.

Examples:

Symbol{VarName: "src", FieldName: nil}                // "src"
Symbol{VarName: "dst", FieldName: &("Name")}          // "dst.Name"

func (Symbol) Expr

func (s Symbol) Expr() *jen.Statement

func (Symbol) ToIndexedSymbol

func (s Symbol) ToIndexedSymbol(idx string) Symbol

type SymbolMetadata

type SymbolMetadata struct {
	IsVariable   bool
	HasZeroValue bool
}

type TypeInfo

type TypeInfo struct {
	PkgPath   string
	PkgName   string
	TypeName  string
	IsPointer bool
}

func MakeTypeInfo

func MakeTypeInfo(in any) TypeInfo

func (TypeInfo) ToType

func (ti TypeInfo) ToType() types.Type

Directories

Path Synopsis
cmd
generator command
go-mapper-gen command
converters
sql
internal
cli
pkg
cli
pkl
Code generated from Pkl module `gomappergen.Config`.
Code generated from Pkl module `gomappergen.Config`.
pkl/mapper
Code generated from Pkl module `gomappergen.mapper`.
Code generated from Pkl module `gomappergen.mapper`.
pkl/mapper/decoratormode
Code generated from Pkl module `gomappergen.mapper`.
Code generated from Pkl module `gomappergen.mapper`.
pkl/mapper/pointer
Code generated from Pkl module `gomappergen.mapper`.
Code generated from Pkl module `gomappergen.mapper`.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL