/
map.go
144 lines (126 loc) · 3.57 KB
/
map.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package data
import (
"bytes"
"encoding/json"
"fmt"
"time"
)
// Map is a map of Values. It can be assigned to Value interface. Only
// string keys are allowed.
type Map map[string]Value
// Type returns TypeID of Map. It's always TypeMap.
func (m Map) Type() TypeID {
return TypeMap
}
func (m Map) asBool() (bool, error) {
return false, castError(m.Type(), TypeBool)
}
func (m Map) asInt() (int64, error) {
return 0, castError(m.Type(), TypeInt)
}
func (m Map) asFloat() (float64, error) {
return 0, castError(m.Type(), TypeFloat)
}
func (m Map) asString() (string, error) {
return "", castError(m.Type(), TypeString)
}
func (m Map) asBlob() ([]byte, error) {
return nil, castError(m.Type(), TypeBlob)
}
func (m Map) asTimestamp() (time.Time, error) {
return time.Time{}, castError(m.Type(), TypeTimestamp)
}
func (m Map) asArray() (Array, error) {
return nil, castError(m.Type(), TypeArray)
}
func (m Map) asMap() (Map, error) {
return m, nil
}
func (m Map) clone() Value {
return m.Copy()
}
// String returns JSON representation of a Map.
func (m Map) String() string {
// the String return value is defined via the
// default JSON serialization
bytes, err := json.Marshal(m)
if err != nil {
return fmt.Sprintf("(unserializable map: %v)", err)
}
return string(bytes)
}
// UnmarshalJSON reconstructs a Map from JSON.
func (m *Map) UnmarshalJSON(data []byte) error {
var j map[string]interface{}
dec := json.NewDecoder(bytes.NewReader(data))
dec.UseNumber()
if err := dec.Decode(&j); err != nil {
return err
}
newMap, err := NewMap(j)
if err != nil {
return err
}
*m = newMap
return nil
}
// Copy performs deep copy of a Map. The Map returned from this method can
// safely be modified without affecting the original.
func (m Map) Copy() Map {
out := make(map[string]Value, len(m))
for key, val := range m {
out[key] = val.clone()
}
return Map(out)
}
// Get returns value(s) from a structured Map as addressed by the
// given path expression. Returns an error when the path expression
// is invalid or the path is not found in the Map.
//
// Type conversion can be done for each type using the Value
// interface's methods.
//
// Example:
// p, err := CompilePath("path")
// if err != nil { ... }
// v, err := map.Get(p)
// if err != nil { ... }
// s, err := v.asString() // cast to String
//
// Path Expression Example:
// Given the following Map structure
// Map{
// "store": Map{
// "name": String("store name"),
// "book": Array([]Value{
// Map{
// "title": String("book name"),
// },
// }),
// },
// }
// To get values, access the following path expressions
// `store` -> get store's Map
// `store.name` -> get "store name"
// `store.book[0].title -> get "book name"
// or
// `["store"]` -> get store's Map
// `["store"]["name"]` -> get "store name"
// `["store"]["book"][0]["title"]` -> get "book name"
//
func (m Map) Get(path Path) (Value, error) {
return path.evaluate(m)
}
// Set sets a value in a structured Map as addressed by the
// given path expression. It is possible to set items even
// if the parent levels do not exist (`mkdir -p` behavior),
// i.e., you can set an item at "stores[17].owner.name" also
// when there is no "stores" key in the top-level Map. If a
// list index is higher than the current length, intermediate
// items will be created as Null items.
// Set returns an error when the path expression is invalid or
// when one of the intermediate components already exists
// but is not a map/list.
func (m Map) Set(path Path, val Value) error {
return path.set(m, val)
}