Skip to content

SetP has unexpected outcome with gabs.Container as value #108

Description

@2manyvcos

Please look at the following example:

package main

import (
	"fmt"
	
	"github.com/Jeffail/gabs/v2"
)

func main() {
	a := gabs.New()
	
        b := gabs.New()
        b.SetP(1, "test")

        // normally: a.SetP(b.Data(), "inner")
        a.SetP(b, "inner")
	
	fmt.Println(a.Path("inner.test").Data())
	fmt.Println(a.String())
}

Output:

<nil>
{"inner":{"test":1}}

As you can see, with gabs v2 there is an issue when setting an attribute to a *gabs.Container instead of its Data().

When you do a.SetP(b, "inner") with gabs v1, "inner" would result in an empty object, which is fine as it indicates that you are not allowed to do this and should do a.SetP(b.Data(), "inner") instead.

However, with v2 when you do a.SetP(b, "inner"), a.String() returns a valid JSON as if the operation was successful and so a.inner looks like it was set to the contents of b.
But subsequent operations on "inner" would fail (e.g. a.SetP(2, "inner.test2")).
When merging a into another gabs object, inner is also replaced as a whole instead of merging its contents.

I think checking if the value of SetP (and potentially other related functions) is a gabs.Container would be a really helpful thing to prevent this confusion, for instance:

func (g *Container) SetP(value interface{}, path string) (*Container, error) {
	if checkIsContainer(value) {
		return g.Set(value.Data(), DotPathToSlice(path)...)
	}
	return g.Set(value, DotPathToSlice(path)...)
}

func checkIsContainer(v interface{}) bool {
	_, ok := v.(*Container)
	return ok
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions