123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- package myth
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "strconv"
- )
- type JSONQuery struct {
- data map[string]interface{}
- }
- func NewJSONQuery(data []byte) (jq *JSONQuery, err error) {
- obj := make(map[string]interface{})
-
- dec := json.NewDecoder(bytes.NewReader(data))
- err = dec.Decode(&obj)
- if err != nil {
- return
- }
- jq = new(JSONQuery)
- jq.data = obj
- return
- }
- func (jq *JSONQuery) Bool(s ...string) (bool, error) {
- val, err := rquery(jq.data, s...)
- if err != nil {
- return false, err
- }
- return boolFromInterface(val)
- }
- func (jq *JSONQuery) Float(s ...string) (float64, error) {
- val, err := rquery(jq.data, s...)
- if err != nil {
- return 0.0, err
- }
- return floatFromInterface(val)
- }
- func (jq *JSONQuery) Int(s ...string) (int, error) {
- val, err := rquery(jq.data, s...)
- if err != nil {
- return 0, err
- }
- return intFromInterface(val)
- }
- func (jq *JSONQuery) Int64(s ...string) (int64, error) {
- val, err := rquery(jq.data, s...)
- if err != nil {
- return 0, err
- }
- return int64FromInterface(val)
- }
- func (jq *JSONQuery) String(s ...string) (string, error) {
- val, err := rquery(jq.data, s...)
- if err != nil {
- return "", err
- }
- return stringFromInterface(val)
- }
- func (jq *JSONQuery) Object(s ...string) (map[string]interface{}, error) {
- val, err := rquery(jq.data, s...)
- if err != nil {
- return map[string]interface{}{}, err
- }
- return objectFromInterface(val)
- }
- func (jq *JSONQuery) Array(s ...string) ([]interface{}, error) {
- val, err := rquery(jq.data, s...)
- if err != nil {
- return []interface{}{}, err
- }
- return arrayFromInterface(val)
- }
- func (jq *JSONQuery) Interface(s ...string) (interface{}, error) {
- val, err := rquery(jq.data, s...)
- if err != nil {
- return nil, err
- }
- return val, nil
- }
- func (jq *JSONQuery) ArrayOfStrings(s ...string) ([]string, error) {
- array, err := jq.Array(s...)
- if err != nil {
- return []string{}, err
- }
- toReturn := make([]string, len(array))
- for index, val := range array {
- toReturn[index], err = stringFromInterface(val)
- if err != nil {
- return toReturn, err
- }
- }
- return toReturn, nil
- }
- func (jq *JSONQuery) ArrayOfInts(s ...string) ([]int, error) {
- array, err := jq.Array(s...)
- if err != nil {
- return []int{}, err
- }
- toReturn := make([]int, len(array))
- for index, val := range array {
- toReturn[index], err = intFromInterface(val)
- if err != nil {
- return toReturn, err
- }
- }
- return toReturn, nil
- }
- func (jq *JSONQuery) ArrayOfFloats(s ...string) ([]float64, error) {
- array, err := jq.Array(s...)
- if err != nil {
- return []float64{}, err
- }
- toReturn := make([]float64, len(array))
- for index, val := range array {
- toReturn[index], err = floatFromInterface(val)
- if err != nil {
- return toReturn, err
- }
- }
- return toReturn, nil
- }
- func (jq *JSONQuery) ArrayOfBools(s ...string) ([]bool, error) {
- array, err := jq.Array(s...)
- if err != nil {
- return []bool{}, err
- }
- toReturn := make([]bool, len(array))
- for index, val := range array {
- toReturn[index], err = boolFromInterface(val)
- if err != nil {
- return toReturn, err
- }
- }
- return toReturn, nil
- }
- func (jq *JSONQuery) ArrayOfObjects(s ...string) ([]map[string]interface{}, error) {
- array, err := jq.Array(s...)
- if err != nil {
- return []map[string]interface{}{}, err
- }
- toReturn := make([]map[string]interface{}, len(array))
- for index, val := range array {
- toReturn[index], err = objectFromInterface(val)
- if err != nil {
- return toReturn, err
- }
- }
- return toReturn, nil
- }
- func (jq *JSONQuery) ArrayOfArrays(s ...string) ([][]interface{}, error) {
- array, err := jq.Array(s...)
- if err != nil {
- return [][]interface{}{}, err
- }
- toReturn := make([][]interface{}, len(array))
- for index, val := range array {
- toReturn[index], err = arrayFromInterface(val)
- if err != nil {
- return toReturn, err
- }
- }
- return toReturn, nil
- }
- func (jq *JSONQuery) Matrix2D(s ...string) ([][]interface{}, error) {
- return jq.ArrayOfArrays(s...)
- }
- func rquery(blob interface{}, s ...string) (interface{}, error) {
- var (
- val interface{}
- err error
- )
- val = blob
- for _, q := range s {
- val, err = query(val, q)
- if err != nil {
- return nil, err
- }
- }
- switch val.(type) {
- case nil:
- return nil, fmt.Errorf("nil value")
- }
- return val, nil
- }
- func query(blob interface{}, query string) (interface{}, error) {
- index, err := strconv.Atoi(query)
-
- if err == nil {
- switch blob.(type) {
- case []interface{}:
- default:
- return nil, fmt.Errorf("Array index on non-array")
- }
- if len(blob.([]interface{})) > index {
- return blob.([]interface{})[index], nil
- }
- return nil, fmt.Errorf("Array index %d out of bounds", index)
- }
-
- switch blob.(type) {
- case map[string]interface{}:
- default:
- return nil, fmt.Errorf("Object lookup \"%s\" on non-object", query)
- }
- val, ok := blob.(map[string]interface{})[query]
- if !ok {
- return nil, fmt.Errorf("Object does not contain field %s", query)
- }
- return val, nil
- }
- func stringFromInterface(val interface{}) (string, error) {
- switch val.(type) {
- case string:
- return val.(string), nil
- }
- return "", fmt.Errorf("Expected string value for String, got \"%v\"", val)
- }
- func boolFromInterface(val interface{}) (bool, error) {
- switch val.(type) {
- case bool:
- return val.(bool), nil
- }
- return false, fmt.Errorf("Expected boolean value for Bool, got \"%v\"", val)
- }
- func floatFromInterface(val interface{}) (float64, error) {
- switch val.(type) {
- case float64:
- return val.(float64), nil
- case int:
- return float64(val.(int)), nil
- case string:
- fval, err := strconv.ParseFloat(val.(string), 64)
- if err == nil {
- return fval, nil
- }
- }
- return 0.0, fmt.Errorf("Expected numeric value for Float, got \"%v\"", val)
- }
- func intFromInterface(val interface{}) (int, error) {
- switch val.(type) {
- case float64:
- return int(val.(float64)), nil
- case string:
- ival, err := strconv.ParseFloat(val.(string), 64)
- if err == nil {
- return int(ival), nil
- }
- case int:
- return val.(int), nil
- }
- return 0, fmt.Errorf("Expected numeric value for Int, got \"%v\"", val)
- }
- func int64FromInterface(val interface{}) (int64, error) {
- switch val.(type) {
- case float64:
- return int64(val.(float64)), nil
- case string:
- ival, err := strconv.ParseFloat(val.(string), 64)
- if err == nil {
- return int64(ival), nil
- }
- case int:
- return int64(val.(int)), nil
- case int64:
- return val.(int64), nil
- }
- return 0, fmt.Errorf("Expected numeric value for Int, got \"%v\"", val)
- }
- func objectFromInterface(val interface{}) (map[string]interface{}, error) {
- switch val.(type) {
- case map[string]interface{}:
- return val.(map[string]interface{}), nil
- }
- return map[string]interface{}{}, fmt.Errorf("Expected json object for Object, got \"%v\"", val)
- }
- func arrayFromInterface(val interface{}) ([]interface{}, error) {
- switch val.(type) {
- case []interface{}:
- return val.([]interface{}), nil
- }
- return []interface{}{}, fmt.Errorf("Expected json array for Array, got \"%v\"", val)
- }
|