Merge "Add support for maps as properties"

This commit is contained in:
Treehugger Robot 2021-05-27 19:32:37 +00:00 committed by Gerrit Code Review
commit 16caaa4817
6 changed files with 563 additions and 316 deletions

View file

@ -78,6 +78,18 @@ func copyProperties(dstValue, srcValue reflect.Value) {
} else {
dstFieldValue.Set(srcFieldValue)
}
case reflect.Map:
if !srcFieldValue.IsNil() {
newMap := reflect.MakeMap(field.Type)
iter := srcFieldValue.MapRange()
for iter.Next() {
newMap.SetMapIndex(iter.Key(), iter.Value())
}
dstFieldValue.Set(newMap)
} else {
dstFieldValue.Set(srcFieldValue)
}
case reflect.Interface:
if srcFieldValue.IsNil() {
dstFieldValue.Set(srcFieldValue)
@ -158,7 +170,7 @@ func zeroProperties(structValue reflect.Value) {
fieldValue := structValue.Field(i)
switch fieldValue.Kind() {
case reflect.Bool, reflect.String, reflect.Slice, reflect.Int, reflect.Uint:
case reflect.Bool, reflect.String, reflect.Slice, reflect.Int, reflect.Uint, reflect.Map:
fieldValue.Set(reflect.Zero(fieldValue.Type()))
case reflect.Interface:
if fieldValue.IsNil() {
@ -220,7 +232,7 @@ func cloneEmptyProperties(dstValue, srcValue reflect.Value) {
dstFieldInterfaceValue := reflect.Value{}
switch srcFieldValue.Kind() {
case reflect.Bool, reflect.String, reflect.Slice, reflect.Int, reflect.Uint:
case reflect.Bool, reflect.String, reflect.Slice, reflect.Map, reflect.Int, reflect.Uint:
// Nothing
case reflect.Struct:
cloneEmptyProperties(dstFieldValue, srcFieldValue)

View file

@ -83,6 +83,29 @@ var clonePropertiesTestCases = []struct {
},
},
},
{
// Clone map
in: &struct{ S map[string]string }{
S: map[string]string{"key": "string1"},
},
out: &struct{ S map[string]string }{
S: map[string]string{"key": "string1"},
},
},
{
// Clone empty map
in: &struct{ S map[string]string }{
S: map[string]string{},
},
out: &struct{ S map[string]string }{
S: map[string]string{},
},
},
{
// Clone nil map
in: &struct{ S map[string]string }{},
out: &struct{ S map[string]string }{},
},
{
// Clone pointer to bool
in: &struct{ B1, B2 *bool }{
@ -285,6 +308,12 @@ func TestCloneProperties(t *testing.T) {
t.Errorf(" expected: %#v", testCase.out)
t.Errorf(" got: %#v", got)
}
if testCase.out == got {
t.Errorf("test case %s", testString)
t.Errorf("items should be cloned, not the original")
t.Errorf(" expected: %s", testCase.out)
t.Errorf(" got: %s", got)
}
}
}

View file

@ -342,7 +342,7 @@ func extendPropertiesRecursive(dstValues []reflect.Value, srcValue reflect.Value
// Recursively extend the struct's fields.
recurse = append(recurse, dstFieldValue)
continue
case reflect.Bool, reflect.String, reflect.Slice:
case reflect.Bool, reflect.String, reflect.Slice, reflect.Map:
if srcFieldValue.Type() != dstFieldValue.Type() {
return extendPropertyErrorf(propertyName, "mismatched types %s and %s",
dstFieldValue.Type(), srcFieldValue.Type())
@ -443,6 +443,34 @@ func ExtendBasicType(dstFieldValue, srcFieldValue reflect.Value, order Order) {
newSlice = reflect.AppendSlice(newSlice, srcFieldValue)
}
dstFieldValue.Set(newSlice)
case reflect.Map:
if srcFieldValue.IsNil() {
break
}
var mapValue reflect.Value
// for append/prepend, maintain keys from original value
// for replace, replace entire map
if order == Replace || dstFieldValue.IsNil() {
mapValue = srcFieldValue
} else {
mapValue = dstFieldValue
iter := srcFieldValue.MapRange()
for iter.Next() {
dstValue := dstFieldValue.MapIndex(iter.Key())
if prepend {
// if the key exists in the map, keep the original value.
if !dstValue.IsValid() {
// otherwise, add the new value
mapValue.SetMapIndex(iter.Key(), iter.Value())
}
} else {
// For append, replace the original value.
mapValue.SetMapIndex(iter.Key(), iter.Value())
}
}
}
dstFieldValue.Set(mapValue)
case reflect.Ptr:
if srcFieldValue.IsNil() {
break

File diff suppressed because it is too large Load diff

View file

@ -129,3 +129,7 @@ func isSlice(t reflect.Type) bool {
func isSliceOfStruct(t reflect.Type) bool {
return isSlice(t) && isStruct(t.Elem())
}
func isMapOfStruct(t reflect.Type) bool {
return t.Kind() == reflect.Map && isStruct(t.Elem())
}

View file

@ -57,7 +57,7 @@ func propertyIndexesWithTag(t reflect.Type, key, value string) [][]int {
field := t.Field(i)
ft := field.Type
if isStruct(ft) || isStructPtr(ft) || isSliceOfStruct(ft) {
if ft.Kind() == reflect.Ptr || ft.Kind() == reflect.Slice {
if ft.Kind() == reflect.Ptr || ft.Kind() == reflect.Slice || ft.Kind() == reflect.Map {
ft = ft.Elem()
}
subIndexes := propertyIndexesWithTag(ft, key, value)