Skip to content

skhoroshavin/automap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

77 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Automap: Automated mapping generation in Go

ci

THIS PROJECT IS IN PROOF OF CONCEPT STAGE AND IS DEFINITELY NOT SUITABLE FOR USE IN PRODUCTION

Automap is a code generation tool that automates creation of mappings between different types. Resulting code operates without any additional runtime or reflection, so it doesn't incur any runtime overhead compared to handwritten mappings. Most of problems with generating mappings will happen at compile time, unlike other automapping solutions based on reflection that tend to fail at runtime. Finally, generated mappings are susceptible to code analysis tools and can also be easily navigated manually.

This tool is heavily inspired by:

  • Wire: dependency injection framework for Go based on code generation
  • AutoMapper: convention-based object-object mapper in .NET

Installing

Install AutoMap by running:

go get github.com/skhoroshavin/automap/cmd/automap

and ensuring that $GOPATH/bin is added to your $PATH.

Quick start

Suppose you want to create a mapping from type User to UserDTO. To do so first you need to create an automap.go file in your project with the following contents:

//go:build automap

package mypackage

import "github.com/skhoroshavin/automap"

func UserToDTO(user *User) *UserDTO {
	panic(automap.Build())
}

Note that:

  • it starts with build tag automap which prevents this file from compiling during normal build process
  • it contains mapper function with desired signature
  • implementation of that mapper function is just a stub which panics with the result of marker function automap.Build()

Then run automap tool in same directory which will create automap_gen.go file with roughly following contents:

// Code generated by automap. DO NOT EDIT.

//go:build !automap

//go:generate automap

package mypackage

func UserToDTO(user *User) *UserDTO {
    return &UserDTO{
        FirstName: user.FirstName,
        LastName: user.LastName,
        AddressCode: user.Address.Code,
        StreetAndCity: user.Address.StreetAndCity(),
        Country: user.Address.Country,
        PrefsGolang: user.Prefs().Golang,
        PrefsCompiled: user.Prefs().Compiled(),
    }
}

Note that:

  • it starts with !automap build tag, so it doesn't interfere with subsequent runs of this tool
  • it includes go:generate statement, so mappings can be updated just with normal go generate calls, no need to explicitly run automap after first bootstrapping
  • it doesn't import anything related to automap anymore
  • generated mapper has same signature as initial stub, and contains explicit mapping of fields that have matching names
  • matching is smart enough to use getters or nested queries if needed
  • if target type has fields that cannot be matched to any of inputs mapping generation will fail - this will prevent accidentally creating incomplete mappings
    • Making this behaviour configurable (for example by somehow providing custom mappings for such fields) is planned in future versions.

About

Convention-based object-object mapper in Go

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages