在 Apollo Server 中的解析器和突变之间共享逻辑
Share logic between resolvers and mutations in Apollo Server
这是我的解析器文件:
import { gql } from 'apollo-server-express'
import * as db from '../database'
export const typeDefs = gql`
extend type Query {
getFoos(): Foo
}
type Foo {
id: ID!
missingBar: [String]
}
input addBarInput {
fooId: ID!
barId: ID!
}
extend type Mutation {
addBar(input: addBarInput): Foo
startFoo(fooId: ID!): Foo
}
`
export const resolvers = {
Query: {
getFoos: async () => db.foo.findAll({include: [db.bar]}),
},
Foo: {
missingBar: async (obj, args, context, info) => {
// here starts the relevant part of code
const someBarIds = await db.some_table.findAll({
where: {bar_id: obj.bar_id},
}).map(el => el.bar_id)
const otherBarIds = await db.other_table.findAll({
where: {id: obj.bars.map(b => b.id)},
}).map(el => el.id)
const missingBarIds = someBarIds.filter(x => !otherBarIds.includes(x));
// here ends the relevant part of code
return await db.instruments.findAll({where: {id: missingInstrumentsIds}}).map(instrument => instrument.name)
},
},
Mutation: {
addBar: async (prev, { input }) => {
const foo = await db.foo.findByPk(input.fooId)
const bar = await db.users.findByPk(input.userId)
await bar.setBar(foo)
return foo
},
startFoo: async (prev, { input }) => {
const foo = await db.foo.findByPk(input.fooId)
// here I would like to have the code from missingBar without copypasting it
// then I need to do more logic (irrelevant for this question) using that missingBarIds array
return foo
},
}
}
请注意,我认为 missingBar
解析器中的精确 Sequelize 逻辑对问题的核心并不重要,因此我对其进行了简化。其要点是,只有当所有必需的元素都已添加到 foo
时,我才想对数据库执行更新,并且执行该检查的逻辑与 missingBar
中的逻辑完全相同]解析器。
有什么方法可以在不同的突变和解析器之间共享部分逻辑吗?理想情况下,在某处声明一个函数并在两个地方都使用它?
在这种情况下,这个假设函数的唯一参数是 foo
对象的一个实例(这是一个 Sequelize 模型,但我认为这在这种情况下并不真正相关),并且 return 值将是 missingBarIds
数组。
在高层次上,您可以只编写一个函数并在两个解析器中使用它。如果你不想把它放在同一个模块中,把它放在不同的模块中并导入它。这没什么不对的。
也就是说,由于您使用的是 Sequelize,因此您可以将静态方法和实例方法添加到您的模型中 class。
一个静态方法会这样写:
Foo.doSomething = function doSomething () {
...
}
并使用模型 class:
调用
Foo.doSomething()
实例方法可以这样写:
Foo.prototype.doSomething = function doSomething () {
...
}
然后在 class:
的实例上调用
const foo = await Foo.findOne()
foo.doSomething()
注意,定义实例方法时,只要不使用箭头函数,this
就会引用实例本身。
这是我的解析器文件:
import { gql } from 'apollo-server-express'
import * as db from '../database'
export const typeDefs = gql`
extend type Query {
getFoos(): Foo
}
type Foo {
id: ID!
missingBar: [String]
}
input addBarInput {
fooId: ID!
barId: ID!
}
extend type Mutation {
addBar(input: addBarInput): Foo
startFoo(fooId: ID!): Foo
}
`
export const resolvers = {
Query: {
getFoos: async () => db.foo.findAll({include: [db.bar]}),
},
Foo: {
missingBar: async (obj, args, context, info) => {
// here starts the relevant part of code
const someBarIds = await db.some_table.findAll({
where: {bar_id: obj.bar_id},
}).map(el => el.bar_id)
const otherBarIds = await db.other_table.findAll({
where: {id: obj.bars.map(b => b.id)},
}).map(el => el.id)
const missingBarIds = someBarIds.filter(x => !otherBarIds.includes(x));
// here ends the relevant part of code
return await db.instruments.findAll({where: {id: missingInstrumentsIds}}).map(instrument => instrument.name)
},
},
Mutation: {
addBar: async (prev, { input }) => {
const foo = await db.foo.findByPk(input.fooId)
const bar = await db.users.findByPk(input.userId)
await bar.setBar(foo)
return foo
},
startFoo: async (prev, { input }) => {
const foo = await db.foo.findByPk(input.fooId)
// here I would like to have the code from missingBar without copypasting it
// then I need to do more logic (irrelevant for this question) using that missingBarIds array
return foo
},
}
}
请注意,我认为 missingBar
解析器中的精确 Sequelize 逻辑对问题的核心并不重要,因此我对其进行了简化。其要点是,只有当所有必需的元素都已添加到 foo
时,我才想对数据库执行更新,并且执行该检查的逻辑与 missingBar
中的逻辑完全相同]解析器。
有什么方法可以在不同的突变和解析器之间共享部分逻辑吗?理想情况下,在某处声明一个函数并在两个地方都使用它?
在这种情况下,这个假设函数的唯一参数是 foo
对象的一个实例(这是一个 Sequelize 模型,但我认为这在这种情况下并不真正相关),并且 return 值将是 missingBarIds
数组。
在高层次上,您可以只编写一个函数并在两个解析器中使用它。如果你不想把它放在同一个模块中,把它放在不同的模块中并导入它。这没什么不对的。
也就是说,由于您使用的是 Sequelize,因此您可以将静态方法和实例方法添加到您的模型中 class。
一个静态方法会这样写:
Foo.doSomething = function doSomething () {
...
}
并使用模型 class:
调用Foo.doSomething()
实例方法可以这样写:
Foo.prototype.doSomething = function doSomething () {
...
}
然后在 class:
的实例上调用const foo = await Foo.findOne()
foo.doSomething()
注意,定义实例方法时,只要不使用箭头函数,this
就会引用实例本身。