@m2k-5f/pgtx 2.0.1 → 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 +40 -4
- package/dist/connection.d.ts +72 -18
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +259 -97
- package/dist/error.d.ts +18 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +37 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/pool.d.ts +13 -1
- package/dist/pool.d.ts.map +1 -1
- package/dist/pool.js +22 -8
- package/dist/protocol/connection-response-reader.d.ts +7 -1
- package/dist/protocol/connection-response-reader.d.ts.map +1 -1
- package/dist/protocol/connection-response-reader.js +46 -3
- 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/dist/query.d.ts +24 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +28 -0
- package/dist/queue.d.ts +2 -0
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +14 -2
- package/dist/transaction.d.ts +1 -1
- package/dist/transaction.d.ts.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/value-parser.d.ts +1 -1
- package/dist/utils/value-parser.d.ts.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -25,10 +25,12 @@ npm install @m2k-5f/pgtx
|
|
|
25
25
|
|
|
26
26
|
| Tool | RPS | Avg Time | Connections |
|
|
27
27
|
|------|-----|----------|-------------|
|
|
28
|
-
| **Pgtx** | **1584** | **0.631ms** | **20 (
|
|
29
|
-
| Native `pg` | 179 | 5.585ms | 20 |
|
|
28
|
+
| **Pgtx** | **1584** | **0.631ms** | **20 pool connections (pipeline multiplexing)** |
|
|
29
|
+
| Native `pg` | 179 | 5.585ms | 20 pool connections |
|
|
30
30
|
|
|
31
|
-
**9x faster**
|
|
31
|
+
**Up to 9x faster in concurrent pipeline workloads**
|
|
32
|
+
|
|
33
|
+
**Pgtx achieves higher throughput by multiplexing concurrent queries over PostgreSQL connections using pipeline execution.**
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
> Benchmark source available in the [repository](https://github.com/M2K-5F/pgtx).
|
|
@@ -43,7 +45,7 @@ npm install @m2k-5f/pgtx
|
|
|
43
45
|
- **Bulk inserts** — Auto-extract columns from objects
|
|
44
46
|
- **Dynamic updates** — Generate SET clauses from objects
|
|
45
47
|
- **Recursive fragments** — Compose SQL like Lego
|
|
46
|
-
- **Prepared statements** —
|
|
48
|
+
- **Prepared statements** — Automatic prepared statement caching
|
|
47
49
|
- **Connection pool** — Auto-management connections with support for pipeline queries via the pool itself.
|
|
48
50
|
- **Zero dependencies** — Lightweight and blazing
|
|
49
51
|
|
|
@@ -111,6 +113,36 @@ await pool.begin(async (tx) => {
|
|
|
111
113
|
})
|
|
112
114
|
```
|
|
113
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
|
+
|
|
114
146
|
### Bulk Inserts
|
|
115
147
|
|
|
116
148
|
```typescript
|
|
@@ -250,6 +282,9 @@ class Connection {
|
|
|
250
282
|
|
|
251
283
|
query<T>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>
|
|
252
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<[]>
|
|
253
288
|
|
|
254
289
|
get isAlive(): boolean
|
|
255
290
|
close(): void
|
|
@@ -273,6 +308,7 @@ class Pool {
|
|
|
273
308
|
|
|
274
309
|
query<T>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>
|
|
275
310
|
begin<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>
|
|
311
|
+
notify(channelName: string, payload?: string): Promise<[]>
|
|
276
312
|
acquire(): Promise<Connection>
|
|
277
313
|
release(conn: Connection): void
|
|
278
314
|
close(): Promise<void>
|
package/dist/connection.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { ColumnDescription } from "./types";
|
|
1
|
+
import { Branded, ColumnDescription } from "./types";
|
|
2
2
|
import { Transaction } from "./transaction";
|
|
3
|
-
import { Queue } from "./queue";
|
|
4
3
|
type LogLevel = "none" | "error" | "notice" | "query";
|
|
5
4
|
export type ConnectionParams = {
|
|
6
5
|
user: string;
|
|
@@ -10,17 +9,26 @@ export type ConnectionParams = {
|
|
|
10
9
|
database: string;
|
|
11
10
|
logLevel?: LogLevel;
|
|
12
11
|
};
|
|
13
|
-
export type
|
|
14
|
-
columns: ColumnDescription[];
|
|
12
|
+
export type ExecuteQueueUnit = {
|
|
15
13
|
rows: (string | null)[][];
|
|
16
14
|
resolve: (value: any) => void;
|
|
17
15
|
reject: (err: Error) => void;
|
|
18
|
-
|
|
19
|
-
statementName: string | null;
|
|
16
|
+
statementName: StatementName;
|
|
20
17
|
};
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
export type ParsingQueueUnit = {
|
|
19
|
+
resolve: (statementName: StatementName) => void;
|
|
20
|
+
reject: (error: Error) => void;
|
|
21
|
+
text: QueryText;
|
|
22
|
+
statementName: StatementName;
|
|
23
|
+
};
|
|
24
|
+
export type DescribeQueueUnit = {
|
|
25
|
+
resolve: (value: ColumnDescription[]) => void;
|
|
26
|
+
reject: (error: Error) => void;
|
|
27
|
+
statementName: StatementName;
|
|
28
|
+
};
|
|
29
|
+
export type StatementName = Branded<string, 'StatementName'>;
|
|
30
|
+
export type QueryText = Branded<string, 'QueryText'>;
|
|
31
|
+
export type ChannelName = Branded<string, "ChannelName">;
|
|
24
32
|
/**
|
|
25
33
|
* Represents a single dedicated connection to the PostgreSQL database.
|
|
26
34
|
*
|
|
@@ -52,14 +60,18 @@ export declare class ConnectionQueryQueue extends Queue<ConnectionQueryContext>
|
|
|
52
60
|
* ```
|
|
53
61
|
*/
|
|
54
62
|
export declare class Connection {
|
|
63
|
+
private readonly params;
|
|
55
64
|
private _isFlushing;
|
|
56
|
-
private
|
|
65
|
+
private _isOpened;
|
|
66
|
+
private _isReconnecting;
|
|
57
67
|
private _socket;
|
|
58
68
|
private _writer;
|
|
59
|
-
private
|
|
60
|
-
private
|
|
61
|
-
private
|
|
62
|
-
private
|
|
69
|
+
private _pipelinesQueue;
|
|
70
|
+
private _described;
|
|
71
|
+
private _describingPending;
|
|
72
|
+
private _parsed;
|
|
73
|
+
private _parsingPending;
|
|
74
|
+
private _listeningCallbacks;
|
|
63
75
|
private _stmtCounter;
|
|
64
76
|
private _logLevel;
|
|
65
77
|
private _nextStatement;
|
|
@@ -69,7 +81,7 @@ export declare class Connection {
|
|
|
69
81
|
*
|
|
70
82
|
* @param params - Connection parameters
|
|
71
83
|
* @returns A new Connection instance
|
|
72
|
-
* @throws {
|
|
84
|
+
* @throws {PostgresError} If authentication fails or connection cannot be established
|
|
73
85
|
*
|
|
74
86
|
* @example
|
|
75
87
|
* ```ts
|
|
@@ -107,7 +119,7 @@ export declare class Connection {
|
|
|
107
119
|
* const users = await conn.query<User>`SELECT * FROM users`
|
|
108
120
|
* ```
|
|
109
121
|
*/
|
|
110
|
-
query<T extends Record<string,
|
|
122
|
+
query<T extends Record<string, any>>(templates: TemplateStringsArray, ...params: any[]): Promise<T[]>;
|
|
111
123
|
/**
|
|
112
124
|
* Starts a managed transaction on this connection.
|
|
113
125
|
*
|
|
@@ -130,15 +142,57 @@ export declare class Connection {
|
|
|
130
142
|
* ```
|
|
131
143
|
*/
|
|
132
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;
|
|
133
183
|
private _registerFlush;
|
|
134
184
|
private _flush;
|
|
185
|
+
private _reconnect;
|
|
186
|
+
private _restoreSubscriptions;
|
|
187
|
+
private _getCurrentQuery;
|
|
188
|
+
private _rejectPipeline;
|
|
135
189
|
private _handlePacket;
|
|
136
|
-
private _handleError;
|
|
137
190
|
/**
|
|
138
191
|
* Checks if the connection is still alive and usable.
|
|
139
192
|
* Returns `false` if the socket is destroyed or connection is dead.
|
|
140
193
|
*/
|
|
141
|
-
get
|
|
194
|
+
get isOpened(): boolean;
|
|
195
|
+
private _destroyConnection;
|
|
142
196
|
/**
|
|
143
197
|
* Closes the connection immediately.
|
|
144
198
|
* All pending queries will be rejected with an error.
|
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,iBAAiB,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"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"}
|
package/dist/connection.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Connection =
|
|
3
|
+
exports.Connection = void 0;
|
|
4
4
|
const process_1 = require("process");
|
|
5
5
|
const connection_request_writer_1 = require("./protocol/connection-request-writer");
|
|
6
6
|
const socket_authorization_1 = require("./protocol/socket-authorization");
|
|
@@ -10,16 +10,9 @@ const template_compiler_1 = require("./utils/template-compiler");
|
|
|
10
10
|
const transaction_1 = require("./transaction");
|
|
11
11
|
const socket_connector_1 = require("./protocol/socket-connector");
|
|
12
12
|
const queue_1 = require("./queue");
|
|
13
|
+
const query_1 = require("./query");
|
|
14
|
+
const _1 = require(".");
|
|
13
15
|
const ErrConnectionDead = new Error("Connection is Dead");
|
|
14
|
-
class ConnectionQueryQueue extends queue_1.Queue {
|
|
15
|
-
rejectAllNext(error) {
|
|
16
|
-
while (!this.isFree) {
|
|
17
|
-
this.get().reject(error);
|
|
18
|
-
this.next();
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
exports.ConnectionQueryQueue = ConnectionQueryQueue;
|
|
23
16
|
/**
|
|
24
17
|
* Represents a single dedicated connection to the PostgreSQL database.
|
|
25
18
|
*
|
|
@@ -54,16 +47,23 @@ class Connection {
|
|
|
54
47
|
_nextStatement() {
|
|
55
48
|
return `s-${this._stmtCounter++}`;
|
|
56
49
|
}
|
|
57
|
-
constructor(socket, writer, logLevel) {
|
|
50
|
+
constructor(socket, writer, logLevel, params) {
|
|
58
51
|
this._isFlushing = false;
|
|
59
|
-
this.
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
63
|
-
this.
|
|
52
|
+
this._isOpened = true;
|
|
53
|
+
this._isReconnecting = false;
|
|
54
|
+
this._pipelinesQueue = new queue_1.Queue();
|
|
55
|
+
this._described = new Map();
|
|
56
|
+
this._describingPending = new Set();
|
|
57
|
+
this._parsed = new Map();
|
|
58
|
+
this._parsingPending = new Map();
|
|
59
|
+
this._listeningCallbacks = new Map();
|
|
64
60
|
this._stmtCounter = 0;
|
|
61
|
+
this.params = params;
|
|
65
62
|
this._logLevel = logLevel;
|
|
66
|
-
this._socket = new socket_connector_1.SocketConnector(socket, (type, reader) => this._handlePacket(type, reader),
|
|
63
|
+
this._socket = new socket_connector_1.SocketConnector(socket, (type, reader) => this._handlePacket(type, reader), (err) => {
|
|
64
|
+
this._isReconnecting = true;
|
|
65
|
+
this._rejectPipeline(ErrConnectionDead);
|
|
66
|
+
});
|
|
67
67
|
this._writer = writer;
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
@@ -71,7 +71,7 @@ class Connection {
|
|
|
71
71
|
*
|
|
72
72
|
* @param params - Connection parameters
|
|
73
73
|
* @returns A new Connection instance
|
|
74
|
-
* @throws {
|
|
74
|
+
* @throws {PostgresError} If authentication fails or connection cannot be established
|
|
75
75
|
*
|
|
76
76
|
* @example
|
|
77
77
|
* ```ts
|
|
@@ -87,7 +87,7 @@ class Connection {
|
|
|
87
87
|
static async new(params) {
|
|
88
88
|
const writer = connection_request_writer_1.ConnectionRequestWriter.new();
|
|
89
89
|
const socket = await (0, socket_authorization_1.createAuthorizedSocket)(writer, params);
|
|
90
|
-
return new Connection(socket, writer, params.logLevel || 'error');
|
|
90
|
+
return new Connection(socket, writer, params.logLevel || 'error', params);
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
93
|
* Executes a query using tagged template literals.
|
|
@@ -113,47 +113,17 @@ class Connection {
|
|
|
113
113
|
* const users = await conn.query<User>`SELECT * FROM users`
|
|
114
114
|
* ```
|
|
115
115
|
*/
|
|
116
|
-
query(templates, ...
|
|
117
|
-
|
|
116
|
+
query(templates, ...params) {
|
|
117
|
+
this._registerFlush();
|
|
118
|
+
if (!this._isOpened)
|
|
118
119
|
throw ErrConnectionDead;
|
|
119
|
-
const
|
|
120
|
+
const { text, args } = (0, template_compiler_1.compileSqlTemplate)({ templates, args: params });
|
|
120
121
|
if (this._logLevel === 'query') {
|
|
121
|
-
console.log(`\nQUERY: ${
|
|
122
|
+
console.log(`\nQUERY: ${text}\n${args.length !== 0 ? `ARGUMENTS: [${args}]\n` : ""}`);
|
|
122
123
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this._writer.writeQuery(query.text);
|
|
127
|
-
this._queue.push({
|
|
128
|
-
resolve, reject, columns: [], rows: [], statementName: null, text: query.text
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
let rejectParsed = reject;
|
|
133
|
-
let statementName = '';
|
|
134
|
-
if (!this._statements.has(query.text) && !this._parsePending.has(query.text)) {
|
|
135
|
-
statementName = this._nextStatement();
|
|
136
|
-
this._parsePending.set(query.text, statementName);
|
|
137
|
-
rejectParsed = (error) => {
|
|
138
|
-
this._parsePending.delete(query.text);
|
|
139
|
-
reject(error);
|
|
140
|
-
};
|
|
141
|
-
this._writer
|
|
142
|
-
.writeParse(statementName, query.text);
|
|
143
|
-
console.log('parsed once', statementName, query.text);
|
|
144
|
-
}
|
|
145
|
-
statementName = this._statements.get(query.text) || this._parsePending.get(query.text);
|
|
146
|
-
if (!this._statementDescriptions.has(statementName)) {
|
|
147
|
-
this._writer.writeDescribe(statementName);
|
|
148
|
-
}
|
|
149
|
-
this._queue.push({
|
|
150
|
-
resolve, reject: rejectParsed, columns: [], rows: [], statementName: statementName, text: query.text
|
|
151
|
-
});
|
|
152
|
-
this._writer
|
|
153
|
-
.writeBind("", statementName, query.args)
|
|
154
|
-
.writeExecute("");
|
|
155
|
-
}
|
|
156
|
-
});
|
|
124
|
+
const query = this._createQuery(text, args);
|
|
125
|
+
this._writeQuery(query);
|
|
126
|
+
return query.promise;
|
|
157
127
|
}
|
|
158
128
|
/**
|
|
159
129
|
* Starts a managed transaction on this connection.
|
|
@@ -177,7 +147,7 @@ class Connection {
|
|
|
177
147
|
* ```
|
|
178
148
|
*/
|
|
179
149
|
async begin(txCallback) {
|
|
180
|
-
if (!this.
|
|
150
|
+
if (!this._isOpened)
|
|
181
151
|
throw ErrConnectionDead;
|
|
182
152
|
const tx = new transaction_1.Transaction(this);
|
|
183
153
|
try {
|
|
@@ -193,35 +163,192 @@ class Connection {
|
|
|
193
163
|
throw err;
|
|
194
164
|
}
|
|
195
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
|
+
}
|
|
222
|
+
_createQuery(text, args) {
|
|
223
|
+
if (this._parsed.has(text)) {
|
|
224
|
+
const statementName = this._parsed.get(text);
|
|
225
|
+
if (this._described.has(statementName)) {
|
|
226
|
+
const columns = this._described.get(statementName);
|
|
227
|
+
return new query_1.Query(text, args, query_1.QueryState.Executing, statementName, columns);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
if (this._describingPending.has(statementName)) {
|
|
231
|
+
return new query_1.Query(text, args, query_1.QueryState.Executing, statementName);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
this._describingPending.add(statementName);
|
|
235
|
+
return new query_1.Query(text, args, query_1.QueryState.Describing, statementName);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
if (this._parsingPending.has(text)) {
|
|
241
|
+
const statementName = this._parsingPending.get(text);
|
|
242
|
+
return new query_1.Query(text, args, query_1.QueryState.Describing, statementName);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
const statementName = this._nextStatement();
|
|
246
|
+
this._parsingPending.set(text, statementName);
|
|
247
|
+
return new query_1.Query(text, args, query_1.QueryState.Parsing, statementName);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
_writeQuery(query) {
|
|
252
|
+
if (query.state === query_1.QueryState.Parsing) {
|
|
253
|
+
this._writer
|
|
254
|
+
.writeParse(query.statementName, query.text)
|
|
255
|
+
.writeDescribe(query.statementName)
|
|
256
|
+
.writeBind("", query.statementName, query.args)
|
|
257
|
+
.writeExecute("");
|
|
258
|
+
}
|
|
259
|
+
if (query.state === query_1.QueryState.Describing) {
|
|
260
|
+
this._writer
|
|
261
|
+
.writeDescribe(query.statementName)
|
|
262
|
+
.writeBind("", query.statementName, query.args)
|
|
263
|
+
.writeExecute("");
|
|
264
|
+
}
|
|
265
|
+
if (query.state === query_1.QueryState.Executing) {
|
|
266
|
+
this._writer
|
|
267
|
+
.writeBind("", query.statementName, query.args)
|
|
268
|
+
.writeExecute("");
|
|
269
|
+
}
|
|
270
|
+
this._pipelinesQueue.get().push(query);
|
|
271
|
+
}
|
|
196
272
|
_registerFlush() {
|
|
197
273
|
if (!this._isFlushing) {
|
|
198
274
|
this._isFlushing = true;
|
|
199
|
-
|
|
275
|
+
this._pipelinesQueue.push(new queue_1.Queue());
|
|
276
|
+
(0, process_1.nextTick)(() => {
|
|
277
|
+
this._flush();
|
|
278
|
+
});
|
|
200
279
|
}
|
|
201
280
|
}
|
|
202
281
|
_flush() {
|
|
203
|
-
if (!this.
|
|
204
|
-
this.
|
|
282
|
+
if (!this._isOpened) {
|
|
283
|
+
this._rejectPipeline(ErrConnectionDead);
|
|
205
284
|
return;
|
|
206
285
|
}
|
|
207
|
-
|
|
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;
|
|
208
295
|
this._socket.write(this._writer.writeSync());
|
|
209
296
|
this._writer.clear();
|
|
210
297
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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();
|
|
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);
|
|
330
|
+
}
|
|
331
|
+
_getCurrentQuery() {
|
|
332
|
+
return this._pipelinesQueue.get().get();
|
|
333
|
+
}
|
|
334
|
+
_rejectPipeline(error) {
|
|
335
|
+
if (this._pipelinesQueue.isFree)
|
|
336
|
+
return;
|
|
337
|
+
const queue = this._pipelinesQueue.get();
|
|
338
|
+
while (queue.hasMore) {
|
|
339
|
+
queue.get().reject(error);
|
|
340
|
+
queue.next();
|
|
215
341
|
}
|
|
216
342
|
}
|
|
217
343
|
_handlePacket(type, reader) {
|
|
218
|
-
const context = this._queue.get();
|
|
219
344
|
switch (type) {
|
|
220
345
|
case constants_1.ResponseTypes.ParseComplete:
|
|
221
346
|
{
|
|
222
347
|
reader.readParseComplete();
|
|
223
|
-
this.
|
|
224
|
-
this.
|
|
348
|
+
const query = this._getCurrentQuery();
|
|
349
|
+
this._parsingPending.delete(query.text);
|
|
350
|
+
this._parsed.set(query.text, query.statementName);
|
|
351
|
+
query.state = query_1.QueryState.Describing;
|
|
225
352
|
}
|
|
226
353
|
break;
|
|
227
354
|
case constants_1.ResponseTypes.BindComplete:
|
|
@@ -242,50 +369,74 @@ class Connection {
|
|
|
242
369
|
case constants_1.ResponseTypes.NoData:
|
|
243
370
|
{
|
|
244
371
|
reader.readNoData();
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
372
|
+
const query = this._getCurrentQuery();
|
|
373
|
+
this._describingPending.delete(query.statementName);
|
|
374
|
+
this._described.set(query.statementName, []);
|
|
375
|
+
query.state = query_1.QueryState.Executing;
|
|
248
376
|
}
|
|
249
377
|
break;
|
|
250
378
|
case constants_1.ResponseTypes.RowDescription:
|
|
251
379
|
{
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
380
|
+
const columns = reader.readRowDescription();
|
|
381
|
+
const query = this._getCurrentQuery();
|
|
382
|
+
this._describingPending.delete(query.statementName);
|
|
383
|
+
this._described.set(query.statementName, columns);
|
|
384
|
+
query.state = query_1.QueryState.Executing;
|
|
385
|
+
query.columns = columns;
|
|
258
386
|
}
|
|
259
387
|
break;
|
|
260
388
|
case constants_1.ResponseTypes.DataRow:
|
|
261
389
|
{
|
|
262
|
-
|
|
390
|
+
const query = this._getCurrentQuery();
|
|
391
|
+
query.rows.push(reader.readDataRow());
|
|
263
392
|
}
|
|
264
393
|
break;
|
|
265
394
|
case constants_1.ResponseTypes.ComandComplete:
|
|
266
395
|
{
|
|
267
396
|
reader.readCommandComplete();
|
|
268
|
-
if (
|
|
269
|
-
|
|
397
|
+
if (this._pipelinesQueue.isFree) {
|
|
398
|
+
this._destroyConnection();
|
|
399
|
+
break;
|
|
270
400
|
}
|
|
271
|
-
|
|
272
|
-
|
|
401
|
+
const query = this._getCurrentQuery();
|
|
402
|
+
if (!query) {
|
|
403
|
+
this._destroyConnection();
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
if (!query.columns) {
|
|
407
|
+
query.columns = this._described.get(query.statementName);
|
|
408
|
+
}
|
|
409
|
+
query.state = query_1.QueryState.Completed;
|
|
410
|
+
this._pipelinesQueue.get().next();
|
|
411
|
+
query.resolve((0, value_parser_1.parseRowValues)(query.columns, query.rows));
|
|
273
412
|
}
|
|
274
413
|
break;
|
|
275
414
|
case constants_1.ResponseTypes.ErrorResponse:
|
|
276
415
|
{
|
|
277
|
-
const
|
|
416
|
+
const error = reader.readErrorResponse();
|
|
278
417
|
if (this._logLevel === 'error' || this._logLevel === 'notice' || this._logLevel === 'query') {
|
|
279
|
-
console.log(`\nError: ${
|
|
418
|
+
console.log(`\nError: ${error}\n`);
|
|
419
|
+
}
|
|
420
|
+
const query = this._getCurrentQuery();
|
|
421
|
+
switch (query.state) {
|
|
422
|
+
case query_1.QueryState.Parsing:
|
|
423
|
+
this._parsingPending.delete(query.text);
|
|
424
|
+
break;
|
|
425
|
+
case query_1.QueryState.Describing:
|
|
426
|
+
this._describingPending.delete(query.statementName);
|
|
427
|
+
break;
|
|
280
428
|
}
|
|
281
|
-
|
|
282
|
-
this.
|
|
429
|
+
query.state = query_1.QueryState.Failed;
|
|
430
|
+
this._rejectPipeline(error);
|
|
283
431
|
}
|
|
284
432
|
break;
|
|
285
433
|
case constants_1.ResponseTypes.ReadyForQuery:
|
|
286
434
|
{
|
|
287
|
-
this._isFlushing = false;
|
|
288
435
|
reader.readReadyForQuery();
|
|
436
|
+
const pipeline = this._pipelinesQueue.get();
|
|
437
|
+
if (!pipeline.hasMore) {
|
|
438
|
+
this._pipelinesQueue.next();
|
|
439
|
+
}
|
|
289
440
|
}
|
|
290
441
|
break;
|
|
291
442
|
case constants_1.ResponseTypes.Notice:
|
|
@@ -296,20 +447,32 @@ class Connection {
|
|
|
296
447
|
}
|
|
297
448
|
}
|
|
298
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;
|
|
299
459
|
default: console.warn('Undeclared response type: ', type);
|
|
300
460
|
}
|
|
301
461
|
}
|
|
302
|
-
_handleError(error) {
|
|
303
|
-
this._isAlive = false;
|
|
304
|
-
this._queue.rejectAllNext(error);
|
|
305
|
-
this._socket.destroy();
|
|
306
|
-
}
|
|
307
462
|
/**
|
|
308
463
|
* Checks if the connection is still alive and usable.
|
|
309
464
|
* Returns `false` if the socket is destroyed or connection is dead.
|
|
310
465
|
*/
|
|
311
|
-
get
|
|
312
|
-
return this.
|
|
466
|
+
get isOpened() {
|
|
467
|
+
return this._isOpened;
|
|
468
|
+
}
|
|
469
|
+
_destroyConnection() {
|
|
470
|
+
this._isOpened = false;
|
|
471
|
+
this._socket.destroy();
|
|
472
|
+
while (this._pipelinesQueue.hasMore) {
|
|
473
|
+
this._rejectPipeline(ErrConnectionDead);
|
|
474
|
+
this._pipelinesQueue.next();
|
|
475
|
+
}
|
|
313
476
|
}
|
|
314
477
|
/**
|
|
315
478
|
* Closes the connection immediately.
|
|
@@ -322,8 +485,7 @@ class Connection {
|
|
|
322
485
|
* ```
|
|
323
486
|
*/
|
|
324
487
|
close() {
|
|
325
|
-
this.
|
|
326
|
-
this._socket.destroy();
|
|
488
|
+
this._destroyConnection();
|
|
327
489
|
}
|
|
328
490
|
}
|
|
329
491
|
exports.Connection = Connection;
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class PostgresError extends Error {
|
|
2
|
+
message: string;
|
|
3
|
+
code: string;
|
|
4
|
+
detail: string;
|
|
5
|
+
severity: string;
|
|
6
|
+
where: string;
|
|
7
|
+
hint: string;
|
|
8
|
+
position: string;
|
|
9
|
+
dataType: string;
|
|
10
|
+
constraint: string;
|
|
11
|
+
constructor(message: string, code: string, detail: string, severity: string, where: string, hint: string, position: string, dataType: string, constraint: string);
|
|
12
|
+
get isParseError(): boolean;
|
|
13
|
+
get isDeadlock(): boolean;
|
|
14
|
+
get isConstraintViolation(): boolean;
|
|
15
|
+
get isTimeout(): boolean;
|
|
16
|
+
get isConnectionFailure(): boolean;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,qBAAa,aAAc,SAAQ,KAAK;IAEhB,OAAO,EAAE,MAAM;IACxB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,UAAU,EAAE,MAAM;gBART,OAAO,EAAE,MAAM,EACxB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM;IAQ7B,IAAI,YAAY,IAAI,OAAO,CAE1B;IAID,IAAI,UAAU,IAAI,OAAO,CAExB;IAID,IAAI,qBAAqB,IAAI,OAAO,CAEnC;IAGD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAGD,IAAI,mBAAmB,IAAI,OAAO,CAEjC;CACJ"}
|
package/dist/error.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgresError = void 0;
|
|
4
|
+
class PostgresError extends Error {
|
|
5
|
+
constructor(message, code, detail, severity, where, hint, position, dataType, constraint) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.message = message;
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.detail = detail;
|
|
10
|
+
this.severity = severity;
|
|
11
|
+
this.where = where;
|
|
12
|
+
this.hint = hint;
|
|
13
|
+
this.position = position;
|
|
14
|
+
this.dataType = dataType;
|
|
15
|
+
this.constraint = constraint;
|
|
16
|
+
this.name = "PostgresError";
|
|
17
|
+
}
|
|
18
|
+
// Parse error
|
|
19
|
+
get isParseError() {
|
|
20
|
+
return this.code.startsWith('42');
|
|
21
|
+
}
|
|
22
|
+
// Execute error
|
|
23
|
+
get isDeadlock() {
|
|
24
|
+
return this.code === '40P01';
|
|
25
|
+
}
|
|
26
|
+
// Execute error
|
|
27
|
+
get isConstraintViolation() {
|
|
28
|
+
return this.code.startsWith('23');
|
|
29
|
+
}
|
|
30
|
+
get isTimeout() {
|
|
31
|
+
return this.code === '57014';
|
|
32
|
+
}
|
|
33
|
+
get isConnectionFailure() {
|
|
34
|
+
return this.code.startsWith('08') || this.code.startsWith('57') && this.code !== '57014';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.PostgresError = PostgresError;
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EACH,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,mBAAmB,EAEnB,WAAW,EACX,aAAa,EACb,cAAc,EACjB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD;;;GAGG;AACH,eAAO,MAAM,GAAG;IACZ;;;;;;;;;;;OAWG;;IAGH;;;;;;OAMG;;IAGH;;;;;;OAMG;;IAGH;;;;;;;;OAQG;;IAGH;;;;;;;;;;;KAWC;;IAGD;;;;;;;;;;OAUG;;IAGH;;;;;;;OAOG;;IAGH;;;;;;;;OAQG;;IAGH;;;;;;;;;;;;;;;;;;;OAmBG;;CAEN,CAAA;AAGD;;;GAGG;AAEH,OAAO,EAAE,UAAU,IAAI,UAAU,EAAE,CAAA;AAEnC,OAAO,EAAE,WAAW,IAAI,WAAW,EAAE,CAAA;AAErC,OAAO,EAAE,QAAQ,IAAI,IAAI,EAAE,CAAA;AAE3B,OAAO,EAAE,aAAa,IAAI,aAAa,EAAE,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EACH,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,mBAAmB,EAEnB,WAAW,EACX,aAAa,EACb,cAAc,EACjB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD;;;GAGG;AACH,eAAO,MAAM,GAAG;IACZ;;;;;;;;;;;OAWG;;IAGH;;;;;;OAMG;;IAGH;;;;;;OAMG;;IAGH;;;;;;;;OAQG;;IAGH;;;;;;;;;;;KAWC;;IAGD;;;;;;;;;;OAUG;;IAGH;;;;;;;OAOG;;IAGH;;;;;;;;OAQG;;IAGH;;;;;;;;;;;;;;;;;;;OAmBG;;CAEN,CAAA;AAGD;;;GAGG;AAEH,OAAO,EAAE,UAAU,IAAI,UAAU,EAAE,CAAA;AAEnC,OAAO,EAAE,WAAW,IAAI,WAAW,EAAE,CAAA;AAErC,OAAO,EAAE,QAAQ,IAAI,IAAI,EAAE,CAAA;AAE3B,OAAO,EAAE,aAAa,IAAI,aAAa,EAAE,CAAA;AAEzC,cAAc,WAAW,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
17
|
exports.setTypeParser = exports.Pool = exports.Transaction = exports.Connection = exports.sql = void 0;
|
|
4
18
|
const pool_1 = require("./pool");
|
|
@@ -120,3 +134,4 @@ exports.sql = {
|
|
|
120
134
|
*/
|
|
121
135
|
array: clauses_1.ArrayClause.create,
|
|
122
136
|
};
|
|
137
|
+
__exportStar(require("./clauses"), exports);
|
package/dist/pool.d.ts
CHANGED
|
@@ -127,7 +127,19 @@ export declare class Pool {
|
|
|
127
127
|
* const users = await pool.query<User>`SELECT * FROM users`
|
|
128
128
|
* ```
|
|
129
129
|
*/
|
|
130
|
-
query<T extends Record<string,
|
|
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;
|
|
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
|
@@ -71,10 +71,10 @@ class Pool {
|
|
|
71
71
|
*/
|
|
72
72
|
async acquire() {
|
|
73
73
|
this._checkClosed();
|
|
74
|
-
while (
|
|
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,11 +113,11 @@ 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
|
}
|
|
120
|
-
if (
|
|
120
|
+
if (this._waiting.hasMore) {
|
|
121
121
|
const waiter = this._waiting.get();
|
|
122
122
|
this._waiting.next();
|
|
123
123
|
waiter.resolve(conn);
|
|
@@ -178,9 +178,9 @@ class Pool {
|
|
|
178
178
|
*/
|
|
179
179
|
query(templates, ...args) {
|
|
180
180
|
this._checkClosed();
|
|
181
|
-
while (
|
|
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
|
*/
|
|
@@ -229,12 +243,12 @@ class Pool {
|
|
|
229
243
|
* ```
|
|
230
244
|
*/
|
|
231
245
|
async close() {
|
|
232
|
-
while (
|
|
246
|
+
while (this._available.hasMore) {
|
|
233
247
|
const conn = this._available.get();
|
|
234
248
|
this._available.next();
|
|
235
249
|
conn.close();
|
|
236
250
|
}
|
|
237
|
-
while (
|
|
251
|
+
while (this._waiting.hasMore) {
|
|
238
252
|
const waiter = this._waiting.get();
|
|
239
253
|
this._waiting.next();
|
|
240
254
|
waiter.reject(new Error('Pool closed'));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AuthenticationCode, ResponseType, TransactionStatus } from "./constants";
|
|
2
2
|
import { ColumnDescription } from "../types";
|
|
3
|
+
import { PostgresError } from "../error";
|
|
4
|
+
import { ChannelName } from "../connection";
|
|
3
5
|
export declare class ConnectionResponseBuffer {
|
|
4
6
|
private buffer;
|
|
5
7
|
private caret;
|
|
@@ -31,12 +33,16 @@ export declare class ConnectionResponseReader {
|
|
|
31
33
|
PID: number;
|
|
32
34
|
secret: number;
|
|
33
35
|
};
|
|
34
|
-
readErrorResponse():
|
|
36
|
+
readErrorResponse(): PostgresError;
|
|
35
37
|
readReadyForQuery(): TransactionStatus;
|
|
36
38
|
readSaslMechanisms(): string[];
|
|
37
39
|
readSaslMessage(): string;
|
|
38
40
|
readRowDescription(): ColumnDescription[];
|
|
39
41
|
readDataRow(): (string | null)[];
|
|
42
|
+
readNotificationResponse(): {
|
|
43
|
+
name: ChannelName;
|
|
44
|
+
payload: string;
|
|
45
|
+
};
|
|
40
46
|
readCommandComplete(): string;
|
|
41
47
|
hasMore(): boolean;
|
|
42
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;
|
|
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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ConnectionResponseReader = exports.ConnectionResponseBuffer = void 0;
|
|
4
|
+
const error_1 = require("../error");
|
|
4
5
|
class ConnectionResponseBuffer {
|
|
5
6
|
constructor(buffer) {
|
|
6
7
|
this.buffer = buffer;
|
|
@@ -91,16 +92,51 @@ class ConnectionResponseReader {
|
|
|
91
92
|
}
|
|
92
93
|
readErrorResponse() {
|
|
93
94
|
this.buffer.readInt32();
|
|
95
|
+
let severity = '';
|
|
96
|
+
let code = '';
|
|
94
97
|
let message = '';
|
|
98
|
+
let detail = '';
|
|
99
|
+
let where = '';
|
|
100
|
+
let hint = '';
|
|
101
|
+
let position = '';
|
|
102
|
+
let dataType = '';
|
|
103
|
+
let constraint = '';
|
|
95
104
|
while (true) {
|
|
96
105
|
const marker = this.buffer.readChar();
|
|
97
106
|
if (marker === '\0')
|
|
98
107
|
break;
|
|
99
108
|
const text = this.buffer.readCString();
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
switch (marker) {
|
|
110
|
+
case 'S':
|
|
111
|
+
severity = text;
|
|
112
|
+
break;
|
|
113
|
+
case 'C':
|
|
114
|
+
code = text;
|
|
115
|
+
break;
|
|
116
|
+
case 'M':
|
|
117
|
+
message = text;
|
|
118
|
+
break;
|
|
119
|
+
case 'D':
|
|
120
|
+
detail = text;
|
|
121
|
+
break;
|
|
122
|
+
case 'W':
|
|
123
|
+
where = text;
|
|
124
|
+
break;
|
|
125
|
+
case 'H':
|
|
126
|
+
hint = text;
|
|
127
|
+
break;
|
|
128
|
+
case 'P':
|
|
129
|
+
position = text;
|
|
130
|
+
break;
|
|
131
|
+
case 'd':
|
|
132
|
+
dataType = text;
|
|
133
|
+
break;
|
|
134
|
+
case 'n':
|
|
135
|
+
constraint = text;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
102
138
|
}
|
|
103
|
-
return message;
|
|
139
|
+
return new error_1.PostgresError(message, code, detail, severity, where, hint, position, dataType, constraint);
|
|
104
140
|
}
|
|
105
141
|
readReadyForQuery() {
|
|
106
142
|
this.buffer.readInt32();
|
|
@@ -152,6 +188,13 @@ class ConnectionResponseReader {
|
|
|
152
188
|
}
|
|
153
189
|
return rowValues;
|
|
154
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
|
+
}
|
|
155
198
|
readCommandComplete() {
|
|
156
199
|
this.buffer.readInt32();
|
|
157
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])
|
package/dist/query.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { QueryText, StatementName } from "./connection";
|
|
2
|
+
import { ColumnDescription, ValueOF } from "./types";
|
|
3
|
+
export declare const QueryState: {
|
|
4
|
+
readonly Parsing: 0;
|
|
5
|
+
readonly Describing: 1;
|
|
6
|
+
readonly Executing: 2;
|
|
7
|
+
readonly Completed: 3;
|
|
8
|
+
readonly Failed: 4;
|
|
9
|
+
};
|
|
10
|
+
export type State = ValueOF<typeof QueryState>;
|
|
11
|
+
export declare class Query<T> {
|
|
12
|
+
text: QueryText;
|
|
13
|
+
args: (string | null)[];
|
|
14
|
+
state: State;
|
|
15
|
+
statementName: StatementName;
|
|
16
|
+
columns?: ColumnDescription[] | undefined;
|
|
17
|
+
promise: Promise<T[]>;
|
|
18
|
+
resolve: (value: T[]) => void;
|
|
19
|
+
reject: (error: Error) => void;
|
|
20
|
+
rows: (string | null)[][];
|
|
21
|
+
constructor(text: QueryText, args: (string | null)[], state: State, statementName: StatementName, columns?: ColumnDescription[] | undefined);
|
|
22
|
+
setState(state: State): void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGrD,eAAO,MAAM,UAAU;;;;;;CAMb,CAAA;AAGV,MAAM,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,UAAU,CAAC,CAAA;AAG9C,qBAAa,KAAK,CAAC,CAAC;IAOL,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IACvB,KAAK,EAAE,KAAK;IACZ,aAAa,EAAE,aAAa;IAC5B,OAAO,CAAC,EAAE,iBAAiB,EAAE;IAVxC,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAA;IACrB,OAAO,EAAG,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAA;IAC9B,MAAM,EAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/B,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,CAAK;gBAGnB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EACvB,KAAK,EAAE,KAAK,EACZ,aAAa,EAAE,aAAa,EAC5B,OAAO,CAAC,EAAE,iBAAiB,EAAE,YAAA;IAQxC,QAAQ,CAAC,KAAK,EAAE,KAAK;CAGxB"}
|
package/dist/query.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Query = exports.QueryState = void 0;
|
|
4
|
+
exports.QueryState = {
|
|
5
|
+
Parsing: 0,
|
|
6
|
+
Describing: 1,
|
|
7
|
+
Executing: 2,
|
|
8
|
+
Completed: 3,
|
|
9
|
+
Failed: 4
|
|
10
|
+
};
|
|
11
|
+
class Query {
|
|
12
|
+
constructor(text, args, state, statementName, columns) {
|
|
13
|
+
this.text = text;
|
|
14
|
+
this.args = args;
|
|
15
|
+
this.state = state;
|
|
16
|
+
this.statementName = statementName;
|
|
17
|
+
this.columns = columns;
|
|
18
|
+
this.rows = [];
|
|
19
|
+
this.promise = new Promise((a, b) => {
|
|
20
|
+
this.resolve = a;
|
|
21
|
+
this.reject = b;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
setState(state) {
|
|
25
|
+
this.state = state;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.Query = Query;
|
package/dist/queue.d.ts
CHANGED
package/dist/queue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,qBAAa,KAAK,CAAC,CAAC;IAChB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAI;IAEpB,IAAI;
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,qBAAa,KAAK,CAAC,CAAC;IAChB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAI;IAEpB,IAAI;IASJ,GAAG;IAKH,KAAK;IAYL,IAAI,CAAC,IAAI,EAAE,CAAC;IAIZ,IAAI,IAAI,WAEP;IAGD,IAAI,OAAO,YAEV;IAGD,IAAI,MAAM,YAA+C;CAC5D"}
|
package/dist/queue.js
CHANGED
|
@@ -8,7 +8,7 @@ class Queue {
|
|
|
8
8
|
}
|
|
9
9
|
next() {
|
|
10
10
|
this._pointer++;
|
|
11
|
-
if (this._pointer
|
|
11
|
+
if (this._pointer >= this._queue.length) {
|
|
12
12
|
this._queue = [];
|
|
13
13
|
this._pointer = 0;
|
|
14
14
|
}
|
|
@@ -16,12 +16,24 @@ class Queue {
|
|
|
16
16
|
get() {
|
|
17
17
|
return this._queue[this._pointer];
|
|
18
18
|
}
|
|
19
|
+
shift() {
|
|
20
|
+
const item = this._queue[this._pointer];
|
|
21
|
+
this._pointer++;
|
|
22
|
+
if (this._pointer >= this._queue.length) {
|
|
23
|
+
this._queue = [];
|
|
24
|
+
this._pointer = 0;
|
|
25
|
+
}
|
|
26
|
+
return item;
|
|
27
|
+
}
|
|
19
28
|
push(item) {
|
|
20
29
|
this._queue.push(item);
|
|
21
30
|
}
|
|
22
31
|
get size() {
|
|
23
32
|
return this._queue.length - this._pointer;
|
|
24
33
|
}
|
|
25
|
-
get
|
|
34
|
+
get hasMore() {
|
|
35
|
+
return this._pointer < this._queue.length;
|
|
36
|
+
}
|
|
37
|
+
get isFree() { return this._pointer >= this._queue.length; }
|
|
26
38
|
}
|
|
27
39
|
exports.Queue = Queue;
|
package/dist/transaction.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare class Transaction {
|
|
|
23
23
|
/**
|
|
24
24
|
* Executes a query within the current transaction.
|
|
25
25
|
*/
|
|
26
|
-
query<T extends Record<string,
|
|
26
|
+
query<T extends Record<string, any>>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>;
|
|
27
27
|
/**
|
|
28
28
|
* Creates a sub-transaction using PostgreSQL SAVEPOINT.
|
|
29
29
|
* If the callback throws, only the actions within this savepoint are rolled back.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC;;;GAGG;AACH,qBAAa,WAAW;IAIhB,QAAQ,CAAC,IAAI,EAAE,UAAU;IAH7B,OAAO,CAAC,UAAU,CAAiB;gBAGtB,IAAI,EAAE,UAAU;IAG7B;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACU,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC;;OAEG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtC;;OAEG;IACU,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC;;;GAGG;AACH,qBAAa,WAAW;IAIhB,QAAQ,CAAC,IAAI,EAAE,UAAU;IAH7B,OAAO,CAAC,UAAU,CAAiB;gBAGtB,IAAI,EAAE,UAAU;IAG7B;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACU,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC;;OAEG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtC;;OAEG;IACU,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAKhH;;;;;;;;;OASG;IACU,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;CAe5G"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,GAAG,EAAE,OAAO,SAAS,GAAG,EAAE,IAAI;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;CACpD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CAC3B,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,CAAC;CACf,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,SAAS,EAAE,oBAAoB,CAAC;IAChC,IAAI,EAAE,GAAG,EAAE,CAAC;CACf,CAAA;AAGD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAClB,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,GAAG,EAAE,OAAO,SAAS,GAAG,EAAE,IAAI;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;CACpD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CAC3B,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,CAAC;CACf,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,SAAS,EAAE,oBAAoB,CAAC;IAChC,IAAI,EAAE,GAAG,EAAE,CAAC;CACf,CAAA;AAGD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG;IAAC,OAAO,EAAE,KAAK,CAAA;CAAC,CAAA;AAEpD,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ColumnDescription } from "../types";
|
|
2
2
|
declare const Parsers: Record<number, (value: string) => unknown>;
|
|
3
|
-
export declare function parseRowValues(columns: ColumnDescription[], rows: (string | null)[][]): Record<string, any
|
|
3
|
+
export declare function parseRowValues(columns: ColumnDescription[], rows: (string | null)[][]): Record<string, any>[];
|
|
4
4
|
export declare const setTypeParser: (typeOID: keyof typeof Parsers, parser: (value: string) => unknown) => void;
|
|
5
5
|
export {};
|
|
6
6
|
//# sourceMappingURL=value-parser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"value-parser.d.ts","sourceRoot":"","sources":["../../src/utils/value-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA+B5C,QAAA,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAkD9C,CAAA;AAMV,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"value-parser.d.ts","sourceRoot":"","sources":["../../src/utils/value-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA+B5C,QAAA,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAkD9C,CAAA;AAMV,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CA8B7G;AAGD,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,OAAO,OAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,SAE9F,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m2k-5f/pgtx",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Blazing-fast PostgreSQL driver with pipeline support.",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -40,8 +40,9 @@
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
+
"@types/node": "^26.1.1",
|
|
44
|
+
"pg": "^8.22.0",
|
|
43
45
|
"tsx": "^4.21.0",
|
|
44
|
-
"typescript": "^5.0.0"
|
|
45
|
-
"@types/node": "^26.1.1"
|
|
46
|
+
"typescript": "^5.0.0"
|
|
46
47
|
}
|
|
47
48
|
}
|