25. Node.js Programming Styles

Node-oracledb supports callbacks, Promises, and Async/Await Node.js styles of programming. The latter is recommended.

25.1. Using Node.js Async/Await with node-oracledb

Node.js supports async functions, also known as Async/Await. These can be used with node-oracledb. For example:

const oracledb = require('oracledb');

const mypw = ... // the hr schema password

function getEmployee(empid) {
    return new Promise(async function(resolve, reject) {
        let connection;

        try {
            connection = await oracledb.getConnection({
                user          : "hr",
                password      : mypw,
                connectString : "localhost/FREEPDB1"
            });

            const result = await connection.execute(
             `SELECT * FROM employees WHERE employee_id = :bv`,
             [empid]
            );
            resolve(result.rows);

        } catch (err) { // catches errors in getConnection and the query
            reject(err);
        } finally {
            if (connection) {   // the connection assignment worked, must release
                try {
                    await connection.release();
                } catch (e) {
                    console.error(e);
                }
            }
        }
    });
}

async function run() {
    try {
        const res = await getEmployee(101);
        console.log(res);
    } catch (err) {
        console.error(err);
    }
}

run();

If you are using Lob instances for LOB data, then the Lobs must be streamed since there is no Promisified interface for them. Alternatively you can work with the data directly as Strings or Buffers.

25.2. Using Node.js Promises with node-oracledb

Node-oracledb supports Promises with all asynchronous methods. The native Promise implementation is used.

If an asynchronous method is invoked without a callback, it returns a Promise:

const oracledb = require('oracledb');

const mypw = ... // the user password

oracledb.getConnection(
  {
    user          : "hr",
    password      : mypw,
    connectString : "localhost/FREEPDB1"
  })
.then(function(connection) {
    return connection.execute(
     `SELECT department_id, department_name
      FROM departments
      WHERE manager_id < :id`,
     [110]  // bind value for :id
    )
    .then(function(result) {
        console.log(result.rows);
        return connection.close();
    })
    .catch(function(err) {
        console.error(err);
        return connection.close();
    });
})
.catch(function(err) {
    console.error(err);
});

With Oracle’s sample HR schema, the output is:

[ [ 60, 'IT' ], [ 90, 'Executive' ], [ 100, 'Finance' ] ]

Notice there are two promise “chains”: one to get a connection and the other to use it. This is required because it is only possible to refer to the connection within the function to which it was passed.

When invoking asynchronous methods, it is possible to accidentally get a Promise by forgetting to pass a callback function:

oracledb.getConnection(
  {
    user          : "hr",
    password      : mypw,
    connectString : "localhost/WRONG_SERVICE_NAME"
  });
. . .

Since the returned promise will not have a catch block, as the intention was to use the callback programming style, any rejections that occur will go unnoticed. Node.js 4.0 added the unhandledRejection event to prevent such rejections from going unnoticed:

process.on('unhandledRejection', (reason, p) => {
    console.error("Unhandled Rejection at: ", p, " reason: ", reason);
    // application specific logging, throwing an error, or other logic here
});

oracledb.getConnection(
  {
    user          : "hr",
    password      : mypw,
    connectString : "localhost/WRONG_SERVICE_NAME"
  });
. . .

Whereas the code without the unhandledRejection exception silently exited, adding the handler could, for example, show:

$ node myapp.js
Unhandled Rejection at:  Promise {
    <rejected> [Error: ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
] }  reason:  [Error: ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
]

25.2.1. Custom Promise Libraries

From node-oracledb 5.0, custom Promise libraries can no longer be used. Use the native Node.js Promise implementation instead.

25.3. Using Node.js Callbacks with node-oracledb

Node-oracledb supports callbacks.

// myscript.js

const oracledb = require('oracledb');

const mypw = ...  // set mypw to the hr schema password

oracledb.getConnection(
  {
        user          : "hr",
        password      : mypw
        connectString : "localhost/FREEPDB1"
  },
  function(err, connection) {
    if (err) {
        console.error(err.message);
        return;
    }
    connection.execute(
     `SELECT manager_id, department_id, department_name
      FROM departments
      WHERE manager_id = :id`,
     [103],  // bind value for :id
     function(err, result) {
        if (err) {
            console.error(err.message);
            doRelease(connection);
            return;
        }
        console.log(result.rows);
        doRelease(connection);
    });
});

function doRelease(connection) {
    connection.close(
      function(err) {
        if (err)
        console.error(err.message);
      });
}

With Oracle’s sample HR schema, the output is:

[ [ 103, 60, 'IT' ] ]