Skip to content

Commit

Permalink
✨ feat: ignore mismatched fields when getting value from src
Browse files Browse the repository at this point in the history
  • Loading branch information
0xE8551CCB committed Oct 12, 2019
1 parent 9290965 commit 5f05a79
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 37 deletions.
11 changes: 6 additions & 5 deletions examples/todo/main.go → _examples/todo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (

"github.com/ifaceless/portal"

"github.com/ifaceless/portal/examples/todo/model"
"github.com/ifaceless/portal/examples/todo/schema"
"github.com/ifaceless/portal/_examples/todo/model"
"github.com/ifaceless/portal/_examples/todo/schema"
)

func main() {
Expand All @@ -26,7 +26,7 @@ func main() {
}

printFullFields(&task)
printWithOnlyFields(&task, "Description")
printWithOnlyFields(&task, "Unknown")
printWithOnlyFields(&task, "ID", "User[id,Notifications[ID],AnotherNotifications[Title]]", "simple_user[id]")
printMany()
printWithExcludeFields(&task, "Description", "ID", "User[Name,Notifications[ID,Content],AnotherNotifications], SimpleUser")
Expand All @@ -40,7 +40,8 @@ func printFullFields(task *model.TaskModel) {

err := portal.DumpWithContext(ctx, &taskSchema, task)
if err != nil {
panic(err)
fmt.Printf("%++v", err)
return
}
data, _ := json.Marshal(taskSchema)
fmt.Println(string(data))
Expand Down Expand Up @@ -78,7 +79,7 @@ func printMany() {
})
}

err := portal.Dump(&taskSchemas, &tasks, portal.Only("ID", "Title", "User[Name]", "Description"), portal.DisableConcurrency())
err := portal.Dump(&taskSchemas, &tasks, portal.Only("ID", "Title", "User[Name]", "Description"))
if err != nil {
panic(err)
}
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"github.com/ifaceless/portal/field"

"github.com/ifaceless/portal/examples/todo/model"
"github.com/ifaceless/portal/_examples/todo/model"
)

type NotiSchema struct {
Expand Down Expand Up @@ -34,6 +34,7 @@ type TaskSchema struct {
Description3 string `json:"description3,omitempty" portal:"meth:GetDescription;async"`
User *UserSchema `json:"user,omitempty" portal:"nested"`
SimpleUser *UserSchema `json:"simple_user,omitempty" portal:"nested;only:Name;attr:User"`
Unknown string `json:"unknown"`
}

func (ts *TaskSchema) GetDescription(model *model.TaskModel) (string, error) {
Expand Down
2 changes: 1 addition & 1 deletion schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (s *schema) fieldValueFromSrc(ctx context.Context, field *schemaField, v in
if field.hasConstValue() {
val = field.constValue()
} else if field.hasMethod() {
ret, err := invokeMethod(ctx, s.rawValue, field.method(), v)
ret, err := invokeMethodOfAnyType(ctx, s.rawValue, field.method(), v)
if err != nil {
return nil, fmt.Errorf("failed to get value: %s", err)
}
Expand Down
24 changes: 18 additions & 6 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,22 @@ func nestedValue(ctx context.Context, any interface{}, chainingAttrs []string) (
}
}

ret, err := invokeMethodFromReflectedValue(ctx, rv, attr)
meth, err := findMethod(rv, attr)
if err != nil {
// ignore method not found here.
// do nothing for mismatched fields.
logger.Warnf("[portal.nestedValue] %s", err)
return nil, nil
}

ret, err := invoke(ctx, rv, meth, attr)
if err != nil {
return nil, err
}
return nestedValue(ctx, ret, chainingAttrs[1:])
}

// invokeMethod calls the specified method of a value and return results.
// invokeMethodOfAnyType calls the specified method of a value and return results.
// Note:
// - Context param is optional
// - Method must returns at least one result.
Expand All @@ -46,21 +54,25 @@ func nestedValue(ctx context.Context, any interface{}, chainingAttrs []string) (
// - `func (f *FooType) Bar(ctx context.Context, v interface{}) string`
// - `func (f *FooType) Bar(ctx context.Context, v interface{}) (string, error)`
// - `func (f *FooType) Bar(ctx context.Context, v interface{}) (string, error)`
func invokeMethod(ctx context.Context, any interface{}, name string, args ...interface{}) (interface{}, error) {
return invokeMethodFromReflectedValue(ctx, reflect.ValueOf(any), name, args...)
func invokeMethodOfAnyType(ctx context.Context, any interface{}, name string, args ...interface{}) (interface{}, error) {
return invokeMethodOfReflectedValue(ctx, reflect.ValueOf(any), name, args...)
}

func invokeMethodFromReflectedValue(ctx context.Context, any reflect.Value, name string, args ...interface{}) (interface{}, error) {
func invokeMethodOfReflectedValue(ctx context.Context, any reflect.Value, name string, args ...interface{}) (interface{}, error) {
method, err := findMethod(any, name)
if err != nil {
return nil, err
}
return invoke(ctx, any, method, name, args...)
}

func invoke(ctx context.Context, any reflect.Value, method reflect.Value, methodName string, args ...interface{}) (interface{}, error) {
methodType := method.Type()
if shouldWithContext(methodType) {
args = append([]interface{}{ctx}, args...)
}

methodNameRepr := fmt.Sprintf("%s.%s", any.Type().String(), name)
methodNameRepr := fmt.Sprintf("%s.%s", any.Type().String(), methodName)

numIn := methodType.NumIn()
if numIn > len(args) {
Expand Down
48 changes: 24 additions & 24 deletions utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ func TestGetNestedValue_Error(t *testing.T) {

var c = Car{name: "foo", Kind: MessageKind(1)}
_, e = nestedValue(ctx, &c, []string{"What"})
assert.EqualError(t, e, "method 'What' not found in '*portal.Car'")
assert.Nil(t, e)

_, e = nestedValue(ctx, &c, []string{"Kind", "NotFound"})
assert.EqualError(t, e, "method 'NotFound' not found in 'portal.MessageKind'")
assert.Nil(t, e)
}

type Foo struct{}
Expand Down Expand Up @@ -144,62 +144,62 @@ func TestInvokeStructMethod(t *testing.T) {
ctx := context.TODO()
ctx = context.WithValue(ctx, "key", "hello, world")

ret, err := invokeMethod(ctx, book, "ShortName")
ret, err := invokeMethodOfAnyType(ctx, book, "ShortName")
assert.Nil(t, err)
assert.Equal(t, "Test", ret)

ret, err = invokeMethod(ctx, book, "FullName")
ret, err = invokeMethodOfAnyType(ctx, book, "FullName")
assert.Nil(t, err)
assert.Equal(t, "Prefix Test", ret)

ret, err = invokeMethod(ctx, &book, "ShortName")
ret, err = invokeMethodOfAnyType(ctx, &book, "ShortName")
assert.Nil(t, err)
assert.Equal(t, "Test", ret)

ret, err = invokeMethod(ctx, &book, "FullName")
ret, err = invokeMethodOfAnyType(ctx, &book, "FullName")
assert.Nil(t, err)
assert.Equal(t, "Prefix Test", ret)

ret, err = invokeMethod(ctx, book, "AddBook", "Book 2")
ret, err = invokeMethodOfAnyType(ctx, book, "AddBook", "Book 2")
assert.Nil(t, err)
assert.Equal(t, "Add 'Book 2' ok", ret)

ret, err = invokeMethod(ctx, book, "GetContextKey")
ret, err = invokeMethodOfAnyType(ctx, book, "GetContextKey")
assert.Nil(t, err)
assert.Equal(t, "hello, world", ret)

ret, err = invokeMethod(ctx, book, "Plus", 100)
ret, err = invokeMethodOfAnyType(ctx, book, "Plus", 100)
assert.Nil(t, err)
assert.Equal(t, 200, ret)

ret, err = invokeMethod(ctx, book, "NoError")
ret, err = invokeMethodOfAnyType(ctx, book, "NoError")
assert.Nil(t, err)
assert.Equal(t, "no error", ret)

ret, err = invokeMethod(ctx, &book, "MethodNotFound")
ret, err = invokeMethodOfAnyType(ctx, &book, "MethodNotFound")
assert.Errorf(t, err, "method '*portal.Book.MethodNotFound' not found in 'Book'")

_, err = invokeMethod(ctx, &book, "Plus")
_, err = invokeMethodOfAnyType(ctx, &book, "Plus")
assert.NotNil(t, err)
assert.Equal(t, "method '*portal.Book.Plus' must has minimum 2 params: 1", err.Error())

_, err = invokeMethod(ctx, &book, "Plus", 1, 2)
_, err = invokeMethodOfAnyType(ctx, &book, "Plus", 1, 2)
assert.NotNil(t, err)
assert.Equal(t, "method '*portal.Book.Plus' must has 2 params: 3", err.Error())

_, err = invokeMethod(ctx, &book, "NotReturn")
_, err = invokeMethodOfAnyType(ctx, &book, "NotReturn")
assert.NotNil(t, err)
assert.Equal(t, "method '*portal.Book.NotReturn' must returns one result with an optional error", err.Error())

_, err = invokeMethod(ctx, &book, "ReturnTooMany")
_, err = invokeMethodOfAnyType(ctx, &book, "ReturnTooMany")
assert.NotNil(t, err)
assert.Equal(t, "method '*portal.Book.ReturnTooMany' must returns one result with an optional error", err.Error())

_, err = invokeMethod(ctx, &book, "ReturnError")
_, err = invokeMethodOfAnyType(ctx, &book, "ReturnError")
assert.NotNil(t, err)
assert.Equal(t, "error", err.Error())

_, err = invokeMethod(ctx, &book, "LastReturnValueNotErrorType")
_, err = invokeMethodOfAnyType(ctx, &book, "LastReturnValueNotErrorType")
assert.NotNil(t, err)
assert.Equal(t, "the last return value of method '*portal.Book.LastReturnValueNotErrorType' must be of `error` type", err.Error())
}
Expand Down Expand Up @@ -242,27 +242,27 @@ func (mk MessageKind) ValueWithArgs(a string) string {
func TestInvokeMethodOfNonStruct(t *testing.T) {
ctx := context.Background()
mk := MessageKind(1)
ret1, err1 := invokeMethod(ctx, mk, "Name")
ret1, err1 := invokeMethodOfAnyType(ctx, mk, "Name")
assert.Nil(t, err1)
assert.Equal(t, "ok", ret1.(string))

ret2, err2 := invokeMethod(ctx, &mk, "Name")
ret2, err2 := invokeMethodOfAnyType(ctx, &mk, "Name")
assert.Nil(t, err2)
assert.Equal(t, "ok", ret2.(string))

ret3, err3 := invokeMethod(ctx, mk, "Alias")
ret3, err3 := invokeMethodOfAnyType(ctx, mk, "Alias")
assert.Nil(t, err3)
assert.Equal(t, "alias_ok", ret3.(string))

ret4, err4 := invokeMethod(ctx, &mk, "Alias")
ret4, err4 := invokeMethodOfAnyType(ctx, &mk, "Alias")
assert.Nil(t, err4)
assert.Equal(t, "alias_ok", ret4.(string))

ret5, err5 := invokeMethod(ctx, &mk, "ValueWithArgs", "_hello")
ret5, err5 := invokeMethodOfAnyType(ctx, &mk, "ValueWithArgs", "_hello")
assert.Nil(t, err5)
assert.Equal(t, "ok_hello", ret5.(string))

_, err6 := invokeMethod(ctx, &mk, "NotFound", "_hello")
_, err6 := invokeMethodOfAnyType(ctx, &mk, "NotFound", "_hello")
assert.NotNil(t, err6)
assert.Equal(t, "method 'NotFound' not found in '*portal.MessageKind'", err6.Error())
}
Expand All @@ -273,7 +273,7 @@ func BenchmarkInvokeMethod(b *testing.B) {

book := Book{name: "Test"}
for i := 0; i < b.N; i++ {
_, _ = invokeMethod(context.TODO(), book, "FullName")
_, _ = invokeMethodOfAnyType(context.TODO(), book, "FullName")
}
}

Expand Down

0 comments on commit 5f05a79

Please sign in to comment.