Необязательный оператор INSERT в цепочке транзакций с использованием NodeJS и Postgres

Я создаю простое веб-приложение с использованием NodeJS/Postgres, которому нужно сделать 3 вставки в базу данных.

Для управления цепочкой операторов я использую pg-transaction.

Моя проблема в том, что я должен всегда запускать 2 первых INSERTS, но у меня есть условие для запуска 3-го.

Возможно, мой код можно было бы построить лучше (предложения приветствуются).

Вот псевдокод:

function(req, res) {
  var tx = new Transaction(client);
  tx.on('error', die);
  tx.begin();
  
  tx.query('INSERT_1 VALUES(...) RETURNING id', paramValues, function(err, result) {
    if (err) {
      tx.rollback();
      res.send("Something was wrong!");
      return;
    }
    
    var paramValues2 = result.rows[0].id;
    tx.query('INSERT_2 VALUES(...)', paramValues2, function(err2, result2) {
      if (err) {
        tx.rollback();
        res.send("Something was wrong!");
        return;
      }
      
      // HERE'S THE PROBLEM (I don't want to always run this last statement)
      // If I don't run it, I will miss tx.commit()
      if (req.body.value != null) {
        tx.query('INSERT_3 VALUES(...)', paramValues3, function(err3, result3) {
          if (err) {
            tx.rollback();
            res.send("Something was wrong!");
            return;
          }
        
          tx.commit();
          res.send("Everything fine!");
        });
      }
    });
  });
}

Выглядит так некрасиво трижды повторять одно и то же if (err) {} после каждого запроса.

Пытаясь проверить некоторые параметры, я нашел Sequelize, но не нашел способа решить эту проблему с его помощью.

Любые предложения приветствуются!

Спасибо!


person Tom    schedule 05.05.2016    source источник
comment
Вы уверены, что в последней вставке именно 'INSERT_3 VALUES(...)', paramValues2, а не какой-то 'INSERT_3 VALUES(...)', paramValues3? то есть вам нужно использовать результат первого запроса, чтобы сделать последний?   -  person vitaly-t    schedule 05.05.2016


Ответы (1)


Ручное управление транзакциями — коварный путь, старайтесь держаться подальше от него! ;)

Вот как это сделать правильно с помощью pg-promise:

function(req, res) {
    db.tx(t => { // automatic BEGIN
            return t.one('INSERT_1 VALUES(...) RETURNING id', paramValues)
                .then(data => {
                    var q = t.none('INSERT_2 VALUES(...)', data.id);
                    if (req.body.value != null) {
                        return q.then(()=> t.none('INSERT_3 VALUES(...)', data.id));
                    }
                    return q;
                });
        })
        .then(data => {
            res.send("Everything's fine!"); // automatic COMMIT was executed
        })
        .catch(error => {
            res.send("Something is wrong!"); // automatic ROLLBACK was executed
        });
}

Или, если вы предпочитаете синтаксис ES7:

function (req, res) {
    db.tx(async t => { // automatic BEGIN
            let data = await t.one('INSERT_1 VALUES(...) RETURNING id', paramValues);
            let q = await t.none('INSERT_2 VALUES(...)', data.id);
            if (req.body.value != null) {
                return await t.none('INSERT_3 VALUES(...)', data.id);
            }
            return q;
        })
        .then(data => {
            res.send("Everything's fine!"); // automatic COMMIT was executed
        })
        .catch(error => {
            res.send("Something is wrong!"); // automatic ROLLBACK was executed
        });
}

ОБНОВЛЕНИЕ

Генераторы ES6 заменены на ES7 async/await в примере, потому что pg-promise перестал поддерживать генераторы ES6 с версии 9.0.0.

person vitaly-t    schedule 05.05.2016
comment
Именно то, что мне было нужно. Только что проверил, работает отлично. Спасибо за полный ответ! - person Tom; 08.05.2016