postgrejs 3.8.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +59 -1
  2. package/README.md +50 -0
  3. package/connection/connection.d.ts +14 -2
  4. package/connection/connection.js +63 -11
  5. package/connection/intl-connection.d.ts +164 -6
  6. package/connection/intl-connection.js +558 -37
  7. package/connection/pool.d.ts +30 -6
  8. package/connection/pool.js +22 -3
  9. package/connection/prepared-statement.js +22 -2
  10. package/data-type-map.d.ts +16 -0
  11. package/data-type-map.js +56 -12
  12. package/data-types/circle-type.js +5 -2
  13. package/data-types/classes/geometric.d.ts +49 -7
  14. package/data-types/classes/geometric.js +59 -11
  15. package/data-types/classes/interval.d.ts +40 -16
  16. package/data-types/classes/interval.js +68 -40
  17. package/data-types/classes/numeric.d.ts +6 -0
  18. package/data-types/classes/numeric.js +8 -0
  19. package/data-types/classes/range.d.ts +6 -1
  20. package/data-types/classes/range.js +6 -1
  21. package/data-types/date-type.js +2 -2
  22. package/data-types/interval-type.js +1 -1
  23. package/data-types/money-type.d.ts +38 -0
  24. package/data-types/money-type.js +212 -0
  25. package/data-types/numeric-type.d.ts +2 -0
  26. package/data-types/numeric-type.js +22 -11
  27. package/data-types/temporal-types.d.ts +19 -0
  28. package/data-types/temporal-types.js +520 -0
  29. package/data-types/timestamp-type.js +2 -2
  30. package/data-types/timestamptz-type.js +2 -2
  31. package/index.d.ts +3 -0
  32. package/index.js +3 -0
  33. package/interfaces/data-mapping-options.d.ts +126 -4
  34. package/interfaces/database-connection-params.d.ts +32 -5
  35. package/interfaces/query-options.d.ts +32 -0
  36. package/interfaces/script-execute-options.d.ts +32 -0
  37. package/interfaces/transaction-options.d.ts +27 -0
  38. package/interfaces/transaction-options.js +1 -0
  39. package/package.json +1 -1
  40. package/protocol/database-error.d.ts +15 -0
  41. package/protocol/database-error.js +19 -0
  42. package/protocol/frontend.js +1 -1
  43. package/protocol/pg-socket.js +7 -10
  44. package/util/array-leaf.d.ts +10 -0
  45. package/util/array-leaf.js +22 -0
  46. package/util/connection-config.js +11 -1
  47. package/util/date-style.d.ts +47 -0
  48. package/util/date-style.js +123 -0
  49. package/util/decimal-as-string.d.ts +11 -0
  50. package/util/decimal-as-string.js +30 -0
  51. package/util/fetch-as-string.d.ts +33 -0
  52. package/util/fetch-as-string.js +122 -0
  53. package/util/get-parsers.js +18 -1
  54. package/util/parse-datetime.d.ts +4 -3
  55. package/util/parse-datetime.js +34 -9
  56. package/util/resolve-column-formats.d.ts +5 -11
  57. package/util/resolve-column-formats.js +28 -24
  58. package/util/row-decoder.d.ts +24 -4
  59. package/util/row-decoder.js +25 -10
  60. package/util/sql-tag.js +2 -1
  61. package/util/stringify-for-sql.js +6 -5
  62. package/util/temporal.d.ts +47 -0
  63. package/util/temporal.js +61 -0
  64. package/util/transaction-command.d.ts +7 -0
  65. package/util/transaction-command.js +32 -0
  66. package/util/unspecified-param.d.ts +18 -8
  67. package/util/unspecified-param.js +22 -14
@@ -0,0 +1,520 @@
1
+ import { DataTypeNames, DataTypeOIDs } from '../constants.js';
2
+ import { DataTypeMap, GlobalTypeMap } from '../data-type-map.js';
3
+ import { readBigInt64BE } from '../util/bigint-methods.js';
4
+ import { getTemporal, systemTimeZone, } from '../util/temporal.js';
5
+ import { DateType } from './date-type.js';
6
+ import { IntervalType, parseIntervalText } from './interval-type.js';
7
+ import { createMultiRangeType, createRangeType } from './range-type.js';
8
+ import { TimeType } from './time-type.js';
9
+ import { TimestampType } from './timestamp-type.js';
10
+ import { TimestamptzType } from './timestamptz-type.js';
11
+ /**
12
+ * PostgreSQL's date/time types decoded into `Temporal` values instead of
13
+ * `Date`.
14
+ *
15
+ * Three things `Date` cannot do and these can: carry the microseconds
16
+ * PostgreSQL actually stores (a `Date` is milliseconds, so the last three
17
+ * digits of every timestamp were being dropped), say that a `timestamp`
18
+ * has no zone at all rather than guessing one from `utcDates`, and keep
19
+ * a `date` a date instead of a midnight in some zone.
20
+ *
21
+ * Decoding only is opinionated: every type here still *accepts* as a
22
+ * parameter everything it accepted before, so turning this on does not
23
+ * invalidate the `Date`s and strings a caller already passes.
24
+ */
25
+ const EPOCH_2000_NS = 946684800000000000n;
26
+ const TS_INFINITY = 0x7fffffffffffffffn;
27
+ const TS_MINUS_INFINITY = -0x8000000000000000n;
28
+ const DATE_INFINITY = 0x7fffffff;
29
+ const DATE_MINUS_INFINITY = -0x80000000;
30
+ const MICROS_PER_DAY = 86400000000n;
31
+ const MAX_SAFE_MICROS = BigInt(Number.MAX_SAFE_INTEGER);
32
+ /** The five types a caller may ask for by OID. */
33
+ export const TemporalCapableOIDs = Object.freeze([
34
+ DataTypeOIDs.date,
35
+ DataTypeOIDs.time,
36
+ DataTypeOIDs.timestamp,
37
+ DataTypeOIDs.timestamptz,
38
+ DataTypeOIDs.interval,
39
+ ]);
40
+ function readMicros(v, offset) {
41
+ return typeof v.readBigInt64BE === 'function'
42
+ ? v.readBigInt64BE(offset)
43
+ : readBigInt64BE(v, offset);
44
+ }
45
+ /**
46
+ * PostgreSQL writes years before the common era as `0044-03-15 BC`;
47
+ * Temporal counts them astronomically, where that year is -43. Rewrites
48
+ * the one into the other - `-000043-03-15` - so the era is not simply
49
+ * refused, and the text path answers what the binary path already does.
50
+ */
51
+ function withoutEra(v) {
52
+ const body = v.slice(0, -3);
53
+ const dash = body.indexOf('-');
54
+ const year = 1 - +body.substring(0, dash);
55
+ return ((year < 0 ? '-' : '+') +
56
+ String(Math.abs(year)).padStart(6, '0') +
57
+ body.substring(dash));
58
+ }
59
+ function zoneOf(options) {
60
+ return options.timeZone || systemTimeZone();
61
+ }
62
+ /** Guards the one thing PostgreSQL can store and Temporal cannot hold. */
63
+ function requireMicrosecondPrecision(ns) {
64
+ if (ns % 1000n)
65
+ throw new TypeError('PostgreSQL stores microseconds, and this value carries ' +
66
+ 'nanoseconds that would be dropped. Round it first: ' +
67
+ "value.round({ smallestUnit: 'microsecond' }).");
68
+ return ns / 1000n;
69
+ }
70
+ /**
71
+ * A `Temporal.Duration` out of the three quantities PostgreSQL keeps
72
+ * apart, or an error when they cannot make one.
73
+ *
74
+ * `interval '1 mon -3 days'` is an ordinary PostgreSQL value and has no
75
+ * Duration: Temporal refuses a duration whose fields disagree in sign,
76
+ * and balancing months against days needs a date to count from, which a
77
+ * bare interval does not have.
78
+ */
79
+ function toDuration(T, months, days, micros) {
80
+ const signs = [
81
+ Math.sign(months),
82
+ Math.sign(days),
83
+ micros > 0n ? 1 : micros < 0n ? -1 : 0,
84
+ ];
85
+ let sign = 0;
86
+ let i;
87
+ for (i = 0; i < 3; i++) {
88
+ if (!signs[i])
89
+ continue;
90
+ if (!sign)
91
+ sign = signs[i];
92
+ else if (signs[i] !== sign)
93
+ throw new TypeError(`The interval ${months} mons ${days} days ${micros} us mixes ` +
94
+ 'signs, and Temporal.Duration allows only one sign for all of ' +
95
+ 'its fields. Leave `interval` out of `temporalTypes` for a ' +
96
+ 'column that holds values like this one.');
97
+ }
98
+ if (micros > MAX_SAFE_MICROS || micros < -MAX_SAFE_MICROS)
99
+ throw new RangeError(`An interval of ${micros} microseconds is past what a ` +
100
+ 'Temporal.Duration field can hold.');
101
+ // The time part is spread over hours/minutes/seconds rather than left
102
+ // as one microsecond count: a Duration never balances itself, so
103
+ // `interval '3 hours'` would answer 0 hours and 10800 seconds. Days
104
+ // and months are the two PostgreSQL keeps apart on purpose and are
105
+ // left exactly as they came.
106
+ const abs = micros < 0n ? -micros : micros;
107
+ const s = micros < 0n ? -1 : 1;
108
+ return T.Duration.from({
109
+ months,
110
+ days,
111
+ hours: Number(abs / 3600000000n) * s,
112
+ minutes: Number((abs / 60000000n) % 60n) * s,
113
+ seconds: Number((abs / 1000000n) % 60n) * s,
114
+ microseconds: Number(abs % 1000000n) * s,
115
+ });
116
+ }
117
+ /**
118
+ * The `Date` an existing decoder produced, as the Temporal value this
119
+ * type answers with. Only for the shapes the fast paths below hand back:
120
+ * `infinity` stays the number it already was, and an unreadable date -
121
+ * a zone abbreviation under a non-ISO DateStyle, which names no offset -
122
+ * is an error rather than an `Invalid Date` nobody can use.
123
+ */
124
+ function checkDate(v, str) {
125
+ if (typeof v === 'number')
126
+ return v;
127
+ if (Number.isNaN(v.getTime()))
128
+ throw new Error(`"${str}" could not be read as a date - see DataMappingOptions.dateStyle.`);
129
+ return v;
130
+ }
131
+ function temporalTimestamptzType(T) {
132
+ const decodeText = (v, options) => {
133
+ // ISO is the default DateStyle and is Instant's own shape once the
134
+ // space between date and time is allowed for, which it is.
135
+ if (!options.dateStyle) {
136
+ const c = v.charCodeAt(0);
137
+ if (c >= 0x30 && c <= 0x39)
138
+ return T.Instant.from(v.endsWith(' BC') ? withoutEra(v) : v).toZonedDateTimeISO(zoneOf(options));
139
+ }
140
+ const d = checkDate(TimestamptzType.decodeText(v, options), v);
141
+ // A styled rendering carries milliseconds at best, so nothing is
142
+ // lost by going through the Date the existing parser built.
143
+ return typeof d === 'number'
144
+ ? d
145
+ : T.Instant.fromEpochMilliseconds(d.getTime()).toZonedDateTimeISO(zoneOf(options));
146
+ };
147
+ return {
148
+ name: 'timestamptz',
149
+ oid: DataTypeOIDs.timestamptz,
150
+ jsType: 'Temporal.ZonedDateTime',
151
+ decodeBinary(v, offset = 0, _len, options) {
152
+ const micros = readMicros(v, offset);
153
+ if (micros === TS_INFINITY)
154
+ return Infinity;
155
+ if (micros === TS_MINUS_INFINITY)
156
+ return -Infinity;
157
+ return T.Instant.fromEpochNanoseconds(EPOCH_2000_NS + micros * 1000n).toZonedDateTimeISO(zoneOf(options));
158
+ },
159
+ decodeText,
160
+ decodeTextBuffer(buf, offset, len, options) {
161
+ return decodeText(buf.toString('latin1', offset, offset + len), options);
162
+ },
163
+ encodeBinary(buf, v, options) {
164
+ if (v instanceof T.ZonedDateTime || v instanceof T.Instant) {
165
+ buf.writeBigInt64BE(requireMicrosecondPrecision(v.epochNanoseconds - EPOCH_2000_NS));
166
+ return;
167
+ }
168
+ TimestamptzType.encodeBinary(buf, v, options);
169
+ },
170
+ encodeText(v, options) {
171
+ // Without the [zone] suffix, which PostgreSQL does not read - the
172
+ // offset in front of it is what carries the instant anyway.
173
+ if (v instanceof T.ZonedDateTime)
174
+ return v.toString({ timeZoneName: 'never' });
175
+ if (v instanceof T.Instant)
176
+ return v.toString();
177
+ return TimestamptzType.encodeText(v, options);
178
+ },
179
+ isType(v) {
180
+ return (v instanceof T.ZonedDateTime ||
181
+ v instanceof T.Instant ||
182
+ TimestamptzType.isType(v));
183
+ },
184
+ };
185
+ }
186
+ function temporalTimestampType(T) {
187
+ const fromDate = (d, options) => options.utcDates
188
+ ? T.PlainDateTime.from({
189
+ year: d.getUTCFullYear(),
190
+ month: d.getUTCMonth() + 1,
191
+ day: d.getUTCDate(),
192
+ hour: d.getUTCHours(),
193
+ minute: d.getUTCMinutes(),
194
+ second: d.getUTCSeconds(),
195
+ millisecond: d.getUTCMilliseconds(),
196
+ })
197
+ : T.PlainDateTime.from({
198
+ year: d.getFullYear(),
199
+ month: d.getMonth() + 1,
200
+ day: d.getDate(),
201
+ hour: d.getHours(),
202
+ minute: d.getMinutes(),
203
+ second: d.getSeconds(),
204
+ millisecond: d.getMilliseconds(),
205
+ });
206
+ const decodeText = (v, options) => {
207
+ if (!options.dateStyle) {
208
+ const c = v.charCodeAt(0);
209
+ if (c >= 0x30 && c <= 0x39)
210
+ return T.PlainDateTime.from(v.endsWith(' BC') ? withoutEra(v) : v);
211
+ }
212
+ const d = checkDate(TimestampType.decodeText(v, options), v);
213
+ return typeof d === 'number' ? d : fromDate(d, options);
214
+ };
215
+ return {
216
+ name: 'timestamp',
217
+ oid: DataTypeOIDs.timestamp,
218
+ jsType: 'Temporal.PlainDateTime',
219
+ decodeBinary(v, offset = 0) {
220
+ const micros = readMicros(v, offset);
221
+ if (micros === TS_INFINITY)
222
+ return Infinity;
223
+ if (micros === TS_MINUS_INFINITY)
224
+ return -Infinity;
225
+ // A timestamp carries no zone, so it is read in UTC and the zone
226
+ // dropped again - `utcDates` has nothing left to decide here.
227
+ return T.Instant.fromEpochNanoseconds(EPOCH_2000_NS + micros * 1000n)
228
+ .toZonedDateTimeISO('UTC')
229
+ .toPlainDateTime();
230
+ },
231
+ decodeText,
232
+ decodeTextBuffer(buf, offset, len, options) {
233
+ return decodeText(buf.toString('latin1', offset, offset + len), options);
234
+ },
235
+ encodeBinary(buf, v, options) {
236
+ if (v instanceof T.PlainDateTime) {
237
+ buf.writeBigInt64BE(requireMicrosecondPrecision(v.toZonedDateTime('UTC').epochNanoseconds - EPOCH_2000_NS));
238
+ return;
239
+ }
240
+ TimestampType.encodeBinary(buf, v, options);
241
+ },
242
+ encodeText(v, options) {
243
+ if (v instanceof T.PlainDateTime)
244
+ return v.toString();
245
+ return TimestampType.encodeText(v, options);
246
+ },
247
+ isType(v) {
248
+ return v instanceof T.PlainDateTime || TimestampType.isType(v);
249
+ },
250
+ };
251
+ }
252
+ function temporalDateType(T) {
253
+ const EPOCH_2000 = T.PlainDate.from('2000-01-01');
254
+ const decodeText = (v, options) => {
255
+ if (!options.dateStyle) {
256
+ const c = v.charCodeAt(0);
257
+ if (c >= 0x30 && c <= 0x39)
258
+ return T.PlainDate.from(v.endsWith(' BC') ? withoutEra(v) : v);
259
+ }
260
+ const d = checkDate(DateType.decodeText(v, options), v);
261
+ if (typeof d === 'number')
262
+ return d;
263
+ return options.utcDates
264
+ ? T.PlainDate.from({
265
+ year: d.getUTCFullYear(),
266
+ month: d.getUTCMonth() + 1,
267
+ day: d.getUTCDate(),
268
+ })
269
+ : T.PlainDate.from({
270
+ year: d.getFullYear(),
271
+ month: d.getMonth() + 1,
272
+ day: d.getDate(),
273
+ });
274
+ };
275
+ return {
276
+ name: 'date',
277
+ oid: DataTypeOIDs.date,
278
+ jsType: 'Temporal.PlainDate',
279
+ decodeBinary(v, offset = 0) {
280
+ const days = v.readInt32BE(offset);
281
+ if (days === DATE_INFINITY)
282
+ return Infinity;
283
+ if (days === DATE_MINUS_INFINITY)
284
+ return -Infinity;
285
+ return EPOCH_2000.add({ days });
286
+ },
287
+ decodeText,
288
+ decodeTextBuffer(buf, offset, len, options) {
289
+ return decodeText(buf.toString('latin1', offset, offset + len), options);
290
+ },
291
+ encodeBinary(buf, v, options) {
292
+ if (v instanceof T.PlainDate) {
293
+ buf.writeInt32BE(EPOCH_2000.until(v, { largestUnit: 'day' }).days);
294
+ return;
295
+ }
296
+ DateType.encodeBinary(buf, v, options);
297
+ },
298
+ encodeText(v, options) {
299
+ if (v instanceof T.PlainDate)
300
+ return v.toString();
301
+ return DateType.encodeText(v, options);
302
+ },
303
+ isType(v) {
304
+ return v instanceof T.PlainDate || DateType.isType(v);
305
+ },
306
+ };
307
+ }
308
+ function temporalTimeType(T) {
309
+ const MIDNIGHT = T.PlainTime.from('00:00:00');
310
+ // `time` is rendered the same way under every DateStyle, so there is
311
+ // no styled shape to fall back to here.
312
+ const decodeText = (v) => T.PlainTime.from(v);
313
+ return {
314
+ name: 'time',
315
+ oid: DataTypeOIDs.time,
316
+ jsType: 'Temporal.PlainTime',
317
+ decodeBinary(v, offset = 0) {
318
+ const micros = readMicros(v, offset);
319
+ // PostgreSQL's `time` runs to 24:00:00 inclusive; a PlainTime stops
320
+ // one nanosecond short of it, and adding a day's worth of
321
+ // microseconds to midnight would silently wrap back to 00:00:00.
322
+ if (micros >= MICROS_PER_DAY)
323
+ throw new RangeError("PostgreSQL's time '24:00:00' has no Temporal.PlainTime - it is " +
324
+ 'the end of the day, and a PlainTime only reaches 23:59:59.999999999.');
325
+ return MIDNIGHT.add({ microseconds: Number(micros) });
326
+ },
327
+ decodeText,
328
+ decodeTextBuffer(buf, offset, len) {
329
+ return decodeText(buf.toString('latin1', offset, offset + len));
330
+ },
331
+ encodeBinary(buf, v, options) {
332
+ if (v instanceof T.PlainTime) {
333
+ const d = MIDNIGHT.until(v, { largestUnit: 'microsecond' });
334
+ if (d.nanoseconds)
335
+ requireMicrosecondPrecision(BigInt(d.nanoseconds));
336
+ buf.writeBigInt64BE(BigInt(d.microseconds));
337
+ return;
338
+ }
339
+ TimeType.encodeBinary(buf, v, options);
340
+ },
341
+ encodeText(v, options) {
342
+ if (v instanceof T.PlainTime)
343
+ return v.toString();
344
+ return TimeType.encodeText(v, options);
345
+ },
346
+ isType(v) {
347
+ return v instanceof T.PlainTime || TimeType.isType(v);
348
+ },
349
+ };
350
+ }
351
+ function temporalIntervalType(T) {
352
+ return {
353
+ name: 'interval',
354
+ oid: DataTypeOIDs.interval,
355
+ jsType: 'Temporal.Duration',
356
+ decodeBinary(v, offset = 0) {
357
+ return toDuration(T, v.readInt32BE(offset + 12), v.readInt32BE(offset + 8), readMicros(v, offset));
358
+ },
359
+ decodeText(v) {
360
+ const iv = parseIntervalText(v);
361
+ return toDuration(T, iv.totalMonths, iv.days ?? 0, iv.totalMicroseconds);
362
+ },
363
+ encodeBinary(buf, v, options) {
364
+ if (!(v instanceof T.Duration)) {
365
+ IntervalType.encodeBinary(buf, v, options);
366
+ return;
367
+ }
368
+ buf.writeBigInt64BE(durationMicros(v));
369
+ buf.writeInt32BE(v.days + v.weeks * 7);
370
+ buf.writeInt32BE(v.years * 12 + v.months);
371
+ },
372
+ encodeText(v, options) {
373
+ // A Duration prints ISO 8601, which PostgreSQL reads whatever its
374
+ // IntervalStyle is set to.
375
+ if (v instanceof T.Duration)
376
+ return v.toString();
377
+ return IntervalType.encodeText(v, options);
378
+ },
379
+ isType(v) {
380
+ return v instanceof T.Duration || IntervalType.isType(v);
381
+ },
382
+ };
383
+ }
384
+ /** A Duration's time part, in the microseconds the wire carries. */
385
+ function durationMicros(d) {
386
+ if (d.nanoseconds % 1000)
387
+ requireMicrosecondPrecision(BigInt(d.nanoseconds));
388
+ return (BigInt(d.hours) * 3600000000n +
389
+ BigInt(d.minutes) * 60000000n +
390
+ BigInt(d.seconds) * 1000000n +
391
+ BigInt(d.milliseconds) * 1000n +
392
+ BigInt(d.microseconds) +
393
+ BigInt(d.nanoseconds / 1000));
394
+ }
395
+ const FAMILIES = {
396
+ [DataTypeOIDs.date]: {
397
+ build: temporalDateType,
398
+ arrayOid: DataTypeOIDs._date,
399
+ range: {
400
+ name: 'daterange',
401
+ oid: DataTypeOIDs.daterange,
402
+ arrayOid: DataTypeOIDs._daterange,
403
+ multiOid: DataTypeOIDs.datemultirange,
404
+ multiArrayOid: DataTypeOIDs._datemultirange,
405
+ },
406
+ },
407
+ [DataTypeOIDs.time]: {
408
+ build: temporalTimeType,
409
+ arrayOid: DataTypeOIDs._time,
410
+ },
411
+ [DataTypeOIDs.timestamp]: {
412
+ build: temporalTimestampType,
413
+ arrayOid: DataTypeOIDs._timestamp,
414
+ range: {
415
+ name: 'tsrange',
416
+ oid: DataTypeOIDs.tsrange,
417
+ arrayOid: DataTypeOIDs._tsrange,
418
+ multiOid: DataTypeOIDs.tsmultirange,
419
+ multiArrayOid: DataTypeOIDs._tsmultirange,
420
+ },
421
+ },
422
+ [DataTypeOIDs.timestamptz]: {
423
+ build: temporalTimestamptzType,
424
+ arrayOid: DataTypeOIDs._timestamptz,
425
+ range: {
426
+ name: 'tstzrange',
427
+ oid: DataTypeOIDs.tstzrange,
428
+ arrayOid: DataTypeOIDs._tstzrange,
429
+ multiOid: DataTypeOIDs.tstzmultirange,
430
+ multiArrayOid: DataTypeOIDs._tstzmultirange,
431
+ },
432
+ },
433
+ [DataTypeOIDs.interval]: {
434
+ build: temporalIntervalType,
435
+ arrayOid: DataTypeOIDs._interval,
436
+ },
437
+ };
438
+ /** Every registration one selected OID stands for. */
439
+ export function temporalTypesFor(oid, T) {
440
+ const spec = FAMILIES[oid];
441
+ const scalar = spec.build(T);
442
+ const out = [
443
+ scalar,
444
+ {
445
+ ...scalar,
446
+ name: '_' + scalar.name,
447
+ oid: spec.arrayOid,
448
+ elementsOID: scalar.oid,
449
+ },
450
+ ];
451
+ const r = spec.range;
452
+ if (r) {
453
+ const multiName = r.name.replace('range', 'multirange');
454
+ const range = createRangeType(r.name, r.oid, scalar);
455
+ const multi = createMultiRangeType(multiName, r.multiOid, range);
456
+ out.push(range, { ...range, name: '_' + r.name, oid: r.arrayOid, elementsOID: r.oid }, multi, {
457
+ ...multi,
458
+ name: '_' + multiName,
459
+ oid: r.multiArrayOid,
460
+ elementsOID: r.multiOid,
461
+ });
462
+ }
463
+ return out;
464
+ }
465
+ function normalizeSelection(selection) {
466
+ if (selection === true)
467
+ return TemporalCapableOIDs.slice();
468
+ if (selection === false)
469
+ return [];
470
+ if (!Array.isArray(selection))
471
+ throw new TypeError('`temporalTypes` is either a boolean or an array of OIDs, not ' +
472
+ typeof selection);
473
+ const out = [];
474
+ const l = selection.length;
475
+ let i;
476
+ let oid;
477
+ for (i = 0; i < l; i++) {
478
+ oid = selection[i];
479
+ if (!TemporalCapableOIDs.includes(oid))
480
+ throw new TypeError('`temporalTypes` accepts only date (1082), time (1083), timestamp ' +
481
+ '(1114), timestamptz (1184) and interval (1186). Received ' +
482
+ `${oid}${DataTypeNames[oid] ? ' (' + DataTypeNames[oid] + ')' : ''}.`);
483
+ if (!out.includes(oid))
484
+ out.push(oid);
485
+ }
486
+ return out.sort((a, b) => a - b);
487
+ }
488
+ const _derived = new WeakMap();
489
+ /**
490
+ * A type map that decodes the selected date/time types into `Temporal`
491
+ * values, built on top of `base` - which keeps whatever else the caller
492
+ * registered there.
493
+ *
494
+ * The same selection on the same base always gives back the same map.
495
+ * That is not only to save the copy: a prepared statement is reused only
496
+ * while the map it was parsed with is the same object, so handing out a
497
+ * fresh map per statement would quietly empty the statement cache.
498
+ */
499
+ export function temporalTypeMap(selection = true, base = GlobalTypeMap) {
500
+ const oids = normalizeSelection(selection);
501
+ if (!oids.length)
502
+ return base;
503
+ const key = oids.join(',');
504
+ let forBase = _derived.get(base);
505
+ if (!forBase) {
506
+ forBase = new Map();
507
+ _derived.set(base, forBase);
508
+ }
509
+ let map = forBase.get(key);
510
+ if (!map) {
511
+ const T = getTemporal();
512
+ map = new DataTypeMap(base);
513
+ const l = oids.length;
514
+ let i;
515
+ for (i = 0; i < l; i++)
516
+ map.register(temporalTypesFor(oids[i], T));
517
+ forBase.set(key, map);
518
+ }
519
+ return map;
520
+ }
@@ -13,7 +13,7 @@ export const TimestampType = {
13
13
  },
14
14
  encodeBinary(buf, v, options) {
15
15
  if (typeof v === 'string')
16
- v = parseDateTime(v, options.utcDates);
16
+ v = parseDateTime(v, options.utcDates, options.dateStyle);
17
17
  if (v === Infinity) {
18
18
  buf.writeInt32BE(0x7fffffff); // hi
19
19
  buf.writeUInt32BE(0xffffffff); // lo
@@ -51,7 +51,7 @@ export const TimestampType = {
51
51
  return d;
52
52
  },
53
53
  decodeText(v, options) {
54
- return parseDateTime(v, options.utcDates);
54
+ return parseDateTime(v, options.utcDates, options.dateStyle);
55
55
  },
56
56
  // Reads PostgreSQL's own timestamp shape straight from the wire bytes -
57
57
  // see timestamptz-type.ts's decodeTextBuffer for why. The guard is what
@@ -14,7 +14,7 @@ export const TimestamptzType = {
14
14
  },
15
15
  encodeBinary(buf, v, options) {
16
16
  if (typeof v === 'string')
17
- v = parseDateTimeTz(v, options.utcDates);
17
+ v = parseDateTimeTz(v, options.utcDates, options.dateStyle);
18
18
  if (v === Infinity) {
19
19
  buf.writeInt32BE(0x7fffffff); // hi
20
20
  buf.writeUInt32BE(0xffffffff); // lo
@@ -53,7 +53,7 @@ export const TimestamptzType = {
53
53
  return new Date((lo + hi * timeMul) / 1000 + timeShift);
54
54
  },
55
55
  decodeText(v, options) {
56
- return parseDateTimeTz(v, options.utcDates);
56
+ return parseDateTimeTz(v, options.utcDates, options.dateStyle);
57
57
  },
58
58
  // Reads PostgreSQL's own timestamp shape straight from the wire bytes.
59
59
  // Building the string first and handing it to decodeText() costs about
package/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from './data-types/classes/geometric.js';
12
12
  export * from './data-types/classes/interval.js';
13
13
  export * from './data-types/classes/numeric.js';
14
14
  export * from './data-types/classes/range.js';
15
+ export * from './data-types/temporal-types.js';
15
16
  export * from './interfaces/batch-result.js';
16
17
  export * from './interfaces/command-result.js';
17
18
  export * from './interfaces/copy-from-rows-options.js';
@@ -27,11 +28,13 @@ export * from './interfaces/query-result.js';
27
28
  export * from './interfaces/script-execute-options.js';
28
29
  export * from './interfaces/script-result.js';
29
30
  export * from './interfaces/statement-prepare-options.js';
31
+ export * from './interfaces/transaction-options.js';
30
32
  export * from './protocol/connection-lost-error.js';
31
33
  export * from './protocol/database-error.js';
32
34
  export * from './protocol/smart-buffer.js';
33
35
  export * from './types.js';
34
36
  export * from './util/connection-config.js';
37
+ export * from './util/decimal-as-string.js';
35
38
  export * from './util/escape-identifier.js';
36
39
  export * from './util/escape-literal.js';
37
40
  export * from './util/parse-datetime.js';
package/index.js CHANGED
@@ -12,6 +12,7 @@ export * from './data-types/classes/geometric.js';
12
12
  export * from './data-types/classes/interval.js';
13
13
  export * from './data-types/classes/numeric.js';
14
14
  export * from './data-types/classes/range.js';
15
+ export * from './data-types/temporal-types.js';
15
16
  export * from './interfaces/batch-result.js';
16
17
  export * from './interfaces/command-result.js';
17
18
  export * from './interfaces/copy-from-rows-options.js';
@@ -27,11 +28,13 @@ export * from './interfaces/query-result.js';
27
28
  export * from './interfaces/script-execute-options.js';
28
29
  export * from './interfaces/script-result.js';
29
30
  export * from './interfaces/statement-prepare-options.js';
31
+ export * from './interfaces/transaction-options.js';
30
32
  export * from './protocol/connection-lost-error.js';
31
33
  export * from './protocol/database-error.js';
32
34
  export * from './protocol/smart-buffer.js';
33
35
  export * from './types.js';
34
36
  export * from './util/connection-config.js';
37
+ export * from './util/decimal-as-string.js';
35
38
  export * from './util/escape-identifier.js';
36
39
  export * from './util/escape-literal.js';
37
40
  export * from './util/parse-datetime.js';