Search code examples
node.jsasynchronouspromisebluebirdpg-promise

Make my db queries synchronous with with my promise based function


How can I make my db queries synchronous with with my promise base function? In my code, I am running 3 db operations inside 3 different functions which need to be run in order, like waterfall model. The functions are running in waterfall model but db queries inside those functions are working in asynchronous. I need to run db queries inside those function in synchronous.

In this example I am expecting in console:

1
2
3
4

But I am getting

1
3
2
4

Code:

const Promise = require('bluebird');

// DB Settings    
const dbConfig = {
    user: process.env.DBUSER,
    password: process.env.DBPWD,
    database: process.env.DBNAME,
    host: process.env.DBHOST,
    port: process.env.DBPORT,
    poolSize: 10, // max number of clients in the pool
    //poolIdleTimeout: 30000, // how long a client is allowed to remain idle before being closed
    //reapIntervalMillis: 1000 //frequency to check for idle clients within the client pool
};
const pgp = require('pg-promise')();
const db = pgp(dbConfig);

var currentStatus = '',newStatus = '';

const _updateCurrentStatus = () => new Promise((resolve, reject) => {


    const _getCurrentStatus = (_userId) => new Promise((_resolve, _reject) => {        

        console.log("1");
        let statusQuery = "SELECT status FROM users WHERE id=" + _userId;

        db.one(statusQuery).then(function (data) {
            console.log("2");
            currentStatus = data.status;
            _resolve();
        }).catch(function (error) {
            _reject(error);
        });
    });

    const _setUpdateStatus = (cStatus, nStatus) => new Promise((_resolve, _reject) => {

        if(allApproved){
            if(cStatus == 'nvd_pending'){
                //nStatus = 'finance_pending';
                newStatus = 'finance_pending';
            }else if(cStatus == 'finance_pending'){
                //nStatus = 'oracle_pending';
                newStatus = 'oracle_pending';
            }else if(cStatus == 'oracle_pending'){
                //nStatus = 'active';
                newStatus = 'active';
            }else{
                //nStatus = cStatus;
                newStatus = cStatus;
            }
        }else{
            //nStatus = 'nvd_pending';
            newStatus = 'nvd_pending';
        }
        //_resolve(nStatus);
        _resolve();

    });

    const _updateStatus = (_newStatus, _payLoad) => new Promise((_resolve, _reject) => {

        console.log("3");

        let updateuserQuery = "UPDATE users SET status = '"+ _newStatus + "' WHERE id=" + _payLoad.user_id;
        let updatePanQuery = "UPDATE user_documents SET status = '" + _payLoad.panstatus + "' WHERE id= " + _payLoad.panid + " AND user_id=" + _payLoad.user_id;
        let updateFinanceQuery = "UPDATE user_finance_details SET status = '" + _payLoad.financestatus +" 'WHERE id= " + _payLoad.financeid + " AND user_id=" + _payLoad.user_id;

        db.tx(function (t) {
            console.log("4");
            // `t` and `this` here are the same;
            // this.ctx = transaction config + state context;
            return t.batch([
                t.none(updateuserQuery),
                t.none(updatePanQuery),
                t.none(updateFinanceQuery)
            ]);
        }).then(function (data) {
            _resolve(data);
        }).catch(function (error) {
            _reject(error);
        });


    });

    _getCurrentStatus(payLoad.user_id)
    .then(_setUpdateStatus)
    .then( _updateStatus(newStatus, payLoad))
    .then( values => {
            resolve(values);
        },error => {
            reject(error);
    })
    .catch((error) => reject(error));
});

Solution

  • You are overcomplicating thing here. First feedback is that you don't need those new Promise wrappers, since pg-promise is already creating promises. You can greatly flatten things here:

    function getCurrentStatus(userId) {
      console.log("1");
      let statusQuery = "SELECT status FROM users WHERE id=" + userId;
    
      return db.one(statusQuery).then(function (data) {               
        console.log("2");
        return data.status;
      });      
    }
    
    function getUpdatedStatus(cStatus) 
      console.log('2');
    
      if (allApproved) {
        if(cStatus == 'nvd_pending'){
          newStatus = 'finance_pending';
        } else if (cStatus == 'finance_pending'){
          newStatus = 'oracle_pending';
        } else if (cStatus == 'oracle_pending'){
          newStatus = 'active';
        } else {
           newStatus = cStatus;
        }
      } else {
        newStatus = 'nvd_pending';
      }
      return newStatus;
    }
    
    function updateStatus(newStatus, payLoad) {
        console.log("3");
    
        let updateuserQuery = "UPDATE users SET status = '"+ newStatus + "' WHERE id=" + payLoad.user_id;
        let updatePanQuery = "UPDATE user_documents SET status = '" + payLoad.panstatus + "' WHERE id= " + payLoad.panid + " AND user_id=" + payLoad.user_id;
        let updateFinanceQuery = "UPDATE user_finance_details SET status = '" + payLoad.financestatus +" 'WHERE id= " + payLoad.financeid + " AND user_id=" + payLoad.user_id;
    
        return db.tx(function (t) {
            console.log("4");
            // `t` and `this` here are the same;
            // this.ctx = transaction config + state context;
            return t.batch([
                t.none(updateuserQuery),
                t.none(updatePanQuery),
                t.none(updateFinanceQuery)
            ]);
        });
    });
    
    function updateCurrentStatus(payLoad) {
      return getCurrentStatus(payLoad.user_id)
        .then(cStatus => getUpdatedStatus(cStatus))
        .then(newStatus => updateStatus(newStatus, payLoad));
    }
    

    The specific reason you're seeing 3 out of order is because you're calling it immediately via _updateStatus(newStatus, payLoad) instead of wrapping it in a function (see my suggested code updates above).