From ef9a89bfc4db1c59a1136e6f1f9a41f91a673030 Mon Sep 17 00:00:00 2001 From: Artem Voronin Date: Tue, 6 May 2025 21:19:34 -0700 Subject: [PATCH] Fix: deepObject return without assign on !required --- bindparam.go | 2 +- bindparam_test.go | 4 ++++ deepobject.go | 12 ++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/bindparam.go b/bindparam.go index 2daf378..a92a0bd 100644 --- a/bindparam.go +++ b/bindparam.go @@ -469,7 +469,7 @@ func BindQueryParameter(style string, explode bool, required bool, paramName str if !explode { return errors.New("deepObjects must be exploded") } - return UnmarshalDeepObject(dest, paramName, queryParams) + return unmarshalDeepObject(dest, paramName, queryParams, required) case "spaceDelimited", "pipeDelimited": return fmt.Errorf("query arguments of style '%s' aren't yet supported", style) default: diff --git a/bindparam_test.go b/bindparam_test.go index 42da394..363c27a 100644 --- a/bindparam_test.go +++ b/bindparam_test.go @@ -322,6 +322,10 @@ func TestBindQueryParameter(t *testing.T) { err := BindQueryParameter("deepObject", true, false, paramName, queryParams, &actual) assert.NoError(t, err) assert.Equal(t, expectedDeepObject, actual) + + // If we require values, we require errors when they're not present. + err = BindQueryParameter("deepObject", true, true, "notfound", queryParams, &actual) + assert.Error(t, err) }) t.Run("form", func(t *testing.T) { diff --git a/deepobject.go b/deepobject.go index 7ec2f02..d06bf53 100644 --- a/deepobject.go +++ b/deepobject.go @@ -124,6 +124,10 @@ func makeFieldOrValue(paths [][]string, values []string) fieldOrValue { } func UnmarshalDeepObject(dst interface{}, paramName string, params url.Values) error { + return unmarshalDeepObject(dst, paramName, params, false) +} + +func unmarshalDeepObject(dst interface{}, paramName string, params url.Values, required bool) error { // Params are all the query args, so we need those that look like // "paramName["... var fieldNames []string @@ -141,6 +145,14 @@ func UnmarshalDeepObject(dst interface{}, paramName string, params url.Values) e } } + if len(fieldNames) == 0 { + if required { + return fmt.Errorf("query parameter '%s' is required", paramName) + } else { + return nil + } + } + // Now, for each field, reconstruct its subscript path and value paths := make([][]string, len(fieldNames)) for i, path := range fieldNames {