web_plsql 0.5.0 → 0.6.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/README.md +123 -110
- package/examples/server_apex.js +28 -0
- package/examples/server_sample.js +30 -0
- package/examples/sql/{doc_table.sql → doctable.sql} +1 -1
- package/examples/sql/install.sql +6 -9
- package/examples/sql/sample_package.sql +27 -0
- package/examples/sql/sample_package_body.sql +245 -0
- package/examples/static/sample.css +11 -10
- package/package.json +90 -83
- package/src/cgi.js +127 -0
- package/src/error.js +24 -0
- package/src/errorPage.js +296 -0
- package/src/file.js +77 -0
- package/src/handlerLogger.js +21 -0
- package/src/handlerMetrics.js +46 -0
- package/src/handlerPlSql.js +65 -0
- package/src/handlerUpload.js +32 -0
- package/src/index.js +17 -0
- package/src/oracle.js +80 -0
- package/src/parsePage.js +193 -0
- package/src/procedure.js +260 -0
- package/src/procedureError.js +40 -0
- package/src/procedureNamed.js +233 -0
- package/src/procedureSanitize.js +215 -0
- package/src/procedureVariable.js +57 -0
- package/src/request.js +103 -0
- package/src/{requestError.ts → requestError.js} +8 -4
- package/src/sendResponse.js +104 -0
- package/src/server.js +106 -0
- package/src/shutdown.js +53 -0
- package/src/stream.js +28 -0
- package/src/trace.js +74 -0
- package/src/tty.js +48 -0
- package/src/types.js +146 -0
- package/src/upload.js +92 -0
- package/src/version.js +23 -0
- package/types/cgi.d.ts +4 -0
- package/types/error.d.ts +1 -0
- package/types/errorPage.d.ts +10 -0
- package/types/file.d.ts +5 -0
- package/types/handlerLogger.d.ts +2 -0
- package/types/handlerMetrics.d.ts +4 -0
- package/types/handlerPlSql.d.ts +8 -0
- package/types/handlerUpload.d.ts +7 -0
- package/types/index.d.ts +10 -0
- package/types/oracle.d.ts +5 -0
- package/types/parsePage.d.ts +3 -0
- package/types/procedure.d.ts +10 -0
- package/types/procedureError.d.ts +23 -0
- package/types/procedureNamed.d.ts +14 -0
- package/types/procedureSanitize.d.ts +14 -0
- package/types/procedureVariable.d.ts +9 -0
- package/types/request.d.ts +7 -0
- package/types/requestError.d.ts +8 -0
- package/types/sendResponse.d.ts +4 -0
- package/types/server.d.ts +7 -0
- package/types/shutdown.d.ts +2 -0
- package/types/stream.d.ts +1 -0
- package/types/trace.d.ts +5 -0
- package/types/tty.d.ts +4 -0
- package/types/types.d.ts +251 -0
- package/types/upload.d.ts +5 -0
- package/types/version.d.ts +7 -0
- package/.editorconfig +0 -8
- package/.eslintignore +0 -3
- package/.eslintrc.js +0 -347
- package/CHANGELOG.md +0 -127
- package/examples/apex.js +0 -70
- package/examples/credentials.js +0 -22
- package/examples/oracledb_example.js +0 -30
- package/examples/sample.js +0 -101
- package/examples/sql/sample.pkb +0 -223
- package/examples/sql/sample.pks +0 -24
- package/jest.config.js +0 -204
- package/src/cgi.ts +0 -95
- package/src/config.ts +0 -97
- package/src/errorPage.ts +0 -286
- package/src/fileUpload.ts +0 -126
- package/src/index.ts +0 -65
- package/src/page.ts +0 -275
- package/src/procedure.ts +0 -360
- package/src/procedureError.ts +0 -27
- package/src/request.ts +0 -139
- package/src/stream.ts +0 -26
- package/src/trace.ts +0 -194
- package/test/.eslintrc.json +0 -5
- package/test/__tests__/cgi.ts +0 -96
- package/test/__tests__/config.ts +0 -41
- package/test/__tests__/errorPage.ts +0 -101
- package/test/__tests__/oracledb_mock.ts +0 -98
- package/test/__tests__/server.ts +0 -495
- package/test/__tests__/stream.ts +0 -21
- package/test/mock/oracledb.ts +0 -85
- package/test/static/static.html +0 -1
- package/tsconfig.json +0 -24
- package/tsconfig.src.json +0 -23
package/src/procedure.ts
DELETED
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Invoke the Oracle procedure and return the raw content of the page
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import oracledb from 'oracledb';
|
|
6
|
-
import {streamToBuffer} from './stream';
|
|
7
|
-
import {uploadFiles, filesUploadType} from './fileUpload';
|
|
8
|
-
import {parse, send} from './page';
|
|
9
|
-
import {ProcedureError} from './procedureError';
|
|
10
|
-
import {RequestError} from './requestError';
|
|
11
|
-
import {Trace} from './trace';
|
|
12
|
-
import express from 'express';
|
|
13
|
-
import {oracleExpressMiddleware$options} from './config';
|
|
14
|
-
|
|
15
|
-
type argObjType = {[key: string]: string | Array<string>};
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Invoke the Oracle procedure and return the page content
|
|
19
|
-
*
|
|
20
|
-
* @param {express.Request} req - The req object represents the HTTP request.
|
|
21
|
-
* @param {express.Response} res - The res object represents the HTTP response that an Express app sends when it gets an HTTP request.
|
|
22
|
-
* @param {argObjType} argObj - - The arguments of the procedure to invoke.
|
|
23
|
-
* @param {Object} cgiObj - The cgi of the procedure to invoke.
|
|
24
|
-
* @param {filesUploadType} filesToUpload - Array of files to be uploaded
|
|
25
|
-
* @param {oracleExpressMiddleware$options} options - the options for the middleware.
|
|
26
|
-
* @param {oracledb.Connection} databaseConnection - Database connection.
|
|
27
|
-
* @param {Trace} trace - Tracing object.
|
|
28
|
-
* @returns {Promise<void>} - Promise resolving to the page content generated by the executed procedure
|
|
29
|
-
*/
|
|
30
|
-
export async function invokeProcedure(req: express.Request, res: express.Response, argObj: argObjType, cgiObj: Record<string, string>, filesToUpload: filesUploadType, options: oracleExpressMiddleware$options, databaseConnection: oracledb.Connection, trace: Trace): Promise<void> {
|
|
31
|
-
trace.write('invokeProcedure: ENTER');
|
|
32
|
-
|
|
33
|
-
const procedure = req.params.name;
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
// 1) UPLOAD FILES
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
trace.write(`invokeProcedure: upload "${filesToUpload.length}" files`);
|
|
40
|
-
/* istanbul ignore else */
|
|
41
|
-
if (typeof options.doctable === 'string' && options.doctable.length > 0) {
|
|
42
|
-
uploadFiles(filesToUpload, options.doctable, databaseConnection);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
//
|
|
46
|
-
// 2) GET SQL STATEMENT AND ARGUMENTS
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
const para = await getProcedure(procedure, argObj, options, databaseConnection, trace);
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
// 3) EXECUTE PROCEDURE
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
const HTBUF_LEN = 63;
|
|
56
|
-
const MAX_IROWS = 100000;
|
|
57
|
-
|
|
58
|
-
const cgi = {
|
|
59
|
-
keys: Object.keys(cgiObj),
|
|
60
|
-
values: Object.values(cgiObj)
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const fileBlob = await databaseConnection.createLob(oracledb.BLOB);
|
|
64
|
-
|
|
65
|
-
const bind = {
|
|
66
|
-
cgicount: {dir: oracledb.BIND_IN, type: oracledb.NUMBER, val: cgi.keys.length},
|
|
67
|
-
cginames: {dir: oracledb.BIND_IN, type: oracledb.STRING, val: cgi.keys},
|
|
68
|
-
cgivalues: {dir: oracledb.BIND_IN, type: oracledb.STRING, val: cgi.values},
|
|
69
|
-
htbuflen: {dir: oracledb.BIND_IN, type: oracledb.NUMBER, val: HTBUF_LEN},
|
|
70
|
-
fileType: {dir: oracledb.BIND_OUT, type: oracledb.STRING},
|
|
71
|
-
fileSize: {dir: oracledb.BIND_OUT, type: oracledb.NUMBER},
|
|
72
|
-
fileBlob: {dir: oracledb.BIND_INOUT, type: oracledb.BLOB, val: fileBlob},
|
|
73
|
-
lines: {dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: HTBUF_LEN * 2, maxArraySize: MAX_IROWS},
|
|
74
|
-
irows: {dir: oracledb.BIND_INOUT, type: oracledb.NUMBER, val: MAX_IROWS}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// execute procedure and retrieve page
|
|
78
|
-
const sqlStatement = getProcedureSQL(para.sql);
|
|
79
|
-
let result: any;
|
|
80
|
-
try {
|
|
81
|
-
trace.write(`execute:\n${'-'.repeat(30)}\n${sqlStatement}\n${'-'.repeat(30)}\nwith bindings:\n${Trace.inspect(bind)}`);
|
|
82
|
-
result = await databaseConnection.execute(sqlStatement, Object.assign(bind, para.bind));
|
|
83
|
-
trace.write(`results:\n${Trace.inspect(result)}`);
|
|
84
|
-
} catch (err) {
|
|
85
|
-
/* istanbul ignore next */
|
|
86
|
-
throwError(`Error when executing procedure\n${sqlStatement}\n${err instanceof Error ? err.toString() : ''}`, para, cgiObj, trace);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
// 4) PROCESS RESULTS
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
// internal error
|
|
94
|
-
if (!result) {
|
|
95
|
-
/* istanbul ignore next */
|
|
96
|
-
throwError('Error when retrieving rows', para, cgiObj, trace);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Make sure that we have retrieved all the rows
|
|
100
|
-
if (result.outBinds.irows > MAX_IROWS) {
|
|
101
|
-
/* istanbul ignore next */
|
|
102
|
-
throwError(`Error when retrieving rows. irows="${result.outBinds.irows}"`, para, cgiObj, trace);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// combine page
|
|
106
|
-
const pageContent = result.outBinds.lines.join('');
|
|
107
|
-
trace.write(`PLAIN CONTENT:\n${'-'.repeat(30)}\n${pageContent}\n${'-'.repeat(30)}`);
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
// 6) PARSE PAGE
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
// parse what we received from PL/SQL
|
|
114
|
-
const pageComponents = parse(pageContent);
|
|
115
|
-
|
|
116
|
-
// add "Server" header
|
|
117
|
-
pageComponents.head.server = cgiObj.SERVER_SOFTWARE;
|
|
118
|
-
|
|
119
|
-
// add file download information
|
|
120
|
-
pageComponents.file.fileType = result.outBinds.fileType;
|
|
121
|
-
pageComponents.file.fileSize = result.outBinds.fileSize;
|
|
122
|
-
pageComponents.file.fileBlob = result.outBinds.fileBlob !== null ? await streamToBuffer(result.outBinds.fileBlob) : null;
|
|
123
|
-
|
|
124
|
-
trace.write(`PARSED CONTENT:\n${'-'.repeat(30)}\n${Trace.inspect(pageComponents)}\n${'-'.repeat(30)}`);
|
|
125
|
-
|
|
126
|
-
//
|
|
127
|
-
// 5) SEND THE RESPONSE
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
send(req, res, pageComponents, trace);
|
|
131
|
-
|
|
132
|
-
//
|
|
133
|
-
// 6) CLEANUP
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
await fileBlob.close();
|
|
137
|
-
|
|
138
|
-
trace.write('invokeProcedure: EXIT');
|
|
139
|
-
|
|
140
|
-
return Promise.resolve();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/*
|
|
144
|
-
* Report error in procedure
|
|
145
|
-
*/
|
|
146
|
-
/* istanbul ignore next */
|
|
147
|
-
function throwError(error: string, para: {sql: string; bind: any}, cgiObj: any, trace: Trace) {
|
|
148
|
-
/* istanbul ignore next */
|
|
149
|
-
trace.write(error);
|
|
150
|
-
/* istanbul ignore next */
|
|
151
|
-
throw new ProcedureError(error, cgiObj, para.sql, para.bind);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/*
|
|
155
|
-
* Get the procedure and arguments to execute
|
|
156
|
-
*/
|
|
157
|
-
async function getProcedure(procedure: string, argObj: argObjType, options: oracleExpressMiddleware$options, databaseConnection: oracledb.Connection, trace: Trace): Promise<{sql: string; bind: any}> {
|
|
158
|
-
if (options.pathAlias && options.pathAlias.alias === procedure) {
|
|
159
|
-
trace.write(`getProcedure: path alias "${options.pathAlias.alias}" redirects to "${options.pathAlias.procedure}"`);
|
|
160
|
-
return Promise.resolve({
|
|
161
|
-
sql: options.pathAlias.procedure + '(p_path=>:p_path);',
|
|
162
|
-
bind: {
|
|
163
|
-
'p_path': {dir: oracledb.BIND_IN, type: oracledb.STRING, val: procedure}
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
} else if (procedure.substring(0, 1) === '!') {
|
|
167
|
-
trace.write('getProcedure: get variable arguments');
|
|
168
|
-
return getVarArgsPara(procedure, argObj);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
trace.write('getProcedure: get named arguments');
|
|
172
|
-
return getFixArgsPara(procedure, argObj, databaseConnection);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/*
|
|
176
|
-
* Get the SQL statement to execute when a new procedure is invoked
|
|
177
|
-
*/
|
|
178
|
-
function getProcedureSQL(procedure: string): string {
|
|
179
|
-
return `
|
|
180
|
-
DECLARE
|
|
181
|
-
fileType VARCHAR2(32767);
|
|
182
|
-
fileSize INTEGER;
|
|
183
|
-
fileBlob BLOB;
|
|
184
|
-
BEGIN
|
|
185
|
-
-- Ensure a stateless environment by resetting package state (dbms_session.reset_package)
|
|
186
|
-
dbms_session.modify_package_state(dbms_session.reinitialize);
|
|
187
|
-
|
|
188
|
-
-- initialize the cgi
|
|
189
|
-
owa.init_cgi_env(:cgicount, :cginames, :cgivalues);
|
|
190
|
-
|
|
191
|
-
-- initialize the htp package
|
|
192
|
-
htp.init;
|
|
193
|
-
|
|
194
|
-
-- set the HTBUF_LEN
|
|
195
|
-
htp.HTBUF_LEN := :htbuflen;
|
|
196
|
-
|
|
197
|
-
-- execute the procedure
|
|
198
|
-
BEGIN
|
|
199
|
-
${procedure}
|
|
200
|
-
EXCEPTION WHEN OTHERS THEN
|
|
201
|
-
raise_application_error(-20000, 'Error executing ${procedure}'||CHR(10)||SUBSTR(dbms_utility.format_error_stack()||CHR(10)||dbms_utility.format_error_backtrace(), 1, 2000));
|
|
202
|
-
END;
|
|
203
|
-
|
|
204
|
-
-- Check for file download
|
|
205
|
-
IF (wpg_docload.is_file_download()) THEN
|
|
206
|
-
wpg_docload.get_download_file(fileType);
|
|
207
|
-
IF (filetype = 'B') THEN
|
|
208
|
-
wpg_docload.get_download_blob(:fileBlob);
|
|
209
|
-
fileSize := dbms_lob.getlength(:fileBlob);
|
|
210
|
-
--dbms_lob.copy(dest_lob=>:fileBlob, src_lob=>fileBlob, amount=>fileSize);
|
|
211
|
-
END IF;
|
|
212
|
-
END IF;
|
|
213
|
-
:fileType := fileType;
|
|
214
|
-
:fileSize := fileSize;
|
|
215
|
-
|
|
216
|
-
-- retrieve the page
|
|
217
|
-
owa.get_page(thepage=>:lines, irows=>:irows);
|
|
218
|
-
END;
|
|
219
|
-
`;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/*
|
|
223
|
-
* Get the sql statement and bindings for the procedure to execute for a variable number of arguments
|
|
224
|
-
*/
|
|
225
|
-
async function getVarArgsPara(procedure: string, argObj: argObjType): Promise<{sql: string; bind: any}> {
|
|
226
|
-
const names = [];
|
|
227
|
-
const values = [];
|
|
228
|
-
|
|
229
|
-
for (const key in argObj) {
|
|
230
|
-
const value = argObj[key];
|
|
231
|
-
if (typeof value === 'string') {
|
|
232
|
-
names.push(key);
|
|
233
|
-
values.push(value);
|
|
234
|
-
} else if (Array.isArray(value)) {
|
|
235
|
-
value.forEach(item => {
|
|
236
|
-
names.push(key);
|
|
237
|
-
values.push(item);
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return Promise.resolve({
|
|
243
|
-
sql: procedure.substring(1) + '(:argnames, :argvalues);',
|
|
244
|
-
bind: {
|
|
245
|
-
argnames: {dir: oracledb.BIND_IN, type: oracledb.STRING, val: names},
|
|
246
|
-
argvalues: {dir: oracledb.BIND_IN, type: oracledb.STRING, val: values}
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/*
|
|
252
|
-
* Get the sql statement and bindings for the procedure to execute for a fixed number of arguments
|
|
253
|
-
*/
|
|
254
|
-
async function getFixArgsPara(procedure: string, argObj: argObjType, databaseConnection: oracledb.Connection): Promise<{sql: string; bind: any}> {
|
|
255
|
-
const bind: {[key: string]: any} = {};
|
|
256
|
-
let index = 0;
|
|
257
|
-
|
|
258
|
-
const argTypes = await getArguments(procedure, databaseConnection);
|
|
259
|
-
|
|
260
|
-
// bindings for the statement
|
|
261
|
-
let sql = procedure + '(';
|
|
262
|
-
for (const key in argObj) {
|
|
263
|
-
const value = argObj[key];
|
|
264
|
-
const parameterName = 'p_' + key;
|
|
265
|
-
|
|
266
|
-
// prepend the separator, if this is not the first argument
|
|
267
|
-
if (index > 0) {
|
|
268
|
-
sql += ',';
|
|
269
|
-
}
|
|
270
|
-
index++;
|
|
271
|
-
|
|
272
|
-
// add the argument
|
|
273
|
-
sql += key + '=>:' + parameterName;
|
|
274
|
-
|
|
275
|
-
// add the binding
|
|
276
|
-
bind[parameterName] = {dir: oracledb.BIND_IN, type: oracledb.STRING};
|
|
277
|
-
|
|
278
|
-
// set the value or array of values
|
|
279
|
-
if (Array.isArray(value) || argTypes[key] === 'PL/SQL TABLE') {
|
|
280
|
-
bind[parameterName].val = [];
|
|
281
|
-
if (typeof value === 'string') {
|
|
282
|
-
bind[parameterName].val.push(value);
|
|
283
|
-
} else {
|
|
284
|
-
value.forEach(element => {
|
|
285
|
-
bind[parameterName].val.push(element);
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
} else if (typeof value === 'string') {
|
|
289
|
-
bind[parameterName].val = value;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
sql += ');';
|
|
293
|
-
|
|
294
|
-
return Promise.resolve({
|
|
295
|
-
sql: sql,
|
|
296
|
-
bind: bind
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/*
|
|
301
|
-
* Retrieve the argument types for a given procedure to be executed.
|
|
302
|
-
* This is important because if the procedure is defined to take a PL/SQL indexed table,
|
|
303
|
-
* we must provise a table, even if there is only one argument to be submitted.
|
|
304
|
-
*/
|
|
305
|
-
async function getArguments(procedure: string, databaseConnection: oracledb.Connection): Promise<{[key: string]: string}> {
|
|
306
|
-
const sql = [
|
|
307
|
-
'DECLARE',
|
|
308
|
-
' schemaName VARCHAR2(32767);',
|
|
309
|
-
' part1 VARCHAR2(32767);',
|
|
310
|
-
' part2 VARCHAR2(32767);',
|
|
311
|
-
' dblink VARCHAR2(32767);',
|
|
312
|
-
' objectType NUMBER;',
|
|
313
|
-
' objectID NUMBER;',
|
|
314
|
-
'BEGIN',
|
|
315
|
-
' dbms_utility.name_resolve(name=>UPPER(:name), context=>1, schema=>schemaName, part1=>part1, part2=>part2, dblink=>dblink, part1_type=>objectType, object_number=>objectID);',
|
|
316
|
-
' IF (part1 IS NOT NULL) THEN',
|
|
317
|
-
' SELECT argument_name, data_type BULK COLLECT INTO :names, :types FROM all_arguments WHERE owner = schemaName AND package_name = part1 AND object_name = part2 AND argument_name IS NOT NULL ORDER BY overload, sequence;',
|
|
318
|
-
' ELSE',
|
|
319
|
-
' SELECT argument_name, data_type BULK COLLECT INTO :names, :types FROM all_arguments WHERE owner = schemaName AND package_name IS NULL AND object_name = part2 AND argument_name IS NOT NULL ORDER BY overload, sequence;',
|
|
320
|
-
' END IF;',
|
|
321
|
-
'END;'
|
|
322
|
-
];
|
|
323
|
-
const MAX_PARAMETER_NUMBER = 1000;
|
|
324
|
-
|
|
325
|
-
const bind = {
|
|
326
|
-
name: {dir: oracledb.BIND_IN, type: oracledb.STRING, val: procedure},
|
|
327
|
-
names: {dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 60, maxArraySize: MAX_PARAMETER_NUMBER},
|
|
328
|
-
types: {dir: oracledb.BIND_OUT, type: oracledb.STRING, maxSize: 60, maxArraySize: MAX_PARAMETER_NUMBER}
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
let result;
|
|
332
|
-
|
|
333
|
-
try {
|
|
334
|
-
result = await databaseConnection.execute<{names: Array<string>; types: Array<string>}>(sql.join('\n'), bind);
|
|
335
|
-
} catch (err) {
|
|
336
|
-
/* istanbul ignore next */
|
|
337
|
-
const message = `Error when retrieving arguments\n${sql.join('\n')}\n${err instanceof Error ? err.stack : ''}`;
|
|
338
|
-
/* istanbul ignore next */
|
|
339
|
-
throw new RequestError(message);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const argTypes: any = {};
|
|
343
|
-
if (typeof result !== 'object' ||
|
|
344
|
-
result === null ||
|
|
345
|
-
typeof result.outBinds !== 'object' ||
|
|
346
|
-
result.outBinds === null ||
|
|
347
|
-
!Array.isArray(result.outBinds.names) ||
|
|
348
|
-
!Array.isArray(result.outBinds.types)
|
|
349
|
-
) {
|
|
350
|
-
/* istanbul ignore next */
|
|
351
|
-
throw new RequestError('getArguments: invalid results');
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
for (let i = 0; i < result.outBinds.names.length; i++) {
|
|
355
|
-
/* istanbul ignore next */
|
|
356
|
-
argTypes[result.outBinds.names[i].toLowerCase()] = result.outBinds.types[i];
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
return Promise.resolve(argTypes);
|
|
360
|
-
}
|
package/src/procedureError.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
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/stream.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
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
|
-
}
|