copier

package module
v0.4.4 Latest Latest
Warning

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

Go to latest
Published: Jan 8, 2025 License: MIT Imports: 8 Imported by: 2

README

Copier

I am a copier, I copy everything from one to another

test status Coverage Status

This fork's purpose

  • Added the Valuer interface.
  • Fixed bug: with the DeepCopy option to true, when the destination slice or map had a longer length than the source slice or map, the destination was not resized accordingly.
  • Fixed bug: if the destination field implement sql/driver.Scanner and the source field implements sql/driver.Valuer, Value() was not called on the source field.
  • Add more test cases

Features

  • Copy from field to field with same name
  • Copy from method to field with same name
  • Copy from field to method with same name
  • Copy from slice to slice
  • Copy from struct to slice
  • Copy from map to map
  • Enforce copying a field with a tag
  • Ignore a field with a tag
  • Deep Copy

Usage

package main

import (
	"fmt"
	"goyave.dev/copier"
)

type Address struct{
	City string
	Street string
} 

// copier.Valuer interface lets custom types implement a function returning the actual value to copy.
// For example if your type is a wrapper, or if it doesn't have to implement `sql/driver.Valuer`,
// you can implement this interface so the returned value will be used instead. It can also be used
// to format your type or convert it to another one before being copied.
// This also enables conversion for types using generics, as you cannot use them with `TypeConverter`.
func (a Address) CopyValue() interface{} {
	return fmt.Sprintf("%s, %s", a.Street, a.City)
}

type User struct {
	Name        string
	Role        string
	Age         int32
	EmployeeCode int64 `copier:"EmployeeNum"` // specify field name

	// Explicitly ignored in the destination struct.
	Salary   int

	Address Address
}

func (user *User) DoubleAge() int32 {
	return 2 * user.Age
}

// Tags in the destination Struct provide instructions to copier.Copy to ignore
// or enforce copying and to panic or return an error if a field was not copied.
type Employee struct {
	// Tell copier.Copy to panic if this field is not copied.
	Name      string `copier:"must"`

	// Tell copier.Copy to return an error if this field is not copied.
	Age       int32  `copier:"must,nopanic"`

	// Tell copier.Copy to explicitly ignore copying this field.
	Salary    int    `copier:"-"`

	DoubleAge int32
	EmployeeId int64 `copier:"EmployeeNum"` // specify field name
	SuperRole string

	Address string
}

func (employee *Employee) Role(role string) {
	employee.SuperRole = "Super " + role
}

func main() {
	var (
		user  = User{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 200000, Address: Address{Street: "123 Main Street", City: "Somewhere"}}
		users = []User{
			{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 100000, Address: Address{Street: "124 Secondary Street", City: "SomewhereElse"}},
			{Name: "jinzhu 2", Age: 30, Role: "Dev", Salary: 60000, Address: Address{Street: "125 Secondary Street", City: "SomewhereElse"}}}
		employee  = Employee{Salary: 150000}
		employees = []Employee{}
	)

	copier.Copy(&employee, &user)

	fmt.Printf("%#v \n", employee)
	// Employee{
	//    Name: "Jinzhu",                          // Copy from field
	//    Age: 18,                                 // Copy from field
	//    Salary:150000,                           // Copying explicitly ignored
	//    DoubleAge: 36,                           // Copy from method
	//    EmployeeId: 0,                           // Ignored
	//    SuperRole: "Super Admin",                // Copy to method
	//    Address: "123 Main Street, Somewhere",   // Copy from value returned by CopyValue()
	// }

	// Copy struct to slice
	copier.Copy(&employees, &user)

	fmt.Printf("%#v \n", employees)
	// []Employee{
	//   {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeeId: 0, SuperRole: "Super Admin", Address: "123 Main Street, Somewhere"}
	// }

	// Copy slice to slice
	employees = []Employee{}
	copier.Copy(&employees, &users)

	fmt.Printf("%#v \n", employees)
	// []Employee{
	//   {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeeId: 0, SuperRole: "Super Admin", Address: "124 Secondary Street, SomewhereElse"},
	//   {Name: "jinzhu 2", Age: 30, Salary:0, DoubleAge: 60, EmployeeId: 0, SuperRole: "Super Dev", Address: "125 Secondary Street, SomewhereElse"},
	// }

 	// Copy map to map
	map1 := map[int]int{3: 6, 4: 8}
	map2 := map[int32]int8{}
	copier.Copy(&map2, map1)

	fmt.Printf("%#v \n", map2)
	// map[int32]int8{3:6, 4:8}
}
Copy with Option
copier.CopyWithOption(&to, &from, copier.Option{IgnoreEmpty: true, DeepCopy: true})

Contributing

You can help to make the project better, check out http://gorm.io/contribute.html for things you can do.

License

Released under the MIT License.

Documentation

Index

Constants

View Source
const (

	// Some default converter types for a nicer syntax
	String  string  = ""
	Bool    bool    = false
	Int     int     = 0
	Float32 float32 = 0
	Float64 float64 = 0
)

These flags define options for tag handling

Variables

View Source
var (
	ErrInvalidCopyDestination        = errors.New("copy destination must be non-nil and addressable")
	ErrInvalidCopyFrom               = errors.New("copy from must be non-nil and addressable")
	ErrMapKeyNotMatch                = errors.New("map's key type doesn't match")
	ErrNotSupported                  = errors.New("not supported")
	ErrFieldNameTagStartNotUpperCase = errors.New("copier field name tag must be start upper case")
)

Functions

func Copy

func Copy(toValue interface{}, fromValue interface{}) (err error)

Copy copy things

func CopyWithOption

func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error)

CopyWithOption copy with option

Types

type FieldNameMapping

type FieldNameMapping struct {
	SrcType interface{}
	DstType interface{}
	Mapping map[string]string
}

type Option

type Option struct {
	Converters []TypeConverter
	// Custom field name mappings to copy values with different names in `fromValue` and `toValue` types.
	// Examples can be found in `copier_field_name_mapping_test.go`.
	FieldNameMapping []FieldNameMapping

	// setting this value to true will ignore copying zero values of all the fields, including bools, as well as a
	// struct having all it's fields set to their zero values respectively (see IsZero() in reflect/value.go)
	IgnoreEmpty   bool
	CaseSensitive bool
	DeepCopy      bool
}

Option sets copy options

type TypeConverter

type TypeConverter struct {
	SrcType interface{}
	DstType interface{}
	Fn      func(src interface{}) (dst interface{}, err error)
}

type Valuer

type Valuer interface {
	CopyValue() interface{}
}

Valuer lets custom types implement a function returning the actual value to copy. For example if your type is a wrapper, or if it doesn't have to implement `sql/driver.Valuer`, you can implement this interface so the returned value will be used instead. It can also be used to format your type or convert it to another one before being copied. This also enables conversion for types using generics, as you cannot use them with `TypeConverter`.

Jump to

Keyboard shortcuts

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