使用函数生成器将值返回到GraphQL Mutation中的outputFields

时间:2016-08-29 08:17:34

标签: javascript node.js generator graphql relayjs

我在 GraphQL变异中使用函数生成器时遇到问题。

函数生成器用于清除变异中的promise链。在重构之前,代码工作正常,目前console.logs显示新创建的数据库写入,因此我可以告诉问题是从函数生成器中获取最终返回值并将其设置为mutateAndGetPayload函数的返回值。

错误

  

无法设置属性' clientMutationId'未定义的

我已经在这一段时间了,并希望得到任何建议或帮助。

如何将函数发生器的返回值放入封闭函数的范围内,以便从该函数返回它?

以下是突变。数据库写入工作正常,输出在获得正确的有效负载时工作(它不起作用,这是我的主要问题)。唯一的问题是在输出字段中将newUser转换为resolve函数。我省略了一些代码来简化问题。

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?
}

2 个答案:

答案 0 :(得分:1)

Async Await

感谢@Bergi的一些帮助,我改为使用async / await

我在这里发布我的答案,以防其他人沿着这条路走下去,需要一只手。

答案结果证明是一个快速修复。

更改正在执行数据库写入的每个promise中的.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值已解决。< / p>

答案 1 :(得分:0)

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)