Fixed unmarshalling json input into `interface{}` type (#1832)

## Changes
Fixed unmarshalling json input into `interface{}` type

Commands like `api post` support free form request input, so it should
be unmarshaled correctly

## Tests
Added regression test + E2E test pass
This commit is contained in:
Andrew Nester 2024-10-15 14:10:02 +02:00 committed by GitHub
parent ab20624206
commit 0753dfe2f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 24 additions and 14 deletions

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"reflect"
"github.com/databricks/cli/libs/diag" "github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn/convert" "github.com/databricks/cli/libs/dyn/convert"
@ -63,11 +64,24 @@ func (j *JsonFlag) Unmarshal(v any) diag.Diagnostics {
return diags.Extend(diag.FromErr(err)) return diags.Extend(diag.FromErr(err))
} }
// Finally unmarshal the normalized data to the output. kind := reflect.ValueOf(v).Kind()
// It will fill in the ForceSendFields field if the struct contains it. if kind == reflect.Ptr {
err = marshal.Unmarshal(data, v) kind = reflect.ValueOf(v).Elem().Kind()
if err != nil { }
return diags.Extend(diag.FromErr(err))
if kind == reflect.Struct {
// Finally unmarshal the normalized data to the output.
// It will fill in the ForceSendFields field if the struct contains it.
err = marshal.Unmarshal(data, v)
if err != nil {
return diags.Extend(diag.FromErr(err))
}
} else {
// If the output is not a struct, just unmarshal the data to the output.
err = json.Unmarshal(data, v)
if err != nil {
return diags.Extend(diag.FromErr(err))
}
} }
return diags return diags

View File

@ -13,10 +13,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
type requestType struct {
Foo string `json:"foo"`
}
func TestJsonFlagEmpty(t *testing.T) { func TestJsonFlagEmpty(t *testing.T) {
var body JsonFlag var body JsonFlag
@ -35,13 +31,13 @@ func TestJsonFlagInline(t *testing.T) {
err := body.Set(`{"foo": "bar"}`) err := body.Set(`{"foo": "bar"}`)
assert.NoError(t, err) assert.NoError(t, err)
var request requestType var request any
diags := body.Unmarshal(&request) diags := body.Unmarshal(&request)
assert.NoError(t, diags.Error()) assert.NoError(t, diags.Error())
assert.Empty(t, diags) assert.Empty(t, diags)
assert.Equal(t, "JSON (14 bytes)", body.String()) assert.Equal(t, "JSON (14 bytes)", body.String())
assert.Equal(t, requestType{"bar"}, request) assert.Equal(t, map[string]any{"foo": "bar"}, request)
} }
func TestJsonFlagError(t *testing.T) { func TestJsonFlagError(t *testing.T) {
@ -50,7 +46,7 @@ func TestJsonFlagError(t *testing.T) {
err := body.Set(`{"foo":`) err := body.Set(`{"foo":`)
assert.NoError(t, err) assert.NoError(t, err)
var request requestType var request any
diags := body.Unmarshal(&request) diags := body.Unmarshal(&request)
assert.EqualError(t, diags.Error(), "error decoding JSON at (inline):1:8: unexpected end of JSON input") assert.EqualError(t, diags.Error(), "error decoding JSON at (inline):1:8: unexpected end of JSON input")
assert.Equal(t, "JSON (7 bytes)", body.String()) assert.Equal(t, "JSON (7 bytes)", body.String())
@ -58,7 +54,7 @@ func TestJsonFlagError(t *testing.T) {
func TestJsonFlagFile(t *testing.T) { func TestJsonFlagFile(t *testing.T) {
var body JsonFlag var body JsonFlag
var request requestType var request any
var fpath string var fpath string
var payload = []byte(`{"foo": "bar"}`) var payload = []byte(`{"foo": "bar"}`)
@ -78,7 +74,7 @@ func TestJsonFlagFile(t *testing.T) {
assert.NoError(t, diags.Error()) assert.NoError(t, diags.Error())
assert.Empty(t, diags) assert.Empty(t, diags)
assert.Equal(t, requestType{"bar"}, request) assert.Equal(t, map[string]any{"foo": "bar"}, request)
} }
const jsonData = ` const jsonData = `