@pi-r/mssql 0.11.2 → 0.12.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/client/index.js +60 -62
- package/client/pool.d.ts +1 -1
- package/client/pool.js +6 -4
- package/package.json +4 -4
- package/types/pool.d.ts +38 -23
package/client/index.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const Db = require("@e-mc/db");
|
|
9
|
-
const types_1 = require("@e-mc/types");
|
|
10
|
-
const util_1 = require("@e-mc/db/util");
|
|
11
|
-
const DbPool = require("@pi-r/mssql/client/pool");
|
|
2
|
+
|
|
3
|
+
const tedious = require('tedious');
|
|
4
|
+
const Db = require('@e-mc/db');
|
|
5
|
+
const { DB_TYPE, asFunction, errorMessage, isArray, isError, isErrorCode, isObject, isPlainObject, isString } = require('@e-mc/types');
|
|
6
|
+
const { parseConnectionString, parseServerAuth } = require('@e-mc/db/util');
|
|
7
|
+
const DbPool = require('@pi-r/mssql/client/pool');
|
|
12
8
|
const TediousPool = require('tedious-connection-pool2');
|
|
13
9
|
const POOL_STATE = {};
|
|
14
|
-
function convertParameters(sql, params,
|
|
15
|
-
if (
|
|
10
|
+
function convertParameters(sql, params, item) {
|
|
11
|
+
if (isPlainObject(params)) {
|
|
16
12
|
const items = [];
|
|
17
13
|
for (const name in params) {
|
|
18
14
|
items.push({ ...params[name], name });
|
|
@@ -25,27 +21,29 @@ function convertParameters(sql, params, output) {
|
|
|
25
21
|
if (name) {
|
|
26
22
|
const type = convertType(sql, param.type, value, options);
|
|
27
23
|
if (type.name === 'TVP') {
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
for (const col of columns) {
|
|
34
|
-
col.type = convertType(sql, col.type, col.value, col.options ||= {});
|
|
24
|
+
if (item && isPlainObject(value)) {
|
|
25
|
+
if (isArray(value.columns)) {
|
|
26
|
+
for (const col of value.columns) {
|
|
27
|
+
col.type = convertType(sql, col.type, col.value, col.options ||= {});
|
|
28
|
+
}
|
|
35
29
|
}
|
|
30
|
+
item.storedProc = true;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
continue;
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
|
-
this[
|
|
36
|
+
this[item ? 'addParameter' : 'addOutputParameter'](name, type, value, options);
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
41
|
function convertType(sql, type, value, options) {
|
|
44
42
|
let result;
|
|
45
|
-
if (
|
|
43
|
+
if (isString(type)) {
|
|
46
44
|
result = sql[type];
|
|
47
45
|
}
|
|
48
|
-
else if (
|
|
46
|
+
else if (isObject(type)) {
|
|
49
47
|
if (typeof type.id === 'number' && typeof type.declaration === 'function' && typeof type.validate === 'function') {
|
|
50
48
|
return type;
|
|
51
49
|
}
|
|
@@ -87,17 +85,17 @@ function convertType(sql, type, value, options) {
|
|
|
87
85
|
return sql.VarChar;
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
|
-
const isOutputParameters = (params) =>
|
|
88
|
+
const isOutputParameters = (params) => isPlainObject(params) && Object.keys(params).length === 2 && 'input' in params && 'output' in params;
|
|
91
89
|
function setCredential(item) {
|
|
92
90
|
let credential = this.getCredential(item), hostname, username, password, port, database;
|
|
93
91
|
if (credential) {
|
|
94
|
-
({ username, password, hostname, port, database } =
|
|
92
|
+
({ username, password, hostname, port, database } = parseServerAuth(credential, true));
|
|
95
93
|
}
|
|
96
94
|
else {
|
|
97
95
|
const uri = item.uri;
|
|
98
96
|
credential = {};
|
|
99
97
|
if (uri) {
|
|
100
|
-
const connection =
|
|
98
|
+
const connection = parseConnectionString(uri);
|
|
101
99
|
if (connection) {
|
|
102
100
|
({ username, password, hostname, port, database } = connection);
|
|
103
101
|
}
|
|
@@ -127,20 +125,20 @@ function setCredential(item) {
|
|
|
127
125
|
break;
|
|
128
126
|
case 'ntlm':
|
|
129
127
|
flags = 1;
|
|
130
|
-
if (!
|
|
128
|
+
if (!isString(authOptions.domain)) {
|
|
131
129
|
errors.push('authentication.options.domain');
|
|
132
130
|
}
|
|
133
131
|
break;
|
|
134
|
-
case 'azure-active-directory-password':
|
|
135
|
-
flags = 1 | 4;
|
|
136
|
-
break;
|
|
137
132
|
case 'token-credential':
|
|
138
|
-
if (!
|
|
133
|
+
if (!isObject(authOptions.credential)) {
|
|
139
134
|
errors.push('authentication.options.credential');
|
|
140
135
|
}
|
|
141
136
|
break;
|
|
137
|
+
case 'azure-active-directory-password':
|
|
138
|
+
flags = 1 | 4;
|
|
139
|
+
break;
|
|
142
140
|
case 'azure-active-directory-access-token':
|
|
143
|
-
if (!
|
|
141
|
+
if (!isString(authOptions.token)) {
|
|
144
142
|
errors.push('authentication.options.token');
|
|
145
143
|
}
|
|
146
144
|
break;
|
|
@@ -149,13 +147,13 @@ function setCredential(item) {
|
|
|
149
147
|
break;
|
|
150
148
|
case 'azure-active-directory-msi-app-service':
|
|
151
149
|
flags = 4 | 8;
|
|
152
|
-
if (!
|
|
150
|
+
if (!isString(authOptions.msiSecret)) {
|
|
153
151
|
errors.push('authentication.options.msiSecret');
|
|
154
152
|
}
|
|
155
153
|
break;
|
|
156
154
|
case 'azure-active-directory-service-principal-secret':
|
|
157
155
|
flags = 4;
|
|
158
|
-
if (!
|
|
156
|
+
if (!isString(authOptions.clientSecret)) {
|
|
159
157
|
errors.push('authentication.options.clientSecret');
|
|
160
158
|
}
|
|
161
159
|
break;
|
|
@@ -165,21 +163,21 @@ function setCredential(item) {
|
|
|
165
163
|
authOptions.userName ||= username;
|
|
166
164
|
authOptions.password ||= password;
|
|
167
165
|
}
|
|
168
|
-
if (!
|
|
166
|
+
if (!isString(authOptions.userName)) {
|
|
169
167
|
errors.push('authentication.options.userName');
|
|
170
168
|
}
|
|
171
|
-
if (!
|
|
169
|
+
if (!isString(authOptions.password)) {
|
|
172
170
|
errors.push('authentication.options.password');
|
|
173
171
|
}
|
|
174
172
|
}
|
|
175
|
-
if ((flags & 4) && !
|
|
173
|
+
if ((flags & 4) && !isString(authOptions.clientId)) {
|
|
176
174
|
errors.push('authentication.options.clientId');
|
|
177
175
|
}
|
|
178
|
-
if ((flags & 8) && !
|
|
176
|
+
if ((flags & 8) && !isString(authOptions.msiEndpoint)) {
|
|
179
177
|
errors.push('authentication.options.msiEndpoint');
|
|
180
178
|
}
|
|
181
179
|
if (errors.length > 0) {
|
|
182
|
-
throw
|
|
180
|
+
throw errorMessage("mssql", "Invalid credentials", errors.join(', '));
|
|
183
181
|
}
|
|
184
182
|
const options = credential.options;
|
|
185
183
|
if (options) {
|
|
@@ -202,7 +200,7 @@ function setCredential(item) {
|
|
|
202
200
|
}
|
|
203
201
|
let pool;
|
|
204
202
|
password = undefined;
|
|
205
|
-
if (
|
|
203
|
+
if (isString(usePool)) {
|
|
206
204
|
username = authOptions.userName;
|
|
207
205
|
if (username) {
|
|
208
206
|
[password, pool] = DbPool.validateKey(POOL_STATE, username, usePool);
|
|
@@ -217,7 +215,7 @@ function setCredential(item) {
|
|
|
217
215
|
}
|
|
218
216
|
}
|
|
219
217
|
const config = this.getPoolConfig("mssql", password);
|
|
220
|
-
const poolConfig =
|
|
218
|
+
const poolConfig = isPlainObject(item.usePool) ? item.usePool : {};
|
|
221
219
|
if (config) {
|
|
222
220
|
const { min, max, idle, queue_idle } = config;
|
|
223
221
|
if (min >= 0) {
|
|
@@ -252,7 +250,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
252
250
|
return [];
|
|
253
251
|
}
|
|
254
252
|
let parallel, connectOnce, errorQuery, sessionKey, outCacheMiss;
|
|
255
|
-
if (
|
|
253
|
+
if (isPlainObject(options)) {
|
|
256
254
|
({ parallel, connectOnce, errorQuery, sessionKey, outCacheMiss } = options);
|
|
257
255
|
}
|
|
258
256
|
else {
|
|
@@ -295,19 +293,12 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
295
293
|
}
|
|
296
294
|
catch (err) {
|
|
297
295
|
let close;
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
case 'EDRIVER':
|
|
301
|
-
case 'EINSTLOOKUP':
|
|
302
|
-
close = 1;
|
|
303
|
-
break;
|
|
304
|
-
default:
|
|
305
|
-
close = pool.closeable;
|
|
306
|
-
break;
|
|
296
|
+
if (!isErrorCode(err, 'ELOGIN', 'EDRIVER', 'EINSTLOOKUP')) {
|
|
297
|
+
close = pool.closeable;
|
|
307
298
|
}
|
|
308
|
-
if (close) {
|
|
299
|
+
if (close !== false) {
|
|
309
300
|
await pool.detach(true);
|
|
310
|
-
if (close
|
|
301
|
+
if (!close) {
|
|
311
302
|
throw err;
|
|
312
303
|
}
|
|
313
304
|
}
|
|
@@ -343,7 +334,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
343
334
|
const item = batch[i];
|
|
344
335
|
const { source, query, ignoreCache } = item;
|
|
345
336
|
let credential = mssqlCredential || onceCredential, error;
|
|
346
|
-
if (!credential && !
|
|
337
|
+
if (!credential && !isPlainObject(credential = item.credential) && (error = errorMessage(source, "Invalid credentials")) || !query && (error = errorMessage(source, "Missing database query"))) {
|
|
347
338
|
if (this.handleFail(error, item, { errorQuery })) {
|
|
348
339
|
if (!parallel) {
|
|
349
340
|
tasks.length = 0;
|
|
@@ -360,7 +351,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
360
351
|
continue;
|
|
361
352
|
}
|
|
362
353
|
item.transactionState = 1;
|
|
363
|
-
const streamRow = typeof item.streamRow === 'string' ? this.hasCoerce("mssql", 'options', credential) &&
|
|
354
|
+
const streamRow = typeof item.streamRow === 'string' ? this.hasCoerce("mssql", 'options', credential) && asFunction(item.streamRow) : item.streamRow;
|
|
364
355
|
const cacheValue = ignoreCache === undefined ? sessionKey : Array.isArray(ignoreCache) ? { sessionKey, exclusiveOf: ignoreCache } : { sessionKey, renewCache: ignoreCache === 0 };
|
|
365
356
|
let params = item.params, queryString = '';
|
|
366
357
|
if (caching && ignoreCache !== true && !streamRow) {
|
|
@@ -403,8 +394,8 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
403
394
|
const processRow = typeof streamRow === 'function' ? streamRow : null;
|
|
404
395
|
const rows = [];
|
|
405
396
|
let recordset = 1, resume = false, output;
|
|
406
|
-
const request = new tedious.Request(query,
|
|
407
|
-
if (error && this.handleFail(error, item, { errorQuery, commandType })) {
|
|
397
|
+
const request = new tedious.Request(query, err => {
|
|
398
|
+
if ((error ||= err) && this.handleFail(error, item, { errorQuery, commandType })) {
|
|
408
399
|
reject(error);
|
|
409
400
|
}
|
|
410
401
|
else {
|
|
@@ -423,10 +414,10 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
423
414
|
({ input: params, output: paramsOutput } = params);
|
|
424
415
|
}
|
|
425
416
|
if (params) {
|
|
426
|
-
convertParameters.call(request, tedious.TYPES, params,
|
|
417
|
+
convertParameters.call(request, tedious.TYPES, params, item);
|
|
427
418
|
}
|
|
428
419
|
if (paramsOutput) {
|
|
429
|
-
convertParameters.call(request, tedious.TYPES, paramsOutput
|
|
420
|
+
convertParameters.call(request, tedious.TYPES, paramsOutput);
|
|
430
421
|
}
|
|
431
422
|
}
|
|
432
423
|
request
|
|
@@ -439,7 +430,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
439
430
|
if (name === 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B') {
|
|
440
431
|
try {
|
|
441
432
|
const items = JSON.parse(data.value);
|
|
442
|
-
if (
|
|
433
|
+
if (isArray(items)) {
|
|
443
434
|
for (const col of items) {
|
|
444
435
|
col.__recordset__ = recordset;
|
|
445
436
|
}
|
|
@@ -458,7 +449,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
458
449
|
if (err === false) {
|
|
459
450
|
return;
|
|
460
451
|
}
|
|
461
|
-
if (err
|
|
452
|
+
if (isError(err)) {
|
|
462
453
|
error = err;
|
|
463
454
|
return;
|
|
464
455
|
}
|
|
@@ -532,5 +523,12 @@ async function executeBatchQuery(batch, options = '', outResult) {
|
|
|
532
523
|
async function checkTimeout(value, limit = 0) {
|
|
533
524
|
return DbPool.checkTimeout(POOL_STATE, value, limit);
|
|
534
525
|
}
|
|
535
|
-
|
|
536
|
-
|
|
526
|
+
const DB_SOURCE_CLIENT = true;
|
|
527
|
+
const DB_SOURCE_TYPE = DB_TYPE.SQL;
|
|
528
|
+
|
|
529
|
+
exports.DB_SOURCE_CLIENT = DB_SOURCE_CLIENT;
|
|
530
|
+
exports.DB_SOURCE_TYPE = DB_SOURCE_TYPE;
|
|
531
|
+
exports.checkTimeout = checkTimeout;
|
|
532
|
+
exports.executeBatchQuery = executeBatchQuery;
|
|
533
|
+
exports.executeQuery = executeQuery;
|
|
534
|
+
exports.setCredential = setCredential;
|
package/client/pool.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { DbPoolConstructor } from '@e-mc/types/lib/db';
|
|
|
2
2
|
|
|
3
3
|
import type { DbPoolCredential, MSSQLDataSource } from '../types';
|
|
4
4
|
|
|
5
|
-
import type
|
|
5
|
+
import type mssql_pool from '../types/pool';
|
|
6
6
|
|
|
7
7
|
declare const MSSQLPool: DbPoolConstructor<MSSQLDataSource, mssql_pool, mssql_pool.PooledConnection, DbPoolCredential>;
|
|
8
8
|
|
package/client/pool.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
2
|
+
|
|
3
|
+
const { isObject } = require('@e-mc/types');
|
|
4
|
+
const { checkEmpty } = require('@e-mc/db/util');
|
|
4
5
|
const DbPool = require('@e-mc/db/pool');
|
|
5
6
|
class MSSQLPool extends DbPool {
|
|
6
7
|
static asString(credential) {
|
|
@@ -11,7 +12,7 @@ class MSSQLPool extends DbPool {
|
|
|
11
12
|
const options = credential.options;
|
|
12
13
|
let tls;
|
|
13
14
|
if (options && (tls = options.cryptoCredentialsDetails)) {
|
|
14
|
-
if (!
|
|
15
|
+
if (!isObject(tls)) {
|
|
15
16
|
delete options.cryptoCredentialsDetails;
|
|
16
17
|
}
|
|
17
18
|
else if (tls.ca || tls.cert || tls.key) {
|
|
@@ -54,10 +55,11 @@ class MSSQLPool extends DbPool {
|
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
57
|
isEmpty() {
|
|
57
|
-
return this.closed ||
|
|
58
|
+
return this.closed || checkEmpty(this.client.connections) && checkEmpty(this.client.waiting);
|
|
58
59
|
}
|
|
59
60
|
get closed() {
|
|
60
61
|
return !!this.client.drained;
|
|
61
62
|
}
|
|
62
63
|
}
|
|
64
|
+
|
|
63
65
|
module.exports = MSSQLPool;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-r/mssql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "MSSQL client driver for E-mc.",
|
|
5
5
|
"main": "client/index.js",
|
|
6
6
|
"types": "client/index.d.ts",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"homepage": "https://github.com/anpham6/pi-r#readme",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@e-mc/db": "^0.
|
|
24
|
-
"@e-mc/types": "^0.
|
|
25
|
-
"tedious": "^
|
|
23
|
+
"@e-mc/db": "^0.14.0",
|
|
24
|
+
"@e-mc/types": "^0.14.0",
|
|
25
|
+
"tedious": "^19.2.1",
|
|
26
26
|
"tedious-connection-pool2": "^2.1.0"
|
|
27
27
|
}
|
|
28
28
|
}
|
package/types/pool.d.ts
CHANGED
|
@@ -2,36 +2,28 @@ import type { Connection, ConnectionConfiguration } from 'tedious';
|
|
|
2
2
|
|
|
3
3
|
import EventEmitter from 'node:events';
|
|
4
4
|
|
|
5
|
-
declare
|
|
5
|
+
declare namespace tcp {
|
|
6
6
|
/**
|
|
7
|
-
* Connection
|
|
8
|
-
* @param poolConfig the pool configuration
|
|
9
|
-
* @param connectionConfig the connection configuration
|
|
10
|
-
*/
|
|
11
|
-
constructor(poolConfig: Pool.PoolConfig, connectionConfig: ConnectionConfiguration);
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* acquires a connection from the pool
|
|
15
|
-
* @param callback invoked when the connection is retrieved and ready
|
|
7
|
+
* Extends Tedious Connection with release function
|
|
16
8
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* closes opened connections
|
|
21
|
-
*/
|
|
22
|
-
drain(): void;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
declare namespace Pool {
|
|
26
|
-
|
|
27
|
-
export class PooledConnection extends Connection {
|
|
9
|
+
class PooledConnection extends Connection {
|
|
28
10
|
/**
|
|
29
11
|
* If the connection is issued from a connection pool returns the connection to the pool.
|
|
30
12
|
*/
|
|
31
13
|
release(): void;
|
|
32
14
|
}
|
|
33
15
|
|
|
34
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Provides a connection or an error
|
|
18
|
+
* @param err error if any
|
|
19
|
+
* @param connection issued from the pool
|
|
20
|
+
*/
|
|
21
|
+
type ConnectionCallback = (err: Error, connection: PooledConnection) => void;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Pool Configuration interface
|
|
25
|
+
*/
|
|
26
|
+
interface PoolConfig {
|
|
35
27
|
/**
|
|
36
28
|
* Minimum concurrent connections
|
|
37
29
|
*/
|
|
@@ -64,4 +56,27 @@ declare namespace Pool {
|
|
|
64
56
|
}
|
|
65
57
|
}
|
|
66
58
|
|
|
67
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Tedious Connection Pool Class
|
|
61
|
+
*/
|
|
62
|
+
declare class tcp extends EventEmitter {
|
|
63
|
+
/**
|
|
64
|
+
* Connection Pool constructor
|
|
65
|
+
* @param poolConfig the pool configuration
|
|
66
|
+
* @param connectionConfig the connection configuration
|
|
67
|
+
*/
|
|
68
|
+
constructor(poolConfig: tcp.PoolConfig, connectionConfig: ConnectionConfiguration);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* acquires a connection from the pool
|
|
72
|
+
* @param callback invoked when the connection is retrieved and ready
|
|
73
|
+
*/
|
|
74
|
+
acquire(callback: tcp.ConnectionCallback): void;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* closes opened connections
|
|
78
|
+
*/
|
|
79
|
+
drain(): void;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export = tcp;
|