From 6382fa08927d904acdf2ff03d261c2cc470b4104 Mon Sep 17 00:00:00 2001 From: team-humaki Date: Tue, 15 Sep 2026 11:33:52 -0700 Subject: [PATCH] Set: unwrap nested *Json so Get can traverse them Fixes #95 --- simplejson.go | 20 +++++++++++++++++++- simplejson_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/simplejson.go b/simplejson.go index 486fe49..eacb1b9 100644 --- a/simplejson.go +++ b/simplejson.go @@ -53,6 +53,23 @@ func (j *Json) MarshalJSON() ([]byte, error) { return json.Marshal(&j.data) } +// unwrapJSON stores the underlying payload when val is a Json wrapper. +// Get() wraps map values in a new Json; leaving a *Json in the map would +// make nested Get/Map fail because they type-assert to map[string]interface{}. +func unwrapJSON(val interface{}) interface{} { + switch v := val.(type) { + case *Json: + if v == nil { + return nil + } + return v.data + case Json: + return v.data + default: + return val + } +} + // Set modifies `Json` map by `key` and `value` // Useful for changing single key/value in a `Json` object easily. func (j *Json) Set(key string, val interface{}) { @@ -60,12 +77,13 @@ func (j *Json) Set(key string, val interface{}) { if err != nil { return } - m[key] = val + m[key] = unwrapJSON(val) } // SetPath modifies `Json`, recursively checking/creating map keys for the supplied path, // and then finally writing in the value func (j *Json) SetPath(branch []string, val interface{}) { + val = unwrapJSON(val) if len(branch) == 0 { j.data = val return diff --git a/simplejson_test.go b/simplejson_test.go index 2ddc89b..c735f19 100644 --- a/simplejson_test.go +++ b/simplejson_test.go @@ -221,6 +221,48 @@ func TestSet(t *testing.T) { } } +func TestSetJsonValue(t *testing.T) { + xx, err := NewJson([]byte(`{"name": "Alice"}`)) + if err != nil { + t.Fatalf("err %#v", err) + } + + yy := New() + yy.Set("Contact", xx) + s, err := yy.Get("Contact").Get("name").String() + if err != nil { + t.Fatalf("err %#v", err) + } + if s != "Alice" { + t.Errorf("got %#v", s) + } + + yy2 := New() + yy2.Set("Contact", xx.Interface()) + s, err = yy2.Get("Contact").Get("name").String() + if err != nil { + t.Fatalf("err %#v", err) + } + if s != "Alice" { + t.Errorf("got %#v", s) + } + + yy.SetPath([]string{"nested", "contact"}, xx) + s, err = yy.GetPath("nested", "contact", "name").String() + if err != nil { + t.Fatalf("err %#v", err) + } + if s != "Alice" { + t.Errorf("got %#v", s) + } + + var n *Json + yy.Set("empty", n) + if yy.Get("empty").Interface() != nil { + t.Errorf("nil *Json should store nil, got %#v", yy.Get("empty").Interface()) + } +} + func TestReplace(t *testing.T) { js, err := NewJson([]byte(`{}`)) if err != nil {