网站搜索

reactjs - 在 Next.js 应用中分解复杂的 Prisma 查询


我有一个 Next.JS 应用。我想在首页渲染一个待办事项 feed,也想在用户页面上渲染。我有点不确定如何拆分我的 Prisma 查询。

我使用 getServerSideProps 获取一个大的数据对象并将其传递给页面组件(并使用 react-query 进行水合和重新获取,但现在不相关)- getRecentTodos(包括 todos)用于我的主页 - getUserDetailsByName(包括 todos)用于用户页面

export type getRecentTodos = ReturnType<typeof getRecentTodos> extends Promise<
  infer T
>
  ? T
  : never
export const getRecentTodos = async (recentItemsAmount = 20) => {
  return await prisma.todos.findMany({
    where: { done: true },
    select: {
      id: true,
      userId: true,
      content: true,
      done: true,
      createdAt: true,
      attachments: true,
      todoReplies: {
        select: {
          id: true,
          userId: true,
          content: true,
          todoReplyLikes: true,
          todoId: true,
          user: { select: { name: true, displayName: true, image: true } },
        },
        orderBy: { createdAt: 'asc' },
      },
      todoLikes: {
        select: {
          user: true,
        },
      },
      user: {
        select: {
          name: true,
          displayName: true,
          image: true,
        },
      },
    },
    orderBy: { createdAt: 'desc' },
    take: recentItemsAmount,
  })
}
export const getUserDetailsByName = async (username: string) => {
  return await prisma.user.findUnique({
    where: {
      name: username,
    },
    select: {
      name: true,
      displayName: true,
      bio: true,
      location: true,
      twitter: true,
      image: true,
      createdAt: true,
      todos: {
        select: {
          id: true,
          content: true,
          userId: true,
          done: true,
          updatedAt: true,
          createdAt: true,
          attachments: true,
          user: true,
          todoLikes: true,
          todoReplies: {
            take: 30,
            orderBy: { createdAt: 'desc' },
            select: {
              id: true,
              userId: true,
              todoId: true,
              createdAt: true,
              content: true,
              user: true,
            },
          },
        },
        take: 30,
        orderBy: { createdAt: 'desc' },
      },
      projects: true,
    },
  })
}

两个查询都会返回“todos”,但它们的返回方式可能略有不同。todo feed 组件期望某些属性是可用的——例如 todoReplies 上的 displayName——但是在 getUserDetailsByName 中,displayName 可能不包含在响应中,或者它嵌套在更深的一层,等等

  • 如何防止这件事很快变得复杂?

    • 你或多或少想在查询中以相同的方式选择待办事项(返回相同的内容并省略相同的内容,除了某些事情比如顺序)
    • 但是在大量查询中手动保持这些内容同步会很快变得复杂

可能的解决方案?

  • 我应该把 getServerSideProps 拆分成多个获取操作吗?

    • 所以不是一个包含 todos 作为关联字段的 'getUserDetailsByName'

      • 获取用户详情
      • 所以不是一个包含 todos 作为关联字段的 ‘getUserDetailsByName’
      • 获取用户详细信息

      • 获取待办事项
    • 这意味着我还必须编写更多的 react-query 代码来进行重新获取等操作……因为你在处理多个对象。但它确实更好地分离了关注点。
  • 在我的代码库中使用 TypeScript 来捕获当一个函数尝试访问某个特定 Prisma 查询未返回的属性时的情况?(我现在才开始看到 TypeScript 在这类事情上的可能性)

  • 我是否应该通过一个函数来标准化在 Prisma 查询中创建待办事项的方式,并在 Prisma 查询中包含该函数?你可以包含类似如下的内容:

const todoSelect = {
  id: true,
  userId: true,
  content: true,
  {.......}
  user: {
    select: {
      name: true,
      displayName: true,
      image: true,
    },
  },
}

export type getRecentTodos = ReturnType<typeof getRecentTodos> extends Promise<
  infer T
>
  ? T
  : never
export const getRecentTodos = async (recentItemsAmount = 20) => {
  return await prisma.todos.findMany({
    where: { done: true },
    select: todoSelect,
    orderBy: { createdAt: 'desc' },
    take: recentItemsAmount,
  })
}

const userSelect = {
  name: true,
    {......}
  todos: {
    select: todoSelect,
    take: 30,
    orderBy: { createdAt: 'desc' },
  },
  projects: true,
}

export const getUserDetailsByName = async (username: string) => {
  return await prisma.user.findUnique({
    where: {
      name: username,
    },
    select: userSelect,
  })
}