Skip to content

Commit

Permalink
Add Delete
Browse files Browse the repository at this point in the history
  • Loading branch information
sunfmin committed Dec 28, 2021
1 parent 63fb18f commit 40223a9
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 2 deletions.
65 changes: 65 additions & 0 deletions delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package reflectutils

import (
"reflect"
"strconv"
"strings"
)

func Delete(i interface{}, name string) (err error) {
key := ""
if strings.HasSuffix(name, "]") {
lb := strings.LastIndex(name, "[")
key = name[lb+1 : len(name)-1]
name = name[0:lb]
}

t := GetType(i, name)
if t == nil {
return NoSuchFieldError
}

for t.Kind() == reflect.Ptr {
t = t.Elem()
}

if t.Kind() == reflect.Slice {
var index int
index, err = strconv.Atoi(key)
if err != nil {
return
}
newSlice := reflect.MakeSlice(t, 0, 0)
v, err1 := Get(i, name)
if err1 != nil {
return err1
}
vv := reflect.ValueOf(v)
for vv.Kind() == reflect.Ptr {
vv = vv.Elem()
}
for j := 0; j < vv.Len(); j++ {
if j == index {
continue
}
newSlice = reflect.Append(newSlice, vv.Index(j))
}
return Set(i, name, newSlice.Interface())
}

if t.Kind() == reflect.Map {
v := MustGet(i, name)
vv := reflect.ValueOf(v)
for vv.Kind() == reflect.Ptr {
vv = vv.Elem()
}
vv.SetMapIndex(reflect.ValueOf(key), reflect.Value{})
return
}

if t.Kind() == reflect.Struct {
return Set(i, name, nil)
}

return Set(i, name, reflect.Zero(t).Interface())
}
165 changes: 163 additions & 2 deletions map_slice_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package reflectutils_test

import (
"fmt"
"testing"

. "github.com/sunfmin/reflectutils"
Expand Down Expand Up @@ -102,7 +103,6 @@ func TestStructSetNil(t *testing.T) {
panic(err)
}


if m != nil {
t.Errorf("got non-nil (%#+v), want nil", m)
}
Expand All @@ -127,4 +127,165 @@ func TestSetFieldNil(t *testing.T) {
panic("s.Value is not nil")
}

}
}

func TestDelete(t *testing.T) {
p := &Person{
Departments: []*Department{
{
Name: "D1",
},
{
Name: "D2",
},
{
Name: "D3",
},
},
Phones: map[string]string{
"felix": "123",
"john": "456",
},
Projects: []*Project{
{
Name: "Project1",
Members: []*Person{
{
Name: "Felix1",
},
{
Name: "Felix2",
},
},
},
},
}
var strs = []string{"1", "2", "3"}
var map1 = map[string]string{"a": "a1", "b": "b1"}
var map2 = &map1

var p2 = &Person{}

var deleteCases = []struct {
caseName string
obj interface{}
name string
result func(obj interface{}) (v interface{})
expected string
expectedErr string
}{
{
caseName: "Delete map element in object",
obj: p,
name: "Phones[felix]",
result: func(obj interface{}) (v interface{}) {
return obj.(*Person).Phones
},
expected: "map[john:456]",
},
{
caseName: "Delete slice element in object",
obj: p,
name: "Departments[1]",
result: func(obj interface{}) (v interface{}) {
return obj.(*Person).Departments[1]
},
expected: "&{Id:0 Name:D3}",
},

{
caseName: "Delete slice element in object nested",
obj: p,
name: "Projects[0].Members[0]",
result: func(obj interface{}) (v interface{}) {
return obj.(*Person).Projects[0].Members[0].Name + obj.(*Person).Projects[0].Name
},
expected: "Felix2Project1",
},

{
caseName: "Delete slice element in object overflow",
obj: p,
name: "Departments[100]",
result: func(obj interface{}) (v interface{}) {
return obj.(*Person).Departments[1]
},
expected: "&{Id:0 Name:D3}",
},

{
caseName: "Delete struct with error",
obj: p,
name: "Comp21",
expectedErr: "no such field",
},

{
caseName: "Delete struct",
obj: p,
name: "Departments[0].Name",
result: func(obj interface{}) (v interface{}) {
return obj.(*Person).Departments[0].Name
},
expected: "",
},

{
caseName: "Delete with wrong index",
obj: p,
name: "Departments[abc].Name",
expectedErr: "no such field",
},

{
caseName: "Delete slice element",
obj: &strs,
name: "[1]",
result: func(obj interface{}) (v interface{}) {
return strs
},
expected: `[1 3]`,
},

{
caseName: "Delete map element",
obj: &map2,
name: "[a]",
result: func(obj interface{}) (v interface{}) {
return map1
},
expected: `map[b:b1]`,
},

{
caseName: "Delete struct whole",
obj: &p2,
name: "",
result: func(obj interface{}) (v interface{}) {
return p2
},
expected: `<nil>`,
},
}

for _, c := range deleteCases {
t.Run(c.caseName, func(t *testing.T) {
err := Delete(c.obj, c.name)
if c.expectedErr != "" {
if err == nil || err.Error() != c.expectedErr {
t.Errorf("expected error %s, but was %+v", c.expectedErr, err)
}
} else {
if err != nil {
t.Error(err)
}
}
if c.result != nil {
actual := fmt.Sprintf("%+v", c.result(c.obj))
if actual != c.expected {
t.Errorf("expected %s, but was %s", c.expected, actual)
}
}
})
}
}

0 comments on commit 40223a9

Please sign in to comment.