web_plsql 0.3.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +8 -8
- package/.eslintignore +3 -3
- package/.eslintrc.js +347 -273
- package/CHANGELOG.md +127 -106
- package/LICENSE +21 -21
- package/README.md +165 -164
- package/examples/apex.js +70 -70
- package/examples/credentials.js +22 -22
- package/examples/oracledb_example.js +30 -30
- package/examples/sample.js +101 -84
- package/examples/sql/doc_table.sql +13 -13
- package/examples/sql/install.sql +31 -31
- package/examples/sql/sample.pkb +223 -223
- package/examples/sql/sample.pks +24 -24
- package/examples/sql/uninstall.sql +5 -5
- package/examples/static/sample.css +25 -25
- package/jest.config.js +204 -0
- package/package.json +85 -109
- package/src/cgi.ts +95 -95
- package/src/config.ts +97 -97
- package/src/errorPage.ts +286 -286
- package/src/fileUpload.ts +126 -132
- package/src/index.ts +65 -66
- package/src/page.ts +275 -277
- package/src/procedure.ts +360 -359
- package/src/procedureError.ts +27 -27
- package/src/request.ts +139 -139
- package/src/requestError.ts +19 -19
- package/src/stream.ts +26 -26
- package/src/trace.ts +194 -193
- package/test/.eslintrc.json +5 -5
- package/test/{cgi.ts → __tests__/cgi.ts} +96 -95
- package/test/{config.ts → __tests__/config.ts} +41 -41
- package/test/__tests__/errorPage.ts +101 -0
- package/test/{oracledb_mock.ts → __tests__/oracledb_mock.ts} +98 -98
- package/test/{server.ts → __tests__/server.ts} +495 -498
- package/test/{stream.ts → __tests__/stream.ts} +21 -21
- package/test/mock/oracledb.ts +85 -85
- package/test/static/static.html +1 -1
- package/tsconfig.json +24 -23
- package/tsconfig.src.json +23 -22
- package/test/errorPage.ts +0 -101
- package/test/mocha.opts +0 -7
- package/tsconfig.test.json +0 -19
package/src/procedureError.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* RequestError
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {environmentType} from './cgi';
|
|
6
|
-
|
|
7
|
-
export class ProcedureError extends Error {
|
|
8
|
-
timestamp: Date;
|
|
9
|
-
environment: environmentType;
|
|
10
|
-
sql: string;
|
|
11
|
-
bind:
|
|
12
|
-
|
|
13
|
-
constructor(message: string, environment: environmentType, sql: string, bind:
|
|
14
|
-
super(message);
|
|
15
|
-
|
|
16
|
-
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
17
|
-
if (Error.captureStackTrace) {
|
|
18
|
-
Error.captureStackTrace(this, ProcedureError);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Custom debugging information
|
|
22
|
-
this.timestamp = new Date();
|
|
23
|
-
this.environment = environment;
|
|
24
|
-
this.sql = sql;
|
|
25
|
-
this.bind = bind;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* RequestError
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {environmentType} from './cgi';
|
|
6
|
+
|
|
7
|
+
export class ProcedureError extends Error {
|
|
8
|
+
timestamp: Date;
|
|
9
|
+
environment: environmentType;
|
|
10
|
+
sql: string;
|
|
11
|
+
bind: unknown;
|
|
12
|
+
|
|
13
|
+
constructor(message: string, environment: environmentType, sql: string, bind: unknown) {
|
|
14
|
+
super(message);
|
|
15
|
+
|
|
16
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
17
|
+
if (Error.captureStackTrace) {
|
|
18
|
+
Error.captureStackTrace(this, ProcedureError);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Custom debugging information
|
|
22
|
+
this.timestamp = new Date();
|
|
23
|
+
this.environment = environment;
|
|
24
|
+
this.sql = sql;
|
|
25
|
+
this.bind = bind;
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/request.ts
CHANGED
|
@@ -1,139 +1,139 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Process the http request
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import util from 'util';
|
|
6
|
-
import oracledb from 'oracledb';
|
|
7
|
-
import {invokeProcedure} from './procedure';
|
|
8
|
-
import {getCGI} from './cgi';
|
|
9
|
-
import {getFiles} from './fileUpload';
|
|
10
|
-
import {RequestError} from './requestError';
|
|
11
|
-
import {Trace} from './trace';
|
|
12
|
-
import express from 'express';
|
|
13
|
-
import {oracleExpressMiddleware$options} from './config';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Process the request
|
|
17
|
-
*
|
|
18
|
-
* @param {express.Request} req - The req object represents the HTTP request.
|
|
19
|
-
* @param {express.Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
|
|
20
|
-
* @param {oracleExpressMiddleware$options} options - the options for the middleware.
|
|
21
|
-
* @param {Promise<oracledb.Pool>} databasePoolPromise - Promise returning a database pool.
|
|
22
|
-
* @param {Trace} trace - Tracing object.
|
|
23
|
-
* returns {Promise<void>} - Promise that resolves when the request has been fullfilled.
|
|
24
|
-
*/
|
|
25
|
-
export async function processRequest(req: express.Request, res: express.Response, options: oracleExpressMiddleware$options, databasePoolPromise: Promise<oracledb.Pool>, trace: Trace): Promise<void> {
|
|
26
|
-
trace.write('processRequest: ENTER');
|
|
27
|
-
|
|
28
|
-
let databasePool;
|
|
29
|
-
let databaseConnection;
|
|
30
|
-
|
|
31
|
-
// wait until the database pool has been allocated
|
|
32
|
-
try {
|
|
33
|
-
databasePool = await databasePoolPromise;
|
|
34
|
-
trace.write('processRequest: Connection pool has been allocated');
|
|
35
|
-
} catch (
|
|
36
|
-
/* istanbul ignore next */
|
|
37
|
-
throw new RequestError(`Unable to create database pool.\n${
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// open database connection
|
|
41
|
-
try {
|
|
42
|
-
databaseConnection = await databasePool.getConnection();
|
|
43
|
-
trace.write('processRequest: Connection has been allocated');
|
|
44
|
-
} catch (
|
|
45
|
-
/* istanbul ignore next */
|
|
46
|
-
throw new RequestError(`Unable to open database connection\n${
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// execute request
|
|
50
|
-
await executeRequest(req, res, options, databaseConnection, trace);
|
|
51
|
-
|
|
52
|
-
// close database connection
|
|
53
|
-
try {
|
|
54
|
-
await databaseConnection.release();
|
|
55
|
-
trace.write('processRequest: Connection has been released');
|
|
56
|
-
} catch (
|
|
57
|
-
/* istanbul ignore next */
|
|
58
|
-
console.error(`Unable to release database connection\n${
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
trace.write('processRequest: EXIT');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Execute the request
|
|
66
|
-
*
|
|
67
|
-
* @param {express.Request} req - The req object represents the HTTP request.
|
|
68
|
-
* @param {express.Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
|
|
69
|
-
* @param {oracleExpressMiddleware$options} options - the options for the middleware.
|
|
70
|
-
* @param {oracledb.Connection} databaseConnection - Database connection.
|
|
71
|
-
* @param {Trace} trace - Tracing object.
|
|
72
|
-
* @returns {Promise<void>} - Promise resolving to th page
|
|
73
|
-
*/
|
|
74
|
-
async function executeRequest(req: express.Request, res: express.Response, options: oracleExpressMiddleware$options, databaseConnection: oracledb.Connection, trace: Trace): Promise<void> {
|
|
75
|
-
trace.write('executeRequest: ENTER');
|
|
76
|
-
|
|
77
|
-
// Get the CGI
|
|
78
|
-
const cgiObj = getCGI(req, options);
|
|
79
|
-
|
|
80
|
-
// Add the query properties
|
|
81
|
-
const argObj: any = {};
|
|
82
|
-
Object.assign(argObj, req.query);
|
|
83
|
-
|
|
84
|
-
// Does the request contain any files
|
|
85
|
-
const filesToUpload = getFiles(req);
|
|
86
|
-
trace.write(`executeRequest: "${filesToUpload.length}" files to upload:\n${Trace.inspect(filesToUpload)}`);
|
|
87
|
-
/* istanbul ignore next */
|
|
88
|
-
if (filesToUpload.length > 0 && (typeof options.doctable !== 'string' || options.doctable.length === 0)) {
|
|
89
|
-
const error = 'Unable to upload files if no document table "doctable" has been configured';
|
|
90
|
-
trace.write(error);
|
|
91
|
-
throw new RequestError(error);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Add the files to the arguments
|
|
95
|
-
filesToUpload.reduce((aggregator, file) => {
|
|
96
|
-
aggregator[file.fieldValue] = file.filename;
|
|
97
|
-
return aggregator;
|
|
98
|
-
}, argObj);
|
|
99
|
-
|
|
100
|
-
// Does the request contain a body
|
|
101
|
-
Object.assign(argObj, normalizeBody(req));
|
|
102
|
-
|
|
103
|
-
// invoke the Oracle procedure and get the page contenst
|
|
104
|
-
await invokeProcedure(req, res, argObj, cgiObj, filesToUpload, options, databaseConnection, trace);
|
|
105
|
-
|
|
106
|
-
trace.write('executeRequest: EXIT');
|
|
107
|
-
|
|
108
|
-
return Promise.resolve();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/*
|
|
112
|
-
* Normalize the body by making sure that only "simple" parameters and no nested objects are submitted
|
|
113
|
-
*/
|
|
114
|
-
function normalizeBody(req: express.Request): {[key: string]: string} {
|
|
115
|
-
const args: {[key: string]: string} = {};
|
|
116
|
-
/* istanbul ignore else */
|
|
117
|
-
if (typeof req.body === 'object') {
|
|
118
|
-
for (const key in req.body) {
|
|
119
|
-
const value = req.body[key];
|
|
120
|
-
/* istanbul ignore else */
|
|
121
|
-
if (isStringOrArrayOfString(value)) {
|
|
122
|
-
args[key] = value;
|
|
123
|
-
} else {
|
|
124
|
-
/* istanbul ignore next */
|
|
125
|
-
throw new RequestError(`The element "${key}" in the body is not a string or an array of strings!\n` + util.inspect(req.body, {showHidden: false, depth: null, colors: false}));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return args;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/*
|
|
134
|
-
* Is the given value a string or an array of strings
|
|
135
|
-
*/
|
|
136
|
-
function isStringOrArrayOfString(value: any): boolean {
|
|
137
|
-
/* istanbul ignore next */
|
|
138
|
-
return typeof value === 'string' || (Array.isArray(value) && value.every(element => typeof element === 'string'));
|
|
139
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* Process the http request
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import util from 'util';
|
|
6
|
+
import oracledb from 'oracledb';
|
|
7
|
+
import {invokeProcedure} from './procedure';
|
|
8
|
+
import {getCGI} from './cgi';
|
|
9
|
+
import {getFiles} from './fileUpload';
|
|
10
|
+
import {RequestError} from './requestError';
|
|
11
|
+
import {Trace} from './trace';
|
|
12
|
+
import express from 'express';
|
|
13
|
+
import {oracleExpressMiddleware$options} from './config';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Process the request
|
|
17
|
+
*
|
|
18
|
+
* @param {express.Request} req - The req object represents the HTTP request.
|
|
19
|
+
* @param {express.Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
|
|
20
|
+
* @param {oracleExpressMiddleware$options} options - the options for the middleware.
|
|
21
|
+
* @param {Promise<oracledb.Pool>} databasePoolPromise - Promise returning a database pool.
|
|
22
|
+
* @param {Trace} trace - Tracing object.
|
|
23
|
+
* returns {Promise<void>} - Promise that resolves when the request has been fullfilled.
|
|
24
|
+
*/
|
|
25
|
+
export async function processRequest(req: express.Request, res: express.Response, options: oracleExpressMiddleware$options, databasePoolPromise: Promise<oracledb.Pool>, trace: Trace): Promise<void> {
|
|
26
|
+
trace.write('processRequest: ENTER');
|
|
27
|
+
|
|
28
|
+
let databasePool;
|
|
29
|
+
let databaseConnection;
|
|
30
|
+
|
|
31
|
+
// wait until the database pool has been allocated
|
|
32
|
+
try {
|
|
33
|
+
databasePool = await databasePoolPromise;
|
|
34
|
+
trace.write('processRequest: Connection pool has been allocated');
|
|
35
|
+
} catch (err) {
|
|
36
|
+
/* istanbul ignore next */
|
|
37
|
+
throw new RequestError(`Unable to create database pool.\n${err instanceof Error ? err.message : ''}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// open database connection
|
|
41
|
+
try {
|
|
42
|
+
databaseConnection = await databasePool.getConnection();
|
|
43
|
+
trace.write('processRequest: Connection has been allocated');
|
|
44
|
+
} catch (err) {
|
|
45
|
+
/* istanbul ignore next */
|
|
46
|
+
throw new RequestError(`Unable to open database connection\n${err instanceof Error ? err.message: ''}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// execute request
|
|
50
|
+
await executeRequest(req, res, options, databaseConnection, trace);
|
|
51
|
+
|
|
52
|
+
// close database connection
|
|
53
|
+
try {
|
|
54
|
+
await databaseConnection.release();
|
|
55
|
+
trace.write('processRequest: Connection has been released');
|
|
56
|
+
} catch (err) {
|
|
57
|
+
/* istanbul ignore next */
|
|
58
|
+
console.error(`Unable to release database connection\n${err instanceof Error ? err.message : ''}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
trace.write('processRequest: EXIT');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Execute the request
|
|
66
|
+
*
|
|
67
|
+
* @param {express.Request} req - The req object represents the HTTP request.
|
|
68
|
+
* @param {express.Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
|
|
69
|
+
* @param {oracleExpressMiddleware$options} options - the options for the middleware.
|
|
70
|
+
* @param {oracledb.Connection} databaseConnection - Database connection.
|
|
71
|
+
* @param {Trace} trace - Tracing object.
|
|
72
|
+
* @returns {Promise<void>} - Promise resolving to th page
|
|
73
|
+
*/
|
|
74
|
+
async function executeRequest(req: express.Request, res: express.Response, options: oracleExpressMiddleware$options, databaseConnection: oracledb.Connection, trace: Trace): Promise<void> {
|
|
75
|
+
trace.write('executeRequest: ENTER');
|
|
76
|
+
|
|
77
|
+
// Get the CGI
|
|
78
|
+
const cgiObj = getCGI(req, options);
|
|
79
|
+
|
|
80
|
+
// Add the query properties
|
|
81
|
+
const argObj: any = {};
|
|
82
|
+
Object.assign(argObj, req.query);
|
|
83
|
+
|
|
84
|
+
// Does the request contain any files
|
|
85
|
+
const filesToUpload = getFiles(req);
|
|
86
|
+
trace.write(`executeRequest: "${filesToUpload.length}" files to upload:\n${Trace.inspect(filesToUpload)}`);
|
|
87
|
+
/* istanbul ignore next */
|
|
88
|
+
if (filesToUpload.length > 0 && (typeof options.doctable !== 'string' || options.doctable.length === 0)) {
|
|
89
|
+
const error = 'Unable to upload files if no document table "doctable" has been configured';
|
|
90
|
+
trace.write(error);
|
|
91
|
+
throw new RequestError(error);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Add the files to the arguments
|
|
95
|
+
filesToUpload.reduce((aggregator, file) => {
|
|
96
|
+
aggregator[file.fieldValue] = file.filename;
|
|
97
|
+
return aggregator;
|
|
98
|
+
}, argObj);
|
|
99
|
+
|
|
100
|
+
// Does the request contain a body
|
|
101
|
+
Object.assign(argObj, normalizeBody(req));
|
|
102
|
+
|
|
103
|
+
// invoke the Oracle procedure and get the page contenst
|
|
104
|
+
await invokeProcedure(req, res, argObj, cgiObj, filesToUpload, options, databaseConnection, trace);
|
|
105
|
+
|
|
106
|
+
trace.write('executeRequest: EXIT');
|
|
107
|
+
|
|
108
|
+
return Promise.resolve();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* Normalize the body by making sure that only "simple" parameters and no nested objects are submitted
|
|
113
|
+
*/
|
|
114
|
+
function normalizeBody(req: express.Request): {[key: string]: string} {
|
|
115
|
+
const args: {[key: string]: string} = {};
|
|
116
|
+
/* istanbul ignore else */
|
|
117
|
+
if (typeof req.body === 'object') {
|
|
118
|
+
for (const key in req.body) {
|
|
119
|
+
const value = req.body[key];
|
|
120
|
+
/* istanbul ignore else */
|
|
121
|
+
if (isStringOrArrayOfString(value)) {
|
|
122
|
+
args[key] = value;
|
|
123
|
+
} else {
|
|
124
|
+
/* istanbul ignore next */
|
|
125
|
+
throw new RequestError(`The element "${key}" in the body is not a string or an array of strings!\n` + util.inspect(req.body, {showHidden: false, depth: null, colors: false}));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return args;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* Is the given value a string or an array of strings
|
|
135
|
+
*/
|
|
136
|
+
function isStringOrArrayOfString(value: any): boolean {
|
|
137
|
+
/* istanbul ignore next */
|
|
138
|
+
return typeof value === 'string' || (Array.isArray(value) && value.every(element => typeof element === 'string'));
|
|
139
|
+
}
|
package/src/requestError.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* RequestError
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export class RequestError extends Error {
|
|
6
|
-
timestamp: Date;
|
|
7
|
-
|
|
8
|
-
constructor(message: string) {
|
|
9
|
-
super(message);
|
|
10
|
-
|
|
11
|
-
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
12
|
-
if (Error.captureStackTrace) {
|
|
13
|
-
Error.captureStackTrace(this, RequestError);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Custom debugging information
|
|
17
|
-
this.timestamp = new Date();
|
|
18
|
-
}
|
|
19
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* RequestError
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export class RequestError extends Error {
|
|
6
|
+
timestamp: Date;
|
|
7
|
+
|
|
8
|
+
constructor(message: string) {
|
|
9
|
+
super(message);
|
|
10
|
+
|
|
11
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
12
|
+
if (Error.captureStackTrace) {
|
|
13
|
+
Error.captureStackTrace(this, RequestError);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Custom debugging information
|
|
17
|
+
this.timestamp = new Date();
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/stream.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import stream from 'stream';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Convert a readable stream to a buffer.
|
|
5
|
-
*
|
|
6
|
-
* @param {stream.Readable} readable - The readable stream.
|
|
7
|
-
* @returns {Promise<Buffer>} - The buffer.
|
|
8
|
-
*/
|
|
9
|
-
export async function streamToBuffer(readable: stream.Readable): Promise<Buffer> {
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
const buffers: Array<Buffer> = [];
|
|
12
|
-
|
|
13
|
-
readable.on('data', buffer => {
|
|
14
|
-
buffers.push(buffer);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
readable.on('end', () => {
|
|
18
|
-
resolve(Buffer.concat(buffers));
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
readable.on('error', err => {
|
|
22
|
-
// istanbul ignore next
|
|
23
|
-
reject(err);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
}
|
|
1
|
+
import stream from 'stream';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert a readable stream to a buffer.
|
|
5
|
+
*
|
|
6
|
+
* @param {stream.Readable} readable - The readable stream.
|
|
7
|
+
* @returns {Promise<Buffer>} - The buffer.
|
|
8
|
+
*/
|
|
9
|
+
export async function streamToBuffer(readable: stream.Readable): Promise<Buffer> {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
const buffers: Array<Buffer> = [];
|
|
12
|
+
|
|
13
|
+
readable.on('data', buffer => {
|
|
14
|
+
buffers.push(buffer);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
readable.on('end', () => {
|
|
18
|
+
resolve(Buffer.concat(buffers));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
readable.on('error', err => {
|
|
22
|
+
// istanbul ignore next
|
|
23
|
+
reject(err);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|