使用函数生成器将值返回到 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内部函数,只做mutateAndGetPayloadasync本身。 再次感谢@Bergi。我已经离开了原始版本来展示这个过程,它将帮助任何第一次在RelayJSGraphQL突变中进入这种模式的人。【参考方案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

使用 GraphQL 代码生成器从解析器返回不完整的形状

FaunaDB - 如何批量更新单个 graphQL 突变中的条目列表?

如何将值返回到数组

Graphql 突变返回 Post 400 错误,不知道如何解决

如何在 Laravel Rebing GraphQL 中使用“隐私”属性函数?