@types/oracledb - Make DBObject class generic (#45239)

* Allow undefined bind parameters

* Upgrading oracledbto 4.1

* Update version number

* Fix tsconfig typo

* Make DBObject generic

* increase min ts version to 3.5
This commit is contained in:
Connor Fitzgerald 2020-06-24 10:24:07 +01:00 committed by GitHub
parent 30813acabc
commit ebd3d903b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 205 additions and 92 deletions

View File

@ -3,7 +3,7 @@
// Definitions by: Richard Natal <https://github.com/Bigous>
// Connor Fitzgerald <https://github.com/connorjayfitzgerald>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 3.2
// TypeScript Version: 3.5
/// <reference types="node" />
@ -592,7 +592,7 @@ declare namespace OracleDB {
*
* @see https://oracle.github.io/node-oracledb/doc/api.html#executebindParams
*/
type BindParameters = Record<string, BindParameter | string | number | Date | DBObject | Buffer | null | undefined> | BindParameter[] | any[];
type BindParameters = Record<string, BindParameter | string | number | Date | DBObject_IN<any> | Buffer | null | undefined> | BindParameter[] | any[];
interface CloseConnectionOptions {
/**
@ -925,21 +925,21 @@ declare namespace OracleDB {
* @see https://oracle.github.io/node-oracledb/doc/api.html#objects
* @since 4.0
*/
getDbObjectClass(className: string): Promise<DBObjectClass>;
getDbObjectClass(
getDbObjectClass<T>(className: string): Promise<DBObjectClass<T>>;
getDbObjectClass<T>(
className: string,
callback: (error: DBError, dbObject: DBObjectClass) => void
callback: (error: DBError, dbObject: DBObjectClass<T>) => void
): void;
getQueue(name: string, options?: GetAdvancedQueueOptions): Promise<AdvancedQueue>;
getQueue(
getQueue<T>(name: string, options?: GetAdvancedQueueOptions): Promise<AdvancedQueue<T>>;
getQueue<T>(
name: string,
callback: (error: DBError, queue: AdvancedQueue) => void
callback: (error: DBError, queue: AdvancedQueue<T>) => void
): void;
getQueue(
getQueue<T>(
name: string,
options: GetAdvancedQueueOptions,
callback: (error: DBError, queue: AdvancedQueue) => void
callback: (error: DBError, queue: AdvancedQueue<T>) => void
): void;
/**
@ -1207,11 +1207,11 @@ declare namespace OracleDB {
/**
* Result of connection.getStatementInfo().
*/
interface StatementInfo {
interface StatementInfo<T = {}> {
/** Array of strings corresponding to the unique names of the bind variables used in the SQL statement. */
bindNames?: string[];
/** Extended metadata properties. */
metaData?: Array<Metadata>;
metaData?: Array<Metadata<T>>;
/** One of the SQL Statement Type Constants. */
statementType?: number;
}
@ -1572,7 +1572,7 @@ declare namespace OracleDB {
/**
* Included in the result of a query execution to describe details of the columns involved.
*/
interface Metadata {
interface Metadata<T> {
/**
* The column name follows Oracles standard name-casing rules. It will commonly be uppercase,
* since most applications create tables using unquoted, case-insensitive names.
@ -1593,7 +1593,7 @@ declare namespace OracleDB {
/**
* The class associated with the database type. This is only set if the database type is an object type.
*/
dbTypeClass?: DBObjectClass;
dbTypeClass?: DBObjectClass<T>;
/**
* Name of the database type, such as NUMBER or VARCHAR2. For object types, this will be the object name.
*/
@ -1962,7 +1962,7 @@ declare namespace OracleDB {
* @see https://oracle.github.io/node-oracledb/doc/api.html#aq
* @since 4.0
*/
interface AdvancedQueue {
interface AdvancedQueue<T> {
/** Contains the name of the queue specified in the connection.getQueue() call. */
readonly name: string;
/** Options to use when dequeuing messages. Attributes can be set before each queue.deqOne() or queue.deqMany(). */
@ -1976,7 +1976,7 @@ declare namespace OracleDB {
*
* This is defined only if payloadType has the value oracledb.DB_TYPE_OBJECT.
*/
readonly payloadTypeClass?: DBObjectClass;
readonly payloadTypeClass?: DBObjectClass<T>;
/** Either the string “RAW” or the name of the Oracle Database object type identified when the queue was created. */
readonly payloadTypeName: string;
@ -1985,14 +1985,14 @@ declare namespace OracleDB {
*
* @param maxMessages Maximum number of messages to dequeue.
*/
deqMany(maxMessages: number): Promise<AdvancedQueueMessage[]>;
deqMany(maxMessages: number, callback: (error: DBError, messages: AdvancedQueueMessage[]) => void): void;
deqMany(maxMessages: number): Promise<AdvancedQueueMessage<T>[]>;
deqMany(maxMessages: number, callback: (error: DBError, messages: AdvancedQueueMessage<T>[]) => void): void;
/**
* Dequeues a single message. Depending on the dequeue options, the message may also be returned as undefined if no message is available.
*/
deqOne(): Promise<AdvancedQueueMessage | undefined>;
deqOne(callback: (error: DBError, message?: AdvancedQueueMessage) => void): void;
deqOne(): Promise<AdvancedQueueMessage<T> | undefined>;
deqOne(callback: (error: DBError, message?: AdvancedQueueMessage<T>) => void): void;
/**
* Enqueues multiple messages.
@ -2003,19 +2003,19 @@ declare namespace OracleDB {
*
* @param messages Messages to enqueue.
*/
enqMany(messages: EnqueueMessage[]): Promise<void>;
enqMany(messages: EnqueueMessage[], callback: (error: DBError) => void): void;
enqMany(messages: EnqueueMessage<T>[]): Promise<void>;
enqMany(messages: EnqueueMessage<T>[], callback: (error: DBError) => void): void;
/**
* Enqueues a single message.
*
* @param message
*/
enqOne(message: EnqueueMessage): Promise<void>;
enqOne(message: EnqueueMessage, callback: (error: DBError) => void): void;
enqOne(message: EnqueueMessage<T>): Promise<void>;
enqOne(message: EnqueueMessage<T>, callback: (error: DBError) => void): void;
}
type EnqueueMessage = string | Buffer | DBObject | {
type EnqueueMessage<T> = string | Buffer | DBObject_IN<T> | {
/** Correlation that was used during enqueue. */
correlation: string;
/** Number of seconds the message was delayed before it could be dequeued. */
@ -2027,7 +2027,7 @@ declare namespace OracleDB {
/** Contains the payload of the message, with type depending on the value of queue.payloadType.
* Note that enqueued Strings are returned as UTF-8 encoded Buffers.
*/
payload: Buffer | DBObject;
payload: string | Buffer | DBObject_IN<T>;
/** Priority of the message when it was enqueued. */
priority: number;
}
@ -2036,13 +2036,29 @@ declare namespace OracleDB {
* @see https://oracle.github.io/node-oracledb/doc/api.html#objects
* @since 4.0
*/
interface DBObjectClass { new(data: Record<string, any>): DBObject }
interface DBObjectClass<T> { new(data?: T): DBObject_IN<T> }
/**
* @see https://oracle.github.io/node-oracledb/doc/api.html#objects
* @since 4.0
*/
class DBObject {
type DBObject_IN<T> = {
[P in keyof T]: T[P]
} & BaseDBObject<T>;
/**
* @see https://oracle.github.io/node-oracledb/doc/api.html#objects
* @since 4.0
*/
type DBObject_OUT<T> = {
[P in keyof T]: DBObject_OUT<T[P]>
} & BaseDBObject<T>;
/**
* @see https://oracle.github.io/node-oracledb/doc/api.html#objects
* @since 4.0
*/
interface BaseDBObject<T> {
/**
* When dbObject.isCollection is false, this will be an object containing attributes corresponding to the Oracle Database object attributes.
*/
@ -2052,11 +2068,11 @@ declare namespace OracleDB {
/** Type, such as 'VARCHAR2' or 'NUMBER'. */
typeName: string;
/** Set if the value of type is a DBObject. */
typeClass?: DBObjectClass;
typeClass?: DBObjectClass<T>;
}>;
/** When dbObject.isCollection is true, this will be one of the DB_TYPE constants. */
readonly elementType: number;
readonly elementTypeClass: DBObjectClass;
readonly elementTypeClass: DBObjectClass<T>;
/** When dbObject.isCollection is true, this will have the name of the element type, such as “VARCHAR2” or “NUMBER”. */
readonly elementTypeName: string;
/** The fully qualified name of the Oracle Database object or collection. */
@ -2070,16 +2086,14 @@ declare namespace OracleDB {
/** Schema owning the Oracle Database object or collection. */
readonly schema: string;
[key: string]: any;
/**
* Add the given value to the end of the collection.
*/
append(value: any): void;
append(value: T): void;
/**
* Deletes the value from collection at the given index.
*/
deleteElement(index: number): void;
deleteElement(index: number): void;
/**
* Return the value associated with the given index.
*/
@ -2090,8 +2104,8 @@ declare namespace OracleDB {
getFirstIndex(): number;
/**
* Returns a JavaScript array containing the index keys.
*/
getKeys(): string[];
*/
getKeys(): T extends string | number ? number[] : (keyof T)[]
/**
* To obtain the last index for later use to obtain a value.
*/
@ -2111,11 +2125,11 @@ declare namespace OracleDB {
/**
* To set the given value at the position of the given index.
*/
setElement(index: number, value: any): void;
setElement(index: number, value: T): void;
/**
* Returns an array of element values as a JavaScript array in key order.
*/
getValues(): any[];
*/
getValues(): T[];
/**
* Trims the specified number of elements from the end of the collection.
*/
@ -2127,7 +2141,7 @@ declare namespace OracleDB {
*
* @since 4.0
*/
interface AdvancedQueueMessage {
interface AdvancedQueueMessage<T> {
/** Correlation that was used during enqueue. */
correlation: string;
/** Number of seconds the message was delayed before it could be dequeued. */
@ -2147,7 +2161,7 @@ declare namespace OracleDB {
/** Contains the payload of the message, with type depending on the value of queue.payloadType.
* Note that enqueued Strings are returned as UTF-8 encoded Buffers.
*/
payload: Buffer | DBObject;
payload: Buffer | DBObject_OUT<T>;
/** Priority of the message when it was enqueued. */
priority: number;
/** State of the message. It can be any one of the AQ_MSG_STATE constants. */
@ -2219,7 +2233,7 @@ declare namespace OracleDB {
* Each columns name is always given. If the oracledb.extendedMetaData or execute() option extendedMetaData
* are true then additional information is included.
*/
metaData?: Metadata[];
metaData?: Metadata<T>[];
/**
* This contains the output values of OUT and IN OUT binds. If bindParams is passed as an array,
* then outBinds is returned as an array. If bindParams is passed as an object,
@ -2311,7 +2325,7 @@ declare namespace OracleDB {
* Each columns name is always given. If the oracledb.extendedMetaData or execute() option
* extendedMetaData are true then additional information is included.
*/
readonly metaData: Metadata[];
readonly metaData: Metadata<T>[];
/**
* Closes a ResultSet. Applications should always call this at the end of fetch or when no more rows are needed.

View File

@ -58,7 +58,7 @@ const testBreak = (connection: oracledb.Connection): Promise<void> =>
setTimeout((): void => {
console.log('Testing connection.execute()...');
connection.break().then((): void => {});
connection.break().then((): void => { });
}, 1000);
},
);
@ -314,6 +314,87 @@ interface One {
one: string;
}
const dbObjectTests = async () => {
const conn = await oracledb.getConnection();
interface Test {
COLUMN1: string;
COLUMN2: string;
}
const TestClass = await conn.getDbObjectClass<Test>('test')
const test1 = new TestClass({
COLUMN1: '1234',
COLUMN2: '1234'
})
test1.COLUMN1 = '1234'
TestClass.prototype;
interface Geom {
SDO_GTYPE: number;
SDO_SRID: string | null;
SDO_POINT: string | null;
SDO_ELEM_INFO: number[];
SDO_ORDINATES: number[];
}
const GeomType = await conn.getDbObjectClass<Geom>("MDSYS.SDO_GEOMETRY");
console.log(GeomType.prototype);
const geom = new GeomType();
geom.SDO_GTYPE = 2003;
geom.SDO_GTYPE = 2003;
geom.SDO_SRID = null;
geom.SDO_POINT = null;
geom.SDO_ELEM_INFO = [1, 1003, 3];
geom.SDO_ORDINATES = [1, 1, 5, 7];
geom.getKeys().find((e) => e === 'SDO_ELEM_INFO')
await conn.execute(
`INSERT INTO testgeometry (id, geometry) VALUES (:id, :g)`,
{ id: 1, g: geom }
);
await conn.execute(
`INSERT INTO testgeometry (id, geometry) VALUES (:id, :g)`,
{
id: 1,
g: {
type: "MDSYS.SDO_GEOMETRY",
val: {
SDO_GTYPE: 2003,
SDO_SRID: null,
SDO_POINT: null,
SDO_ELEM_INFO: [1, 1003, 3],
SDO_ORDINATES: [1, 1, 5, 7]
}
}
}
);
interface OutGeom {
SDO_GTYPE: number;
SDO_SRID: string | null;
SDO_POINT: string | null;
SDO_ELEM_INFO: oracledb.DBObject_OUT<number>;
SDO_ORDINATES: oracledb.DBObject_OUT<number>;
}
const result = await conn.execute<oracledb.DBObject_OUT<OutGeom>[]>(`SELECT geometry FROM testgeometry WHERE id = 1`);
const o = result.rows[0][0];
console.log(o.isCollection);
o.getKeys()
o.SDO_ELEM_INFO.getKeys()
console.log(o.SDO_ELEM_INFO.isCollection);
console.log(o.SDO_ELEM_INFO.getKeys().find(e => typeof e === 'number'));
console.log(o.getValues()[0].SDO_ELEM_INFO);
}
const version4Tests = async () => {
console.log(oracledb.OUT_FORMAT_ARRAY, oracledb.OUT_FORMAT_OBJECT);
@ -322,7 +403,7 @@ const version4Tests = async () => {
const connection = await pool.getConnection();
const implicitResults = (await connection.execute<One>(
'SELECT 1 FROM DUAL',
'SELECT 1 FROM DUAL',
)).implicitResults as oracledb.ResultSet<One>[];
(await implicitResults[0].getRow()).one;
@ -330,7 +411,7 @@ const version4Tests = async () => {
await implicitResults[0].close()
const implicitResults2 = (await connection.execute<One>(
'SELECT 1 FROM DUAL',
'SELECT 1 FROM DUAL',
)).implicitResults as One[][];
const results = implicitResults2[0][0];
@ -338,34 +419,32 @@ const version4Tests = async () => {
console.log(results.one);
const GeomType = await connection.getDbObjectClass("MDSYS.SDO_GEOMETRY");
const geom = new GeomType(
{
SDO_GTYPE: 2003,
SDO_SRID: null,
SDO_POINT: null,
SDO_ELEM_INFO: [ 1, 1003, 3 ],
SDO_ORDINATES: [ 1, 1, 5, 7 ]
SDO_GTYPE: 2003,
SDO_SRID: null,
SDO_POINT: null,
SDO_ELEM_INFO: [1, 1003, 3],
SDO_ORDINATES: [1, 1, 5, 7]
}
);
);
geom.attributes = {
geom.attributes = {
STREET_NUMBER: { type: 2, typeName: 'NUMBER' },
LOCATION: {
type: 2023,
typeName: 'MDSYS.SDO_POINT_TYPE',
typeClass: GeomType,
type: 2023,
typeName: 'MDSYS.SDO_POINT_TYPE',
typeClass: GeomType,
}
}
}
new geom.attributes.test.typeClass({});
geom.S_GTYPE = 2003;
await connection.execute(
`INSERT INTO testgeometry (id, geometry) VALUES (:id, :g)`,
{id: 1, g: geom}
);
{ id: 1, g: geom }
);
const sub = await connection.subscribe('test', {
sql: 'test',
@ -375,7 +454,7 @@ const version4Tests = async () => {
});
console.log(sub.regId);
const queue = await connection.getQueue('test', {
payloadType: 'test'
})
@ -406,8 +485,8 @@ const version4Tests = async () => {
const lob = await connection.createLob(2);
await lob.getData();
const plsql = `
const plsql = `
DECLARE
c1 SYS_REFCURSOR;
c2 SYS_REFCURSOR;
@ -429,14 +508,14 @@ const version4Tests = async () => {
result = await connection.execute(plsql, [], { resultSet: true });
for (let i = 0; i < result.implicitResults.length; i++) {
console.log(' Implicit Result Set', i + 1);
const rs = result.implicitResults[i] as oracledb.ResultSet<One>; // get the next ResultSet
let row;
while ((row = await rs.getRow())) {
console.log(' ', row);
}
console.log(' Implicit Result Set', i + 1);
const rs = result.implicitResults[i] as oracledb.ResultSet<One>; // get the next ResultSet
let row;
while ((row = await rs.getRow())) {
console.log(' ', row);
}
await rs.close();
await rs.close();
}
const queueName = "DEMO_RAW_QUEUE";
@ -452,16 +531,36 @@ const version4Tests = async () => {
const message = new queue.payloadTypeClass(
{
NAME: "scott",
ADDRESS: "The Kennel"
NAME: "scott",
ADDRESS: "The Kennel"
}
);
await queue.enqOne(message);
await connection.commit();
);
await queue.enqOne(message);
await connection.commit();
const queue5 = await connection.getQueue(queueName, {payloadType: "DEMOQUEUE.USER_ADDRESS_TYPE"});
const msg5 = await queue.deqOne();
await connection.commit();
const queue5 = await connection.getQueue(queueName, { payloadType: "DEMOQUEUE.USER_ADDRESS_TYPE" });
const msg5 = await queue.deqOne();
await connection.commit();
}
const aqTests = async () => {
const c = await oracledb.getConnection();
interface QueueItem {
test: string;
connor: boolean;
test2: number;
}
const MyClass = await c.getDbObjectClass<QueueItem>('test');
const q = await c.getQueue<QueueItem>('test');
q.enqOne('test');
q.enqOne(new Buffer('test'));
q.enqOne(new MyClass());
const msg = await q.deqOne();
msg.payload
}
interface MyTableRow {
@ -479,7 +578,7 @@ const testGenerics = async () => {
console.log(result.rows[0].firstColumn);
console.log(result.rows[0].secondColumn);
const result2 = await connection.execute<{test: string}>(' BEGIN DO_SOMETHING END;', {
const result2 = await connection.execute<{ test: string }>(' BEGIN DO_SOMETHING END;', {
test: {
dir: oracledb.BIND_OUT,
val: 'something'
@ -498,17 +597,17 @@ const testGenerics = async () => {
const test4point1 = async (): Promise<void> => {
defaultOracledb.poolMaxPerShard = 45;
defaultOracledb.poolMaxPerShard = 45;
await oracledb.createPool({
poolMaxPerShard: 5,
});
await oracledb.createPool({
poolMaxPerShard: 5,
});
const connection = await oracledb.getConnection({
shardingKey: ['TEST', 1234, new Date(), new Buffer('1234')],
superShardingKey: ['TEST', 1234, new Date(), new Buffer('1234')],
});
const connection = await oracledb.getConnection({
shardingKey: ['TEST', 1234, new Date(), new Buffer('1234')],
superShardingKey: ['TEST', 1234, new Date(), new Buffer('1234')],
});
connection.clientInfo = '12345';
connection.dbOp = '12345';
connection.clientInfo = '12345';
connection.dbOp = '12345';
};