Skip to content

feat: Generate terraform datasource structs #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 134 additions & 1 deletion pkg/translate/terraform_provider/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type spec struct {
OneOf map[string]*properties.SpecParam
}

func getReturnPangoTypeForProperty(pkgName string, parent string, prop *properties.SpecParam) string {
func returnPangoTypeForProperty(pkgName string, parent string, prop *properties.SpecParam) string {
if prop.Type == "" {
return fmt.Sprintf("%s.%s", pkgName, parent)
} else if prop.Type == "list" {
Expand Down Expand Up @@ -675,6 +675,139 @@ func RenderLocationsStateToPango(names *NameProvider, spec *properties.Normaliza
return processTemplate(locationsStateToPango, "render-locations-state-to-pango", data, commonFuncMap)
}

const dataSourceStructs = `
{{- range .Structs }}
type {{ .StructName }}{{ .ModelOrObject }} struct {
{{- range .Fields }}
{{ .Name }} {{ .Type }} {{ range .Tags }}{{ . }} {{ end }}
{{- end }}
}
{{- end }}
`

type datasourceStructFieldSpec struct {
Name string
Type string
Tags []string
}

type datasourceStructSpec struct {
StructName string
ModelOrObject string
Fields []datasourceStructFieldSpec
}

func terraformTypeForProperty(structPrefix string, prop *properties.SpecParam) string {
if prop.Type == "" {
return fmt.Sprintf("*%s%sObject", structPrefix, prop.Name.CamelCase)
}

if prop.Type == "list" && prop.Items.Type == "entry" {
return fmt.Sprintf("[]%s%sObject", structPrefix, prop.Name.CamelCase)
}

if prop.Type == "list" {
return fmt.Sprintf("[]types.%s", pascalCase(prop.Items.Type))
}

return fmt.Sprintf("types.%s", pascalCase(prop.Type))
}

func structFieldSpec(param *properties.SpecParam, structPrefix string) datasourceStructFieldSpec {
tfTag := fmt.Sprintf("`tfsdk:\"%s\"`", param.Name.Underscore)
return datasourceStructFieldSpec{
Name: param.Name.CamelCase,
Type: terraformTypeForProperty(structPrefix, param),
Tags: []string{tfTag},
}
}

func dataSourceStructContextForParam(structPrefix string, param *properties.SpecParam) []datasourceStructSpec {
var structs []datasourceStructSpec

structName := fmt.Sprintf("%s%s", structPrefix, param.Name.CamelCase)

var params []datasourceStructFieldSpec
if param.Spec != nil {
for _, elt := range param.Spec.Params {
params = append(params, structFieldSpec(elt, structName))
}

for _, elt := range param.Spec.OneOf {
params = append(params, structFieldSpec(elt, structName))
}
}

structs = append(structs, datasourceStructSpec{
StructName: structName,
ModelOrObject: "Object",
Fields: params,
})

if param.Spec == nil {
return structs
}

for _, elt := range param.Spec.Params {
if elt.Type == "" || (elt.Type == "list" && elt.Items.Type == "entry") {
structs = append(structs, dataSourceStructContextForParam(structName, elt)...)
}
}

for _, elt := range param.Spec.OneOf {
if elt.Type == "" || (elt.Type == "list" && elt.Items.Type == "entry") {
structs = append(structs, dataSourceStructContextForParam(structName, elt)...)
}
}

return structs
}

func dataSourceStructContext(spec *properties.Normalization) []datasourceStructSpec {
var structs []datasourceStructSpec

if spec.Spec == nil {
return nil
}

names := NewNameProvider(spec)

var fields []datasourceStructFieldSpec

for _, elt := range spec.Spec.Params {
fields = append(fields, structFieldSpec(elt, names.DataSourceStructName))
if elt.Type == "" || (elt.Type == "list" && elt.Items.Type == "entry") {
structs = append(structs, dataSourceStructContextForParam(names.DataSourceStructName, elt)...)
}
}

for _, elt := range spec.Spec.OneOf {
fields = append(fields, structFieldSpec(elt, names.DataSourceStructName))
if elt.Type == "" || (elt.Type == "list" && elt.Items.Type == "entry") {
structs = append(structs, dataSourceStructContextForParam(names.DataSourceStructName, elt)...)
}
}

structs = append(structs, datasourceStructSpec{
StructName: names.DataSourceStructName,
ModelOrObject: "Model",
Fields: fields,
})
return structs
}

func RenderDataSourceStructs(names *NameProvider, spec *properties.Normalization) (string, error) {
type context struct {
Structs []datasourceStructSpec
}

data := context{
Structs: dataSourceStructContext(spec),
}

return processTemplate(dataSourceStructs, "render-locations-state-to-pango", data, commonFuncMap)
}

func ResourceCreateFunction(names *NameProvider, serviceName string, paramSpec *properties.Normalization, terraformProvider *properties.TerraformProviderFile, resourceSDKName string) (string, error) {
funcMap := template.FuncMap{
"ConfigToEntry": ConfigEntry,
Expand Down
8 changes: 1 addition & 7 deletions pkg/translate/terraform_provider/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,17 +498,11 @@ type {{ structName }} struct {
client *pango.Client
}
type {{ structName }}Model struct {
//TODO: Generate Data Source model via function
}
type {{ structName }}Filter struct {
//TODO: Generate Data Source filter via function
}
type {{ structName }}Entry struct {
// TODO: Entry model struct via function
}
{{ RenderDataSourceStructs }}
// Metadata returns the data source type name.
func (d *{{ structName }}) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
Expand Down
12 changes: 7 additions & 5 deletions pkg/translate/terraform_provider/terraform_provider_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type NameProvider struct {
}

// NewNameProvider creates a new NameProvider based on given specifications.
func NewNameProvider(spec *properties.Normalization, resourceName string) *NameProvider {
func NewNameProvider(spec *properties.Normalization) *NameProvider {
var objectName string

tfName := spec.Name
Expand Down Expand Up @@ -100,7 +100,7 @@ func (g *GenerateTerraformProvider) generateTerraformEntityTemplate(resourceType
// GenerateTerraformResource generates a Terraform resource template.
func (g *GenerateTerraformProvider) GenerateTerraformResource(spec *properties.Normalization, terraformProvider *properties.TerraformProviderFile) error {
resourceType := "Resource"
names := NewNameProvider(spec, resourceType)
names := NewNameProvider(spec)
funcMap := template.FuncMap{
"metaName": func() string { return names.MetaName },
"structName": func() string { return names.StructName },
Expand Down Expand Up @@ -235,13 +235,15 @@ func (g *GenerateTerraformProvider) GenerateTerraformDataSource(spec *properties

if !spec.TerraformProviderConfig.SkipDatasource {
terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/datasource/schema", "dsschema")
terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/types", "")
terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/datasource", "")

resourceType := "DataSource"
names := NewNameProvider(spec, resourceType)
names := NewNameProvider(spec)
funcMap := template.FuncMap{
"metaName": func() string { return names.MetaName },
"structName": func() string { return names.DataSourceStructName },
"metaName": func() string { return names.MetaName },
"structName": func() string { return names.DataSourceStructName },
"RenderDataSourceStructs": func() (string, error) { return RenderDataSourceStructs(names, spec) },
}
err := g.generateTerraformEntityTemplate(resourceType, names, spec, terraformProvider, dataSourceSingletonObj, funcMap)
if err != nil {
Expand Down