id |
name |
1 |
Jane |
2 |
Max |
3 |
John |
4 |
Scott |
5 |
Mark |
result = User.after(3)
=>
[
{ id: 4, name: "Scott" },
{ id: 5, name: "Mark" }
]
result.has_more?
=> false
result.total_size
=> 2
result.total_count
=> 6
result = User.before(3)
=>
[
{ id: 2, name: "Max" },
{ id: 1, name: "Jane" }
]
result.has_more?
=> false
result.total_size
=> 2
result.total_count
=> 6
result = User.after(1).limit(1)
=>
[
{ id: 2, name: "Max" }
]
result.has_more?
=> true
result.total_size
=> 5
result.total_count
=> 6
result = User.after(1).before(3)
=>
[
{ id: 2, name: "Max" }
]
result.has_more?
=> false
result.total_size
=> 1
result.total_count
=> 6
@jerrygreen
It's not a bad implementation or nonsense. It served my use case just fine. Just because it doesn't fit yours doesn't make it bad. I did not intend for it to account for sorting on anything other than the primary key. This is how most cursor based apis work. It doesn't break your sorting, it intentionally removes it. You can't sort by arbitrary columns. The field you compare the cursor to has to be unique, sequential and immutable.
It's been several years since I posted this. I think the solution I would implement now is to generate an opaque token for the cursor that contains the necessary information. One cursor for the next page and one for the previous would be sent back to the client.
Making it opaque to the client means you can change the implementation server side, which is a win.
Slack has a decent write up on this: https://slack.engineering/evolving-api-pagination-at-slack-1c1f644f8e12