Skip to content
Snippets Groups Projects
optional.go 3.83 KiB
Newer Older
  • Learn to ignore specific revisions
  • package utils
    
    import (
    	"context"
    
    	"github.com/hashicorp/terraform-plugin-framework/attr"
    	"github.com/hashicorp/terraform-plugin-framework/diag"
    	"github.com/hashicorp/terraform-plugin-framework/path"
    	"github.com/hashicorp/terraform-plugin-framework/types"
    
    	v20230301 "github.com/smallstep/terraform-provider-smallstep/internal/apiclient/v20230301"
    
    )
    
    // These helpers handle conversion from API types to terraform types for
    // optional fields. The challenge with optional fields is that they may be
    // either null or empty in terraform config, but the API returns nil for
    // both.  In this case use the value from state to avoid "inconsistent result
    // after apply" errors.
    // https://github.com/hashicorp/terraform/blob/main/docs/resource-instance-change-lifecycle.md#planresourcechange
    
    func ToOptionalSet(ctx context.Context, remote *[]string, priorState AttributeGetter, p path.Path) (types.Set, diag.Diagnostics) {
    	if remote == nil || len(*remote) == 0 {
    		setFromState := types.Set{}
    		diags := priorState.GetAttribute(ctx, p, &setFromState)
    		if diags.HasError() {
    			return types.Set{}, diags
    		}
    		if setFromState.IsNull() || len(setFromState.Elements()) == 0 {
    			return setFromState, diags
    		}
    	}
    
    	if remote == nil {
    		return types.SetNull(types.StringType), diag.Diagnostics{}
    	}
    
    	values := make([]attr.Value, len(*remote))
    	for i, s := range *remote {
    		values[i] = types.StringValue(s)
    	}
    	return types.SetValue(types.StringType, values)
    }
    
    
    func ToOptionalList(ctx context.Context, remote *[]string, priorState AttributeGetter, p path.Path) (types.List, diag.Diagnostics) {
    	if remote == nil || len(*remote) == 0 {
    		listFromState := types.List{}
    		diags := priorState.GetAttribute(ctx, p, &listFromState)
    		if diags.HasError() {
    			return types.List{}, diags
    		}
    		if listFromState.IsNull() || len(listFromState.Elements()) == 0 {
    			return listFromState, diags
    		}
    	}
    
    	if remote == nil {
    		return types.ListNull(types.StringType), diag.Diagnostics{}
    	}
    
    	values := make([]attr.Value, len(*remote))
    	for i, s := range *remote {
    		values[i] = types.StringValue(s)
    	}
    	return types.ListValue(types.StringType, values)
    }
    
    type Str interface {
    	string |
    		v20230301.EndpointKeyInfoFormat |
    		v20230301.EndpointKeyInfoType
    }
    
    func ToOptionalString[S Str](ctx context.Context, remote *S, priorState AttributeGetter, p path.Path) (types.String, diag.Diagnostics) {
    
    	if remote == nil || *remote == "" {
    		stringFromState := types.String{}
    		diags := priorState.GetAttribute(ctx, p, &stringFromState)
    		if diags.HasError() {
    			return types.String{}, diags
    		}
    		if stringFromState.IsNull() || stringFromState.ValueString() == "" {
    			return stringFromState, diags
    		}
    	}
    
    	if remote == nil {
    		return types.StringNull(), diag.Diagnostics{}
    	}
    
    
    	return types.StringValue(string(*remote)), diag.Diagnostics{}
    
    }
    
    func ToOptionalBool(ctx context.Context, remote *bool, priorState AttributeGetter, p path.Path) (types.Bool, diag.Diagnostics) {
    	if remote == nil || *remote == false {
    		boolFromState := types.Bool{}
    		diags := priorState.GetAttribute(ctx, p, &boolFromState)
    		if diags.HasError() {
    			return types.Bool{}, diags
    		}
    		if boolFromState.IsNull() || boolFromState.ValueBool() == false {
    			return boolFromState, diags
    		}
    	}
    
    	if remote == nil {
    		return types.BoolNull(), diag.Diagnostics{}
    	}
    
    	return types.BoolValue(*remote), diag.Diagnostics{}
    }
    
    
    func ToOptionalInt(ctx context.Context, remote *int, priorState AttributeGetter, p path.Path) (types.Int64, diag.Diagnostics) {
    	if remote == nil || *remote == 0 {
    		intFromState := types.Int64{}
    		diags := priorState.GetAttribute(ctx, p, &intFromState)
    		if diags.HasError() {
    			return types.Int64{}, diags
    		}
    		if intFromState.IsNull() || intFromState.ValueInt64() == 0 {
    			return intFromState, diags
    		}
    	}
    
    	if remote == nil {
    		return types.Int64Null(), diag.Diagnostics{}
    	}
    
    	return types.Int64Value(int64(*remote)), diag.Diagnostics{}
    }