Introduction to the MLE JavaScript SQL Driver
node-oracledb
.
This close relationship between the server-side and client-side drivers reduces the effort required to port client-side JavaScript code from Node.js or Deno to the database. Functionality that cannot be reasonably mapped to the server-side environment is omitted from MLE and the MLE JavaScript driver and will throw errors.
This helps you identify those parts of the code requiring changes. Furthermore, the MLE JavaScript implementation is a pure JavaScript implementation. Certain features not part of the ECMAScript standard are unavailable in MLE, such as the window object as well as direct file and network I/O.
The mle-js-oracledb
SQL driver defaults to a synchronous
operating model and partially supports asynchronous execution via async/await.
Note:
Production code should adhere to industry best practices for error handling and logging, which have been omitted from this chapter's examples for the sake of clarity. Additionally, most examples feature the synchronous execution model due to its greater readability.Note:
If you are running your JavaScript code in a restricted execution context, you cannot use the MLE JavaScript SQL driver. For more information about restricted execution contexts, see About Restricted Execution Contexts.See Also:
-
Server-Side JavaScript API Documentation for more information about the built-in JavaScript modules
Topics
- Working with the MLE JavaScript Driver
Generic workflow for working with the MLE JavaScript driver. - Connection Management in the MLE JavaScript Driver
Considerations when dealing with connection management in the MLE JavaScript driver. - Introduction to Executing SQL Statements
A single SQL or PL/SQL statement can be executed by theConnection
class'sexecute()
method. Query results can either be returned in a single JavaScript array or fetched in batches using aResultSet
object. - Processing Comparison Between node-oracledb and mle-js-oracledb
Thenode-oracledb
documentation recommends the use of the async/await interface. Due to the nature of client-server interactions, most of the processing involved between node and the database is executed asynchronously.
Working with the MLE JavaScript Driver
Generic workflow for working with the MLE JavaScript driver.
At a high level, working with the MLE
JavaScript driver is very similar to using the client-side
node-oracledb
driver, namely:
- Get a connection handle to the existing database session.
- Use the connection to execute a SQL statement.
- Check the result object returned by the statement executed, as well as any database errors that may have occurred.
- In the case of select statements, iterate over the resulting cursor.
- For statements manipulating data, decide whether to commit or roll the transaction back.
Applications that aren't ported from client-side Node.js or Deno can benefit from coding aids available in the MLE JavaScript SQL driver, such as many frequently used variables available in the global scope. These variables include the following:
oracledb
for theOracleDb
driver objectsession
for the default connection objectsoda
for theSodaDatabase
objectplsffi
for the foreign function interface (FFI) object
Additionally, the following types are available:
OracleNumber
OracleClob
OracleBlob
OracleTimestamp
OracleTimestampTZ
OracleDate
OracleIntervalDayToSecond
OracleIntervalYearToMonth
The availability of these objects in the global scope reduces the need to write boilerplate code. For details about global symbols available with the MLE JavaScript SQL driver, see Server-Side JavaScript API Documentation.
Parent topic: Introduction to the MLE JavaScript SQL Driver
Connection Management in the MLE JavaScript Driver
Connection management in the MLE JavaScript driver is greatly simplified compared to the client driver. Because a database session will already exist when a JavaScript stored procedure is invoked, you don't need to worry about establishing and tearing down connections, connection pools, and secure credential management, to name just a few.
You need only be concerned with the getDefaultConnection()
method from the mle-js-oracledb
module or use the global session
object.
Parent topic: Introduction to the MLE JavaScript SQL Driver
Introduction to Executing SQL Statements
Connection
class's execute()
method. Query results
can either be returned in a single JavaScript array or fetched in batches using a
ResultSet
object.
Fetching as ResultSet
offers more control over the fetch operation
whereas using arrays requires fewer lines of code and provides performance benefits
unless the amount of data returned is enormous.
Example 7-1 Getting Started with the MLE JavaScript SQL Driver
The following code demonstrates how to import the MLE JavaScript SQL driver into the current module's namespace. This example is based on one provided in the node-oracledb documentation, A SQL SELECT statement in Node.js.
CREATE OR REPLACE MLE MODULE js_sql_mod LANGUAGE JAVASCRIPT AS
import oracledb from "mle-js-oracledb";
/**
* Perform a lookup operation on the HR.DEPARTMENTS table to find all
* departments managed by a given manager ID and print the result on
* the console
* @param {number} managerID the manager ID
*/
function queryExample(managerID) {
if (managerID === undefined) {
throw new Error (
"Parameter managerID has not been provided to queryExample()"
);
}
let connection;
try {
connection = oracledb.defaultConnection();
const result = connection.execute(`
SELECT manager_id, department_id, department_name
FROM hr.departments
WHERE manager_id = :id`,
[
managerID
],
{
outFormat: oracledb.OUT_FORMAT_OBJECT
}
);
if (result.rows.length > 0) {
for (let row of result.rows) {
console.log(`The query found a row:
manager_id: ${row.MANAGER_ID}
department_id: ${row.DEPARTMENT_ID}
department_name: ${row.DEPARTMENT_NAME}`);
}
} else {
console.log(`no data found for manager ID ${managerID}`);
}
} catch (err) {
console.error(`an error occurred while processing the query: ${err.message}`);
}
}
export { queryExample };
/
The only function present in the module, queryExample()
,
selects a single row from the HR departments table using a bind variable by calling
connection.execute()
. The value of the bind variable is passed
as a parameter to the function. Another parameter passed to
connection.execute()
indicates that each row returned by the
query should be provided as a JavaScript object.
If data has been found for a given managerID
, it is
printed on the screen. By default, the call to console.log()
is
redirected to DBMS_OUTPUT
. Should there be no rows returned a
message indicating this fact is printed on the console.
The call specification in the following snippet allows the code to be invoked in the database.
CREATE OR REPLACE PROCEDURE p_js_sql_query_ex(
p_manager_id number)
AS MLE MODULE js_sql_mod
SIGNATURE 'queryExample(number)';
/
Provided the defaults are still in place, invoking
p_js_sql_query_ex
displays the following:
SQL> set serveroutput on
SQL> EXEC p_js_sql_query_ex(103)
The query found a row:
manager_id: 103
department_id: 60
department_name: IT
See Also:
Server-Side JavaScript API
Documentation for more information about the built-in JavaScript
modules, including mle-js-oracledb
Example 7-2 Use Global Variables to Simplify SQL Execution
Example 7-1 can be greatly simplified for use with MLE. Variables injected into the global scope
can be referenced, eliminating the need to import the
mle-js-oracledb
module. Additionally, because only a single
function is defined in the module, an inline call specification saves even more
typing.
CREATE OR REPLACE PROCEDURE js_sql_mod_simplified(
"managerID" number
) AS MLE LANGUAGE JAVASCRIPT
{{
if (managerID === undefined || managerID === null){
throw new Error (
"Parameter managerID has not been provided to js_sql_mod_simplified()"
);
}
const result = session.execute(`
SELECT
manager_id,
department_id,
department_name
FROM
hr.departments
WHERE
manager_id = :id`,
[ managerID ]
);
if(result.rows.length > 0){
for(let row of result.rows){
console.log(
`The query found a row:
manager_id: ${row.MANAGER_ID}
department_id: ${row.DEPARTMENT_ID}
department_name: ${row.DEPARTMENT_NAME}`
);
}
} else {
console.log(`no data found for manager ID ${managerID}`);
}
}};
/
Invoking
js_sql_mod_simplified
results in the following
output:SQL> set serveroutput on
SQL> exec js_sql_mod_simplified(100);
The query found a row:
manager_id: 100
department_id: 90
department_name: Executive
Parent topic: Introduction to the MLE JavaScript SQL Driver
Processing Comparison Between node-oracledb and mle-js-oracledb
The node-oracledb
documentation recommends the use of the
async/await interface. Due to the nature of client-server interactions, most of the
processing involved between node and the database is executed asynchronously.
The MLE JavaScript driver does not require asynchronous processing. Like the PL/SQL driver, this is thanks to the driver's location within the database. The MLE JavaScript driver understands the async/await syntax, however, it processes requests synchronously under the hood.
Unlike the node-oracledb
driver, the MLE JavaScript SQL driver returns rows as objects
(oracledb.OUT_FORMAT_OBJECT
) rather than arrays
(oracledb.OUTFORMAT_ARRAY
) when using the ECMAScript 2023 syntax.
Code still relying on the deprecated require
syntax remains backwards
compatible by returning rows as an array.
Note:
A promise-based interface is not provided with the MLE JavaScript driver.Parent topic: Introduction to the MLE JavaScript SQL Driver