Skip to content

lynchborg/automapper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Automapper 🤖🗺️

Go Reference Go Coverage Go Report Card

Easily map from a source to a destination struct.

Why though? Well, while writing mappings by hand is great and all, it's very tedious if the types are largely the same but with only some small differences.

Automapper will (automatically 🤖) map fields that are the same name and type, just leaving you to define what you want to do with the exceptions.

package main

import (
	"fmt"
	"strconv"

	"github.com/lynchborg/automapper"
)

type sub1 struct{ Bar string }
type sub2 struct{ Bar string }

type from struct {
	String string
	Int    int
	Inline struct {
		Foo string
	}
	Struct         sub1
	StringSlice    []string
	StructSlice    []sub1
	WrongTypeSlice []int
}

type to struct {
	Int    int
	String string
	Inline struct {
		Foo string
	}
	Struct         sub2
	StringSlice    []string
	StructSlice    []sub2
	WrongTypeSlice []string
	Missing        bool
}

var c automapper.Config[from, to]

func init() {
	subMapper := automapper.New[sub1, sub2]()
	// first set up the mapper, advised to do this at startup once since it's costly with reflection
	// via string names
	c = automapper.New[from, to]().
		ForFieldName("Struct", automapper.MapField(func(src from) (any, error) {
			return subMapper.Map(src.Struct)
		})).
		ForFieldName("StructSlice", automapper.MapField(func(src from) (any, error) {
			return subMapper.MapSlice(src.StructSlice)
		})).
		ForFieldName("Missing", automapper.IgnoreField()).
		ForFieldName("WrongTypeSlice", automapper.MapField(func(src from) (any, error) {
			return automapper.MapSlice(src.WrongTypeSlice, func(input int) string {
				return strconv.Itoa(input)
			}), nil
		}))

	// or by func
	c = automapper.New[from, to]().
		ForField(func(dest *to) any {
			return &dest.Struct
		}, automapper.MapField(func(src from) (any, error) {
			return subMapper.Map(src.Struct)
		})).
		ForField(func(dest *to) any {
			return &dest.StructSlice
		}, automapper.MapField(func(src from) (any, error) {
			return subMapper.MapSlice(src.StructSlice)
		})).
		ForField(func(dest *to) any {
			return &dest.Missing
		}, automapper.IgnoreField()).
		ForField(func(dest *to) any {
			return &dest.WrongTypeSlice
		}, automapper.MapField(func(src from) (any, error) {
			return automapper.MapSlice(src.WrongTypeSlice, func(input int) string {
				return strconv.Itoa(input)
			}), nil
		}))

}

func main() {

	src := from{
		String:      "String",
		Int:         999,
		Struct:      sub1{Bar: "hey"},
		StringSlice: []string{"1", "2"},
		StructSlice: []sub1{
			{Bar: "1"},
			{Bar: "2"},
		},
		WrongTypeSlice: []int{999, 998},
	}
	// do your mapping
	dest, err := c.Map(src)
	if err != nil {
		panic(err)
	}

	fmt.Println(dest)
}

About

Map between structs, a bit like dotnet's AutoMapper

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages