graphile / crystal

šŸ”® Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!
https://graphile.org/
Other
12.58k stars 570 forks source link

PageInfo implemented incorrectly? #2138

Closed adamni21 closed 1 month ago

adamni21 commented 2 months ago

Summary

PageInfo is not implement as per relay specification .

Steps to reproduce

I've created a branch, with the cursor related tests adjusted. https://github.com/adamni21/crystal/tree/fix-PageInfo-tests

Note: The adjusted tests still don't quite line up with the specification I think. Since the spec states: "that elements exist prior to after" / "that elements exist following before" which to me (non-native speaker) implies prior/following exclusive after/before, which imho is illogical, and should be inclusive. (the GitHub graphql api agrees with me)

Expected results

The adjusted tests should pass.

Actual results

The adjusted tests do fail.

Possible Solution

šŸ¤·

benjie commented 2 months ago

If the client is paginating with first/after, then the client may return true if edges prior to after exist, if it can do so efficiently, otherwise may return false.

When pagination with first/after we cannot efficiently determine if edges prior to after exist, to do so would require an additional query. Hence we follow the ā€œotherwiseā€, as per the specification, and always return false. I have previously discussed this with members of the relay team and the behaviour we have implemented is correct.

Unless I misunderstand the issue?

adamni21 commented 2 months ago

I kind of just ignored the "efficiently determine" part in the specification šŸ™ˆ

I would however argue, if the client selects hasPreviousPage, it should be okay with the associated perfomance penalty. Otherwise it shouldn't have selected hasPreviousPage in the first place. I mean, the with the current implementation, there is no need to select it for "first" queries, anyway. Because hasPreviousPage will always be false for these.

But if you disagree, we (the company I work at) really need it to work as described by these tests, but I guess it should be achievable via a plugin, or is it tied too closely to internal steps like PgSelect, etc.?

benjie commented 2 months ago

Are you sure you need it to work? Typically you can infer: ā€œif there is an after cursor, then there must be a previous pageā€, and when you then start paginating backwards hasPreviousPage will be honoured as required by the spec.

Iā€™m frustrated that they didnā€™t allow null in the case where you opt out due to performance, that would have been more sensible.

Yes you can override the plan for that field with a plugin, but implementing a check to see if there is a previous page is somewhat complex, which is one of the reasons we dropped it from V5.

adamni21 commented 2 months ago

Are you sure you need it to work? Typically you can infer: ā€œif there is an after cursor, then there must be a previous pageā€, and when you then start paginating backwards hasPreviousPage will be honoured as required by the spec.

Yeah, I thought of this alternative as well, I'll discuss it with my team. Thanks for the suggestion!

Iā€™m frustrated that they didnā€™t allow null in the case where you opt out due to performance, that would have been more sensible.

That would have made more sense, imho šŸ˜„

Would it make sense though, to add this to the list of breaking changes, in the v5 docs? Otherwise, I suppose, this ticket can be closed. Thanks again, for your help.

benjie commented 2 months ago

If itā€™s not already in there then yes that would be a good note to add, I think we did mention changes around nullability for it, so maybe near there? Use your judgement.

benjie commented 1 month ago

Documentation added in #2140