【TypeScript】【Prisma】Cursor-Based Paginationを触ってみる。
はじめに
cusrorを使ったページネーションは、ページネーションの一種で、データベースのクエリ結果やAPIのレスポンスにおいて、特定の位置を指定して結果を取得する方法です。
TypeScript向けのオープンソースのORM(Object Relational Mapping)ライブラリであるPrismaのドキュメントにはoffsetを使ったページネーションとcursorを使ったページネーションが紹介されています。
今回はcursorを使ったページネーションの書き方や、実行されるSQLのクエリを確認します
成果物
https://github.com/kntks/blog-code/tree/main/2023/03/prisma-cursor-based-pagination
バージョン
バージョン | |
---|---|
node | 18.13.0 |
npm | 8.19.3 |
prisma | 4.11.0 |
mysql | 8.0.32 |
準備
テーブルの定義
データを作成する
データを20個作成しました。
データを取得する
1ページ目の取得
1ページ目となる先頭5つのデータを取得します。
実行されたクエリは以下の通りです。
sqlformatterを使って整形しています。
次のページを取得する
Cursor-based pagination - Prisma docsは、cursorにIDやタイムスタンプのようなユニークで連続したカラムを使う必要がある、と言っています。今回の場合、IDをauto incrementにしていているため、cursorはIDで良さそうです。
次のページを取得したい場合は、1ページ目にあった最後のIDをcursorとして使用します。
どうやらcursorを設定すると、サブクエリを実行していることがわかります。
sqlformatterを使って整形しています。
前のページを取得する
現在3ページ目にいると仮定します。前のページのデータ(id: 5 ~ 10)はどうやって取得したら良いでしょうか?
Prismaのドキュメントに書いてありました。取得するサイズ ( take)の値をマイナスにすれば、前のページのデータを取得できそうです。
やってみます。cursorは3ページ目先頭のid: 11です。
無事に2ページ目と同じデータを取得することができました。
SQLだと以下のようなクエリが実行されおり、次のページに進んでいた場合と違う箇所はORDERがASC
からDESC
にかわっています。
つまり並び順を昇順から降順にして、takeで指定した数だけ取得しているということですね。
sqlformatterを使って整形しています。
図で表現すると以下のようなイメージです。
Previous Page Token for Cursor Paginationにも同じテクニックが書いてありました。
まとめ
prismaでcusor baseのページネーションをするとき以下のことがわかりました
- 次のページに進みたいときはcursorに値を設定し、takeとskipを設定する。
- 前のページに戻りたいときはcursorに値を設定し、takeをマイナスにして設定する。
今回使用したコードは blog-code/prisma-cursor-based-pagination - GitHubにあります。