Add the extension types, datetime and duration#35
Conversation
d92facc to
14e55f5
Compare
internal/eval/evalers.go
Outdated
| if err != nil { | ||
| return nil, err | ||
| } | ||
| l, ok := v.(types.ComparableValue) |
There was a problem hiding this comment.
Can you make ComparableValue be an interface that only exists within the evalers package? I don't think the general public needs to be aware of it.
internal/eval/evalers.go
Outdated
| if err != nil { | ||
| return zeroValue(), err | ||
| } | ||
| return types.Long(lhs.Value / 1000 / 60 / 60), nil |
There was a problem hiding this comment.
Can all theses things end up as constants? lhs.Value / Hour or something
| year, month, day, hour, minute, second, milli int | ||
| i int | ||
| ) | ||
|
|
There was a problem hiding this comment.
Max nitpick - maybe less linebreaks would feel a bit nicer.
types/datetime.go
Outdated
|
|
||
| minute = 10*int(rune(s[i])-'0') + int(rune(s[i+1])-'0') | ||
|
|
||
| i = i + 2 |
There was a problem hiding this comment.
Maybe it would be nice if there was a few private constants
`
const dateOffset = 3
const hourOffset = 6
etc.
The changing of i, then using offsets from i is a bit hard to read.
types/datetime.go
Outdated
| return ok && a == b | ||
| } | ||
|
|
||
| func (a Datetime) Less(bi Value) bool { |
There was a problem hiding this comment.
Less and LessEqual should return errors in case the types are not the same.
Also, I'd call them LessThan and LessThanOrEqual to better match the cedar operators list:
https://docs.cedarpolicy.com/policies/syntax-operators.html
There was a problem hiding this comment.
Alternatively it could just take in the exact type only Less(bi Datetime)
Then you'd just do all the type checking work within the evalers package.
Could go either way on this.
There was a problem hiding this comment.
I think it's less desirable for the method to take a concrete type given there's an interface here. I'll do a type assertion in the implementation.
| // The following are not supported: | ||
| // "datetime(\"1970-01-01T00:00:00Z\")" | ||
| // {"fn":"datetime","arg":"1970-01-01T00:00:00Z"} | ||
| var res extValueJSON |
There was a problem hiding this comment.
As long as this is in parity with what we did for Decimal/IPAddr it's okay for now. But maybe add an issue somewhere about the deficit.
There was a problem hiding this comment.
I'll just add it for duration/datetime, as they aren't hard to add.
types/duration.go
Outdated
| "unicode" | ||
| ) | ||
|
|
||
| const ( |
There was a problem hiding this comment.
Ah, since I mentioned those constants elsewhere, maybe they can all live in the internal/consts package?
types/duration.go
Outdated
| } | ||
|
|
||
| // UnsafeDuration creates a duration via unsafe conversion from int, int64, float64 | ||
| func UnsafeDuration[T int | int64 | float64](v T) Duration { |
There was a problem hiding this comment.
Maybe it should multiply by 1000 or something? And the comment should indicate what it takes in, e.g. seconds?
There was a problem hiding this comment.
I'd probably just drop this function and only include FromStdDuration.
948a208 to
cf55f89
Compare
|
@philhassey I think all of your comments have been addressed. |
internal/eval/comparable.go
Outdated
| type ComparableValue interface { | ||
| types.Value | ||
| LessThan(types.Value) (bool, error) | ||
| LessThanEqual(types.Value) (bool, error) |
There was a problem hiding this comment.
Can we change LessThanEqual to LessThanOrEqual, that better matches the cedar docs:
https://docs.cedarpolicy.com/policies/syntax-operators.html#function-lessThanOrEqual
| return Duration{Value: negative * total}, nil | ||
| } | ||
|
|
||
| func (a Duration) Equal(bi Value) bool { |
There was a problem hiding this comment.
All method and functions need a go-doc style docstring.
types/datetime.go
Outdated
| Value int64 | ||
| } | ||
|
|
||
| func UnsafeDatetime[T int | int64 | float64](v T) Datetime { |
There was a problem hiding this comment.
I still think this function isn't useful.
There was a problem hiding this comment.
ha! I think I stopped using it and didn't delete it. I'll get rid of it.
There was a problem hiding this comment.
Apparently I didn't stop using it. 🤔 I will stop using it.
|
I think this will be the next release, so maybe add in something to the README.md explaining the latest goodies in 0.3.2. And also add some explanation as to how datetime is an accepted RFC, but it's a bit bleeding edge (as discussed in the meeting yesterday) |
This PR does not add the duration type, nor the methods `toTime()`, `offset()`, or `durationSince()` that would require it. This PR adds operator overloading, by introducing a set of "Virtual" comparison Evaler. Types that can overload operators must implement the `Lesser` interface. Long and Datetime are implemented in this PR. (Note: It is expected that there will be a Decimal operator overload RFC at some later date, but that is not hooked into this) The now obsolete Evalers for Long comparisons have not been removed. A possible improvement to this PR would be to utilize them when it is known that Longs are on the right and left side. The datetime itself is backed by an int64, and can be lifted from a Go `time.Time`, integer or float "unsafely." Signed-off-by: Andrew Gwozdziewycz <andrew.gwozdziewycz@strongdm.com>
This builds on the Datetime PR. It adds the duration type, and all of the associated methods that require durations: - datetime.toTime - datetime.offset - datetime.durationSince - duration.toMilliseconds - duration.toSeconds - duration.toMinutes - duration.toHours - duration.toDays Signed-off-by: Andrew Gwozdziewycz <andrew.gwozdziewycz@strongdm.com>
4adb50c to
47eb643
Compare
types/datetime.go
Outdated
| return Datetime{Value: t.UnixMilli()}, nil | ||
| } | ||
|
|
||
| // Equal returns true if the lfs represents the same timestamp as the rhs. |
There was a problem hiding this comment.
I think "lhs" instead of "lfs"
I feel like "lhs" and "rhs" is a bit odd. Maybe have it phrased "Equal returns true if the input represents the same timestamp."
philhassey
left a comment
There was a problem hiding this comment.
Looks good, just a tiny text edit. Can @patjakdev give this a quick review as well?
30daa0a to
78770a1
Compare
|
OK. At 100% coverage for all changes. There's one line that's not covered in cedar_unmarshal that is unrelated to my changes. I tried to figure out a quick way to reach it, but failed. :) |
patjakdev
left a comment
There was a problem hiding this comment.
Looks really good to me. Just a couple of nits.
| if err != nil { | ||
| return zeroValue(), err | ||
| } | ||
| ok, err := lhs.LessThanOrEqual(rhs) |
There was a problem hiding this comment.
tiny nit: the ok here maybe should be isLessThanOrEqual? ok implies something else to me.
internal/consts/consts.go
Outdated
| MillisPerDay = int64(1000 * 60 * 60 * 24) | ||
| MillisPerHour = int64(1000 * 60 * 60) | ||
| MillisPerMinute = int64(1000 * 60) | ||
| MillisPerSecond = int64(1000) |
There was a problem hiding this comment.
tiny nit: seems like these could be composed from each other
types/duration.go
Outdated
|
|
||
| // A Duration is a value representing a span of time in milliseconds. | ||
| type Duration struct { | ||
| Value int64 |
There was a problem hiding this comment.
I think we should strongly consider making Value private. The accessor methods with units seem like the right public interface for this.
There was a problem hiding this comment.
Changed. Note that Decimal still exposes this.
types/datetime.go
Outdated
| // Datetime represents a Cedar datetime value | ||
| type Datetime struct { | ||
| // Value is a timestamp in milliseconds | ||
| Value int64 |
There was a problem hiding this comment.
I think we should strongly consider keeping Value private and making an accessor method that gives you the time since the epoch in milliseconds.
There was a problem hiding this comment.
Changed. Note that Decimal still exposes this.
There was a problem hiding this comment.
I think Decimal will take a bit more effort, I've made an issue in the IDX project for us to handle that in a separate PR.
- Lesser becomes ComparableValue - Move ComparableValue to evalers only - Move all magic values to constants - TypeError when incompatible comparable types - Support more deserialization for duration/datetime - Make the datetime parser easier to follow - Drop UnsafeDatetime in favor of FromStdTime(time.UnixMilli(..)) - Document methods - Test Coverage to 100% Signed-off-by: Andrew Gwozdziewycz <andrew.gwozdziewycz@strongdm.com>
Signed-off-by: Andrew Gwozdziewycz <andrew.gwozdziewycz@strongdm.com>
78770a1 to
125cddb
Compare
See merged RFC 80.
This PR adds:
datetimeanddurationtype specified in RFC 80ComparableValues, such as Long, Datetime, Duration.This does not extend ComparableValue to Decimal, as there's no RFC / specification to make that so (doing so would be straightforward, however).
Both
datetimeanddurationare backed by an int64 and can be lifted from a Gotime.Timeand atime.Durationrespectively. It would be possible to remove the struct wrapper around the int64, as no other state is stored. We aren't doing this to prevent accidental casting / type assertions that remove the semantic meaning of these values.(Note: there was some previous discussion in the strongdm fork of this repo: strongdm#3)