-
Notifications
You must be signed in to change notification settings - Fork 25
feat: Add Time configtype #1905
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
erezrokah
left a comment
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.
Hi @rhino1998, nice 🚀 Can you give an example how this will be used in a plugin and in a spec file?
|
Added some more context. Should |
erezrokah
left a comment
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 like the idea of having this kind of type as an SDK helper.
A few comments:
- If the purpose is to make it easier to configure relative times, I would use https://github.com/tj/go-naturaldate/tree/master instead of a wrapper over duration
- I would hide the
IsRelativeandNewRelativeTimeand doNewTime(t string)that accepts either an RFC3339 or a natural date string. I don't see a reason consumers need to know the internal representation, also I don't think we even needtyp timeType, as you can haveNewTime(t string, base time.Time)and convert the string on creation.
I would push back on this; the library was last updated 4 years ago, and supports much more than we need to support. I think we would be better off supporting a small, well-defined number of formats. Also I think the purpose here is not to make it easier, it's to make it possible at all (in Cloud), in a standardized way. |
I agree it hasn't change in a long time, but it doesn't have any other dependencies (other than the ones used for testing), and the author is https://github.com/tj (https://x.com/tjholowaychuk), which has a bunch of other popular repositories like https://github.com/tj/commander.js and https://github.com/koajs/koa
Agree it does more than we need, but
Can you add more context on the Cloud use case? We want the backend to specify a duration via spec generated via backend code in Go? If so is it possible to convert the duration to time before? |
We want users to be able to specify a relative time, such as "30 days ago", which will be stored as part of the spec. Every time the sync runs, this should be converted to a timestamp relative to the current time. This way, we don't need to involve the backend to do string interpolation on the spec, and things remain relatively simple. Right now, what happens in many plugins is they allow only a fixed timestamp to be specified, such as |
I agree with this. I'm also okay with using that library, but if we do, let's not support everything that the library supports, but instead limit it to a defined list of supported formats that we can control. I would maybe say something like:
would be a good enough start (we can always add more if requested) |
Sounds like a plan to me |
|
I forgot that in addition to relative times, we'd also want to support fixed timestamps of course, probably using RFC 3339. And also some support for plain dates, e.g. |
| { | ||
| Name: "complex relative duration", | ||
| Err: false, | ||
| Spec: `"10 months 3 days 4h20m from now"`, |
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 if we're going to expose MarshalJSON then we should probably make this format 10 months 3 days 4 hours 20 minutes from now for consistency (and so we don't need to make a breaking change later to fix it)
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.
Alternatively we could remove the ability to specify an arbitrary duration in the constructor (just remove the constructor) and only allow this to be constructed using a simple string like 10 days ago
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.
The reason for the weird hybrid format is for backwards compat for the Duration type. It ensures that anything constructed from a plain duration will emit the same json as before this PR. It may be reasonable to separate the json serialization format and the string parsed format and make the serialization format (but still unmarshalling the nicer human format) just [-+](\d+[a-zA-Z])+ (basically time.ParseDuration format but with additional units). That frees us to have the string format be nicer and human readable
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.
Would https://github.com/cloudquery/plugin-sdk/pull/1905/files#r1775175473 solve this?
erezrokah
left a comment
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.
Thanks for the following @rhino1998, added a few more comments
configtype/duration.go
Outdated
| "github.com/invopop/jsonschema" | ||
| ) | ||
|
|
||
| var ( |
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 prefer if we don't change the semantics of the existing duration type, as that could breaking existing behavior for consumers of this 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.
All previously valid values are still valid for the duration type. This just adds more possible valid values. Additionally all previously valid values will serialize to the same string after this PR in its current state. (unless I missed something)
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.
This just adds more possible valid values.
Exactly, so now the JSON validation is more relaxed, so something that would have failed before can pass now.
While this could be seen as a feature, it's better if plugins opt-in to it, then document the new behavior
configtype/time.go
Outdated
| } | ||
|
|
||
| func (t Time) MarshalJSON() ([]byte, error) { | ||
| switch t.typ { |
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 we can keep the original string that we got in ParseTime and return that instead, WDYT?
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.
263750b, but unclear what the handling for an uninitialized Time or Duration should be. Currently it just marshals to ""
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.
Also, as a side-effect Time and Duration are no longer == comparable in a useful way
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.
263750b, but unclear what the handling for an uninitialized Time or Duration should be. Currently it just marshals to
""
I think we need to decide that and pick whatever we want to happen, we can
- Error out on uninitialized
- Return
MarshalJSONof the zero value oftime.Time - Return
MarshalJSONof the zero value oftime.Duration - Return
null - Maybe more options
Not sure what's the best option but it needs to be consistent with UnmarshalJSON.
We can see what happens for time.Time and time.Duration zero values
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.
Also, as a side-effect Time and Duration are no longer == comparable in a useful way
How could you compare Time and Duration before? Where do you need this comparison and how will it be used?
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.
Duration was comparable with == (as it was just a struct) containing a time.Duration. I'm unsure if that was used anywhere but removing that is a breaking change. Adding days,months,etc to the struct maintained comparability for equal values but adding the input string field breaks that for anything besides values that had the same input string even if they're otherwise equivalent (including whitespace differences).
I guess Time wasn't usefully comparable with == as while time.Time is == comparable doing doesn't handle timezones and so is not recommended.
As for where it is needed, it isn't exactly for time, but the duration change is breaking change in the API (unclear if anything actually uses it though)
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.
Ok so:
- I don't think we should modify the existing duration config type. Relaxing the parsing is also a breaking change
- Even if we did modify the existing type, we can used the parsed value of the duration for
Equals
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.
Regarding 2., that still will have broken == comparison, although again unclear if that is used externally or if that even counts as an explicit part of the API to be broken
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.
Regarding default behavior, returning the zero value of time seems sane as it'll allow the current IsZero check to work. Although that is "0001-01-01T00:00:00Z"
|
@erezrokah @rhino1998 I lost track a bit, is there still anything unresolved on this PR? |
Not sure https://github.com/cloudquery/plugin-sdk/pull/1905/files#r1774764467 is resolved, also #1905 (comment) I'd rather if we don't change the existing type behavior as that implicitly change spec parsing behavior for plugins. If plugins want to support the new human friend format mixed duration/time format they should do it explicitly I think |
The new mixed duration/time format is opt-in, but the new duration format does extend the old plain time.ParseDuration-based format. How would you prefer the opt-in be done? A DurationV2 type? A separate package? |
I don't mind I mostly don't want to change the existing behavior of the current type. You can also put everything under the new |
| { | ||
| Name: "complex relative duration", | ||
| Err: false, | ||
| Spec: `"10 months 3 days 4h20m from now"`, |
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.
Should we change this to @hermanschaaf's suggestion of 10 months 3 days 4 hours 20 minutes from now?
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.
In its current state, both are handled and whatever was input will be emitted. I added some test cases to make this clearer. 1a5ae0a
|
Nothing blocking on my end, so you can merge at will. We might want to wait with releasing the new SDK until after today's plugins release cycle to avoid creating noise for the plugins teams |
|
I think (sorry for the late comment) the |
We could pretty easily add support for stuff like |
|
@disq Do you consider the above blocking? |
@rhino1998 No not at all. |
|
Not sure what's the status here, should we merge this or close it as stale? |
🤖 I have created a release *beep* *boop* --- ## [4.68.0](v4.67.1...v4.68.0) (2024-10-31) ### Features * Add Time configtype ([#1905](#1905)) ([f57c3eb](f57c3eb)) * Support for quota query interval header ([#1948](#1948)) ([bfce6fe](bfce6fe)) * Test `MeterUsage` API call on initial setup of client ([#1906](#1906)) ([78df77d](78df77d)) ### Bug Fixes * Clean up usage retry logic ([#1950](#1950)) ([ca982f9](ca982f9)) * **deps:** Update module github.com/cloudquery/plugin-pb-go to v1.25.0 ([#1946](#1946)) ([b8e3e10](b8e3e10)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Summary
This adds a new Time type to be used in plugin specs that can represent either fixed times or relative times. A future PR should extend the duration parsing to handle days, etc.
Here
timeframe_startandtimeframe_endare both configtype.Time types. Using mixed relative/fixed timestamps for timeframes isn't really useful here as the relative one will be relative to the run-time of the sync but in this example havingor even omitting
timeframe_endentirely is more usefulThe plugin is free to define default like so