Apollo 和 Prisma Graphql 显式模型关系不可查询

Apollo and Prisma Graphql explicit model relationship not queryable

我已经开始为新应用程序测试 prisma 2 和 graphql。我正在 运行 遇到一个关于能够查询关系的明确的多对多 table 问题。

这是我的 apollo 模式:

scalar DateTime

type Query {
    user(id: String!): User
    users: [User]
    spaces: [Space]
    roles: [Role]
}

type Mutation {
    createUser(id: String!, email: String!): User!
    createSpace(name: String!): Space!
}

type User {
    id: ID!
    email: String!
    spaces: [UserSpace!]
    createdAt: DateTime!
    updatedAt: DateTime!
}

type Space {
    id: ID!
    name: String!
    users: [UserSpace!]
    createdAt: DateTime!
    updatedAt: DateTime!
}

type Role {
    id: ID!
    name: String!
    description: String!
    users: UserSpace
    createdAt: DateTime!
    updatedAt: DateTime!
}

type UserSpace {
    id: ID!
    user: User!
    space: Space!
    role: Role!
    createdAt: DateTime!
    updatedAt: DateTime!
}

这是我的棱镜模式:

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// npx prisma migrate dev
// npx prisma generate

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id String @id
  email String @unique
  spaces UserSpace[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Space {
  id Int @default(autoincrement()) @id
  name String @unique
  users UserSpace[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Role {
  id Int @default(autoincrement()) @id
  name String @unique
  description String
  users UserSpace[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model UserSpace {
  id Int @default(autoincrement()) @id
  user User @relation(fields: [userId], references: [id])
  userId String
  space Space @relation(fields: [spaceId], references: [id])
  spaceId Int
  role Role @relation(fields: [roleId], references: [id])
  roleId Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

这是我的突变解析器:

const { prisma } = require(".prisma/client");

async function createUser(parent, args, context, info) {
    return await context.prisma.user.create({
        data: {
            ...args,
        },
    });
}

async function createSpace(parent, args, context, info) {
    const isAuthenticated = context.authentication.isAuthenticated;
    let role = null;

    if(!isAuthenticated) {
        throw new Error("Not Authenticated");
    }

    try {
        role = await context.prisma.role.findUnique({
            where: {
                name: "Space Administrator",
            },
        });
    }
    catch(err) {
        throw new Error(err);
    }

    return await context.prisma.space.create({
        data: {
            ...args,
            users: {
                create: {
                    role: { 
                        connect: { id: role.id },
                    },
                    user: {
                        connect: { id: context.authentication.auth0Id },
                    },
                },
            },
        },
    });
}

module.exports = {
    createUser,
    createSpace,
}

这是我的用户解析器(我知道这是问题所在,但我不知道如何解决):

function spaces(parent, args, context, info) {
    return context.prisma.user.findUnique({ where: { id: parent.id } }).spaces();
}

module.exports = {
    spaces,
}

基本上,当我创建 space 时,用户会作为 Space 管理员添加到 space,然后应该可以使用以下内容进行查询:

query {
  users {
    id
    email
    spaces {
      id
      role {
        name
      }
      space {
        name
      }
    }
    createdAt
  }
}

然而,当我 运行 查询时,出现以下错误:

"message": "Cannot return null for non-nullable field UserSpace.role.",

在 prisma 2 中,我如何使用户的解析器使用显式多对多 table 以及其中的第三个关系如何?我是 prisma 和 graphql 的新手,所以如果还有其他突出的东西,我也想得到输入。

您是否将值提供给用户 arg?像这样:users(id: "string_value")。因为是 id 是必需的。

我使用 type 一词来指代 GraphQL 模式中的对象模型,model 指代 Prisma 模式中的数据模型。

问题

我看到你有一个 User 类型的解析器,它有一个解析器函数用于你的 User 类型中的 User.spaces 字段。您在 User.spaces 解析器中定义的查询将 return 来自数据库的相关 userSpace 记录。

但是,这些 userSpace 记录在默认情况下不会解析 role 字段,因为它是一个关系字段。这就是 prisma 的工作原理(除非明确说明,否则默认情况下不解析关系字段)。

解决方案

UserSpace 类型创建一个解析器,并明确定义 UserSpace.role 字段的解析器函数。这就是它的样子

// UserSpace resolver module

function role(parent, args, context, info) {
    return context.prisma.userSpace.findUnique({ where: { id: parent.id } }).role();
}

module.exports = {
    role,
}

虽然还有一些其他方法可以解决这个问题,但推荐使用我展示的方法(以及特定语法),因为在底层它允许 prisma 对 solve the n+1 query problem 执行某些优化。但是,如果您不知道那是什么,您也不必担心。