@@ -16,7 +16,24 @@ import (
1616// terraform-plugin-go. Third parties should not use it, and its behavior is
1717// not covered under the API compatibility guarantees. Don't use this.
1818func ValueFromJSON (data []byte , typ Type ) (Value , error ) {
19- return jsonUnmarshal (data , typ , NewAttributePath ())
19+ return jsonUnmarshal (data , typ , NewAttributePath (), ValueFromJSONOpts {})
20+ }
21+
22+ // ValueFromJSONOpts contains options that can be used to modify the behaviour when
23+ // unmarshalling JSON.
24+ type ValueFromJSONOpts struct {
25+ // IgnoreUndefinedAttributes is used to ignore any attributes which appear in the
26+ // JSON but do not have a corresponding entry in the schema. For example, raw state
27+ // where an attribute has been removed from the schema.
28+ IgnoreUndefinedAttributes bool
29+ }
30+
31+ // ValueFromJSONWithOpts is identical to ValueFromJSON with the exception that it
32+ // accepts ValueFromJSONOpts which can be used to modify the unmarshalling behaviour, such
33+ // as ignoring undefined attributes, for instance. This can occur when the JSON
34+ // being unmarshalled does not have a corresponding attribute in the schema.
35+ func ValueFromJSONWithOpts (data []byte , typ Type , opts ValueFromJSONOpts ) (Value , error ) {
36+ return jsonUnmarshal (data , typ , NewAttributePath (), opts )
2037}
2138
2239func jsonByteDecoder (buf []byte ) * json.Decoder {
@@ -26,7 +43,7 @@ func jsonByteDecoder(buf []byte) *json.Decoder {
2643 return dec
2744}
2845
29- func jsonUnmarshal (buf []byte , typ Type , p * AttributePath ) (Value , error ) {
46+ func jsonUnmarshal (buf []byte , typ Type , p * AttributePath , opts ValueFromJSONOpts ) (Value , error ) {
3047 dec := jsonByteDecoder (buf )
3148
3249 tok , err := dec .Token ()
@@ -46,18 +63,17 @@ func jsonUnmarshal(buf []byte, typ Type, p *AttributePath) (Value, error) {
4663 case typ .Is (Bool ):
4764 return jsonUnmarshalBool (buf , typ , p )
4865 case typ .Is (DynamicPseudoType ):
49- return jsonUnmarshalDynamicPseudoType (buf , typ , p )
66+ return jsonUnmarshalDynamicPseudoType (buf , typ , p , opts )
5067 case typ .Is (List {}):
51- return jsonUnmarshalList (buf , typ .(List ).ElementType , p )
68+ return jsonUnmarshalList (buf , typ .(List ).ElementType , p , opts )
5269 case typ .Is (Set {}):
53- return jsonUnmarshalSet (buf , typ .(Set ).ElementType , p )
54-
70+ return jsonUnmarshalSet (buf , typ .(Set ).ElementType , p , opts )
5571 case typ .Is (Map {}):
56- return jsonUnmarshalMap (buf , typ .(Map ).ElementType , p )
72+ return jsonUnmarshalMap (buf , typ .(Map ).ElementType , p , opts )
5773 case typ .Is (Tuple {}):
58- return jsonUnmarshalTuple (buf , typ .(Tuple ).ElementTypes , p )
74+ return jsonUnmarshalTuple (buf , typ .(Tuple ).ElementTypes , p , opts )
5975 case typ .Is (Object {}):
60- return jsonUnmarshalObject (buf , typ .(Object ).AttributeTypes , p )
76+ return jsonUnmarshalObject (buf , typ .(Object ).AttributeTypes , p , opts )
6177 }
6278 return Value {}, p .NewErrorf ("unknown type %s" , typ )
6379}
@@ -140,7 +156,7 @@ func jsonUnmarshalBool(buf []byte, _ Type, p *AttributePath) (Value, error) {
140156 return Value {}, p .NewErrorf ("unsupported type %T sent as %s" , tok , Bool )
141157}
142158
143- func jsonUnmarshalDynamicPseudoType (buf []byte , _ Type , p * AttributePath ) (Value , error ) {
159+ func jsonUnmarshalDynamicPseudoType (buf []byte , _ Type , p * AttributePath , opts ValueFromJSONOpts ) (Value , error ) {
144160 dec := jsonByteDecoder (buf )
145161 tok , err := dec .Token ()
146162 if err != nil {
@@ -190,10 +206,10 @@ func jsonUnmarshalDynamicPseudoType(buf []byte, _ Type, p *AttributePath) (Value
190206 if valBody == nil {
191207 return Value {}, p .NewErrorf ("missing value in dynamically-typed value" )
192208 }
193- return jsonUnmarshal (valBody , t , p )
209+ return jsonUnmarshal (valBody , t , p , opts )
194210}
195211
196- func jsonUnmarshalList (buf []byte , elementType Type , p * AttributePath ) (Value , error ) {
212+ func jsonUnmarshalList (buf []byte , elementType Type , p * AttributePath , opts ValueFromJSONOpts ) (Value , error ) {
197213 dec := jsonByteDecoder (buf )
198214
199215 tok , err := dec .Token ()
@@ -227,7 +243,7 @@ func jsonUnmarshalList(buf []byte, elementType Type, p *AttributePath) (Value, e
227243 if err != nil {
228244 return Value {}, innerPath .NewErrorf ("error decoding value: %w" , err )
229245 }
230- val , err := jsonUnmarshal (rawVal , elementType , innerPath )
246+ val , err := jsonUnmarshal (rawVal , elementType , innerPath , opts )
231247 if err != nil {
232248 return Value {}, err
233249 }
@@ -254,7 +270,7 @@ func jsonUnmarshalList(buf []byte, elementType Type, p *AttributePath) (Value, e
254270 }, vals ), nil
255271}
256272
257- func jsonUnmarshalSet (buf []byte , elementType Type , p * AttributePath ) (Value , error ) {
273+ func jsonUnmarshalSet (buf []byte , elementType Type , p * AttributePath , opts ValueFromJSONOpts ) (Value , error ) {
258274 dec := jsonByteDecoder (buf )
259275
260276 tok , err := dec .Token ()
@@ -284,7 +300,7 @@ func jsonUnmarshalSet(buf []byte, elementType Type, p *AttributePath) (Value, er
284300 if err != nil {
285301 return Value {}, innerPath .NewErrorf ("error decoding value: %w" , err )
286302 }
287- val , err := jsonUnmarshal (rawVal , elementType , innerPath )
303+ val , err := jsonUnmarshal (rawVal , elementType , innerPath , opts )
288304 if err != nil {
289305 return Value {}, err
290306 }
@@ -310,7 +326,7 @@ func jsonUnmarshalSet(buf []byte, elementType Type, p *AttributePath) (Value, er
310326 }, vals ), nil
311327}
312328
313- func jsonUnmarshalMap (buf []byte , attrType Type , p * AttributePath ) (Value , error ) {
329+ func jsonUnmarshalMap (buf []byte , attrType Type , p * AttributePath , opts ValueFromJSONOpts ) (Value , error ) {
314330 dec := jsonByteDecoder (buf )
315331
316332 tok , err := dec .Token ()
@@ -341,7 +357,7 @@ func jsonUnmarshalMap(buf []byte, attrType Type, p *AttributePath) (Value, error
341357 if err != nil {
342358 return Value {}, innerPath .NewErrorf ("error decoding value: %w" , err )
343359 }
344- val , err := jsonUnmarshal (rawVal , attrType , innerPath )
360+ val , err := jsonUnmarshal (rawVal , attrType , innerPath , opts )
345361 if err != nil {
346362 return Value {}, err
347363 }
@@ -360,7 +376,7 @@ func jsonUnmarshalMap(buf []byte, attrType Type, p *AttributePath) (Value, error
360376 }, vals ), nil
361377}
362378
363- func jsonUnmarshalTuple (buf []byte , elementTypes []Type , p * AttributePath ) (Value , error ) {
379+ func jsonUnmarshalTuple (buf []byte , elementTypes []Type , p * AttributePath , opts ValueFromJSONOpts ) (Value , error ) {
364380 dec := jsonByteDecoder (buf )
365381
366382 tok , err := dec .Token ()
@@ -398,7 +414,7 @@ func jsonUnmarshalTuple(buf []byte, elementTypes []Type, p *AttributePath) (Valu
398414 if err != nil {
399415 return Value {}, innerPath .NewErrorf ("error decoding value: %w" , err )
400416 }
401- val , err := jsonUnmarshal (rawVal , elementType , innerPath )
417+ val , err := jsonUnmarshal (rawVal , elementType , innerPath , opts )
402418 if err != nil {
403419 return Value {}, err
404420 }
@@ -422,7 +438,9 @@ func jsonUnmarshalTuple(buf []byte, elementTypes []Type, p *AttributePath) (Valu
422438 }, vals ), nil
423439}
424440
425- func jsonUnmarshalObject (buf []byte , attrTypes map [string ]Type , p * AttributePath ) (Value , error ) {
441+ // jsonUnmarshalObject attempts to decode JSON object structure to tftypes.Value object.
442+ // opts contains fields that can be used to modify the behaviour of JSON unmarshalling.
443+ func jsonUnmarshalObject (buf []byte , attrTypes map [string ]Type , p * AttributePath , opts ValueFromJSONOpts ) (Value , error ) {
426444 dec := jsonByteDecoder (buf )
427445
428446 tok , err := dec .Token ()
@@ -446,6 +464,12 @@ func jsonUnmarshalObject(buf []byte, attrTypes map[string]Type, p *AttributePath
446464 }
447465 attrType , ok := attrTypes [key ]
448466 if ! ok {
467+ if opts .IgnoreUndefinedAttributes {
468+ // We are trying to ignore the key and value of any unsupported attribute.
469+ _ = dec .Decode (new (json.RawMessage ))
470+ continue
471+ }
472+
449473 return Value {}, innerPath .NewErrorf ("unsupported attribute %q" , key )
450474 }
451475 innerPath = p .WithAttributeName (key )
@@ -455,7 +479,7 @@ func jsonUnmarshalObject(buf []byte, attrTypes map[string]Type, p *AttributePath
455479 if err != nil {
456480 return Value {}, innerPath .NewErrorf ("error decoding value: %w" , err )
457481 }
458- val , err := jsonUnmarshal (rawVal , attrType , innerPath )
482+ val , err := jsonUnmarshal (rawVal , attrType , innerPath , opts )
459483 if err != nil {
460484 return Value {}, err
461485 }
0 commit comments