Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
// 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
// When set to true, all fields will be treated as if they have the "must" tag
Must bool
// When set to true, all fields will be treated as if they have the "nopanic" tag.
// This only has an effect when Must is also true
NoPanic bool
}

func (opt Option) converters() map[converterPair]TypeConverter {
Expand Down Expand Up @@ -206,7 +211,7 @@
to.SetMapIndex(toKey, toValue)
break
}
elemType = reflect.PointerTo(elemType)

Check failure on line 214 in copier.go

View workflow job for this annotation

GitHub Actions / ci (1.17, ubuntu-latest)

undefined: reflect.PointerTo
toValue = toValue.Addr()
}
}
Expand Down Expand Up @@ -312,8 +317,8 @@
dest = indirect(reflect.New(toType))
}

// Get tag options
flgs, err := getFlags(dest, source, toType, fromType)
var flgs flags
flgs, err = getFlags(dest, source, toType, fromType, opt)
if err != nil {
return err
}
Expand Down Expand Up @@ -732,7 +737,7 @@
}

// getTagFlags Parses struct tags for bit flags, field name.
func getFlags(dest, src reflect.Value, toType, fromType reflect.Type) (flags, error) {
func getFlags(dest, src reflect.Value, toType, fromType reflect.Type, opt Option) (flags, error) {
flgs := flags{
BitFlags: map[string]uint8{},
SrcNames: tagNameMapping{
Expand All @@ -745,6 +750,9 @@
},
}

mustOpt := opt.Must
noPanicOpt := opt.NoPanic

var toTypeFields, fromTypeFields []reflect.StructField
if dest.IsValid() {
toTypeFields = deepFields(toType)
Expand All @@ -766,6 +774,14 @@
flgs.DestNames.TagToFieldName[name] = field.Name
}
}

// Apply default flags
if mustOpt {
flgs.BitFlags[field.Name] = flgs.BitFlags[field.Name] | tagMust
}
if noPanicOpt {
flgs.BitFlags[field.Name] = flgs.BitFlags[field.Name] | tagNoPanic
}
}

// Get a list source of tags
Expand Down
54 changes: 54 additions & 0 deletions copier_tags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ type EmployeeTags struct {
ID int `copier:"-"`
}

type EmployeeTags2 struct {
Name string `copier:"must,nopanic"`
DOB string
Address string
ID int `copier:"-"`
}

type EmployeeTags3 struct {
Name string
DOB string
Address string
ID int
}

type User1 struct {
Name string
DOB string
Expand Down Expand Up @@ -49,6 +63,46 @@ func TestCopyTagMust(t *testing.T) {
copier.Copy(employee, user)
}

func TestCopyTagMustByOption(t *testing.T) {
employee := &EmployeeTags3{}
user := &User2{DOB: "1 January 1970"}
t.Run("must is true", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected a panic.")
}
}()
copier.CopyWithOption(employee, user, copier.Option{Must: true})
})

t.Run("must is false", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Error("Expected no panic.")
}
}()
copier.CopyWithOption(employee, user, copier.Option{Must: false})
})
}

func TestCopyTagMustAndNoPanic(t *testing.T) {
employee := &EmployeeTags2{}
user := &User2{DOB: "1 January 1970"}
err := copier.Copy(employee, user)
if err == nil {
t.Error("expected error")
}
}

func TestCopyTagMustAndNoPanicByOption(t *testing.T) {
employee := &EmployeeTags3{}
user := &User2{DOB: "1 January 1970"}
err := copier.CopyWithOption(employee, user, copier.Option{Must: true, NoPanic: true})
if err == nil {
t.Error("expected error")
}
}

func TestCopyTagOverrideZeroValue(t *testing.T) {
options := copier.Option{IgnoreEmpty: true}
employee := EmployeeTags{ID: 100, Address: ""}
Expand Down
Loading