首页 > 解决方案 > 如何在 pg-promise 事务中包装 graphql 请求

问题描述

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 提供了一个 Express 中间件来处理 GraphQL 请求。它取决于一组预定义的“解析器”,它们解析请求的不同部分。这些解析器是从库中调用的,它们的结果放在一起形成响应。

我希望能够在 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 会按顺序运行解析器,并且它们可以返回一个必须在下一个解析器运行之前解析的承诺,我认为这会起作用。

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

我根本不喜欢这种方法,实际上它似乎过于复杂,但我正在寻找某种方法来让我的 GraphQL 解析在事务中运行。虽然我目前正在使用 Express、Apollo 和 PG-Promise,但这些不是必需的,如果其他库可以解决问题的话。

有任何想法吗?

标签: node.jstransactionsgraphqlpg-promise

解决方案


推荐阅读