From 9fbb30c23e63122c490daf24f22ec3d0177b1442 Mon Sep 17 00:00:00 2001 From: Kirill Date: Wed, 16 Aug 2023 13:42:25 +0400 Subject: [PATCH] Allow passing empty/nil params in case all are optional (#1078) --- jsonrpc/server.go | 22 ++++++++++++++++++++-- utils/slices.go | 5 +++++ utils/slices_test.go | 24 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/jsonrpc/server.go b/jsonrpc/server.go index a89665afea..be0578374e 100644 --- a/jsonrpc/server.go +++ b/jsonrpc/server.go @@ -363,11 +363,15 @@ func (s *Server) handleRequest(ctx context.Context, req *request) (*response, er func (s *Server) buildArguments(ctx context.Context, params any, method Method) ([]reflect.Value, error) { if isNil(params) { - if len(method.Params) > 0 { + allParamsAreOptional := utils.All(method.Params, func(p Parameter) bool { + return p.Optional + }) + + if len(method.Params) > 0 && !allParamsAreOptional { return nil, errors.New("missing non-optional param field") } - return make([]reflect.Value, 0), nil + return s.buildDefaultArguments(ctx, method) } handlerType := reflect.TypeOf(method.Handler) @@ -423,6 +427,20 @@ func (s *Server) buildArguments(ctx context.Context, params any, method Method) return args, nil } +func (s *Server) buildDefaultArguments(_ context.Context, method Method) ([]reflect.Value, error) { + handlerType := reflect.TypeOf(method.Handler) + + numArgs := handlerType.NumIn() + args := make([]reflect.Value, 0, numArgs) + + for i := 0; i < numArgs; i++ { + arg := reflect.New(handlerType.In(i)).Elem() + args = append(args, arg) + } + + return args, nil +} + func (s *Server) parseParam(param any, t reflect.Type) (reflect.Value, error) { handlerParam := reflect.New(t) valueMarshaled, err := json.Marshal(param) // we have to marshal the value into JSON again diff --git a/utils/slices.go b/utils/slices.go index 1dcf249e22..a9a73cfc08 100644 --- a/utils/slices.go +++ b/utils/slices.go @@ -42,3 +42,8 @@ func IndexFunc[T comparable](slice []T, f func(T) bool) int { return -1 } + +// All returns true if all elements match the given predicate +func All[T comparable](slice []T, f func(T) bool) bool { + return IndexFunc(slice, func(e T) bool { return !f(e) }) == -1 +} diff --git a/utils/slices_test.go b/utils/slices_test.go index a7012658f3..824e844c72 100644 --- a/utils/slices_test.go +++ b/utils/slices_test.go @@ -65,3 +65,27 @@ func TestIndexFunc(t *testing.T) { assert.Equal(t, 2, idx) }) } + +func TestAll(t *testing.T) { + t.Run("nil slice", func(t *testing.T) { + var input []int + allValue := All(input, func(int) bool { + return false + }) + assert.True(t, allValue) + }) + t.Run("no element matches the predicate", func(t *testing.T) { + input := []int{1, 2, 3, 4} + allEven := All(input, func(v int) bool { + return v%2 == 0 + }) + assert.False(t, allEven) + }) + t.Run("all elements match the predicate", func(t *testing.T) { + input := []int{1, 3, 5, 7} + allOdd := All(input, func(v int) bool { + return v%2 != 0 + }) + assert.True(t, allOdd) + }) +}