Commit 80729e9f by Kyle Brandt Committed by GitHub

Chore: remove unused go package dynmap (#23409)

parent 1496da03
// uses code from https://github.com/antonholmquist/jason/blob/master/jason.go
// MIT License
package dynmap
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"strings"
)
// Error values returned when validation functions fail
var (
ErrNotNull = errors.New("is not null")
ErrNotArray = errors.New("Not an array")
ErrNotNumber = errors.New("not a number")
ErrNotBool = errors.New("no bool")
ErrNotObject = errors.New("not an object")
ErrNotObjectArray = errors.New("not an object array")
ErrNotString = errors.New("not a string")
)
type KeyNotFoundError struct {
Key string
}
func (k KeyNotFoundError) Error() string {
if k.Key != "" {
return fmt.Sprintf("key '%s' not found", k.Key)
}
return "key not found"
}
// Value represents an arbitrary JSON value.
// It may contain a bool, number, string, object, array or null.
type Value struct {
data interface{}
exists bool // Used to separate nil and non-existing values
}
// Object represents an object JSON object.
// It inherets from Value but with an additional method to access
// a map representation of it's content. It's useful when iterating.
type Object struct {
Value
m map[string]*Value
valid bool
}
// Returns the golang map.
// Needed when iterating through the values of the object.
func (v *Object) Map() map[string]*Value {
return v.m
}
func NewFromMap(data map[string]interface{}) *Object {
val := &Value{data: data, exists: true}
obj, _ := val.Object()
return obj
}
func NewObject() *Object {
val := &Value{data: make(map[string]interface{}), exists: true}
obj, _ := val.Object()
return obj
}
// Creates a new value from an io.reader.
// Returns an error if the reader does not contain valid json.
// Useful for parsing the body of a net/http response.
// Example: NewFromReader(res.Body)
func NewValueFromReader(reader io.Reader) (*Value, error) {
j := new(Value)
d := json.NewDecoder(reader)
d.UseNumber()
err := d.Decode(&j.data)
return j, err
}
// Creates a new value from bytes.
// Returns an error if the bytes are not valid json.
func NewValueFromBytes(b []byte) (*Value, error) {
r := bytes.NewReader(b)
return NewValueFromReader(r)
}
func objectFromValue(v *Value, err error) (*Object, error) {
if err != nil {
return nil, err
}
o, err := v.Object()
if err != nil {
return nil, err
}
return o, nil
}
func NewObjectFromBytes(b []byte) (*Object, error) {
return objectFromValue(NewValueFromBytes(b))
}
func NewObjectFromReader(reader io.Reader) (*Object, error) {
return objectFromValue(NewValueFromReader(reader))
}
// Marshal into bytes.
func (v *Value) Marshal() ([]byte, error) {
return json.Marshal(v.data)
}
// Get the interyling data as interface
func (v *Value) Interface() interface{} {
return v.data
}
func (v *Value) StringMap() map[string]interface{} {
return v.data.(map[string]interface{})
}
// Private Get
func (v *Value) get(key string) (*Value, error) {
// Assume this is an object
obj, err := v.Object()
if err == nil {
child, ok := obj.Map()[key]
if ok {
return child, nil
}
return nil, KeyNotFoundError{key}
}
return nil, err
}
// Private get path
func (v *Value) getPath(keys []string) (*Value, error) {
current := v
var err error
for _, key := range keys {
current, err = current.get(key)
if err != nil {
return nil, err
}
}
return current, nil
}
// Gets the value at key path.
// Returns error if the value does not exist.
// Consider using the more specific Get<Type>(..) methods instead.
// Example:
// value, err := GetValue("address", "street")
func (v *Object) GetValue(keys ...string) (*Value, error) {
return v.getPath(keys)
}
// Gets the value at key path and attempts to typecast the value into an object.
// Returns error if the value is not a json object.
// Example:
// object, err := GetObject("person", "address")
func (v *Object) GetObject(keys ...string) (*Object, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
obj, err := child.Object()
if err != nil {
return nil, err
}
return obj, nil
}
// Gets the value at key path and attempts to typecast the value into a string.
// Returns error if the value is not a json string.
// Example:
// string, err := GetString("address", "street")
func (v *Object) GetString(keys ...string) (string, error) {
child, err := v.getPath(keys)
if err != nil {
return "", err
}
return child.String()
}
func (v *Object) MustGetString(path string, def string) string {
keys := strings.Split(path, ".")
str, err := v.GetString(keys...)
if err != nil {
return def
}
return str
}
// Gets the value at key path and attempts to typecast the value into null.
// Returns error if the value is not json null.
// Example:
// err := GetNull("address", "street")
func (v *Object) GetNull(keys ...string) error {
child, err := v.getPath(keys)
if err != nil {
return err
}
return child.Null()
}
// Gets the value at key path and attempts to typecast the value into a number.
// Returns error if the value is not a json number.
// Example:
// n, err := GetNumber("address", "street_number")
func (v *Object) GetNumber(keys ...string) (json.Number, error) {
child, err := v.getPath(keys)
if err != nil {
return "", err
}
n, err := child.Number()
if err != nil {
return "", err
}
return n, nil
}
// Gets the value at key path and attempts to typecast the value into a float64.
// Returns error if the value is not a json number.
// Example:
// n, err := GetNumber("address", "street_number")
func (v *Object) GetFloat64(keys ...string) (float64, error) {
child, err := v.getPath(keys)
if err != nil {
return 0, err
}
n, err := child.Float64()
if err != nil {
return 0, err
}
return n, nil
}
// Gets the value at key path and attempts to typecast the value into a float64.
// Returns error if the value is not a json number.
// Example:
// n, err := GetNumber("address", "street_number")
func (v *Object) GetInt64(keys ...string) (int64, error) {
child, err := v.getPath(keys)
if err != nil {
return 0, err
}
n, err := child.Int64()
if err != nil {
return 0, err
}
return n, nil
}
// Gets the value at key path and attempts to typecast the value into a float64.
// Returns error if the value is not a json number.
// Example:
// v, err := GetInterface("address", "anything")
func (v *Object) GetInterface(keys ...string) (interface{}, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
return child.Interface(), nil
}
// Gets the value at key path and attempts to typecast the value into a bool.
// Returns error if the value is not a json boolean.
// Example:
// married, err := GetBoolean("person", "married")
func (v *Object) GetBoolean(keys ...string) (bool, error) {
child, err := v.getPath(keys)
if err != nil {
return false, err
}
return child.Boolean()
}
// Gets the value at key path and attempts to typecast the value into an array.
// Returns error if the value is not a json array.
// Consider using the more specific Get<Type>Array() since it may reduce later type casts.
// Example:
// friends, err := GetValueArray("person", "friends")
// for i, friend := range friends {
// ... // friend will be of type Value here
// }
func (v *Object) GetValueArray(keys ...string) ([]*Value, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
return child.Array()
}
// Gets the value at key path and attempts to typecast the value into an array of objects.
// Returns error if the value is not a json array or if any of the contained objects are not objects.
// Example:
// friends, err := GetObjectArray("person", "friends")
// for i, friend := range friends {
// ... // friend will be of type Object here
// }
func (v *Object) GetObjectArray(keys ...string) ([]*Object, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
array, err := child.Array()
if err != nil {
return nil, err
}
typedArray := make([]*Object, len(array))
for index, arrayItem := range array {
typedArrayItem, err := arrayItem.
Object()
if err != nil {
return nil, err
}
typedArray[index] = typedArrayItem
}
return typedArray, nil
}
// Gets the value at key path and attempts to typecast the value into an array of string.
// Returns error if the value is not a json array or if any of the contained objects are not strings.
// Gets the value at key path and attempts to typecast the value into an array of objects.
// Returns error if the value is not a json array or if any of the contained objects are not objects.
// Example:
// friendNames, err := GetStringArray("person", "friend_names")
// for i, friendName := range friendNames {
// ... // friendName will be of type string here
// }
func (v *Object) GetStringArray(keys ...string) ([]string, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
array, err := child.Array()
if err != nil {
return nil, err
}
typedArray := make([]string, len(array))
for index, arrayItem := range array {
typedArrayItem, err := arrayItem.String()
if err != nil {
return nil, err
}
typedArray[index] = typedArrayItem
}
return typedArray, nil
}
// Gets the value at key path and attempts to typecast the value into an array of numbers.
// Returns error if the value is not a json array or if any of the contained objects are not numbers.
// Example:
// friendAges, err := GetNumberArray("person", "friend_ages")
// for i, friendAge := range friendAges {
// ... // friendAge will be of type float64 here
// }
func (v *Object) GetNumberArray(keys ...string) ([]json.Number, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
array, err := child.Array()
if err != nil {
return nil, err
}
typedArray := make([]json.Number, len(array))
for index, arrayItem := range array {
typedArrayItem, err := arrayItem.Number()
if err != nil {
return nil, err
}
typedArray[index] = typedArrayItem
}
return typedArray, nil
}
// Gets the value at key path and attempts to typecast the value into an array of floats.
// Returns error if the value is not a json array or if any of the contained objects are not numbers.
func (v *Object) GetFloat64Array(keys ...string) ([]float64, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
array, err := child.Array()
if err != nil {
return nil, err
}
typedArray := make([]float64, len(array))
for index, arrayItem := range array {
typedArrayItem, err := arrayItem.Float64()
if err != nil {
return nil, err
}
typedArray[index] = typedArrayItem
}
return typedArray, nil
}
// Gets the value at key path and attempts to typecast the value into an array of ints.
// Returns error if the value is not a json array or if any of the contained objects are not numbers.
func (v *Object) GetInt64Array(keys ...string) ([]int64, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
array, err := child.Array()
if err != nil {
return nil, err
}
typedArray := make([]int64, len(array))
for index, arrayItem := range array {
typedArrayItem, err := arrayItem.Int64()
if err != nil {
return nil, err
}
typedArray[index] = typedArrayItem
}
return typedArray, nil
}
// Gets the value at key path and attempts to typecast the value into an array of bools.
// Returns error if the value is not a json array or if any of the contained objects are not booleans.
func (v *Object) GetBooleanArray(keys ...string) ([]bool, error) {
child, err := v.getPath(keys)
if err != nil {
return nil, err
}
array, err := child.Array()
if err != nil {
return nil, err
}
typedArray := make([]bool, len(array))
for index, arrayItem := range array {
typedArrayItem, err := arrayItem.Boolean()
if err != nil {
return nil, err
}
typedArray[index] = typedArrayItem
}
return typedArray, nil
}
// Gets the value at key path and attempts to typecast the value into an array of nulls.
// Returns length, or an error if the value is not a json array or if any of the contained objects are not nulls.
func (v *Object) GetNullArray(keys ...string) (int64, error) {
child, err := v.getPath(keys)
if err != nil {
return 0, err
}
array, err := child.Array()
if err != nil {
return 0, err
}
var length int64 = 0
for _, arrayItem := range array {
err := arrayItem.Null()
if err != nil {
return 0, err
}
length++
}
return length, nil
}
// Returns an error if the value is not actually null
func (v *Value) Null() error {
var valid bool
// Check the type of this data
switch v.data.(type) {
case nil:
valid = v.exists // Valid only if j also exists, since other values could possibly also be nil
}
if valid {
return nil
}
return ErrNotNull
}
// Attempts to typecast the current value into an array.
// Returns error if the current value is not a json array.
// Example:
// friendsArray, err := friendsValue.Array()
func (v *Value) Array() ([]*Value, error) {
var valid bool
// Check the type of this data
switch v.data.(type) {
case []interface{}:
valid = true
}
// Unsure if this is a good way to use slices, it's probably not
var slice []*Value
if valid {
for _, element := range v.data.([]interface{}) {
child := Value{element, true}
slice = append(slice, &child)
}
return slice, nil
}
return slice, ErrNotArray
}
// Attempts to typecast the current value into a number.
// Returns error if the current value is not a json number.
// Example:
// ageNumber, err := ageValue.Number()
func (v *Value) Number() (json.Number, error) {
var valid bool
// Check the type of this data
switch v.data.(type) {
case json.Number:
valid = true
}
if valid {
return v.data.(json.Number), nil
}
return "", ErrNotNumber
}
// Attempts to typecast the current value into a float64.
// Returns error if the current value is not a json number.
// Example:
// percentage, err := v.Float64()
func (v *Value) Float64() (float64, error) {
n, err := v.Number()
if err != nil {
return 0, err
}
return n.Float64()
}
// Attempts to typecast the current value into a int64.
// Returns error if the current value is not a json number.
// Example:
// id, err := v.Int64()
func (v *Value) Int64() (int64, error) {
n, err := v.Number()
if err != nil {
return 0, err
}
return n.Int64()
}
// Attempts to typecast the current value into a bool.
// Returns error if the current value is not a json boolean.
// Example:
// marriedBool, err := marriedValue.Boolean()
func (v *Value) Boolean() (bool, error) {
var valid bool
// Check the type of this data
switch v.data.(type) {
case bool:
valid = true
}
if valid {
return v.data.(bool), nil
}
return false, ErrNotBool
}
// Attempts to typecast the current value into an object.
// Returns error if the current value is not a json object.
// Example:
// friendObject, err := friendValue.Object()
func (v *Value) Object() (*Object, error) {
var valid bool
// Check the type of this data
switch v.data.(type) {
case map[string]interface{}:
valid = true
}
if valid {
obj := new(Object)
obj.valid = valid
m := make(map[string]*Value)
if valid {
for key, element := range v.data.(map[string]interface{}) {
m[key] = &Value{element, true}
}
}
obj.data = v.data
obj.m = m
return obj, nil
}
return nil, ErrNotObject
}
// Attempts to typecast the current value into an object arrau.
// Returns error if the current value is not an array of json objects
// Example:
// friendObjects, err := friendValues.ObjectArray()
func (v *Value) ObjectArray() ([]*Object, error) {
var valid bool
// Check the type of this data
switch v.data.(type) {
case []interface{}:
valid = true
}
// Unsure if this is a good way to use slices, it's probably not
var slice []*Object
if valid {
for _, element := range v.data.([]interface{}) {
childValue := Value{element, true}
childObject, err := childValue.Object()
if err != nil {
return nil, ErrNotObjectArray
}
slice = append(slice, childObject)
}
return slice, nil
}
return nil, ErrNotObjectArray
}
// Attempts to typecast the current value into a string.
// Returns error if the current value is not a json string
// Example:
// nameObject, err := nameValue.String()
func (v *Value) String() (string, error) {
var valid bool
// Check the type of this data
switch v.data.(type) {
case string:
valid = true
}
if valid {
return v.data.(string), nil
}
return "", ErrNotString
}
// Returns the value a json formatted string.
// Note: The method named String() is used by golang's log method for logging.
// Example:
func (v *Object) String() string {
f, err := json.Marshal(v.data)
if err != nil {
return err.Error()
}
return string(f)
}
func (v *Object) SetValue(key string, value interface{}) *Value {
data := v.Interface().(map[string]interface{})
data[key] = value
return &Value{
data: value,
exists: true,
}
}
// uses code from https://github.com/antonholmquist/jason/blob/master/jason.go
// MIT License
package dynmap
import (
"log"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
type Assert struct {
T *testing.T
}
func NewAssert(t *testing.T) *Assert {
return &Assert{
T: t,
}
}
func (assert *Assert) True(value bool, message string) {
if !value {
log.Panicln("Assert: ", message)
}
}
func TestFirst(t *testing.T) {
anton := "anton"
street42 := "Street 42"
assert := NewAssert(t)
testJSON := `{
"name": "anton",
"age": 29,
"nothing": null,
"true": true,
"false": false,
"list": [
"first",
"second"
],
"list2": [
{
"street": "Street 42",
"city": "Stockholm"
},
{
"street": "Street 42",
"city": "Stockholm"
}
],
"address": {
"street": "Street 42",
"city": "Stockholm"
},
"country": {
"name": "Sweden"
}
}`
j, err := NewObjectFromBytes([]byte(testJSON))
assert.True(err == nil, "failed to create new object from bytes")
a, err := j.GetObject("address")
assert.True(a != nil && err == nil, "failed to create json from string")
assert.True(err == nil, "failed to create json from string")
s, err := j.GetString("name")
assert.True(s == anton && err == nil, "name should be a string")
s = j.MustGetString("name", "fallback")
assert.True(s == anton, "must get string")
s = j.MustGetString("adsasdas", "fallback")
assert.True(s == "fallback", "must get string return fallback")
s, err = j.GetString("name")
assert.True(s == anton && err == nil, "name should match")
s, err = j.GetString("address", "street")
assert.True(s == street42 && err == nil, "street should match")
//log.Println("s: ", s.String())
_, err = j.GetNumber("age")
assert.True(err == nil, "age should be a number")
n, err := j.GetInt64("age")
assert.True(n == 29 && err == nil, "age mismatch")
ageInterface, err := j.GetInterface("age")
assert.True(ageInterface != nil, "should be defined")
assert.True(err == nil, "age interface error")
invalidInterface, err := j.GetInterface("not_existing")
assert.True(invalidInterface == nil, "should not give error here")
assert.True(err != nil, "should give error here")
age, err := j.GetValue("age")
assert.True(age != nil && err == nil, "age should exist")
age2, err := j.GetValue("age2")
assert.True(age2 == nil && err != nil, "age2 should not exist")
address, err := j.GetObject("address")
assert.True(address != nil && err == nil, "address should be an object")
//log.Println("address: ", address)
s, err = address.GetString("street")
assert.True(s == street42 && err == nil, "street mismatching")
addressAsString, err := j.GetString("address")
assert.True(addressAsString == "" && err != nil, "address should not be an string")
s, err = j.GetString("address", "street")
assert.True(s == street42 && err == nil, "street mismatching")
s, err = j.GetString("address", "name2")
assert.True(s == "" && err != nil, "nonexistent string fail")
b, err := j.GetBoolean("true")
assert.True(b && err == nil, "bool true test")
b, err = j.GetBoolean("false")
assert.True(!b && err == nil, "bool false test")
b, err = j.GetBoolean("invalid_field")
assert.True(!b && err != nil, "bool invalid test")
list, err := j.GetValueArray("list")
assert.True(list != nil && err == nil, "list should be an array")
list2, err := j.GetValueArray("list2")
assert.True(list2 != nil && err == nil, "list2 should be an array")
list2Array, err := j.GetValueArray("list2")
assert.True(err == nil, "List2 should not return error on AsArray")
assert.True(len(list2Array) == 2, "List2 should should have length 2")
list2Value, err := j.GetValue("list2")
assert.True(err == nil, "List2 should not return error on value")
list2ObjectArray, err := list2Value.ObjectArray()
assert.True(err == nil, "list2Value should not return error on ObjectArray")
assert.True(len(list2ObjectArray) == 2, "list2ObjectArray should should have length 2")
for _, elementValue := range list2Array {
//assert.True(element.IsObject() == true, "first fail")
element, err := elementValue.Object()
assert.True(err == nil, "create element fail")
s, err = element.GetString("street")
assert.True(s == street42 && err == nil, "second fail")
}
obj, err := j.GetObject("country")
assert.True(obj != nil && err == nil, "country should not return error on AsObject")
for key, value := range obj.Map() {
assert.True(key == "name", "country name key incorrect")
s, err = value.String()
assert.True(s == "Sweden" && err == nil, "country name should be Sweden")
}
}
func TestSecond(t *testing.T) {
json := `
{
"data": [
{
"id": "X999_Y999",
"from": {
"name": "Tom Brady", "id": "X12"
},
"message": "Looking forward to 2010!",
"actions": [
{
"name": "Comment",
"link": "http://www.facebook.com/X999/posts/Y999"
},
{
"name": "Like",
"link": "http://www.facebook.com/X999/posts/Y999"
}
],
"type": "status",
"created_time": "2010-08-02T21:27:44+0000",
"updated_time": "2010-08-02T21:27:44+0000"
},
{
"id": "X998_Y998",
"from": {
"name": "Peyton Manning", "id": "X18"
},
"message": "Where's my contract?",
"actions": [
{
"name": "Comment",
"link": "http://www.facebook.com/X998/posts/Y998"
},
{
"name": "Like",
"link": "http://www.facebook.com/X998/posts/Y998"
}
],
"type": "status",
"created_time": "2010-08-02T21:27:44+0000",
"updated_time": "2010-08-02T21:27:44+0000"
}
]
}`
assert := NewAssert(t)
j, err := NewObjectFromBytes([]byte(json))
assert.True(j != nil && err == nil, "failed to parse json")
dataObject, err := j.GetObject("data")
assert.True(dataObject == nil && err != nil, "data should not be an object")
dataArray, err := j.GetObjectArray("data")
assert.True(dataArray != nil && err == nil, "data should be an object array")
for index, dataItem := range dataArray {
if index == 0 {
id, err := dataItem.GetString("id")
assert.True(id == "X999_Y999" && err == nil, "item id mismatch")
fromName, err := dataItem.GetString("from", "name")
assert.True(fromName == "Tom Brady" && err == nil, "fromName mismatch")
actions, err := dataItem.GetObjectArray("actions")
assert.True(err == nil, "get object from array failed")
for index, action := range actions {
if index == 1 {
name, err := action.GetString("name")
assert.True(name == "Like" && err == nil, "name mismatch")
link, err := action.GetString("link")
assert.True(link == "http://www.facebook.com/X999/posts/Y999" && err == nil, "Like mismatch")
}
}
} else if index == 1 {
id, err := dataItem.GetString("id")
assert.True(id == "X998_Y998" && err == nil, "item id mismatch")
}
}
}
func TestErrors(t *testing.T) {
json := `
{
"string": "hello",
"number": 1,
"array": [1,2,3]
}`
errstr := "expected an error getting %s, but got '%s'"
j, err := NewObjectFromBytes([]byte(json))
if err != nil {
t.Fatal("failed to parse json")
}
if _, err = j.GetObject("string"); err != ErrNotObject {
t.Errorf(errstr, "object", err)
}
if err = j.GetNull("string"); err != ErrNotNull {
t.Errorf(errstr, "null", err)
}
if _, err = j.GetStringArray("string"); err != ErrNotArray {
t.Errorf(errstr, "array", err)
}
if _, err = j.GetStringArray("array"); err != ErrNotString {
t.Errorf(errstr, "string array", err)
}
if _, err = j.GetNumber("array"); err != ErrNotNumber {
t.Errorf(errstr, "number", err)
}
if _, err = j.GetBoolean("array"); err != ErrNotBool {
t.Errorf(errstr, "boolean", err)
}
if _, err = j.GetString("number"); err != ErrNotString {
t.Errorf(errstr, "string", err)
}
_, err = j.GetString("not_found")
if e, ok := err.(KeyNotFoundError); !ok {
t.Errorf(errstr, "key not found error", e)
}
}
func TestWriting(t *testing.T) {
Convey("When writing", t, func() {
j, _ := NewObjectFromBytes([]byte(`{}`))
j.SetValue("prop", "value")
So(j.MustGetString("prop", ""), ShouldEqual, "value")
})
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment