-
Notifications
You must be signed in to change notification settings - Fork 9.4k
/
map.go
163 lines (144 loc) · 4.73 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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package structured
import (
"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
)
// ChangeMap is a Change that represents a Map or an Object type, and has
// converted the relevant interfaces into maps for easier access.
type ChangeMap struct {
// Before contains the value before the proposed change.
Before map[string]interface{}
// After contains the value after the proposed change.
After map[string]interface{}
// Unknown contains the unknown status of any elements/attributes of this
// map/object.
Unknown map[string]interface{}
// BeforeSensitive contains the before sensitive status of any
// elements/attributes of this map/object.
BeforeSensitive map[string]interface{}
// AfterSensitive contains the after sensitive status of any
// elements/attributes of this map/object.
AfterSensitive map[string]interface{}
// ReplacePaths matches the same attributes in Change exactly.
ReplacePaths attribute_path.Matcher
// RelevantAttributes matches the same attributes in Change exactly.
RelevantAttributes attribute_path.Matcher
}
// AsMap converts the Change into an object or map representation by converting
// the internal Before, After, Unknown, BeforeSensitive, and AfterSensitive
// data structures into generic maps.
func (change Change) AsMap() ChangeMap {
return ChangeMap{
Before: genericToMap(change.Before),
After: genericToMap(change.After),
Unknown: genericToMap(change.Unknown),
BeforeSensitive: genericToMap(change.BeforeSensitive),
AfterSensitive: genericToMap(change.AfterSensitive),
ReplacePaths: change.ReplacePaths,
RelevantAttributes: change.RelevantAttributes,
}
}
// GetChild safely packages up a Change object for the given child, handling
// all the cases where the data might be null or a static boolean.
func (m ChangeMap) GetChild(key string) Change {
before, beforeExplicit := getFromGenericMap(m.Before, key)
after, afterExplicit := getFromGenericMap(m.After, key)
unknown, _ := getFromGenericMap(m.Unknown, key)
beforeSensitive, _ := getFromGenericMap(m.BeforeSensitive, key)
afterSensitive, _ := getFromGenericMap(m.AfterSensitive, key)
return Change{
BeforeExplicit: beforeExplicit,
AfterExplicit: afterExplicit,
Before: before,
After: after,
Unknown: unknown,
BeforeSensitive: beforeSensitive,
AfterSensitive: afterSensitive,
ReplacePaths: m.ReplacePaths.GetChildWithKey(key),
RelevantAttributes: m.RelevantAttributes.GetChildWithKey(key),
}
}
// ExplicitKeys returns the keys in the Before and After, as opposed to AllKeys
// which also includes keys from the additional meta structures (like the
// sensitive and unknown values).
//
// This function is useful for processing nested attributes and repeated blocks
// where the unknown and sensitive structs contain information about the actual
// attributes, while the before and after structs hold the actual nested values.
func (m ChangeMap) ExplicitKeys() []string {
keys := make(map[string]bool)
for before := range m.Before {
if _, ok := keys[before]; ok {
continue
}
keys[before] = true
}
for after := range m.After {
if _, ok := keys[after]; ok {
continue
}
keys[after] = true
}
var dedupedKeys []string
for key := range keys {
dedupedKeys = append(dedupedKeys, key)
}
return dedupedKeys
}
// AllKeys returns all the possible keys for this map. The keys for the map are
// potentially hidden and spread across multiple internal data structures and
// so this function conveniently packages them up.
func (m ChangeMap) AllKeys() []string {
keys := make(map[string]bool)
for before := range m.Before {
if _, ok := keys[before]; ok {
continue
}
keys[before] = true
}
for after := range m.After {
if _, ok := keys[after]; ok {
continue
}
keys[after] = true
}
for unknown := range m.Unknown {
if _, ok := keys[unknown]; ok {
continue
}
keys[unknown] = true
}
for sensitive := range m.AfterSensitive {
if _, ok := keys[sensitive]; ok {
continue
}
keys[sensitive] = true
}
for sensitive := range m.BeforeSensitive {
if _, ok := keys[sensitive]; ok {
continue
}
keys[sensitive] = true
}
var dedupedKeys []string
for key := range keys {
dedupedKeys = append(dedupedKeys, key)
}
return dedupedKeys
}
func getFromGenericMap(generic map[string]interface{}, key string) (interface{}, bool) {
if generic == nil {
return nil, false
}
if child, ok := generic[key]; ok {
return child, ok
}
return nil, false
}
func genericToMap(generic interface{}) map[string]interface{} {
if concrete, ok := generic.(map[string]interface{}); ok {
return concrete
}
return nil
}