@slonik/driver 43.0.6
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 +5 -0
- package/dist/Logger.d.ts +2 -0
- package/dist/Logger.d.ts.map +1 -0
- package/dist/Logger.js +8 -0
- package/dist/Logger.js.map +1 -0
- package/dist/factories/createDriverFactory.d.ts +109 -0
- package/dist/factories/createDriverFactory.d.ts.map +1 -0
- package/dist/factories/createDriverFactory.js +227 -0
- package/dist/factories/createDriverFactory.js.map +1 -0
- package/dist/factories/createDriverFactory.test.d.ts +2 -0
- package/dist/factories/createDriverFactory.test.d.ts.map +1 -0
- package/dist/factories/createDriverFactory.test.js +10 -0
- package/dist/factories/createDriverFactory.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/package.json +92 -0
- package/src/Logger.ts +5 -0
- package/src/factories/createDriverFactory.test.ts +5 -0
- package/src/factories/createDriverFactory.ts +439 -0
- package/src/index.ts +16 -0
package/README.md
ADDED
package/dist/Logger.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../src/Logger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,+DAEjB,CAAC"}
|
package/dist/Logger.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Logger.js","sourceRoot":"","sources":["../src/Logger.ts"],"names":[],"mappings":";;;AAAA,iCAA8B;AAEjB,QAAA,MAAM,GAAG,aAAK,CAAC,KAAK,CAAC;IAChC,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
import { type Field } from '@slonik/types';
|
|
5
|
+
import EventEmitter from 'node:events';
|
|
6
|
+
import { type Readable } from 'node:stream';
|
|
7
|
+
import { type ConnectionOptions as TlsConnectionOptions } from 'node:tls';
|
|
8
|
+
import { type StrictEventEmitter } from 'strict-event-emitter-types';
|
|
9
|
+
type StreamDataEvent<T> = {
|
|
10
|
+
data: T;
|
|
11
|
+
fields: readonly Field[];
|
|
12
|
+
};
|
|
13
|
+
export interface DriverStream<T> extends Readable {
|
|
14
|
+
on(event: 'data', listener: (chunk: StreamDataEvent<T>) => void): this;
|
|
15
|
+
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
|
16
|
+
[Symbol.asyncIterator]: () => AsyncIterableIterator<StreamDataEvent<T>>;
|
|
17
|
+
}
|
|
18
|
+
type BasicConnection = {
|
|
19
|
+
readonly query: (query: string) => Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* @property name Value of "pg_type"."typname" (e.g. "int8", "timestamp", "timestamptz").
|
|
23
|
+
*/
|
|
24
|
+
export type DriverTypeParser<T = unknown> = {
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly parse: (value: string) => T;
|
|
27
|
+
};
|
|
28
|
+
export type DriverConfiguration = {
|
|
29
|
+
readonly connectionTimeout: number | 'DISABLE_TIMEOUT';
|
|
30
|
+
readonly connectionUri: string;
|
|
31
|
+
readonly gracefulTerminationTimeout?: number;
|
|
32
|
+
readonly idleInTransactionSessionTimeout: number | 'DISABLE_TIMEOUT';
|
|
33
|
+
readonly idleTimeout?: number | 'DISABLE_TIMEOUT';
|
|
34
|
+
readonly maximumPoolSize?: number;
|
|
35
|
+
readonly resetConnection?: (connection: BasicConnection) => Promise<void>;
|
|
36
|
+
readonly ssl?: TlsConnectionOptions;
|
|
37
|
+
readonly statementTimeout: number | 'DISABLE_TIMEOUT';
|
|
38
|
+
readonly typeParsers: readonly DriverTypeParser[];
|
|
39
|
+
};
|
|
40
|
+
export type DriverNotice = {
|
|
41
|
+
message: string;
|
|
42
|
+
};
|
|
43
|
+
export type DriverEventEmitter = StrictEventEmitter<EventEmitter, {
|
|
44
|
+
error: (error: Error) => void;
|
|
45
|
+
}>;
|
|
46
|
+
export type DriverClientEventEmitter = StrictEventEmitter<EventEmitter, {
|
|
47
|
+
acquire: () => void;
|
|
48
|
+
destroy: () => void;
|
|
49
|
+
error: (error: Error) => void;
|
|
50
|
+
notice: (event: DriverNotice) => void;
|
|
51
|
+
release: () => void;
|
|
52
|
+
}>;
|
|
53
|
+
export type DriverClientState = 'ACQUIRED' | 'DESTROYED' | 'IDLE' | 'PENDING_DESTROY' | 'PENDING_RELEASE';
|
|
54
|
+
export type DriverClient = {
|
|
55
|
+
acquire: () => void;
|
|
56
|
+
destroy: () => Promise<void>;
|
|
57
|
+
id: () => string;
|
|
58
|
+
off: DriverClientEventEmitter['off'];
|
|
59
|
+
on: DriverClientEventEmitter['on'];
|
|
60
|
+
query: (query: string, values?: unknown[]) => Promise<DriverQueryResult>;
|
|
61
|
+
release: () => Promise<void>;
|
|
62
|
+
removeListener: DriverClientEventEmitter['removeListener'];
|
|
63
|
+
state: () => DriverClientState;
|
|
64
|
+
stream: (query: string, values?: unknown[]) => DriverStream<DriverStreamResult>;
|
|
65
|
+
};
|
|
66
|
+
export type Driver = {
|
|
67
|
+
createClient: () => Promise<DriverClient>;
|
|
68
|
+
};
|
|
69
|
+
export type DriverFactory = ({ driverConfiguration, }: {
|
|
70
|
+
driverConfiguration: DriverConfiguration;
|
|
71
|
+
}) => Promise<Driver>;
|
|
72
|
+
type DriverField = {
|
|
73
|
+
dataTypeId: number;
|
|
74
|
+
name: string;
|
|
75
|
+
};
|
|
76
|
+
export type DriverCommand = 'COPY' | 'DELETE' | 'INSERT' | 'SELECT' | 'UPDATE';
|
|
77
|
+
export type DriverQueryResult = {
|
|
78
|
+
readonly command: DriverCommand;
|
|
79
|
+
readonly fields: DriverField[];
|
|
80
|
+
readonly rowCount: number | null;
|
|
81
|
+
readonly rows: Array<Record<string, unknown>>;
|
|
82
|
+
};
|
|
83
|
+
export type DriverStreamResult = {
|
|
84
|
+
readonly fields: DriverField[];
|
|
85
|
+
readonly row: Record<string, unknown>;
|
|
86
|
+
};
|
|
87
|
+
type DriverSetup = ({ driverEventEmitter, driverConfiguration, }: {
|
|
88
|
+
driverConfiguration: DriverConfiguration;
|
|
89
|
+
driverEventEmitter: DriverEventEmitter;
|
|
90
|
+
}) => Promise<InternalPoolClientFactory>;
|
|
91
|
+
/**
|
|
92
|
+
* @property {Function} connect - Connect to the database. The client must not be used before this method is called.
|
|
93
|
+
* @property {Function} end - Disconnect from the database. The client must not be used after this method is called.
|
|
94
|
+
* @property {Function} query - Execute a SQL query.
|
|
95
|
+
*/
|
|
96
|
+
type InternalPoolClient = {
|
|
97
|
+
connect: () => Promise<void>;
|
|
98
|
+
end: () => Promise<void>;
|
|
99
|
+
query: (query: string, values?: unknown[]) => Promise<DriverQueryResult>;
|
|
100
|
+
stream: (query: string, values?: unknown[]) => DriverStream<DriverStreamResult>;
|
|
101
|
+
};
|
|
102
|
+
type InternalPoolClientFactory = {
|
|
103
|
+
createPoolClient: ({ clientEventEmitter, }: {
|
|
104
|
+
clientEventEmitter: DriverClientEventEmitter;
|
|
105
|
+
}) => Promise<InternalPoolClient>;
|
|
106
|
+
};
|
|
107
|
+
export declare const createDriverFactory: (setup: DriverSetup) => DriverFactory;
|
|
108
|
+
export {};
|
|
109
|
+
//# sourceMappingURL=createDriverFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createDriverFactory.d.ts","sourceRoot":"","sources":["../../src/factories/createDriverFactory.ts"],"names":[],"mappings":";;;AACA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,OAAO,YAAY,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,KAAK,iBAAiB,IAAI,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAE1E,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,KAAK,eAAe,CAAC,CAAC,IAAI;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAA;CAAE,CAAC;AAGhE,MAAM,WAAW,YAAY,CAAC,CAAC,CAAE,SAAQ,QAAQ;IAE/C,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAEvE,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAErE,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,MAAM,qBAAqB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;CACzE;AAED,KAAK,eAAe,GAAG;IACrB,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,GAAG,OAAO,IAAI;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAC7C,QAAQ,CAAC,+BAA+B,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACrE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;IAClD,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,QAAQ,CAAC,GAAG,CAAC,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACtD,QAAQ,CAAC,WAAW,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,kBAAkB,CACjD,YAAY,EACZ;IACE,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/B,CACF,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,CACvD,YAAY,EACZ;IACE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC9B,MAAM,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CACF,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,WAAW,GACX,MAAM,GACN,iBAAiB,GACjB,iBAAiB,CAAC;AAEtB,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,EAAE,EAAE,MAAM,MAAM,CAAC;IACjB,GAAG,EAAE,wBAAwB,CAAC,KAAK,CAAC,CAAC;IACrC,EAAE,EAAE,wBAAwB,CAAC,IAAI,CAAC,CAAC;IACnC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,cAAc,EAAE,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;IAC3D,KAAK,EAAE,MAAM,iBAAiB,CAAC;IAC/B,MAAM,EAAE,CACN,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,OAAO,EAAE,KACf,YAAY,CAAC,kBAAkB,CAAC,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,YAAY,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,EAC3B,mBAAmB,GACpB,EAAE;IACD,mBAAmB,EAAE,mBAAmB,CAAC;CAC1C,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEtB,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE/E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF,KAAK,WAAW,GAAG,CAAC,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,EAAE;IACD,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;AAEzC;;;;GAIG;AACH,KAAK,kBAAkB,GAAG;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzE,MAAM,EAAE,CACN,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,OAAO,EAAE,KACf,YAAY,CAAC,kBAAkB,CAAC,CAAC;CACvC,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,gBAAgB,EAAE,CAAC,EACjB,kBAAkB,GACnB,EAAE;QACD,kBAAkB,EAAE,wBAAwB,CAAC;KAC9C,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,mBAAmB,UAAW,WAAW,KAAG,aA8RxD,CAAC"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createDriverFactory = void 0;
|
|
7
|
+
const Logger_1 = require("../Logger");
|
|
8
|
+
const utilities_1 = require("@slonik/utilities");
|
|
9
|
+
const node_events_1 = __importDefault(require("node:events"));
|
|
10
|
+
const promises_1 = require("node:timers/promises");
|
|
11
|
+
const serialize_error_1 = require("serialize-error");
|
|
12
|
+
const createDriverFactory = (setup) => {
|
|
13
|
+
return async ({ driverConfiguration }) => {
|
|
14
|
+
const { resetConnection } = driverConfiguration;
|
|
15
|
+
const driverEventEmitter = new node_events_1.default();
|
|
16
|
+
const { createPoolClient } = await setup({
|
|
17
|
+
driverConfiguration,
|
|
18
|
+
driverEventEmitter,
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
createClient: async () => {
|
|
22
|
+
const clientEventEmitter = new node_events_1.default();
|
|
23
|
+
// eslint-disable-next-line prefer-const
|
|
24
|
+
let destroy;
|
|
25
|
+
const onError = (error) => {
|
|
26
|
+
if (destroy) {
|
|
27
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
28
|
+
void destroy().catch(() => {
|
|
29
|
+
// Do nothing. The error has been emitted already.
|
|
30
|
+
// See "handles unexpected backend termination" test.
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
Logger_1.Logger.warn({
|
|
34
|
+
error: (0, serialize_error_1.serializeError)(error),
|
|
35
|
+
namespace: 'driverClient',
|
|
36
|
+
}, 'unhandled driver client error');
|
|
37
|
+
};
|
|
38
|
+
clientEventEmitter.on('error', onError);
|
|
39
|
+
const { query, stream, connect, end } = await createPoolClient({
|
|
40
|
+
clientEventEmitter,
|
|
41
|
+
});
|
|
42
|
+
let isAcquired = false;
|
|
43
|
+
let isDestroyed = false;
|
|
44
|
+
let idleTimeout = null;
|
|
45
|
+
let activeQueryPromise = null;
|
|
46
|
+
let destroyPromise = null;
|
|
47
|
+
let releasePromise = null;
|
|
48
|
+
const id = (0, utilities_1.generateUid)();
|
|
49
|
+
const clearIdleTimeout = () => {
|
|
50
|
+
if (idleTimeout) {
|
|
51
|
+
clearTimeout(idleTimeout);
|
|
52
|
+
idleTimeout = null;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const state = () => {
|
|
56
|
+
if (destroyPromise) {
|
|
57
|
+
return 'PENDING_DESTROY';
|
|
58
|
+
}
|
|
59
|
+
if (releasePromise) {
|
|
60
|
+
return 'PENDING_RELEASE';
|
|
61
|
+
}
|
|
62
|
+
if (isDestroyed) {
|
|
63
|
+
return 'DESTROYED';
|
|
64
|
+
}
|
|
65
|
+
if (isAcquired) {
|
|
66
|
+
return 'ACQUIRED';
|
|
67
|
+
}
|
|
68
|
+
return 'IDLE';
|
|
69
|
+
};
|
|
70
|
+
const internalDestroy = async () => {
|
|
71
|
+
const currentState = state();
|
|
72
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
73
|
+
throw new Error('Client is pending destroy.');
|
|
74
|
+
}
|
|
75
|
+
if (currentState === 'DESTROYED') {
|
|
76
|
+
throw new Error('Client is destroyed.');
|
|
77
|
+
}
|
|
78
|
+
clearIdleTimeout();
|
|
79
|
+
if (activeQueryPromise) {
|
|
80
|
+
await Promise.race([
|
|
81
|
+
(0, promises_1.setTimeout)(driverConfiguration.gracefulTerminationTimeout),
|
|
82
|
+
activeQueryPromise,
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
if (releasePromise) {
|
|
86
|
+
await releasePromise;
|
|
87
|
+
}
|
|
88
|
+
isDestroyed = true;
|
|
89
|
+
clientEventEmitter.emit('destroy');
|
|
90
|
+
await end();
|
|
91
|
+
clientEventEmitter.off('error', onError);
|
|
92
|
+
};
|
|
93
|
+
destroy = async () => {
|
|
94
|
+
if (destroyPromise) {
|
|
95
|
+
return destroyPromise;
|
|
96
|
+
}
|
|
97
|
+
destroyPromise = internalDestroy();
|
|
98
|
+
return destroyPromise;
|
|
99
|
+
};
|
|
100
|
+
const internalRelease = async () => {
|
|
101
|
+
const currentState = state();
|
|
102
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
103
|
+
throw new Error('Client is pending destroy.');
|
|
104
|
+
}
|
|
105
|
+
if (currentState === 'DESTROYED') {
|
|
106
|
+
throw new Error('Client is destroyed.');
|
|
107
|
+
}
|
|
108
|
+
if (currentState !== 'ACQUIRED') {
|
|
109
|
+
throw new Error('Client is not acquired.');
|
|
110
|
+
}
|
|
111
|
+
if (activeQueryPromise) {
|
|
112
|
+
throw new Error('Client has an active query.');
|
|
113
|
+
}
|
|
114
|
+
if (resetConnection) {
|
|
115
|
+
await resetConnection({
|
|
116
|
+
query: async (sql) => {
|
|
117
|
+
await query(sql);
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (driverConfiguration.idleTimeout !== 'DISABLE_TIMEOUT') {
|
|
122
|
+
clearIdleTimeout();
|
|
123
|
+
idleTimeout = setTimeout(() => {
|
|
124
|
+
void destroy();
|
|
125
|
+
idleTimeout = null;
|
|
126
|
+
}, driverConfiguration.idleTimeout).unref();
|
|
127
|
+
}
|
|
128
|
+
// eslint-disable-next-line require-atomic-updates
|
|
129
|
+
isAcquired = false;
|
|
130
|
+
releasePromise = null;
|
|
131
|
+
clientEventEmitter.emit('release');
|
|
132
|
+
};
|
|
133
|
+
const release = () => {
|
|
134
|
+
if (destroyPromise) {
|
|
135
|
+
return destroyPromise;
|
|
136
|
+
}
|
|
137
|
+
if (releasePromise) {
|
|
138
|
+
return releasePromise;
|
|
139
|
+
}
|
|
140
|
+
releasePromise = internalRelease();
|
|
141
|
+
return releasePromise;
|
|
142
|
+
};
|
|
143
|
+
const client = {
|
|
144
|
+
acquire: () => {
|
|
145
|
+
const currentState = state();
|
|
146
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
147
|
+
throw new Error('Client is pending destroy.');
|
|
148
|
+
}
|
|
149
|
+
if (currentState === 'PENDING_RELEASE') {
|
|
150
|
+
throw new Error('Client is pending release.');
|
|
151
|
+
}
|
|
152
|
+
if (currentState === 'DESTROYED') {
|
|
153
|
+
throw new Error('Client is destroyed.');
|
|
154
|
+
}
|
|
155
|
+
if (currentState === 'ACQUIRED') {
|
|
156
|
+
throw new Error('Client is already acquired.');
|
|
157
|
+
}
|
|
158
|
+
clearIdleTimeout();
|
|
159
|
+
isAcquired = true;
|
|
160
|
+
clientEventEmitter.emit('acquire');
|
|
161
|
+
},
|
|
162
|
+
destroy,
|
|
163
|
+
id: () => id,
|
|
164
|
+
off: (event, listener) => {
|
|
165
|
+
return clientEventEmitter.off(event, listener);
|
|
166
|
+
},
|
|
167
|
+
on: (event, listener) => {
|
|
168
|
+
return clientEventEmitter.on(event, listener);
|
|
169
|
+
},
|
|
170
|
+
query: async (sql, values) => {
|
|
171
|
+
const currentState = state();
|
|
172
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
173
|
+
throw new Error('Client is pending destroy.');
|
|
174
|
+
}
|
|
175
|
+
if (currentState === 'PENDING_RELEASE') {
|
|
176
|
+
throw new Error('Client is pending release.');
|
|
177
|
+
}
|
|
178
|
+
if (currentState === 'DESTROYED') {
|
|
179
|
+
throw new Error('Client is destroyed.');
|
|
180
|
+
}
|
|
181
|
+
if (currentState !== 'ACQUIRED') {
|
|
182
|
+
throw new Error('Client is not acquired.');
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
activeQueryPromise = query(sql, values);
|
|
186
|
+
const result = await activeQueryPromise;
|
|
187
|
+
if (!activeQueryPromise) {
|
|
188
|
+
throw new Error('Expected `activeQueryPromise` to be set.');
|
|
189
|
+
}
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
// eslint-disable-next-line require-atomic-updates
|
|
194
|
+
activeQueryPromise = null;
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
release,
|
|
198
|
+
removeListener: (event, listener) => {
|
|
199
|
+
return clientEventEmitter.removeListener(event, listener);
|
|
200
|
+
},
|
|
201
|
+
state,
|
|
202
|
+
stream: (sql, values) => {
|
|
203
|
+
const currentState = state();
|
|
204
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
205
|
+
throw new Error('Client is pending destroy.');
|
|
206
|
+
}
|
|
207
|
+
if (currentState === 'PENDING_RELEASE') {
|
|
208
|
+
throw new Error('Client is pending release.');
|
|
209
|
+
}
|
|
210
|
+
if (currentState === 'DESTROYED') {
|
|
211
|
+
throw new Error('Client is destroyed.');
|
|
212
|
+
}
|
|
213
|
+
if (currentState !== 'ACQUIRED') {
|
|
214
|
+
throw new Error('Client is not acquired.');
|
|
215
|
+
}
|
|
216
|
+
// TODO determine if streaming and do not allow to release the client until the stream is finished
|
|
217
|
+
return stream(sql, values);
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
await connect();
|
|
221
|
+
return client;
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
exports.createDriverFactory = createDriverFactory;
|
|
227
|
+
//# sourceMappingURL=createDriverFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createDriverFactory.js","sourceRoot":"","sources":["../../src/factories/createDriverFactory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createDriverFactory.test.d.ts","sourceRoot":"","sources":["../../src/factories/createDriverFactory.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const ava_1 = __importDefault(require("ava"));
|
|
7
|
+
(0, ava_1.default)('ok', (t) => {
|
|
8
|
+
t.pass();
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=createDriverFactory.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createDriverFactory.test.js","sourceRoot":"","sources":["../../src/factories/createDriverFactory.test.ts"],"names":[],"mappings":";;;;;AAAA,8CAAuB;AAEvB,IAAA,aAAI,EAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;IACf,CAAC,CAAC,IAAI,EAAE,CAAC;AACX,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { createDriverFactory, type Driver, type DriverClient, type DriverClientEventEmitter, type DriverClientState, type DriverCommand, type DriverConfiguration, type DriverEventEmitter, type DriverFactory, type DriverNotice, type DriverQueryResult, type DriverStream, type DriverStreamResult, type DriverTypeParser, } from './factories/createDriverFactory';
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,iCAAiC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDriverFactory = void 0;
|
|
4
|
+
var createDriverFactory_1 = require("./factories/createDriverFactory");
|
|
5
|
+
Object.defineProperty(exports, "createDriverFactory", { enumerable: true, get: function () { return createDriverFactory_1.createDriverFactory; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uEAeyC;AAdvC,0HAAA,mBAAmB,OAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": {
|
|
3
|
+
"email": "gajus@gajus.com",
|
|
4
|
+
"name": "Gajus Kuizinas",
|
|
5
|
+
"url": "http://gajus.com"
|
|
6
|
+
},
|
|
7
|
+
"ava": {
|
|
8
|
+
"extensions": [
|
|
9
|
+
"ts"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
"src/**/*.test.ts"
|
|
13
|
+
],
|
|
14
|
+
"require": [
|
|
15
|
+
"ts-node/register/transpile-only"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@slonik/utilities": "^43.0.6",
|
|
20
|
+
"@slonik/types": "^43.0.6",
|
|
21
|
+
"serialize-error": "^8.0.0",
|
|
22
|
+
"roarr": "^7.21.1",
|
|
23
|
+
"strict-event-emitter-types": "^2.0.0"
|
|
24
|
+
},
|
|
25
|
+
"description": "A Node.js PostgreSQL client with strict types, detailed logging and assertions.",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^18.15.3",
|
|
28
|
+
"ava": "^5.3.1",
|
|
29
|
+
"cspell": "^8.6.0",
|
|
30
|
+
"eslint": "^8.57.0",
|
|
31
|
+
"eslint-config-canonical": "^42.8.1",
|
|
32
|
+
"nyc": "^15.1.0",
|
|
33
|
+
"ts-node": "^10.9.1",
|
|
34
|
+
"typescript": "^5.4.3"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"./src",
|
|
41
|
+
"./dist"
|
|
42
|
+
],
|
|
43
|
+
"keywords": [
|
|
44
|
+
"postgresql",
|
|
45
|
+
"promise",
|
|
46
|
+
"types"
|
|
47
|
+
],
|
|
48
|
+
"license": "BSD-3-Clause",
|
|
49
|
+
"main": "./dist/index.js",
|
|
50
|
+
"exports": {
|
|
51
|
+
".": {
|
|
52
|
+
"require": "./dist/index.js",
|
|
53
|
+
"types": "./dist/index.d.ts"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"name": "@slonik/driver",
|
|
57
|
+
"nyc": {
|
|
58
|
+
"all": true,
|
|
59
|
+
"exclude": [
|
|
60
|
+
"**/*.d.ts"
|
|
61
|
+
],
|
|
62
|
+
"include": [
|
|
63
|
+
"src/**/*.ts"
|
|
64
|
+
],
|
|
65
|
+
"reporter": [
|
|
66
|
+
"html",
|
|
67
|
+
"text-summary"
|
|
68
|
+
],
|
|
69
|
+
"require": [
|
|
70
|
+
"ts-node/register/transpile-only"
|
|
71
|
+
],
|
|
72
|
+
"silent": true,
|
|
73
|
+
"sourceMap": false
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"zod": "^3"
|
|
77
|
+
},
|
|
78
|
+
"repository": {
|
|
79
|
+
"type": "git",
|
|
80
|
+
"url": "https://github.com/gajus/slonik"
|
|
81
|
+
},
|
|
82
|
+
"scripts": {
|
|
83
|
+
"build": "rm -fr ./dist && tsc --project ./tsconfig.json",
|
|
84
|
+
"lint": "npm run lint:cspell && npm run lint:eslint && npm run lint:tsc",
|
|
85
|
+
"lint:cspell": "cspell . --no-progress --gitignore",
|
|
86
|
+
"lint:eslint": "eslint --cache ./src",
|
|
87
|
+
"lint:tsc": "tsc --noEmit",
|
|
88
|
+
"test": "nyc ava --verbose --serial"
|
|
89
|
+
},
|
|
90
|
+
"types": "./dist/index.d.ts",
|
|
91
|
+
"version": "43.0.6"
|
|
92
|
+
}
|
package/src/Logger.ts
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import { Logger } from '../Logger';
|
|
2
|
+
import { type Field } from '@slonik/types';
|
|
3
|
+
import { generateUid } from '@slonik/utilities';
|
|
4
|
+
import EventEmitter from 'node:events';
|
|
5
|
+
import { type Readable } from 'node:stream';
|
|
6
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
7
|
+
import { type ConnectionOptions as TlsConnectionOptions } from 'node:tls';
|
|
8
|
+
import { serializeError } from 'serialize-error';
|
|
9
|
+
import { type StrictEventEmitter } from 'strict-event-emitter-types';
|
|
10
|
+
|
|
11
|
+
type StreamDataEvent<T> = { data: T; fields: readonly Field[] };
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
14
|
+
export interface DriverStream<T> extends Readable {
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/method-signature-style
|
|
16
|
+
on(event: 'data', listener: (chunk: StreamDataEvent<T>) => void): this;
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/method-signature-style
|
|
18
|
+
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
|
19
|
+
|
|
20
|
+
[Symbol.asyncIterator]: () => AsyncIterableIterator<StreamDataEvent<T>>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type BasicConnection = {
|
|
24
|
+
readonly query: (query: string) => Promise<void>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @property name Value of "pg_type"."typname" (e.g. "int8", "timestamp", "timestamptz").
|
|
29
|
+
*/
|
|
30
|
+
export type DriverTypeParser<T = unknown> = {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly parse: (value: string) => T;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type DriverConfiguration = {
|
|
36
|
+
readonly connectionTimeout: number | 'DISABLE_TIMEOUT';
|
|
37
|
+
readonly connectionUri: string;
|
|
38
|
+
readonly gracefulTerminationTimeout?: number;
|
|
39
|
+
readonly idleInTransactionSessionTimeout: number | 'DISABLE_TIMEOUT';
|
|
40
|
+
readonly idleTimeout?: number | 'DISABLE_TIMEOUT';
|
|
41
|
+
readonly maximumPoolSize?: number;
|
|
42
|
+
readonly resetConnection?: (connection: BasicConnection) => Promise<void>;
|
|
43
|
+
readonly ssl?: TlsConnectionOptions;
|
|
44
|
+
readonly statementTimeout: number | 'DISABLE_TIMEOUT';
|
|
45
|
+
readonly typeParsers: readonly DriverTypeParser[];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type DriverNotice = {
|
|
49
|
+
message: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type DriverEventEmitter = StrictEventEmitter<
|
|
53
|
+
EventEmitter,
|
|
54
|
+
{
|
|
55
|
+
error: (error: Error) => void;
|
|
56
|
+
}
|
|
57
|
+
>;
|
|
58
|
+
|
|
59
|
+
export type DriverClientEventEmitter = StrictEventEmitter<
|
|
60
|
+
EventEmitter,
|
|
61
|
+
{
|
|
62
|
+
acquire: () => void;
|
|
63
|
+
destroy: () => void;
|
|
64
|
+
error: (error: Error) => void;
|
|
65
|
+
notice: (event: DriverNotice) => void;
|
|
66
|
+
release: () => void;
|
|
67
|
+
}
|
|
68
|
+
>;
|
|
69
|
+
|
|
70
|
+
export type DriverClientState =
|
|
71
|
+
| 'ACQUIRED'
|
|
72
|
+
| 'DESTROYED'
|
|
73
|
+
| 'IDLE'
|
|
74
|
+
| 'PENDING_DESTROY'
|
|
75
|
+
| 'PENDING_RELEASE';
|
|
76
|
+
|
|
77
|
+
export type DriverClient = {
|
|
78
|
+
acquire: () => void;
|
|
79
|
+
destroy: () => Promise<void>;
|
|
80
|
+
id: () => string;
|
|
81
|
+
off: DriverClientEventEmitter['off'];
|
|
82
|
+
on: DriverClientEventEmitter['on'];
|
|
83
|
+
query: (query: string, values?: unknown[]) => Promise<DriverQueryResult>;
|
|
84
|
+
release: () => Promise<void>;
|
|
85
|
+
removeListener: DriverClientEventEmitter['removeListener'];
|
|
86
|
+
state: () => DriverClientState;
|
|
87
|
+
stream: (
|
|
88
|
+
query: string,
|
|
89
|
+
values?: unknown[],
|
|
90
|
+
) => DriverStream<DriverStreamResult>;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export type Driver = {
|
|
94
|
+
createClient: () => Promise<DriverClient>;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export type DriverFactory = ({
|
|
98
|
+
driverConfiguration,
|
|
99
|
+
}: {
|
|
100
|
+
driverConfiguration: DriverConfiguration;
|
|
101
|
+
}) => Promise<Driver>;
|
|
102
|
+
|
|
103
|
+
type DriverField = {
|
|
104
|
+
dataTypeId: number;
|
|
105
|
+
name: string;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export type DriverCommand = 'COPY' | 'DELETE' | 'INSERT' | 'SELECT' | 'UPDATE';
|
|
109
|
+
|
|
110
|
+
export type DriverQueryResult = {
|
|
111
|
+
readonly command: DriverCommand;
|
|
112
|
+
readonly fields: DriverField[];
|
|
113
|
+
readonly rowCount: number | null;
|
|
114
|
+
readonly rows: Array<Record<string, unknown>>;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export type DriverStreamResult = {
|
|
118
|
+
readonly fields: DriverField[];
|
|
119
|
+
readonly row: Record<string, unknown>;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
type DriverSetup = ({
|
|
123
|
+
driverEventEmitter,
|
|
124
|
+
driverConfiguration,
|
|
125
|
+
}: {
|
|
126
|
+
driverConfiguration: DriverConfiguration;
|
|
127
|
+
driverEventEmitter: DriverEventEmitter;
|
|
128
|
+
}) => Promise<InternalPoolClientFactory>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @property {Function} connect - Connect to the database. The client must not be used before this method is called.
|
|
132
|
+
* @property {Function} end - Disconnect from the database. The client must not be used after this method is called.
|
|
133
|
+
* @property {Function} query - Execute a SQL query.
|
|
134
|
+
*/
|
|
135
|
+
type InternalPoolClient = {
|
|
136
|
+
connect: () => Promise<void>;
|
|
137
|
+
end: () => Promise<void>;
|
|
138
|
+
query: (query: string, values?: unknown[]) => Promise<DriverQueryResult>;
|
|
139
|
+
stream: (
|
|
140
|
+
query: string,
|
|
141
|
+
values?: unknown[],
|
|
142
|
+
) => DriverStream<DriverStreamResult>;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
type InternalPoolClientFactory = {
|
|
146
|
+
createPoolClient: ({
|
|
147
|
+
clientEventEmitter,
|
|
148
|
+
}: {
|
|
149
|
+
clientEventEmitter: DriverClientEventEmitter;
|
|
150
|
+
}) => Promise<InternalPoolClient>;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export const createDriverFactory = (setup: DriverSetup): DriverFactory => {
|
|
154
|
+
return async ({ driverConfiguration }): Promise<Driver> => {
|
|
155
|
+
const { resetConnection } = driverConfiguration;
|
|
156
|
+
|
|
157
|
+
const driverEventEmitter: DriverEventEmitter = new EventEmitter();
|
|
158
|
+
|
|
159
|
+
const { createPoolClient } = await setup({
|
|
160
|
+
driverConfiguration,
|
|
161
|
+
driverEventEmitter,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
createClient: async () => {
|
|
166
|
+
const clientEventEmitter: DriverClientEventEmitter = new EventEmitter();
|
|
167
|
+
|
|
168
|
+
// eslint-disable-next-line prefer-const
|
|
169
|
+
let destroy: () => Promise<void>;
|
|
170
|
+
|
|
171
|
+
const onError = (error: Error) => {
|
|
172
|
+
if (destroy) {
|
|
173
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
174
|
+
void destroy().catch(() => {
|
|
175
|
+
// Do nothing. The error has been emitted already.
|
|
176
|
+
// See "handles unexpected backend termination" test.
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
Logger.warn(
|
|
181
|
+
{
|
|
182
|
+
error: serializeError(error),
|
|
183
|
+
namespace: 'driverClient',
|
|
184
|
+
},
|
|
185
|
+
'unhandled driver client error',
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
clientEventEmitter.on('error', onError);
|
|
190
|
+
|
|
191
|
+
const { query, stream, connect, end } = await createPoolClient({
|
|
192
|
+
clientEventEmitter,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
let isAcquired = false;
|
|
196
|
+
let isDestroyed = false;
|
|
197
|
+
let idleTimeout: NodeJS.Timeout | null = null;
|
|
198
|
+
|
|
199
|
+
let activeQueryPromise: Promise<DriverQueryResult> | null = null;
|
|
200
|
+
let destroyPromise: Promise<void> | null = null;
|
|
201
|
+
let releasePromise: Promise<void> | null = null;
|
|
202
|
+
|
|
203
|
+
const id = generateUid();
|
|
204
|
+
|
|
205
|
+
const clearIdleTimeout = () => {
|
|
206
|
+
if (idleTimeout) {
|
|
207
|
+
clearTimeout(idleTimeout);
|
|
208
|
+
|
|
209
|
+
idleTimeout = null;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const state = () => {
|
|
214
|
+
if (destroyPromise) {
|
|
215
|
+
return 'PENDING_DESTROY';
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (releasePromise) {
|
|
219
|
+
return 'PENDING_RELEASE';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (isDestroyed) {
|
|
223
|
+
return 'DESTROYED';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (isAcquired) {
|
|
227
|
+
return 'ACQUIRED';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return 'IDLE';
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const internalDestroy = async () => {
|
|
234
|
+
const currentState = state();
|
|
235
|
+
|
|
236
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
237
|
+
throw new Error('Client is pending destroy.');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (currentState === 'DESTROYED') {
|
|
241
|
+
throw new Error('Client is destroyed.');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
clearIdleTimeout();
|
|
245
|
+
|
|
246
|
+
if (activeQueryPromise) {
|
|
247
|
+
await Promise.race([
|
|
248
|
+
delay(driverConfiguration.gracefulTerminationTimeout),
|
|
249
|
+
activeQueryPromise,
|
|
250
|
+
]);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (releasePromise) {
|
|
254
|
+
await releasePromise;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
isDestroyed = true;
|
|
258
|
+
|
|
259
|
+
clientEventEmitter.emit('destroy');
|
|
260
|
+
|
|
261
|
+
await end();
|
|
262
|
+
|
|
263
|
+
clientEventEmitter.off('error', onError);
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
destroy = async () => {
|
|
267
|
+
if (destroyPromise) {
|
|
268
|
+
return destroyPromise;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
destroyPromise = internalDestroy();
|
|
272
|
+
|
|
273
|
+
return destroyPromise;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const internalRelease = async () => {
|
|
277
|
+
const currentState = state();
|
|
278
|
+
|
|
279
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
280
|
+
throw new Error('Client is pending destroy.');
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (currentState === 'DESTROYED') {
|
|
284
|
+
throw new Error('Client is destroyed.');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (currentState !== 'ACQUIRED') {
|
|
288
|
+
throw new Error('Client is not acquired.');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (activeQueryPromise) {
|
|
292
|
+
throw new Error('Client has an active query.');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (resetConnection) {
|
|
296
|
+
await resetConnection({
|
|
297
|
+
query: async (sql) => {
|
|
298
|
+
await query(sql);
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (driverConfiguration.idleTimeout !== 'DISABLE_TIMEOUT') {
|
|
304
|
+
clearIdleTimeout();
|
|
305
|
+
|
|
306
|
+
idleTimeout = setTimeout(() => {
|
|
307
|
+
void destroy();
|
|
308
|
+
|
|
309
|
+
idleTimeout = null;
|
|
310
|
+
}, driverConfiguration.idleTimeout).unref();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// eslint-disable-next-line require-atomic-updates
|
|
314
|
+
isAcquired = false;
|
|
315
|
+
|
|
316
|
+
releasePromise = null;
|
|
317
|
+
|
|
318
|
+
clientEventEmitter.emit('release');
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const release = () => {
|
|
322
|
+
if (destroyPromise) {
|
|
323
|
+
return destroyPromise;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (releasePromise) {
|
|
327
|
+
return releasePromise;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
releasePromise = internalRelease();
|
|
331
|
+
|
|
332
|
+
return releasePromise;
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const client = {
|
|
336
|
+
acquire: () => {
|
|
337
|
+
const currentState = state();
|
|
338
|
+
|
|
339
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
340
|
+
throw new Error('Client is pending destroy.');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (currentState === 'PENDING_RELEASE') {
|
|
344
|
+
throw new Error('Client is pending release.');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (currentState === 'DESTROYED') {
|
|
348
|
+
throw new Error('Client is destroyed.');
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (currentState === 'ACQUIRED') {
|
|
352
|
+
throw new Error('Client is already acquired.');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
clearIdleTimeout();
|
|
356
|
+
|
|
357
|
+
isAcquired = true;
|
|
358
|
+
|
|
359
|
+
clientEventEmitter.emit('acquire');
|
|
360
|
+
},
|
|
361
|
+
destroy,
|
|
362
|
+
id: () => id,
|
|
363
|
+
off: (event, listener) => {
|
|
364
|
+
return clientEventEmitter.off(event, listener);
|
|
365
|
+
},
|
|
366
|
+
on: (event, listener) => {
|
|
367
|
+
return clientEventEmitter.on(event, listener);
|
|
368
|
+
},
|
|
369
|
+
query: async (sql, values) => {
|
|
370
|
+
const currentState = state();
|
|
371
|
+
|
|
372
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
373
|
+
throw new Error('Client is pending destroy.');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (currentState === 'PENDING_RELEASE') {
|
|
377
|
+
throw new Error('Client is pending release.');
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (currentState === 'DESTROYED') {
|
|
381
|
+
throw new Error('Client is destroyed.');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (currentState !== 'ACQUIRED') {
|
|
385
|
+
throw new Error('Client is not acquired.');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
activeQueryPromise = query(sql, values);
|
|
390
|
+
|
|
391
|
+
const result = await activeQueryPromise;
|
|
392
|
+
|
|
393
|
+
if (!activeQueryPromise) {
|
|
394
|
+
throw new Error('Expected `activeQueryPromise` to be set.');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return result;
|
|
398
|
+
} finally {
|
|
399
|
+
// eslint-disable-next-line require-atomic-updates
|
|
400
|
+
activeQueryPromise = null;
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
release,
|
|
404
|
+
removeListener: (event, listener) => {
|
|
405
|
+
return clientEventEmitter.removeListener(event, listener);
|
|
406
|
+
},
|
|
407
|
+
state,
|
|
408
|
+
stream: (sql, values) => {
|
|
409
|
+
const currentState = state();
|
|
410
|
+
|
|
411
|
+
if (currentState === 'PENDING_DESTROY') {
|
|
412
|
+
throw new Error('Client is pending destroy.');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (currentState === 'PENDING_RELEASE') {
|
|
416
|
+
throw new Error('Client is pending release.');
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (currentState === 'DESTROYED') {
|
|
420
|
+
throw new Error('Client is destroyed.');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (currentState !== 'ACQUIRED') {
|
|
424
|
+
throw new Error('Client is not acquired.');
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// TODO determine if streaming and do not allow to release the client until the stream is finished
|
|
428
|
+
|
|
429
|
+
return stream(sql, values);
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
await connect();
|
|
434
|
+
|
|
435
|
+
return client;
|
|
436
|
+
},
|
|
437
|
+
};
|
|
438
|
+
};
|
|
439
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
createDriverFactory,
|
|
3
|
+
type Driver,
|
|
4
|
+
type DriverClient,
|
|
5
|
+
type DriverClientEventEmitter,
|
|
6
|
+
type DriverClientState,
|
|
7
|
+
type DriverCommand,
|
|
8
|
+
type DriverConfiguration,
|
|
9
|
+
type DriverEventEmitter,
|
|
10
|
+
type DriverFactory,
|
|
11
|
+
type DriverNotice,
|
|
12
|
+
type DriverQueryResult,
|
|
13
|
+
type DriverStream,
|
|
14
|
+
type DriverStreamResult,
|
|
15
|
+
type DriverTypeParser,
|
|
16
|
+
} from './factories/createDriverFactory';
|