Skip to content

Commit 80ee5cc

Browse files
author
Paddy Carver
committed
Actually handle null values.
When calling `tftypes.Value.As` actually handle null values. If casting to a pointer to a pointer, null values set the pointer to nil. If casting to just a pointer, null values set the variable to its empty value, because we can't safely assume we can store nil; the practice of calling `Value.As(&dst)` is too common, in which case `dst` wouldn't retain the nil the way users would expect. So we require a pointer to a pointer to be able to surface the nil value.
1 parent 01eb778 commit 80ee5cc

File tree

1 file changed

+50
-3
lines changed

1 file changed

+50
-3
lines changed

tfprotov5/tftypes/value.go

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,48 +45,95 @@ func (val Value) As(dst interface{}) error {
4545
if ok {
4646
return unmarshaler.UnmarshalTerraform5Type(val)
4747
}
48-
if val.IsNull() {
49-
return fmt.Errorf("unmarshaling null values is not supported")
50-
}
5148
if !val.IsKnown() {
5249
return fmt.Errorf("unmarshaling unknown values is not supported")
5350
}
5451
switch target := dst.(type) {
5552
case *string:
53+
if val.IsNull() {
54+
*target = ""
55+
return nil
56+
}
5657
v, ok := val.value.(string)
5758
if !ok {
5859
return fmt.Errorf("can't unmarshal %s into %T, expected string", val.typ, dst)
5960
}
6061
*target = v
6162
return nil
63+
case **string:
64+
if val.IsNull() {
65+
*target = nil
66+
return nil
67+
}
68+
return val.As(*target)
6269
case *big.Float:
70+
if val.IsNull() {
71+
target.Set(big.NewFloat(0))
72+
return nil
73+
}
6374
v, ok := val.value.(*big.Float)
6475
if !ok {
6576
return fmt.Errorf("can't unmarshal %s into %T, expected *big.Float", val.typ, dst)
6677
}
6778
target.Set(v)
6879
return nil
80+
case **big.Float:
81+
if val.IsNull() {
82+
*target = nil
83+
return nil
84+
}
85+
return val.As(*target)
6986
case *bool:
87+
if val.IsNull() {
88+
*target = false
89+
return nil
90+
}
7091
v, ok := val.value.(bool)
7192
if !ok {
7293
return fmt.Errorf("can't unmarshal %s into %T, expected boolean", val.typ, dst)
7394
}
7495
*target = v
7596
return nil
97+
case **bool:
98+
if val.IsNull() {
99+
*target = nil
100+
return nil
101+
}
102+
return val.As(*target)
76103
case *map[string]Value:
104+
if val.IsNull() {
105+
*target = map[string]Value{}
106+
return nil
107+
}
77108
v, ok := val.value.(map[string]Value)
78109
if !ok {
79110
return fmt.Errorf("can't unmarshal %s into %T, expected map[string]tftypes.Value", val.typ, dst)
80111
}
81112
*target = v
82113
return nil
114+
case **map[string]Value:
115+
if val.IsNull() {
116+
*target = nil
117+
return nil
118+
}
119+
return val.As(*target)
83120
case *[]Value:
121+
if val.IsNull() {
122+
*target = []Value{}
123+
return nil
124+
}
84125
v, ok := val.value.([]Value)
85126
if !ok {
86127
return fmt.Errorf("can't unmarshal %s into %T expected []tftypes.Value", val.typ, dst)
87128
}
88129
*target = v
89130
return nil
131+
case **[]Value:
132+
if val.IsNull() {
133+
*target = nil
134+
return nil
135+
}
136+
return val.As(*target)
90137
}
91138
return fmt.Errorf("can't unmarshal into %T, needs UnmarshalTerraform5Type method", dst)
92139
}

0 commit comments

Comments
 (0)