487 lines
16 KiB
JavaScript
487 lines
16 KiB
JavaScript
/* Copyright (c) 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
|
|
* 271. fetchTypeHandler.js
|
|
*
|
|
* DESCRIPTION
|
|
* Testing driver fetchTypeHandler feature.
|
|
*
|
|
*****************************************************************************/
|
|
'use strict';
|
|
|
|
const oracledb = require('oracledb');
|
|
const assert = require('assert');
|
|
const dbConfig = require('./dbconfig.js');
|
|
const testsUtil = require(`./testsUtil.js`);
|
|
|
|
describe('271. fetchTypeHandler.js', function() {
|
|
|
|
let connection = null;
|
|
before('Get connection', async function() {
|
|
connection = await oracledb.getConnection(dbConfig);
|
|
});
|
|
|
|
after('Release connection', async function() {
|
|
await connection.close();
|
|
});
|
|
|
|
afterEach('Reset oracledb.fetchTypeHandler property', function() {
|
|
oracledb.fetchTypeHandler = undefined;
|
|
});
|
|
|
|
it('271.1 Property value check', async function() {
|
|
const myFetchTypeHandler = function() {
|
|
return {converter: (val) => val.toString()};
|
|
};
|
|
|
|
oracledb.fetchTypeHandler = myFetchTypeHandler;
|
|
const sql = `select 1+1 from dual`;
|
|
const result = await connection.execute(sql);
|
|
assert.strictEqual(result.rows[0][0], '2');
|
|
});
|
|
|
|
it('271.2 invalid syntax for "type" should result in error', async function() {
|
|
oracledb.fetchTypeHandler = function() {
|
|
return {'hello' : oracledb.STRING};
|
|
};
|
|
const result = await connection.execute(`SELECT 1+1 FROM DUAL`);
|
|
assert.strictEqual(result.rows[0][0], 2);
|
|
});
|
|
|
|
it('271.3 value attribute "type" must be a valid database type', async function() {
|
|
oracledb.fetchTypeHandler = function() {
|
|
return {type : oracledb.BIND_IN};
|
|
};
|
|
|
|
await assert.rejects(
|
|
async () => {
|
|
await connection.execute(
|
|
"SELECT SYSDATE AS THE_DATE FROM DUAL");
|
|
},
|
|
// NJS-121: fetchTypeHandler return value attribute "type" must be a valid database type
|
|
/NJS-121:/
|
|
);
|
|
});
|
|
|
|
it('271.4 attribute "converter" must be a function', async function() {
|
|
const myFetchTypeHandler = function() {
|
|
return {converter: oracledb.STRING};
|
|
};
|
|
|
|
oracledb.fetchTypeHandler = myFetchTypeHandler;
|
|
const sql = `select 1+1 from dual`;
|
|
await assert.rejects(
|
|
async () => await connection.execute(sql),
|
|
/NJS-122:/ //NJS-122: fetchTypeHandler return value attribute "converter" must be a function
|
|
);
|
|
});
|
|
|
|
it('271.5 FetchTypeHandler return value attribute "converter" must be a function', async function() {
|
|
const myFetchTypeHandler = function() {
|
|
return {converter: 5};
|
|
};
|
|
|
|
oracledb.fetchTypeHandler = myFetchTypeHandler;
|
|
const sql = `select 1+1 from dual`;
|
|
await assert.rejects(
|
|
async () => await connection.execute(sql),
|
|
/NJS-122:/ //NJS-122: fetchTypeHandler return value attribute "converter" must be a function
|
|
);
|
|
});
|
|
|
|
it('271.6 fetchTypeHandler return value must be an object', async function() {
|
|
oracledb.fetchTypeHandler = function() {
|
|
return 2;
|
|
};
|
|
const sql = `select 1+1 from dual`;
|
|
await assert.rejects(
|
|
async () => await connection.execute(sql),
|
|
/NJS-120:/ //NJS-120: fetchTypeHandler return value must be an object
|
|
);
|
|
});
|
|
|
|
it('271.7 Not supported database type conversion', async function() {
|
|
oracledb.fetchTypeHandler = function() {
|
|
return {type: oracledb.NUMBER};
|
|
};
|
|
|
|
await assert.rejects(
|
|
async () => await connection.execute("SELECT ROWID from DUAL"),
|
|
/NJS-119:/ //NJS-119: conversion from type DB_TYPE_ROWID to type DB_TYPE_NUMBER is not supported/
|
|
);
|
|
});
|
|
|
|
it('271.8 Fetch number as string', async function() {
|
|
oracledb.fetchTypeHandler = function() {
|
|
return {type: oracledb.STRING};
|
|
};
|
|
|
|
const sql = `select 5, 6 from dual`;
|
|
const result = await connection.execute(sql);
|
|
assert.strictEqual(result.rows[0][0], '5');
|
|
});
|
|
|
|
it('271.9 Fetch DATE column values as STRING - by-Column name', async function() {
|
|
oracledb.fetchTypeHandler = function() {
|
|
return {type: oracledb.STRING};
|
|
};
|
|
|
|
let result = await connection.execute(
|
|
"SELECT TO_DATE('2005-01-06', 'YYYY-DD-MM') AS TS_DATE FROM DUAL",
|
|
[],
|
|
{
|
|
outFormat: oracledb.OUT_FORMAT_OBJECT
|
|
}
|
|
);
|
|
assert.strictEqual(typeof result.rows[0].TS_DATE, "string");
|
|
});
|
|
|
|
it('271.10 fetchTypeHandler will take precedence over fetchInfo', async function() {
|
|
await connection.execute("alter session set time_zone = '+0:00'");
|
|
oracledb.fetchTypeHandler = function(metadata) {
|
|
if (metadata.dbTypeName === "TIMESTAMP") {
|
|
return {type: oracledb.DATE};
|
|
}
|
|
return {type: oracledb.NUMBER};
|
|
};
|
|
|
|
const result = await connection.execute(
|
|
"SELECT 1234567 AS TS_NUM, TO_TIMESTAMP('1999-12-01 11:10:01.00123', 'YYYY-MM-DD HH:MI:SS.FF') AS TS_DATE FROM DUAL",
|
|
[],
|
|
{
|
|
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
|
fetchInfo:
|
|
{
|
|
"TS_DATE" : { type : oracledb.STRING },
|
|
"TS_NUM" : { type : oracledb.STRING }
|
|
}
|
|
});
|
|
assert.deepEqual(result.rows[0].TS_DATE, new Date('1999-12-01T11:10:01.001Z'));
|
|
assert.strictEqual(typeof result.rows[0].TS_NUM, 'number');
|
|
assert.strictEqual(result.rows[0].TS_NUM, 1234567);
|
|
});
|
|
|
|
it('271.11 fetchInfo will take precedence over fetchTypeHandler when "undefined" returned', async function() {
|
|
await connection.execute("alter session set time_zone = '+0:00'");
|
|
oracledb.fetchTypeHandler = function() {
|
|
return undefined;
|
|
};
|
|
|
|
const result = await connection.execute(
|
|
"SELECT 1234567 AS TS_NUM, TO_TIMESTAMP('1999-12-01 11:10:01.00123', 'YYYY-MM-DD HH:MI:SS.FF') AS TS_DATE FROM DUAL",
|
|
[],
|
|
{
|
|
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
|
fetchInfo :
|
|
{
|
|
"TS_DATE" : { type : oracledb.DEFAULT },
|
|
"TS_NUM" : { type : oracledb.STRING }
|
|
}
|
|
});
|
|
assert.deepEqual(result.rows[0].TS_DATE, new Date('1999-12-01T11:10:01.001Z'));
|
|
assert.strictEqual(typeof result.rows[0].TS_NUM, 'string');
|
|
assert.strictEqual(result.rows[0].TS_NUM, '1234567');
|
|
});
|
|
|
|
it('271.12 Fetch DATE, NUMBER column values STRING - by Column-name', async function() {
|
|
await connection.execute("alter session set time_zone = '+0:00'");
|
|
oracledb.fetchTypeHandler = function() {
|
|
return {type: oracledb.STRING};
|
|
};
|
|
let result = await connection.execute(
|
|
"SELECT 1234567 AS TS_NUM, TO_TIMESTAMP('1999-12-01 11:10:01.00123', 'YYYY-MM-DD HH:MI:SS.FF') AS TS_DATE FROM DUAL",
|
|
[],
|
|
{
|
|
outFormat: oracledb.OUT_FORMAT_OBJECT
|
|
}
|
|
);
|
|
assert.strictEqual(typeof result.rows[0].TS_DATE, "string");
|
|
assert.strictEqual(typeof result.rows[0].TS_NUM, "string");
|
|
assert.strictEqual(Number(result.rows[0].TS_NUM), 1234567);
|
|
});
|
|
|
|
it('271.13 Fetch DATE, NUMBER column as STRING by-type and override at execute time', async function() {
|
|
oracledb.fetchTypeHandler = function(metadata) {
|
|
if (metadata.dbType === oracledb.DB_TYPE_DATE) {
|
|
return {type: oracledb.DATE};
|
|
}
|
|
return {type: oracledb.NUMBER};
|
|
};
|
|
|
|
const myFetchTypeHandler = function() {
|
|
return { type : oracledb.STRING };
|
|
};
|
|
|
|
const options = {fetchTypeHandler: myFetchTypeHandler};
|
|
let result = await connection.execute(
|
|
"SELECT 1234567 AS TS_NUM, TO_DATE('1999-12-01', 'YYYY-MM-DD') AS TS_DATE FROM DUAL",
|
|
[],
|
|
options
|
|
);
|
|
assert.strictEqual(result.rows[0][0], '1234567');
|
|
assert.strictEqual(typeof result.rows[0][1], "string");
|
|
});
|
|
|
|
it('271.14 Fetch DATE, NUMBER column as STRING by-type with converter', async function() {
|
|
oracledb.fetchTypeHandler = function(metadata) {
|
|
if (metadata.dbType === oracledb.DB_TYPE_DATE) {
|
|
const myConverter = (v) => {
|
|
const year = v.getUTCFullYear();
|
|
const month = ("0" + (v.getUTCMonth() + 1)).slice(-2); // Add leading zero if needed
|
|
const day = ("0" + v.getUTCDate()).slice(-2); // Add leading zero if needed
|
|
const formattedDate = `${year}-${month}-${day}`;
|
|
return formattedDate;
|
|
};
|
|
return {converter: myConverter};
|
|
}
|
|
return {type: oracledb.NUMBER};
|
|
};
|
|
|
|
let result = await connection.execute(
|
|
"SELECT 1234567 AS TS_NUM, TO_DATE('1999-12-01', 'YYYY-MM-DD') AS TS_DATE FROM DUAL"
|
|
);
|
|
assert.strictEqual(result.rows[0][0], 1234567);
|
|
assert.strictEqual(result.rows[0][1], "1999-12-01");
|
|
});
|
|
|
|
it('271.15 Negative cases', async function() {
|
|
const array = ['', null, NaN, 10, 'abc', [], oracledb.DATE];
|
|
await Promise.all(array.map(function(element) {
|
|
assert.throws(() => oracledb.fetchTypeHandler = element,
|
|
/NJS-004:/ //NJS-004: invalid value for property fetchTypeHandler
|
|
);
|
|
}));
|
|
});
|
|
|
|
|
|
it('271.16 Padding numeric values with leading zeroes', async function() {
|
|
oracledb.fetchTypeHandler = function(metadata) {
|
|
if (metadata.name.endsWith("Id")) {
|
|
const myConverter = (v) => {
|
|
if (v !== null)
|
|
v = v.padStart(9, "0");
|
|
return v;
|
|
};
|
|
return {type: oracledb.DB_TYPE_VARCHAR, converter: myConverter};
|
|
}
|
|
};
|
|
const sql = `select 5 as "MyId", 6 as "MyValue", 'A string' as "MyString" from dual`;
|
|
const result = await connection.execute(sql);
|
|
|
|
assert.strictEqual(result.metaData[0].name, 'MyId');
|
|
assert.deepEqual(result.rows, [ [ '000000005', 6, 'A string' ] ]);
|
|
});
|
|
|
|
it('271.17 converting dates to use the requested locale-specific format', async function() {
|
|
const myFetchTypeHandler = function(metadata) {
|
|
if (metadata.dbType === oracledb.DB_TYPE_DATE) {
|
|
const myConverter = (v) => {
|
|
if (v !== null) {
|
|
v = v.toLocaleString('fr');
|
|
}
|
|
return v;
|
|
};
|
|
return {converter: myConverter};
|
|
}
|
|
};
|
|
const sql = `select sysdate from dual`;
|
|
const binds = [];
|
|
const options = {fetchTypeHandler: myFetchTypeHandler};
|
|
const result = await connection.execute(sql, binds, options);
|
|
assert.strictEqual(typeof result.rows[0][0], 'string');
|
|
});
|
|
|
|
it('271.18 getting JSON data', async function() {
|
|
if (connection.oracleServerVersion < 2100000000 || testsUtil.getClientVersion() < 2100000000) {
|
|
this.skip();
|
|
}
|
|
const TABLE = 'jsondata';
|
|
oracledb.fetchTypeHandler = function() {
|
|
const myConverter = (v) => {
|
|
v.empId = 10;
|
|
return v;
|
|
};
|
|
return {converter: myConverter};
|
|
};
|
|
|
|
const createTable = (`CREATE TABLE ${TABLE} (
|
|
obj_data JSON
|
|
)
|
|
`);
|
|
const plsql = testsUtil.sqlCreateTable(TABLE, createTable);
|
|
await connection.execute(plsql);
|
|
|
|
const sql = `INSERT into ${TABLE} VALUES ('{"empId": 1, "empName": "Employee1", "city": "New City"}')`;
|
|
await connection.execute(sql);
|
|
|
|
const result = await connection.execute(`select * from ${TABLE}`);
|
|
assert.strictEqual(result.rows[0][0]["empId"], 10);
|
|
assert.strictEqual(result.rows[0][0]["empName"], 'Employee1');
|
|
assert.strictEqual(result.rows[0][0]["city"], 'New City');
|
|
await connection.execute(testsUtil.sqlDropTable(TABLE));
|
|
});
|
|
|
|
/*
|
|
* The maximum safe integer in JavaScript is (2^53 - 1).
|
|
* The minimum safe integer in JavaScript is (-(2^53 - 1)).
|
|
* Numbers out of above range will be rounded.
|
|
* The last element is out of Oracle database standard Number range. It will be rounded by database.
|
|
*/
|
|
let numStrs =
|
|
[
|
|
'17249138680355831',
|
|
'-17249138680355831',
|
|
'0.17249138680355831',
|
|
'-0.17249138680355831',
|
|
'0.1724913868035583123456789123456789123456'
|
|
];
|
|
|
|
let numResults =
|
|
[
|
|
'17249138680355831',
|
|
'-17249138680355831',
|
|
'.17249138680355831',
|
|
'-.17249138680355831',
|
|
'.172491386803558312345678912345678912346'
|
|
];
|
|
|
|
it('271.19 large numbers with fetchTypeHandler', async function() {
|
|
oracledb.fetchTypeHandler = function() {
|
|
return {type: oracledb.STRING};
|
|
};
|
|
|
|
for (let element of numStrs) {
|
|
let result = await connection.execute(
|
|
"SELECT TO_NUMBER( " + element + " ) AS TS_NUM FROM DUAL",
|
|
[],
|
|
{
|
|
outFormat : oracledb.OUT_FORMAT_OBJECT
|
|
}
|
|
);
|
|
assert.strictEqual(typeof result.rows[0].TS_NUM, "string");
|
|
assert.strictEqual(result.rows[0].TS_NUM, numResults[numStrs.indexOf(element)]);
|
|
}
|
|
});
|
|
|
|
it('271.20 setting a private property in the metadata', async function() {
|
|
oracledb.fetchTypeHandler = function(metadata) {
|
|
metadata._privateProp = 'I am a private property of ' + metadata.name;
|
|
};
|
|
|
|
const sql = `select 5 as "MyId", 6 as "MyValue", 'A string' as "MyString" from dual`;
|
|
const result = await connection.execute(sql);
|
|
|
|
assert.strictEqual(result.metaData[0]._privateProp, "I am a private property of MyId");
|
|
assert.strictEqual(result.metaData[1]._privateProp, "I am a private property of MyValue");
|
|
assert.strictEqual(result.metaData[2]._privateProp, "I am a private property of MyString");
|
|
});
|
|
|
|
it('271.21 fetchTypeHandler for nulls with converter function', async function() {
|
|
oracledb.fetchTypeHandler = function() {
|
|
const myConverter = (v) => {
|
|
return String(v);
|
|
};
|
|
return {converter: myConverter};
|
|
};
|
|
|
|
const sql = `SELECT NULL FROM DUAL`;
|
|
const result = await connection.execute(sql);
|
|
assert.strictEqual(result.rows[0][0], "null");
|
|
});
|
|
|
|
it('271.22 converter function to convert column val to string', async function() {
|
|
const TABLE = 't';
|
|
const sql = `CREATE TABLE ${TABLE} (n_col NUMBER)`;
|
|
const plsql = testsUtil.sqlCreateTable(TABLE, sql);
|
|
await connection.execute(plsql);
|
|
const inssql = `INSERT INTO ${TABLE} (n_col) VALUES (:bv)`;
|
|
await connection.execute(inssql, { bv: 123 });
|
|
|
|
function fetchTypeHandlerFunc(metadata) {
|
|
if (metadata.dbType === oracledb.DB_TYPE_NUMBER) {
|
|
return {converter: convertToString};
|
|
}
|
|
}
|
|
|
|
function convertToString(val) {
|
|
if (val !== null) {
|
|
val = 'abc';
|
|
}
|
|
return val;
|
|
}
|
|
|
|
const result = await connection.execute(
|
|
`select * from ${TABLE}`,
|
|
[],
|
|
{
|
|
fetchTypeHandler: fetchTypeHandlerFunc,
|
|
outFormat: oracledb.OUT_FORMAT_OBJECT
|
|
}
|
|
);
|
|
|
|
assert.strictEqual(result.rows[0].N_COL, 'abc');
|
|
await connection.execute(testsUtil.sqlDropTable(TABLE));
|
|
});
|
|
|
|
it('271.23 converter function with multiple columns', async function() {
|
|
await connection.execute("alter session set time_zone = '+0:00'");
|
|
|
|
oracledb.fetchTypeHandler = function(metadata) {
|
|
if (metadata.dbTypeName === "TIMESTAMP") {
|
|
return {type: oracledb.DATE};
|
|
} else if (metadata.dbTypeName === "NUMBER") {
|
|
return {type: oracledb.STRING};
|
|
}
|
|
};
|
|
const TABLE = 'my_table';
|
|
const sql = `CREATE TABLE ${TABLE} (
|
|
id NUMBER,
|
|
name VARCHAR2(50),
|
|
age NUMBER,
|
|
created_date TIMESTAMP
|
|
)`;
|
|
const plsql = testsUtil.sqlCreateTable(TABLE, sql);
|
|
await connection.execute(plsql);
|
|
|
|
await connection.execute(`INSERT INTO ${TABLE} values (01, 'ABC', 23,
|
|
TO_TIMESTAMP('2023-04-27 10:30:00', 'YYYY-MM-DD HH24:MI:SS'))`);
|
|
const result = await connection.execute(
|
|
`SELECT id, name, age,
|
|
created_date AS TS_DATE FROM ${TABLE}`,
|
|
[],
|
|
{
|
|
outFormat: oracledb.OUT_FORMAT_OBJECT
|
|
}
|
|
);
|
|
|
|
assert.deepEqual(Object.getOwnPropertyNames(result.rows[0]), ["ID", "NAME", "AGE", "TS_DATE"]);
|
|
assert.deepEqual(result.rows[0].ID, "1");
|
|
assert.deepEqual(result.rows[0].NAME, "ABC");
|
|
assert.deepEqual(result.rows[0].AGE, "23");
|
|
assert.deepEqual(result.rows[0].TS_DATE, new Date('2023-04-27T10:30:00.000Z'));
|
|
await connection.execute(testsUtil.sqlDropTable(TABLE));
|
|
});
|
|
});
|