Skip to content

Commit deaee72

Browse files
fix: spurious update plans for float attributes after import
1 parent 25a4f1b commit deaee72

File tree

4 files changed

+181
-75
lines changed

4 files changed

+181
-75
lines changed

internal/apiform/form_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
1818

1919
"github.com/hanzoai/terraform-provider-hanzo/internal/customfield"
20+
type_helpers "github.com/hanzoai/terraform-provider-hanzo/internal/types"
2021
)
2122

2223
func P[T any](v T) *T { return &v }
@@ -325,7 +326,7 @@ Content-Type: application/json
325326
TerraformTypes{
326327
A: types.BoolValue(true),
327328
B: types.Int64Value(237628372683),
328-
C: types.Float64Value(654),
329+
C: type_helpers.NewFloat64ValueFromStringUnsafe("654"),
329330
D: types.StringValue("a string value"),
330331
E: timetypes.NewRFC3339TimeValue(time.Date(2006, time.January, 2, 15, 4, 5, 0, time.UTC)),
331332
F: customfield.NewObjectMust(context.TODO(), &NestedTerraformType{
@@ -334,7 +335,7 @@ Content-Type: application/json
334335
G: types.ObjectValueMust(map[string]attr.Type{"hello": basetypes.StringType{}}, map[string]attr.Value{"hello": basetypes.NewStringValue("world")}),
335336
H: types.ListValueMust(basetypes.StringType{}, []attr.Value{basetypes.NewStringValue("a"), basetypes.NewStringValue("b")}),
336337
I: types.MapValueMust(basetypes.Int64Type{}, map[string]attr.Value{"a": basetypes.NewInt64Value(3), "b": basetypes.NewInt64Value(8932)}),
337-
J: types.SetValueMust(basetypes.Float64Type{}, []attr.Value{basetypes.NewFloat64Value(23.345), basetypes.NewFloat64Value(15)}),
338+
J: types.SetValueMust(basetypes.Float64Type{}, []attr.Value{type_helpers.NewFloat64ValueFromStringUnsafe("23.345"), type_helpers.NewFloat64ValueFromStringUnsafe("15")}),
338339
K: types.DynamicValue(types.ObjectValueMust(map[string]attr.Type{"dynamic_hello": basetypes.StringType{}}, map[string]attr.Value{"dynamic_hello": basetypes.NewStringValue("dynamic_world")})),
339340
L: customfield.NewListMust[types.String](context.TODO(), []attr.Value{basetypes.NewStringValue("a"), basetypes.NewStringValue("b")}),
340341
M: customfield.NewMapMust[types.String](context.TODO(), map[string]types.String{"a": basetypes.NewStringValue("3"), "b": basetypes.NewStringValue("8932")}),

internal/apijson/decoder.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package apijson
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"math/big"
89
"reflect"
@@ -19,6 +20,7 @@ import (
1920
"github.com/tidwall/gjson"
2021

2122
"github.com/hanzoai/terraform-provider-hanzo/internal/customfield"
23+
type_helpers "github.com/hanzoai/terraform-provider-hanzo/internal/types"
2224
)
2325

2426
// decoders is a synchronized map with roughly the following type:
@@ -478,23 +480,44 @@ func (d *decoderBuilder) newTerraformTypeDecoder(t reflect.Type) decoderFunc {
478480

479481
if (t == reflect.TypeOf(basetypes.Float64Value{})) {
480482
return d.decodeTerraformPrimitive(func() any { return types.Float64Null() }, func(node gjson.Result, value reflect.Value, state *decoderState) error {
481-
// use ParseFloat just to validate that it's a valid number
482-
_, err := strconv.ParseFloat(node.Str, 64)
483-
if node.Type == gjson.JSON || (node.Type == gjson.String && err != nil) {
484-
return fmt.Errorf("apijson: failed to parse types.Float64Value")
483+
var rawVal string
484+
switch node.Type {
485+
case gjson.String:
486+
rawVal = node.Str
487+
case gjson.Number:
488+
rawVal = node.Raw
489+
default:
490+
return errors.New("apijson: failed to parse as basetypes.Float64Value")
485491
}
486-
value.Set(reflect.ValueOf(types.Float64Value(node.Float())))
492+
493+
f64Val, err := type_helpers.NewFloat64ValueFromString(rawVal)
494+
if err != nil {
495+
return fmt.Errorf("apijson: %w", err)
496+
}
497+
498+
value.Set(reflect.ValueOf(f64Val))
487499
return nil
488500
})
489501
}
490502

491503
if (t == reflect.TypeOf(basetypes.NumberValue{})) {
492504
return d.decodeTerraformPrimitive(func() any { return types.NumberNull() }, func(node gjson.Result, value reflect.Value, state *decoderState) error {
493-
value.Set(reflect.ValueOf(types.NumberValue(big.NewFloat(node.Float()))))
494-
_, err := strconv.ParseFloat(node.Str, 64)
495-
if node.Type == gjson.JSON || (node.Type == gjson.String && err != nil) {
496-
return fmt.Errorf("apijson: failed to parse types.Float64Value")
505+
var rawVal string
506+
switch node.Type {
507+
case gjson.String:
508+
rawVal = node.Str
509+
case gjson.Number:
510+
rawVal = node.Raw
511+
default:
512+
return errors.New("apijson: failed to parse as basetypes.NumberValue")
497513
}
514+
515+
numberVal, err := type_helpers.NewNumberValueFromString(rawVal)
516+
if err != nil {
517+
return fmt.Errorf("apijson: %w", err)
518+
}
519+
520+
value.Set(reflect.ValueOf(numberVal))
498521
return nil
499522
})
500523
}
@@ -1350,7 +1373,7 @@ func (d *decoderBuilder) inferTerraformAttrFromValue(node gjson.Result) (attr.Va
13501373
if err == nil {
13511374
return types.Int64Value(node.Int()), nil
13521375
}
1353-
return types.Float64Value(node.Float()), nil
1376+
return type_helpers.NewFloat64ValueFromString(node.String())
13541377
case gjson.String:
13551378
return types.StringValue(node.String()), nil
13561379
case gjson.JSON:

0 commit comments

Comments
 (0)