~tsileo/blobstash

ref: b178995e346d blobstash/pkg/docstore/maputil/maputil.go -rw-r--r-- 2.2 KiB
b178995eThomas Sileo vendor: update deps 2 years ago
                                                                                
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
package maputil // import "a4.io/blobstash/pkg/docstore/maputil"

import (
	"errors"
	"strconv"
	"strings"
)

var ErrKeyNotFound = errors.New("Key not found")

// FlattenList takes a `[]interface{}` and flatten/explode each items a map key.
// e.g.: ["s1", "s2"] => {"0": "s1", "1": "s2"}
func FlattenList(l []interface{}, parent, delimiter string) map[string]interface{} {
	out := map[string]interface{}{}
	var key string
	for i, ival := range l {
		if len(parent) > 0 {
			key = parent + delimiter + strconv.Itoa(i)
		} else {
			key = strconv.Itoa(i)
		}
		switch val := ival.(type) {
		case nil, int, float64, string, bool:
			out[key] = val
		case []interface{}:
			tmpout := FlattenList(val, key, delimiter)
			for tmpkey, tmpval := range tmpout {
				out[tmpkey] = tmpval
			}
		case map[string]interface{}:
			tmpout := FlattenMap(val, key, delimiter)
			for tmpkey, tmpval := range tmpout {
				out[tmpkey] = tmpval
			}

		default:
		}
	}
	return out
}

// FlattenMap takes a `map[string]interface{}` and flatten/explode it
// e.g.: {"k1": {"k2": 1}} => {"k1.k2": 1}
func FlattenMap(m map[string]interface{}, parent, delimiter string) map[string]interface{} {
	out := map[string]interface{}{}
	for key, ival := range m {
		if len(parent) > 0 {
			key = parent + delimiter + key
		}
		switch val := ival.(type) {
		case nil, int, float64, string, bool:
			out[key] = val
		case []interface{}:
			tmpout := FlattenList(val, key, delimiter)
			for tmpk, tmpv := range tmpout {
				out[tmpk] = tmpv
			}
		case map[string]interface{}:
			tmpout := FlattenMap(val, key, delimiter)
			for tmpk, tmpv := range tmpout {
				out[tmpk] = tmpv
			}
		default:
		}
	}
	return out
}

// GetPath returns the map value for the given "dot notation" path, or returns `ErrKeyNotFound`
func GetPath(doc map[string]interface{}, path string) (interface{}, error) {
	keys := strings.Split(path, ".")
	for i, key := range keys {
		if val, ok := doc[key]; ok {
			if i == len(keys)-1 {
				return val, nil
			}
			if mval, ok := val.(map[string]interface{}); ok {
				doc = mval
			} else {
				// The key exists, but it's not a map
				return nil, ErrKeyNotFound
			}
		} else {
			// The key doesn't exist
			return nil, ErrKeyNotFound
		}
	}
	return doc, nil
}