diff --git a/attr/value.go b/attr/value.go index b34a3bb73..4ce77e9de 100644 --- a/attr/value.go +++ b/attr/value.go @@ -57,9 +57,16 @@ type Value interface { // IsNull returns true if the Value is not set, or is explicitly set to null. IsNull() bool - // IsUnknown returns true if the value is not yet known. + // IsUnKnown returns true if the value is not yet known. + // If the value is an aggregate type, only the top level of the aggregate type + // is checked; elements and attributes are not checked. IsUnknown() bool + // IsFullyNullableKnown returns true if the value is nullable known. If the value + // is an aggregate type, IsFullyNullableKnown only returns true if all elements + // and attributes are nullable known, as well. + IsFullyNullableKnown() bool + // String returns a summary representation of either the underlying Value, // or UnknownValueString (``) when IsUnknown() returns true, // or NullValueString (``) when IsNull() return true. diff --git a/internal/testing/testtypes/bool.go b/internal/testing/testtypes/bool.go index 12e635f5b..62212deff 100644 --- a/internal/testing/testtypes/bool.go +++ b/internal/testing/testtypes/bool.go @@ -116,6 +116,10 @@ func (b Bool) IsUnknown() bool { return b.Bool.IsUnknown() } +func (b Bool) IsFullyNullableKnown() bool { + return b.Bool.IsFullyNullableKnown() +} + func (b Bool) String() string { return b.Bool.String() } diff --git a/internal/testing/testtypes/invalid.go b/internal/testing/testtypes/invalid.go index c6461d365..60b7dc47c 100644 --- a/internal/testing/testtypes/invalid.go +++ b/internal/testing/testtypes/invalid.go @@ -63,6 +63,10 @@ func (i Invalid) IsUnknown() bool { return false } +func (i Invalid) IsFullyNullableKnown() bool { + return false +} + func (i Invalid) String() string { return "" } diff --git a/internal/testing/testtypes/number.go b/internal/testing/testtypes/number.go index 9d4f3ca55..6075b1ea7 100644 --- a/internal/testing/testtypes/number.go +++ b/internal/testing/testtypes/number.go @@ -119,3 +119,7 @@ func (n Number) IsNull() bool { func (n Number) IsUnknown() bool { return n.Number.IsUnknown() } + +func (n Number) IsFullyNullableKnown() bool { + return n.Number.IsFullyNullableKnown() +} diff --git a/internal/testing/testtypes/numberwithvalidateattribute.go b/internal/testing/testtypes/numberwithvalidateattribute.go index 09067e74f..69fd4ea2e 100644 --- a/internal/testing/testtypes/numberwithvalidateattribute.go +++ b/internal/testing/testtypes/numberwithvalidateattribute.go @@ -75,6 +75,10 @@ func (v NumberValueWithValidateAttributeError) IsUnknown() bool { return v.InternalNumber.IsUnknown() } +func (v NumberValueWithValidateAttributeError) IsFullyNullableKnown() bool { + return v.InternalNumber.IsFullyNullableKnown() +} + func (v NumberValueWithValidateAttributeError) String() string { return v.InternalNumber.String() } @@ -145,6 +149,10 @@ func (v NumberValueWithValidateAttributeWarning) IsUnknown() bool { return v.InternalNumber.IsUnknown() } +func (v NumberValueWithValidateAttributeWarning) IsFullyNullableKnown() bool { + return v.InternalNumber.IsFullyNullableKnown() +} + func (v NumberValueWithValidateAttributeWarning) String() string { return v.InternalNumber.String() } diff --git a/internal/testing/testtypes/string.go b/internal/testing/testtypes/string.go index f1b06da81..f59c70535 100644 --- a/internal/testing/testtypes/string.go +++ b/internal/testing/testtypes/string.go @@ -127,6 +127,10 @@ func (s String) IsUnknown() bool { return s.InternalString.IsUnknown() } +func (s String) IsFullyNullableKnown() bool { + return s.InternalString.IsFullyNullableKnown() +} + func (s String) String() string { return s.InternalString.String() } diff --git a/internal/testing/testtypes/stringwithvalidateattribute.go b/internal/testing/testtypes/stringwithvalidateattribute.go index cb6440db0..f26984802 100644 --- a/internal/testing/testtypes/stringwithvalidateattribute.go +++ b/internal/testing/testtypes/stringwithvalidateattribute.go @@ -75,6 +75,10 @@ func (v StringValueWithValidateAttributeError) IsUnknown() bool { return v.InternalString.IsUnknown() } +func (v StringValueWithValidateAttributeError) IsFullyNullableKnown() bool { + return v.InternalString.IsFullyNullableKnown() +} + func (v StringValueWithValidateAttributeError) String() string { return v.InternalString.String() } @@ -145,6 +149,10 @@ func (v StringValueWithValidateAttributeWarning) IsUnknown() bool { return v.InternalString.IsUnknown() } +func (v StringValueWithValidateAttributeWarning) IsFullyNullableKnown() bool { + return v.InternalString.IsFullyNullableKnown() +} + func (v StringValueWithValidateAttributeWarning) String() string { return v.InternalString.String() } diff --git a/internal/testing/testtypes/stringwithvalidateparameter.go b/internal/testing/testtypes/stringwithvalidateparameter.go index 751bbcd47..1b4f871c6 100644 --- a/internal/testing/testtypes/stringwithvalidateparameter.go +++ b/internal/testing/testtypes/stringwithvalidateparameter.go @@ -75,6 +75,10 @@ func (v StringValueWithValidateParameterError) IsUnknown() bool { return v.InternalString.IsUnknown() } +func (v StringValueWithValidateParameterError) IsFullyNullableKnown() bool { + return v.InternalString.IsFullyNullableKnown() +} + func (v StringValueWithValidateParameterError) String() string { return v.InternalString.String() } diff --git a/types/basetypes/bool_value.go b/types/basetypes/bool_value.go index aa10b3981..0717c2bb6 100644 --- a/types/basetypes/bool_value.go +++ b/types/basetypes/bool_value.go @@ -138,6 +138,11 @@ func (b BoolValue) IsUnknown() bool { return b.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the Bool represents a currently nullable known value. +func (b BoolValue) IsFullyNullableKnown() bool { + return !b.IsUnknown() +} + // String returns a human-readable representation of the Bool value. // The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. diff --git a/types/basetypes/dynamic_value.go b/types/basetypes/dynamic_value.go index 07946e18c..8bf058d36 100644 --- a/types/basetypes/dynamic_value.go +++ b/types/basetypes/dynamic_value.go @@ -140,6 +140,12 @@ func (v DynamicValue) IsUnknown() bool { return v.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the DynamicValue's underlying value +// represents a currently nullable known value. +func (v DynamicValue) IsFullyNullableKnown() bool { + return v.value == nil || v.value.IsFullyNullableKnown() +} + // String returns a human-readable representation of the DynamicValue. The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. func (v DynamicValue) String() string { diff --git a/types/basetypes/float64_value.go b/types/basetypes/float64_value.go index fb9c19a5e..1267ce143 100644 --- a/types/basetypes/float64_value.go +++ b/types/basetypes/float64_value.go @@ -174,6 +174,11 @@ func (f Float64Value) IsUnknown() bool { return f.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the Float64 represents a currently nullable known value. +func (f Float64Value) IsFullyNullableKnown() bool { + return !f.IsUnknown() +} + // String returns a human-readable representation of the Float64 value. // The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. diff --git a/types/basetypes/int64_value.go b/types/basetypes/int64_value.go index bf8b3bd53..eb671920a 100644 --- a/types/basetypes/int64_value.go +++ b/types/basetypes/int64_value.go @@ -138,6 +138,11 @@ func (i Int64Value) IsUnknown() bool { return i.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the Int64 represents a currently nullable known value. +func (i Int64Value) IsFullyNullableKnown() bool { + return !i.IsUnknown() +} + // String returns a human-readable representation of the Int64 value. // The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. diff --git a/types/basetypes/list_value.go b/types/basetypes/list_value.go index f89cbb73f..281dc2fa0 100644 --- a/types/basetypes/list_value.go +++ b/types/basetypes/list_value.go @@ -297,6 +297,17 @@ func (l ListValue) IsUnknown() bool { return l.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the List represents a currently nullable known value, +// including all its elements, recursively. +func (l ListValue) IsFullyNullableKnown() bool { + for _, elem := range l.elements { + if !elem.IsFullyNullableKnown() { + return false + } + } + return true +} + // String returns a human-readable representation of the List value. // The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. diff --git a/types/basetypes/map_value.go b/types/basetypes/map_value.go index 56a64361c..0b41c9916 100644 --- a/types/basetypes/map_value.go +++ b/types/basetypes/map_value.go @@ -304,6 +304,17 @@ func (m MapValue) IsUnknown() bool { return m.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the Map represents a currently nullable known value, +// including all its elements, recursively. +func (m MapValue) IsFullyNullableKnown() bool { + for _, elem := range m.elements { + if !elem.IsFullyNullableKnown() { + return false + } + } + return true +} + // String returns a human-readable representation of the Map value. // The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. diff --git a/types/basetypes/missing_value.go b/types/basetypes/missing_value.go index 37f600d7d..c2a918900 100644 --- a/types/basetypes/missing_value.go +++ b/types/basetypes/missing_value.go @@ -42,6 +42,11 @@ func (v missingValue) IsUnknown() bool { return false } +// IsFullyNullableKnown returns false. +func (v missingValue) IsFullyNullableKnown() bool { + return !v.IsUnknown() +} + // String returns a human-readable representation of the value. // // The string returned here is not protected by any compatibility guarantees, diff --git a/types/basetypes/number_value.go b/types/basetypes/number_value.go index 28c89de5d..befdb9e2e 100644 --- a/types/basetypes/number_value.go +++ b/types/basetypes/number_value.go @@ -138,6 +138,11 @@ func (n NumberValue) IsUnknown() bool { return n.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the Number represents a currently nullable known value. +func (n NumberValue) IsFullyNullableKnown() bool { + return !n.IsUnknown() +} + // String returns a human-readable representation of the Number value. // The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. diff --git a/types/basetypes/object_value.go b/types/basetypes/object_value.go index baeb8c0eb..adbd035c3 100644 --- a/types/basetypes/object_value.go +++ b/types/basetypes/object_value.go @@ -361,6 +361,17 @@ func (o ObjectValue) IsUnknown() bool { return o.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the Object represents a currently nullable known value, +// including all its attributes, recursively. +func (o ObjectValue) IsFullyNullableKnown() bool { + for _, attr := range o.attributes { + if !attr.IsFullyNullableKnown() { + return false + } + } + return true +} + // String returns a human-readable representation of the Object value. // The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. diff --git a/types/basetypes/set_value.go b/types/basetypes/set_value.go index 9beb2da3d..140b48e52 100644 --- a/types/basetypes/set_value.go +++ b/types/basetypes/set_value.go @@ -305,6 +305,17 @@ func (s SetValue) IsUnknown() bool { return s.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the Set represents a currently nullable known value, +// including all its elements, recursively. +func (s SetValue) IsFullyNullableKnown() bool { + for _, elem := range s.elements { + if !elem.IsFullyNullableKnown() { + return false + } + } + return true +} + // String returns a human-readable representation of the Set value. // The string returned here is not protected by any compatibility guarantees, // and is intended for logging and error reporting. diff --git a/types/basetypes/string_value.go b/types/basetypes/string_value.go index 46ac22485..7ac60492c 100644 --- a/types/basetypes/string_value.go +++ b/types/basetypes/string_value.go @@ -148,6 +148,11 @@ func (s StringValue) IsUnknown() bool { return s.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the String represents a currently nullable known value. +func (s StringValue) IsFullyNullableKnown() bool { + return s.state != attr.ValueStateUnknown +} + // String returns a human-readable representation of the String value. Use // the ValueString method for Terraform data handling instead. // diff --git a/types/basetypes/tuple_value.go b/types/basetypes/tuple_value.go index 5987d3824..a32490f72 100644 --- a/types/basetypes/tuple_value.go +++ b/types/basetypes/tuple_value.go @@ -188,6 +188,17 @@ func (v TupleValue) IsUnknown() bool { return v.state == attr.ValueStateUnknown } +// IsFullyNullableKnown returns true if the Tuple represents a currently nullable known value, +// including all its elements, recursively. +func (v TupleValue) IsFullyNullableKnown() bool { + for _, elem := range v.elements { + if !elem.IsFullyNullableKnown() { + return false + } + } + return true +} + // String returns a human-readable representation of the Tuple. The string returned here is not protected by any // compatibility guarantees, and is intended for logging and error reporting. func (v TupleValue) String() string {