postgrejs 3.9.0 → 3.10.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 +22 -1
- package/connection/connection.js +6 -2
- package/connection/intl-connection.d.ts +18 -1
- package/connection/intl-connection.js +104 -11
- package/data-types/circle-type.js +5 -2
- package/data-types/classes/geometric.d.ts +49 -7
- package/data-types/classes/geometric.js +59 -11
- package/data-types/classes/interval.d.ts +40 -16
- package/data-types/classes/interval.js +68 -40
- package/data-types/classes/numeric.d.ts +6 -0
- package/data-types/classes/numeric.js +8 -0
- package/data-types/classes/range.d.ts +6 -1
- package/data-types/classes/range.js +6 -1
- package/data-types/interval-type.js +1 -1
- package/data-types/money-type.js +11 -2
- package/data-types/numeric-type.js +21 -10
- package/data-types/temporal-types.d.ts +19 -0
- package/data-types/temporal-types.js +520 -0
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/interfaces/data-mapping-options.d.ts +99 -4
- package/package.json +1 -1
- package/util/connection-config.js +11 -1
- package/util/decimal-as-string.d.ts +11 -0
- package/util/decimal-as-string.js +30 -0
- package/util/fetch-as-string.d.ts +33 -0
- package/util/fetch-as-string.js +122 -0
- package/util/get-parsers.js +18 -1
- package/util/resolve-column-formats.d.ts +5 -11
- package/util/resolve-column-formats.js +24 -24
- package/util/stringify-for-sql.js +6 -5
- package/util/temporal.d.ts +47 -0
- package/util/temporal.js +61 -0
- package/util/unspecified-param.d.ts +18 -3
- package/util/unspecified-param.js +21 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
-
### [v3.
|
|
3
|
+
### [v3.10.0](https://github.com/panates/postgrejs/compare/v3.9.0...v3.10.0) -
|
|
4
|
+
|
|
5
|
+
#### Breaking Changes :warning:
|
|
6
|
+
|
|
7
|
+
- feat!: serialise the value classes as their fields @Eray Hanoğlu
|
|
8
|
+
|
|
9
|
+
#### 🚀 New Features
|
|
10
|
+
|
|
11
|
+
- feat: decode the date/time types into Temporal values on request @Eray Hanoğlu
|
|
12
|
+
- feat: let fetchAsString ask for a scalar without its arrays @Eray Hanoğlu
|
|
13
|
+
- feat: decode money and numeric as their exact decimal string on request @Eray Hanoğlu
|
|
14
|
+
- feat: let fetchAsString name an array column by its element type @Eray Hanoğlu
|
|
15
|
+
- feat: report a lost connection on 'error', not only on 'close' @Eray Hanoğlu
|
|
16
|
+
- feat: name Circle's radius `radius`, as pg does @Eray Hanoğlu
|
|
17
|
+
|
|
18
|
+
#### 🪲 Fixes
|
|
19
|
+
|
|
20
|
+
- fix: stop declaring an element type for an array of numbers @Eray Hanoğlu
|
|
21
|
+
- fix: sign only the interval components that have one, and add toPostgres() @Eray Hanoğlu
|
|
22
|
+
- fix: read the database out of a `postgresql://` URL @Eray Hanoğlu
|
|
23
|
+
|
|
24
|
+
### [v3.9.0](https://github.com/panates/postgrejs/compare/v3.8.0...v3.9.0) - 22 September 2026
|
|
4
25
|
|
|
5
26
|
#### 🚀 New Features
|
|
6
27
|
|
package/connection/connection.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ConnectionState, DataTypeOIDs } from '../constants.js';
|
|
2
|
-
import { GlobalTypeMap } from '../data-type-map.js';
|
|
3
2
|
import { SafeEventEmitter } from '../safe-event-emitter.js';
|
|
4
3
|
import { withAbortSignal } from '../util/abort-signal.js';
|
|
5
4
|
import { normalizeChannelName } from '../util/channel-name.js';
|
|
@@ -665,7 +664,12 @@ export class Connection extends SafeEventEmitter {
|
|
|
665
664
|
: this._intlCon.config.pipeline === false;
|
|
666
665
|
}
|
|
667
666
|
async _query(sql, options) {
|
|
668
|
-
|
|
667
|
+
// Only the type map, not withDefaults(): the parameter types are
|
|
668
|
+
// decided here, before the options are merged, and merging them here
|
|
669
|
+
// would change what the merge means - a fetchAsString list that came
|
|
670
|
+
// from the connection deliberately takes a cheaper route than one
|
|
671
|
+
// named on the call.
|
|
672
|
+
const typeMap = this._intlCon.resolveTypeMap(options);
|
|
669
673
|
const paramTypes = options?.params?.map(prm => prm instanceof BindParam
|
|
670
674
|
? prm.oid
|
|
671
675
|
: // A Date and a string go out with no declared type, so the
|
|
@@ -73,9 +73,14 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
73
73
|
/** The session's DateStyle as last reported, and what it parsed to. */
|
|
74
74
|
protected _dateStyleRaw?: string;
|
|
75
75
|
protected _dateStyle?: PgDateStyle;
|
|
76
|
+
/** The session's TimeZone as last reported, once checked. */
|
|
77
|
+
protected _timeZoneRaw?: string;
|
|
78
|
+
protected _timeZone?: string;
|
|
76
79
|
/** The server's own money rendering - see ensureMoneyFormat(). */
|
|
77
80
|
protected _moneyFormat?: MoneyFormat;
|
|
78
81
|
protected _moneyFormatPromise?: Promise<void>;
|
|
82
|
+
/** Whether the socket has been up, which is what makes a close a loss. */
|
|
83
|
+
protected _live: boolean;
|
|
79
84
|
/** Statements currently holding the wire - see enterWire(). */
|
|
80
85
|
protected _wireUsers: number;
|
|
81
86
|
protected _wireIdleWaiters?: (() => void)[];
|
|
@@ -410,6 +415,12 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
410
415
|
* loop is over and the question can be asked.
|
|
411
416
|
*/
|
|
412
417
|
protected _decodeDeferredRows(deferred: DeferredRows[], rowDecoder: RowDecoder, options: QueryOptions): Promise<QueryOptions>;
|
|
418
|
+
/**
|
|
419
|
+
* The type map a statement is parsed and its parameters typed with:
|
|
420
|
+
* the call's, else the connection's, with whatever `temporalTypes`
|
|
421
|
+
* asks for registered on top of it.
|
|
422
|
+
*/
|
|
423
|
+
resolveTypeMap(options?: ConnectionMappingDefaults): DataTypeMap;
|
|
413
424
|
withDefaults<T extends DataMappingOptions>(options: T): T;
|
|
414
425
|
/**
|
|
415
426
|
* The session's DateStyle, when it is not ISO.
|
|
@@ -422,8 +433,14 @@ export declare class IntlConnection extends SafeEventEmitter {
|
|
|
422
433
|
* compare while nothing changes - which is always, for the ISO
|
|
423
434
|
* default that needs no parsing at all.
|
|
424
435
|
*/
|
|
436
|
+
/**
|
|
437
|
+
* The zone `timestamptz` values are given when they decode to a
|
|
438
|
+
* Temporal.ZonedDateTime. Checked when the server's answer changes, so
|
|
439
|
+
* that a zone nothing can resolve is reported against the setting it
|
|
440
|
+
* came from instead of from inside a decode.
|
|
441
|
+
*/
|
|
442
|
+
protected _currentTimeZone(): Maybe<string>;
|
|
425
443
|
protected _currentDateStyle(): Maybe<PgDateStyle>;
|
|
426
|
-
protected _onError(err: Error): void;
|
|
427
444
|
}
|
|
428
445
|
export declare function getIntlConnection(connection: Connection): IntlConnection;
|
|
429
446
|
export {};
|
|
@@ -2,6 +2,7 @@ import { performance } from 'node:perf_hooks';
|
|
|
2
2
|
import { ConnectionState, DataTypeOIDs, DEFAULT_COLUMN_FORMAT, } from '../constants.js';
|
|
3
3
|
import { GlobalTypeMap } from '../data-type-map.js';
|
|
4
4
|
import { parseMoneyFormat } from '../data-types/money-type.js';
|
|
5
|
+
import { temporalTypeMap } from '../data-types/temporal-types.js';
|
|
5
6
|
import { DatabaseError } from '../protocol/database-error.js';
|
|
6
7
|
import { PgSocket } from '../protocol/pg-socket.js';
|
|
7
8
|
import { Protocol } from '../protocol/protocol.js';
|
|
@@ -9,10 +10,13 @@ import { SafeEventEmitter } from '../safe-event-emitter.js';
|
|
|
9
10
|
import { getConnectionConfig } from '../util/connection-config.js';
|
|
10
11
|
import { buildCopySql, buildProbeSql, writeCopyBinaryRows, } from '../util/copy-from-rows.js';
|
|
11
12
|
import { parseDateStyleSetting } from '../util/date-style.js';
|
|
13
|
+
import { validateDecimalAsString } from '../util/decimal-as-string.js';
|
|
12
14
|
import { escapeLiteral } from '../util/escape-literal.js';
|
|
15
|
+
import { fetchAsStringEqual, fetchAsStringNamesElement, fetchAsStringNamesOid, validateFetchAsString, } from '../util/fetch-as-string.js';
|
|
13
16
|
import { getParsers } from '../util/get-parsers.js';
|
|
14
|
-
import {
|
|
17
|
+
import { resolveColumnFormats } from '../util/resolve-column-formats.js';
|
|
15
18
|
import { resolveRowDecoder, resolveRowType, } from '../util/row-decoder.js';
|
|
19
|
+
import { requireTimeZone } from '../util/temporal.js';
|
|
16
20
|
import { isTransactionCommand, refusesSavepoint, } from '../util/transaction-command.js';
|
|
17
21
|
import { wrapRowDescription } from '../util/wrap-row-description.js';
|
|
18
22
|
import { CopyFromStream, CopyToStream } from './copy-stream.js';
|
|
@@ -89,11 +93,14 @@ const PREPARE_AFTER_USES = 2;
|
|
|
89
93
|
/** The connection-configuration keys that are per-statement defaults. */
|
|
90
94
|
const MAPPING_DEFAULT_KEYS = [
|
|
91
95
|
'typeMap',
|
|
96
|
+
'temporalTypes',
|
|
97
|
+
'timeZone',
|
|
92
98
|
'columnFormat',
|
|
93
99
|
'objectRows',
|
|
94
100
|
'rowDecoder',
|
|
95
101
|
'utcDates',
|
|
96
102
|
'fetchAsString',
|
|
103
|
+
'decimalAsString',
|
|
97
104
|
'unknownTypesAsString',
|
|
98
105
|
'moneyFormat',
|
|
99
106
|
];
|
|
@@ -197,9 +204,14 @@ export class IntlConnection extends SafeEventEmitter {
|
|
|
197
204
|
/** The session's DateStyle as last reported, and what it parsed to. */
|
|
198
205
|
_dateStyleRaw;
|
|
199
206
|
_dateStyle;
|
|
207
|
+
/** The session's TimeZone as last reported, once checked. */
|
|
208
|
+
_timeZoneRaw;
|
|
209
|
+
_timeZone;
|
|
200
210
|
/** The server's own money rendering - see ensureMoneyFormat(). */
|
|
201
211
|
_moneyFormat;
|
|
202
212
|
_moneyFormatPromise;
|
|
213
|
+
/** Whether the socket has been up, which is what makes a close a loss. */
|
|
214
|
+
_live = false;
|
|
203
215
|
/** Statements currently holding the wire - see enterWire(). */
|
|
204
216
|
_wireUsers = 0;
|
|
205
217
|
_wireIdleWaiters;
|
|
@@ -223,11 +235,36 @@ export class IntlConnection extends SafeEventEmitter {
|
|
|
223
235
|
super();
|
|
224
236
|
this._config = Object.freeze(getConnectionConfig(config));
|
|
225
237
|
this._mappingDefaults = pickMappingDefaults(this._config);
|
|
238
|
+
// Built here rather than at the first statement, so that a Temporal
|
|
239
|
+
// this runtime does not have, or an OID that is not one of the five,
|
|
240
|
+
// is reported before any I/O - and so the map every statement then
|
|
241
|
+
// reuses is made once.
|
|
242
|
+
if (this._mappingDefaults?.temporalTypes)
|
|
243
|
+
temporalTypeMap(this._mappingDefaults.temporalTypes, this._mappingDefaults.typeMap || GlobalTypeMap);
|
|
226
244
|
this.socket = new PgSocket(this._config);
|
|
227
|
-
this.socket.on('
|
|
245
|
+
this.socket.on('ready', () => {
|
|
246
|
+
this._live = true;
|
|
247
|
+
});
|
|
228
248
|
// The reason travels with it: 'close' on its own cannot tell an
|
|
229
249
|
// ordinary shutdown from the backend being terminated under us.
|
|
230
|
-
|
|
250
|
+
//
|
|
251
|
+
// A loss is reported on 'error' as well, which is where `pg` puts it
|
|
252
|
+
// and where code ported from it listens - `client.on('error')` was
|
|
253
|
+
// attached and never fired, because a terminated backend closes
|
|
254
|
+
// cleanly at the socket level and Node gives 'close' without an
|
|
255
|
+
// 'error' of its own. The Pool already reports the same object the
|
|
256
|
+
// same way. Emitted before 'close': the loss is the cause and the
|
|
257
|
+
// close is the consequence. Safe to do unconditionally, since
|
|
258
|
+
// SafeEventEmitter drops an 'error' nobody is listening for instead
|
|
259
|
+
// of throwing - and only for a connection that was up, so a failed
|
|
260
|
+
// connect stays the business of the promise connect() returns.
|
|
261
|
+
this.socket.on('close', (reason) => {
|
|
262
|
+
const live = this._live;
|
|
263
|
+
this._live = false;
|
|
264
|
+
if (reason && live)
|
|
265
|
+
this.emit('error', reason);
|
|
266
|
+
this.emit('close', reason);
|
|
267
|
+
});
|
|
231
268
|
this.socket.on('notification', payload => this.emit('notification', payload));
|
|
232
269
|
// Covers a notice that arrives while no statement is running. One
|
|
233
270
|
// raised *by* a statement is dispatched to that statement's own
|
|
@@ -618,8 +655,11 @@ export class IntlConnection extends SafeEventEmitter {
|
|
|
618
655
|
if (oid !== DataTypeOIDs.money && oid !== DataTypeOIDs._money)
|
|
619
656
|
continue;
|
|
620
657
|
// Named by fetchAsString, so the value goes back exactly as the
|
|
621
|
-
// server rendered it and no decoder asks what a minor unit is
|
|
622
|
-
|
|
658
|
+
// server rendered it and no decoder asks what a minor unit is -
|
|
659
|
+
// which naming `money` does for a `money[]` column too.
|
|
660
|
+
if (fetchAsStringNamesOid(asString, oid) ||
|
|
661
|
+
(oid === DataTypeOIDs._money &&
|
|
662
|
+
fetchAsStringNamesElement(asString, DataTypeOIDs.money)))
|
|
623
663
|
continue;
|
|
624
664
|
return true;
|
|
625
665
|
}
|
|
@@ -1815,11 +1855,27 @@ export class IntlConnection extends SafeEventEmitter {
|
|
|
1815
1855
|
}
|
|
1816
1856
|
return opts;
|
|
1817
1857
|
}
|
|
1858
|
+
/**
|
|
1859
|
+
* The type map a statement is parsed and its parameters typed with:
|
|
1860
|
+
* the call's, else the connection's, with whatever `temporalTypes`
|
|
1861
|
+
* asks for registered on top of it.
|
|
1862
|
+
*/
|
|
1863
|
+
resolveTypeMap(options) {
|
|
1864
|
+
const defaults = this._mappingDefaults;
|
|
1865
|
+
const base = options?.typeMap || defaults?.typeMap || GlobalTypeMap;
|
|
1866
|
+
const temporal = options?.temporalTypes ?? defaults?.temporalTypes;
|
|
1867
|
+
return temporal ? temporalTypeMap(temporal, base) : base;
|
|
1868
|
+
}
|
|
1818
1869
|
withDefaults(options) {
|
|
1819
1870
|
const defaults = this._mappingDefaults;
|
|
1820
1871
|
const money = this._moneyFormat;
|
|
1821
1872
|
const dateStyle = this._currentDateStyle();
|
|
1822
|
-
if (!defaults &&
|
|
1873
|
+
if (!defaults &&
|
|
1874
|
+
!money &&
|
|
1875
|
+
!dateStyle &&
|
|
1876
|
+
!options.temporalTypes &&
|
|
1877
|
+
!options.fetchAsString &&
|
|
1878
|
+
options.decimalAsString === undefined)
|
|
1823
1879
|
return options;
|
|
1824
1880
|
let out;
|
|
1825
1881
|
if (defaults) {
|
|
@@ -1840,6 +1896,32 @@ export class IntlConnection extends SafeEventEmitter {
|
|
|
1840
1896
|
out = out || { ...options };
|
|
1841
1897
|
out.dateStyle = dateStyle;
|
|
1842
1898
|
}
|
|
1899
|
+
// Every path into a statement passes through here, so a selector
|
|
1900
|
+
// that asks for something this does not do is refused once, at the
|
|
1901
|
+
// call that carries it, rather than in whichever of the three
|
|
1902
|
+
// readers of the list happens to reach it first.
|
|
1903
|
+
if ((out || options).fetchAsString)
|
|
1904
|
+
validateFetchAsString((out || options).fetchAsString, this.resolveTypeMap(out || options));
|
|
1905
|
+
if ((out || options).decimalAsString !== undefined)
|
|
1906
|
+
validateDecimalAsString((out || options).decimalAsString);
|
|
1907
|
+
if ((out || options).temporalTypes) {
|
|
1908
|
+
// On top of whatever type map is in effect, rather than instead of
|
|
1909
|
+
// it. The map is memoized per (base, selection), so this is two
|
|
1910
|
+
// lookups and not a copy.
|
|
1911
|
+
const base = (out || options).typeMap || GlobalTypeMap;
|
|
1912
|
+
const map = this.resolveTypeMap(out || options);
|
|
1913
|
+
if (map !== base) {
|
|
1914
|
+
out = out || { ...options };
|
|
1915
|
+
out.typeMap = map;
|
|
1916
|
+
}
|
|
1917
|
+
if (!(out || options).timeZone) {
|
|
1918
|
+
const tz = this._currentTimeZone();
|
|
1919
|
+
if (tz) {
|
|
1920
|
+
out = out || { ...options };
|
|
1921
|
+
out.timeZone = tz;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1843
1925
|
return out || options;
|
|
1844
1926
|
}
|
|
1845
1927
|
/**
|
|
@@ -1853,6 +1935,22 @@ export class IntlConnection extends SafeEventEmitter {
|
|
|
1853
1935
|
* compare while nothing changes - which is always, for the ISO
|
|
1854
1936
|
* default that needs no parsing at all.
|
|
1855
1937
|
*/
|
|
1938
|
+
/**
|
|
1939
|
+
* The zone `timestamptz` values are given when they decode to a
|
|
1940
|
+
* Temporal.ZonedDateTime. Checked when the server's answer changes, so
|
|
1941
|
+
* that a zone nothing can resolve is reported against the setting it
|
|
1942
|
+
* came from instead of from inside a decode.
|
|
1943
|
+
*/
|
|
1944
|
+
_currentTimeZone() {
|
|
1945
|
+
const raw = this.socket.sessionParameters.TimeZone;
|
|
1946
|
+
if (raw !== this._timeZoneRaw) {
|
|
1947
|
+
this._timeZoneRaw = raw;
|
|
1948
|
+
this._timeZone = raw
|
|
1949
|
+
? requireTimeZone(raw, 'the session TimeZone')
|
|
1950
|
+
: undefined;
|
|
1951
|
+
}
|
|
1952
|
+
return this._timeZone;
|
|
1953
|
+
}
|
|
1856
1954
|
_currentDateStyle() {
|
|
1857
1955
|
const raw = this.socket.sessionParameters.DateStyle;
|
|
1858
1956
|
if (raw !== this._dateStyleRaw) {
|
|
@@ -1861,11 +1959,6 @@ export class IntlConnection extends SafeEventEmitter {
|
|
|
1861
1959
|
}
|
|
1862
1960
|
return this._dateStyle;
|
|
1863
1961
|
}
|
|
1864
|
-
_onError(err) {
|
|
1865
|
-
if (this.socket.state !== ConnectionState.READY)
|
|
1866
|
-
return;
|
|
1867
|
-
this.emit('error', err);
|
|
1868
|
-
}
|
|
1869
1962
|
}
|
|
1870
1963
|
export function getIntlConnection(connection) {
|
|
1871
1964
|
return connection._intlCon;
|
|
@@ -8,13 +8,16 @@ export const CircleType = {
|
|
|
8
8
|
name: 'circle',
|
|
9
9
|
oid: DataTypeOIDs.circle,
|
|
10
10
|
jsType: 'Circle',
|
|
11
|
+
// isType() accepts a plain object as well as a Circle, and that object
|
|
12
|
+
// may spell the radius either way - hence Circle.radiusOf() rather
|
|
13
|
+
// than the property.
|
|
11
14
|
encodeText(v) {
|
|
12
|
-
return `<(${v.x},${v.y}),${v
|
|
15
|
+
return `<(${v.x},${v.y}),${Circle.radiusOf(v)}>`;
|
|
13
16
|
},
|
|
14
17
|
encodeBinary(buf, v) {
|
|
15
18
|
buf.writeDoubleBE(v.x);
|
|
16
19
|
buf.writeDoubleBE(v.y);
|
|
17
|
-
buf.writeDoubleBE(v
|
|
20
|
+
buf.writeDoubleBE(Circle.radiusOf(v));
|
|
18
21
|
},
|
|
19
22
|
decodeBinary(v, offset = 0) {
|
|
20
23
|
return new Circle(v.readDoubleBE(offset), v.readDoubleBE(offset + 8), v.readDoubleBE(offset + 16));
|
|
@@ -5,19 +5,46 @@ export declare class Point {
|
|
|
5
5
|
constructor(x?: number, y?: number);
|
|
6
6
|
/** As PostgreSQL prints it, so it casts back through `::point`. */
|
|
7
7
|
toString(): string;
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
10
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
11
|
+
* client decoded can be handed straight to one.
|
|
12
|
+
*/
|
|
13
|
+
toPostgres(): string;
|
|
9
14
|
static isPointLike(v: any): boolean;
|
|
10
15
|
}
|
|
11
16
|
/** A `circle`: a centre and a radius. */
|
|
12
17
|
export declare class Circle {
|
|
13
18
|
x: number;
|
|
14
19
|
y: number;
|
|
15
|
-
|
|
16
|
-
constructor(x?: number, y?: number,
|
|
20
|
+
radius: number;
|
|
21
|
+
constructor(x?: number, y?: number, radius?: number);
|
|
22
|
+
/**
|
|
23
|
+
* The radius under the name this client used up to 3.9. `pg` spells it
|
|
24
|
+
* `radius`, and a value decoded here should be usable wherever one of
|
|
25
|
+
* its own is, so `radius` is what the property is now - but `r` was a
|
|
26
|
+
* released name, so it stays as an accessor onto the same number
|
|
27
|
+
* rather than silently reading back undefined.
|
|
28
|
+
*
|
|
29
|
+
* @deprecated use `radius`
|
|
30
|
+
*/
|
|
31
|
+
get r(): number;
|
|
32
|
+
set r(value: number);
|
|
17
33
|
/** As PostgreSQL prints it, so it casts back through `::circle`. */
|
|
18
34
|
toString(): string;
|
|
19
|
-
|
|
35
|
+
/**
|
|
36
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
37
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
38
|
+
* client decoded can be handed straight to one.
|
|
39
|
+
*/
|
|
40
|
+
toPostgres(): string;
|
|
20
41
|
static isCircleLike(v: any): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The radius of anything isCircleLike() accepts: a Circle, the plain
|
|
44
|
+
* `{x, y, radius}` object `pg` hands back, or the `{x, y, r}` that was
|
|
45
|
+
* this client's own shape before the classes existed.
|
|
46
|
+
*/
|
|
47
|
+
static radiusOf(v: any): number;
|
|
21
48
|
}
|
|
22
49
|
/**
|
|
23
50
|
* Two corners, which is how both `box` and `lseg` are carried - and why
|
|
@@ -32,7 +59,12 @@ declare abstract class TwoPoints {
|
|
|
32
59
|
x2: number;
|
|
33
60
|
y2: number;
|
|
34
61
|
constructor(x1?: number, y1?: number, x2?: number, y2?: number);
|
|
35
|
-
|
|
62
|
+
/**
|
|
63
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
64
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
65
|
+
* client decoded can be handed straight to one.
|
|
66
|
+
*/
|
|
67
|
+
toPostgres(): string;
|
|
36
68
|
static isTwoPointsLike(v: any): boolean;
|
|
37
69
|
}
|
|
38
70
|
/** A `box`: a rectangle given by two opposite corners. */
|
|
@@ -61,7 +93,12 @@ export declare class Line {
|
|
|
61
93
|
constructor(a?: number, b?: number, c?: number);
|
|
62
94
|
/** As PostgreSQL prints it, so it casts back through `::line`. */
|
|
63
95
|
toString(): string;
|
|
64
|
-
|
|
96
|
+
/**
|
|
97
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
98
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
99
|
+
* client decoded can be handed straight to one.
|
|
100
|
+
*/
|
|
101
|
+
toPostgres(): string;
|
|
65
102
|
static isLineLike(v: any): boolean;
|
|
66
103
|
}
|
|
67
104
|
/**
|
|
@@ -77,7 +114,12 @@ declare abstract class PointList {
|
|
|
77
114
|
x: number;
|
|
78
115
|
y: number;
|
|
79
116
|
})[]);
|
|
80
|
-
|
|
117
|
+
/**
|
|
118
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
119
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
120
|
+
* client decoded can be handed straight to one.
|
|
121
|
+
*/
|
|
122
|
+
toPostgres(): string;
|
|
81
123
|
protected join(): string;
|
|
82
124
|
}
|
|
83
125
|
/**
|
|
@@ -27,7 +27,12 @@ export class Point {
|
|
|
27
27
|
toString() {
|
|
28
28
|
return `(${this.x},${this.y})`;
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
32
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
33
|
+
* client decoded can be handed straight to one.
|
|
34
|
+
*/
|
|
35
|
+
toPostgres() {
|
|
31
36
|
return this.toString();
|
|
32
37
|
}
|
|
33
38
|
/* c8 ignore next 3 */
|
|
@@ -42,17 +47,37 @@ export class Point {
|
|
|
42
47
|
export class Circle {
|
|
43
48
|
x;
|
|
44
49
|
y;
|
|
45
|
-
|
|
46
|
-
constructor(x = 0, y = 0,
|
|
50
|
+
radius;
|
|
51
|
+
constructor(x = 0, y = 0, radius = 0) {
|
|
47
52
|
this.x = x;
|
|
48
53
|
this.y = y;
|
|
49
|
-
this.
|
|
54
|
+
this.radius = radius;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The radius under the name this client used up to 3.9. `pg` spells it
|
|
58
|
+
* `radius`, and a value decoded here should be usable wherever one of
|
|
59
|
+
* its own is, so `radius` is what the property is now - but `r` was a
|
|
60
|
+
* released name, so it stays as an accessor onto the same number
|
|
61
|
+
* rather than silently reading back undefined.
|
|
62
|
+
*
|
|
63
|
+
* @deprecated use `radius`
|
|
64
|
+
*/
|
|
65
|
+
get r() {
|
|
66
|
+
return this.radius;
|
|
67
|
+
}
|
|
68
|
+
set r(value) {
|
|
69
|
+
this.radius = value;
|
|
50
70
|
}
|
|
51
71
|
/** As PostgreSQL prints it, so it casts back through `::circle`. */
|
|
52
72
|
toString() {
|
|
53
|
-
return `<(${this.x},${this.y}),${this.
|
|
54
|
-
}
|
|
55
|
-
|
|
73
|
+
return `<(${this.x},${this.y}),${this.radius}>`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
77
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
78
|
+
* client decoded can be handed straight to one.
|
|
79
|
+
*/
|
|
80
|
+
toPostgres() {
|
|
56
81
|
return this.toString();
|
|
57
82
|
}
|
|
58
83
|
static isCircleLike(v) {
|
|
@@ -60,7 +85,15 @@ export class Circle {
|
|
|
60
85
|
Object.keys(v).length === 3 &&
|
|
61
86
|
isNum(v.x) &&
|
|
62
87
|
isNum(v.y) &&
|
|
63
|
-
isNum(v.r));
|
|
88
|
+
(isNum(v.radius) || isNum(v.r)));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The radius of anything isCircleLike() accepts: a Circle, the plain
|
|
92
|
+
* `{x, y, radius}` object `pg` hands back, or the `{x, y, r}` that was
|
|
93
|
+
* this client's own shape before the classes existed.
|
|
94
|
+
*/
|
|
95
|
+
static radiusOf(v) {
|
|
96
|
+
return v.radius ?? v.r;
|
|
64
97
|
}
|
|
65
98
|
}
|
|
66
99
|
/**
|
|
@@ -81,7 +114,12 @@ class TwoPoints {
|
|
|
81
114
|
this.x2 = x2;
|
|
82
115
|
this.y2 = y2;
|
|
83
116
|
}
|
|
84
|
-
|
|
117
|
+
/**
|
|
118
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
119
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
120
|
+
* client decoded can be handed straight to one.
|
|
121
|
+
*/
|
|
122
|
+
toPostgres() {
|
|
85
123
|
return this.toString();
|
|
86
124
|
}
|
|
87
125
|
static isTwoPointsLike(v) {
|
|
@@ -129,7 +167,12 @@ export class Line {
|
|
|
129
167
|
toString() {
|
|
130
168
|
return `{${this.a},${this.b},${this.c}}`;
|
|
131
169
|
}
|
|
132
|
-
|
|
170
|
+
/**
|
|
171
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
172
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
173
|
+
* client decoded can be handed straight to one.
|
|
174
|
+
*/
|
|
175
|
+
toPostgres() {
|
|
133
176
|
return this.toString();
|
|
134
177
|
}
|
|
135
178
|
static isLineLike(v) {
|
|
@@ -152,7 +195,12 @@ class PointList {
|
|
|
152
195
|
constructor(points = []) {
|
|
153
196
|
this.points = points.map(p => p instanceof Point ? p : new Point(p.x, p.y));
|
|
154
197
|
}
|
|
155
|
-
|
|
198
|
+
/**
|
|
199
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
200
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
201
|
+
* client decoded can be handed straight to one.
|
|
202
|
+
*/
|
|
203
|
+
toPostgres() {
|
|
156
204
|
return this.toString();
|
|
157
205
|
}
|
|
158
206
|
join() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** The fields an Interval is built from
|
|
1
|
+
/** The fields an Interval is built from; it keeps the ones that have a value. */
|
|
2
2
|
export interface IntervalFields {
|
|
3
3
|
years?: number;
|
|
4
4
|
months?: number;
|
|
@@ -18,20 +18,29 @@ export interface IntervalFields {
|
|
|
18
18
|
* zone, can add one to a timestamp. Anything here that answered "how many
|
|
19
19
|
* milliseconds is this" would have to invent those lengths.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
21
|
+
* It carries the fields that have a value and no others, which is what
|
|
22
|
+
* the wire format carries too - three quantities, and a zero among them
|
|
23
|
+
* is not a field:
|
|
22
24
|
*
|
|
23
25
|
* ```ts
|
|
24
26
|
* const iv = new Interval({ days: 1, hours: 2 });
|
|
25
|
-
* iv
|
|
27
|
+
* Object.keys(iv); // ['days', 'hours']
|
|
28
|
+
* iv.minutes; // undefined
|
|
26
29
|
* String(iv); // '1 day 02:00:00'
|
|
27
30
|
* iv.toISOString(); // 'P0Y0M1DT2H0M0S'
|
|
28
31
|
* ```
|
|
29
32
|
*
|
|
30
|
-
* The field names are `pg`'s (`postgres-interval`), so code
|
|
31
|
-
* reads the same values from the same places
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
33
|
+
* The field names and the shape are `pg`'s (`postgres-interval`), so code
|
|
34
|
+
* ported from it reads the same values from the same places and a
|
|
35
|
+
* `JSON.stringify` of a row says the same thing. The difference is that
|
|
36
|
+
* this has a `toString()` - `pg`'s object gives `[object Object]` in a log
|
|
37
|
+
* line - and a `toPostgres()`, so the value can be sent back.
|
|
38
|
+
*
|
|
39
|
+
* The fields are optional, so `iv.hours + 1` does not compile without
|
|
40
|
+
* saying what an absent one means (`(iv.hours ?? 0) + 1`). That is the
|
|
41
|
+
* point: which fields a value has depends on the value, not on the type,
|
|
42
|
+
* and the older shape - every field present and 0 - hid that behind
|
|
43
|
+
* numbers nobody wrote.
|
|
35
44
|
*
|
|
36
45
|
* `milliseconds` carries the sub-second part and can be fractional, since
|
|
37
46
|
* PostgreSQL stores microseconds: `interval '0.000001 seconds'` is
|
|
@@ -40,17 +49,27 @@ export interface IntervalFields {
|
|
|
40
49
|
* A negative interval carries the sign on each field that has one, the way
|
|
41
50
|
* the server prints it: `interval '-1 day -2 hours'` is
|
|
42
51
|
* `{ days: -1, hours: -2 }`.
|
|
52
|
+
*
|
|
53
|
+
* `toPostgres()` is `pg`'s convention for "write yourself back", so a
|
|
54
|
+
* value read here can be passed to any encoder that follows it - this
|
|
55
|
+
* client's own parameter path never needed it, since it knows the class.
|
|
43
56
|
*/
|
|
44
57
|
export declare class Interval implements IntervalFields {
|
|
45
|
-
years
|
|
46
|
-
months
|
|
47
|
-
days
|
|
48
|
-
hours
|
|
49
|
-
minutes
|
|
58
|
+
years?: number;
|
|
59
|
+
months?: number;
|
|
60
|
+
days?: number;
|
|
61
|
+
hours?: number;
|
|
62
|
+
minutes?: number;
|
|
50
63
|
/** Whole seconds; the sub-second part is in `milliseconds`. */
|
|
51
|
-
seconds
|
|
64
|
+
seconds?: number;
|
|
52
65
|
/** The sub-second part, fractional down to a microsecond. */
|
|
53
|
-
milliseconds
|
|
66
|
+
milliseconds?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Keeps the fields that have a value. A zero is not one: it is what
|
|
69
|
+
* every field of every interval would otherwise be filled with, and
|
|
70
|
+
* `{ days: 1 }` says what `interval '1 day'` is far better than the
|
|
71
|
+
* same thing plus six zeroes nobody wrote.
|
|
72
|
+
*/
|
|
54
73
|
constructor(fields?: IntervalFields);
|
|
55
74
|
/**
|
|
56
75
|
* Builds one from the three quantities the wire format carries: a signed
|
|
@@ -69,5 +88,10 @@ export declare class Interval implements IntervalFields {
|
|
|
69
88
|
toString(): string;
|
|
70
89
|
/** The interval as an ISO 8601 duration. */
|
|
71
90
|
toISOString(): string;
|
|
72
|
-
|
|
91
|
+
/**
|
|
92
|
+
* The literal PostgreSQL reads back, for an encoder that asks the value
|
|
93
|
+
* how to write itself - `pg`'s convention, and the reason a value this
|
|
94
|
+
* client decoded can be handed straight to one.
|
|
95
|
+
*/
|
|
96
|
+
toPostgres(): string;
|
|
73
97
|
}
|