[core]: allow empty struct member updates#3190
[core]: allow empty struct member updates#3190pierreprinetti merged 2 commits intogophercloud:masterfrom
Conversation
7c84d45 to
e34cfc6
Compare
|
I've approved it but I need an extra pair of eyes on this one, ping @pierreprinetti |
pierreprinetti
left a comment
There was a problem hiding this comment.
I understand the value of changing all types to pointer types in UpdateOpts structs while keeping the omitempty tag, to make a clear difference between "I want to change this property" and "I don't want to change this property", including the case where the required new value happens to be the zero value for the type (and as a consequence wasn't sent to the server before this patch).
This technically is a superfluous change in some instances. For example, let's take the servers package. It's useless to use *string in Name, because the API refuses the empty string as a name. Same goes for accessIPv4 and accessIPv6. However, I agree with you that this change brings consistency and consistency is valuable.
My comments propose the addition of a convenience generic function that given a value, returns a pointer to it. It may make code more easily readable and reduce the LOC count of this patch. Please consider adding it in an internal package (I propose internal/ptr) to use it in both unit and acceptance tests.
| name := tools.RandomString("TESTACCT-", 8) | ||
| flavorProfileUpdateOpts := flavorprofiles.UpdateOpts{ | ||
| Name: tools.RandomString("TESTACCTUP-", 8), | ||
| Name: &name, |
There was a problem hiding this comment.
| Name: &name, | |
| Name: ptr.To(tools.RandomString("TESTACCTUP-", 8)), |
| Description: description, | ||
| FlavorProfileId: flavorProfile.ID, | ||
| Enabled: true, | ||
| Enabled: new(bool), |
There was a problem hiding this comment.
| Enabled: new(bool), | |
| Enabled: ptr.To(true), |
| name := "new-name" | ||
| actual, err := servers.Update(context.TODO(), client, "1234asdf", servers.UpdateOpts{Name: &name}).Extract() |
There was a problem hiding this comment.
| name := "new-name" | |
| actual, err := servers.Update(context.TODO(), client, "1234asdf", servers.UpdateOpts{Name: &name}).Extract() | |
| actual, err := servers.Update(context.TODO(), client, "1234asdf", servers.UpdateOpts{Name: ptr.To("new-name")}).Extract() |
| Name: &name, | ||
| AvailabilityZone: &availabilityZone, |
There was a problem hiding this comment.
Please consider adding an internal convenience function to indirect values on-the-fly:
diff --git a/internal/ptr/to.go b/internal/ptr/to.go
new file mode 100644
index 00000000..0f2fd60f
--- /dev/null
+++ b/internal/ptr/to.go
@@ -0,0 +1,3 @@
+package ptr
+
+func To[T any](v T) *T { return &v }After that, this can become:
| Name: &name, | |
| AvailabilityZone: &availabilityZone, | |
| Name: ptr.To("new_aggregate_name"), | |
| AvailabilityZone: ptr.To("new_azone"), |
As a byproduct, it's a function we can point users to in case they want to copy-paste.
There was a problem hiding this comment.
why internal? this can be reused in other packages. also it would be helpful to have a helper to get a pointer value on-the-fly. and if it's a nil, return an empty struct.
There was a problem hiding this comment.
Internal so that it doesn't increase the package's API. I don't think we want that function to be part of the exported Gophercloud funtions.
it would be helpful to have a helper to get a pointer value on-the-fly. and if it's a nil, return an empty struct
That looks complex. Do you envision that as another convenience function for testing? Would you use that in this PR?
| updateOpts := secgroups.UpdateOpts{ | ||
| Name: newName, | ||
| Name: &newName, | ||
| Description: &description, |
There was a problem hiding this comment.
This can become:
| Description: &description, | |
| Description: ptr.To(""), |
There was a problem hiding this comment.
I'll keep this as is, since description is used below in code.
| "name": "Basic", | ||
| "description": "A basic standalone Octavia load balancer.", | ||
| "enabled": true, | ||
| "enabled": false, |
There was a problem hiding this comment.
This can be reverted once you apply my suggestion above
There was a problem hiding this comment.
no, we want to ensure that this can be set to false.
There was a problem hiding this comment.
OK; but then please add a new test to verify the new functionality, and leave this old test here doing its job of testing regressions :)
| Name: "Basic", | ||
| Description: "A basic standalone Octavia load balancer.", | ||
| Enabled: true, | ||
| Enabled: new(bool), |
There was a problem hiding this comment.
| Enabled: new(bool), | |
| Enabled: ptr.To(true), |
| Name: &name, | ||
| Description: &description, | ||
| Enabled: &enabled, |
a43d466 to
84deba4
Compare
internal/ptr/ptr.go
Outdated
| func From[T any](p *T) T { | ||
| if p == nil { | ||
| var v T | ||
| return v | ||
| } | ||
| return *p | ||
| } |
There was a problem hiding this comment.
This doesn't seem to be used anywhere. Please remove
e89ce11 to
9a4af6a
Compare
Octavia Flavor's `enabled` is true by default
9a4af6a to
c9703e7
Compare
pierreprinetti
left a comment
There was a problem hiding this comment.
Thanks! This is for v3
Fixes #1332