LoginSignup
1
0

More than 1 year has passed since last update.

Next.js + サーバーサイドTypeScript + 関数フレーバーでクリーンなアプリを作ったので実装意図とか書く Advent Calendar 2022
14日目株式会社mofmofに生息しているshwldです。

前日はGraphQLリゾルバのディレクトリの構造について書きました

RelayStyleページネーションをPrismaで実装する

GraphQLでページネーションを実装する際の選択肢の一つとしてRelay Styleにするというものがあります。
MetaのRelayというGraphQLクライアントが定めている仕様で、これに合わせることでRelay Styleに対応したクライアントでページネーションの実装が楽になるので、これを採用しました。

自前で実装するのは大変なのかなと思ったのですが、graphql-relayの中に便利メソッドが生えていたので、割と簡単に実装できました。

利用するメソッドは以下です。

import { connectionFromArraySlice, cursorToOffset } from 'graphql-relay';

connectionFromArraySliceは、スライスされた配列に開始位置と件数を渡すことで、仕様にあったconnectionを作ってくれます。簡単。
ちなみにconnectionFromArrayというメソッドもあり、こちらはスライスされる前の長い配列の中から開始位置、件数で該当の配列を切り出してconnectionを作ってくれるメソッドです。

今回はPrisma側で切り出し(カーソルいちから件数分の抽出)を行うため前者のconnectionFromArraySliceを使います。
といっても難しいことはなく、以下の流れでできます。

  1. 受け取ったカーソル(connectionのafter引数)をSQLのoffsetに変換する
  2. 受け取った件数(connectionのfirst引数)をSQLのtakeに変換する
  3. Prismaのaggregateで件数を取得する
  4. PrismaのfindManyoffset, takeを渡して結果を取得する
  5. 結果と取得件数を、connectionFromArraySliceでconnectionに変換する

書いてて気づきましたが、この記事で扱う内容では、firstとafter以外のargumentに対応してないです。

import { connectionFromArraySlice, cursorToOffset } from 'graphql-relay';
import type { ConnectionArguments } from 'graphql-relay';

args: ConnectionArguments

const take = args.first
const skip = cursorToOffset(args.after)
const accounts = await db.account.findMany({ skip, take })
const totalCount = await db.account.aggregate({ _count: true });

const relayConnection = connectionFromArraySlice(accounts, args, {
  sliceStart: skip,
  arrayLength: totalCount._count,
});

できました。

参考コード: /use-cases/graphql-resolvers/src/shared/helpers/connection-helpers.ts

次回予告

明日はTurborepo使ってみたについて書きます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0