postgrejs 3.7.0 → 3.9.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/CHANGELOG.md +53 -0
- package/README.md +50 -0
- package/connection/connection.d.ts +14 -2
- package/connection/connection.js +70 -10
- package/connection/intl-connection.d.ts +146 -5
- package/connection/intl-connection.js +485 -35
- package/connection/pool.d.ts +30 -6
- package/connection/pool.js +28 -3
- package/connection/prepared-statement.d.ts +11 -0
- package/connection/prepared-statement.js +39 -5
- package/data-type-map.d.ts +16 -0
- package/data-type-map.js +56 -12
- package/data-types/classes/numeric.d.ts +8 -4
- package/data-types/classes/numeric.js +8 -4
- package/data-types/date-type.js +2 -2
- package/data-types/int2-vector-type.js +4 -1
- package/data-types/money-type.d.ts +38 -0
- package/data-types/money-type.js +203 -0
- package/data-types/numeric-type.d.ts +2 -0
- package/data-types/numeric-type.js +1 -1
- package/data-types/oid-vector-type.js +4 -1
- package/data-types/timestamp-type.js +2 -2
- package/data-types/timestamptz-type.js +11 -2
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/interfaces/data-mapping-options.d.ts +27 -0
- package/interfaces/database-connection-params.d.ts +32 -5
- package/interfaces/query-options.d.ts +32 -0
- package/interfaces/script-execute-options.d.ts +32 -0
- package/interfaces/transaction-options.d.ts +27 -0
- package/interfaces/transaction-options.js +1 -0
- package/package.json +1 -1
- package/protocol/database-error.d.ts +15 -0
- package/protocol/database-error.js +19 -0
- package/protocol/frontend.js +17 -0
- package/protocol/pg-socket.js +7 -10
- package/util/array-leaf.d.ts +10 -0
- package/util/array-leaf.js +22 -0
- package/util/date-style.d.ts +47 -0
- package/util/date-style.js +123 -0
- package/util/decode-binaryarray.js +8 -1
- package/util/encode-binaryarray.d.ts +12 -1
- package/util/encode-binaryarray.js +13 -2
- package/util/format-datetime.d.ts +18 -0
- package/util/format-datetime.js +33 -0
- package/util/parse-datetime.d.ts +4 -3
- package/util/parse-datetime.js +34 -9
- package/util/resolve-column-formats.js +4 -0
- package/util/row-decoder.d.ts +24 -4
- package/util/row-decoder.js +25 -10
- package/util/sql-tag.js +16 -0
- package/util/stringify-for-sql.js +7 -0
- package/util/transaction-command.d.ts +7 -0
- package/util/transaction-command.js +32 -0
- package/util/unspecified-param.d.ts +27 -0
- package/util/unspecified-param.js +31 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
+
### [v3.9.0](https://github.com/panates/postgrejs/compare/v3.8.0...v3.9.0) -
|
|
4
|
+
|
|
5
|
+
#### 🚀 New Features
|
|
6
|
+
|
|
7
|
+
- feat: decode money, by asking the server what a minor unit is @Eray Hanoğlu
|
|
8
|
+
- feat: pipeline by default, and let a connection opt out of it @Eray Hanoğlu
|
|
9
|
+
- feat: take the transaction's modes on startTransaction() @Eray Hanoğlu
|
|
10
|
+
- feat: let a connection answer the data-mapping options once @Eray Hanoğlu
|
|
11
|
+
- feat: keep the server's own error text on serverMessage @Eray Hanoğlu
|
|
12
|
+
|
|
13
|
+
#### 🪲 Fixes
|
|
14
|
+
|
|
15
|
+
- fix: read a text date in the DateStyle the server said it wrote @Eray Hanoğlu
|
|
16
|
+
- fix: let SET TRANSACTION run with rollbackOnError on @Eray Hanoğlu
|
|
17
|
+
- fix: ask for money's scale on the two paths that decoded before asking @Eray Hanoğlu
|
|
18
|
+
- fix: name a statement once, not once per caller in a burst @Eray Hanoğlu
|
|
19
|
+
- fix: keep a pooled connection unshared unless the caller asks @Eray Hanoğlu
|
|
20
|
+
- fix: type an array from the first value inside it, not from value[0] @Eray Hanoğlu
|
|
21
|
+
- fix: answer an empty statement instead of raising @Eray Hanoğlu
|
|
22
|
+
|
|
23
|
+
#### 📖 Documentation Changes
|
|
24
|
+
|
|
25
|
+
- docs: list the ORM adapters that run on this client @Eray Hanoğlu
|
|
26
|
+
|
|
27
|
+
#### 🛠 Refactoring and Updates
|
|
28
|
+
|
|
29
|
+
- refactor: let a row decoder declare its own rowType @Eray Hanoğlu
|
|
30
|
+
|
|
31
|
+
#### ⚡️ Performance Improvments
|
|
32
|
+
|
|
33
|
+
- perf: walk fewer types to infer a parameter, and write once per statement @Eray Hanoğlu
|
|
34
|
+
- perf: stop paying for a text row twice @Eray Hanoğlu
|
|
35
|
+
|
|
36
|
+
#### 💬 General Changes
|
|
37
|
+
|
|
38
|
+
- bench: regenerate the reports, and pin the adapter's options @Eray Hanoğlu
|
|
39
|
+
|
|
40
|
+
### [v3.8.0](https://github.com/panates/postgrejs/compare/v3.7.0...v3.8.0) - 21 September 2026
|
|
41
|
+
|
|
42
|
+
#### 🚀 New Features
|
|
43
|
+
|
|
44
|
+
- feat: deliver server notices to the connection @Eray Hanoğlu
|
|
45
|
+
|
|
46
|
+
#### 🪲 Fixes
|
|
47
|
+
|
|
48
|
+
- fix: send a string parameter unspecified, so the column decides @Eray Hanoğlu
|
|
49
|
+
- fix: send a Date parameter unspecified, so the column decides @Eray Hanoğlu
|
|
50
|
+
- fix: write a lower bound of 1 for an ordinary binary array @Eray Hanoğlu
|
|
51
|
+
|
|
52
|
+
#### 🧪 Changes to Test Assests
|
|
53
|
+
|
|
54
|
+
- test: skip the types PostgreSQL 12 does not have @Eray Hanoğlu
|
|
55
|
+
|
|
3
56
|
### [v3.7.0](https://github.com/panates/postgrejs/compare/v3.6.1...v3.7.0) - 20 September 2026
|
|
4
57
|
|
|
5
58
|
#### Breaking Changes :warning:
|
package/README.md
CHANGED
|
@@ -48,6 +48,56 @@ prepared statements, server-side cursors, LISTEN/NOTIFY, bulk `COPY` streams, lo
|
|
|
48
48
|
two-phase commit, multi-host failover, and SCRAM channel binding - all in the one package, written in
|
|
49
49
|
strictly-typed TypeScript from the ground up.
|
|
50
50
|
|
|
51
|
+
### 🔌 Bring Your Own ORM
|
|
52
|
+
|
|
53
|
+
PostgreJS is a driver, not a framework, so what you build on top of it stays your choice:
|
|
54
|
+
|
|
55
|
+
<!-- One cell per adapter, so each renders as its own card: a table because
|
|
56
|
+
GitHub strips CSS, and this is the one layout that survives everywhere
|
|
57
|
+
the README is read. The logos come from postgrejs.com rather than being
|
|
58
|
+
hotlinked from each project, and Drizzle's follows the reader's theme. -->
|
|
59
|
+
<table>
|
|
60
|
+
<tr>
|
|
61
|
+
<td align="center" width="230" valign="top">
|
|
62
|
+
<a href="https://www.sqbjs.org"><img src="https://www.postgrejs.com/img/sqb-logo.svg" alt="SQB" height="60"></a><br><br>
|
|
63
|
+
<b><a href="https://www.sqbjs.org">SQB</a></b><br>
|
|
64
|
+
<a href="https://www.npmjs.com/package/@sqb/postgres"><code>@sqb/postgres</code></a><br>
|
|
65
|
+
<sub>native driver</sub>
|
|
66
|
+
</td>
|
|
67
|
+
<td align="center" width="230" valign="top">
|
|
68
|
+
<a href="https://kysely.dev"><img src="https://www.postgrejs.com/img/kysely-logo.svg" alt="Kysely" height="60"></a><br><br>
|
|
69
|
+
<b><a href="https://kysely.dev">Kysely</a></b><br>
|
|
70
|
+
<a href="https://github.com/panates/postgrejs-kysely"><code>kysely-postgrejs</code></a><br>
|
|
71
|
+
<sub>dialect</sub>
|
|
72
|
+
</td>
|
|
73
|
+
<td align="center" width="230" valign="top">
|
|
74
|
+
<a href="https://orm.drizzle.team"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.postgrejs.com/img/drizzle-logo-dark.svg"><img src="https://www.postgrejs.com/img/drizzle-logo-light.svg" alt="Drizzle ORM" height="34"></picture></a><br><br>
|
|
75
|
+
<b><a href="https://orm.drizzle.team">Drizzle ORM</a></b><br>
|
|
76
|
+
<a href="https://github.com/panates/postgrejs-drizzle"><code>drizzle-postgrejs</code></a><br>
|
|
77
|
+
<sub>driver</sub>
|
|
78
|
+
</td>
|
|
79
|
+
</tr>
|
|
80
|
+
<tr>
|
|
81
|
+
<td align="center" width="230" valign="top">
|
|
82
|
+
<a href="https://typeorm.io"><img src="https://www.postgrejs.com/img/typeorm-icon.png" alt="TypeORM" height="60"></a><br><br>
|
|
83
|
+
<b><a href="https://typeorm.io">TypeORM</a></b><br>
|
|
84
|
+
<a href="https://github.com/panates/postgrejs-typeorm"><code>typeorm-postgrejs</code></a><br>
|
|
85
|
+
<sub>driver</sub>
|
|
86
|
+
</td>
|
|
87
|
+
<td align="center" width="230" valign="top">
|
|
88
|
+
<a href="https://www.prisma.io"><img src="https://www.postgrejs.com/img/prisma-icon.svg" alt="Prisma" height="60"></a><br><br>
|
|
89
|
+
<b><a href="https://www.prisma.io">Prisma</a></b><br>
|
|
90
|
+
<a href="https://github.com/panates/postgrejs-prisma"><code>prisma-postgrejs</code></a><br>
|
|
91
|
+
<sub>driver adapter</sub>
|
|
92
|
+
</td>
|
|
93
|
+
<td width="230"></td>
|
|
94
|
+
</tr>
|
|
95
|
+
</table>
|
|
96
|
+
|
|
97
|
+
Each adapter hands the compiled SQL straight to this client, with no `pg` left anywhere in the chain, and each is
|
|
98
|
+
compared query by query against the driver it replaces - and, where the project ships a suite of its own, run
|
|
99
|
+
against that too. So adopting one is a change to how the connection is created and nothing else.
|
|
100
|
+
|
|
51
101
|
## Installation
|
|
52
102
|
|
|
53
103
|
```bash
|
|
@@ -9,6 +9,7 @@ import type { QueryResult } from '../interfaces/query-result.js';
|
|
|
9
9
|
import type { ScriptExecuteOptions } from '../interfaces/script-execute-options.js';
|
|
10
10
|
import type { ScriptResult } from '../interfaces/script-result.js';
|
|
11
11
|
import type { StatementPrepareOptions } from '../interfaces/statement-prepare-options.js';
|
|
12
|
+
import type { TransactionOptions } from '../interfaces/transaction-options.js';
|
|
12
13
|
import type { DatabaseError } from '../protocol/database-error.js';
|
|
13
14
|
import type { Protocol } from '../protocol/protocol.js';
|
|
14
15
|
import { SafeEventEmitter } from '../safe-event-emitter.js';
|
|
@@ -281,7 +282,7 @@ export declare class Connection extends SafeEventEmitter implements AsyncDisposa
|
|
|
281
282
|
/**
|
|
282
283
|
* Starts a transaction
|
|
283
284
|
*/
|
|
284
|
-
startTransaction(): Promise<void>;
|
|
285
|
+
startTransaction(options?: TransactionOptions): Promise<void>;
|
|
285
286
|
/**
|
|
286
287
|
* Runs `fn` inside a transaction and commits when it returns, or rolls
|
|
287
288
|
* back and rethrows when it throws - the try/catch every caller of
|
|
@@ -309,7 +310,7 @@ export declare class Connection extends SafeEventEmitter implements AsyncDisposa
|
|
|
309
310
|
* `fn` is handed this same connection: every statement it runs on it is
|
|
310
311
|
* inside the transaction, and one it runs on another connection is not.
|
|
311
312
|
*/
|
|
312
|
-
transaction<T>(fn: (connection: this) => Promise<T
|
|
313
|
+
transaction<T>(fn: (connection: this) => Promise<T>, options?: TransactionOptions): Promise<T>;
|
|
313
314
|
/**
|
|
314
315
|
* Commits current transaction.
|
|
315
316
|
* @param immediate - Commits right away, ignoring how many nested
|
|
@@ -370,6 +371,11 @@ export declare class Connection extends SafeEventEmitter implements AsyncDisposa
|
|
|
370
371
|
listen(channel: string, callback: NotificationCallback): Promise<void>;
|
|
371
372
|
unListen(channel: string): Promise<void>;
|
|
372
373
|
unListenAll(): Promise<void>;
|
|
374
|
+
/**
|
|
375
|
+
* Whether a statement asked for the wire to itself - `pipeline: false`
|
|
376
|
+
* on the call, or on the connection when the call says nothing.
|
|
377
|
+
*/
|
|
378
|
+
protected _isExclusive(pipeline: Maybe<boolean>): boolean;
|
|
373
379
|
protected _query(sql: string, options?: QueryOptions): Promise<QueryResult>;
|
|
374
380
|
/**
|
|
375
381
|
* A large object's descriptor is only valid inside the transaction that
|
|
@@ -381,6 +387,12 @@ export declare class Connection extends SafeEventEmitter implements AsyncDisposa
|
|
|
381
387
|
protected _openLargeObject(oid: number, mode: number, ownsTransaction: boolean): Promise<LargeObject>;
|
|
382
388
|
protected _handleNotification(msg: NotificationMessage): void;
|
|
383
389
|
protected _close(): Promise<void>;
|
|
390
|
+
/**
|
|
391
|
+
* Adds the source excerpt the server's `position` points at to
|
|
392
|
+
* `message`, so an error reads in a terminal without the caller doing
|
|
393
|
+
* anything. `err.serverMessage` keeps the undecorated text for
|
|
394
|
+
* anything that parses it.
|
|
395
|
+
*/
|
|
384
396
|
protected _handleError(err: DatabaseError, script: string): DatabaseError;
|
|
385
397
|
/**
|
|
386
398
|
* Remembers where a call came from, so the error it may reject with points
|
package/connection/connection.js
CHANGED
|
@@ -5,6 +5,7 @@ import { withAbortSignal } from '../util/abort-signal.js';
|
|
|
5
5
|
import { normalizeChannelName } from '../util/channel-name.js';
|
|
6
6
|
import { escapeIdentifier } from '../util/escape-identifier.js';
|
|
7
7
|
import { QueryRequest } from '../util/sql-tag.js';
|
|
8
|
+
import { isUnspecifiedParam } from '../util/unspecified-param.js';
|
|
8
9
|
import { BindParam } from './bind-param.js';
|
|
9
10
|
import { IntlConnection } from './intl-connection.js';
|
|
10
11
|
import { LargeObject, LargeObjectMode } from './large-object.js';
|
|
@@ -158,9 +159,17 @@ export class Connection extends SafeEventEmitter {
|
|
|
158
159
|
sql = sql.stringify({ ...options, typeMap: options?.typeMap });
|
|
159
160
|
if (this.listenerCount('execute'))
|
|
160
161
|
this.emit('execute', sql, options);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
let release = this._intlCon.enterWire(this._isExclusive(options?.pipeline));
|
|
163
|
+
if (typeof release !== 'function')
|
|
164
|
+
release = await release;
|
|
165
|
+
try {
|
|
166
|
+
return await withAbortSignal(options?.signal, () => this._intlCon.cancel(), () => this._captureErrorStack(this._intlCon.execute(sql, options), this.execute, options?.asyncErrorHandling).catch((e) => {
|
|
167
|
+
throw this._handleError(e, sql);
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
release();
|
|
172
|
+
}
|
|
164
173
|
}
|
|
165
174
|
/**
|
|
166
175
|
* The legacy Function Call sub-protocol - calls a function by OID
|
|
@@ -199,7 +208,15 @@ export class Connection extends SafeEventEmitter {
|
|
|
199
208
|
/* c8 ignore stop */
|
|
200
209
|
if (this.listenerCount('query'))
|
|
201
210
|
this.emit('query', sql, options);
|
|
202
|
-
|
|
211
|
+
let release = this._intlCon.enterWire(this._isExclusive(options?.pipeline));
|
|
212
|
+
if (typeof release !== 'function')
|
|
213
|
+
release = await release;
|
|
214
|
+
try {
|
|
215
|
+
return await withAbortSignal(options?.signal, () => this._intlCon.cancel(), () => this._query(sql, options));
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
release();
|
|
219
|
+
}
|
|
203
220
|
}
|
|
204
221
|
/**
|
|
205
222
|
* Runs a `COPY ... TO STDOUT` and returns its output as a stream of the
|
|
@@ -478,8 +495,8 @@ export class Connection extends SafeEventEmitter {
|
|
|
478
495
|
/**
|
|
479
496
|
* Starts a transaction
|
|
480
497
|
*/
|
|
481
|
-
startTransaction() {
|
|
482
|
-
return this._captureErrorStack(this._intlCon.startTransaction());
|
|
498
|
+
startTransaction(options) {
|
|
499
|
+
return this._captureErrorStack(this._intlCon.startTransaction(options));
|
|
483
500
|
}
|
|
484
501
|
/**
|
|
485
502
|
* Runs `fn` inside a transaction and commits when it returns, or rolls
|
|
@@ -508,10 +525,19 @@ export class Connection extends SafeEventEmitter {
|
|
|
508
525
|
* `fn` is handed this same connection: every statement it runs on it is
|
|
509
526
|
* inside the transaction, and one it runs on another connection is not.
|
|
510
527
|
*/
|
|
511
|
-
async transaction(fn) {
|
|
512
|
-
|
|
528
|
+
async transaction(fn, options) {
|
|
529
|
+
// A call inside a transaction becomes a savepoint scope, which has
|
|
530
|
+
// no BEGIN to carry modes - see startTransaction(), which refuses
|
|
531
|
+
// them for the same reason rather than applying them to somebody
|
|
532
|
+
// else's transaction.
|
|
533
|
+
if (this._intlCon.inTransaction) {
|
|
534
|
+
if (options)
|
|
535
|
+
throw new Error('transaction() cannot set transaction modes inside a transaction ' +
|
|
536
|
+
'that is already open - the inner scope is a savepoint, and the ' +
|
|
537
|
+
'modes belong to the BEGIN that opened the outer one');
|
|
513
538
|
return await this._savepointScope(fn);
|
|
514
|
-
|
|
539
|
+
}
|
|
540
|
+
await this.startTransaction(options);
|
|
515
541
|
try {
|
|
516
542
|
const result = await fn(this);
|
|
517
543
|
await this.commit();
|
|
@@ -629,9 +655,37 @@ export class Connection extends SafeEventEmitter {
|
|
|
629
655
|
await this._captureErrorStack(this.query('UNLISTEN *'));
|
|
630
656
|
}
|
|
631
657
|
}
|
|
658
|
+
/**
|
|
659
|
+
* Whether a statement asked for the wire to itself - `pipeline: false`
|
|
660
|
+
* on the call, or on the connection when the call says nothing.
|
|
661
|
+
*/
|
|
662
|
+
_isExclusive(pipeline) {
|
|
663
|
+
return pipeline != null
|
|
664
|
+
? !pipeline
|
|
665
|
+
: this._intlCon.config.pipeline === false;
|
|
666
|
+
}
|
|
632
667
|
async _query(sql, options) {
|
|
633
668
|
const typeMap = options?.typeMap || GlobalTypeMap;
|
|
634
|
-
const paramTypes = options?.params?.map(prm => prm instanceof BindParam
|
|
669
|
+
const paramTypes = options?.params?.map(prm => prm instanceof BindParam
|
|
670
|
+
? prm.oid
|
|
671
|
+
: // A Date and a string go out with no declared type, so the
|
|
672
|
+
// server resolves each from where it lands - neither can say
|
|
673
|
+
// what it is, and naming a type for them is what made a `Date`
|
|
674
|
+
// move by the client's offset and a string unusable anywhere a
|
|
675
|
+
// `varchar` is not what the context wanted. See
|
|
676
|
+
// `isUnspecifiedParam()` for what that costs. The text they go
|
|
677
|
+
// out as is written in getBindMessage().
|
|
678
|
+
isUnspecifiedParam(prm)
|
|
679
|
+
? 0
|
|
680
|
+
: typeMap.determine(prm));
|
|
681
|
+
// A money parameter is written as an int64 of minor units, so the
|
|
682
|
+
// scale has to be known before the Bind goes out - the probe fired
|
|
683
|
+
// at connect answers in time for every result, but not necessarily
|
|
684
|
+
// for the encode of the very first statement.
|
|
685
|
+
if (paramTypes &&
|
|
686
|
+
(paramTypes.includes(DataTypeOIDs.money) ||
|
|
687
|
+
paramTypes.includes(DataTypeOIDs._money)))
|
|
688
|
+
await this._intlCon.ensureMoneyFormat();
|
|
635
689
|
const effectiveAutoCommit = options?.autoCommit != null
|
|
636
690
|
? options.autoCommit
|
|
637
691
|
: this._intlCon.config.autoCommit;
|
|
@@ -704,6 +758,12 @@ export class Connection extends SafeEventEmitter {
|
|
|
704
758
|
await this._captureErrorStack(this._intlCon.close());
|
|
705
759
|
this._closing = false;
|
|
706
760
|
}
|
|
761
|
+
/**
|
|
762
|
+
* Adds the source excerpt the server's `position` points at to
|
|
763
|
+
* `message`, so an error reads in a terminal without the caller doing
|
|
764
|
+
* anything. `err.serverMessage` keeps the undecorated text for
|
|
765
|
+
* anything that parses it.
|
|
766
|
+
*/
|
|
707
767
|
_handleError(err, script) {
|
|
708
768
|
if (err.position != null) {
|
|
709
769
|
const i1 = script.lastIndexOf('\n', err.position - 1) + 1;
|
|
@@ -2,7 +2,8 @@ import { ConnectionState } from '../constants.js';
|
|
|
2
2
|
import type { DataTypeMap } from '../data-type-map.js';
|
|
3
3
|
import type { BatchResult } from '../interfaces/batch-result.js';
|
|
4
4
|
import type { CopyFromRowsOptions, CopyFromRowsResult } from '../interfaces/copy-from-rows-options.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type { DataMappingOptions, MoneyFormat } from '../interfaces/data-mapping-options.js';
|
|
6
|
+
import type { ConnectionConfiguration, ConnectionMappingDefaults } from '../interfaces/database-connection-params.js';
|
|
6
7
|
import type { FieldInfo } from '../interfaces/field-info.js';
|
|
7
8
|
import type { FunctionCallOptions } from '../interfaces/function-call-options.js';
|
|
8
9
|
import type { FunctionCallResult } from '../interfaces/function-call-result.js';
|
|
@@ -10,13 +11,29 @@ import type { QueryOptions } from '../interfaces/query-options.js';
|
|
|
10
11
|
import type { QueryResult } from '../interfaces/query-result.js';
|
|
11
12
|
import type { ScriptExecuteOptions } from '../interfaces/script-execute-options.js';
|
|
12
13
|
import type { ScriptResult } from '../interfaces/script-result.js';
|
|
14
|
+
import type { TransactionOptions } from '../interfaces/transaction-options.js';
|
|
13
15
|
import { PgSocket } from '../protocol/pg-socket.js';
|
|
14
16
|
import { Protocol } from '../protocol/protocol.js';
|
|
15
17
|
import { SafeEventEmitter } from '../safe-event-emitter.js';
|
|
16
18
|
import type { AnyParseFunction, Maybe, OID } from '../types.js';
|
|
17
19
|
import { type CopyRowSource } from '../util/copy-from-rows.js';
|
|
20
|
+
import { type PgDateStyle } from '../util/date-style.js';
|
|
21
|
+
import { type RowDecoder } from '../util/row-decoder.js';
|
|
18
22
|
import type { Connection } from './connection.js';
|
|
19
23
|
import { CopyFromStream, CopyToStream } from './copy-stream.js';
|
|
24
|
+
interface PreparedCacheEntry {
|
|
25
|
+
name: string;
|
|
26
|
+
fields?: Protocol.RowDescription[];
|
|
27
|
+
}
|
|
28
|
+
/** See IntlConnection._decodeDeferredRows(). */
|
|
29
|
+
interface DeferredRows {
|
|
30
|
+
target: {
|
|
31
|
+
rows?: any[];
|
|
32
|
+
};
|
|
33
|
+
raw: Protocol.DataRowMessage[];
|
|
34
|
+
parsers: AnyParseFunction[];
|
|
35
|
+
fields: any;
|
|
36
|
+
}
|
|
20
37
|
export declare class IntlConnection extends SafeEventEmitter {
|
|
21
38
|
/**
|
|
22
39
|
* Server-side prepared statements this connection has built, keyed by
|
|
@@ -29,6 +46,15 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
29
46
|
* this is per connection and dies with it.
|
|
30
47
|
*/
|
|
31
48
|
private _preparedCache;
|
|
49
|
+
/**
|
|
50
|
+
* The names being given out right now, one per SQL. A burst of the
|
|
51
|
+
* same statement arrives before any of it is prepared, and without
|
|
52
|
+
* this every call in the burst prepares its own copy: measured at 50
|
|
53
|
+
* concurrent `select $1::int4`, 25 Parse+Describe round trips and 25
|
|
54
|
+
* named statements left on the server that this map's one entry could
|
|
55
|
+
* never close again.
|
|
56
|
+
*/
|
|
57
|
+
private _preparing;
|
|
32
58
|
/** SQL seen once but not yet prepared - see PREPARE_AFTER_USES. */
|
|
33
59
|
private _preparedCandidates;
|
|
34
60
|
private _preparedCounter;
|
|
@@ -38,6 +64,24 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
38
64
|
protected _savepointDepths: Map<string, number>;
|
|
39
65
|
protected _config: ConnectionConfiguration;
|
|
40
66
|
protected _onErrorSavePoint: string;
|
|
67
|
+
/**
|
|
68
|
+
* The data-mapping options this connection was configured with, or
|
|
69
|
+
* undefined when it was given none - which is the common case, and
|
|
70
|
+
* the one that must not pay for this.
|
|
71
|
+
*/
|
|
72
|
+
protected readonly _mappingDefaults?: ConnectionMappingDefaults;
|
|
73
|
+
/** The session's DateStyle as last reported, and what it parsed to. */
|
|
74
|
+
protected _dateStyleRaw?: string;
|
|
75
|
+
protected _dateStyle?: PgDateStyle;
|
|
76
|
+
/** The server's own money rendering - see ensureMoneyFormat(). */
|
|
77
|
+
protected _moneyFormat?: MoneyFormat;
|
|
78
|
+
protected _moneyFormatPromise?: Promise<void>;
|
|
79
|
+
/** Statements currently holding the wire - see enterWire(). */
|
|
80
|
+
protected _wireUsers: number;
|
|
81
|
+
protected _wireIdleWaiters?: (() => void)[];
|
|
82
|
+
protected _wireLock?: Promise<void>;
|
|
83
|
+
/** Bound once: enterWire()'s fast path hands out this same function. */
|
|
84
|
+
protected _releaseWire: () => void;
|
|
41
85
|
transactionStatus: string;
|
|
42
86
|
socket: PgSocket;
|
|
43
87
|
owner?: SafeEventEmitter;
|
|
@@ -74,7 +118,7 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
74
118
|
* that point). A matching number of commit() calls is then needed to
|
|
75
119
|
* actually commit - see commit().
|
|
76
120
|
*/
|
|
77
|
-
startTransaction(): Promise<void>;
|
|
121
|
+
startTransaction(options?: TransactionOptions): Promise<void>;
|
|
78
122
|
/**
|
|
79
123
|
* Starts a savepoint, or - if one under the same `name` is already open -
|
|
80
124
|
* marks a nested level of it. Mirrors startTransaction(): only the
|
|
@@ -142,6 +186,49 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
142
186
|
rollbackToSavepoint(name: string): Promise<void>;
|
|
143
187
|
/** Asks the server to cancel whatever this session is running. */
|
|
144
188
|
cancel(): Promise<void>;
|
|
189
|
+
/**
|
|
190
|
+
* Claims the wire for one statement, and hands back the function that
|
|
191
|
+
* releases it.
|
|
192
|
+
*
|
|
193
|
+
* Several statements share it by default: PostgreSQL correlates
|
|
194
|
+
* responses to requests by order, so a connection can carry more than
|
|
195
|
+
* one at a time and a caller that does not wait for each reply is
|
|
196
|
+
* measurably faster. `exclusive` is `pipeline: false` - the statement
|
|
197
|
+
* waits until nothing else is running here, and nothing else starts
|
|
198
|
+
* until it releases.
|
|
199
|
+
*
|
|
200
|
+
* Returns the release function itself rather than a promise of one
|
|
201
|
+
* whenever it can be taken without waiting, which is every statement
|
|
202
|
+
* on a connection nobody has asked to serialise - the common case, and
|
|
203
|
+
* the one that must not pay for this.
|
|
204
|
+
*/
|
|
205
|
+
enterWire(exclusive?: boolean): (() => void) | Promise<() => void>;
|
|
206
|
+
/**
|
|
207
|
+
* Asks the server how it renders money, once per connection.
|
|
208
|
+
*
|
|
209
|
+
* `money` travels as an int64 of the smallest currency unit, and how
|
|
210
|
+
* many of those make one unit is `lc_monetary` - which the server
|
|
211
|
+
* does not report among its startup parameters, so `1234` on the wire
|
|
212
|
+
* is $12.34, ¥1234 or 1.234 KWD depending on a setting only the server
|
|
213
|
+
* knows. Asking it to render a value it already knows is the whole
|
|
214
|
+
* answer, and needs no locale data on this side.
|
|
215
|
+
*
|
|
216
|
+
* `1` is the value asked for because it cannot carry a thousands
|
|
217
|
+
* separator: whatever separator comes back can only be the decimal
|
|
218
|
+
* one, and the digits after it can only be the fraction. `$1.00` is
|
|
219
|
+
* two, `¥1` is none.
|
|
220
|
+
*/
|
|
221
|
+
ensureMoneyFormat(): Promise<void>;
|
|
222
|
+
/**
|
|
223
|
+
* Whether these columns need the server's money format and this
|
|
224
|
+
* connection has not asked for it yet.
|
|
225
|
+
*
|
|
226
|
+
* The scan costs a look at each column's OID, and only until the
|
|
227
|
+
* answer is in - from then on the first test ends it.
|
|
228
|
+
*/
|
|
229
|
+
needsMoneyFormat(fields: Maybe<{
|
|
230
|
+
dataTypeId: OID;
|
|
231
|
+
}[]>, options?: DataMappingOptions): boolean;
|
|
145
232
|
ref(): void;
|
|
146
233
|
unref(): boolean;
|
|
147
234
|
assertConnected(): void;
|
|
@@ -204,11 +291,22 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
204
291
|
/**
|
|
205
292
|
* The savepoint rollbackOnError calls for, or undefined when this call
|
|
206
293
|
* needs none: outside a transaction there is nothing to roll back to,
|
|
207
|
-
*
|
|
208
|
-
* boundaries (wrapping COMMIT in a savepoint would be nonsense)
|
|
294
|
+
* a statement that is itself a transaction command manages its own
|
|
295
|
+
* boundaries (wrapping COMMIT in a savepoint would be nonsense), and
|
|
296
|
+
* PostgreSQL refuses `SET TRANSACTION` inside one outright.
|
|
209
297
|
*/
|
|
210
298
|
protected _inlineSavepointFor(sql: string, options: QueryOptions): Maybe<string>;
|
|
211
|
-
protected _queryCached(sql: string, paramTypes: Maybe<Maybe<OID>[]>, params: Maybe<Maybe<any>[]>, options: QueryOptions, savepoint: Maybe<string
|
|
299
|
+
protected _queryCached(sql: string, paramTypes: Maybe<Maybe<OID>[]>, params: Maybe<Maybe<any>[]>, options: QueryOptions, savepoint: Maybe<string>,
|
|
300
|
+
/** Whether the CALL asked for text columns, not the connection. */
|
|
301
|
+
callWantsFields: boolean): Promise<QueryResult>;
|
|
302
|
+
/**
|
|
303
|
+
* Gives this SQL a name and caches it, once, however many callers are
|
|
304
|
+
* waiting. A Parse that fails caches nothing and reports itself; the
|
|
305
|
+
* statement is simply never reused. It runs outside the savepoint, as
|
|
306
|
+
* the prepare() the transaction path used to do ahead of its own
|
|
307
|
+
* wrapper.
|
|
308
|
+
*/
|
|
309
|
+
protected _prepareForCache(key: string, sql: string, paramTypes: Maybe<Maybe<OID>[]>): Promise<PreparedCacheEntry>;
|
|
212
310
|
/**
|
|
213
311
|
* Counts one more use of this SQL and says whether it has now been seen
|
|
214
312
|
* often enough to be worth preparing under a name.
|
|
@@ -283,6 +381,49 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
283
381
|
executeBatchReused(statementName: string, cachedFields: Protocol.RowDescription[] | undefined, paramTypes: Maybe<Maybe<OID>[]>, paramSets: Maybe<any>[][], options: QueryOptions): Promise<BatchResult>;
|
|
284
382
|
executeReused(statementName: string, cachedFields: Protocol.RowDescription[] | undefined, paramTypes: Maybe<Maybe<OID>[]>, params: Maybe<Maybe<any>[]>, options: QueryOptions, savepoint?: string): Promise<QueryResult>;
|
|
285
383
|
emit(event: string | symbol, ...args: any[]): boolean;
|
|
384
|
+
/**
|
|
385
|
+
* The slow half of enterWire(): either an exclusive statement, or an
|
|
386
|
+
* ordinary one arriving while an exclusive statement holds the wire.
|
|
387
|
+
*
|
|
388
|
+
* The claim itself is synchronous on purpose. Each waiter wakes in its
|
|
389
|
+
* own microtask and runs to its next `await` without interruption, so
|
|
390
|
+
* re-reading `_wireLock` and assigning it in the same stretch is what
|
|
391
|
+
* makes two waiters unable to both believe they took it.
|
|
392
|
+
*/
|
|
393
|
+
protected _enterWireQueued(exclusive: boolean): Promise<() => void>;
|
|
394
|
+
/**
|
|
395
|
+
* `options` with whatever this connection can answer for it: the
|
|
396
|
+
* data-mapping defaults it was configured with, and the money format
|
|
397
|
+
* it has learned.
|
|
398
|
+
*
|
|
399
|
+
* At most one shallow copy per statement, and only when there is
|
|
400
|
+
* something to fill in - a connection configured with nothing and no
|
|
401
|
+
* money in sight hands the caller's own object straight back.
|
|
402
|
+
*/
|
|
403
|
+
/**
|
|
404
|
+
* Rows left raw because a money column's scale was not in yet.
|
|
405
|
+
*
|
|
406
|
+
* Two paths decode inside the message loop, where there is no longer
|
|
407
|
+
* anywhere to ask the server anything: the Simple Query protocol and
|
|
408
|
+
* a pipeline. Rather than read those against a scale nobody
|
|
409
|
+
* confirmed, they set the rows aside and this reads them once the
|
|
410
|
+
* loop is over and the question can be asked.
|
|
411
|
+
*/
|
|
412
|
+
protected _decodeDeferredRows(deferred: DeferredRows[], rowDecoder: RowDecoder, options: QueryOptions): Promise<QueryOptions>;
|
|
413
|
+
withDefaults<T extends DataMappingOptions>(options: T): T;
|
|
414
|
+
/**
|
|
415
|
+
* The session's DateStyle, when it is not ISO.
|
|
416
|
+
*
|
|
417
|
+
* Read off the reported parameters rather than cached once: `SET
|
|
418
|
+
* DateStyle` is answered with a fresh ParameterStatus, so the string
|
|
419
|
+
* changes under us and a connection that changes it mid-session must
|
|
420
|
+
* not go on decoding by the old one. The comparison is against the
|
|
421
|
+
* same string the socket holds, so it costs a read and a pointer
|
|
422
|
+
* compare while nothing changes - which is always, for the ISO
|
|
423
|
+
* default that needs no parsing at all.
|
|
424
|
+
*/
|
|
425
|
+
protected _currentDateStyle(): Maybe<PgDateStyle>;
|
|
286
426
|
protected _onError(err: Error): void;
|
|
287
427
|
}
|
|
288
428
|
export declare function getIntlConnection(connection: Connection): IntlConnection;
|
|
429
|
+
export {};
|