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. Это зависит от набора предопределенных «преобразователей», которые разрешают разные части запроса. Эти распознаватели вызываются из библиотеки, а их результаты объединяются в ответ.
Я бы хотел иметь возможность обернуть запрос GraphQL, который извлекает несколько фрагментов данных или выполняет несколько операций с базами данных (мутации), в транзакцию pg-обещания, чтобы обеспечить базовую целостность транзакции. Нет очевидного для меня способа сделать это.
Лучшая идея, которую я придумала, - это создать собственное промежуточное программное обеспечение для запуска до GraphQL, который добавляет новую задачу транзакции к объекту запроса:
const bindTx = (req, res, next) => {
db.tx(async (t) => {
req = Object.assign(req, {getTransaction: () => t})
await next()
})
}
Здесь я подумал, что это промежуточное программное обеспечение обеспечит запуск следующего промежуточного программного обеспечения внутри транзакции Я вставил это в цепочку Express перед GraphQL:
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, это не требования, если другие библиотеки могут решить эту проблему.
Есть идеи?