@m2k-5f/pgtx 2.6.1 → 2.6.2
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 +237 -487
- package/dist/batch.d.ts +2 -1
- package/dist/batch.d.ts.map +1 -1
- package/dist/batch.js +8 -7
- package/dist/connection.d.ts +39 -150
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +184 -273
- package/dist/pool.d.ts +29 -181
- package/dist/pool.d.ts.map +1 -1
- package/dist/pool.js +49 -180
- package/dist/protocol/connection-response-reader.d.ts +1 -0
- package/dist/protocol/connection-response-reader.d.ts.map +1 -1
- package/dist/protocol/connection-response-reader.js +3 -0
- package/dist/protocol/socket-connector.d.ts +5 -5
- package/dist/protocol/socket-connector.d.ts.map +1 -1
- package/dist/protocol/socket-connector.js +24 -15
- package/dist/query.d.ts +17 -17
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +22 -17
- package/dist/transaction.d.ts +9 -1
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +11 -0
- package/dist/types.d.ts +9 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/pool.d.ts
CHANGED
|
@@ -2,41 +2,15 @@ import { Connection } from "./connection";
|
|
|
2
2
|
import { Transaction } from "./transaction";
|
|
3
3
|
import { Future } from "fluent-future";
|
|
4
4
|
import { PostgresError } from "./error";
|
|
5
|
-
import { PoolPartialConfig } from "./types";
|
|
5
|
+
import { PoolPartialConfig, Row } from "./types";
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
* Manages a connection pool and provides high-level API for queries and transactions.
|
|
7
|
+
* Connection pool and the main entry point for Pgtx.
|
|
9
8
|
*
|
|
10
9
|
* @example
|
|
11
|
-
*
|
|
12
|
-
* const pool = new Pool({
|
|
13
|
-
* host: 'localhost',
|
|
14
|
-
* user: 'postgres',
|
|
15
|
-
* password: 'postgres',
|
|
16
|
-
* database: 'test',
|
|
17
|
-
* max: 10
|
|
18
|
-
* })
|
|
19
|
-
*
|
|
20
|
-
* // Simple query
|
|
10
|
+
* const pool = new Pool({ host: 'localhost', user: 'postgres', password: 'postgres', database: 'test', max: 10 })
|
|
21
11
|
* const users = await pool.query`SELECT * FROM users WHERE id = ${1}`
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* const result = await pool.begin(async tx => {
|
|
25
|
-
* await tx.query`INSERT INTO users ...`
|
|
26
|
-
* return 'success'
|
|
27
|
-
* })
|
|
28
|
-
*
|
|
29
|
-
* // Manual acquire/release
|
|
30
|
-
* const conn = await pool.acquire()
|
|
31
|
-
* try {
|
|
32
|
-
* await conn.query`SELECT 1`
|
|
33
|
-
* } finally {
|
|
34
|
-
* pool.release(conn)
|
|
35
|
-
* }
|
|
36
|
-
*
|
|
37
|
-
* // Clean up
|
|
38
|
-
* pool.close()
|
|
39
|
-
* ```
|
|
12
|
+
* await pool.begin(async tx => tx.query`INSERT INTO users ...`)
|
|
13
|
+
* await pool.close()
|
|
40
14
|
*/
|
|
41
15
|
export declare class Pool {
|
|
42
16
|
private _available;
|
|
@@ -46,188 +20,62 @@ export declare class Pool {
|
|
|
46
20
|
private _isOpened;
|
|
47
21
|
constructor(config: PoolPartialConfig);
|
|
48
22
|
/**
|
|
49
|
-
* Acquires a dedicated connection
|
|
50
|
-
*
|
|
51
|
-
* **Note:** You must call `pool.release(conn)` manually when finished.
|
|
52
|
-
* For most cases, prefer using `pool.query()` or `pool.begin()` which handle this automatically.
|
|
53
|
-
*
|
|
54
|
-
* @returns A connection from the pool or a new one if available.
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
* ```ts
|
|
58
|
-
* const conn = await pool.acquire()
|
|
59
|
-
* try {
|
|
60
|
-
* await conn.query`SELECT 1`
|
|
61
|
-
* } finally {
|
|
62
|
-
* pool.release(conn)
|
|
63
|
-
* }
|
|
64
|
-
* ```
|
|
23
|
+
* Acquires a dedicated connection. Call `pool.release(conn)` when done —
|
|
24
|
+
* prefer `pool.query()`/`pool.begin()` where possible, they release automatically.
|
|
65
25
|
*/
|
|
66
26
|
acquire(): Future<Connection, PostgresError>;
|
|
67
27
|
/**
|
|
68
|
-
*
|
|
69
|
-
* directly on a single, dedicated `Connection` instance.
|
|
70
|
-
*
|
|
71
|
-
* Automatically borrows a free socket from the pool, forwards it to the provided callback function,
|
|
72
|
-
* and guarantees that the connection is released back to the pool once the execution completes,
|
|
73
|
-
* even if errors or unexpected exceptions are thrown. Prevents connection descriptor leaks.
|
|
74
|
-
*
|
|
75
|
-
* @template T The return type of the provided callback function.
|
|
76
|
-
* @param {(conn: Connection) => Promise<T>} fn A callback function that operates on the allocated Connection.
|
|
77
|
-
* @returns {Future<T, PostgresError>} A `Future` that resolves with the return value of the callback.
|
|
28
|
+
* Runs `fn` with a borrowed connection and releases it afterward, even on error.
|
|
78
29
|
*
|
|
79
30
|
* @example
|
|
80
|
-
*
|
|
81
|
-
* const status = await pool.withAcquire(async (conn) => {
|
|
82
|
-
* return await conn.query`SELECT pg_is_in_recovery()`;
|
|
83
|
-
* });
|
|
31
|
+
* const status = await pool.withAcquire(conn => conn.query`SELECT pg_is_in_recovery()`)
|
|
84
32
|
*/
|
|
85
33
|
withAcquire<T>(fn: (conn: Connection) => Promise<T>): Future<T, unknown>;
|
|
86
|
-
/**
|
|
87
|
-
* Releases the connection back to the pool.
|
|
88
|
-
*
|
|
89
|
-
* If there are pending `acquire()` calls, the connection is passed directly to the next waiter.
|
|
90
|
-
* Otherwise, it's added to the available connections queue.
|
|
91
|
-
*
|
|
92
|
-
* @param conn - The connection to release.
|
|
93
|
-
*
|
|
94
|
-
* @example
|
|
95
|
-
* ```ts
|
|
96
|
-
* const conn = await pool.acquire()
|
|
97
|
-
* try {
|
|
98
|
-
* await conn.query`SELECT 1`
|
|
99
|
-
* } finally {
|
|
100
|
-
* pool.release(conn)
|
|
101
|
-
* }
|
|
102
|
-
* ```
|
|
103
|
-
*/
|
|
34
|
+
/** Returns `conn` to the pool, or hands it directly to the next waiting `acquire()`. */
|
|
104
35
|
release(conn: Connection): void;
|
|
105
36
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* Automatically acquires a connection and handles `BEGIN`, `COMMIT`, and `ROLLBACK`.
|
|
109
|
-
* If the callback throws an error, the transaction is rolled back.
|
|
110
|
-
*
|
|
111
|
-
* @param txCallback - Async function that receives a `Transaction` instance.
|
|
112
|
-
* @returns The value returned from the callback.
|
|
37
|
+
* Runs `txCallback` inside a transaction on a borrowed connection, releasing it afterward.
|
|
113
38
|
*
|
|
114
39
|
* @example
|
|
115
|
-
*
|
|
116
|
-
* const result = await pool.begin(async tx => {
|
|
117
|
-
* await tx.query`INSERT INTO accounts (id, balance) VALUES (1, 100)`
|
|
40
|
+
* await pool.begin(async tx => {
|
|
118
41
|
* await tx.query`UPDATE accounts SET balance = balance - 10 WHERE id = 1`
|
|
119
|
-
* return { success: true }
|
|
120
42
|
* })
|
|
121
|
-
* ```
|
|
122
43
|
*/
|
|
123
44
|
begin<T>(txCallback: (transaction: Transaction) => Promise<T>): Future<T, unknown>;
|
|
124
45
|
/**
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* Automatically acquires and releases a connection from the pool.
|
|
128
|
-
* For optimal performance, multiple queries can be pipelined through the same connection.
|
|
129
|
-
*
|
|
130
|
-
* @param templates - Tagged template string with SQL.
|
|
131
|
-
* @param args - Query parameters.
|
|
132
|
-
* @returns Array of rows with proper typing.
|
|
133
|
-
*
|
|
134
|
-
* @example
|
|
135
|
-
* ```ts
|
|
136
|
-
* // Simple query
|
|
137
|
-
* const users = await pool.query`SELECT * FROM users`
|
|
138
|
-
*
|
|
139
|
-
* // With parameters
|
|
140
|
-
* const user = await pool.query`SELECT * FROM users WHERE id = ${1}`
|
|
141
|
-
*
|
|
142
|
-
* // With typed result
|
|
143
|
-
* type User = { id: number, name: string }
|
|
144
|
-
* const users = await pool.query<User>`SELECT * FROM users`
|
|
145
|
-
* ```
|
|
146
|
-
*/
|
|
147
|
-
query<T extends Record<string, any>>(templates: TemplateStringsArray, ...args: any[]): Future<T[], PostgresError>;
|
|
148
|
-
/**
|
|
149
|
-
* Executes an SQL query in streaming mode.
|
|
150
|
-
*
|
|
151
|
-
* Data is streamed directly from the PostgreSQL binary network buffer into the Web Streams API
|
|
152
|
-
* (`ReadableStream`), bypassing any intermediate array allocation or row accumulation in the JS heap.
|
|
153
|
-
* This pattern provides a true Zero-Memory Footprint and is ideal for exporting massive tables
|
|
154
|
-
* or piping database payloads directly into HTTP responses (e.g., via `Bun.serve` or fetch `Response`).
|
|
155
|
-
*
|
|
156
|
-
* @template T The expected shape of a single row interface.
|
|
157
|
-
* @param {TemplateStringsArray} templates The SQL string parts from the tagged template literal.
|
|
158
|
-
* @param {...any} args The parameterized query arguments.
|
|
159
|
-
* @returns {ReadableStream<T>} Synchronously returns a native Web ReadableStream instance.
|
|
160
|
-
*
|
|
161
|
-
* @example
|
|
162
|
-
* // Streaming a giant table directly to an HTTP response (Bun.serve)
|
|
163
|
-
* const userStream = pool.stream<User>`SELECT id, name FROM users`;
|
|
164
|
-
* return new Response(userStream, { headers: { 'Content-Type': 'application/json' } });
|
|
46
|
+
* Runs a one-off query on a borrowed connection.
|
|
165
47
|
*
|
|
166
48
|
* @example
|
|
167
|
-
*
|
|
168
|
-
* const stream = pool.stream<User>`SELECT * FROM orders WHERE status = ${'processed'}`;
|
|
169
|
-
* for await (const row of stream) {
|
|
170
|
-
* console.log(row.id, row.amount); // Row object is eligible for GC immediately after iteration
|
|
171
|
-
* }
|
|
49
|
+
* const users = await pool.query<User>`SELECT * FROM users WHERE id = ${1}`
|
|
172
50
|
*/
|
|
173
|
-
|
|
51
|
+
query<T extends Row>(templates: TemplateStringsArray, ...args: any[]): Future<T[], PostgresError>;
|
|
52
|
+
/** Like {@link query}, but for statements that don't return rows. */
|
|
53
|
+
execute(templates: TemplateStringsArray, ...params: any[]): Future<void, PostgresError>;
|
|
174
54
|
/**
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* @param channelName - The channel identifier
|
|
178
|
-
* @param payload - Optional string data (max 8000 bytes)
|
|
55
|
+
* Streams query results as a `ReadableStream`, without buffering rows in memory.
|
|
179
56
|
*
|
|
180
57
|
* @example
|
|
181
|
-
*
|
|
182
|
-
* await pool.notify('events', 'hello')
|
|
183
|
-
* ```
|
|
58
|
+
* for await (const row of pool.stream<User>`SELECT * FROM orders`) { ... }
|
|
184
59
|
*/
|
|
60
|
+
stream<T extends Row>(templates: TemplateStringsArray, ...args: any[]): ReadableStream<T>;
|
|
61
|
+
/** Sends a `pg_notify` message on `channelName` (payload ≤ 8000 bytes). */
|
|
185
62
|
notify(channelName: string, payload?: string): Future<void, PostgresError>;
|
|
186
63
|
/**
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* This method automatically claims a dedicated connection from the pool, registers the callback
|
|
190
|
-
* to handle incoming asynchronous database notices (`NotificationResponse` packets), and returns
|
|
191
|
-
* a lazy unsubscribe function wrapped in a `Future`.
|
|
192
|
-
*
|
|
193
|
-
* Invoking the returned unsubscribe function will automatically issue the `UNLISTEN` command
|
|
194
|
-
* to the database backend, clean up the memory callback, and safely release the connection back to the pool.
|
|
195
|
-
*
|
|
196
|
-
* @param {string} channel The name of the PostgreSQL notification channel.
|
|
197
|
-
* @param {(payload: string) => void} callback The event handler invoked when a NOTIFY message arrives.
|
|
198
|
-
* @returns {Future<() => Promise<void>, PostgresError>} A `Future` resolving to an async unsubscribe function.
|
|
64
|
+
* Subscribes `callback` to `channel` on a dedicated connection.
|
|
65
|
+
* Returns an unsubscribe function that issues `UNLISTEN` and releases the connection.
|
|
199
66
|
*
|
|
200
67
|
* @example
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
* const order = JSON.parse(payload);
|
|
204
|
-
* console.log(`New order received: ${order.id}`);
|
|
205
|
-
* });
|
|
206
|
-
*
|
|
207
|
-
* // When the subscription is no longer needed (e.g., during teardown or server stop):
|
|
208
|
-
* await unlisten(); // The socket cleanly issues UNLISTEN and returns to the pool of free connections.
|
|
68
|
+
* const unlisten = await pool.listen('order_created', payload => console.log(payload))
|
|
69
|
+
* await unlisten()
|
|
209
70
|
*/
|
|
210
71
|
listen(channel: string, callback: (payload: string) => void): Future<() => Future<void, PostgresError>, PostgresError>;
|
|
211
|
-
/**
|
|
212
|
-
* Number of available (idle) connections in the pool.
|
|
213
|
-
*/
|
|
72
|
+
/** Number of idle connections. */
|
|
214
73
|
get size(): number;
|
|
215
|
-
/**
|
|
216
|
-
* Total number of connections currently managed by the pool
|
|
217
|
-
* (available + in use).
|
|
218
|
-
*/
|
|
74
|
+
/** Total connections managed (idle + in use). */
|
|
219
75
|
get total(): number;
|
|
220
76
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* All pending `acquire()` calls will be rejected with an error.
|
|
224
|
-
* The pool cannot be used after calling `close()`.
|
|
225
|
-
*
|
|
226
|
-
* @example
|
|
227
|
-
* ```ts
|
|
228
|
-
* pool.close()
|
|
229
|
-
* ```
|
|
77
|
+
* Closes idle connections and rejects pending `acquire()` calls. Not usable afterward.
|
|
230
78
|
*/
|
|
231
|
-
close(): void
|
|
79
|
+
close(): Future<void, PostgresError>;
|
|
232
80
|
}
|
|
233
81
|
//# sourceMappingURL=pool.d.ts.map
|
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,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,OAAO,EAAS,MAAM,EAAM,MAAM,eAAe,CAAC;AAClD,OAAO,EAAiB,aAAa,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,EAAc,iBAAiB,EAAU,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,OAAO,EAAS,MAAM,EAAM,MAAM,eAAe,CAAC;AAClD,OAAO,EAAiB,aAAa,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,EAAc,iBAAiB,EAAE,GAAG,EAAU,MAAM,SAAS,CAAC;AAGrE;;;;;;;;GAQG;AACH,qBAAa,IAAI;IACb,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,SAAS,CAAO;gBAEZ,MAAM,EAAE,iBAAiB;IAOrC;;;OAGG;IACH,OAAO;IA2BP;;;;;OAKG;IACH,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC;IAUnD,wFAAwF;IACxF,OAAO,CAAC,IAAI,EAAE,UAAU;IAoBxB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;IAU7D;;;;;OAKG;IACH,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;IAuBpE,qEAAqE;IACrE,OAAO,CAAC,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAuBzD;;;;;OAKG;IACH,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC;IAoCzF,2EAA2E;IAC3E,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW;IAQhD;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;IAY3D,kCAAkC;IAClC,IAAI,IAAI,WAEP;IAGD,iDAAiD;IACjD,IAAI,KAAK,WAER;IAGD;;OAEG;IACH,KAAK;CAiBR"}
|
package/dist/pool.js
CHANGED
|
@@ -3,39 +3,13 @@ import { Queue, RingQueue } from "./queue";
|
|
|
3
3
|
import { Begin, Future, Ok } from "fluent-future";
|
|
4
4
|
import { ErrPoolClosed } from "./error";
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* Manages a connection pool and provides high-level API for queries and transactions.
|
|
6
|
+
* Connection pool and the main entry point for Pgtx.
|
|
8
7
|
*
|
|
9
8
|
* @example
|
|
10
|
-
*
|
|
11
|
-
* const pool = new Pool({
|
|
12
|
-
* host: 'localhost',
|
|
13
|
-
* user: 'postgres',
|
|
14
|
-
* password: 'postgres',
|
|
15
|
-
* database: 'test',
|
|
16
|
-
* max: 10
|
|
17
|
-
* })
|
|
18
|
-
*
|
|
19
|
-
* // Simple query
|
|
9
|
+
* const pool = new Pool({ host: 'localhost', user: 'postgres', password: 'postgres', database: 'test', max: 10 })
|
|
20
10
|
* const users = await pool.query`SELECT * FROM users WHERE id = ${1}`
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* const result = await pool.begin(async tx => {
|
|
24
|
-
* await tx.query`INSERT INTO users ...`
|
|
25
|
-
* return 'success'
|
|
26
|
-
* })
|
|
27
|
-
*
|
|
28
|
-
* // Manual acquire/release
|
|
29
|
-
* const conn = await pool.acquire()
|
|
30
|
-
* try {
|
|
31
|
-
* await conn.query`SELECT 1`
|
|
32
|
-
* } finally {
|
|
33
|
-
* pool.release(conn)
|
|
34
|
-
* }
|
|
35
|
-
*
|
|
36
|
-
* // Clean up
|
|
37
|
-
* pool.close()
|
|
38
|
-
* ```
|
|
11
|
+
* await pool.begin(async tx => tx.query`INSERT INTO users ...`)
|
|
12
|
+
* await pool.close()
|
|
39
13
|
*/
|
|
40
14
|
export class Pool {
|
|
41
15
|
constructor(config) {
|
|
@@ -47,22 +21,8 @@ export class Pool {
|
|
|
47
21
|
this._available = new RingQueue(this.config.max);
|
|
48
22
|
}
|
|
49
23
|
/**
|
|
50
|
-
* Acquires a dedicated connection
|
|
51
|
-
*
|
|
52
|
-
* **Note:** You must call `pool.release(conn)` manually when finished.
|
|
53
|
-
* For most cases, prefer using `pool.query()` or `pool.begin()` which handle this automatically.
|
|
54
|
-
*
|
|
55
|
-
* @returns A connection from the pool or a new one if available.
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```ts
|
|
59
|
-
* const conn = await pool.acquire()
|
|
60
|
-
* try {
|
|
61
|
-
* await conn.query`SELECT 1`
|
|
62
|
-
* } finally {
|
|
63
|
-
* pool.release(conn)
|
|
64
|
-
* }
|
|
65
|
-
* ```
|
|
24
|
+
* Acquires a dedicated connection. Call `pool.release(conn)` when done —
|
|
25
|
+
* prefer `pool.query()`/`pool.begin()` where possible, they release automatically.
|
|
66
26
|
*/
|
|
67
27
|
acquire() {
|
|
68
28
|
if (!this._isOpened)
|
|
@@ -84,22 +44,10 @@ export class Pool {
|
|
|
84
44
|
return future;
|
|
85
45
|
}
|
|
86
46
|
/**
|
|
87
|
-
*
|
|
88
|
-
* directly on a single, dedicated `Connection` instance.
|
|
89
|
-
*
|
|
90
|
-
* Automatically borrows a free socket from the pool, forwards it to the provided callback function,
|
|
91
|
-
* and guarantees that the connection is released back to the pool once the execution completes,
|
|
92
|
-
* even if errors or unexpected exceptions are thrown. Prevents connection descriptor leaks.
|
|
93
|
-
*
|
|
94
|
-
* @template T The return type of the provided callback function.
|
|
95
|
-
* @param {(conn: Connection) => Promise<T>} fn A callback function that operates on the allocated Connection.
|
|
96
|
-
* @returns {Future<T, PostgresError>} A `Future` that resolves with the return value of the callback.
|
|
47
|
+
* Runs `fn` with a borrowed connection and releases it afterward, even on error.
|
|
97
48
|
*
|
|
98
49
|
* @example
|
|
99
|
-
*
|
|
100
|
-
* const status = await pool.withAcquire(async (conn) => {
|
|
101
|
-
* return await conn.query`SELECT pg_is_in_recovery()`;
|
|
102
|
-
* });
|
|
50
|
+
* const status = await pool.withAcquire(conn => conn.query`SELECT pg_is_in_recovery()`)
|
|
103
51
|
*/
|
|
104
52
|
withAcquire(fn) {
|
|
105
53
|
return Begin()
|
|
@@ -107,27 +55,12 @@ export class Pool {
|
|
|
107
55
|
.andThen(conn => Future.of(fn(conn))
|
|
108
56
|
.finally(() => this.release(conn)));
|
|
109
57
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Releases the connection back to the pool.
|
|
112
|
-
*
|
|
113
|
-
* If there are pending `acquire()` calls, the connection is passed directly to the next waiter.
|
|
114
|
-
* Otherwise, it's added to the available connections queue.
|
|
115
|
-
*
|
|
116
|
-
* @param conn - The connection to release.
|
|
117
|
-
*
|
|
118
|
-
* @example
|
|
119
|
-
* ```ts
|
|
120
|
-
* const conn = await pool.acquire()
|
|
121
|
-
* try {
|
|
122
|
-
* await conn.query`SELECT 1`
|
|
123
|
-
* } finally {
|
|
124
|
-
* pool.release(conn)
|
|
125
|
-
* }
|
|
126
|
-
* ```
|
|
127
|
-
*/
|
|
58
|
+
/** Returns `conn` to the pool, or hands it directly to the next waiting `acquire()`. */
|
|
128
59
|
release(conn) {
|
|
129
|
-
if (!this._isOpened)
|
|
60
|
+
if (!this._isOpened) {
|
|
61
|
+
void conn.close();
|
|
130
62
|
throw ErrPoolClosed;
|
|
63
|
+
}
|
|
131
64
|
if (!conn.isOpened) {
|
|
132
65
|
this._total--;
|
|
133
66
|
return;
|
|
@@ -139,22 +72,12 @@ export class Pool {
|
|
|
139
72
|
this._available.push(conn);
|
|
140
73
|
}
|
|
141
74
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* Automatically acquires a connection and handles `BEGIN`, `COMMIT`, and `ROLLBACK`.
|
|
145
|
-
* If the callback throws an error, the transaction is rolled back.
|
|
146
|
-
*
|
|
147
|
-
* @param txCallback - Async function that receives a `Transaction` instance.
|
|
148
|
-
* @returns The value returned from the callback.
|
|
75
|
+
* Runs `txCallback` inside a transaction on a borrowed connection, releasing it afterward.
|
|
149
76
|
*
|
|
150
77
|
* @example
|
|
151
|
-
*
|
|
152
|
-
* const result = await pool.begin(async tx => {
|
|
153
|
-
* await tx.query`INSERT INTO accounts (id, balance) VALUES (1, 100)`
|
|
78
|
+
* await pool.begin(async tx => {
|
|
154
79
|
* await tx.query`UPDATE accounts SET balance = balance - 10 WHERE id = 1`
|
|
155
|
-
* return { success: true }
|
|
156
80
|
* })
|
|
157
|
-
* ```
|
|
158
81
|
*/
|
|
159
82
|
begin(txCallback) {
|
|
160
83
|
return Begin()
|
|
@@ -163,27 +86,10 @@ export class Pool {
|
|
|
163
86
|
.finally(() => this.release(conn)));
|
|
164
87
|
}
|
|
165
88
|
/**
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* Automatically acquires and releases a connection from the pool.
|
|
169
|
-
* For optimal performance, multiple queries can be pipelined through the same connection.
|
|
170
|
-
*
|
|
171
|
-
* @param templates - Tagged template string with SQL.
|
|
172
|
-
* @param args - Query parameters.
|
|
173
|
-
* @returns Array of rows with proper typing.
|
|
89
|
+
* Runs a one-off query on a borrowed connection.
|
|
174
90
|
*
|
|
175
91
|
* @example
|
|
176
|
-
*
|
|
177
|
-
* // Simple query
|
|
178
|
-
* const users = await pool.query`SELECT * FROM users`
|
|
179
|
-
*
|
|
180
|
-
* // With parameters
|
|
181
|
-
* const user = await pool.query`SELECT * FROM users WHERE id = ${1}`
|
|
182
|
-
*
|
|
183
|
-
* // With typed result
|
|
184
|
-
* type User = { id: number, name: string }
|
|
185
|
-
* const users = await pool.query<User>`SELECT * FROM users`
|
|
186
|
-
* ```
|
|
92
|
+
* const users = await pool.query<User>`SELECT * FROM users WHERE id = ${1}`
|
|
187
93
|
*/
|
|
188
94
|
query(templates, ...args) {
|
|
189
95
|
if (!this._isOpened)
|
|
@@ -203,30 +109,30 @@ export class Pool {
|
|
|
203
109
|
return conn.query(templates, ...args);
|
|
204
110
|
});
|
|
205
111
|
}
|
|
112
|
+
/** Like {@link query}, but for statements that don't return rows. */
|
|
113
|
+
execute(templates, ...params) {
|
|
114
|
+
if (!this._isOpened)
|
|
115
|
+
return Future.reject(ErrPoolClosed);
|
|
116
|
+
while (this._available.hasMore) {
|
|
117
|
+
const conn = this._available.shift;
|
|
118
|
+
if (conn.isClosed) {
|
|
119
|
+
this._total--;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
this._available.push(conn);
|
|
123
|
+
return conn.execute(templates, ...params);
|
|
124
|
+
}
|
|
125
|
+
return this.acquire()
|
|
126
|
+
.andThen(conn => {
|
|
127
|
+
this.release(conn);
|
|
128
|
+
return conn.execute(templates, ...params);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
206
131
|
/**
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
* Data is streamed directly from the PostgreSQL binary network buffer into the Web Streams API
|
|
210
|
-
* (`ReadableStream`), bypassing any intermediate array allocation or row accumulation in the JS heap.
|
|
211
|
-
* This pattern provides a true Zero-Memory Footprint and is ideal for exporting massive tables
|
|
212
|
-
* or piping database payloads directly into HTTP responses (e.g., via `Bun.serve` or fetch `Response`).
|
|
213
|
-
*
|
|
214
|
-
* @template T The expected shape of a single row interface.
|
|
215
|
-
* @param {TemplateStringsArray} templates The SQL string parts from the tagged template literal.
|
|
216
|
-
* @param {...any} args The parameterized query arguments.
|
|
217
|
-
* @returns {ReadableStream<T>} Synchronously returns a native Web ReadableStream instance.
|
|
132
|
+
* Streams query results as a `ReadableStream`, without buffering rows in memory.
|
|
218
133
|
*
|
|
219
134
|
* @example
|
|
220
|
-
*
|
|
221
|
-
* const userStream = pool.stream<User>`SELECT id, name FROM users`;
|
|
222
|
-
* return new Response(userStream, { headers: { 'Content-Type': 'application/json' } });
|
|
223
|
-
*
|
|
224
|
-
* @example
|
|
225
|
-
* // Asynchronously iterating over rows as they arrive from the wire socket
|
|
226
|
-
* const stream = pool.stream<User>`SELECT * FROM orders WHERE status = ${'processed'}`;
|
|
227
|
-
* for await (const row of stream) {
|
|
228
|
-
* console.log(row.id, row.amount); // Row object is eligible for GC immediately after iteration
|
|
229
|
-
* }
|
|
135
|
+
* for await (const row of pool.stream<User>`SELECT * FROM orders`) { ... }
|
|
230
136
|
*/
|
|
231
137
|
stream(templates, ...args) {
|
|
232
138
|
if (!this._isOpened)
|
|
@@ -249,52 +155,26 @@ export class Pool {
|
|
|
249
155
|
this.acquire()
|
|
250
156
|
.tap(conn => {
|
|
251
157
|
this.release(conn);
|
|
252
|
-
conn['
|
|
158
|
+
conn['_performStream'](templates, args, controller);
|
|
253
159
|
})
|
|
254
160
|
.catch(err => {
|
|
255
161
|
controller.error(err);
|
|
256
162
|
});
|
|
257
163
|
return stream;
|
|
258
164
|
}
|
|
259
|
-
/**
|
|
260
|
-
* Sends an asynchronous notification to a channel via `pg_notify`.
|
|
261
|
-
*
|
|
262
|
-
* @param channelName - The channel identifier
|
|
263
|
-
* @param payload - Optional string data (max 8000 bytes)
|
|
264
|
-
*
|
|
265
|
-
* @example
|
|
266
|
-
* ```ts
|
|
267
|
-
* await pool.notify('events', 'hello')
|
|
268
|
-
* ```
|
|
269
|
-
*/
|
|
165
|
+
/** Sends a `pg_notify` message on `channelName` (payload ≤ 8000 bytes). */
|
|
270
166
|
notify(channelName, payload = "") {
|
|
271
167
|
return this.acquire()
|
|
272
168
|
.andThen(conn => conn.notify(channelName, payload)
|
|
273
169
|
.finally(() => this.release(conn)));
|
|
274
170
|
}
|
|
275
171
|
/**
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
* This method automatically claims a dedicated connection from the pool, registers the callback
|
|
279
|
-
* to handle incoming asynchronous database notices (`NotificationResponse` packets), and returns
|
|
280
|
-
* a lazy unsubscribe function wrapped in a `Future`.
|
|
281
|
-
*
|
|
282
|
-
* Invoking the returned unsubscribe function will automatically issue the `UNLISTEN` command
|
|
283
|
-
* to the database backend, clean up the memory callback, and safely release the connection back to the pool.
|
|
284
|
-
*
|
|
285
|
-
* @param {string} channel The name of the PostgreSQL notification channel.
|
|
286
|
-
* @param {(payload: string) => void} callback The event handler invoked when a NOTIFY message arrives.
|
|
287
|
-
* @returns {Future<() => Promise<void>, PostgresError>} A `Future` resolving to an async unsubscribe function.
|
|
172
|
+
* Subscribes `callback` to `channel` on a dedicated connection.
|
|
173
|
+
* Returns an unsubscribe function that issues `UNLISTEN` and releases the connection.
|
|
288
174
|
*
|
|
289
175
|
* @example
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
* const order = JSON.parse(payload);
|
|
293
|
-
* console.log(`New order received: ${order.id}`);
|
|
294
|
-
* });
|
|
295
|
-
*
|
|
296
|
-
* // When the subscription is no longer needed (e.g., during teardown or server stop):
|
|
297
|
-
* await unlisten(); // The socket cleanly issues UNLISTEN and returns to the pool of free connections.
|
|
176
|
+
* const unlisten = await pool.listen('order_created', payload => console.log(payload))
|
|
177
|
+
* await unlisten()
|
|
298
178
|
*/
|
|
299
179
|
listen(channel, callback) {
|
|
300
180
|
return this.acquire()
|
|
@@ -302,38 +182,27 @@ export class Pool {
|
|
|
302
182
|
.map(() => () => conn.unlisten(channel, callback)
|
|
303
183
|
.tap(() => this.release(conn))));
|
|
304
184
|
}
|
|
305
|
-
/**
|
|
306
|
-
* Number of available (idle) connections in the pool.
|
|
307
|
-
*/
|
|
185
|
+
/** Number of idle connections. */
|
|
308
186
|
get size() {
|
|
309
187
|
return this._available.size;
|
|
310
188
|
}
|
|
311
|
-
/**
|
|
312
|
-
* Total number of connections currently managed by the pool
|
|
313
|
-
* (available + in use).
|
|
314
|
-
*/
|
|
189
|
+
/** Total connections managed (idle + in use). */
|
|
315
190
|
get total() {
|
|
316
191
|
return this._total;
|
|
317
192
|
}
|
|
318
193
|
/**
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
* All pending `acquire()` calls will be rejected with an error.
|
|
322
|
-
* The pool cannot be used after calling `close()`.
|
|
323
|
-
*
|
|
324
|
-
* @example
|
|
325
|
-
* ```ts
|
|
326
|
-
* pool.close()
|
|
327
|
-
* ```
|
|
194
|
+
* Closes idle connections and rejects pending `acquire()` calls. Not usable afterward.
|
|
328
195
|
*/
|
|
329
196
|
close() {
|
|
330
197
|
this._isOpened = false;
|
|
198
|
+
const futures = [];
|
|
331
199
|
while (this._available.hasMore) {
|
|
332
|
-
this._available.shift.close();
|
|
200
|
+
futures.push(this._available.shift.close());
|
|
333
201
|
}
|
|
334
202
|
while (this._waiting.hasMore) {
|
|
335
203
|
this._waiting.shift.reject(ErrPoolClosed);
|
|
336
204
|
}
|
|
337
205
|
this._total = 0;
|
|
206
|
+
return Future.all(futures).map(() => { });
|
|
338
207
|
}
|
|
339
208
|
}
|
|
@@ -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,EAA6B,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC5G,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACzD,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,EAA6B,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC5G,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAQxC,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,OAAO,IAAI,OAAO;IAKlB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAO3C,cAAc,IAAI,IAAI;IAOtB,mBAAmB,IAAI,IAAI;IAO3B,cAAc,IAAI,MAAM;IAaxB,SAAS,CAAC,SAAS,EAAE,MAAM;IAK3B,aAAa,IAAI,OAAO;IAaxB,iBAAiB;IAIjB,QAAQ;IAMR,YAAY,IAAI,MAAM;IAOtB,SAAS;IAST,WAAW;IAOX,WAAW,IAAI,MAAM;IAMrB,QAAQ;IAWR,SAAS,CAAC,MAAM,EAAE,MAAM;IAQxB,aAAa,CAAC,MAAM,EAAE,MAAM;CAW/B;AAGD,qBAAa,wBAAwB;IAG7B,OAAO,CAAC,MAAM;IADlB,OAAO;IAKP,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM;IAK1B,QAAQ;cACoC,YAAY;;;IAIxD,kBAAkB,IACoB,kBAAkB;IAIxD,WAAW;IAKX,mBAAmB;;;;IAQnB,kBAAkB;;;;IAQlB,iBAAiB,IAAI,aAAa;IA4ClC,iBAAiB,IACoB,iBAAiB;IAItD,kBAAkB,IAAI,MAAM,EAAE;IAa9B,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAKvC,kBAAkB;IAsBlB,WAAW,CAAC,YAAY,EAAE,iBAAiB,EAAE,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA0G1F,wBAAwB;;;;IASxB,mBAAmB,IAAI,MAAM;IAK7B,OAAO;IAKP,aAAa;IAKb,iBAAiB;IAKjB,iBAAiB;IAGjB,gBAAgB;IAGhB,wBAAwB;IAOxB,UAAU;IAEV,IAAI,CAAC,KAAK,EAAE,MAAM;CAGrB"}
|
|
@@ -4,14 +4,14 @@ import { ConnectionResponseReader } from '../protocol/connection-response-reader
|
|
|
4
4
|
import { ConnectionRequestWriter } from '../protocol/connection-request-writer';
|
|
5
5
|
export declare class SocketConnector {
|
|
6
6
|
private _socket;
|
|
7
|
-
private _onData;
|
|
8
|
-
private _onError;
|
|
9
7
|
private residualBuffer;
|
|
10
|
-
private
|
|
11
|
-
|
|
8
|
+
private _onError;
|
|
9
|
+
private _onClose;
|
|
10
|
+
private _onData;
|
|
11
|
+
private _destroyed;
|
|
12
|
+
constructor(_socket: Socket, onData: (type: ResponseType, length: number, reader: ConnectionResponseReader) => void, onError: (error: unknown) => void);
|
|
12
13
|
write(writer: ConnectionRequestWriter): void;
|
|
13
14
|
unwrapSocket(): Socket;
|
|
14
15
|
destroy(): void;
|
|
15
|
-
get isDestroyed(): boolean;
|
|
16
16
|
}
|
|
17
17
|
//# sourceMappingURL=socket-connector.d.ts.map
|
|
@@ -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;
|
|
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;IAQpB,OAAO,CAAC,OAAO;IAPnB,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAQ;gBAGd,OAAO,EAAE,MAAM,EACvB,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,wBAAwB,KAAK,IAAI,EACtF,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI;IA4CrC,KAAK,CAAC,MAAM,EAAE,uBAAuB;IAKrC,YAAY;IASZ,OAAO;CAGV"}
|