postgrejs 2.23.1 → 3.0.1

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 (105) hide show
  1. package/CHANGELOG.md +152 -1
  2. package/LICENSE +26 -17
  3. package/README.md +195 -175
  4. package/connection/connection.d.ts +152 -13
  5. package/connection/connection.js +296 -49
  6. package/connection/copy-stream.d.ts +88 -0
  7. package/connection/copy-stream.js +244 -0
  8. package/connection/cursor.js +20 -13
  9. package/connection/intl-connection.d.ts +68 -3
  10. package/connection/intl-connection.js +414 -57
  11. package/connection/large-object.d.ts +65 -0
  12. package/connection/large-object.js +151 -0
  13. package/connection/logical-replication.d.ts +121 -0
  14. package/connection/logical-replication.js +279 -0
  15. package/connection/pool.d.ts +61 -4
  16. package/connection/pool.js +177 -29
  17. package/connection/portal.d.ts +18 -4
  18. package/connection/portal.js +53 -59
  19. package/connection/prepared-statement.d.ts +22 -1
  20. package/connection/prepared-statement.js +117 -97
  21. package/data-type-map.js +4 -2
  22. package/data-types/bool-type.js +14 -10
  23. package/data-types/box-type.js +15 -8
  24. package/data-types/bytea-type.js +9 -5
  25. package/data-types/char-type.js +11 -5
  26. package/data-types/circle-type.js +15 -7
  27. package/data-types/date-type.js +25 -19
  28. package/data-types/float4-type.js +10 -3
  29. package/data-types/float8-type.js +12 -3
  30. package/data-types/int2-type.js +9 -4
  31. package/data-types/int2-vector-type.js +9 -4
  32. package/data-types/int4-type.js +11 -5
  33. package/data-types/int8-type.js +22 -7
  34. package/data-types/json-type.js +17 -8
  35. package/data-types/jsonb-type.js +20 -14
  36. package/data-types/lseg-type.js +16 -8
  37. package/data-types/numeric-type.d.ts +8 -0
  38. package/data-types/numeric-type.js +112 -8
  39. package/data-types/oid-type.d.ts +0 -1
  40. package/data-types/oid-type.js +9 -10
  41. package/data-types/oid-vector-type.d.ts +9 -0
  42. package/data-types/oid-vector-type.js +51 -0
  43. package/data-types/point-type.js +14 -6
  44. package/data-types/time-type.js +20 -13
  45. package/data-types/timestamp-type.js +32 -25
  46. package/data-types/timestamptz-type.js +33 -21
  47. package/data-types/uuid-type.js +21 -11
  48. package/data-types/varchar-type.js +16 -4
  49. package/index.d.ts +5 -0
  50. package/index.js +5 -0
  51. package/interfaces/data-type.d.ts +5 -3
  52. package/interfaces/database-connection-params.d.ts +95 -0
  53. package/interfaces/query-options.d.ts +17 -0
  54. package/interfaces/script-execute-options.d.ts +17 -0
  55. package/package.json +2 -3
  56. package/protocol/backend.d.ts +6 -1
  57. package/protocol/backend.js +70 -45
  58. package/protocol/buffer-reader.d.ts +0 -2
  59. package/protocol/buffer-reader.js +3 -10
  60. package/protocol/cert-signature.d.ts +12 -0
  61. package/protocol/cert-signature.js +114 -0
  62. package/protocol/frontend.d.ts +16 -0
  63. package/protocol/frontend.js +57 -6
  64. package/protocol/pg-socket.d.ts +220 -9
  65. package/protocol/pg-socket.js +539 -102
  66. package/protocol/pgoutput.d.ts +76 -0
  67. package/protocol/pgoutput.js +155 -0
  68. package/protocol/protocol.d.ts +3 -4
  69. package/protocol/protocol.js +1 -1
  70. package/protocol/sasl.d.ts +11 -1
  71. package/protocol/sasl.js +35 -4
  72. package/protocol/smart-buffer.d.ts +0 -2
  73. package/protocol/smart-buffer.js +11 -16
  74. package/types.d.ts +5 -3
  75. package/util/abort-signal.d.ts +24 -0
  76. package/util/abort-signal.js +63 -0
  77. package/util/array-calculatedim.js +3 -1
  78. package/util/connection-config.js +77 -3
  79. package/util/decode-binaryarray.d.ts +1 -1
  80. package/util/decode-binaryarray.js +15 -6
  81. package/util/encode-binaryarray.js +7 -3
  82. package/util/escape-identifier.d.ts +14 -0
  83. package/util/escape-identifier.js +32 -0
  84. package/util/escape-literal.js +3 -0
  85. package/util/fast-parseint.d.ts +1 -0
  86. package/util/fast-parseint.js +12 -17
  87. package/util/format-datetime.d.ts +10 -0
  88. package/util/format-datetime.js +71 -0
  89. package/util/get-parsers.js +31 -10
  90. package/util/parse-array.js +2 -2
  91. package/util/parse-bytea.d.ts +2 -0
  92. package/util/parse-bytea.js +83 -0
  93. package/util/parse-datetime.d.ts +3 -1
  94. package/util/parse-datetime.js +86 -17
  95. package/util/parse-row.d.ts +3 -1
  96. package/util/parse-row.js +60 -5
  97. package/util/parse-time.js +8 -1
  98. package/util/sql-tag.d.ts +60 -0
  99. package/util/sql-tag.js +202 -0
  100. package/util/starts-transaction.d.ts +38 -0
  101. package/util/starts-transaction.js +148 -0
  102. package/util/stringify-arrayliteral.js +13 -1
  103. package/util/wrap-row-description.js +13 -4
  104. package/util/convert-row-to-object.d.ts +0 -2
  105. package/util/convert-row-to-object.js +0 -9
@@ -1,20 +1,26 @@
1
1
  import { DataTypeOIDs } from '../constants.js';
2
- import { fastParseInt } from '../util/fast-parseint.js';
2
+ import { fastParseInt, fastParseIntBuffer } from '../util/fast-parseint.js';
3
3
  export const Int4Type = {
4
4
  name: 'int4',
5
5
  oid: DataTypeOIDs.int4,
6
6
  jsType: 'number',
7
- parseBinary(v) {
8
- return v.readInt32BE(0);
7
+ fixedBinarySize: 4,
8
+ encodeText(v) {
9
+ return '' + v;
9
10
  },
10
11
  encodeBinary(buf, v) {
11
12
  buf.writeInt32BE(fastParseInt(v));
12
13
  },
13
- parseText: fastParseInt,
14
+ decodeBinary(v, offset = 0) {
15
+ return v.readInt32BE(offset);
16
+ },
17
+ decodeText: fastParseInt,
18
+ decodeTextBuffer: fastParseIntBuffer,
14
19
  isType(v) {
15
20
  return (typeof v === 'number' &&
16
21
  Number.isInteger(v) &&
17
- v <= Number.MAX_SAFE_INTEGER);
22
+ v >= -2147483648 &&
23
+ v <= 2147483647);
18
24
  },
19
25
  };
20
26
  export const ArrayInt4Type = {
@@ -1,28 +1,43 @@
1
1
  import { DataTypeOIDs } from '../constants.js';
2
2
  import { readBigInt64BE } from '../util/bigint-methods.js';
3
+ import { fastParseIntBuffer } from '../util/fast-parseint.js';
3
4
  const maxSafeInteger = BigInt(Number.MAX_SAFE_INTEGER);
4
5
  export const Int8Type = {
5
6
  name: 'int8',
6
7
  oid: DataTypeOIDs.int8,
7
8
  jsType: 'BigInt',
8
- parseBinary(buf) {
9
- const v = typeof buf.readBigInt64BE === 'function'
10
- ? buf.readBigInt64BE(0)
11
- : readBigInt64BE(buf);
12
- return v >= -maxSafeInteger && v <= maxSafeInteger ? Number(v) : v;
9
+ fixedBinarySize: 8,
10
+ encodeText(v) {
11
+ return '' + v;
13
12
  },
14
13
  encodeBinary(buf, v) {
15
14
  buf.writeBigInt64BE(v);
16
15
  },
17
- parseText(s) {
16
+ decodeBinary(buf, offset = 0) {
17
+ const v = typeof buf.readBigInt64BE === 'function'
18
+ ? buf.readBigInt64BE(offset)
19
+ : readBigInt64BE(buf, offset);
20
+ return v >= -maxSafeInteger && v <= maxSafeInteger ? Number(v) : v;
21
+ },
22
+ decodeText(s) {
23
+ const digits = s.charCodeAt(0) === 45 /* '-' */ ? s.length - 1 : s.length;
24
+ if (digits <= 15)
25
+ return Number(s);
18
26
  const v = BigInt(s);
19
27
  return v >= -maxSafeInteger && v <= maxSafeInteger ? Number(v) : v;
20
28
  },
29
+ decodeTextBuffer(buf, offset, len) {
30
+ const digits = buf[offset] === 45 /* '-' */ ? len - 1 : len;
31
+ if (digits <= 15)
32
+ return fastParseIntBuffer(buf, offset, len);
33
+ const v = BigInt(buf.toString('utf8', offset, offset + len));
34
+ return v >= -maxSafeInteger && v <= maxSafeInteger ? Number(v) : v;
35
+ },
21
36
  isType(v) {
22
37
  return (typeof v === 'bigint' ||
23
38
  (typeof v === 'number' &&
24
39
  Number.isInteger(v) &&
25
- v > Number.MAX_SAFE_INTEGER));
40
+ (v > 2147483647 || v < -2147483648)));
26
41
  },
27
42
  };
28
43
  export const ArrayInt8Type = {
@@ -3,28 +3,37 @@ export const JsonType = {
3
3
  name: 'json',
4
4
  oid: DataTypeOIDs.json,
5
5
  jsType: 'string',
6
- parseBinary(v, options) {
7
- const content = v.toString('utf8');
8
- const fetchAsString = options.fetchAsString &&
9
- options.fetchAsString.includes(DataTypeOIDs.jsonb);
6
+ decodeBinary(v, offset = 0, options) {
7
+ const content = v.toString('utf8', offset);
8
+ const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.json);
10
9
  if (fetchAsString)
11
10
  return content;
12
11
  return content ? JSON.parse(content) : undefined;
13
12
  },
13
+ // json is stored as the text itself, so its binary form is those bytes.
14
+ encodeBinary(buf, v) {
15
+ buf.writeString(JsonType.encodeText(v, {}), 'utf8');
16
+ },
14
17
  encodeText(v) {
15
- if (typeof v === 'object' || typeof v === 'bigint')
18
+ // JSON.stringify() cannot serialize a BigInt itself (it throws), so a
19
+ // bigint is written directly as a bare numeric literal instead.
20
+ if (typeof v === 'bigint')
21
+ return v.toString();
22
+ if (typeof v === 'object')
16
23
  return JSON.stringify(v);
17
24
  if (typeof v === 'boolean')
18
25
  return v ? 'true' : 'false';
19
26
  return '' + v;
20
27
  },
21
- parseText(v, options) {
22
- const fetchAsString = options.fetchAsString &&
23
- options.fetchAsString.includes(DataTypeOIDs.jsonb);
28
+ decodeText(v, options) {
29
+ const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.json);
24
30
  if (fetchAsString)
25
31
  return v;
26
32
  return v ? JSON.parse(v) : null;
27
33
  },
34
+ decodeTextBuffer(buf, offset, len, options) {
35
+ return JsonType.decodeText(buf.toString('utf8', offset, offset + len), options);
36
+ },
28
37
  isType(v) {
29
38
  return v && typeof v === 'object';
30
39
  },
@@ -4,31 +4,37 @@ export const JsonbType = {
4
4
  name: 'jsonb',
5
5
  oid: DataTypeOIDs.jsonb,
6
6
  jsType: 'string',
7
- parseBinary(v, options) {
8
- const buf = new BufferReader(v);
7
+ encodeText(v) {
8
+ if (typeof v === 'object' || typeof v === 'bigint')
9
+ return JSON.stringify(v);
10
+ if (typeof v === 'boolean')
11
+ return v ? 'true' : 'false';
12
+ return '' + v;
13
+ },
14
+ encodeBinary(buf, v) {
15
+ buf.writeUInt8(1);
16
+ buf.writeString(JsonbType.encodeText(v, {}), 'utf8');
17
+ },
18
+ decodeBinary(v, offset = 0, options) {
19
+ const buf = new BufferReader(offset ? v.subarray(offset) : v);
9
20
  if (buf.readUInt8() !== 1)
10
21
  throw new Error('Unexpected Jsonb version value in header');
11
- const fetchAsString = options.fetchAsString &&
12
- options.fetchAsString.includes(DataTypeOIDs.json);
22
+ const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.jsonb);
13
23
  const content = buf.readLString(buf.length - buf.offset);
14
24
  if (fetchAsString)
15
25
  return content;
16
26
  return content ? JSON.parse(content) : undefined;
17
27
  },
18
- encodeText(v) {
19
- if (typeof v === 'object' || typeof v === 'bigint')
20
- return JSON.stringify(v);
21
- if (typeof v === 'boolean')
22
- return v ? 'true' : 'false';
23
- return '\x0001' + v;
24
- },
25
- parseText(v, options) {
26
- const fetchAsString = options.fetchAsString &&
27
- options.fetchAsString.includes(DataTypeOIDs.json);
28
+ decodeText(v, options) {
29
+ const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.jsonb);
28
30
  if (fetchAsString)
29
31
  return v;
30
32
  return v ? JSON.parse(v) : null;
31
33
  },
34
+ // See json-type.ts's decodeTextBuffer comment - same rationale.
35
+ decodeTextBuffer(buf, offset, len, options) {
36
+ return JsonbType.decodeText(buf.toString('utf8', offset, offset + len), options);
37
+ },
32
38
  isType(v) {
33
39
  return v && typeof v === 'object';
34
40
  },
@@ -7,13 +7,9 @@ export const LsegType = {
7
7
  name: 'lseg',
8
8
  oid: DataTypeOIDs.lseg,
9
9
  jsType: 'object',
10
- parseBinary(v) {
11
- return {
12
- x1: v.readDoubleBE(0),
13
- y1: v.readDoubleBE(8),
14
- x2: v.readDoubleBE(16),
15
- y2: v.readDoubleBE(24),
16
- };
10
+ fixedBinarySize: 32,
11
+ encodeText(v) {
12
+ return `[(${v.x1},${v.y1}),(${v.x2},${v.y2})]`;
17
13
  },
18
14
  encodeBinary(buf, v) {
19
15
  buf.writeDoubleBE(v.x1);
@@ -21,7 +17,15 @@ export const LsegType = {
21
17
  buf.writeDoubleBE(v.x2);
22
18
  buf.writeDoubleBE(v.y2);
23
19
  },
24
- parseText(v) {
20
+ decodeBinary(v, offset = 0) {
21
+ return {
22
+ x1: v.readDoubleBE(offset),
23
+ y1: v.readDoubleBE(offset + 8),
24
+ x2: v.readDoubleBE(offset + 16),
25
+ y2: v.readDoubleBE(offset + 24),
26
+ };
27
+ },
28
+ decodeText(v) {
25
29
  const m = v.match(LSEG_PATTERN1) ||
26
30
  v.match(LSEG_PATTERN2) ||
27
31
  v.match(LSEG_PATTERN3) ||
@@ -35,6 +39,10 @@ export const LsegType = {
35
39
  y2: parseFloat(m[4]),
36
40
  };
37
41
  },
42
+ // See box-type.ts's decodeTextBuffer comment - same rationale.
43
+ decodeTextBuffer(buf, offset, len, options) {
44
+ return LsegType.decodeText(buf.toString('latin1', offset, offset + len), options);
45
+ },
38
46
  isType(v) {
39
47
  return (typeof v === 'object' &&
40
48
  Object.keys(v).length === 4 &&
@@ -1,6 +1,14 @@
1
1
  import type { DataType } from '../interfaces/data-type.js';
2
2
  export declare const NumericType: DataType;
3
3
  export declare const ArrayNumericType: DataType;
4
+ /**
5
+ * Turns a JS exponential-notation number string (e.g. "1e+21", "-1.5e-7")
6
+ * into plain decimal notation by shifting the decimal point across the
7
+ * mantissa's own digits - no floating-point math involved, so it stays
8
+ * exact for magnitudes past what toFixed() can express (it reverts to
9
+ * exponential notation itself once |x| reaches 1e21).
10
+ */
11
+ export declare function expandExponential(str: string): string;
4
12
  /**
5
13
  * Convert a number from binary representation to text representation.
6
14
  * @param digits array of shorts that can be decoded as the number String
@@ -1,22 +1,100 @@
1
1
  import { DataTypeOIDs } from '../constants.js';
2
2
  const NUMERIC_NEG = 0x4000;
3
3
  const NUMERIC_NAN = 0xc000;
4
+ const NUMERIC_PINF = 0xd000;
5
+ const NUMERIC_NINF = 0xf000;
4
6
  const DEC_DIGITS = 4;
5
7
  const ROUND_POWERS = [0, 1000, 100, 10];
6
8
  export const NumericType = {
7
9
  name: 'numeric',
8
10
  oid: DataTypeOIDs.numeric,
9
11
  jsType: 'number',
10
- parseBinary(v) {
11
- const len = v.readInt16BE();
12
- const weight = v.readInt16BE(2);
13
- const sign = v.readInt16BE(4);
14
- const scale = v.readInt16BE(6);
12
+ /**
13
+ * numeric on the wire is a base-10000 number: a digit count, the weight
14
+ * of the first group (in groups of four decimal digits, not digits), a
15
+ * sign mask, the display scale, then the groups themselves.
16
+ *
17
+ * Encoded from the decimal text rather than from the float, so a value
18
+ * that JavaScript cannot hold exactly - which is most of what numeric
19
+ * exists for - survives when it was given as a string.
20
+ */
21
+ encodeBinary(buf, v) {
22
+ const writeHeader = (ndigits, weight, sign, dscale) => {
23
+ buf.writeInt16BE(ndigits);
24
+ buf.writeInt16BE(weight);
25
+ buf.writeUInt16BE(sign);
26
+ buf.writeInt16BE(dscale);
27
+ };
28
+ if (typeof v === 'number' && !Number.isFinite(v)) {
29
+ writeHeader(0, 0, Number.isNaN(v) ? NUMERIC_NAN : v > 0 ? NUMERIC_PINF : NUMERIC_NINF, 0);
30
+ return;
31
+ }
32
+ let str = typeof v === 'string' ? v.trim() : String(v);
33
+ if (str === 'NaN')
34
+ return writeHeader(0, 0, NUMERIC_NAN, 0);
35
+ if (str === 'Infinity')
36
+ return writeHeader(0, 0, NUMERIC_PINF, 0);
37
+ if (str === '-Infinity')
38
+ return writeHeader(0, 0, NUMERIC_NINF, 0);
39
+ // Exponent form has no place in the wire format; go through Number to
40
+ // get it back into plain notation. toFixed() cannot do this itself -
41
+ // per spec it falls back to exponential notation once the magnitude
42
+ // reaches 1e21, so this shifts the decimal point manually instead.
43
+ if (/e/i.test(str))
44
+ str = expandExponential(Number(str).toString());
45
+ let sign = 0;
46
+ if (str.startsWith('-')) {
47
+ sign = NUMERIC_NEG;
48
+ str = str.substring(1);
49
+ }
50
+ else if (str.startsWith('+'))
51
+ str = str.substring(1);
52
+ const dot = str.indexOf('.');
53
+ let intPart = dot < 0 ? str : str.substring(0, dot);
54
+ let fracPart = dot < 0 ? '' : str.substring(dot + 1);
55
+ const dscale = fracPart.length;
56
+ // Group into fours, aligned on the decimal point from both sides.
57
+ const intPad = (DEC_DIGITS - (intPart.length % DEC_DIGITS)) % DEC_DIGITS;
58
+ intPart = '0'.repeat(intPad) + intPart;
59
+ const fracPad = (DEC_DIGITS - (fracPart.length % DEC_DIGITS)) % DEC_DIGITS;
60
+ fracPart = fracPart + '0'.repeat(fracPad);
61
+ const digits = [];
62
+ for (let i = 0; i < intPart.length; i += DEC_DIGITS)
63
+ digits.push(+intPart.substring(i, i + DEC_DIGITS));
64
+ for (let i = 0; i < fracPart.length; i += DEC_DIGITS)
65
+ digits.push(+fracPart.substring(i, i + DEC_DIGITS));
66
+ // weight counts groups before the point, less one; leading zero groups
67
+ // are dropped and lower it, trailing ones are simply dropped.
68
+ let weight = intPart.length / DEC_DIGITS - 1;
69
+ while (digits.length && digits[0] === 0) {
70
+ digits.shift();
71
+ weight--;
72
+ }
73
+ while (digits.length && digits[digits.length - 1] === 0)
74
+ digits.pop();
75
+ if (!digits.length)
76
+ weight = 0;
77
+ writeHeader(digits.length, weight, sign, dscale);
78
+ for (const d of digits)
79
+ buf.writeInt16BE(d);
80
+ },
81
+ decodeBinary(v, offset = 0) {
82
+ const len = v.readInt16BE(offset);
83
+ const weight = v.readInt16BE(offset + 2);
84
+ // sign is a bitmask (0x0000/0x4000/0xC000/0xD000/0xF000), not a two's
85
+ // complement quantity - must be read unsigned or NaN/Infinity sign
86
+ // values (which set the top bit) never compare equal to the constants.
87
+ const sign = v.readUInt16BE(offset + 4);
88
+ const scale = v.readInt16BE(offset + 6);
15
89
  if (sign === NUMERIC_NAN)
16
90
  return NaN;
91
+ if (sign === NUMERIC_PINF)
92
+ return Infinity;
93
+ if (sign === NUMERIC_NINF)
94
+ return -Infinity;
17
95
  const digits = [];
18
96
  for (let i = 0; i < len; i++) {
19
- digits[i] = v.readInt16BE(8 + i * 2);
97
+ digits[i] = v.readInt16BE(offset + 8 + i * 2);
20
98
  }
21
99
  const numString = numberBytesToString(digits, scale, weight, sign);
22
100
  return parseFloat(numString);
@@ -25,7 +103,11 @@ export const NumericType = {
25
103
  const n = typeof v === 'number' ? v : parseFloat(v);
26
104
  return '' + n;
27
105
  },
28
- parseText: parseFloat,
106
+ decodeText: parseFloat,
107
+ // See float4-type.ts's decodeTextBuffer comment - same rationale.
108
+ decodeTextBuffer(buf, offset, len) {
109
+ return parseFloat(buf.toString('latin1', offset, offset + len));
110
+ },
29
111
  isType(v) {
30
112
  return typeof v === 'number';
31
113
  },
@@ -36,6 +118,26 @@ export const ArrayNumericType = {
36
118
  oid: DataTypeOIDs._numeric,
37
119
  elementsOID: DataTypeOIDs.numeric,
38
120
  };
121
+ /**
122
+ * Turns a JS exponential-notation number string (e.g. "1e+21", "-1.5e-7")
123
+ * into plain decimal notation by shifting the decimal point across the
124
+ * mantissa's own digits - no floating-point math involved, so it stays
125
+ * exact for magnitudes past what toFixed() can express (it reverts to
126
+ * exponential notation itself once |x| reaches 1e21).
127
+ */
128
+ export function expandExponential(str) {
129
+ const m = str.match(/^(-)?(\d+)(?:\.(\d+))?e([+-]?\d+)$/i);
130
+ if (!m)
131
+ return str;
132
+ const sign = m[1] || '';
133
+ const digits = m[2] + (m[3] || '');
134
+ const pointPos = m[2].length + parseInt(m[4], 10);
135
+ if (pointPos <= 0)
136
+ return sign + '0.' + '0'.repeat(-pointPos) + digits;
137
+ if (pointPos >= digits.length)
138
+ return sign + digits + '0'.repeat(pointPos - digits.length);
139
+ return sign + digits.slice(0, pointPos) + '.' + digits.slice(pointPos);
140
+ }
39
141
  /* https://github.com/pgjdbc/pgjdbc/blob/3eca3a76aa4a04cb28cb960ed674cb67db30b5e3/pgjdbc/src/main/java/org/postgresql/util/ByteConverter.java */
40
142
  /**
41
143
  * Convert a number from binary representation to text representation.
@@ -103,7 +205,9 @@ function digitToString(idx, digits, alwaysPutIt) {
103
205
  let dig = idx >= 0 && idx < digits.length ? digits[idx] : 0;
104
206
  // Each dig represents 4 decimal digits (e.g. 9999)
105
207
  // If we continue the number, then we need to print 0 as 0000 (alwaysPutIt parameter is true)
106
- for (let p = 1; p < ROUND_POWERS.length; p++) {
208
+ const l = ROUND_POWERS.length;
209
+ let p;
210
+ for (p = 1; p < l; p++) {
107
211
  const pow = ROUND_POWERS[p];
108
212
  const d1 = Math.trunc(dig / pow);
109
213
  dig -= d1 * pow;
@@ -1,4 +1,3 @@
1
1
  import type { DataType } from '../interfaces/data-type.js';
2
2
  export declare const OidType: DataType;
3
3
  export declare const ArrayOidType: DataType;
4
- export declare const VectorOidType: DataType;
@@ -1,16 +1,21 @@
1
1
  import { DataTypeNames, DataTypeOIDs } from '../constants.js';
2
- import { fastParseInt } from '../util/fast-parseint.js';
2
+ import { fastParseInt, fastParseIntBuffer } from '../util/fast-parseint.js';
3
3
  export const OidType = {
4
4
  name: 'oid',
5
5
  oid: DataTypeOIDs.oid,
6
6
  jsType: 'number',
7
- parseBinary(v) {
8
- return v.readUInt32BE(0);
7
+ fixedBinarySize: 4,
8
+ encodeText(v) {
9
+ return '' + v;
9
10
  },
10
11
  encodeBinary(buf, v) {
11
12
  buf.writeUInt32BE(fastParseInt(v));
12
13
  },
13
- parseText: fastParseInt,
14
+ decodeBinary(v, offset = 0) {
15
+ return v.readUInt32BE(offset);
16
+ },
17
+ decodeText: fastParseInt,
18
+ decodeTextBuffer: fastParseIntBuffer,
14
19
  isType(v) {
15
20
  return typeof v === 'number' && Number.isInteger(v) && !!DataTypeNames[v];
16
21
  },
@@ -21,9 +26,3 @@ export const ArrayOidType = {
21
26
  oid: DataTypeOIDs._oid,
22
27
  elementsOID: DataTypeOIDs.oid,
23
28
  };
24
- export const VectorOidType = {
25
- ...OidType,
26
- name: '_oidvector',
27
- oid: DataTypeOIDs.oidvector,
28
- elementsOID: DataTypeOIDs.oid,
29
- };
@@ -0,0 +1,9 @@
1
+ import type { DataType } from '../interfaces/data-type.js';
2
+ /**
3
+ * `oidvector` (OID 30) is a list of OIDs, not the array type of `oid` -
4
+ * that is `_oid` (1028). It has its own array type, `_oidvector` (1013),
5
+ * exactly as `int2vector` has `_int2vector`, and its text form is
6
+ * space-separated rather than braced.
7
+ */
8
+ export declare const OidVectorType: DataType;
9
+ export declare const ArrayOidVectorType: DataType;
@@ -0,0 +1,51 @@
1
+ import { DataTypeOIDs } from '../constants.js';
2
+ import { SmartBuffer } from '../protocol/smart-buffer.js';
3
+ import { decodeBinaryArray } from '../util/decode-binaryarray.js';
4
+ import { encodeBinaryArray } from '../util/encode-binaryarray.js';
5
+ import { fastParseInt } from '../util/fast-parseint.js';
6
+ /**
7
+ * `oidvector` (OID 30) is a list of OIDs, not the array type of `oid` -
8
+ * that is `_oid` (1028). It has its own array type, `_oidvector` (1013),
9
+ * exactly as `int2vector` has `_int2vector`, and its text form is
10
+ * space-separated rather than braced.
11
+ */
12
+ export const OidVectorType = {
13
+ name: 'oidvector',
14
+ oid: DataTypeOIDs.oidvector,
15
+ jsType: 'array',
16
+ encodeBinary(buf, v) {
17
+ encodeBinaryArray(buf, v, DataTypeOIDs.oid, {}, (io, x) => {
18
+ io.writeUInt32BE(x);
19
+ });
20
+ },
21
+ encodeCalculateDim(v) {
22
+ return [v.length];
23
+ },
24
+ decodeBinary(v) {
25
+ return decodeBinaryArray(v, 0, b => b.readUInt32BE()) || undefined;
26
+ },
27
+ decodeText(str) {
28
+ return str.split(' ').map(fastParseInt);
29
+ },
30
+ // See box-type.ts's decodeTextBuffer comment - same rationale (this text
31
+ // grammar is pure ASCII digits and spaces).
32
+ decodeTextBuffer(buf, offset, len, options) {
33
+ return OidVectorType.decodeText(buf.toString('latin1', offset, offset + len), options);
34
+ },
35
+ encodeText(v) {
36
+ return v.join(' ');
37
+ },
38
+ isType(v) {
39
+ return (Array.isArray(v) &&
40
+ !v.find(x => !(typeof x === 'number' &&
41
+ Number.isInteger(x) &&
42
+ x >= 0 &&
43
+ x <= 4294967295)));
44
+ },
45
+ };
46
+ export const ArrayOidVectorType = {
47
+ ...OidVectorType,
48
+ name: '_oidvector',
49
+ oid: DataTypeOIDs._oidvector,
50
+ elementsOID: DataTypeOIDs.oidvector,
51
+ };
@@ -5,17 +5,21 @@ export const PointType = {
5
5
  name: 'point',
6
6
  oid: DataTypeOIDs.point,
7
7
  jsType: 'object',
8
- parseBinary(v) {
9
- return {
10
- x: v.readDoubleBE(0),
11
- y: v.readDoubleBE(8),
12
- };
8
+ fixedBinarySize: 16,
9
+ encodeText(v) {
10
+ return `(${v.x},${v.y})`;
13
11
  },
14
12
  encodeBinary(buf, v) {
15
13
  buf.writeDoubleBE(v.x);
16
14
  buf.writeDoubleBE(v.y);
17
15
  },
18
- parseText(v) {
16
+ decodeBinary(v, offset = 0) {
17
+ return {
18
+ x: v.readDoubleBE(offset),
19
+ y: v.readDoubleBE(offset + 8),
20
+ };
21
+ },
22
+ decodeText(v) {
19
23
  const m = v.match(POINT_PATTERN1) || v.match(POINT_PATTERN2);
20
24
  if (!m)
21
25
  return undefined;
@@ -24,6 +28,10 @@ export const PointType = {
24
28
  y: parseFloat(m[2]),
25
29
  };
26
30
  },
31
+ // See box-type.ts's decodeTextBuffer comment - same rationale.
32
+ decodeTextBuffer(buf, offset, len, options) {
33
+ return PointType.decodeText(buf.toString('latin1', offset, offset + len), options);
34
+ },
27
35
  isType(v) {
28
36
  return (typeof v === 'object' &&
29
37
  Object.keys(v).length === 2 &&
@@ -1,20 +1,14 @@
1
1
  import { DataTypeOIDs } from '../constants.js';
2
+ import { formatTime } from '../util/format-datetime.js';
2
3
  import { parseTime, STRICT_TIME_PATTERN } from '../util/parse-time.js';
3
4
  const timeMul = 4294967296;
4
5
  export const TimeType = {
5
6
  name: 'time',
6
7
  oid: DataTypeOIDs.time,
7
8
  jsType: 'string',
8
- parseBinary(v, options) {
9
- const fetchAsString = options.fetchAsString &&
10
- options.fetchAsString.includes(DataTypeOIDs.time);
11
- const hi = v.readInt32BE();
12
- const lo = v.readUInt32BE(4);
13
- let d = new Date((lo + hi * timeMul) / 1000);
14
- if (fetchAsString || !options.utcDates) {
15
- d = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
16
- }
17
- return fetchAsString ? dateToTimeString(d) : d;
9
+ fixedBinarySize: 8,
10
+ encodeText(v, options) {
11
+ return formatTime(v, options);
18
12
  },
19
13
  encodeBinary(buf, v, options) {
20
14
  if (typeof v === 'string')
@@ -31,12 +25,25 @@ export const TimeType = {
31
25
  buf.writeInt32BE(hi);
32
26
  buf.writeUInt32BE(lo);
33
27
  },
34
- parseText(v, options) {
35
- if (options.fetchAsString &&
36
- options.fetchAsString.includes(DataTypeOIDs.time))
28
+ decodeBinary(v, offset = 0, options) {
29
+ const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.time);
30
+ const hi = v.readInt32BE(offset);
31
+ const lo = v.readUInt32BE(offset + 4);
32
+ let d = new Date((lo + hi * timeMul) / 1000);
33
+ if (fetchAsString || !options.utcDates) {
34
+ d = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds());
35
+ }
36
+ return fetchAsString ? dateToTimeString(d) : d;
37
+ },
38
+ decodeText(v, options) {
39
+ if (options.fetchAsString?.includes(DataTypeOIDs.time))
37
40
  return v;
38
41
  return parseTime(v, false, options.utcDates);
39
42
  },
43
+ // See date-type.ts's decodeTextBuffer comment - same rationale.
44
+ decodeTextBuffer(buf, offset, len, options) {
45
+ return TimeType.decodeText(buf.toString('latin1', offset, offset + len), options);
46
+ },
40
47
  isType(v) {
41
48
  return ((v instanceof Date &&
42
49
  v.getFullYear() === 1970 &&