123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- package objx
- import (
- "encoding/base64"
- "encoding/json"
- "errors"
- "io/ioutil"
- "net/url"
- "strings"
- )
- // MSIConvertable is an interface that defines methods for converting your
- // custom types to a map[string]interface{} representation.
- type MSIConvertable interface {
- // MSI gets a map[string]interface{} (msi) representing the
- // object.
- MSI() map[string]interface{}
- }
- // Map provides extended functionality for working with
- // untyped data, in particular map[string]interface (msi).
- type Map map[string]interface{}
- // Value returns the internal value instance
- func (m Map) Value() *Value {
- return &Value{data: m}
- }
- // Nil represents a nil Map.
- var Nil = New(nil)
- // New creates a new Map containing the map[string]interface{} in the data argument.
- // If the data argument is not a map[string]interface, New attempts to call the
- // MSI() method on the MSIConvertable interface to create one.
- func New(data interface{}) Map {
- if _, ok := data.(map[string]interface{}); !ok {
- if converter, ok := data.(MSIConvertable); ok {
- data = converter.MSI()
- } else {
- return nil
- }
- }
- return Map(data.(map[string]interface{}))
- }
- // MSI creates a map[string]interface{} and puts it inside a new Map.
- //
- // The arguments follow a key, value pattern.
- //
- // Returns nil if any key argument is non-string or if there are an odd number of arguments.
- //
- // # Example
- //
- // To easily create Maps:
- //
- // m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
- //
- // // creates an Map equivalent to
- // m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}}
- func MSI(keyAndValuePairs ...interface{}) Map {
- newMap := Map{}
- keyAndValuePairsLen := len(keyAndValuePairs)
- if keyAndValuePairsLen%2 != 0 {
- return nil
- }
- for i := 0; i < keyAndValuePairsLen; i = i + 2 {
- key := keyAndValuePairs[i]
- value := keyAndValuePairs[i+1]
- // make sure the key is a string
- keyString, keyStringOK := key.(string)
- if !keyStringOK {
- return nil
- }
- newMap[keyString] = value
- }
- return newMap
- }
- // ****** Conversion Constructors
- // MustFromJSON creates a new Map containing the data specified in the
- // jsonString.
- //
- // Panics if the JSON is invalid.
- func MustFromJSON(jsonString string) Map {
- o, err := FromJSON(jsonString)
- if err != nil {
- panic("objx: MustFromJSON failed with error: " + err.Error())
- }
- return o
- }
- // MustFromJSONSlice creates a new slice of Map containing the data specified in the
- // jsonString. Works with jsons with a top level array
- //
- // Panics if the JSON is invalid.
- func MustFromJSONSlice(jsonString string) []Map {
- slice, err := FromJSONSlice(jsonString)
- if err != nil {
- panic("objx: MustFromJSONSlice failed with error: " + err.Error())
- }
- return slice
- }
- // FromJSON creates a new Map containing the data specified in the
- // jsonString.
- //
- // Returns an error if the JSON is invalid.
- func FromJSON(jsonString string) (Map, error) {
- var m Map
- err := json.Unmarshal([]byte(jsonString), &m)
- if err != nil {
- return Nil, err
- }
- return m, nil
- }
- // FromJSONSlice creates a new slice of Map containing the data specified in the
- // jsonString. Works with jsons with a top level array
- //
- // Returns an error if the JSON is invalid.
- func FromJSONSlice(jsonString string) ([]Map, error) {
- var slice []Map
- err := json.Unmarshal([]byte(jsonString), &slice)
- if err != nil {
- return nil, err
- }
- return slice, nil
- }
- // FromBase64 creates a new Obj containing the data specified
- // in the Base64 string.
- //
- // The string is an encoded JSON string returned by Base64
- func FromBase64(base64String string) (Map, error) {
- decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
- decoded, err := ioutil.ReadAll(decoder)
- if err != nil {
- return nil, err
- }
- return FromJSON(string(decoded))
- }
- // MustFromBase64 creates a new Obj containing the data specified
- // in the Base64 string and panics if there is an error.
- //
- // The string is an encoded JSON string returned by Base64
- func MustFromBase64(base64String string) Map {
- result, err := FromBase64(base64String)
- if err != nil {
- panic("objx: MustFromBase64 failed with error: " + err.Error())
- }
- return result
- }
- // FromSignedBase64 creates a new Obj containing the data specified
- // in the Base64 string.
- //
- // The string is an encoded JSON string returned by SignedBase64
- func FromSignedBase64(base64String, key string) (Map, error) {
- parts := strings.Split(base64String, SignatureSeparator)
- if len(parts) != 2 {
- return nil, errors.New("objx: Signed base64 string is malformed")
- }
- sig := HashWithKey(parts[0], key)
- if parts[1] != sig {
- return nil, errors.New("objx: Signature for base64 data does not match")
- }
- return FromBase64(parts[0])
- }
- // MustFromSignedBase64 creates a new Obj containing the data specified
- // in the Base64 string and panics if there is an error.
- //
- // The string is an encoded JSON string returned by Base64
- func MustFromSignedBase64(base64String, key string) Map {
- result, err := FromSignedBase64(base64String, key)
- if err != nil {
- panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
- }
- return result
- }
- // FromURLQuery generates a new Obj by parsing the specified
- // query.
- //
- // For queries with multiple values, the first value is selected.
- func FromURLQuery(query string) (Map, error) {
- vals, err := url.ParseQuery(query)
- if err != nil {
- return nil, err
- }
- m := Map{}
- for k, vals := range vals {
- m[k] = vals[0]
- }
- return m, nil
- }
- // MustFromURLQuery generates a new Obj by parsing the specified
- // query.
- //
- // For queries with multiple values, the first value is selected.
- //
- // Panics if it encounters an error
- func MustFromURLQuery(query string) Map {
- o, err := FromURLQuery(query)
- if err != nil {
- panic("objx: MustFromURLQuery failed with error: " + err.Error())
- }
- return o
- }
|