Skip to content

Commit

Permalink
[Internal] Generate Effective Fields (#4057)
Browse files Browse the repository at this point in the history
This PR introduces changes to the TFSDK generator to support “effective
fields” for server-provided values. When fields are marked with the new
proto annotation `ServerProposedIfEmpty` (name pending final decision,
until then the `computed` annotation is used to indicate these fields,
while specific fields are excluded), the generator will create an
additional computed field (e.g., `Effective<FieldName>`) and add two
sync functions to ensure proper handling of user-provided and
server-determined values.

### Generated Struct:
```
type ResourceModel struct {
    OriginalField    types.String `tfsdk:"original_field" tf:"optional"`
    EffectiveField   types.String `tfsdk:"effective_field" tf:"computed"`
}
```
### Sync Functions:
```
func (newState *ResourceModel) SyncEffectiveFieldsDuringCreateOrUpdate(plan ResourceModel) {
    newState.EffectiveField = newState.OriginalField
    newState.OriginalField = plan.OriginalField
}

func (newState *ResourceModel) SyncEffectiveFieldsDuringRead(existingState ResourceModel) {
    if existingState.EffectiveField.ValueString() == newState.OriginalField.ValueString() {
        newState.OriginalField = existingState.OriginalField
    }
}
```


## Changes
<!-- Summary of your changes that are easy to understand -->

## Tests
<!-- 
How is this tested? Please see the checklist below and also describe any
other relevant tests
-->

- [ ] `make test` run locally
- [ ] relevant change in `docs/` folder
- [ ] covered with integration tests in `internal/acceptance`
- [ ] relevant acceptance tests are passing
- [ ] using Go SDK

---------

Co-authored-by: Omer Lachish <[email protected]>
  • Loading branch information
rauchy and rauchy authored Oct 15, 2024
1 parent ef27ec5 commit 1f59bfd
Showing 1 changed file with 56 additions and 2 deletions.
58 changes: 56 additions & 2 deletions .codegen/model.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,74 @@ import (
"github.com/databricks/databricks-sdk-go/marshal"
"github.com/hashicorp/terraform-plugin-framework/types"
)
{{- $excluded := dict "ShareInfo" (list "CreatedAt" "CreatedBy" "UpdatedAt" "UpdatedBy")
"SharedDataObject" (list "AddedAt" "AddedBy" "Status") -}}
{{range .Types}}
{{- if or .Fields .IsEmpty}}
{{.Comment "// " 80}}
type {{.PascalName}} struct {
{{- $excluded := getOrDefault $excluded .PascalName (list) -}}
{{- range .Fields}}
{{.Comment " // " 80}}
{{.PascalName}} {{template "type" .Entity}} `{{template "field-tag" . }}`{{end}}
{{- $data := dict "field" . "excluded" $excluded }}
{{template "field" $data}}{{if and .Entity.IsComputed (not (in $excluded .PascalName))}}{{ $data := dict "field" . "excluded" $excluded "effective" true }}{{printf "\n"}}{{template "field" $data}}{{end}}{{end}}
}

func (newState *{{.PascalName}}) SyncEffectiveFieldsDuringCreateOrUpdate(plan {{.PascalName}}) {
{{- range .Fields -}}
{{- if and .Entity.IsComputed (or .Entity.IsString .Entity.IsBool .Entity.IsInt64 .Entity.IsFloat64 .Entity.IsInt .Entity.Enum) -}}
{{- if not (in $excluded .PascalName)}}
newState.Effective{{.PascalName}} = newState.{{.PascalName}}
newState.{{.PascalName}} = plan.{{.PascalName}}
{{- end}}
{{- end}}
{{- end}}
}

func (newState *{{.PascalName}}) SyncEffectiveFieldsDuringRead(existingState {{.PascalName}}) {
{{- range .Fields -}}
{{- if and .Entity.IsComputed (or .Entity.IsString .Entity.IsBool .Entity.IsInt64 .Entity.IsFloat64 .Entity.IsInt .Entity.Enum) -}}
{{- if not (in $excluded .PascalName) -}}
{{- $type := "" -}}
{{- if .Entity.IsString}}{{$type = "String"}}{{end}}
{{- if .Entity.IsBool}}{{$type = "Bool"}}{{end}}
{{- if .Entity.IsInt64}}{{$type = "Int64"}}{{end}}
{{- if .Entity.IsFloat64}}{{$type = "Float64"}}{{end}}
{{- if .Entity.IsInt}}{{$type = "Int64"}}{{end}}
{{- if .Entity.Enum}}{{$type = "String"}}{{end}}
if existingState.Effective{{.PascalName}}.Value{{$type}}() == newState.{{.PascalName}}.Value{{$type}}() {
newState.{{.PascalName}} = existingState.{{.PascalName}}
}
{{- end}}
{{- end}}
{{- end}}
}

{{end}}
{{end}}

{{- define "field" -}}
{{if .effective}}Effective{{end}}{{.field.PascalName}} {{template "type" .field.Entity}} `{{template "field-tag" . }}`
{{- end -}}

{{- define "field-tag" -}}
{{if .IsJson}}tfsdk:"{{if and (ne .Entity.Terraform nil) (ne .Entity.Terraform.Alias "") }}{{.Entity.Terraform.Alias}}{{else}}{{.Name}}{{end}}" tf:"{{- $first := true -}}{{- if not .Required -}}{{- if not $first -}},{{end}}optional{{- $first = false -}}{{- end -}}{{- if .Entity.IsObject -}}{{- if not $first -}},{{end}}object{{- $first = false -}}{{- end -}}"{{else}}tfsdk:"-"{{end -}}
{{- $annotations := "" -}}
{{- if in .excluded .field.PascalName -}}
{{- $annotations = (printf "%scomputed,optional," $annotations) -}}
{{- else if .effective -}}
{{- $annotations = (printf "%scomputed,optional," $annotations) -}}
{{- else -}}
{{- if not .field.Required -}}
{{- $annotations = (printf "%soptional," $annotations) -}}
{{- end -}}
{{- if .field.Entity.IsObject -}}
{{- $annotations = (printf "%sobject," $annotations) -}}
{{- end -}}
{{- end -}}
{{- if gt (len $annotations) 0 -}}
{{- $annotations = (printf "%s" (trimSuffix "," $annotations)) -}}
{{- end -}}
{{if .field.IsJson}}tfsdk:"{{if and (ne .field.Entity.Terraform nil) (ne .field.Entity.Terraform.Alias "") }}{{.field.Entity.Terraform.Alias}}{{else}}{{if .effective}}effective_{{end}}{{.field.Name}}{{end}}" tf:"{{$annotations}}"{{else}}tfsdk:"-"{{end -}}
{{- end -}}

{{- define "type" -}}
Expand Down

0 comments on commit 1f59bfd

Please sign in to comment.