Skip to content

Commit

Permalink
Add iterating object fields as map and improved array support
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeffail committed Jul 19, 2015
1 parent 4f7cc4b commit 001079a
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 3 deletions.
89 changes: 86 additions & 3 deletions gabs.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,23 @@ func (g *Container) S(hierarchy ...string) *Container {
}

/*
Children - Return a slice of all the children of the array. This also works for objects, however, the
children returned for an object will NOT be in order and you lose the names of the returned objects
this way.
Index - Attempt to find and return an object with a JSON array by specifying the index of the
target.
*/
func (g *Container) Index(index int) *Container {
if array, ok := g.Data().([]interface{}); ok {
if index >= len(array) {
return &Container{nil}
}
return &Container{array[index]}
}
return &Container{nil}
}

/*
Children - Return a slice of all the children of the array. This also works for objects, however,
the children returned for an object will NOT be in order and you lose the names of the returned
objects this way.
*/
func (g *Container) Children() ([]*Container, error) {
if array, ok := g.Data().([]interface{}); ok {
Expand All @@ -150,6 +164,20 @@ func (g *Container) Children() ([]*Container, error) {
return nil, ErrNotObjOrArray
}

/*
ChildrenMap - Return a map of all the children of an object.
*/
func (g *Container) ChildrenMap() (map[string]*Container, error) {
if mmap, ok := g.Data().(map[string]interface{}); ok {
children := map[string]*Container{}
for name, obj := range mmap {
children[name] = &Container{obj}
}
return children, nil
}
return nil, ErrNotObj
}

/*---------------------------------------------------------------------------------------------------
*/

Expand Down Expand Up @@ -187,6 +215,20 @@ func (g *Container) SetP(value interface{}, path string) (*Container, error) {
return g.Set(value, strings.Split(path, ".")...)
}

/*
SetIndex - Set a value of an array element based on the index.
*/
func (g *Container) SetIndex(value interface{}, index int) (*Container, error) {
if array, ok := g.Data().([]interface{}); ok {
if index >= len(array) {
return &Container{nil}, ErrOutOfBounds
}
array[index] = value
return &Container{array[index]}, nil
}
return &Container{nil}, ErrNotArray
}

/*
Object - Create a new JSON object at a path. Returns an error if the path contains a collision with
a non object type.
Expand All @@ -202,6 +244,14 @@ func (g *Container) ObjectP(path string) (*Container, error) {
return g.Object(strings.Split(path, ".")...)
}

/*
ObjectI - Create a new JSON object at an array index. Returns an error if the object is not an array
or the index is out of bounds.
*/
func (g *Container) ObjectI(index int) (*Container, error) {
return g.SetIndex(map[string]interface{}{}, index)
}

/*
Array - Create a new JSON array at a path. Returns an error if the path contains a collision with
a non object type.
Expand All @@ -217,6 +267,39 @@ func (g *Container) ArrayP(path string) (*Container, error) {
return g.Array(strings.Split(path, ".")...)
}

/*
ArrayI - Create a new JSON array at an array index. Returns an error if the object is not an array
or the index is out of bounds.
*/
func (g *Container) ArrayI(index int) (*Container, error) {
return g.SetIndex([]interface{}{}, index)
}

/*
ArrayOfSize - Create a new JSON array of a particular size at a path. Returns an error if the path
contains a collision with a non object type.
*/
func (g *Container) ArrayOfSize(size int, path ...string) (*Container, error) {
a := make([]interface{}, size)
return g.Set(a, path...)
}

/*
ArrayOfSizeP - Does the same as ArrayOfSize, but using a dot notation JSON path.
*/
func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) {
return g.ArrayOfSize(size, strings.Split(path, ".")...)
}

/*
ArrayOfSizeI - Create a new JSON array of a particular size at an array index. Returns an error if
the object is not an array or the index is out of bounds.
*/
func (g *Container) ArrayOfSizeI(size, index int) (*Container, error) {
a := make([]interface{}, size)
return g.SetIndex(a, index)
}

/*---------------------------------------------------------------------------------------------------
*/

Expand Down
162 changes: 162 additions & 0 deletions gabs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,89 @@ func TestChildren(t *testing.T) {
}
}

func TestChildrenMap(t *testing.T) {
json1, _ := ParseJSON([]byte(`{
"objectOne":{"num":1},
"objectTwo":{"num":2},
"objectThree":{"num":3}
}`))

objectMap, err := json1.ChildrenMap()
if err != nil {
t.Error(err)
return
}

if len(objectMap) != 3 {
t.Errorf("Wrong num of elements in objectMap: %v != %v", len(objectMap), 3)
return
}

for key, val := range objectMap {
if "objectOne" == key {
if val := val.S("num").Data().(float64); val != 1 {
t.Errorf("%v != %v", val, 1)
}
} else if "objectTwo" == key {
if val := val.S("num").Data().(float64); val != 2 {
t.Errorf("%v != %v", val, 2)
}
} else if "objectThree" == key {
if val := val.S("num").Data().(float64); val != 3 {
t.Errorf("%v != %v", val, 3)
}
} else {
t.Errorf("Unexpected key: %v", key)
}
}

objectMap["objectOne"].Set(500, "num")
if val := json1.Path("objectOne.num").Data().(int); val != 500 {
t.Errorf("set objectOne failed: %v != %v", val, 500)
}
}

func TestNestedAnonymousArrays(t *testing.T) {
json1, _ := ParseJSON([]byte(`{
"array":[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ],
[{ "test" : 50 }]
]
}`))

childTest, err := json1.S("array").Index(0).Children()
if err != nil {
t.Error(err)
return
}

if val := childTest[0].Data().(float64); val != 1 {
t.Errorf("child test: %v != %v", val, 1)
}
if val := childTest[1].Data().(float64); val != 2 {
t.Errorf("child test: %v != %v", val, 2)
}
if val := childTest[2].Data().(float64); val != 3 {
t.Errorf("child test: %v != %v", val, 3)
}

if val := json1.Path("array").Index(1).Index(1).Data().(float64); val != 5 {
t.Errorf("nested child test: %v != %v", val, 5)
}

if val := json1.Path("array").Index(3).Index(0).S("test").Data().(float64); val != 50 {
t.Errorf("nested child object test: %v != %v", val, 50)
}

json1.Path("array").Index(3).Index(0).Set(200, "test")

if val := json1.Path("array").Index(3).Index(0).S("test").Data().(int); val != 200 {
t.Errorf("set nested child object: %v != %v", val, 200)
}
}

func TestArrays(t *testing.T) {
json1, _ := ParseJSON([]byte(`{
"languages":{
Expand Down Expand Up @@ -413,6 +496,85 @@ func TestArrays(t *testing.T) {
}
}

func TestArraysTwo(t *testing.T) {
json1 := New()

test1, _ := json1.ArrayOfSize(4, "test1")

if _, err := test1.ArrayOfSizeI(2, 0); err != nil {
t.Error(err)
}
if _, err := test1.ArrayOfSizeI(2, 1); err != nil {
t.Error(err)
}
if _, err := test1.ArrayOfSizeI(2, 2); err != nil {
t.Error(err)
}
if _, err := test1.ArrayOfSizeI(2, 3); err != nil {
t.Error(err)
}

if _, err := test1.ArrayOfSizeI(2, 4); err != ErrOutOfBounds {
t.Errorf("Index should have been out of bounds")
}

if _, err := json1.S("test1").Index(0).SetIndex(10, 0); err != nil {
t.Error(err)
}
if _, err := json1.S("test1").Index(0).SetIndex(11, 1); err != nil {
t.Error(err)
}

if _, err := json1.S("test1").Index(1).SetIndex(12, 0); err != nil {
t.Error(err)
}
if _, err := json1.S("test1").Index(1).SetIndex(13, 1); err != nil {
t.Error(err)
}

if _, err := json1.S("test1").Index(2).SetIndex(14, 0); err != nil {
t.Error(err)
}
if _, err := json1.S("test1").Index(2).SetIndex(15, 1); err != nil {
t.Error(err)
}

if _, err := json1.S("test1").Index(3).SetIndex(16, 0); err != nil {
t.Error(err)
}
if _, err := json1.S("test1").Index(3).SetIndex(17, 1); err != nil {
t.Error(err)
}

if val := json1.S("test1").Index(0).Index(0).Data().(int); val != 10 {
t.Errorf("create array: %v != %v", val, 10)
}
if val := json1.S("test1").Index(0).Index(1).Data().(int); val != 11 {
t.Errorf("create array: %v != %v", val, 11)
}

if val := json1.S("test1").Index(1).Index(0).Data().(int); val != 12 {
t.Errorf("create array: %v != %v", val, 12)
}
if val := json1.S("test1").Index(1).Index(1).Data().(int); val != 13 {
t.Errorf("create array: %v != %v", val, 13)
}

if val := json1.S("test1").Index(2).Index(0).Data().(int); val != 14 {
t.Errorf("create array: %v != %v", val, 14)
}
if val := json1.S("test1").Index(2).Index(1).Data().(int); val != 15 {
t.Errorf("create array: %v != %v", val, 15)
}

if val := json1.S("test1").Index(3).Index(0).Data().(int); val != 16 {
t.Errorf("create array: %v != %v", val, 16)
}
if val := json1.S("test1").Index(3).Index(1).Data().(int); val != 17 {
t.Errorf("create array: %v != %v", val, 17)
}
}

func TestLargeSample(t *testing.T) {
sample := []byte(`{
"test":{
Expand Down

0 comments on commit 001079a

Please sign in to comment.