跳到主要內容

在 JavaScript 中使用 GraphQL 解析器的自動完成

問題

當您將 GraphQL 與 TypeScript 搭配使用時,您始終可以在 GraphQL 解析器中獲得 Prisma Client 實例的自動完成功能,因為這樣一來,context 物件就可以被輸入類型 – 無論人們是先使用 Nexus、TypeGraphQL 還是 SDL。這對於自動完成和防止不必要的錯誤非常有幫助。

不幸的是,當您在純 JavaScript 中工作時,這需要多費一些力氣。假設我們有如下的解析器

filterPosts: (parent, args, ctx) => {
return ctx.prisma.post.findMany({
where: {
OR: [
{ title: { contains: args.searchString } },
{ content: { contains: args.searchString } },
],
},
})
}

現在,每當您輸入 ctx. 時,VS Code 將在自動完成中提供不必要的選項,這是不可取的。

Unwanted autocomplete values by VSCode

VS Code 不知道 context 物件的類型,因此它無法為其提供任何 intellisense,這就是為什麼會顯示不必要的建議。

解決方案

為了克服這個問題,您需要新增一個名為 typedefJSDoc 註解,以「匯入」PrismaClient 實例的正確類型。

// Add this to the top of the file

/**
* @typedef { import("@prisma/client").PrismaClient } Prisma
*/

注意:您可以在此處了解更多關於 JSDoc 的資訊。

最後,您需要為解析器引數輸入類型。為了簡化,請忽略 parentargs 參數。因此,解析器現在應該看起來像這樣

/**
* @param {any} parent
* @param {{ searchString: string }} args
* @param {{ prisma: Prisma }} ctx
*/
filterPosts: (parent, args, ctx) => {
return ctx.prisma.post.findMany({
where: {
OR: [
{ title: { contains: args.searchString } },
{ content: { contains: args.searchString } },
],
},
})
}

這將告訴 VS Code,context 具有一個名為 prisma 的屬性,且類型為 Prisma,這是在上面的 @typedef 中定義的。

瞧!純 JavaScript 中的自動完成功能。

The correct parameters for context are obtained

最終檔案應該看起來像這樣

/**
* @typedef { import("@prisma/client").PrismaClient } Prisma
* @typedef { import("@prisma/client").UserCreateArgs } UserCreateArgs
*/

const { makeExecutableSchema } = require('graphql-tools')

const typeDefs = `
type User {
email: String!
id: ID!
name: String
posts: [Post!]!
}

type Post {
author: User
content: String
id: ID!
published: Boolean!
title: String!
}


type Query {
feed: [Post!]!
filterPosts(searchString: String): [Post!]!
post(where: PostWhereUniqueInput!): Post
}

type Mutation {
createDraft(authorEmail: String, content: String, title: String!): Post!
deleteOnePost(where: PostWhereUniqueInput!): Post
publish(id: ID): Post
signupUser(data: UserCreateInput!): User!
}

input PostWhereUniqueInput {
id: ID
}

input UserCreateInput {
email: String!
id: ID
name: String
posts: PostCreateManyWithoutPostsInput
}

input PostCreateManyWithoutPostsInput {
connect: [PostWhereUniqueInput!]
create: [PostCreateWithoutAuthorInput!]
}

input PostCreateWithoutAuthorInput {
content: String
id: ID
published: Boolean
title: String!
}
`

const resolvers = {
Query: {
/**
* @param {any} parent
* @param {any} args
* @param {{ prisma: Prisma }} ctx
*/
feed: (parent, args, ctx) => {
return ctx.prisma.post.findMany({
where: { published: true },
})
},
/**
* @param {any} parent
* @param {{ searchString: string }} args
* @param {{ prisma: Prisma }} ctx
*/
filterPosts: (parent, args, ctx) => {
return ctx.prisma.post.findMany({
where: {
OR: [
{ title: { contains: args.searchString } },
{ content: { contains: args.searchString } },
],
},
})
},
/**
* @param {any} parent
* @param {{ where: { id: string }}} args
* @param {{ prisma: Prisma }} ctx
*/
post: (parent, args, ctx) => {
return ctx.prisma.post.findUnique({
where: { id: Number(args.where.id) },
})
},
},
Mutation: {
/**
* @param {any} parent
* @param {{ title: string, content: string, authorEmail: (string|undefined) }} args
* @param {{ prisma: Prisma }} ctx
*/
createDraft: (parent, args, ctx) => {
return ctx.prisma.post.create({
data: {
title: args.title,
content: args.content,
published: false,
author: args.authorEmail && {
connect: { email: args.authorEmail },
},
},
})
},
/**
* @param {any} parent
* @param {{ where: { id: string }}} args
* @param {{ prisma: Prisma }} ctx
*/
deleteOnePost: (parent, args, ctx) => {
return ctx.prisma.post.delete({
where: { id: Number(args.where.id) },
})
},
/**
* @param {any} parent
* @param {{ id: string }} args
* @param {{ prisma: Prisma }} ctx
*/
publish: (parent, args, ctx) => {
return ctx.prisma.post.update({
where: { id: Number(args.id) },
data: { published: true },
})
},
/**
* @param {any} parent
* @param {UserCreateArgs} args
* @param {{ prisma: Prisma }} ctx
*/
signupUser: (parent, args, ctx) => {
return ctx.prisma.user.create(args)
},
},
User: {
/**
* @param {{ id: number }} parent
* @param {any} args
* @param {{ prisma: Prisma }} ctx
*/
posts: (parent, args, ctx) => {
return ctx.prisma.user
.findUnique({
where: { id: parent.id },
})
.posts()
},
},
Post: {
/**
* @param {{ id: number }} parent
* @param {any} args
* @param {{ prisma: Prisma }} ctx
*/
author: (parent, args, ctx) => {
return ctx.prisma.post
.findUnique({
where: { id: parent.id },
})
.author()
},
},
}

const schema = makeExecutableSchema({
resolvers,
typeDefs,
})

module.exports = {
schema,
}