Skip to main content

Copier

The copier package provides struct-to-struct field copying with built-in type converters for common VEF types.

API Reference

APIContract
copier.Copy(src, dst, options...)Copies from src into dst by calling copier.CopyWithOption(dst, src, opt) from github.com/jinzhu/copier; dst must be a pointer destination or the underlying copier returns an error
copier.CopyOptionFunction option type that mutates the underlying option struct from github.com/jinzhu/copier
copier.TypeConverterAlias for github.com/jinzhu/copier.TypeConverter
copier.FieldNameMappingAlias for github.com/jinzhu/copier.FieldNameMapping
copier.WithIgnoreEmpty()Sets IgnoreEmpty = true
copier.WithDeepCopy()Sets DeepCopy = true
copier.WithCaseInsensitive()Sets CaseSensitive = false; default copying remains case-sensitive
copier.WithFieldNameMapping(...)Appends mappings to FieldNameMapping
copier.WithTypeConverters(...)Appends custom converters after the built-in converters rather than replacing them

Quick Start

import "github.com/coldsmirk/vef-framework-go/copier"

type UserParams struct {
Username string
Email string
}

type User struct {
Username string
Email string
IsActive bool
}

params := UserParams{Username: "alice", Email: "alice@example.com"}
user := User{}

err := copier.Copy(params, &user)
// user.Username = "alice", user.Email = "alice@example.com"

Options

All copier options use the public CopyOption type.

Copy(...) is case-sensitive by default and always starts with the built-in converter list. Options are applied in the order they are passed. WithTypeConverters(...) appends custom converters instead of replacing those defaults. WithFieldNameMapping(...) also appends mappings.

WithIgnoreEmpty

Skips copying fields with zero values. This is how the framework's Update CRUD operation merges partial updates:

err := copier.Copy(params, &user, copier.WithIgnoreEmpty())

WithDeepCopy

Enables deep copying of nested structures:

err := copier.Copy(src, &dst, copier.WithDeepCopy())

WithCaseInsensitive

Enables case-insensitive field name matching:

err := copier.Copy(src, &dst, copier.WithCaseInsensitive())

WithFieldNameMapping

Adds custom field name mappings for fields with different names:

err := copier.Copy(src, &dst, copier.WithFieldNameMapping(
copier.FieldNameMapping{
SrcType: UserParams{},
DstType: User{},
Mapping: map[string]string{
"Name": "Username",
},
},
))

WithTypeConverters

Adds custom type converters:

err := copier.Copy(src, &dst, copier.WithTypeConverters(
copier.TypeConverter{
SrcType: MyCustomType{},
DstType: "",
Fn: func(src interface{}) (interface{}, error) {
return src.(MyCustomType).String(), nil
},
},
))

Built-in Type Converters

The copier includes automatic converters for value ↔ pointer conversions of all common types:

Type PairDirection
string*stringBoth ways
bool*boolBoth ways
int, int8...int64*int...*int64Both ways
uint, uint8...uint64*uint...*uint64Both ways
float32, float64*float32, *float64Both ways
decimal.Decimal*decimal.DecimalBoth ways
time.Time*time.TimeBoth ways
timex.DateTime*timex.DateTimeBoth ways
timex.Date*timex.DateBoth ways
timex.Time*timex.TimeBoth ways

This means you can freely use pointer types in params structs for optional fields without worrying about type conversion.

Value-to-pointer converters allocate a new local value and return its address. Pointer-to-value converters dereference non-nil pointers. If the source pointer is nil, the converter returns the zero value for the destination type, for example "", false, 0, decimal.Zero, or a zero time.Time / timex.DateTime.

Framework Integration

The copier package is used internally by the CRUD Create, CreateMany, Update, and UpdateMany builders to copy TParams fields into TModel instances. The update builders use WithIgnoreEmpty() when merging incoming models into existing models for partial updates.