使用 Prisma 生成的包装器查询节点时包含关系



我遵循Prisma提供的GraphQL Prisma Typescript示例,并创建了一个简单的数据模型,为Prisma客户端和解析器等生成了代码。

我的数据模型包括以下节点:

type User {
id: ID! @unique
displayName: String!
}
type SystemUserLogin {
id: ID! @unique
username: String! @unique
passwordEnvironmentVariable: String!
user: User!
}

我已经播种了一个系统用户和用户。

mutation {
systemUserLogin: createSystemUserLogin({
data: {
username: "SYSTEM",
passwordEnvironmentVariable: "SYSTEM_PASSWORD",
user: {
create: {
displayName: "System User"
}
}
}
})
}

我创建了一个示例突变login

login: async (_parent, { username, password }, ctx) => {
let user
const systemUser = await ctx.db.systemUserLogin({ username })
const valid = systemUser && systemUser.passwordEnvironmentVariable && process.env[systemUser.passwordEnvironmentVariable] &&(process.env[systemUser.passwordEnvironmentVariable] === password)
if (valid) {
user = systemUser.user // this is always undefined!
}
if (!valid || !user) {
throw new Error('Invalid Credentials')
}
const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET)
return {
token,
user: ctx.db.user({ id: user.id }),
}
},

但无论我做什么,systemUser.user总是不确定的!

这是有道理的 - 客户端包装器如何在没有我告诉的情况下知道递归到图形中的"深度"?

但是我怎么能告诉它我想包括User关系呢?

编辑:我尝试了下面的建议来使用prisma-client

但是我的解析器似乎都没有被召唤过......

export const SystemUserLogin: SystemUserLoginResolvers.Type<TypeMap> = {
id: parent => parent.id,
user: (parent, args, ctx: any) => {
console.log('resolving')
return ctx.db.systemUserLogin({id: parent.id}).user()
},
environmentVariable: parent => parent.environmentVariable,
systemUsername: parent => parent.systemUsername,
createdAt: parent => parent.createdAt,
updatedAt: parent => parent.updatedAt
};

和。。。

let identity: UserParent;
const systemUserLogins = await context.db.systemUserLogins({
where: {
systemUsername: user,
}
});
const systemUserLogin = (systemUserLogins) ? systemUserLogins[0] : null ;
if (systemUserLogin && systemUserLogin.environmentVariable && process.env[systemUserLogin.environmentVariable] && process.env[systemUserLogin.environmentVariable] === password) {
console.log('should login!')
identity = systemUserLogin.user; // still null
}

编辑2:这是存储库

https://github.com/jshin47/annotorious/tree/master/server

目前有两种方法可以解决此问题:

  • 像OP目前一样使用Prisma客户端
  • 按照@User97在接受的答案中的建议使用Prisma 绑定

您可以在此论坛帖子中了解有关 Prisma 客户端和 Prisma 绑定之间区别的更多信息。

由于OP目前正在使用Prisma客户端,因此我也将用它来回答!

我们来看看OP在问题中的一句话:

这是有道理的 - 客户端包装器如何在没有我告诉的情况下知道递归到图形中的"深度"?

OP 正确地指出,Prisma 客户端无法知道如何深入进入图形以及获取哪些关系。事实上,除非另有明确说明(例如使用$fragmentAPI(,否则客户端永远不会获取任何关系,并且始终只获取标量值。来自Prisma文档:

每当使用 Prisma 客户端查询模型时,都会获取该模型的所有标量字段。无论查询单个对象还是对象列表,都是如此。

那么,如何妥善解决这种情况呢?事实上,解决方案不是改变 Prisma 客户端的使用方式,而是实现一个额外的 GraphQL 解析器函数!

关于解析器的要点是,它们正在获取架构中特定字段的数据。在 OP 的情况下,目前没有解析器可以"解析"在SystemUserLogin类型上定义的user关系:

type SystemUserLogin {
id: ID! @unique
username: String! @unique
passwordEnvironmentVariable: String!
user: User! # GraphQL doesn't know how to resolve this
}

要解决这种情况,您需要为其实现一个专用的"类型解析器",如下所示:

const resolvers = {
SystemUserLogin: {
user(parent, args, ctx) {
return ctx.db.systemUserLogin({id: parent.id}).user()
}
} 
}

完全披露:我在Prisma工作,我们正在努力为该用例添加更好的文档和资源。另请查看此示例,其中出于相同原因需要authorposts关系字段的显式解析程序。

希望对您有所帮助!

编辑:我们还在Prisma教程中添加了一个关于常见解析器模式的更全面的解释。

prisma 绑定函数的第二个参数接受 GraphQL 查询字符串。将以下行从

const systemUser = await ctx.db.query.systemUserLogin({ username })

const systemUser = await ctx.db.query.systemUserLogin({ username }, `{id username user {id displayName}}`)

会给你用户的数据。

Prisma 绑定将仅返回模型的直接属性,以防第二个参数未传递给它。

最新更新