/* Copyright (c) 2019, 2023, Oracle and/or its affiliates. */ /****************************************************************************** * * This software is dual-licensed to you under the Universal Permissive License * (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License * 2.0 as shown at https://www.apache.org/licenses/LICENSE-2.0. You may choose * either license. * * If you elect to accept the software under the Apache License, Version 2.0, * the following applies: * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * NAME * 208. dbObject9.js * * DESCRIPTION * REF Cursors and Implicit Results that fetch DbObjects. * *****************************************************************************/ 'use strict'; const oracledb = require('oracledb'); const assert = require('assert'); const dbConfig = require('./dbconfig.js'); const testsUtil = require('./testsUtil.js'); describe('208. dbObject9.js', function() { let isRunnable = false; let conn; const TYPE = 'NODB_PERSON_T'; const TABLE = 'NODB_TAB_EMPLOYEES'; const PEOPLE = [ { ID: 123, NAME: 'Alice', GENDER: 'Female' }, { ID: 234, NAME: 'Bob', GENDER: 'Male' }, { ID: 345, NAME: 'Charlie', GENDER: 'Male' }, { ID: 456, NAME: 'Dolores', GENDER: 'Female' } ]; before(async function() { isRunnable = await testsUtil.checkPrerequisites(); if (!isRunnable) { this.skip(); return; } else { conn = await oracledb.getConnection(dbConfig); let sql = `CREATE OR REPLACE TYPE ${TYPE} AS OBJECT ( id NUMBER, name VARCHAR2(30), gender VARCHAR2(20) );`; await conn.execute(sql); sql = `CREATE TABLE ${TABLE} ( empnum NUMBER, person ${TYPE} )`; const plsql = testsUtil.sqlCreateTable(TABLE, sql); await conn.execute(plsql); const PersonType = await conn.getDbObjectClass(TYPE); const bindArr = []; for (let i = 0, num, p; i < PEOPLE.length; i++) { num = i + 1; p = new PersonType(PEOPLE[i]); bindArr[i] = [num, p]; } const opts = { autoCommit: true, bindDefs: [ { type: oracledb.NUMBER }, { type: PersonType } ] }; const result = await conn.executeMany( `INSERT INTO ${TABLE} VALUES (:1, :2)`, bindArr, opts ); assert.strictEqual(result.rowsAffected, PEOPLE.length); } }); // before() after(async function() { if (!isRunnable) { return; } else { let sql = `DROP TABLE ${TABLE} PURGE`; await conn.execute(sql); sql = `DROP TYPE ${TYPE}`; await conn.execute(sql); await conn.close(); } }); // after() it('208.1 REF cursors that fetch object', async () => { const PROC = 'nodb_proc_getemp'; let plsql = ` CREATE OR REPLACE PROCEDURE ${PROC} (p_out OUT SYS_REFCURSOR) AS BEGIN OPEN p_out FOR SELECT * FROM ${TABLE}; END; `; await conn.execute(plsql); plsql = `BEGIN ${PROC}(:out); END;`; const opts = { out: { dir: oracledb.BIND_OUT, type: oracledb.DB_TYPE_CURSOR } }; const result = await conn.execute(plsql, opts); // Fetch rows from ResultSet const RS = result.outBinds.out; const rows = await RS.getRows(PEOPLE.length); for (let i = 0; i < PEOPLE.length; i++) { assert.deepStrictEqual(rows[i][1]._toPojo(), PEOPLE[i]); assert.strictEqual(JSON.stringify(rows[i][1]), JSON.stringify(PEOPLE[i])); } await RS.close(); const sql = `DROP PROCEDURE ${PROC}`; await conn.execute(sql); }); // 208.1 const queryImpres = ` DECLARE c SYS_REFCURSOR; BEGIN OPEN c FOR SELECT * FROM ${TABLE}; DBMS_SQL.RETURN_RESULT(C); END; `; it('208.2 Implicit results that fetch objects', async function() { if (dbConfig.test.isCmanTdm) this.skip(); const result = await conn.execute(queryImpres); const rows = result.implicitResults[0]; for (let i = 0; i < PEOPLE.length; i++) { assert.deepStrictEqual(rows[i][1]._toPojo(), PEOPLE[i]); assert.strictEqual(JSON.stringify(rows[i][1]), JSON.stringify(PEOPLE[i])); } }); // 208.2 it('208.3 Implicit results that fetch objects with Result Set', async function() { if (dbConfig.test.isCmanTdm) this.skip(); const result = await conn.execute(queryImpres, [], { resultSet: true}); const rows = await result.implicitResults[0].getRows(PEOPLE.length); for (let i = 0; i < PEOPLE.length; i++) { assert.deepStrictEqual(rows[i][1]._toPojo(), PEOPLE[i]); assert.strictEqual(JSON.stringify(rows[i][1]), JSON.stringify(PEOPLE[i])); } }); // 208.3 it('208.4 DML RETURNING INTO, explicit bind type', async () => { const PersonType = await conn.getDbObjectClass(TYPE); const staff = { ID: 1123, NAME: 'Changjie', GENDER: 'Male' }; const staffNo = 23; const p = new PersonType(staff); const sql = `INSERT INTO ${TABLE} VALUES (:1, :2) RETURNING empnum, person INTO :3, :4`; const bindVar = [ staffNo, { type: PersonType, val: p }, { dir: oracledb.BIND_OUT, type: oracledb.DB_TYPE_NUMBER }, { dir: oracledb.BIND_OUT, type: PersonType } ]; const result = await conn.execute(sql, bindVar); assert.strictEqual(result.rowsAffected, 1); assert.strictEqual(result.outBinds[0][0], staffNo); assert.deepStrictEqual( result.outBinds[1][0]._toPojo(), staff ); }); // 208.4 it('208.5 DML RETURNING INTO, implicit bind type', async () => { const PersonType = await conn.getDbObjectClass(TYPE); const staff = { ID: 23456, NAME: 'Chris', GENDER: 'Male' }; const staffNo = 101; const p = new PersonType(staff); const sql = `INSERT INTO ${TABLE} VALUES (:1, :2) RETURNING empnum, person INTO :3, :4`; const bindVar = [ staffNo, p, { dir: oracledb.BIND_OUT, type: oracledb.DB_TYPE_NUMBER }, { dir: oracledb.BIND_OUT, type: PersonType } ]; const result = await conn.execute(sql, bindVar); assert.strictEqual(result.rowsAffected, 1); assert.strictEqual(result.outBinds[0][0], staffNo); assert.deepStrictEqual( result.outBinds[1][0]._toPojo(), staff ); }); // 208.5 it('208.6 DML RETURNING INTO, bind by named values', async () => { const PersonType = await conn.getDbObjectClass(TYPE); const staff = { ID: 789, NAME: 'Shelly', GENDER: 'Female' }; const staffNo = 102; const p = new PersonType(staff); const sql = `INSERT INTO ${TABLE} VALUES (:n, :i) RETURNING empnum, person INTO :o1, :o2`; const bindVar = { n: staffNo, i: p, o1: { dir: oracledb.BIND_OUT, type: oracledb.DB_TYPE_NUMBER }, o2: { dir: oracledb.BIND_OUT, type: PersonType } }; const result = await conn.execute(sql, bindVar); assert.strictEqual(result.rowsAffected, 1); assert.strictEqual(result.outBinds.o1[0], staffNo); assert.deepStrictEqual( result.outBinds.o2[0]._toPojo(), staff ); }); // 208.6 it.skip('208.7 DML RETURNING INTO and executeMany()', async () => { const PersonType = await conn.getDbObjectClass(TYPE); const staffs = [ { ID: 7001, NAME: 'Emma', GENDER: 'Female' }, { ID: 7002, NAME: 'Ashley', GENDER: 'Female' }, { ID: 7003, NAME: 'Alexanda', GENDER: 'Male' }, ]; const staffNo = [201, 202, 203]; const bindArr = []; for (let i = 0, num, p; i < staffs.length; i++) { num = staffNo[i]; p = new PersonType(staffs[i]); bindArr[i] = [num, p]; } const opts = { autoCommit: true, bindDefs: [ { type: oracledb.NUMBER }, { type: PersonType }, { dir: oracledb.BIND_OUT, type: oracledb.DB_TYPE_NUMBER }, { dir: oracledb.BIND_OUT, type: PersonType } ] }; const result = await conn.executeMany( `INSERT INTO ${TABLE} VALUES (:1, :2) RETURNING empnum, person INTO :3, :4`, bindArr, opts ); console.log("==== Result of RETURNING INTO ========"); for (let i = 0; i < staffs.length; i++) { console.log(result.outBinds[i]); } console.log(); console.log("==== Result in table ========"); const res = await conn.execute(`SELECT * FROM ${TABLE} WHERE empnum > 200 AND empnum < 205`); console.log(res); }); // 208.7 });