12 // MSIConvertable is an interface that defines methods for converting your
13 // custom types to a map[string]interface{} representation.
14 type MSIConvertable interface {
15 // MSI gets a map[string]interface{} (msi) representing the
17 MSI() map[string]interface{}
20 // Map provides extended functionality for working with
21 // untyped data, in particular map[string]interface (msi).
22 type Map map[string]interface{}
24 // Value returns the internal value instance
25 func (m Map) Value() *Value {
26 return &Value{data: m}
29 // Nil represents a nil Map.
30 var Nil Map = New(nil)
32 // New creates a new Map containing the map[string]interface{} in the data argument.
33 // If the data argument is not a map[string]interface, New attempts to call the
34 // MSI() method on the MSIConvertable interface to create one.
35 func New(data interface{}) Map {
36 if _, ok := data.(map[string]interface{}); !ok {
37 if converter, ok := data.(MSIConvertable); ok {
38 data = converter.MSI()
43 return Map(data.(map[string]interface{}))
46 // MSI creates a map[string]interface{} and puts it inside a new Map.
48 // The arguments follow a key, value pattern.
52 // Panics if any key arugment is non-string or if there are an odd number of arguments.
56 // To easily create Maps:
58 // m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
60 // // creates an Map equivalent to
61 // m := objx.New(map[string]interface{}{"name": "Mat", "age": 29, "subobj": map[string]interface{}{"active": true}})
62 func MSI(keyAndValuePairs ...interface{}) Map {
64 newMap := make(map[string]interface{})
65 keyAndValuePairsLen := len(keyAndValuePairs)
67 if keyAndValuePairsLen%2 != 0 {
68 panic("objx: MSI must have an even number of arguments following the 'key, value' pattern.")
71 for i := 0; i < keyAndValuePairsLen; i = i + 2 {
73 key := keyAndValuePairs[i]
74 value := keyAndValuePairs[i+1]
76 // make sure the key is a string
77 keyString, keyStringOK := key.(string)
79 panic("objx: MSI must follow 'string, interface{}' pattern. " + keyString + " is not a valid key.")
82 newMap[keyString] = value
89 // ****** Conversion Constructors
91 // MustFromJSON creates a new Map containing the data specified in the
94 // Panics if the JSON is invalid.
95 func MustFromJSON(jsonString string) Map {
96 o, err := FromJSON(jsonString)
99 panic("objx: MustFromJSON failed with error: " + err.Error())
105 // FromJSON creates a new Map containing the data specified in the
108 // Returns an error if the JSON is invalid.
109 func FromJSON(jsonString string) (Map, error) {
112 err := json.Unmarshal([]byte(jsonString), &data)
118 return New(data), nil
122 // FromBase64 creates a new Obj containing the data specified
123 // in the Base64 string.
125 // The string is an encoded JSON string returned by Base64
126 func FromBase64(base64String string) (Map, error) {
128 decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
130 decoded, err := ioutil.ReadAll(decoder)
135 return FromJSON(string(decoded))
138 // MustFromBase64 creates a new Obj containing the data specified
139 // in the Base64 string and panics if there is an error.
141 // The string is an encoded JSON string returned by Base64
142 func MustFromBase64(base64String string) Map {
144 result, err := FromBase64(base64String)
147 panic("objx: MustFromBase64 failed with error: " + err.Error())
153 // FromSignedBase64 creates a new Obj containing the data specified
154 // in the Base64 string.
156 // The string is an encoded JSON string returned by SignedBase64
157 func FromSignedBase64(base64String, key string) (Map, error) {
158 parts := strings.Split(base64String, SignatureSeparator)
160 return nil, errors.New("objx: Signed base64 string is malformed.")
163 sig := HashWithKey(parts[0], key)
165 return nil, errors.New("objx: Signature for base64 data does not match.")
168 return FromBase64(parts[0])
171 // MustFromSignedBase64 creates a new Obj containing the data specified
172 // in the Base64 string and panics if there is an error.
174 // The string is an encoded JSON string returned by Base64
175 func MustFromSignedBase64(base64String, key string) Map {
177 result, err := FromSignedBase64(base64String, key)
180 panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
186 // FromURLQuery generates a new Obj by parsing the specified
189 // For queries with multiple values, the first value is selected.
190 func FromURLQuery(query string) (Map, error) {
192 vals, err := url.ParseQuery(query)
198 m := make(map[string]interface{})
199 for k, vals := range vals {
206 // MustFromURLQuery generates a new Obj by parsing the specified
209 // For queries with multiple values, the first value is selected.
211 // Panics if it encounters an error
212 func MustFromURLQuery(query string) Map {
214 o, err := FromURLQuery(query)
217 panic("objx: MustFromURLQuery failed with error: " + err.Error())