Merge "Add support for maps as properties"
This commit is contained in:
commit
16caaa4817
6 changed files with 563 additions and 316 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue