- Notifications
You must be signed in to change notification settings - Fork928
feat: Addcodersdk.NullTime
, change workspace build deadline#3552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
// ping@johnstcn, what do you think about this approach? |
a7c0920
to43fbbea
Compare
:chefs-kiss: |
@@ -50,7 +50,7 @@ type WorkspaceBuild struct { | |||
InitiatorID uuid.UUID `json:"initiator_id"` | |||
InitiatorUsername string `json:"initiator_name"` | |||
Job ProvisionerJob `json:"job"` | |||
Deadlinetime.Time `json:"deadline"` | |||
DeadlineNullTime`json:"deadline,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Based on the comment in the attached issue, it's unclear what the use-case for knowing the time is null is that a pointer wouldn't solve.
Is this related to the TypeScript generation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I think this is a cleaner approach from a usability perspective in Go code. That is to say, the benefit is not in the frontend talking to the backend, it's using these values in the backend or cli.
IMO it'd be nice for us to consistently useNullTime
over*time.Time
in the API. Things like not being able to take a pointer of a function call&time.Now()
are not an issue when you can writecodersdk.NewNullTime(time.Now(), true)
. Likewise when using the type, there's no need for theif t != nil
check.
There are work-arounds for making pointer use a bit more convenient, like usingcoderd/util/ptr
, but it's an extra step to using them vs accessing the concrete type directly.
One last point in favor ofNullTime
, it's safer to use. There's no risk of doing a nil pointer dereference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
FWIW working with pointers makes me sad; I much prefer theNullXXX
approach.
Unless we start going down the lines of having a genericOptional[T]
type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'm hesitant to stray from such strong language primitives. Do we imagine having aNullXXX
for every type that could be nullable? This seems odd to me because embedded structs would likely be pointers withomitempty
rather thanNull<StructName>
. Are we promoting thisonly for built-in types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I understand why you may be hesitant, but I don't think it will be a problem. If we strive to make the zero value useful in most cases, the need for nullable values will be pretty low. We can also look atcodersdk
(today), there we only have a couple of primitives (int, string) and time.
7 *int64 5 *time.Time 3 *string 2 *uuid.UUID
Theuuid
package already hasuuid.NullUUID
, so it would make sense to use that one instead. In fact, the occurrence ofuuid.NullUUID
is much larger in our codebase than that of*uuid.UUID
(14 vs 3), yet we have both.
I also foresee that the need for a nullable struct will be very rare (we have none incodersdk
, currently), and in those cases it would likely be a custom type for which we can simply implement a custom json marshaler/unmarshaler. It's unfortunate Go never got around to addingomitzero
/omitempty
to thejson
package, because many times that would solve the use-case for using pointer-structs (i.e. often the reason is not to detect omission, it's to create a specific type of output).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I appreciate the explanation! I agree thatNullUUID
is classically used, but that's typically been used for database operations, not the API.
I'll defer here though. You've spent a lot more time thinking about this than I, so I approve!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Leaving this here for future reference, and perhaps an alternative avenue for achieving the same in a generic way. (Did some prototyping on this with@johnstcn some days ago)
typeOptional[Tany]struct {ValueTValidbool}// Of returns a new Optional of the given value.funcOf[Tany](oT)Optional[T] {returnOptional[T]{Value:o,Valid:true,}}// MarshalJSON implements json.Marshaler.func (oOptional[T])MarshalJSON() ([]byte,error) {// omitted for brevity}// UnmarshalJSON implements json.Unmarshaler.func (o*Optional[T])UnmarshalJSON(data []byte)error {// omitted for brevity}typeAPIRequeststruct {TimeOptional[time.Time]`json:"time"`}// other packagefuncsample() {r:= codersdk.APIRequest{}r.Time=codersdk.Of(time.Now())ifr.Time.Valid {// if we care about null._=r.Time.Value}// zero value is ok without null check too_=r.Time.Value.IsZero()}
The namingsOptional
,Of
, etc are all up in the air, they could beNull
andNewFrom
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
✅ FE
I only see an update to thedeadline
property being made optional now. I imagine this shouldn't have any consequences assuming we have tests for code using that interface.
If there is something else you want reviewed by FE, ping me!
a77ae97
to0c66c39
Comparemafredri commentedAug 25, 2022 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@jsjoeio Your comment made me take a look at the site code, and some updates were indeed required. Please take a look at I believe none of this was caught due to the function signature of |
3a3cb79
toe390cef
Compare89576ed
tofdb657e
CompareThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks for going the extra mile to double-check any side effects on the FE! 👏🏼
site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.tsx OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
…utton.tsxCo-authored-by: Joe Previte <jjprevite@gmail.com>
I took a slightly different approach in this PR than what originally proposed in#2015, it's closer to my proposal in a later comment.
Currently we embedd
sql.NullTime
forone reason, it gives us database scanner/valuer and means we can pass nullable times to the DB by doingt.NullTime
.We can simplify this though, if it's not needed so that we have plain
codersdk.NullTime{Time time.Time; Valid boold}
.Fixes#2015