Skip to content

Instantly share code, notes, and snippets.

@jooyunghan
Created October 7, 2015 10:20
Show Gist options
  • Save jooyunghan/8b4bb4211d4fe04181be to your computer and use it in GitHub Desktop.
Save jooyunghan/8b4bb4211d4fe04181be to your computer and use it in GitHub Desktop.

node-postgres라이브러리 위키에는 아래의 예제 코드가 나온다. Transaction으로 insertion을 두 번 하는 코드다.

var Client = require('pg').Client;

var client = new Client(/*your connection info goes here*/);
client.connect();

var rollback = function(client) {
  client.query('ROLLBACK', function() {
    client.end();
  });
};

client.query('BEGIN', function(err, result) {
  if(err) return rollback(client);
  client.query('INSERT INTO account(money) VALUES(100) WHERE id = $1', [1], function(err, result) {
    if(err) return rollback(client);
    client.query('INSERT INTO account(money) VALUES(-100) WHERE id = $1', [2], function(err, result) {
      if(err) return rollback(client);
      //disconnect after successful commit
      client.query('COMMIT', client.end.bind(client));
    });
  });
});

대표적인 콜백헬 모양을 보여준다.

async를 이용한다면 아래와 같이 해볼 수 있을 것 같다.

async.series([
  client.query.bind(client, 'BEGIN'),
  client.query.bind(client, 'INSERT ... ', [1]),
  client.query.bind(client, 'INSERT ... ', [2])
], function(err){
  if (err) client.query('ROLLBACK', client.end.bind(client));
  else client.query('COMMIT', client.end.bind(client));
});

만약 insert할 데이터가 배열에 들어있다면..

async.series([
  client.query.bind(client, 'BEGIN'),
  function (cb) {
    async.each(values, function (v, cb0) {
      client.query("INSERT ... ", v, cb0);
    }, cb);
  }
], function(err){
  if (err) client.query('ROLLBACK', client.end.bind(client));
  else client.query('COMMIT', client.end.bind(client));
});

API 하나하나만 봤을 때는 별 문제 없어보이지만 추상화의 부족으로 인해 composition하기가 여전히 불편하다. (cb/cb0를 제대로 사용하기 어렵지 않을까??)

Promise/Observable 등의 추상화가 빛을 발한다. query를 Promise버전으로 만들었다고 보자.

client.query('BEGIN')
.then(function() {
  return Promise.all(values.map(function(v) {
    return client.query('INSERT ... ', v);
  }));
})
.then(client.query.bind(client, 'COMMIT'))
.catch(client.query.bind(client, 'ROLLBACK'))
.finally(client.end.bind(client));

만약 Observable이었다면 all 대신 zip으로, then 대신 flatMap으로, catch 대신 onCompleted Handler로 처리하는 등이 바뀌고 나머진 그대로 일 것이다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment