-
Notifications
You must be signed in to change notification settings - Fork 15
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: add eloquent cursor pagination implementation #37
feat: add eloquent cursor pagination implementation #37
Conversation
Thanks for this! I'm going to need a bit of time to look through it, which I don't have tonight. But I will hopefully get to it soon. |
No rush, will investigate that failing test... 🤔 |
fixed, didn't realise the Video models uuids were v4's (random) and therefore would not provide a deterministic sort. this is probably something to callout in the docs for this if/when merged. It does assume your model's keys are sequential/monotonic, such as an autoincrement or ordered uuid (v7). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@haddowg sorry for taking a bit of time to look at this, but finally been through it.
This is an excellent bit of work - thank you so much! I'm sure there's lots of people who are going to use this, and we can recommend it as the approach for cursor pagination going forward.
There's a number of tidying up things, which I was going to do myself rather than expecting you to do - but unfortunately I couldn't push to your fork. I'll do them after merging this PR into develop
instead.
My only main comment is just to check we've got all the correct tests in there. We seem to be covering a lot, but I wanted to check we haven't missed anything. Did you base your tests on the test file that's in the cursor pagination package? I.e. this one: https://github.com/laravel-json-api/cursor-pagination/blob/develop/tests/lib/Acceptance/Test.php
The ones that I think are missing are as follows:
We need to test the ID encoding. We need to check that if you base64_decode
the value that the Eloquent cursor implementation gives you, the ID contained within it is the JSON:API encoded value. That's because any client could decode it, and the point of the JSON:API ID encoding is not to expose the database value. Are you able to add a test for both the before and after encoding? In the test file linked above, it's testAfterWithIdEncoding()
and testBeforeWithIdEncoding
. You can bring in the EncodedId
class from that package for the test.
The other thing that I think we need to have a test for is what happens if either the before or after IDs sent by the client do not exist. In the existing cursor pagination package, it throws an exception as it expects you to have validated the query parameters. We should have tests for this scenario. If the Eloquent cursor handles it differently, i.e. if it would work in this scenario, then we should align to what the Eloquent cursor does. But I'd still like to know exactly what happens in this scenario, which is why it would be good to have testAfterDoesNotExist()
and testBeforeDoesNotExist()
so that we're 100% sure what it does.
Hope that all makes sense? Do let me know if there's anything that doesn't make sense!
That all makes sense, the id encoding definitely works as I am using it for binary uuids but should indeed be tested. Re fork/pr permission it seems GitHub treats forks in an organisation differently.. next time I will fork to my personal account. |
… within a cursor test: test cursor id encoding/decoding
This behavior is fixed and tested, I was in-fact only decoding from the cursor and not encoding when creating, this worked in my own use case since my binary uuids were already encoded (string cast) by the model itself, so they only needed decoding back to binary for the query, so great catch 👍.
This one I am not sure how best to approach, since there may in fact be no ids in the cursor at all depending on your sort and if you used the Let me know what you think. |
Thanks! Have some allocated Laravel JSON:API time this evening (UK time) so will look into this and get back to you. Hoping I can merge this PR and tag but will look into the issue you've raised first. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Thanks so much for the extra changes. I'm going to merge this into develop
now so I can tidy up some things before releasing. If I find anything that's more than tidying up, I'll create a separate PR and ask for your review of it.
Cursor Pagination
Adds a Cursor Pagination implementation that uses eloquent's
cursorPaginate
under the hood but maintains the contract from the existingcursor-pagination
package implementation meaning it should act as a drop-in replacement in most cases.Changes to existing CursorPagination API:
Features
withTotal
andwithTotalOnFirstPage
method, this will add atotal
to the page meta that is a count of the total results, the former will do this on any paginated query (with or without a cursor), whereas the later will only do this additional query on thefirst page
i.e. when paginating but with nobefore
orafter
cursor provided.Breaking
withCursorColumn
method, this is no longer necessary as you can sort by any arbitrary column(s).withoutKeySort
.The
withAscending
method will now only affect this default key sort. I.e you can reverse the default applied key sort, but if its disabled withwithoutKeySort
this will do nothing.If you relied specifically on the default created_at sorting applied when not providing a
withCursorColumn
(with a non sequential monotonic key column, such that the order would actually change) then you will need to explicitly add this as a sort either as a default or via a global scope etc.Notes