olavim / objection-cursor

Cursor based pagination plugin for Objection.js
MIT License
30 stars 8 forks source link

Begin pagination from a specific item? #24

Closed Smtih closed 4 years ago

Smtih commented 4 years ago

I've got a question whether it is possible with this library to create a paginated list starting from a specific item. My use case is, a user does a search through chat messages. when they select a chat message, I then want to navigate to the chat at that specific message, allowing the user to paginate backwards or forwards.

From my understanding of cursor based pagination I think this should be possible, but I was wondering if there's a straightforward way to do it.

My current approach that I plan to try is something like this.

const result = await Messages.query().where("id", <id>).orderBy("postDate").paginate();
const list = await Messages.query().where("chatId", <chatId>).orderBy("postDate").paginate(result.pageInfo.next);
return {
   pageInfo: {
      ...list.pageInfo,
      previous: result.pageInfo.previous },
   results: [result.results[0], ...list.results] };

I'll report back if this even works, but if there's a smarter way to do this would love to hear.

olavim commented 4 years ago

If you give the mixin the nodes: true option, query response will give you nodes that each contain a cursor. You can then use that cursor to get results before or after the node.

See quick start in the README for an example.

Smtih commented 4 years ago

The issue is the cursor is based by the orderBy fields.

Search is ordered by relevance to the search term so the cursor wouldn't make sense when used in a list ordered by date?

Perhaps this assumption is wrong?

olavim commented 4 years ago

Ok, in that case your current approach looks to be on the right track. Indeed, the cursor is based on the orderBy fields, so you can do some tricks with where statements to do what you want. If your chat messages have unique ids, then you can do the following:

  1. User finds a specific message with your search functionality.
  2. Get a cursor for the message by searching by its id and order by post date:
    const message = await Messages.query()
    .where('id', /*messageId*/)
    .where('chatId', /*chatId*/)
    .orderBy('postDate'); // orderBy statement needed for cursor
  3. Get messages after this message in a given chat. We accomplish this by changing the where statement to our liking, but the orderBy statements must be the same:
    const list = await Messages.query()
    .where('chatId', /*chatId*/)
    .orderBy('postDate')
    .nextCursorPage(message.pageInfo.next);
Smtih commented 4 years ago

Great, thanks for the info, will let you know how this approach goes.