我正在遵循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
}
答案 0 :(得分:3)
目前有两种方法可以解决此问题:
您可以在this论坛帖子中详细了解Prisma客户端和Prisma绑定之间的区别。
由于OP当前正在使用Prisma客户端,因此我也将其用于此答案!
我们来看看问题中的陈述OP:
这很有意义-客户端包装程序如何在不通知我的情况下知道如何“深入”到图中?
OP正确地指出,Prisma客户端不知道如何深入该图以及要获取什么关系。实际上,除非明确地另行告知(例如,使用$fragment
API),否则客户端将永远不会获取任何关系,而只会获取标量值。来自Prisma docs:
每当使用Prisma客户端查询模型时,都会获取该模型的所有标量字段。无论查询单个对象还是对象列表,都是如此。
那么,如何正确解决这种情况?实际上,解决方案不是 来更改Prisma客户端的使用方式,而是实现其他GraphQL解析器功能!
关于解析程序的要点是,它们正在获取架构中特定于 字段的数据。在OP的情况下,当前没有解析器可以“解析”在user
类型上定义的SystemUserLogin
关系:
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工作,我们正在努力为该用例添加更好的文档和资源。还要查看this示例,出于相同原因,其中需要author
和posts
关系字段的显式解析器。
希望有帮助!
编辑:我们还在Prisma教程中添加了关于Common resolver patterns的更为详尽的解释。
答案 1 :(得分:1)
prisma绑定函数的第二个参数接受GraphQL查询字符串。更改以下行
const systemUser = await ctx.db.query.systemUserLogin({ username })
到
const systemUser = await ctx.db.query.systemUserLogin({ username }, `{id username user {id displayName}}`)
将为您提供用户数据。
如果未将第二个参数传递给模型,Prisma绑定将仅返回模型的直接属性。