mirror of
https://github.com/LukeHagar/plexterraform.git
synced 2025-12-10 04:21:03 +00:00
ci: regenerated with OpenAPI Doc 0.0.3, Speakeasy CLI 1.129.1
This commit is contained in:
266
internal/provider/reflect/struct.go
Normal file
266
internal/provider/reflect/struct.go
Normal file
@@ -0,0 +1,266 @@
|
||||
// Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT.
|
||||
|
||||
package reflect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/attr/xattr"
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||
"github.com/hashicorp/terraform-plugin-go/tftypes"
|
||||
)
|
||||
|
||||
// Struct builds a new struct using the data in `object`, as long as `object`
|
||||
// is a `tftypes.Object`. It will take the struct type from `target`, which
|
||||
// must be a struct type.
|
||||
//
|
||||
// The properties on `target` must be tagged with a "tfsdk" label containing
|
||||
// the field name to map to that property. Every property must be tagged, and
|
||||
// every property must be present in the type of `object`, and all the
|
||||
// attributes in the type of `object` must have a corresponding property.
|
||||
// Properties that don't map to object attributes must have a `tfsdk:"-"` tag,
|
||||
// explicitly defining them as not part of the object. This is to catch typos
|
||||
// and other mistakes early.
|
||||
//
|
||||
// Struct is meant to be called from Into, not directly.
|
||||
func Struct(ctx context.Context, typ attr.Type, object tftypes.Value, target reflect.Value, opts Options, path path.Path) (reflect.Value, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
|
||||
// this only works with object values, so make sure that constraint is
|
||||
// met
|
||||
if target.Kind() != reflect.Struct {
|
||||
diags.Append(diag.WithPath(path, DiagIntoIncompatibleType{
|
||||
Val: object,
|
||||
TargetType: target.Type(),
|
||||
Err: fmt.Errorf("expected a struct type, got %s", target.Type()),
|
||||
}))
|
||||
return target, diags
|
||||
}
|
||||
if !object.Type().Is(tftypes.Object{}) {
|
||||
diags.Append(diag.WithPath(path, DiagIntoIncompatibleType{
|
||||
Val: object,
|
||||
TargetType: target.Type(),
|
||||
Err: fmt.Errorf("cannot reflect %s into a struct, must be an object", object.Type().String()),
|
||||
}))
|
||||
return target, diags
|
||||
}
|
||||
attrsType, ok := typ.(attr.TypeWithAttributeTypes)
|
||||
if !ok {
|
||||
diags.Append(diag.WithPath(path, DiagIntoIncompatibleType{
|
||||
Val: object,
|
||||
TargetType: target.Type(),
|
||||
Err: fmt.Errorf("cannot reflect object using type information provided by %T, %T must be an attr.TypeWithAttributeTypes", typ, typ),
|
||||
}))
|
||||
return target, diags
|
||||
}
|
||||
|
||||
// collect a map of fields that are in the object passed in
|
||||
var objectFields map[string]tftypes.Value
|
||||
err := object.As(&objectFields)
|
||||
if err != nil {
|
||||
diags.Append(diag.WithPath(path, DiagIntoIncompatibleType{
|
||||
Val: object,
|
||||
TargetType: target.Type(),
|
||||
Err: err,
|
||||
}))
|
||||
return target, diags
|
||||
}
|
||||
|
||||
// collect a map of fields that are defined in the tags of the struct
|
||||
// passed in
|
||||
targetFields, err := getStructTags(ctx, target, path)
|
||||
if err != nil {
|
||||
diags.Append(diag.WithPath(path, DiagIntoIncompatibleType{
|
||||
Val: object,
|
||||
TargetType: target.Type(),
|
||||
Err: fmt.Errorf("error retrieving field names from struct tags: %w", err),
|
||||
}))
|
||||
return target, diags
|
||||
}
|
||||
|
||||
// we require an exact, 1:1 match of these fields to avoid typos
|
||||
// leading to surprises, so let's ensure they have the exact same
|
||||
// fields defined
|
||||
var objectMissing, targetMissing []string
|
||||
for field := range targetFields {
|
||||
if _, ok := objectFields[field]; !ok {
|
||||
objectMissing = append(objectMissing, field)
|
||||
}
|
||||
}
|
||||
for field := range objectFields {
|
||||
if _, ok := targetFields[field]; !ok {
|
||||
targetMissing = append(targetMissing, field)
|
||||
}
|
||||
}
|
||||
if len(objectMissing) > 0 || len(targetMissing) > 0 {
|
||||
var missing []string
|
||||
if len(objectMissing) > 0 {
|
||||
missing = append(missing, fmt.Sprintf("Struct defines fields not found in object: %s.", commaSeparatedString(objectMissing)))
|
||||
}
|
||||
if len(targetMissing) > 0 {
|
||||
missing = append(missing, fmt.Sprintf("Object defines fields not found in struct: %s.", commaSeparatedString(targetMissing)))
|
||||
}
|
||||
diags.Append(diag.WithPath(path, DiagIntoIncompatibleType{
|
||||
Val: object,
|
||||
TargetType: target.Type(),
|
||||
Err: fmt.Errorf("mismatch between struct and object: %s", strings.Join(missing, " ")),
|
||||
}))
|
||||
return target, diags
|
||||
}
|
||||
|
||||
attrTypes := attrsType.AttributeTypes()
|
||||
|
||||
// now that we know they match perfectly, fill the struct with the
|
||||
// values in the object
|
||||
// Fork start
|
||||
//result := reflect.New(target.Type()).Elem()
|
||||
var result reflect.Value
|
||||
if target.CanSet() {
|
||||
result = target
|
||||
} else {
|
||||
result = reflect.New(target.Type()).Elem()
|
||||
}
|
||||
// Fork End
|
||||
for field, structFieldPos := range targetFields {
|
||||
attrType, ok := attrTypes[field]
|
||||
if !ok {
|
||||
diags.Append(diag.WithPath(path, DiagIntoIncompatibleType{
|
||||
Val: object,
|
||||
TargetType: target.Type(),
|
||||
Err: fmt.Errorf("could not find type information for attribute in supplied attr.Type %T", typ),
|
||||
}))
|
||||
return target, diags
|
||||
}
|
||||
structField := result.Field(structFieldPos)
|
||||
fieldVal, fieldValDiags := BuildValue(ctx, attrType, objectFields[field], structField, opts, path.AtName(field))
|
||||
diags.Append(fieldValDiags...)
|
||||
|
||||
if diags.HasError() {
|
||||
return target, diags
|
||||
}
|
||||
structField.Set(fieldVal)
|
||||
}
|
||||
return result, diags
|
||||
}
|
||||
|
||||
// FromStruct builds an attr.Value as produced by `typ` from the data in `val`.
|
||||
// `val` must be a struct type, and must have all its properties tagged and be
|
||||
// a 1:1 match with the attributes reported by `typ`. FromStruct will recurse
|
||||
// into FromValue for each attribute, using the type of the attribute as
|
||||
// reported by `typ`.
|
||||
//
|
||||
// It is meant to be called through FromValue, not directly.
|
||||
func FromStruct(ctx context.Context, typ attr.TypeWithAttributeTypes, val reflect.Value, path path.Path) (attr.Value, diag.Diagnostics) {
|
||||
var diags diag.Diagnostics
|
||||
objTypes := map[string]tftypes.Type{}
|
||||
objValues := map[string]tftypes.Value{}
|
||||
|
||||
// collect a map of fields that are defined in the tags of the struct
|
||||
// passed in
|
||||
targetFields, err := getStructTags(ctx, val, path)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error retrieving field names from struct tags: %w", err)
|
||||
diags.AddAttributeError(
|
||||
path,
|
||||
"Value Conversion Error",
|
||||
"An unexpected error was encountered trying to convert from struct value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+err.Error(),
|
||||
)
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
attrTypes := typ.AttributeTypes()
|
||||
|
||||
var objectMissing, structMissing []string
|
||||
|
||||
for field := range targetFields {
|
||||
if _, ok := attrTypes[field]; !ok {
|
||||
objectMissing = append(objectMissing, field)
|
||||
}
|
||||
}
|
||||
|
||||
for attrName, attrType := range attrTypes {
|
||||
if attrType == nil {
|
||||
objectMissing = append(objectMissing, attrName)
|
||||
}
|
||||
|
||||
if _, ok := targetFields[attrName]; !ok {
|
||||
structMissing = append(structMissing, attrName)
|
||||
}
|
||||
}
|
||||
|
||||
if len(objectMissing) > 0 || len(structMissing) > 0 {
|
||||
missing := make([]string, 0, len(objectMissing)+len(structMissing))
|
||||
|
||||
if len(objectMissing) > 0 {
|
||||
missing = append(missing, fmt.Sprintf("Struct defines fields not found in object: %s.", commaSeparatedString(objectMissing)))
|
||||
}
|
||||
|
||||
if len(structMissing) > 0 {
|
||||
missing = append(missing, fmt.Sprintf("Object defines fields not found in struct: %s.", commaSeparatedString(structMissing)))
|
||||
}
|
||||
|
||||
diags.AddAttributeError(
|
||||
path,
|
||||
"Value Conversion Error",
|
||||
"An unexpected error was encountered trying to convert from struct into an object. "+
|
||||
"This is always an error in the provider. Please report the following to the provider developer:\n\n"+
|
||||
fmt.Sprintf("Mismatch between struct and object type: %s\n", strings.Join(missing, " "))+
|
||||
fmt.Sprintf("Struct: %s\n", val.Type())+
|
||||
fmt.Sprintf("Object type: %s", typ),
|
||||
)
|
||||
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
for name, fieldNo := range targetFields {
|
||||
path := path.AtName(name)
|
||||
fieldValue := val.Field(fieldNo)
|
||||
|
||||
attrVal, attrValDiags := FromValue(ctx, attrTypes[name], fieldValue.Interface(), path)
|
||||
diags.Append(attrValDiags...)
|
||||
|
||||
if diags.HasError() {
|
||||
return nil, diags
|
||||
}
|
||||
|
||||
tfObjVal, err := attrVal.ToTerraformValue(ctx)
|
||||
if err != nil {
|
||||
return nil, append(diags, toTerraformValueErrorDiag(err, path))
|
||||
}
|
||||
|
||||
if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok {
|
||||
diags.Append(typeWithValidate.Validate(ctx, tfObjVal, path)...)
|
||||
|
||||
if diags.HasError() {
|
||||
return nil, diags
|
||||
}
|
||||
}
|
||||
|
||||
objValues[name] = tfObjVal
|
||||
objTypes[name] = tfObjVal.Type()
|
||||
}
|
||||
|
||||
tfVal := tftypes.NewValue(tftypes.Object{
|
||||
AttributeTypes: objTypes,
|
||||
}, objValues)
|
||||
|
||||
if typeWithValidate, ok := typ.(xattr.TypeWithValidate); ok {
|
||||
diags.Append(typeWithValidate.Validate(ctx, tfVal, path)...)
|
||||
|
||||
if diags.HasError() {
|
||||
return nil, diags
|
||||
}
|
||||
}
|
||||
|
||||
ret, err := typ.ValueFromTerraform(ctx, tfVal)
|
||||
if err != nil {
|
||||
return nil, append(diags, valueFromTerraformErrorDiag(err, path))
|
||||
}
|
||||
|
||||
return ret, diags
|
||||
}
|
||||
Reference in New Issue
Block a user