David Baños
David Baños

Reputation: 69

Q promises not running in correct order inside connection pool with oracledb driver for nodejs

My problem is the next:

When I try to chain promises Q within a connection pool with Oracle oracledb driver not running in the correct order.

Paste the code to explain better:

var Q = require('q');
var oracledb = require("oracledb");

oracledb.autoCommit = true;

var deferedPool;

/**
 * @function ejecutaPool
 * @param {Object} pool Objeto que contiene el pool de conexiones a base de       datos.
 * @param {String} sql Cadena de texto con la consulta SQL.
 * @param {Array} parametros Array con los parámetros que se bindean en la    consulta SQL.
 * @description Crea una promesa en la cual se recupera un Pool de    conexiones a base de datos en las cuales se conecta a la base de   *  datos y   devuelve el mensaje de conexión creada o un error en el caso en el que se   produzca un error. Ejecuta la consulta SQL y     *  devuelve el resultado de la    misma o un error en el caso en el que se produzca un error. Se desconecta de la     base de datos y       *  devuelve el mensaje de conexión terminada o un error en    el caso en el que se produzca un error. La promesa devuelve el resultado   *  de      la ejecución de la consulta SQL.
 */
exports.ejecutaPool = function(pool,sql,parametros) {
  deferedPool = Q.defer();

  pool.getConnection(function(err, connection) {
  console.log("1.- Obteniendo conexion");
   if (err) { 
    console.log("ERROR: No se puede obtener la conexion: ", err);
    deferedPool.reject(err);
    return;
  }else{
    console.log("Conexion realizada");
  }

 if (typeof pool !== "undefined") {
  console.log("INFO: Conexiones abiertas: " + pool.connectionsOpen);
  console.log("INFO: Conexiones en uso: " + pool.connectionsInUse);
 }

 connection.execute(
  sql,
  parametros,
  {outFormat: oracledb.ARRAY},
  function (err, result){
    console.log("2.- Ejecutando consulta");
    if (err){
      console.log(err.message);
      deferedPool.reject(err);
    } else {
      console.log('2.1.- Resultado consulta: ' + JSON.stringify(result));
      deferedPool.resolve(result); //result.ejecuta;
    }

    connection.release(function(err) {
      console.log('3.- Liberando conexion');
      if (err) {
        deferedPool.reject(err);
      }else {
        console.log("Conexion terminada"); //result.libera;
      }
    });
   });
  });
  return deferedPool.promise;
 }

This is the file: apiOraclePool.js

And the bellow is the file: pruebasApiOracle.js

var db = require('./apiOraclePool.js');
var dbconfig = require('./dbconfig.js');
var oracledb    = require('oracledb');
var Q = require('q');

var sqlSelect = "SELECT * FROM CERTS";
console.log(sqlSelect);

var sqlInsert = "begin insert into CERTS (ID, NOMBRE, APELLIDOS, NIF) values     (:id, :nm, :ap, :nif); commit; exception when DUP_VAL_ON_INDEX then ROLLBACK;   end;";

console.log(sqlInsert);

var parametrosSelect = [];

var parametrosInsert = ['7','ooo','ppp ttt','01928364R'];

var sqlUpdate = "UPDATE CERTS SET NOMBRE = 'Jose' WHERE NOMBRE = 'Pepe'";
console.log(sqlUpdate);

var parametrosUpdate = [];

var sqlDelete = "DELETE FROM CERTS WHERE NOMBRE = 'Jose'";
console.log(sqlDelete);

var parametrosDelete = [];

var sqlProcedure = "BEGIN testproc(:i, :io, :o); END;";
console.log(sqlProcedure);

var parametrosProcedure = {
  i:  'Chris',  // bind type is determined from the data type
  io: { val: 'Jones', dir : oracledb.BIND_INOUT },
  o:  { type: oracledb.NUMBER, dir : oracledb.BIND_OUT },
};

/*var promesaInsert = db.ejecutaInsert(sqlInsert,parametrosInsert);
promesaInsert.then(tratarResultadoInsert).done();

var promesaSelect = db.ejecutaSelect(sqlSelect,parametrosSelect);
promesaSelect.then(tratarResultadoSelect).done();

var promesaUpdate = db.ejecutaUpdate(sqlUpdate,parametrosUpdate);
promesaUpdate.then(tratarResultadoUpdate).done();

var promesaDelete = db.ejecutaDelete(sqlDelete,parametrosDelete);
promesaDelete.then(tratarResultadoDelete).done();*/

oracledb.createPool({
  user:             dbconfig.user,
  password:         dbconfig.password,
  connectString:    dbconfig.connectString,
  poolMax:          44,
  poolMin:          1,
  poolIncrement:    1,
  poolTimeout:      4
}, function(err, pool) {

 console.log(pool);

 if (err) {
  console.log("ERROR: ", new Date(), ": createPool() callback: " +    err.message);
   return;
  }

  var promesaUpdate = db.ejecutaPool(pool,sqlUpdate,parametrosUpdate);
  var promesaSelect = db.ejecutaPool(pool,sqlSelect,parametrosSelect);
  var promesaInsert = db.ejecutaPool(pool,sqlInsert,parametrosInsert);
  var promesaDelete = db.ejecutaPool(pool,sqlDelete,parametrosDelete);
  var promesaProcedure =               db.ejecutaPool(pool,sqlProcedure,parametrosProcedure);

  /*
  var promesa= Q();
  var promesaUpdate = Q().then(function(){ console.log('1. Update   ejecutado'); } );
  var promesaSelect = Q().then(function(){ console.log('2. Select ejecutado   '); } );
  var promesaInsert = Q().then(function(){ console.log('3. Insert ejecutado '); } );
  var promesaDelete = Q().then(function(){ console.log('4. Delete ejecutado '); } );
  var promesaProcedure = Q().then(function(){ console.log('5. Procedure ejecutado '); } );
  */

   //promesa.then(promesaUpdate).then(promesaSelect).then(promesaInsert).then(promesaDelete).then(promesaProcedure);//.done();

  promesaUpdate.then(tratarResultadoUpdate).then(promesaSelect).then(tratarResulta doSelect).then(promesaInsert).then(tratarResultadoInsert).then(promesaDelete).then(tratarResultadoDelete).then(promesaProcedure).then(tratarResultadoProcedure);

  var promesa = Q.defer();
  var resultadoUpdate = function (texto){
    promesa.resolve(console.log(texto));
    return promesa.promise;
  }

  var resultadoSelect = function (texto){
    promesa.resolve(console.log(texto));
    return promesa.promise;
  }

  var resultadoInsert = function (texto){
    promesa.resolve(console.log(texto));
    return promesa.promise;
  }

  var resultadoDelete = function (texto){
    promesa.resolve(console.log(texto));
    return promesa.promise;
  }

  var resultadoProcedure = function (texto){
    promesa.resolve(console.log(texto));
    return promesa.promise;
  }

  /*
  promesaUpdate("1. Estoy en la consulta Update").then(promesaSelect("2.   Estoy en la consulta Select")).then(promesaInsert("3. Estoy en la consulta Insert")).then(promesaDelete("4. Estoy en la consulta Delete"));
  */

  /*
  var promesaSelect = Q().then(function(){ console.log('2. Select ejecutado '); } );
  var promesaInsert = Q().then(function(){ console.log('3. Insert ejecutado '); } );
  var promesaDelete = Q().then(function(){ console.log('4. Delete ejecutado '); } );
  var promesaProcedure = Q().then(function(){ console.log('5. Procedure ejecutado '); } );
  */


 });

 function tratarResultadoUpdate (resultadoUpdate){
   console.log("Filas actualizadas: " + resultadoUpdate.rowsAffected);
 }

 function tratarResultadoSelect (resultadoSelect){
    console.log("Respuesta de la base de datos:" +        resultadoSelect.rows.length);
   if(resultadoSelect.rows.length > 0){
      for (var i=0;i < resultadoSelect.rows.length; i++){
        console.log(resultadoSelect.rows[i]);
      }
   }
 }

function tratarResultadoInsert (resultadoInsert){
  console.log(resultadoInsert.outBinds);
}

function tratarResultadoDelete (resultadoDelete){
  console.log("Filas eliminadas: " + resultadoDelete.rowsAffected);
}

function tratarResultadoProcedure (resultadoProcedure){
  console.log(resultadoProcedure.outBinds);
}

Thank you in advance.

Upvotes: 0

Views: 526

Answers (1)

jeffm13
jeffm13

Reputation: 41

I suspect you're running into trouble mixing promises with callbacks. I do something similar with Bluebird:

var Oracle = require('oracledb');
var Promise = require('bluebird');

function createPool(config) {
    return new Promise(function(resolve, reject) {
        console.log('creating pool ' + JSON.stringify(config));
        Oracle.createPool(config,
            function(err, pool) {
                if (err) {
                    return reject(err);
                } 
                resolve(pool);
        });
    });
}

function getConnection(pool) {
    return new Promise(function(resolve, reject) {
        pool.getConnection(function(err, connection) {
            if (err) {
                return reject(err);
            }
            resolve(connection);
        });
    });
}

function _innerExecute(sql, bindParams, options, connection) {
    return new Promise(function(resolve, reject) {
        connection.execute(sql, bindParams, options, function(err, results) {
            if (err) {
                reject(err);
            }
            resolve(results);
        });
    });
}

function execute(sql, bindParams, options, pool) {
    return using (getConnection(pool), function(connection) {
        return _innerExecute(sql, bindParams, options, connection);
    });
}

function testSelect() {
    var config = {
       connectString: '//localhost:1521/test',
       user: 'test',
       password: 'test'
    };

    var pool; 
    createPool(config)
       .then(function(p) { pool = p; })
       .catch(function(e) { console.log(e); });

    execute('SELECT * FROM EMPLOYEES', {}, {}, pool)
       .then(function(results) {
            console.log('results = ' + results);
          })
       .catch(function(error) { console.log(e); });
}

This is a simplified example, but it should give an idea of an approach that works. It also adds the benefit of automatically releasing connections.

You might want to take a look at https://jsao.io/2015/03/making-a-wrapper-module-for-the-node-js-driver-for-oracle-database/ for a similar but somewhat more comprehensive approach to wrap oracledb with promises using es6-promises.

Upvotes: 1

Related Questions