util/reflect: add Equal func with ability to skip some fields
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
parent
23e1174f25
commit
7c6bd98498
@ -508,3 +508,74 @@ func FieldName(name string) string {
|
|||||||
|
|
||||||
return string(newstr)
|
return string(newstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Equal(src interface{}, dst interface{}, excptFields ...string) bool {
|
||||||
|
srcVal := reflect.ValueOf(src)
|
||||||
|
dstVal := reflect.ValueOf(dst)
|
||||||
|
|
||||||
|
switch srcVal.Kind() {
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
for i := 0; i < srcVal.Len(); i++ {
|
||||||
|
e := srcVal.Index(i).Interface()
|
||||||
|
a := dstVal.Index(i).Interface()
|
||||||
|
if !Equal(e, a, excptFields...) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Map:
|
||||||
|
for i := 0; i < len(srcVal.MapKeys()); i++ {
|
||||||
|
key := srcVal.MapKeys()[i]
|
||||||
|
keyStr := fmt.Sprintf("%v", key.Interface())
|
||||||
|
if stringContains(keyStr, excptFields) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s := srcVal.MapIndex(key)
|
||||||
|
d := dstVal.MapIndex(key)
|
||||||
|
if !Equal(s.Interface(), d.Interface(), excptFields...) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Struct, reflect.Interface:
|
||||||
|
for i := 0; i < srcVal.NumField(); i++ {
|
||||||
|
typeField := srcVal.Type().Field(i)
|
||||||
|
if stringContains(typeField.Name, excptFields) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s := srcVal.Field(i)
|
||||||
|
d := dstVal.FieldByName(typeField.Name)
|
||||||
|
if s.CanInterface() && d.CanInterface() {
|
||||||
|
if !Equal(s.Interface(), d.Interface(), excptFields...) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Ptr:
|
||||||
|
if srcVal.IsNil() {
|
||||||
|
return dstVal.IsNil()
|
||||||
|
}
|
||||||
|
s := srcVal.Elem()
|
||||||
|
d := reflect.Indirect(dstVal)
|
||||||
|
if s.CanInterface() && d.CanInterface() {
|
||||||
|
return Equal(s.Interface(), d.Interface(), excptFields...)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case reflect.String, reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64, reflect.Bool:
|
||||||
|
return src == dst
|
||||||
|
default:
|
||||||
|
return srcVal.Interface() == dstVal.Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringContains(a string, list []string) bool {
|
||||||
|
for _, b := range list {
|
||||||
|
if b == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -133,3 +133,16 @@ func TestMergeNested(t *testing.T) {
|
|||||||
t.Fatalf("merge error: %#+v", dst.Nested)
|
t.Fatalf("merge error: %#+v", dst.Nested)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEqual(t *testing.T) {
|
||||||
|
type tstr struct {
|
||||||
|
Key1 string
|
||||||
|
Key2 string
|
||||||
|
}
|
||||||
|
|
||||||
|
src := &tstr{Key1: "val1", Key2: "micro:generate"}
|
||||||
|
dst := &tstr{Key1: "val1", Key2: "val2"}
|
||||||
|
if !Equal(src, dst, "Key2") {
|
||||||
|
t.Fatal("invalid Equal test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user