How to implement GraphQL Relay style cursor based pagination in postgres (with sqlalchemy and fastAPI)

700 views Asked by At

I am trying to implement Relay-Style pagination on a postgres. I have gone through the relay specification, and it recommends having a globally unique cursor for each entity. The specification for pagination is that the client provides first and after for Forward pagination and last and before for Backward pagination.

Assume I have a table called Products, with an auto incrementing primary key integer ID. In the most basic case, pagination is very straight forward. For forward pagination it would be something like SELECT * FROM products WHERE id > cursor LIMIT 10 for forward pagination, and SELECT * FROM products WHERE id < cursor ORDER BY id DESC LIMIT 10

The problem arises when we have additional sorting requirements. Let us say, our product table has a name field on which we want to sort.

Name    Id (cursor field)
Trendy  1
Autumn  2
Winter  3
Crazy   4
Antman  5
Marvel  6

And we want to paginate, with page size of 3, sorted on name ASC. The query would be:

SELECT * FROM products ORDER BY name ASC LIMIT 3, And we would get the following output:

(Antman, 5), (Autumn 1), (Crazy 4)

But now, how will I get the next three? This query SELECT * FROM products WHERE id >= 4 ORDER BY name ASC LIMIT 3; would not work, as Trendy has ID < 1. Do I create a different cursor for Name and use that for paginating with Name? Okay, what if we wanted to sort on multiple fields together (let us say we have a price field, we want to sort from decreasing to increasing price, and then sort based on created time, and then on name. The price might not be unique and any other additional constraints), how would I create a cursor then?

What is the standard approach to solve this problem? I have tried to research as much as I can but I couldn't find any information on how to accomplish this in fastapi and sqlalchemy. Django has FilterableConnectionField, but I couldn't understand the implementation. Any help is very appreciated, thank you.

edit: I figured out how to do this. It is called queryset pagination, and sqlakeyset repo on github had a good implementation of this pattern. https://github.com/djrobstep/sqlakeyset

0

There are 0 answers