-
Notifications
You must be signed in to change notification settings - Fork 10
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
Add the extension types, datetime and duration #35
Conversation
d92facc
to
14e55f5
Compare
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.
Hope those help!
internal/eval/evalers.go
Outdated
if err != nil { | ||
return nil, err | ||
} | ||
l, ok := v.(types.ComparableValue) |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think this function isn't useful.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently I didn't stop using it. 🤔 I will stop using 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.
Hope that helps!
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 <[email protected]>
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 <[email protected]>
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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."
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.
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. :) |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed. Note that Decimal still exposes this.
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 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 <[email protected]>
Signed-off-by: Andrew Gwozdziewycz <[email protected]>
78770a1
to
125cddb
Compare
See merged RFC 80.
This PR adds:
datetime
andduration
type specified in RFC 80ComparableValue
s, 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
datetime
andduration
are backed by an int64 and can be lifted from a Gotime.Time
and atime.Duration
respectively. 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)