Skip to content
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

feat(pgrx): add chrono feature for easy conversions #1603

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from

Conversation

t3hmrman
Copy link

This commit adds a chrono feature flag to pgrx, which enables conversions between pgrx native date/time (with or without timezone) and chrono types like NaiveDateTime.

@eeeebbbbrrrr
Copy link
Contributor

I think you're probably on the right track here. I suppose we'd want to also have conversions from the chrono types into the Postgres types.

I don't know how far @workingjubilee might want to take this in terms of also supporting IntoDatum/FromDatum for the chrono types (not clear to which SQL type they'd map to), so that's an open question...

@workingjubilee
Copy link
Member

Yeah, this seems like the right direction.

I don't think we want to support IntoDatum/FromDatum for these types. I would rather move towards making it easier to distinguish when something is a "zero-overhead" or "direct" conversion that is natively supported by Postgres, and when something requires additional logic like these types always will.

@t3hmrman
Copy link
Author

Thanks for the check @workingjubilee @eeeebbbbrrrr and for the heads up -- just to confirm I do plan to add the conversions both ways.

Will finish up the rest of it in this pattern and turn this to ready for review hopefully soon!

@t3hmrman t3hmrman force-pushed the feat(pgrx)=add-chrono-feature branch from 0060346 to 602e592 Compare March 27, 2024 04:25
@t3hmrman t3hmrman force-pushed the feat(pgrx)=add-chrono-feature branch 3 times, most recently from f82cda2 to d389f30 Compare April 11, 2024 07:21
@t3hmrman t3hmrman marked this pull request as ready for review April 11, 2024 07:21
@t3hmrman
Copy link
Author

Hey @workingjubilee @eeeebbbbrrrr just finished the first version of this, would love a review whenever you can find some time!

I've tried to be pretty explicit about where the microseconds-only limitation of pg comes into play. I'm also equally happy to put this functionality in some sort of external crate if you'd prefer to not upstream this functionality as well!

@daamien
Copy link
Contributor

daamien commented Jul 1, 2024

Hi !

Is there's a way for me to help moving this PR forward ? It would be very useful in my own extension...

@t3hmrman t3hmrman force-pushed the feat(pgrx)=add-chrono-feature branch from d389f30 to ba845a4 Compare July 1, 2024 09:11
@t3hmrman
Copy link
Author

t3hmrman commented Jul 1, 2024

Rebased just to make sure that's not blocking progress here :)

@t3hmrman t3hmrman force-pushed the feat(pgrx)=add-chrono-feature branch from ba845a4 to 77a2824 Compare July 1, 2024 09:13
@workingjubilee
Copy link
Member

Sorry, all my focus was being consumed by #1731 since that was one of our last release blockers so reviewing anything that wasn't incredibly trivial was backburnered.

Copy link
Member

@workingjubilee workingjubilee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for letting this sit for a while. It looks good and I think my only request is for property testing. It's been very good at finding edge-cases in our datetime handling in particular.

pgrx/src/datum/datetime_support/chrono.rs Show resolved Hide resolved
Comment on lines +23 to +74
fn chrono_simple_date_conversion() -> DtcResult<()> {
let original = pgrx::Date::new(1970, 1, 1)?;
let d = chrono::NaiveDate::try_from(original)?;
assert_eq!(d.year(), original.year(), "year matches");
assert_eq!(d.month(), 1, "month matches");
assert_eq!(d.day(), 1, "day matches");
let backwards = pgrx::Date::try_from(d)?;
assert_eq!(backwards, original);
Ok(())
}

/// Ensure simple conversion ([`pgrx::Time`] -> [`chrono::NaiveTime`]) works
#[pg_test]
fn chrono_simple_time_conversion() -> DtcResult<()> {
let original = pgrx::Time::new(12, 1, 59.0000001)?;
let d = chrono::NaiveTime::try_from(original)?;
assert_eq!(d.hour(), 12, "hours match");
assert_eq!(d.minute(), 1, "minutes match");
assert_eq!(d.second(), 59, "seconds match");
assert_eq!(d.nanosecond(), 0, "nanoseconds are zero (pg only supports microseconds)");
let backwards = pgrx::Time::try_from(d)?;
assert_eq!(backwards, original);
Ok(())
}

/// Ensure simple conversion ([`pgrx::Timestamp`] -> [`chrono::NaiveDateTime`]) works
#[pg_test]
fn chrono_simple_timestamp_conversion() -> DtcResult<()> {
let original = pgrx::Timestamp::new(1970, 1, 1, 1, 1, 1.0)?;
let d = chrono::NaiveDateTime::try_from(original)?;
assert_eq!(d.hour(), 1, "hours match");
assert_eq!(d.minute(), 1, "minutes match");
assert_eq!(d.second(), 1, "seconds match");
assert_eq!(d.nanosecond(), 0, "nanoseconds are zero (pg only supports microseconds)");
let backwards = pgrx::Timestamp::try_from(d)?;
assert_eq!(backwards, original, "NaiveDateTime -> Timestamp return conversion failed");
Ok(())
}

/// Ensure simple conversion ([`pgrx::TimestampWithTimeZone`] -> [`chrono::DateTime<Utc>`]) works
#[pg_test]
fn chrono_simple_datetime_with_time_zone_conversion() -> DtcResult<()> {
let original = pgrx::TimestampWithTimeZone::with_timezone(1970, 1, 1, 1, 1, 1.0, "utc")?;
let d = chrono::DateTime::<Utc>::try_from(original)?;
assert_eq!(d.hour(), 1, "hours match");
assert_eq!(d.minute(), 1, "minutes match");
assert_eq!(d.second(), 1, "seconds match");
assert_eq!(d.nanosecond(), 0, "nanoseconds are zero (pg only supports microseconds)");
let backwards = pgrx::TimestampWithTimeZone::try_from(d)?;
assert_eq!(backwards, original);
Ok(())
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you, in addition to these simpler tests, set up a proptest like in https://github.com/pgcentralfoundation/pgrx/blob/77a28242fd89372a6fd7cc4ded1fcae9a63319f8/pgrx-tests/src/tests/proptests.rs so that these conversions are fairly invariant?

It doesn't have to roundtrip stuff through SPI, since that's not really what we'd be testing, so it doesn't need to use the exact pattern I used there. It can do something simpler with just handling https://github.com/pgcentralfoundation/pgrx/blob/77a28242fd89372a6fd7cc4ded1fcae9a63319f8/pgrx-tests/src/proptest.rs

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely -- yeah I didn't think the roundtripping was necessary, but a prop test would definitely make a ton of sense here.

  • Add property test for conversions

@t3hmrman
Copy link
Author

t3hmrman commented Jul 2, 2024

@workingjubilee absolutely no problem -- thanks for taking a look (P.S. I saw the other thing you were working on 👍 👍 👍).

Will add the additional tests!

This commit adds a `chrono` feature flag to `pgrx`, which enables
conversions between `pgrx` native date/time (with or without timezone)
and `chrono` types like `NaiveDateTime`.
@t3hmrman t3hmrman force-pushed the feat(pgrx)=add-chrono-feature branch from 77a2824 to d2f1002 Compare July 5, 2024 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants