ash
ash copied to clipboard
Analog for more? field for Keyset pagination, but for backward direction
Is your feature request related to a problem? Please describe.
GraphQL Relay specification has 2 fields to describe cursor position: hasNextPage and hasPreviousPage. First returns true if there is a next page, second returns true if there is a previous page.
Ash.Page.Keyset have implementation only for the first field (it is called more?), but not for the second one.
Describe the solution you'd like
Add another field to Keyset record which will behave in a similar way with more?, but for the backward paginagion direction.
Describe alternatives you've considered
%Ash.Page.Keyset{count: count, after: after_cursor, before: before_cursor} = page
has_previous_page = count > 0 and (not is_nil(after_cursor) or not is_nil(before_cursor))
But it is possible that it's working only because of some issue (like #333), or can break on the some set of conditions
Express the feature either with a change to resource syntax, or with a change to the resource interface
For example
%Ash.Page.Keyset{more?: more?, prev?: prev?}
Additional context Discussion of https://github.com/ash-project/ash_graphql/pull/36
Actually, I think you are correct. Given that after and before doesn't include the record itself, your method of determining has_previous_page is correct. We can just add that into the Keyset struct.
count > 0 is not necessarily enough though, because count is not always selected.
However, it will only be "wrong" in the very rare case that the thing you are asking for has been removed i.e after: 1 when 1 has been deleted and you aren't selecting the count.
with #255 issue resolved actually we can detect this case, because we will look up the record before doing the rest of the request. If it isn't there then we'll know and be able to say that there isn't a previous page.
Alright, so my plan is to fix this after #255 and to make "fetch" style (where we look up the record by its primary key keyset and load any relevant aggregates/calculations) the only method.
Alright, I think perhaps this is all that is left to get https://github.com/ash-project/ash_graphql/pull/36 going?
Actually, I didn't get how prev? could be implemented with a https://github.com/ash-project/ash/commit/64b3312cb94869d3ef9b25a11658e056c7191380
🤔 I've just realized two things.
-
64b3312 falls apart when there is no record with the provided primary key. I'm not sure if that is a kryptonite for that solution or not. What we would have to do in that case is restart the pagination, which sounds like a pretty bad experience. Another flaw with that solution is that if you are sorting on something and that value changes, then you'd jump around in the page. I think that means that the "fetch" style of keyset pagination actually is unacceptable, and that we instead need to go back to the old way. I have an idea for how we can support "complex" fields the old way. I'll undo the previous commit and go back to the previous way.
-
As for
prev?I think you may be right. I think there is no way to determine if there is a previous page without running a second query.
i.e flip before and after and say limit: 1. We can do that only on request via a pagination option, i.e page: [populate_prev_page?: true], and then the graphql extension can do that only when that information is requested.
I think for now, the relay specification required for ash_graphql allows for us to just say false when showing hasNextPage combined with before and hasPrevPage when combined with after, meaning we actually have all that we need (for now).