diff --git a/builtin/builtin.go b/builtin/builtin.go index 35a9f687e..8dd37acc3 100644 --- a/builtin/builtin.go +++ b/builtin/builtin.go @@ -443,7 +443,21 @@ var Builtins = []*Function{ Name: "fromJSON", Func: func(args ...any) (any, error) { var v any - err := json.Unmarshal([]byte(args[0].(string)), &v) + var jsonStr string + + switch arg := args[0].(type) { + case string: + jsonStr = arg + case *string: + if arg == nil { + return nil, fmt.Errorf("nil string pointer") + } + jsonStr = *arg + default: + return nil, fmt.Errorf("expected string or *string, got %T", args[0]) + } + + err := json.Unmarshal([]byte(jsonStr), &v) if err != nil { return nil, err } diff --git a/builtin/builtin_test.go b/builtin/builtin_test.go index 499a838b7..5166c225c 100644 --- a/builtin/builtin_test.go +++ b/builtin/builtin_test.go @@ -638,3 +638,55 @@ func Test_int_unwraps_underlying_value(t *testing.T) { require.NoError(t, err) assert.Equal(t, true, out) } + +func TestBuiltin_json(t *testing.T) { + t.Run("fromJSON/string", func(t *testing.T) { + env := map[string]any{ + "json": `{"foo": "bar"}`, + } + program, err := expr.Compile(`fromJSON(json)`, expr.Env(env)) + require.NoError(t, err) + + out, err := expr.Run(program, env) + require.NoError(t, err) + assert.Equal(t, map[string]any{"foo": "bar"}, out) + }) + + t.Run("fromJSON/string pointer", func(t *testing.T) { + jsonString := `{"foo": "bar"}` + env := map[string]any{ + "json": &jsonString, + } + program, err := expr.Compile(`fromJSON(json)`, expr.Env(env)) + require.NoError(t, err) + + out, err := expr.Run(program, env) + require.NoError(t, err) + assert.Equal(t, map[string]any{"foo": "bar"}, out) + }) + + t.Run("toJSON/object", func(t *testing.T) { + env := map[string]any{ + "obj": map[string]any{"foo": "bar"}, + } + program, err := expr.Compile(`toJSON(obj)`, expr.Env(env)) + require.NoError(t, err) + + out, err := expr.Run(program, env) + require.NoError(t, err) + assert.Equal(t, "{\n \"foo\": \"bar\"\n}", out) + }) + + t.Run("toJSON/object pointer", func(t *testing.T) { + obj := map[string]any{"foo": "bar"} + env := map[string]any{ + "obj": &obj, + } + program, err := expr.Compile(`toJSON(obj)`, expr.Env(env)) + require.NoError(t, err) + + out, err := expr.Run(program, env) + require.NoError(t, err) + assert.Equal(t, "{\n \"foo\": \"bar\"\n}", out) + }) +}