Как можно обернуть запрос graphql в транзакцию pg-обещания

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-prom, чтобы обеспечить базовую целостность транзакции. Для меня нет очевидного способа сделать это.

Лучшая идея, которую я придумал, - это создать собственное промежуточное ПО для запуска до 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, это не требования, если другие библиотеки могут решить проблему.

Любые идеи?

Во-первых: обещания решателей не должны возвращаться до выполнения следующего. Это относится только к полям верхнего уровня мутаций. Во-вторых: я не думаю, что вы можете дождаться функции next в экспрессе. По моему опыту написания промежуточного ПО, которое нисходящее промежуточное ПО обертывания довольно сложно выразить. Но вы можете сделать это в Коа, просто также дождитесь транзакции. Если вы можете легко изменить фреймворк http, я настоятельно рекомендую фреймворк, который работает с обещаниями / ожиданием. Я понятия не имею, почему люди до сих пор используют экспресс в эпоху пост-Node 6.

Herku 27.04.2018 12:07

Тело транзакции ожидает внутри себя необязательного обещания, что означает, что вы можете связать любую функциональность внутри транзакции, пока она выполняется. Вы даже можете выполнять сложное секвенирование, как в этот пример.

vitaly-t 27.04.2018 17:27

@Herku, спасибо, это фантастическое предложение. Я никак не привязан к Express, это было просто по умолчанию. Как только у меня будет время вернуться к этому, я попробую Коа. Я немного отредактировал вопрос, чтобы прояснить, что инструменты не обязательны.

Matthew Krauss 27.04.2018 22:14

@ vitaly-t, PG-Promise меня пока что впечатлила. На мой взгляд, проблема здесь больше в других инструментах или в моем непонимании.

Matthew Krauss 27.04.2018 22:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
728
0

Другие вопросы по теме