From 408ec3feeca543cd79c1da46cc6cdee44cbee7bc Mon Sep 17 00:00:00 2001 From: Colleen Murphy Date: Mon, 18 Sep 2023 14:01:06 -0700 Subject: [PATCH] Add support for getting array index in GetValue Add the ability to use an index number to get an item out of a slice. The number will still be a string representation of an integer. For example, to get the last element from a nested slice like: ``` data := map[string]interface{}{ "data": []interface{}{ "first", "second", "third", }, } ``` Use keys like ``` val := GetValues(data, "dat", "2") ``` The initial data object still needs to be a `map[string]interface{}` type. --- pkg/data/values.go | 32 ++++++++++++++++++++++++++++---- pkg/data/values_test.go | 32 +++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/pkg/data/values.go b/pkg/data/values.go index 87ff6159..1942ec24 100644 --- a/pkg/data/values.go +++ b/pkg/data/values.go @@ -1,5 +1,9 @@ package data +import ( + "strconv" +) + func RemoveValue(data map[string]interface{}, keys ...string) (interface{}, bool) { for i, key := range keys { if i == len(keys)-1 { @@ -18,18 +22,38 @@ func GetValueN(data map[string]interface{}, keys ...string) interface{} { return val } -func GetValue(data map[string]interface{}, keys ...string) (interface{}, bool) { +func GetValue(data interface{}, keys ...string) (interface{}, bool) { for i, key := range keys { if i == len(keys)-1 { - val, ok := data[key] - return val, ok + if dataMap, ok := data.(map[string]interface{}); ok { + val, ok := dataMap[key] + return val, ok + } + if dataSlice, ok := data.([]interface{}); ok { + return itemByIndex(dataSlice, key) + } + } + if dataMap, ok := data.(map[string]interface{}); ok { + data, _ = dataMap[key] + } else if dataSlice, ok := data.([]interface{}); ok { + data, _ = itemByIndex(dataSlice, key) } - data, _ = data[key].(map[string]interface{}) } return nil, false } +func itemByIndex(dataSlice []interface{}, key string) (interface{}, bool) { + keyInt, err := strconv.Atoi(key) + if err != nil { + return nil, false + } + if keyInt >= len(dataSlice) || keyInt < 0 { + return nil, false + } + return dataSlice[keyInt], true +} + func PutValue(data map[string]interface{}, val interface{}, keys ...string) { if data == nil { return diff --git a/pkg/data/values_test.go b/pkg/data/values_test.go index 69aa96ca..9b9b52d3 100644 --- a/pkg/data/values_test.go +++ b/pkg/data/values_test.go @@ -56,7 +56,7 @@ func TestGetValue(t *testing.T) { name: "get index of slice", data: map[string]interface{}{ "parent": map[string]interface{}{ - "children": []string{ + "children": []interface{}{ "alice", "bob", "eve", @@ -64,6 +64,36 @@ func TestGetValue(t *testing.T) { }, }, keys: []string{"parent", "children", "2"}, + wantValue: "eve", + wantSuccess: true, + }, + { + name: "index is too big", + data: map[string]interface{}{ + "parent": map[string]interface{}{ + "children": []interface{}{ + "alice", + "bob", + "eve", + }, + }, + }, + keys: []string{"parent", "children", "3"}, + wantValue: nil, + wantSuccess: false, + }, + { + name: "index is negative", + data: map[string]interface{}{ + "parent": map[string]interface{}{ + "children": []interface{}{ + "alice", + "bob", + "eve", + }, + }, + }, + keys: []string{"parent", "children", "-3"}, wantValue: nil, wantSuccess: false, },