Skip to content

Commit

Permalink
support case-insensitive copy
Browse files Browse the repository at this point in the history
  • Loading branch information
QianChenglong committed Apr 7, 2023
1 parent 20cee7e commit 61dc501
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 9 deletions.
19 changes: 14 additions & 5 deletions copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ const (
type Option struct {
// 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
DeepCopy bool
Converters []TypeConverter
IgnoreEmpty bool
CaseSensitive bool
DeepCopy bool
Converters []TypeConverter
}

func (opt Option) converters() map[converterPair]TypeConverter {
Expand Down Expand Up @@ -300,7 +301,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
break
}

toField := dest.FieldByName(destFieldName)
toField := fieldByName(dest, destFieldName, opt.CaseSensitive)
if toField.IsValid() {
if toField.CanSet() {
isSet, err := set(toField, fromField, opt.DeepCopy, converters)
Expand Down Expand Up @@ -346,7 +347,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
}

if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 && !shouldIgnore(fromMethod, opt.IgnoreEmpty) {
if toField := dest.FieldByName(destFieldName); toField.IsValid() && toField.CanSet() {
if toField := fieldByName(dest, destFieldName, opt.CaseSensitive); toField.IsValid() && toField.CanSet() {
values := fromMethod.Call([]reflect.Value{})
if len(values) >= 1 {
set(toField, values[0], opt.DeepCopy, converters)
Expand Down Expand Up @@ -741,3 +742,11 @@ func driverValuer(v reflect.Value) (i driver.Valuer, ok bool) {
i, ok = v.Addr().Interface().(driver.Valuer)
return
}

func fieldByName(v reflect.Value, name string, caseSensitive bool) reflect.Value {
if caseSensitive {
return v.FieldByName(name)
}

return v.FieldByNameFunc(func(n string) bool { return strings.EqualFold(n, name) })
}
2 changes: 1 addition & 1 deletion copier_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func BenchmarkNamaCopy(b *testing.B) {
for x := 0; x < b.N; x++ {
employee := &Employee{
Name: user.Name,
Nickname: &user.Nickname,
NickName: &user.Nickname,
Age: int64(user.Age),
FakeAge: int(*user.FakeAge),
DoubleAge: user.DoubleAge(),
Expand Down
6 changes: 3 additions & 3 deletions copier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type Employee struct {
_User *User
Name string
Birthday *time.Time
Nickname *string
NickName *string
Age int64
FakeAge int
EmployeID int64
Expand All @@ -48,7 +48,7 @@ func checkEmployee(employee Employee, user User, t *testing.T, testCase string)
if employee.Name != user.Name {
t.Errorf("%v: Name haven't been copied correctly.", testCase)
}
if employee.Nickname == nil || *employee.Nickname != user.Nickname {
if employee.NickName == nil || *employee.NickName != user.Nickname {
t.Errorf("%v: NickName haven't been copied correctly.", testCase)
}
if employee.Birthday == nil && user.Birthday != nil {
Expand Down Expand Up @@ -102,7 +102,7 @@ func TestCopySameStructWithPointerField(t *testing.T) {

func checkEmployee2(employee Employee, user *User, t *testing.T, testCase string) {
if user == nil {
if employee.Name != "" || employee.Nickname != nil || employee.Birthday != nil || employee.Age != 0 ||
if employee.Name != "" || employee.NickName != nil || employee.Birthday != nil || employee.Age != 0 ||
employee.DoubleAge != 0 || employee.FakeAge != 0 || employee.SuperRule != "" || employee.Notes != nil {
t.Errorf("%v : employee should be empty", testCase)
}
Expand Down

0 comments on commit 61dc501

Please sign in to comment.