You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Prisma1迁移至Prisma2:保留Connection分页格式的方案咨询

Migrating Prisma 1's usersConnection Pagination to Prisma 2 (Keeping Legacy Schema Structure)

Great question—since Prisma 2 (now just "Prisma") doesn’t auto-generate the Relay-style connection structures that Prisma 1 did, you’ll need to manually replicate that schema shape in your GraphQL layer and wrap Prisma’s native pagination API to match the old structure. The good news is you don’t need to fully rebuild user objects, and there’s a clean, maintainable way to do this without breaking your frontend.

Step 1: Keep Your Legacy GraphQL Schema Intact

First, retain the exact type definitions your frontend depends on (add the missing PageInfo type if you haven’t already):

"""A connection to a list of items."""
type UserConnection {
  """Information to aid in pagination."""
  pageInfo: PageInfo!
  """A list of edges."""
  edges: [UserEdge]!
  aggregate: AggregateUser!
}

"""An edge in a connection."""
type UserEdge {
  """The item at the end of the edge."""
  node: User!
  """A cursor for use in pagination."""
  cursor: String!
}

type AggregateUser {
  count: Int!
}

"""Pagination metadata"""
type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

Step 2: Wrap Prisma’s Native Pagination in Resolvers

Prisma’s findMany supports both offset-based (skip/take) and cursor-based pagination out of the box. You’ll write resolver logic to translate the Relay-style connection arguments (first, last, after, before) into Prisma-compatible queries, then map the results back to your UserConnection structure.

Here’s a practical TypeScript example for the usersConnection resolver:

Helper Functions for Cursor Encoding/Decoding

Prisma 1 typically used base64-encoded IDs as cursors—match that behavior to keep frontend compatibility:

// Encode a user ID into a cursor string
const encodeCursor = (id: string): string => Buffer.from(id).toString('base64');

// Decode a cursor string back to a user ID
const decodeCursor = (cursor: string): string => Buffer.from(cursor, 'base64').toString('utf-8');

Main Resolver Logic

async function usersConnection(_, args, context) {
  const { first, last, after, before } = args;
  const prismaQuery = {};
  let hasNextPage = false;
  let hasPreviousPage = false;

  // Handle cursor-based pagination (after/before)
  if (after) {
    prismaQuery.cursor = { id: decodeCursor(after) };
    prismaQuery.skip = 1; // Skip the cursor itself
  }
  if (before) {
    prismaQuery.cursor = { id: decodeCursor(before) };
    prismaQuery.skip = 1;
    prismaQuery.take = -last; // Fetch items before the cursor (reverse order)
  }

  // Fetch one extra item to detect if there's a next/previous page
  if (first) {
    prismaQuery.take = first + 1;
  } else if (last) {
    prismaQuery.take = -last - 1;
  }

  // Fetch users from Prisma
  let users = await context.prisma.user.findMany(prismaQuery);

  // Adjust results to match connection rules
  if (first && users.length > first) {
    hasNextPage = true;
    users = users.slice(0, first); // Remove the extra item we fetched
  }
  if (last) {
    if (users.length > last) {
      hasPreviousPage = true;
      users = users.slice(1).reverse(); // Remove extra item and restore correct order
    } else {
      users = users.reverse();
    }
  }

  // Build edges and page info
  const edges = users.map(user => ({
    node: user, // Use Prisma's user object directly—no need to rebuild!
    cursor: encodeCursor(user.id)
  }));
  const pageInfo = {
    hasNextPage,
    hasPreviousPage,
    startCursor: edges[0]?.cursor || null,
    endCursor: edges[edges.length - 1]?.cursor || null
  };

  // Get aggregate count
  const aggregate = { count: await context.prisma.user.count() };

  return { pageInfo, edges, aggregate };
}

Do You Need to Rebuild User Objects?

Nope! Prisma returns fully populated User objects that you can directly use as the node field in UserEdge. The only extra work is adding the cursor field (which is just the user’s ID encoded as base64).

Optimal Improvements

  • Create a generic connection helper: If you have other models that need connection-style pagination, extract the core logic into a reusable function (e.g., createConnectionResolver(model, args)).
  • Add input validation: Ensure conflicting arguments (like first and last used together) are handled gracefully to avoid errors.
  • Reuse Prisma’s cursor support: Prisma supports cursor pagination on any unique field, so if you used something other than id for cursors in Prisma 1, adjust the cursor logic to match that field.

内容的提问来源于stack exchange,提问作者Alan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 20:32:46