From bf847e845e1aa973eb0809a78e882b988a9a347f Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 26 Jan 2020 23:11:36 +0100 Subject: [PATCH] Improvements to embedded struct support(uuid and similar tag names) and extra tests --- examples/example-4/main.go | 76 +++++++++++++++++++++++++++++ fields.go | 17 ++++++- fields_test.go | 98 +++++++++++++++++++++++++++++++++++++- go.mod | 5 +- go.sum | 2 + 5 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 examples/example-4/main.go diff --git a/examples/example-4/main.go b/examples/example-4/main.go new file mode 100644 index 0000000..98cf77c --- /dev/null +++ b/examples/example-4/main.go @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Alex aka mailoman + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @author Alex aka mailoman + * @copyright Copyright (c) 2020 Alex aka mailoman + * @since 26.01.2020 + * + */ + +package main + +import ( + "encoding/json" + "log" + + "github.com/go-convert/fields" + "github.com/satori/go.uuid" +) + +type FromStructBase struct { + ID uuid.UUID `conv:"new,update"` + Field1 string `conv:"new,update"` +} + +type fromStruct struct { + FromStructBase `conv:"new,update"` + Field2 string `conv:"update"` +} + +type toStruct struct { + Id string + Field1 string + Field2 string + Field3 string +} + +func main() { + fromDefault := fromStruct{ + FromStructBase{uuid.FromStringOrNil("bb9f2a39-1dbd-4929-8e87-4863696d9cb3"), "field 1 value"}, "field 2 value", + } + toDefault := toStruct{ + "old val 1", "old field 1 value", "old field 2 value", "old field 3 value", + } + + log.Print("example 4.1 - new") + from := fromDefault + to := toDefault + + fields.Сonvert(from, "new", &to) + fromB, _ := json.Marshal(from) + toB, _ := json.Marshal(to) + + log.Printf("from %s => to %s", string(fromB), string(toB)) + + log.Print("example 4.2 - update") + from = fromDefault + to = toDefault + + fields.Сonvert(from, "update", &to) + fromB, _ = json.Marshal(from) + toB, _ = json.Marshal(to) + + log.Printf("from %s => to %s", string(fromB), string(toB)) +} diff --git a/fields.go b/fields.go index 3e4cc5d..88e3fbb 100644 --- a/fields.go +++ b/fields.go @@ -25,6 +25,8 @@ import ( "log" "reflect" "strings" + + "github.com/satori/go.uuid" ) //Convert copies field values from one struct to another based on tags setup @@ -70,10 +72,23 @@ func Сonvert(from interface{}, kind string, to interface{}) { if found { ft := vt.FieldByName(f.Name) + if f.Name == strings.ToUpper(f.Name) && !ft.IsValid() { + // was uppercase and not valid => to Capitalize first letter + ft = vt.FieldByName(strings.Title(strings.ToLower(f.Name))) + } + if !ft.IsValid() && fv.Kind() == reflect.Struct { Сonvert(fv.Interface(), kind, to) } else { - ft.Set(fv) + if ft.IsValid() { + switch f.Type.String() { + case "uuid.UUID": + mv := fv.Interface().(uuid.UUID) + ft.SetString(mv.String()) + default: + ft.Set(fv) + } + } } } } diff --git a/fields_test.go b/fields_test.go index f760fdd..90989c8 100644 --- a/fields_test.go +++ b/fields_test.go @@ -24,6 +24,7 @@ package fields_test import ( "testing" + "github.com/satori/go.uuid" "github.com/stretchr/testify/assert" "github.com/go-convert/fields" @@ -51,6 +52,14 @@ type ToStruct struct { Field4 string } +type ToStruct2 struct { + Id string + Field1 string + Field2 string + Field3 string + Field4 string +} + type FromStructCustom struct { ID string `copy:"new,update"` Field1 string `copy:"new,update"` @@ -64,6 +73,11 @@ type FromStructBase struct { Field1 string `conv:"new,update"` } +type FromStructExtraBase struct { + ID uuid.UUID `conv:"new,update"` + Field1 string `conv:"new,update"` +} + type FromStructCombined struct { FromStructBase `conv:"new,update"` Field2 string `conv:"update"` @@ -71,6 +85,13 @@ type FromStructCombined struct { Field4 string `conv:"category-1,omitempty"` } +type FromStructCombinedExtra struct { + FromStructExtraBase `conv:"new,update"` + Field2 uuid.UUID `conv:"update"` + Field3 string `conv:"update,omit"` + Field4 string `conv:"category-1,omitempty"` +} + var ( // testsNormal provides normal test cases testsNormal = []struct { @@ -271,7 +292,7 @@ var ( }, } - // testsCombinedNormal provides normal test cases with custom init config + // testsCombinedNormal provides normal test cases with embedded structs testsCombinedNormal = []struct { from FromStructCombined kind string @@ -331,6 +352,67 @@ var ( }, }, } + + // testsCombinedExtra provides normal test cases with embedded structs with more features + testsCombinedExtra = []struct { + from FromStructCombinedExtra + kind string + to ToStruct2 + expectedTo ToStruct2 + }{ + // case 4.1 + { + FromStructCombinedExtra{ + FromStructExtraBase{uuid.FromStringOrNil("bb9f2a39-1dbd-4929-8e87-4863696d9cb3"), "field 1 value"}, uuid.FromStringOrNil("d039089d-27f5-438b-8b70-90eb3df0d79b"), "omitting", "", + }, + "new", + ToStruct2{ + "old val 1", "old field 1 value", "old field 2 value", "old field 3 value", "", + }, + ToStruct2{ + "bb9f2a39-1dbd-4929-8e87-4863696d9cb3", "field 1 value", "old field 2 value", "old field 3 value", "", + }, + }, + // case 4.2 + { + FromStructCombinedExtra{ + FromStructExtraBase{uuid.FromStringOrNil("bb9f2a39-1dbd-4929-8e87-4863696d9cb3"), "field 1 value"}, uuid.FromStringOrNil("d039089d-27f5-438b-8b70-90eb3df0d79b"), "omitting", "", + }, + "update", + ToStruct2{ + "old val 1", "old field 1 value", "old field 2 value", "old field 3 value", "", + }, + ToStruct2{ + "bb9f2a39-1dbd-4929-8e87-4863696d9cb3", "field 1 value", "d039089d-27f5-438b-8b70-90eb3df0d79b", "old field 3 value", "", + }, + }, + // case 4.3.1 + { + FromStructCombinedExtra{ + FromStructExtraBase{uuid.FromStringOrNil("bb9f2a39-1dbd-4929-8e87-4863696d9cb3"), "field 1 value"}, uuid.FromStringOrNil("d039089d-27f5-438b-8b70-90eb3df0d79b"), "omitting", "", + }, + "category-1", + ToStruct2{ + "old val 1", "old field 1 value", "old field 2 value", "old field 3 value", "old field 4 value", + }, + ToStruct2{ + "old val 1", "old field 1 value", "old field 2 value", "old field 3 value", "old field 4 value", + }, + }, + // case 4.3.2 + { + FromStructCombinedExtra{ + FromStructExtraBase{uuid.FromStringOrNil("bb9f2a39-1dbd-4929-8e87-4863696d9cb3"), "field 1 value"}, uuid.FromStringOrNil("d039089d-27f5-438b-8b70-90eb3df0d79b"), "omitting", "not empty", + }, + "category-1", + ToStruct2{ + "old val 1", "old field 1 value", "old field 2 value", "old field 3 value", "old field 4 value", + }, + ToStruct2{ + "old val 1", "old field 1 value", "old field 2 value", "old field 3 value", "not empty", + }, + }, + } ) func TestConvert_Normal(t *testing.T) { @@ -444,3 +526,17 @@ func TestConvert_CombinedNormal(t *testing.T) { assert.Equal(t, test.expectedTo, *to) } } + +func TestConvert_CombinedExtra(t *testing.T) { + fields.SetDefaults() + for _, test := range testsCombinedExtra { + + to := &ToStruct2{} + *to = test.to + + fields.Сonvert(test.from, test.kind, to) + + assert.NotEmpty(t, *to) + assert.Equal(t, test.expectedTo, *to) + } +} diff --git a/go.mod b/go.mod index fa25bb0..0f8fa46 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/go-convert/fields go 1.13 -require github.com/stretchr/testify v1.4.0 + require ( + github.com/satori/go.uuid v1.2.0 + github.com/stretchr/testify v1.4.0 + ) diff --git a/go.sum b/go.sum index 8fdee58..5e6de34 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=