如何在pg-promise事务中包装graphql请求

时间:2018-04-27 04:26:44

标签: node.js transactions graphql pg-promise

PG-Promise提供了一个很好的安全事务包装器

db.tx(t => {
    // Here you can use t to run any queries
    // in a single transaction, on a single connection.
})

Apollo GraphQL Express提供了一个处理GraphQL请求的Express中间件。它取决于一组预定义的"解析器"它解决了请求的不同部分。这些解析器从库中调用,并将它们的结果放在一起形成响应。

我希望能够在pg-promise事务中包装一个GraphQL请求,该请求可以获取多个数据或执行多个数据库操作(突变),从而实现基本的事务完整性。没有明显的方法可以做到这一点。

我提出的最好的想法是创建我自己的中间件,在GraphQL之前运行,这会向请求对象添加一个新的事务任务:

const bindTx = (req, res, next) => {
    db.tx(async (t) => {
        req = Object.assign(req, {getTransaction: () => t})
        await next()
    })
}

我的想法是,这个中间件将确保下一个中间件在事务中运行。我把它放在GraphQL之前的Express链中:

app.use('/graphql', bodyParser.json(), bindTx, graphql)

我的graphql设置然后通过bindTx将请求添加到请求中,并通过context将其传递给解析器:

const graphql = graphqlExpress((req) => {
  const t = req.getTransaction()

  return {
    schema: makeExecutableSchema({
      typeDefs,
      resolvers
    }),
    context: {t}
  }
}

最后,解析器可能如下所示:

getSomethingById(_, {somethingId}, context) {
  context.t.one(
    'select * from something where id = ${somethingId}',
    {somethingId}
  )
}

由于我理解GraphQL按顺序运行解析器,并且它们可以返回一个必须在下一个解析器运行之前解析的promise,我认为这样可行。

这似乎导致竞争条件,大多数情况下它会产生错误Unhandled rejection Error: Querying against a released or lost connection.我认为这意味着当解析器运行并尝试查询时,事务已经关闭。

我根本不依赖于这种方法,事实上它似乎过于复杂,但我正在寻找一些方法来使我的GraphQL解析在一个事务中运行。虽然我目前正在使用Express,Apollo和PG-Promise,但如果其他库可以解决问题,这些都不是要求。

有什么想法吗?

0 个答案:

没有答案