From 79b8fcfb38c2a2fc7a6b8db98dae9fecb4d75880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergen=20Yal=C3=A7=C4=B1n?= <44261342+sergenyalcin@users.noreply.github.com> Date: Fri, 9 May 2025 10:58:31 +0300 Subject: [PATCH] Revert "chore: deprecate the reference pointer helper functions" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sergen Yalçın --- pkg/reconciler/managed/reconciler_typed.go | 1 - pkg/reference/reference.go | 123 +++++++++++++++++++++ pkg/reference/reference_test.go | 91 +++++++++++++++ 3 files changed, 214 insertions(+), 1 deletion(-) diff --git a/pkg/reconciler/managed/reconciler_typed.go b/pkg/reconciler/managed/reconciler_typed.go index 3db15a9..1ca2772 100644 --- a/pkg/reconciler/managed/reconciler_typed.go +++ b/pkg/reconciler/managed/reconciler_typed.go @@ -52,7 +52,6 @@ func (c *typedExternalClientWrapper[managed]) Create(ctx context.Context, mg res } return c.c.Create(ctx, cr) } - func (c *typedExternalClientWrapper[managed]) Update(ctx context.Context, mg resource.Managed) (ExternalUpdate, error) { cr, ok := mg.(managed) if !ok { diff --git a/pkg/reference/reference.go b/pkg/reference/reference.go index 3c36d90..3248e21 100644 --- a/pkg/reference/reference.go +++ b/pkg/reference/reference.go @@ -20,6 +20,7 @@ package reference import ( "context" + "strconv" kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" @@ -39,6 +40,128 @@ const ( errNoValue = "referenced field was empty (referenced resource may not yet be ready)" ) +// NOTE(negz): There are many equivalents of FromPtrValue and ToPtrValue +// throughout the Crossplane codebase. We duplicate them here to reduce the +// number of packages our API types have to import to support references. + +// FromPtrValue adapts a string pointer field for use as a CurrentValue. +func FromPtrValue(v *string) string { + if v == nil { + return "" + } + return *v +} + +// FromFloatPtrValue adapts a float pointer field for use as a CurrentValue. +func FromFloatPtrValue(v *float64) string { + if v == nil { + return "" + } + return strconv.FormatFloat(*v, 'f', 0, 64) +} + +// FromIntPtrValue adapts an int pointer field for use as a CurrentValue. +func FromIntPtrValue(v *int64) string { + if v == nil { + return "" + } + return strconv.FormatInt(*v, 10) +} + +// ToPtrValue adapts a ResolvedValue for use as a string pointer field. +func ToPtrValue(v string) *string { + if v == "" { + return nil + } + return &v +} + +// ToFloatPtrValue adapts a ResolvedValue for use as a float64 pointer field. +func ToFloatPtrValue(v string) *float64 { + if v == "" { + return nil + } + vParsed, err := strconv.ParseFloat(v, 64) + if err != nil { + return nil + } + return &vParsed +} + +// ToIntPtrValue adapts a ResolvedValue for use as an int pointer field. +func ToIntPtrValue(v string) *int64 { + if v == "" { + return nil + } + vParsed, err := strconv.ParseInt(v, 10, 64) + if err != nil { + return nil + } + return &vParsed +} + +// FromPtrValues adapts a slice of string pointer fields for use as CurrentValues. +// NOTE: Do not use this utility function unless you have to. +// Using pointer slices does not adhere to our current API practices. +// The current use case is where generated code creates reference-able fields in a provider which are +// string pointers and need to be resolved as part of `ResolveMultiple`. +func FromPtrValues(v []*string) []string { + res := make([]string, len(v)) + for i := range len(v) { + res[i] = FromPtrValue(v[i]) + } + return res +} + +// FromFloatPtrValues adapts a slice of float64 pointer fields for use as CurrentValues. +func FromFloatPtrValues(v []*float64) []string { + res := make([]string, len(v)) + for i := range len(v) { + res[i] = FromFloatPtrValue(v[i]) + } + return res +} + +// FromIntPtrValues adapts a slice of int64 pointer fields for use as CurrentValues. +func FromIntPtrValues(v []*int64) []string { + res := make([]string, len(v)) + for i := range len(v) { + res[i] = FromIntPtrValue(v[i]) + } + return res +} + +// ToPtrValues adapts ResolvedValues for use as a slice of string pointer fields. +// NOTE: Do not use this utility function unless you have to. +// Using pointer slices does not adhere to our current API practices. +// The current use case is where generated code creates reference-able fields in a provider which are +// string pointers and need to be resolved as part of `ResolveMultiple`. +func ToPtrValues(v []string) []*string { + res := make([]*string, len(v)) + for i := range len(v) { + res[i] = ToPtrValue(v[i]) + } + return res +} + +// ToFloatPtrValues adapts ResolvedValues for use as a slice of float64 pointer fields. +func ToFloatPtrValues(v []string) []*float64 { + res := make([]*float64, len(v)) + for i := range len(v) { + res[i] = ToFloatPtrValue(v[i]) + } + return res +} + +// ToIntPtrValues adapts ResolvedValues for use as a slice of int64 pointer fields. +func ToIntPtrValues(v []string) []*int64 { + res := make([]*int64, len(v)) + for i := range len(v) { + res[i] = ToIntPtrValue(v[i]) + } + return res +} + // To indicates the kind of managed resource a reference is to. type To struct { Managed resource.Managed diff --git a/pkg/reference/reference_test.go b/pkg/reference/reference_test.go index 67106c4..6697d25 100644 --- a/pkg/reference/reference_test.go +++ b/pkg/reference/reference_test.go @@ -47,6 +47,97 @@ func (fml *FakeManagedList) GetItems() []resource.Managed { return fml.Items } +func TestToAndFromPtr(t *testing.T) { + cases := map[string]struct { + want string + }{ + "Zero": {want: ""}, + "NonZero": {want: "pointy"}, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := FromPtrValue(ToPtrValue(tc.want)) + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("FromPtrValue(ToPtrValue(%s): -want, +got: %s", tc.want, diff) + } + }) + } +} + +func TestToAndFromFloatPtr(t *testing.T) { + cases := map[string]struct { + want string + }{ + "Zero": {want: ""}, + "NonZero": {want: "1123581321"}, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := FromFloatPtrValue(ToFloatPtrValue(tc.want)) + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("FromPtrValue(ToPtrValue(%s): -want, +got: %s", tc.want, diff) + } + }) + } +} + +func TestToAndFromPtrValues(t *testing.T) { + cases := map[string]struct { + want []string + }{ + "Nil": {want: []string{}}, + "Zero": {want: []string{""}}, + "NonZero": {want: []string{"pointy"}}, + "Multiple": {want: []string{"pointy", "pointers"}}, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := FromPtrValues(ToPtrValues(tc.want)) + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("FromPtrValues(ToPtrValues(%s): -want, +got: %s", tc.want, diff) + } + }) + } +} + +func TestToAndFromFloatPtrValues(t *testing.T) { + cases := map[string]struct { + want []string + }{ + "Nil": {want: []string{}}, + "Zero": {want: []string{""}}, + "NonZero": {want: []string{"1123581321"}}, + "Multiple": {want: []string{"1123581321", "1234567890"}}, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := FromFloatPtrValues(ToFloatPtrValues(tc.want)) + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("FromPtrValues(ToPtrValues(%s): -want, +got: %s", tc.want, diff) + } + }) + } +} + +func TestToAndFromIntPtrValues(t *testing.T) { + cases := map[string]struct { + want []string + }{ + "Nil": {want: []string{}}, + "Zero": {want: []string{""}}, + "NonZero": {want: []string{"1123581321"}}, + "Multiple": {want: []string{"1123581321", "1234567890"}}, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + got := FromIntPtrValues(ToIntPtrValues(tc.want)) + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("FromIntPtrValues(ToIntPtrValues(%s): -want, +got: %s", tc.want, diff) + } + }) + } +} + func TestResolve(t *testing.T) { errBoom := errors.New("boom") now := metav1.Now()