Skip to content

Commit

Permalink
Adding TransformPlanDefaults for BoolAttribute (#668)
Browse files Browse the repository at this point in the history
  • Loading branch information
bendbennett committed Feb 14, 2023
1 parent 38c6858 commit c24881c
Show file tree
Hide file tree
Showing 13 changed files with 342 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,78 +1,77 @@
package fwxschema
package fwschema

import (
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults"
)

// AttributeWithBoolDefaultValue is an optional interface on Attribute which
// enables Bool default value support.
type AttributeWithBoolDefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.Bool
}

// AttributeWithFloat64DefaultValue is an optional interface on Attribute which
// enables Float64 default value support.
type AttributeWithFloat64DefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.Float64
}

// AttributeWithInt64DefaultValue is an optional interface on Attribute which
// enables Int64 default value support.
type AttributeWithInt64DefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.Int64
}

// AttributeWithListDefaultValue is an optional interface on Attribute which
// enables List default value support.
type AttributeWithListDefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.List
}

// AttributeWithMapDefaultValue is an optional interface on Attribute which
// enables Map default value support.
type AttributeWithMapDefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.Map
}

// AttributeWithNumberDefaultValue is an optional interface on Attribute which
// enables Number default value support.
type AttributeWithNumberDefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.Number
}

// AttributeWithObjectDefaultValue is an optional interface on Attribute which
// enables Object default value support.
type AttributeWithObjectDefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.Object
}

// AttributeWithSetDefaultValue is an optional interface on Attribute which
// enables Set default value support.
type AttributeWithSetDefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.Set
}

// AttributeWithStringDefaultValue is an optional interface on Attribute which
// enables String default value support.
type AttributeWithStringDefaultValue interface {
fwschema.Attribute
Attribute

DefaultValue() defaults.String
}
62 changes: 62 additions & 0 deletions internal/fwschemadata/data_default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package fwschemadata

import (
"context"

"github.com/hashicorp/terraform-plugin-go/tftypes"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fromtftypes"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/defaults"
)

// TransformPlanDefaults walks the schema and applies schema defined default values
// when the source Data type contains a null value at the same path.
// values. The reverse conversion is ReifyNullCollectionBlocks.
func (d *Data) TransformPlanDefaults(ctx context.Context) diag.Diagnostics {
var diags diag.Diagnostics

// Errors are handled as richer diag.Diagnostics instead.
d.TerraformValue, _ = tftypes.Transform(d.TerraformValue, func(tfTypePath *tftypes.AttributePath, tfTypeValue tftypes.Value) (tftypes.Value, error) {
// Do not transform if value is not null.
if !tfTypeValue.IsNull() {
return tfTypeValue, nil
}

fwPath, fwPathDiags := fromtftypes.AttributePath(ctx, tfTypePath, d.Schema)

diags.Append(fwPathDiags...)

// Do not transform if path cannot be converted.
// Checking against fwPathDiags will capture all errors.
if fwPathDiags.HasError() {
return tfTypeValue, nil
}

attrAtPath, attrAtPathDiags := d.Schema.AttributeAtPath(context.Background(), fwPath)

diags.Append(attrAtPathDiags...)

// Do not transform if schema attribute path cannot be retrieved.
// Checking against fwPathDiags will capture all errors.
if attrAtPathDiags.HasError() {
return tfTypeValue, nil
}

switch attrAtPath.(type) {
case fwschema.AttributeWithBoolDefaultValue:
attribWithBoolDefaultValue := attrAtPath.(fwschema.AttributeWithBoolDefaultValue)
defVal := attribWithBoolDefaultValue.DefaultValue()

resp := defaults.BoolResponse{}
defVal.DefaultBool(ctx, defaults.BoolRequest{}, &resp)

return tftypes.NewValue(tfTypeValue.Type(), resp.PlanValue.ValueBool()), nil
}

return tfTypeValue, nil
})

return diags
}
177 changes: 177 additions & 0 deletions internal/fwschemadata/data_default_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package fwschemadata_test

import (
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-go/tftypes"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschemadata"
"github.com/hashicorp/terraform-plugin-framework/internal/testing/testschema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/types"
)

func TestDataDefault(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
data *fwschemadata.Data
expected *fwschemadata.Data
expectedDiags diag.Diagnostics
}{
"bool-attribute-unmodified": {
data: &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: testschema.Schema{
Attributes: map[string]fwschema.Attribute{
"bool_attribute": testschema.Attribute{
Optional: true,
Type: types.BoolType,
},
},
},
TerraformValue: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"bool_attribute": tftypes.Bool,
},
},
map[string]tftypes.Value{
"bool_attribute": tftypes.NewValue(tftypes.Bool, true),
},
),
},
expected: &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: testschema.Schema{
Attributes: map[string]fwschema.Attribute{
"bool_attribute": testschema.Attribute{
Optional: true,
Type: types.BoolType,
},
},
},
TerraformValue: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"bool_attribute": tftypes.Bool,
},
},
map[string]tftypes.Value{
"bool_attribute": tftypes.NewValue(tftypes.Bool, true),
},
),
},
},
"bool-attribute-null": {
data: &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: testschema.Schema{
Attributes: map[string]fwschema.Attribute{
"bool_attribute": testschema.Attribute{
Optional: true,
Type: types.BoolType,
},
},
},
TerraformValue: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"bool_attribute": tftypes.Bool,
},
},
map[string]tftypes.Value{
"bool_attribute": tftypes.NewValue(tftypes.Bool, nil), // intentionally nil
},
),
},
expected: &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: testschema.Schema{
Attributes: map[string]fwschema.Attribute{
"bool_attribute": testschema.Attribute{
Optional: true,
Type: types.BoolType,
},
},
},
TerraformValue: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"bool_attribute": tftypes.Bool,
},
},
map[string]tftypes.Value{
"bool_attribute": tftypes.NewValue(tftypes.Bool, nil), // intentionally nil
},
),
},
},
"bool-attribute-null-default": {
data: &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: testschema.Schema{
Attributes: map[string]fwschema.Attribute{
"bool_attribute": testschema.AttributeWithBoolDefaultValue{
Optional: true,
Default: booldefault.StaticValue(false),
},
},
},
TerraformValue: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"bool_attribute": tftypes.Bool,
},
},
map[string]tftypes.Value{
"bool_attribute": tftypes.NewValue(tftypes.Bool, nil), // intentionally nil
},
),
},
expected: &fwschemadata.Data{
Description: fwschemadata.DataDescriptionConfiguration,
Schema: testschema.Schema{
Attributes: map[string]fwschema.Attribute{
"bool_attribute": testschema.AttributeWithBoolDefaultValue{
Optional: true,
Default: booldefault.StaticValue(false),
},
},
},
TerraformValue: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"bool_attribute": tftypes.Bool,
},
},
map[string]tftypes.Value{
"bool_attribute": tftypes.NewValue(tftypes.Bool, false), // intentionally nil
},
),
},
},
}

for name, testCase := range testCases {
name, testCase := name, testCase

t.Run(name, func(t *testing.T) {
t.Parallel()

diags := testCase.data.TransformPlanDefaults(context.Background())

if diff := cmp.Diff(diags, testCase.expectedDiags); diff != "" {
t.Errorf("unexpected diagnostics difference: %s", diff)
}

if diff := cmp.Diff(testCase.data, testCase.expected); diff != "" {
t.Errorf("unexpected difference: %s", diff)
}
})
}
}

0 comments on commit c24881c

Please sign in to comment.