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: bootstrap jiff-sqlx development #141

Open
wants to merge 18 commits into
base: master
Choose a base branch
from

Conversation

tisonkun
Copy link

This refers to #50.

Firstly, I considered to add a separated sqlx-jiff method, but soon I found that due to Rust's orphan rules, implementing sqlx's trait for Timestamp and other types requires the code to be located at the same crate (jiff). Otherwise we need an extra wrapper struct like:

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Timestamp(pub jiff::Timestamp);

I prefer to implement code in jiff and gate it with feature flags.

@BurntSushi This demonstrates the integration implementation direction. I'll complete other parts when we agree on this direction.

@BurntSushi
Copy link
Owner

#50 (comment) discusses this. And the orphan rule is taken into account there. The way to do this integration, short of getting it merged upstream in sqlx itself, is with a wrapper type in a jiff-sqlx crate. The comment linked explains how to do this.

Jiff is a "low level" crate. Having it depend on "high level" crates like sqlx would lead to all sorts of problems, especially if and when the time ever comes for sqlx to add Jiff integration on their end. It's really a non-starter.

Copy link
Author

@tisonkun tisonkun left a comment

Choose a reason for hiding this comment

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

@BurntSushi Yeah .. Adopt the other way now.

sqlx-jiff/src/lib.rs Outdated Show resolved Hide resolved
sqlx-jiff/src/lib.rs Outdated Show resolved Hide resolved
@BurntSushi
Copy link
Owner

Also, the crate should be called jiff-sqlx, since it lives with jiff.

@tisonkun
Copy link
Author

tisonkun commented Oct 11, 2024

Other type mapping to be wrapped once we agree on the pattern:

  • jiff::civil::Date <-> DATE
  • jiff::civil:Time <-> TIME
  • jiff:civil::DateTime <-> TIMESTAMP
  • jiff::Timestamp <-> TIMESTAMPTZ
  • jiff::SignedDuration <-> INTERVAL

Ref -

@tisonkun tisonkun changed the title feat: bootstrap sqlx-jiff development feat: bootstrap jiff-sqlx development Oct 14, 2024
@tisonkun
Copy link
Author

All bridges submitted. Note that integrations for PgRange and PgTimeTz cannot be added due to the orphan rule.

I'd suspend the task here to start jiff-sqlx with Postgres support first since it's my real use case and I'd avoid adding too many things at the very beginning.

@tisonkun tisonkun requested a review from BurntSushi October 23, 2024 07:21
@tisonkun
Copy link
Author

The failing wasm CI job doesn't seem to be relevant to this patch ..

@maxcountryman
Copy link

  • jiff::SignedDuration <-> INTERVAL

I'm curious why this wouldn't be jiff::Span? That's how I'm doing these conversions manually.

@tisonkun
Copy link
Author

@maxcountryman

It's possible to support multiple type mappings, so it's possible to support both Span and Duration.

However, PG's interval supports only months, days and microseconds parts. Span supports other units. I'm not sure if we can always assume 1 year=12 months, and 1 week=7days.

Anyway, we may support two types together.

@maxcountryman
Copy link

Span supports other units. I'm not sure if we can always assume 1 year=12 months, and 1 week=7days.

As I understand, Span doesn't assume 12 months == 1 year (ergo keeping each unit as a discrete property). I think that might be a reason to use Span here, right? (In particular, I believe Span is needed for full ISO 8601 support.)

@tisonkun
Copy link
Author

tisonkun commented Jan 4, 2025

Hi @BurntSushi!

IMO code gets evolved and mature by tested in real world.

It's understandable that your context is not for such an integration, and you don't want release code that you don't look carefully into.

So, I wonder if it's OK for you that I release this crate under the name jiff-sqlx while I'm the crate owner for all the followups. And once you or the sqlx's maintainer accept to maintain it in either upstream (for the benefits to evolve together and catch up changes in the first place), we can work a transfer solution then.

@BurntSushi
Copy link
Owner

Can you please pick a different name? That way we don't need to do any transfers or have any other project expectations.

I also thought you had this code in your own project internally? Why do you need to publish a crate to do it?

@tisonkun
Copy link
Author

tisonkun commented Jan 4, 2025

Can you please pick a different name? That way we don't need to do any transfers or have any other project expectations.

Then I'd leave this PR here so that anyone need it can use it by copying the code. I don't think such an integration worth a dedicated name.

I also thought you had this code in your own project internally? Why do you need to publish a crate to do it?

This is somehow like a question "why do you write opensource code". I write opensource code everyday so sharing code is by default (as shown in my GitHub profile). Also you can see that there are several other users want it. This is enough.

@BurntSushi
Copy link
Owner

Yes sorry, it is totally cool to publish a crate for the good of open source. I was in a "are you yourself blocked" frame of mind versus "you want to publish a crate for others to use." So in the latter case, I think it's just a matter of either you going ahead and doing it (which is your right, although I request that you not use a jiff- prefix) or waiting until I'm able to dig into it.

Ecosystem integration is a big problem and I need to context switch into it. I'm just not there yet. And I'm currently thinking I'll do it with a jiff 0.2 release, since there are a number of breaking changes I'd like to make.

@maxcountryman
Copy link

My two cents: this is not the correct implementation re Postgres intervals. I think that should be addressed before publishing.

@BurntSushi
Copy link
Owner

@maxcountryman I haven't looked too closely yet. It looks like only SignedDuration is supported here and it collapses everything down to microseconds. Can you say more about what you see as incorrect?

@maxcountryman
Copy link

@BurntSushi
Copy link
Owner

SignedDuration would still certainly emit ISO 8601.

Regardless, I'll dig into this more when I address ecosystem integration. But if you have any more explanation, I would be happy to hear it!

@maxcountryman
Copy link

@BurntSushi This passage in the docs: "Unlike the Span type, though, only uniform units are supported. This means that ISO 8601 durations with non-zero units of days or greater cannot be parsed directly into a SignedDuration" along with this from the Postgres docs, "As previously explained, PostgreSQL stores interval values as months, days, and microseconds" seem incompatible.

value: <Postgres as Database>::ValueRef<'r>,
) -> Result<Self, BoxDynError> {
let pg_interval = PgInterval::decode(value)?;
let micros = pg_interval.microseconds;
Copy link
Owner

Choose a reason for hiding this comment

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

@maxcountryman Ah so I think this is where there is a correctness issue? The non-microseconds units are being silently ignored here.

Choose a reason for hiding this comment

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

This is almost certainly incorrect, yes.

However, I'm also pointing out that Postgres can be configured to output ISO 8601. Your docs say SignedDuration is not capable of parsing ISO 8601 with non-zero days. Moreover, my impression is that Spans may be preferred for ISO 8601. Regardless, Postgres will use non-zero days when configured this way so that must be handled somehow. In my own programs I just use Span.

I said as much earlier in the thread but the original author did not respond after I pointed this out.

I don't think an implementation that doesn't address this somehow should be published personally.

Choose a reason for hiding this comment

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

Just to confirm there is a correctness issue here, this implementation omits two fields, days and months.

Copy link
Owner

Choose a reason for hiding this comment

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

Okay thanks, I understand now. I agree.

I'll take a closer look later.

Copy link
Author

@tisonkun tisonkun Jan 5, 2025

Choose a reason for hiding this comment

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

@maxcountryman Thanks for your feedback! Your analysis is correct.

The decode part is added three days ago at 2f17955 while I'd like to use SignedDuration to hold PG's interval. The background in my use case is that all the interval is written by my code and thus it's guaranteed only microseconds unit are filled. But for general purpose usage, this may not be true.

There is a related discussion at #174 (reply in thread). In short, I'd first remove the decode impl for SignedDuration now because you can hardly convert days & months to seconds without a relative datetime by jiff's design. But perhaps we can support codec over Span.

However, the encode part of SignedDuration should be fine.

Copy link
Author

Choose a reason for hiding this comment

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

Or instead, we may check months and days are 0 when decode to SignedDuration and return an error if so.

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