使用函数生成器将值返回到 GraphQL Mutation 中的 outputFields
Posted
技术标签:
【中文标题】使用函数生成器将值返回到 GraphQL Mutation 中的 outputFields【英文标题】:Return value to outputFields in GraphQL Mutation using a Function Generator 【发布时间】:2017-01-05 04:57:52 【问题描述】:我在 GraphQL 突变 中使用 函数生成器 时遇到问题。
函数生成器用于清理突变内部的承诺链。在重构代码之前工作正常,目前console.logs
正在显示新创建的对数据库的写入,据我所知,问题是从函数生成器中获取最终返回值并将其设置为返回mutateAndGetPayload
函数的值。
错误
无法设置未定义的属性“clientMutationId”
我已经有一段时间了,如果有任何建议或帮助,我将不胜感激。
如何将函数生成器的返回值放入封闭函数的范围内,以便从该函数中返回它?
下面是突变。数据库写入工作正常,当它获得正确的有效负载时输出工作正常(它不工作,这是我的主要问题)。唯一的问题是将newUser
获取到输出字段中的解析函数。为了简化问题,我省略了一些代码。
const addEmployeeMutation = mutationWithClientMutationId(
name: 'AddEmployee',
inputFields:
/** this section works fine **/
,
outputFields:
attendee:
type: AttendeeType,
resolve: r.compose(
/** this section works fine **/
r.prop('id')
)
,
mutateAndGetPayload: (payload, userId) =>
const getUser = (userId) =>
return authorize(userId)
.then(can => /** works fine **/ )
.then(user => gen.next(user))
const createHash = (plainPassword) =>
return genSalt(10)
.then((salt, err) => /** works fine **/ )
.then((hashed_password, err) => gen.next(hashed_password))
const createUser = (payload, hashed_password, user) =>
return new UserModel( /** works fine **/ ).save()
.then(newUser => gen.next(newUser))
const createProfile = (payload, newUserId) =>
return new ProfileModel( /** works fine **/ )
.then(profile => gen.next(profile))
.catch(err => throw new GraphQLError(`Error: $err`))
let gen = generator()
gen.next()
function* generator()
const user = yield getUser(userId)
console.log('USER >>>>>>>>>>>>>>>>>>', user)
const hash = yield createHash(payload.password)
console.log('HASH >>>>>>>>>>>>>>>>>>', hash)
const newUser = yield createUser(payload, hash, user)
console.log('NEW USER >>>>>>>>>>>>>>>>>> ', newUser)
const newProfile = yield createProfile(payload, newUser.id)
console.log('NEW PROFILE >>>>>>>>>>>>>>>>>> ', newProfile)
return newUser
return newUser // <- How do I get a value to here?
【问题讨论】:
那里没有价值。生成器不会使异步代码同步执行,其他也不会。顺便说一句,你应该使用async
/await
,它比手写的协程运行器更容易使用。
看起来 mutateAndGetPayload 在生成器完成其产量之前返回未定义?我虽然它会支持包含功能。我在这里猜测,但如果可以在解析函数中运行生成器,它可能会工作,但在这种情况下,它可能不是要走的路。谢谢@Bergi,我会尝试使用async
/await
,如果有趣的话可能会在这里发布结果。
是的,因为您正在异步运行生成器,所以函数将在完成之前返回。您所能做的就是为最终结果返回一个承诺(async function
也将这样做)。
只需使用async
/await
重写它,它就可以完美运行。非常感谢@Bergi!
【参考方案1】:
异步等待
感谢@Bergi 的帮助,我改为使用async
/await
。
我在这里发布我的答案,以防其他人走上这条路并需要帮助。
结果证明是一个快速解决方案。
更改每个执行数据库写入的承诺中的.then()
以返回所需的对象。然后将它们移到一个单独的实用程序模块中。
在突变本身中,我使用以下代码运行异步写入并将所需的有效负载返回到输出字段:
mutateAndGetPayload: (payload, userId) =>
async function generateUser()
const user = await getUser(userId)
const hash = await createHash(payload.password)
const newUser = await createUser(payload, hash, user)
await createProfile(payload, newUser.id)
return newUser
return generateUser()
编辑
一个更简洁的解决方案,再次感谢@Bergi。我将离开原始解决方案,因为它提供了一些关于如何使用 async
/await
的清晰度,并演示了如何重构代码以提高简洁性。同样,有人可能会觉得这很有用。
mutateAndGetPayload: async function(payload, userId)
const user = await getUser(userId)
const hash = await createHash(payload.password)
const newUser = await createUser(payload, hash, user)
await createProfile(payload, newUser.id)
return newUser
说明
由于在 OP 中使用 函数生成器 是异步的,因此是非阻塞的,mutateAndGetPayload
函数在生成器有时间完成之前返回 undefined
。通过使用async
/await
(在两个版本中),mutateAndGetPayload
函数被阻止完成,直到添加 await
值已按照指定的顺序解析。
【讨论】:
其实你应该去掉generateUser
内部函数,只做mutateAndGetPayload
async
本身。
再次感谢@Bergi。我已经离开了原始版本来展示这个过程,它将帮助任何第一次在RelayJS
GraphQL
突变中进入这种模式的人。【参考方案2】:
Ramda JS
另一种利用ramda
函数式编程库的方法。在q
的帮助下管理承诺。
使用 ramda.js 涉及对实用程序函数进行柯里化,以便它们等待数据以正确的顺序出现。
mutateAndGetPayload: (payload, userId) =>
r.compose(
then(
r.compose(
then(r.last),
r.converge(
r.unapply(q.all),
[
createProfile(payload),
createUserRole(payload),
r.identity
]
)
)
),
r.converge(
r.compose(
then(createUser(payload)),
r.unapply(q.all)
),
[
r.identity,
then(_ => createHash(payload))
]
),
getUser
)(userId)
【讨论】:
以上是关于使用函数生成器将值返回到 GraphQL Mutation 中的 outputFields的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 Apollo Client 和 GraphQL .NET 将值转换为 AST
FaunaDB - 如何批量更新单个 graphQL 突变中的条目列表?