From 1d97017b303caa29379e7202a04814985604bea2 Mon Sep 17 00:00:00 2001 From: "Jonas L." Date: Tue, 5 Nov 2024 12:10:24 +0100 Subject: [PATCH] feat: use custom IDOrName type for schemas (#545) Add typing information to the fields that support passing either an ID as int, an ID as string or a Name as string. An empty value will be marshalled to `null` to reflect the behavior of an empty interface. After this change, we do not have to cast IDs to float64 or to string to be able to read the values. Since this is part of the schema package, this is not a breaking change for our customers, but might break our tests that rely on casting the interface to the desired type. --- hcloud/load_balancer.go | 6 +- hcloud/load_balancer_test.go | 6 +- hcloud/schema/id_or_name.go | 68 ++++++++++++++++++++ hcloud/schema/id_or_name_test.go | 105 +++++++++++++++++++++++++++++++ hcloud/schema/load_balancer.go | 4 +- hcloud/schema/server.go | 12 ++-- hcloud/schema/volume.go | 2 +- hcloud/schema_gen.go | 11 ---- hcloud/schema_test.go | 4 +- hcloud/server.go | 30 +++------ hcloud/server_test.go | 16 ++--- hcloud/volume.go | 6 +- hcloud/volume_test.go | 2 +- hcloud/zz_schema.go | 12 +++- 14 files changed, 221 insertions(+), 63 deletions(-) create mode 100644 hcloud/schema/id_or_name.go create mode 100644 hcloud/schema/id_or_name_test.go mode change 100755 => 100644 hcloud/zz_schema.go diff --git a/hcloud/load_balancer.go b/hcloud/load_balancer.go index fb40057b..c634d160 100644 --- a/hcloud/load_balancer.go +++ b/hcloud/load_balancer.go @@ -935,10 +935,8 @@ type LoadBalancerChangeTypeOpts struct { // ChangeType changes a Load Balancer's type. func (c *LoadBalancerClient) ChangeType(ctx context.Context, loadBalancer *LoadBalancer, opts LoadBalancerChangeTypeOpts) (*Action, *Response, error) { reqBody := schema.LoadBalancerActionChangeTypeRequest{} - if opts.LoadBalancerType.ID != 0 { - reqBody.LoadBalancerType = opts.LoadBalancerType.ID - } else { - reqBody.LoadBalancerType = opts.LoadBalancerType.Name + if opts.LoadBalancerType.ID != 0 || opts.LoadBalancerType.Name != "" { + reqBody.LoadBalancerType = schema.IDOrName{ID: opts.LoadBalancerType.ID, Name: opts.LoadBalancerType.Name} } reqBodyData, err := json.Marshal(reqBody) if err != nil { diff --git a/hcloud/load_balancer_test.go b/hcloud/load_balancer_test.go index f9190b26..2f18efe3 100644 --- a/hcloud/load_balancer_test.go +++ b/hcloud/load_balancer_test.go @@ -175,7 +175,7 @@ func TestLoadBalancerCreate(t *testing.T) { } expectedReqBody := schema.LoadBalancerCreateRequest{ Name: "load-balancer", - LoadBalancerType: "lb1", + LoadBalancerType: schema.IDOrName{Name: "lb1"}, Algorithm: &schema.LoadBalancerCreateRequestAlgorithm{ Type: "round_robin", }, @@ -813,7 +813,7 @@ func TestLoadBalancerClientChangeType(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if id, ok := reqBody.LoadBalancerType.(float64); !ok || id != 1 { + if reqBody.LoadBalancerType.ID != 1 { t.Errorf("unexpected Load Balancer type ID: %v", reqBody.LoadBalancerType) } json.NewEncoder(w).Encode(schema.LoadBalancerActionChangeTypeResponse{ @@ -844,7 +844,7 @@ func TestLoadBalancerClientChangeType(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if name, ok := reqBody.LoadBalancerType.(string); !ok || name != "type" { + if reqBody.LoadBalancerType.Name != "type" { t.Errorf("unexpected Load Balancer type name: %v", reqBody.LoadBalancerType) } json.NewEncoder(w).Encode(schema.LoadBalancerActionChangeTypeResponse{ diff --git a/hcloud/schema/id_or_name.go b/hcloud/schema/id_or_name.go new file mode 100644 index 00000000..75e1169b --- /dev/null +++ b/hcloud/schema/id_or_name.go @@ -0,0 +1,68 @@ +package schema + +import ( + "bytes" + "encoding/json" + "reflect" + "strconv" +) + +// IDOrName can be used in API requests where either a resource id or name can be +// specified. +type IDOrName struct { + ID int64 + Name string +} + +var _ json.Unmarshaler = (*IDOrName)(nil) +var _ json.Marshaler = (*IDOrName)(nil) + +func (o IDOrName) MarshalJSON() ([]byte, error) { + if o.ID != 0 { + return json.Marshal(o.ID) + } + if o.Name != "" { + return json.Marshal(o.Name) + } + + // We want to preserve the behavior of an empty interface{} to prevent breaking + // changes (marshaled to null when empty). + return json.Marshal(nil) +} + +func (o *IDOrName) UnmarshalJSON(data []byte) error { + d := json.NewDecoder(bytes.NewBuffer(data)) + // This ensures we won't lose precision on large IDs, see json.Number below + d.UseNumber() + + var v any + if err := d.Decode(&v); err != nil { + return err + } + + switch typed := v.(type) { + case string: + id, err := strconv.ParseInt(typed, 10, 64) + if err == nil { + o.ID = id + } else if typed != "" { + o.Name = typed + } + case json.Number: + id, err := typed.Int64() + if err != nil { + return &json.UnmarshalTypeError{ + Value: string(data), + Type: reflect.TypeOf(*o), + } + } + o.ID = id + default: + return &json.UnmarshalTypeError{ + Value: string(data), + Type: reflect.TypeOf(*o), + } + } + + return nil +} diff --git a/hcloud/schema/id_or_name_test.go b/hcloud/schema/id_or_name_test.go new file mode 100644 index 00000000..54e20a54 --- /dev/null +++ b/hcloud/schema/id_or_name_test.go @@ -0,0 +1,105 @@ +package schema + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestIDOrNameMarshall(t *testing.T) { + t.Run("id", func(t *testing.T) { + i := IDOrName{ID: 1} + + got, err := i.MarshalJSON() + require.NoError(t, err) + require.Equal(t, `1`, string(got)) + }) + + t.Run("name", func(t *testing.T) { + i := IDOrName{Name: "name"} + + got, err := i.MarshalJSON() + require.NoError(t, err) + require.Equal(t, `"name"`, string(got)) + }) + + t.Run("id and name", func(t *testing.T) { + i := IDOrName{ID: 1, Name: "name"} + + got, err := i.MarshalJSON() + require.NoError(t, err) + require.Equal(t, `1`, string(got)) + }) + + t.Run("null", func(t *testing.T) { + i := IDOrName{} + + got, err := i.MarshalJSON() + require.NoError(t, err) + require.Equal(t, `null`, string(got)) + }) +} + +func TestIDOrNameUnMarshall(t *testing.T) { + t.Run("id", func(t *testing.T) { + i := IDOrName{} + + err := i.UnmarshalJSON([]byte(`1`)) + require.NoError(t, err) + require.Equal(t, IDOrName{ID: 1}, i) + }) + t.Run("name", func(t *testing.T) { + i := IDOrName{} + + err := i.UnmarshalJSON([]byte(`"name"`)) + require.NoError(t, err) + require.Equal(t, IDOrName{Name: "name"}, i) + }) + t.Run("id string", func(t *testing.T) { + i := IDOrName{} + + err := i.UnmarshalJSON([]byte(`"1"`)) + require.NoError(t, err) + require.Equal(t, IDOrName{ID: 1}, i) + }) + t.Run("id float", func(t *testing.T) { + i := IDOrName{} + + err := i.UnmarshalJSON([]byte(`1.0`)) + require.EqualError(t, err, "json: cannot unmarshal 1.0 into Go value of type schema.IDOrName") + }) + t.Run("null", func(t *testing.T) { + i := IDOrName{} + + err := i.UnmarshalJSON([]byte(`null`)) + require.EqualError(t, err, "json: cannot unmarshal null into Go value of type schema.IDOrName") + }) +} + +func TestIDOrName(t *testing.T) { + // Make sure the behavior does not change from the use of an interface{}. + type FakeRequest struct { + Old interface{} `json:"old"` + New IDOrName `json:"new"` + } + + t.Run("null", func(t *testing.T) { + o := FakeRequest{} + body, err := json.Marshal(o) + require.NoError(t, err) + require.Equal(t, `{"old":null,"new":null}`, string(body)) + }) + t.Run("id", func(t *testing.T) { + o := FakeRequest{Old: int64(1), New: IDOrName{ID: 1}} + body, err := json.Marshal(o) + require.NoError(t, err) + require.Equal(t, `{"old":1,"new":1}`, string(body)) + }) + t.Run("name", func(t *testing.T) { + o := FakeRequest{Old: "name", New: IDOrName{Name: "name"}} + body, err := json.Marshal(o) + require.NoError(t, err) + require.Equal(t, `{"old":"name","new":"name"}`, string(body)) + }) +} diff --git a/hcloud/schema/load_balancer.go b/hcloud/schema/load_balancer.go index 7e1c4f5d..d8760ad2 100644 --- a/hcloud/schema/load_balancer.go +++ b/hcloud/schema/load_balancer.go @@ -251,7 +251,7 @@ type LoadBalancerDeleteServiceResponse struct { type LoadBalancerCreateRequest struct { Name string `json:"name"` - LoadBalancerType interface{} `json:"load_balancer_type"` // int or string + LoadBalancerType IDOrName `json:"load_balancer_type"` Algorithm *LoadBalancerCreateRequestAlgorithm `json:"algorithm,omitempty"` Location *string `json:"location,omitempty"` NetworkZone *string `json:"network_zone,omitempty"` @@ -380,7 +380,7 @@ type LoadBalancerActionDisablePublicInterfaceResponse struct { } type LoadBalancerActionChangeTypeRequest struct { - LoadBalancerType interface{} `json:"load_balancer_type"` // int or string + LoadBalancerType IDOrName `json:"load_balancer_type"` } type LoadBalancerActionChangeTypeResponse struct { diff --git a/hcloud/schema/server.go b/hcloud/schema/server.go index b9c945a8..72aaf269 100644 --- a/hcloud/schema/server.go +++ b/hcloud/schema/server.go @@ -99,8 +99,8 @@ type ServerListResponse struct { // create a server. type ServerCreateRequest struct { Name string `json:"name"` - ServerType interface{} `json:"server_type"` // int or string - Image interface{} `json:"image"` // int or string + ServerType IDOrName `json:"server_type"` + Image IDOrName `json:"image"` SSHKeys []int64 `json:"ssh_keys,omitempty"` Location string `json:"location,omitempty"` Datacenter string `json:"datacenter,omitempty"` @@ -257,7 +257,7 @@ type ServerActionDisableRescueResponse struct { // ServerActionRebuildRequest defines the schema for the request to // rebuild a server. type ServerActionRebuildRequest struct { - Image interface{} `json:"image"` // int or string + Image IDOrName `json:"image"` } // ServerActionRebuildResponse defines the schema of the response when @@ -270,7 +270,7 @@ type ServerActionRebuildResponse struct { // ServerActionAttachISORequest defines the schema for the request to // attach an ISO to a server. type ServerActionAttachISORequest struct { - ISO interface{} `json:"iso"` // int or string + ISO IDOrName `json:"iso"` } // ServerActionAttachISOResponse defines the schema of the response when @@ -308,8 +308,8 @@ type ServerActionDisableBackupResponse struct { // ServerActionChangeTypeRequest defines the schema for the request to // change a server's type. type ServerActionChangeTypeRequest struct { - ServerType interface{} `json:"server_type"` // int or string - UpgradeDisk bool `json:"upgrade_disk"` + ServerType IDOrName `json:"server_type"` + UpgradeDisk bool `json:"upgrade_disk"` } // ServerActionChangeTypeResponse defines the schema of the response when diff --git a/hcloud/schema/volume.go b/hcloud/schema/volume.go index 1de64595..89223ba4 100644 --- a/hcloud/schema/volume.go +++ b/hcloud/schema/volume.go @@ -23,7 +23,7 @@ type VolumeCreateRequest struct { Name string `json:"name"` Size int `json:"size"` Server *int64 `json:"server,omitempty"` - Location interface{} `json:"location,omitempty"` // int, string, or nil + Location *IDOrName `json:"location,omitempty"` Labels *map[string]string `json:"labels,omitempty"` Automount *bool `json:"automount,omitempty"` Format *string `json:"format,omitempty"` diff --git a/hcloud/schema_gen.go b/hcloud/schema_gen.go index c2c37351..4566acfe 100644 --- a/hcloud/schema_gen.go +++ b/hcloud/schema_gen.go @@ -69,7 +69,6 @@ You can find a documentation of goverter here: https://goverter.jmattheis.de/ // goverter:extend durationFromIntSeconds // goverter:extend intSecondsFromDuration // goverter:extend serverFromImageCreatedFromSchema -// goverter:extend anyFromLoadBalancerType // goverter:extend serverMetricsTimeSeriesFromSchema // goverter:extend loadBalancerMetricsTimeSeriesFromSchema // goverter:extend stringPtrFromLoadBalancerServiceProtocol @@ -808,16 +807,6 @@ func volumePricingFromSchema(s schema.Pricing) VolumePricing { } } -func anyFromLoadBalancerType(t *LoadBalancerType) interface{} { - if t == nil { - return nil - } - if t.ID != 0 { - return t.ID - } - return t.Name -} - func serverMetricsTimeSeriesFromSchema(s schema.ServerTimeSeriesVals) ([]ServerMetricsValue, error) { vals := make([]ServerMetricsValue, len(s.Values)) diff --git a/hcloud/schema_test.go b/hcloud/schema_test.go index 3ee2779e..3bec207f 100644 --- a/hcloud/schema_test.go +++ b/hcloud/schema_test.go @@ -1508,7 +1508,7 @@ func TestLoadBalancerCreateOptsToSchema(t *testing.T) { }, Request: schema.LoadBalancerCreateRequest{ Name: "test", - LoadBalancerType: "lb11", + LoadBalancerType: schema.IDOrName{Name: "lb11"}, Algorithm: &schema.LoadBalancerCreateRequestAlgorithm{ Type: string(LoadBalancerAlgorithmTypeRoundRobin), }, @@ -1593,7 +1593,7 @@ func TestLoadBalancerCreateOptsToSchema(t *testing.T) { }, Request: schema.LoadBalancerCreateRequest{ Name: "test", - LoadBalancerType: "lb11", + LoadBalancerType: schema.IDOrName{Name: "lb11"}, Algorithm: &schema.LoadBalancerCreateRequestAlgorithm{ Type: string(LoadBalancerAlgorithmTypeRoundRobin), }, diff --git a/hcloud/server.go b/hcloud/server.go index 11857e17..d1514f5c 100644 --- a/hcloud/server.go +++ b/hcloud/server.go @@ -378,15 +378,11 @@ func (c *ServerClient) Create(ctx context.Context, opts ServerCreateOpts) (Serve reqBody.Name = opts.Name reqBody.Automount = opts.Automount reqBody.StartAfterCreate = opts.StartAfterCreate - if opts.ServerType.ID != 0 { - reqBody.ServerType = opts.ServerType.ID - } else if opts.ServerType.Name != "" { - reqBody.ServerType = opts.ServerType.Name + if opts.ServerType.ID != 0 || opts.ServerType.Name != "" { + reqBody.ServerType = schema.IDOrName{ID: opts.ServerType.ID, Name: opts.ServerType.Name} } - if opts.Image.ID != 0 { - reqBody.Image = opts.Image.ID - } else if opts.Image.Name != "" { - reqBody.Image = opts.Image.Name + if opts.Image.ID != 0 || opts.Image.Name != "" { + reqBody.Image = schema.IDOrName{ID: opts.Image.ID, Name: opts.Image.Name} } if opts.Labels != nil { reqBody.Labels = &opts.Labels @@ -778,10 +774,8 @@ func (c *ServerClient) Rebuild(ctx context.Context, server *Server, opts ServerR // RebuildWithResult rebuilds a server. func (c *ServerClient) RebuildWithResult(ctx context.Context, server *Server, opts ServerRebuildOpts) (ServerRebuildResult, *Response, error) { reqBody := schema.ServerActionRebuildRequest{} - if opts.Image.ID != 0 { - reqBody.Image = opts.Image.ID - } else { - reqBody.Image = opts.Image.Name + if opts.Image.ID != 0 || opts.Image.Name != "" { + reqBody.Image = schema.IDOrName{ID: opts.Image.ID, Name: opts.Image.Name} } reqBodyData, err := json.Marshal(reqBody) if err != nil { @@ -813,10 +807,8 @@ func (c *ServerClient) RebuildWithResult(ctx context.Context, server *Server, op // AttachISO attaches an ISO to a server. func (c *ServerClient) AttachISO(ctx context.Context, server *Server, iso *ISO) (*Action, *Response, error) { reqBody := schema.ServerActionAttachISORequest{} - if iso.ID != 0 { - reqBody.ISO = iso.ID - } else { - reqBody.ISO = iso.Name + if iso.ID != 0 || iso.Name != "" { + reqBody.ISO = schema.IDOrName{ID: iso.ID, Name: iso.Name} } reqBodyData, err := json.Marshal(reqBody) if err != nil { @@ -899,10 +891,8 @@ func (c *ServerClient) ChangeType(ctx context.Context, server *Server, opts Serv reqBody := schema.ServerActionChangeTypeRequest{ UpgradeDisk: opts.UpgradeDisk, } - if opts.ServerType.ID != 0 { - reqBody.ServerType = opts.ServerType.ID - } else { - reqBody.ServerType = opts.ServerType.Name + if opts.ServerType.ID != 0 || opts.ServerType.Name != "" { + reqBody.ServerType = schema.IDOrName{ID: opts.ServerType.ID, Name: opts.ServerType.Name} } reqBodyData, err := json.Marshal(reqBody) if err != nil { diff --git a/hcloud/server_test.go b/hcloud/server_test.go index 0a015135..f1e4535a 100644 --- a/hcloud/server_test.go +++ b/hcloud/server_test.go @@ -1468,7 +1468,7 @@ func TestServerClientRebuild(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if id, ok := reqBody.Image.(float64); !ok || id != 1 { + if reqBody.Image.ID != 1 { t.Errorf("unexpected image ID: %v", reqBody.Image) } json.NewEncoder(w).Encode(schema.ServerActionRebuildResponse{ @@ -1499,7 +1499,7 @@ func TestServerClientRebuild(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if name, ok := reqBody.Image.(string); !ok || name != "debian-9" { + if reqBody.Image.Name != "debian-9" { t.Errorf("unexpected image name: %v", reqBody.Image) } json.NewEncoder(w).Encode(schema.ServerActionRebuildResponse{ @@ -1537,7 +1537,7 @@ func TestServerClientRebuildWithResult(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if id, ok := reqBody.Image.(float64); !ok || id != 1 { + if reqBody.Image.ID != 1 { t.Errorf("unexpected image ID: %v", reqBody.Image) } json.NewEncoder(w).Encode(schema.ServerActionRebuildResponse{ @@ -1572,7 +1572,7 @@ func TestServerClientRebuildWithResult(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if name, ok := reqBody.Image.(string); !ok || name != "debian-9" { + if reqBody.Image.Name != "debian-9" { t.Errorf("unexpected image name: %v", reqBody.Image) } json.NewEncoder(w).Encode(schema.ServerActionRebuildResponse{ @@ -1614,7 +1614,7 @@ func TestServerClientAttachISO(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if id, ok := reqBody.ISO.(float64); !ok || id != 1 { + if reqBody.ISO.ID != 1 { t.Errorf("unexpected ISO ID: %v", reqBody.ISO) } json.NewEncoder(w).Encode(schema.ServerActionAttachISOResponse{ @@ -1643,7 +1643,7 @@ func TestServerClientAttachISO(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if name, ok := reqBody.ISO.(string); !ok || name != "debian.iso" { + if reqBody.ISO.Name != "debian.iso" { t.Errorf("unexpected ISO name: %v", reqBody.ISO) } json.NewEncoder(w).Encode(schema.ServerActionAttachISOResponse{ @@ -1757,7 +1757,7 @@ func TestServerClientChangeType(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if id, ok := reqBody.ServerType.(float64); !ok || id != 1 { + if reqBody.ServerType.ID != 1 { t.Errorf("unexpected server type ID: %v", reqBody.ServerType) } if !reqBody.UpgradeDisk { @@ -1792,7 +1792,7 @@ func TestServerClientChangeType(t *testing.T) { if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { t.Fatal(err) } - if name, ok := reqBody.ServerType.(string); !ok || name != "type" { + if reqBody.ServerType.Name != "type" { t.Errorf("unexpected server type name: %v", reqBody.ServerType) } if !reqBody.UpgradeDisk { diff --git a/hcloud/volume.go b/hcloud/volume.go index c744b5a8..6fe9d5ab 100644 --- a/hcloud/volume.go +++ b/hcloud/volume.go @@ -220,10 +220,8 @@ func (c *VolumeClient) Create(ctx context.Context, opts VolumeCreateOpts) (Volum reqBody.Server = Ptr(opts.Server.ID) } if opts.Location != nil { - if opts.Location.ID != 0 { - reqBody.Location = opts.Location.ID - } else { - reqBody.Location = opts.Location.Name + if opts.Location.ID != 0 || opts.Location.Name != "" { + reqBody.Location = &schema.IDOrName{ID: opts.Location.ID, Name: opts.Location.Name} } } diff --git a/hcloud/volume_test.go b/hcloud/volume_test.go index 8e2255a3..de05b945 100644 --- a/hcloud/volume_test.go +++ b/hcloud/volume_test.go @@ -319,7 +319,7 @@ func TestVolumeClientCreateWithLocation(t *testing.T) { if reqBody.Size != 42 { t.Errorf("unexpected volume size in request: %v", reqBody.Size) } - if reqBody.Location != float64(1) { + if reqBody.Location.ID != 1 { t.Errorf("unexpected volume location in request: %v", reqBody.Location) } if reqBody.Server != nil { diff --git a/hcloud/zz_schema.go b/hcloud/zz_schema.go old mode 100755 new mode 100644 index c739e1d8..4f4b866f --- a/hcloud/zz_schema.go +++ b/hcloud/zz_schema.go @@ -690,7 +690,7 @@ func (c *converterImpl) SchemaFromLoadBalancerAddServiceOpts(source LoadBalancer func (c *converterImpl) SchemaFromLoadBalancerCreateOpts(source LoadBalancerCreateOpts) schema.LoadBalancerCreateRequest { var schemaLoadBalancerCreateRequest schema.LoadBalancerCreateRequest schemaLoadBalancerCreateRequest.Name = source.Name - schemaLoadBalancerCreateRequest.LoadBalancerType = anyFromLoadBalancerType(source.LoadBalancerType) + schemaLoadBalancerCreateRequest.LoadBalancerType = c.pHcloudLoadBalancerTypeToSchemaIDOrName(source.LoadBalancerType) schemaLoadBalancerCreateRequest.Algorithm = c.pHcloudLoadBalancerAlgorithmToPSchemaLoadBalancerCreateRequestAlgorithm(source.Algorithm) schemaLoadBalancerCreateRequest.Location = c.pHcloudLocationToPString(source.Location) schemaLoadBalancerCreateRequest.NetworkZone = stringPtrFromNetworkZone(source.NetworkZone) @@ -1732,6 +1732,16 @@ func (c *converterImpl) pHcloudLoadBalancerToInt64(source *LoadBalancer) int64 { } return xint64 } +func (c *converterImpl) pHcloudLoadBalancerTypeToSchemaIDOrName(source *LoadBalancerType) schema.IDOrName { + var schemaIDOrName schema.IDOrName + if source != nil { + var schemaIDOrName2 schema.IDOrName + schemaIDOrName2.ID = (*source).ID + schemaIDOrName2.Name = (*source).Name + schemaIDOrName = schemaIDOrName2 + } + return schemaIDOrName +} func (c *converterImpl) pHcloudLoadBalancerUpdateServiceOptsHTTPToPSchemaLoadBalancerActionUpdateServiceRequestHTTP(source *LoadBalancerUpdateServiceOptsHTTP) *schema.LoadBalancerActionUpdateServiceRequestHTTP { var pSchemaLoadBalancerActionUpdateServiceRequestHTTP *schema.LoadBalancerActionUpdateServiceRequestHTTP if source != nil {