@m2k-5f/pgtx 2.1.0 → 2.2.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 +34 -0
- package/dist/connection.d.ts +48 -6
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +157 -51
- package/dist/pool.d.ts +12 -0
- package/dist/pool.d.ts.map +1 -1
- package/dist/pool.js +17 -3
- package/dist/protocol/connection-response-reader.d.ts +5 -0
- package/dist/protocol/connection-response-reader.d.ts.map +1 -1
- package/dist/protocol/connection-response-reader.js +7 -0
- package/dist/protocol/constants.d.ts +1 -0
- package/dist/protocol/constants.d.ts.map +1 -1
- package/dist/protocol/constants.js +2 -1
- package/dist/protocol/socket-connector.d.ts.map +1 -1
- package/dist/protocol/socket-connector.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,6 +113,36 @@ await pool.begin(async (tx) => {
|
|
|
113
113
|
})
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
|
|
117
|
+
### Async Notifications (LISTEN / NOTIFY)
|
|
118
|
+
|
|
119
|
+
Pgtx natively handles PostgreSQL `LISTEN/NOTIFY` protocol messages asynchronously without interrupting multiplexed query pipeline.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// 1. Sending a notification
|
|
123
|
+
await pool.notify('user_events', JSON.stringify({ id: 42, action: 'signup' }))
|
|
124
|
+
|
|
125
|
+
// 2. Receiving notifications (Requires a dedicated connection from the pool)
|
|
126
|
+
const conn = await pool.acquire()
|
|
127
|
+
|
|
128
|
+
const onEvent = (payload: string) => {
|
|
129
|
+
console.log(`Received payload: ${payload}`)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Multiplexes multiple callbacks onto a single LISTEN command seamlessly
|
|
133
|
+
await conn.listen('user_events', onEvent)
|
|
134
|
+
await conn.listen('user_events', (data) => logToFile(data))
|
|
135
|
+
|
|
136
|
+
// Clean up callbacks (Sends UNLISTEN only when the channel has zero callbacks left)
|
|
137
|
+
await conn.unlisten('user_events', onEvent)
|
|
138
|
+
|
|
139
|
+
// Keep the connection active as long as you need notifications!
|
|
140
|
+
// Do NOT release it back to the pool prematurely.
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
> ⚠️ **Architecture Note:** While `notify` is atomic and can be triggered directly from the `Pool` on any random socket, `listen` and `unlisten` are stateful commands tied to a specific PostgreSQL backend process. Therefore, subscription methods are **strictly available only on explicit `Connection` instances** fetched via `pool.acquire()`.
|
|
144
|
+
|
|
145
|
+
|
|
116
146
|
### Bulk Inserts
|
|
117
147
|
|
|
118
148
|
```typescript
|
|
@@ -252,6 +282,9 @@ class Connection {
|
|
|
252
282
|
|
|
253
283
|
query<T>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>
|
|
254
284
|
begin<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>
|
|
285
|
+
notify(channelName: string, payload?: string): Promise<[]>
|
|
286
|
+
listen(channelName: string, callback: (payload: string) => void): Promise<[]>
|
|
287
|
+
unlisten(channelName: string, callback: (payload: string) => void): Promise<[]>
|
|
255
288
|
|
|
256
289
|
get isAlive(): boolean
|
|
257
290
|
close(): void
|
|
@@ -275,6 +308,7 @@ class Pool {
|
|
|
275
308
|
|
|
276
309
|
query<T>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>
|
|
277
310
|
begin<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>
|
|
311
|
+
notify(channelName: string, payload?: string): Promise<[]>
|
|
278
312
|
acquire(): Promise<Connection>
|
|
279
313
|
release(conn: Connection): void
|
|
280
314
|
close(): Promise<void>
|
package/dist/connection.d.ts
CHANGED
|
@@ -26,8 +26,9 @@ export type DescribeQueueUnit = {
|
|
|
26
26
|
reject: (error: Error) => void;
|
|
27
27
|
statementName: StatementName;
|
|
28
28
|
};
|
|
29
|
-
export type StatementName = Branded<string, '
|
|
30
|
-
export type QueryText = Branded<string, '
|
|
29
|
+
export type StatementName = Branded<string, 'StatementName'>;
|
|
30
|
+
export type QueryText = Branded<string, 'QueryText'>;
|
|
31
|
+
export type ChannelName = Branded<string, "ChannelName">;
|
|
31
32
|
/**
|
|
32
33
|
* Represents a single dedicated connection to the PostgreSQL database.
|
|
33
34
|
*
|
|
@@ -59,8 +60,10 @@ export type QueryText = Branded<string, 'queryText'>;
|
|
|
59
60
|
* ```
|
|
60
61
|
*/
|
|
61
62
|
export declare class Connection {
|
|
63
|
+
private readonly params;
|
|
62
64
|
private _isFlushing;
|
|
63
|
-
private
|
|
65
|
+
private _isOpened;
|
|
66
|
+
private _isReconnecting;
|
|
64
67
|
private _socket;
|
|
65
68
|
private _writer;
|
|
66
69
|
private _pipelinesQueue;
|
|
@@ -68,6 +71,7 @@ export declare class Connection {
|
|
|
68
71
|
private _describingPending;
|
|
69
72
|
private _parsed;
|
|
70
73
|
private _parsingPending;
|
|
74
|
+
private _listeningCallbacks;
|
|
71
75
|
private _stmtCounter;
|
|
72
76
|
private _logLevel;
|
|
73
77
|
private _nextStatement;
|
|
@@ -116,8 +120,6 @@ export declare class Connection {
|
|
|
116
120
|
* ```
|
|
117
121
|
*/
|
|
118
122
|
query<T extends Record<string, any>>(templates: TemplateStringsArray, ...params: any[]): Promise<T[]>;
|
|
119
|
-
private _createQuery;
|
|
120
|
-
private _writeQuery;
|
|
121
123
|
/**
|
|
122
124
|
* Starts a managed transaction on this connection.
|
|
123
125
|
*
|
|
@@ -140,8 +142,48 @@ export declare class Connection {
|
|
|
140
142
|
* ```
|
|
141
143
|
*/
|
|
142
144
|
begin<T>(txCallback: (transaction: Transaction) => Promise<T>): Promise<T>;
|
|
145
|
+
/**
|
|
146
|
+
* Sends an asynchronous notification to a channel via `pg_notify`.
|
|
147
|
+
*
|
|
148
|
+
* @param channelName - The channel identifier
|
|
149
|
+
* @param payload - Optional string data (max 8000 bytes)
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* await conn.notify('events', 'hello')
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
notify(channelName: string, payload?: string): Promise<[]>;
|
|
157
|
+
/**
|
|
158
|
+
* Subscribes a callback to a channel. Sends `LISTEN` on the first subscription.
|
|
159
|
+
*
|
|
160
|
+
* @param channelName - The channel identifier
|
|
161
|
+
* @param callback - Function invoked when a notification arrives
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* await conn.listen('events', data => console.log(data))
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
listen(channelName: string, callback: (payload: string) => void): Promise<Record<string, any>[]>;
|
|
169
|
+
/**
|
|
170
|
+
* Unsubscribes a callback. Sends `UNLISTEN` if no callbacks remain for the channel.
|
|
171
|
+
*
|
|
172
|
+
* @param channelName - The channel identifier
|
|
173
|
+
* @param callback - The registered callback to remove
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```ts
|
|
177
|
+
* await conn.unlisten('events', callback)
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
unlisten(channelName: string, callback: (payload: string) => void): Promise<void> | Promise<Record<string, any>[]>;
|
|
181
|
+
private _createQuery;
|
|
182
|
+
private _writeQuery;
|
|
143
183
|
private _registerFlush;
|
|
144
184
|
private _flush;
|
|
185
|
+
private _reconnect;
|
|
186
|
+
private _restoreSubscriptions;
|
|
145
187
|
private _getCurrentQuery;
|
|
146
188
|
private _rejectPipeline;
|
|
147
189
|
private _handlePacket;
|
|
@@ -149,7 +191,7 @@ export declare class Connection {
|
|
|
149
191
|
* Checks if the connection is still alive and usable.
|
|
150
192
|
* Returns `false` if the socket is destroyed or connection is dead.
|
|
151
193
|
*/
|
|
152
|
-
get
|
|
194
|
+
get isOpened(): boolean;
|
|
153
195
|
private _destroyConnection;
|
|
154
196
|
/**
|
|
155
197
|
* Closes the connection immediately.
|
package/dist/connection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
|
package/dist/connection.js
CHANGED
|
@@ -11,6 +11,7 @@ const transaction_1 = require("./transaction");
|
|
|
11
11
|
const socket_connector_1 = require("./protocol/socket-connector");
|
|
12
12
|
const queue_1 = require("./queue");
|
|
13
13
|
const query_1 = require("./query");
|
|
14
|
+
const _1 = require(".");
|
|
14
15
|
const ErrConnectionDead = new Error("Connection is Dead");
|
|
15
16
|
/**
|
|
16
17
|
* Represents a single dedicated connection to the PostgreSQL database.
|
|
@@ -46,18 +47,22 @@ class Connection {
|
|
|
46
47
|
_nextStatement() {
|
|
47
48
|
return `s-${this._stmtCounter++}`;
|
|
48
49
|
}
|
|
49
|
-
constructor(socket, writer, logLevel) {
|
|
50
|
+
constructor(socket, writer, logLevel, params) {
|
|
50
51
|
this._isFlushing = false;
|
|
51
|
-
this.
|
|
52
|
+
this._isOpened = true;
|
|
53
|
+
this._isReconnecting = false;
|
|
52
54
|
this._pipelinesQueue = new queue_1.Queue();
|
|
53
55
|
this._described = new Map();
|
|
54
56
|
this._describingPending = new Set();
|
|
55
57
|
this._parsed = new Map();
|
|
56
58
|
this._parsingPending = new Map();
|
|
59
|
+
this._listeningCallbacks = new Map();
|
|
57
60
|
this._stmtCounter = 0;
|
|
61
|
+
this.params = params;
|
|
58
62
|
this._logLevel = logLevel;
|
|
59
63
|
this._socket = new socket_connector_1.SocketConnector(socket, (type, reader) => this._handlePacket(type, reader), (err) => {
|
|
60
|
-
this.
|
|
64
|
+
this._isReconnecting = true;
|
|
65
|
+
this._rejectPipeline(ErrConnectionDead);
|
|
61
66
|
});
|
|
62
67
|
this._writer = writer;
|
|
63
68
|
}
|
|
@@ -82,7 +87,7 @@ class Connection {
|
|
|
82
87
|
static async new(params) {
|
|
83
88
|
const writer = connection_request_writer_1.ConnectionRequestWriter.new();
|
|
84
89
|
const socket = await (0, socket_authorization_1.createAuthorizedSocket)(writer, params);
|
|
85
|
-
return new Connection(socket, writer, params.logLevel || 'error');
|
|
90
|
+
return new Connection(socket, writer, params.logLevel || 'error', params);
|
|
86
91
|
}
|
|
87
92
|
/**
|
|
88
93
|
* Executes a query using tagged template literals.
|
|
@@ -110,7 +115,7 @@ class Connection {
|
|
|
110
115
|
*/
|
|
111
116
|
query(templates, ...params) {
|
|
112
117
|
this._registerFlush();
|
|
113
|
-
if (!this.
|
|
118
|
+
if (!this._isOpened)
|
|
114
119
|
throw ErrConnectionDead;
|
|
115
120
|
const { text, args } = (0, template_compiler_1.compileSqlTemplate)({ templates, args: params });
|
|
116
121
|
if (this._logLevel === 'query') {
|
|
@@ -120,6 +125,100 @@ class Connection {
|
|
|
120
125
|
this._writeQuery(query);
|
|
121
126
|
return query.promise;
|
|
122
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Starts a managed transaction on this connection.
|
|
130
|
+
*
|
|
131
|
+
* Automatically handles:
|
|
132
|
+
* - `BEGIN` before the callback
|
|
133
|
+
* - `COMMIT` on successful completion
|
|
134
|
+
* - `ROLLBACK` if an error is thrown
|
|
135
|
+
*
|
|
136
|
+
* @param txCallback - Async function that receives a `Transaction` instance
|
|
137
|
+
* @returns The value returned from the callback
|
|
138
|
+
* @throws {Error} If connection is dead or transaction fails
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const result = await conn.begin(async tx => {
|
|
143
|
+
* await tx.query`INSERT INTO accounts (id, balance) VALUES (1, 100)`
|
|
144
|
+
* await tx.query`UPDATE accounts SET balance = balance - 10 WHERE id = 1`
|
|
145
|
+
* return { success: true }
|
|
146
|
+
* })
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
async begin(txCallback) {
|
|
150
|
+
if (!this._isOpened)
|
|
151
|
+
throw ErrConnectionDead;
|
|
152
|
+
const tx = new transaction_1.Transaction(this);
|
|
153
|
+
try {
|
|
154
|
+
await tx.query `BEGIN`;
|
|
155
|
+
const result = await txCallback(tx);
|
|
156
|
+
if (tx.isActive)
|
|
157
|
+
await tx.commit();
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
if (tx.isActive)
|
|
162
|
+
await tx.rollback();
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Sends an asynchronous notification to a channel via `pg_notify`.
|
|
168
|
+
*
|
|
169
|
+
* @param channelName - The channel identifier
|
|
170
|
+
* @param payload - Optional string data (max 8000 bytes)
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* await conn.notify('events', 'hello')
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
notify(channelName, payload = "") {
|
|
178
|
+
return this.query `select pg_notify(${channelName}, ${payload})`;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Subscribes a callback to a channel. Sends `LISTEN` on the first subscription.
|
|
182
|
+
*
|
|
183
|
+
* @param channelName - The channel identifier
|
|
184
|
+
* @param callback - Function invoked when a notification arrives
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* await conn.listen('events', data => console.log(data))
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
listen(channelName, callback) {
|
|
192
|
+
if (!this._listeningCallbacks.has(channelName)) {
|
|
193
|
+
this._listeningCallbacks.set(channelName, new Set());
|
|
194
|
+
}
|
|
195
|
+
const callbackSet = this._listeningCallbacks.get(channelName);
|
|
196
|
+
callbackSet.add(callback);
|
|
197
|
+
return this.query `listen ${_1.sql.ident(channelName)};`;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Unsubscribes a callback. Sends `UNLISTEN` if no callbacks remain for the channel.
|
|
201
|
+
*
|
|
202
|
+
* @param channelName - The channel identifier
|
|
203
|
+
* @param callback - The registered callback to remove
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* await conn.unlisten('events', callback)
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
unlisten(channelName, callback) {
|
|
211
|
+
if (!this._listeningCallbacks.has(channelName)) {
|
|
212
|
+
return Promise.resolve();
|
|
213
|
+
}
|
|
214
|
+
const callbackSet = this._listeningCallbacks.get(channelName);
|
|
215
|
+
callbackSet.delete(callback);
|
|
216
|
+
if (callbackSet.size === 0) {
|
|
217
|
+
this._listeningCallbacks.delete(channelName);
|
|
218
|
+
return this.query `unlisten ${_1.sql.ident(channelName)};`;
|
|
219
|
+
}
|
|
220
|
+
return Promise.resolve();
|
|
221
|
+
}
|
|
123
222
|
_createQuery(text, args) {
|
|
124
223
|
if (this._parsed.has(text)) {
|
|
125
224
|
const statementName = this._parsed.get(text);
|
|
@@ -170,44 +269,6 @@ class Connection {
|
|
|
170
269
|
}
|
|
171
270
|
this._pipelinesQueue.get().push(query);
|
|
172
271
|
}
|
|
173
|
-
/**
|
|
174
|
-
* Starts a managed transaction on this connection.
|
|
175
|
-
*
|
|
176
|
-
* Automatically handles:
|
|
177
|
-
* - `BEGIN` before the callback
|
|
178
|
-
* - `COMMIT` on successful completion
|
|
179
|
-
* - `ROLLBACK` if an error is thrown
|
|
180
|
-
*
|
|
181
|
-
* @param txCallback - Async function that receives a `Transaction` instance
|
|
182
|
-
* @returns The value returned from the callback
|
|
183
|
-
* @throws {Error} If connection is dead or transaction fails
|
|
184
|
-
*
|
|
185
|
-
* @example
|
|
186
|
-
* ```ts
|
|
187
|
-
* const result = await conn.begin(async tx => {
|
|
188
|
-
* await tx.query`INSERT INTO accounts (id, balance) VALUES (1, 100)`
|
|
189
|
-
* await tx.query`UPDATE accounts SET balance = balance - 10 WHERE id = 1`
|
|
190
|
-
* return { success: true }
|
|
191
|
-
* })
|
|
192
|
-
* ```
|
|
193
|
-
*/
|
|
194
|
-
async begin(txCallback) {
|
|
195
|
-
if (!this._isAlive)
|
|
196
|
-
throw ErrConnectionDead;
|
|
197
|
-
const tx = new transaction_1.Transaction(this);
|
|
198
|
-
try {
|
|
199
|
-
await tx.query `BEGIN`;
|
|
200
|
-
const result = await txCallback(tx);
|
|
201
|
-
if (tx.isActive)
|
|
202
|
-
await tx.commit();
|
|
203
|
-
return result;
|
|
204
|
-
}
|
|
205
|
-
catch (err) {
|
|
206
|
-
if (tx.isActive)
|
|
207
|
-
await tx.rollback();
|
|
208
|
-
throw err;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
272
|
_registerFlush() {
|
|
212
273
|
if (!this._isFlushing) {
|
|
213
274
|
this._isFlushing = true;
|
|
@@ -218,18 +279,54 @@ class Connection {
|
|
|
218
279
|
}
|
|
219
280
|
}
|
|
220
281
|
_flush() {
|
|
221
|
-
this.
|
|
222
|
-
if (!this._isAlive) {
|
|
282
|
+
if (!this._isOpened) {
|
|
223
283
|
this._rejectPipeline(ErrConnectionDead);
|
|
224
284
|
return;
|
|
225
285
|
}
|
|
226
|
-
|
|
286
|
+
if (this._isReconnecting) {
|
|
287
|
+
this._reconnect().then(socket => {
|
|
288
|
+
this._isFlushing = false;
|
|
289
|
+
socket.write(this._writer.writeSync());
|
|
290
|
+
this._writer.clear();
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
this._isFlushing = false;
|
|
227
295
|
this._socket.write(this._writer.writeSync());
|
|
228
296
|
this._writer.clear();
|
|
229
297
|
}
|
|
230
|
-
|
|
231
|
-
|
|
298
|
+
}
|
|
299
|
+
_reconnect() {
|
|
300
|
+
this._parsed.clear();
|
|
301
|
+
this._described.clear();
|
|
302
|
+
this._describingPending.clear();
|
|
303
|
+
this._parsingPending.clear();
|
|
304
|
+
this._writer.clear();
|
|
305
|
+
while (this._pipelinesQueue.hasMore) {
|
|
306
|
+
this._rejectPipeline(ErrConnectionDead);
|
|
307
|
+
this._pipelinesQueue.next();
|
|
232
308
|
}
|
|
309
|
+
this._pipelinesQueue = new queue_1.Queue();
|
|
310
|
+
this._pipelinesQueue.push(new queue_1.Queue());
|
|
311
|
+
return (0, socket_authorization_1.createAuthorizedSocket)(connection_request_writer_1.ConnectionRequestWriter.new(), this.params)
|
|
312
|
+
.then(socket => {
|
|
313
|
+
const connector = new socket_connector_1.SocketConnector(socket, (type, reader) => this._handlePacket(type, reader), (err) => {
|
|
314
|
+
this._isReconnecting = true;
|
|
315
|
+
this._rejectPipeline(ErrConnectionDead);
|
|
316
|
+
});
|
|
317
|
+
this._socket = connector;
|
|
318
|
+
this._restoreSubscriptions();
|
|
319
|
+
this._isReconnecting = false;
|
|
320
|
+
return connector;
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
_restoreSubscriptions() {
|
|
324
|
+
if (this._listeningCallbacks.size === 0)
|
|
325
|
+
return Promise.resolve();
|
|
326
|
+
const promises = Array.from(this._listeningCallbacks.keys()).map(channel => {
|
|
327
|
+
return this.query `LISTEN ${_1.sql.ident(channel)};`;
|
|
328
|
+
});
|
|
329
|
+
return Promise.all(promises);
|
|
233
330
|
}
|
|
234
331
|
_getCurrentQuery() {
|
|
235
332
|
return this._pipelinesQueue.get().get();
|
|
@@ -350,6 +447,15 @@ class Connection {
|
|
|
350
447
|
}
|
|
351
448
|
}
|
|
352
449
|
break;
|
|
450
|
+
case constants_1.ResponseTypes.NotificationResponse:
|
|
451
|
+
{
|
|
452
|
+
const { name, payload } = reader.readNotificationResponse();
|
|
453
|
+
const callbackSet = this._listeningCallbacks.get(name);
|
|
454
|
+
if (!callbackSet)
|
|
455
|
+
break;
|
|
456
|
+
callbackSet.forEach(cb => cb(payload));
|
|
457
|
+
}
|
|
458
|
+
break;
|
|
353
459
|
default: console.warn('Undeclared response type: ', type);
|
|
354
460
|
}
|
|
355
461
|
}
|
|
@@ -357,11 +463,11 @@ class Connection {
|
|
|
357
463
|
* Checks if the connection is still alive and usable.
|
|
358
464
|
* Returns `false` if the socket is destroyed or connection is dead.
|
|
359
465
|
*/
|
|
360
|
-
get
|
|
361
|
-
return this.
|
|
466
|
+
get isOpened() {
|
|
467
|
+
return this._isOpened;
|
|
362
468
|
}
|
|
363
469
|
_destroyConnection() {
|
|
364
|
-
this.
|
|
470
|
+
this._isOpened = false;
|
|
365
471
|
this._socket.destroy();
|
|
366
472
|
while (this._pipelinesQueue.hasMore) {
|
|
367
473
|
this._rejectPipeline(ErrConnectionDead);
|
package/dist/pool.d.ts
CHANGED
|
@@ -128,6 +128,18 @@ export declare class Pool {
|
|
|
128
128
|
* ```
|
|
129
129
|
*/
|
|
130
130
|
query<T extends Record<string, any>>(templates: TemplateStringsArray, ...args: any[]): Promise<T[]>;
|
|
131
|
+
/**
|
|
132
|
+
* Sends an asynchronous notification to a channel via `pg_notify`.
|
|
133
|
+
*
|
|
134
|
+
* @param channelName - The channel identifier
|
|
135
|
+
* @param payload - Optional string data (max 8000 bytes)
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* await pool.notify('events', 'hello')
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
notify(channelName: string, payload?: string): Promise<[]>;
|
|
131
143
|
/**
|
|
132
144
|
* Number of available (idle) connections in the pool.
|
|
133
145
|
*/
|
package/dist/pool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAK3C,KAAK,UAAU,GAAG,gBAAgB,GAAG;IACjC,GAAG,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,IAAI;IACb,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,YAAY;gBAIR,MAAM,EAAE,UAAU;IAM9B;;;;;;;;;;;;;;;;;OAiBG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IA6BpC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,IAAI,EAAE,UAAU;IAoBxB;;;;;;;;;;;;;;;;;OAiBG;IACG,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAYhF;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAmCnG;;OAEG;IACH,IAAI,IAAI,WAEP;IAGD;;;OAGG;IACH,IAAI,KAAK,WAER;IAGD;;;;;;;;;;OAUG;IACG,KAAK;CAed"}
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAK3C,KAAK,UAAU,GAAG,gBAAgB,GAAG;IACjC,GAAG,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,IAAI;IACb,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,YAAY;gBAIR,MAAM,EAAE,UAAU;IAM9B;;;;;;;;;;;;;;;;;OAiBG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IA6BpC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,IAAI,EAAE,UAAU;IAoBxB;;;;;;;;;;;;;;;;;OAiBG;IACG,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAYhF;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAmCnG;;;;;;;;;;OAUG;IACH,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW,GACuB,OAAO,CAAC,EAAE,CAAC;IAIlF;;OAEG;IACH,IAAI,IAAI,WAEP;IAGD;;;OAGG;IACH,IAAI,KAAK,WAER;IAGD;;;;;;;;;;OAUG;IACG,KAAK;CAed"}
|
package/dist/pool.js
CHANGED
|
@@ -74,7 +74,7 @@ class Pool {
|
|
|
74
74
|
while (this._available.hasMore) {
|
|
75
75
|
const conn = this._available.get();
|
|
76
76
|
this._available.next();
|
|
77
|
-
if (conn.
|
|
77
|
+
if (conn.isOpened) {
|
|
78
78
|
return conn;
|
|
79
79
|
}
|
|
80
80
|
this._total--;
|
|
@@ -113,7 +113,7 @@ class Pool {
|
|
|
113
113
|
*/
|
|
114
114
|
release(conn) {
|
|
115
115
|
this._checkClosed();
|
|
116
|
-
if (!conn.
|
|
116
|
+
if (!conn.isOpened) {
|
|
117
117
|
this._total--;
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
@@ -180,7 +180,7 @@ class Pool {
|
|
|
180
180
|
this._checkClosed();
|
|
181
181
|
while (this._available.hasMore) {
|
|
182
182
|
const conn = this._available.get();
|
|
183
|
-
if (conn.
|
|
183
|
+
if (conn.isOpened) {
|
|
184
184
|
return conn.query(templates, ...args);
|
|
185
185
|
}
|
|
186
186
|
this._available.next();
|
|
@@ -204,6 +204,20 @@ class Pool {
|
|
|
204
204
|
return conn.query(templates, ...args);
|
|
205
205
|
});
|
|
206
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Sends an asynchronous notification to a channel via `pg_notify`.
|
|
209
|
+
*
|
|
210
|
+
* @param channelName - The channel identifier
|
|
211
|
+
* @param payload - Optional string data (max 8000 bytes)
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```ts
|
|
215
|
+
* await pool.notify('events', 'hello')
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
notify(channelName, payload = "") {
|
|
219
|
+
return this.query `select pg_notify(${channelName}, ${payload})`;
|
|
220
|
+
}
|
|
207
221
|
/**
|
|
208
222
|
* Number of available (idle) connections in the pool.
|
|
209
223
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AuthenticationCode, ResponseType, TransactionStatus } from "./constants";
|
|
2
2
|
import { ColumnDescription } from "../types";
|
|
3
3
|
import { PostgresError } from "../error";
|
|
4
|
+
import { ChannelName } from "../connection";
|
|
4
5
|
export declare class ConnectionResponseBuffer {
|
|
5
6
|
private buffer;
|
|
6
7
|
private caret;
|
|
@@ -38,6 +39,10 @@ export declare class ConnectionResponseReader {
|
|
|
38
39
|
readSaslMessage(): string;
|
|
39
40
|
readRowDescription(): ColumnDescription[];
|
|
40
41
|
readDataRow(): (string | null)[];
|
|
42
|
+
readNotificationResponse(): {
|
|
43
|
+
name: ChannelName;
|
|
44
|
+
payload: string;
|
|
45
|
+
};
|
|
41
46
|
readCommandComplete(): string;
|
|
42
47
|
hasMore(): boolean;
|
|
43
48
|
hasFullPacket(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-response-reader.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-response-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"connection-response-reader.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-response-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAG3C,qBAAa,wBAAwB;IAI7B,OAAO,CAAC,MAAM;IAHlB,OAAO,CAAC,KAAK,CAAI;IAEjB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ,IAAI,MAAM;IAOlB,SAAS,IAAI,MAAM;IAOnB,SAAS,IAAI,MAAM;IAOnB,WAAW,IAAI,MAAM;IAQrB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAOrC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAOjC,OAAO,IAAI,OAAO;IAKlB,aAAa,IAAI,OAAO;IAaxB,iBAAiB;CAGpB;AAGD,qBAAa,wBAAwB;IAI7B,OAAO,CAAC,MAAM;IAHlB,OAAO,CAAC,mBAAmB,CAAK;IAEhC,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ,IAC6B,YAAY;IAIjD,kBAAkB,IAGoB,kBAAkB;IAIxD,WAAW;IAKX,mBAAmB;;;;IAUnB,kBAAkB;;;;IAUlB,iBAAiB,IAAI,aAAa;IA8ClC,iBAAiB,IAEoB,iBAAiB;IAItD,kBAAkB,IAAI,MAAM,EAAE;IAa9B,eAAe,IAAI,MAAM;IAOzB,kBAAkB;IAuBlB,WAAW;IAmBX,wBAAwB;;;;IAUxB,mBAAmB,IAAI,MAAM;IAM7B,OAAO;IAKP,aAAa;IAKb,iBAAiB;IAKjB,iBAAiB;IAKjB,gBAAgB;IAKhB,wBAAwB;IAQxB,UAAU;CAGb"}
|
|
@@ -188,6 +188,13 @@ class ConnectionResponseReader {
|
|
|
188
188
|
}
|
|
189
189
|
return rowValues;
|
|
190
190
|
}
|
|
191
|
+
readNotificationResponse() {
|
|
192
|
+
this.buffer.readInt32();
|
|
193
|
+
this.buffer.readInt32();
|
|
194
|
+
const name = this.buffer.readCString();
|
|
195
|
+
const payload = this.buffer.readCString();
|
|
196
|
+
return { name, payload };
|
|
197
|
+
}
|
|
191
198
|
readCommandComplete() {
|
|
192
199
|
this.buffer.readInt32();
|
|
193
200
|
return this.buffer.readCString();
|
|
@@ -26,6 +26,7 @@ export declare const ResponseTypes: {
|
|
|
26
26
|
readonly ParameterDescription: "t";
|
|
27
27
|
readonly NoData: "n";
|
|
28
28
|
readonly Notice: "N";
|
|
29
|
+
readonly NotificationResponse: "A";
|
|
29
30
|
};
|
|
30
31
|
export type ResponseType = ValueOF<typeof ResponseTypes>;
|
|
31
32
|
export declare const AuthenticationCodes: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/protocol/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAElC,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,YAAY,CAAC,CAAA;AAGtD,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/protocol/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAElC,eAAO,MAAM,YAAY;;;;;;;;;CASf,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,YAAY,CAAC,CAAA;AAGtD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;CAiBhB,CAAA;AAGV,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,aAAa,CAAC,CAAA;AAGxD,eAAO,MAAM,mBAAmB;;;;;;;CAOtB,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAGpE,eAAO,MAAM,mBAAmB;;;;CAItB,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,mBAAmB,CAAC,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-connector.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAE/E,qBAAa,eAAe;IAKpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IANpB,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,YAAY,CAAQ;gBAGhB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,wBAAwB,KAAK,IAAI,EACvE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;
|
|
1
|
+
{"version":3,"file":"socket-connector.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAE/E,qBAAa,eAAe;IAKpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IANpB,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,YAAY,CAAQ;gBAGhB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,wBAAwB,KAAK,IAAI,EACvE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;IA6B5C,KAAK,CAAC,MAAM,EAAE,uBAAuB;IAOrC,YAAY;IAQZ,OAAO;IAMP,IAAI,WAAW,YAA6B;CAC/C"}
|
|
@@ -9,6 +9,7 @@ class SocketConnector {
|
|
|
9
9
|
this._onError = _onError;
|
|
10
10
|
this.residualBuffer = null;
|
|
11
11
|
this._isDestroyed = false;
|
|
12
|
+
_socket.setKeepAlive(true, 10000);
|
|
12
13
|
_socket.on('data', buffer => {
|
|
13
14
|
const currentBuffer = this.residualBuffer
|
|
14
15
|
? Buffer.concat([this.residualBuffer, buffer])
|