@juit/pgproxy-types 1.0.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 (80) hide show
  1. package/README.md +14 -0
  2. package/dist/index.cjs +48 -0
  3. package/dist/index.cjs.map +6 -0
  4. package/dist/index.d.ts +9 -0
  5. package/dist/index.mjs +15 -0
  6. package/dist/index.mjs.map +6 -0
  7. package/dist/oids.cjs +163 -0
  8. package/dist/oids.cjs.map +6 -0
  9. package/dist/oids.d.ts +74 -0
  10. package/dist/oids.mjs +138 -0
  11. package/dist/oids.mjs.map +6 -0
  12. package/dist/parsers/array.cjs +140 -0
  13. package/dist/parsers/array.cjs.map +6 -0
  14. package/dist/parsers/array.d.ts +31 -0
  15. package/dist/parsers/array.mjs +111 -0
  16. package/dist/parsers/array.mjs.map +6 -0
  17. package/dist/parsers/basic.cjs +69 -0
  18. package/dist/parsers/basic.cjs.map +6 -0
  19. package/dist/parsers/basic.d.ts +15 -0
  20. package/dist/parsers/basic.mjs +28 -0
  21. package/dist/parsers/basic.mjs.map +6 -0
  22. package/dist/parsers/bytea.cjs +68 -0
  23. package/dist/parsers/bytea.cjs.map +6 -0
  24. package/dist/parsers/bytea.d.ts +7 -0
  25. package/dist/parsers/bytea.mjs +43 -0
  26. package/dist/parsers/bytea.mjs.map +6 -0
  27. package/dist/parsers/geometric.cjs +86 -0
  28. package/dist/parsers/geometric.cjs.map +6 -0
  29. package/dist/parsers/geometric.d.ts +27 -0
  30. package/dist/parsers/geometric.mjs +58 -0
  31. package/dist/parsers/geometric.mjs.map +6 -0
  32. package/dist/parsers/interval.cjs +50 -0
  33. package/dist/parsers/interval.cjs.map +6 -0
  34. package/dist/parsers/interval.d.ts +23 -0
  35. package/dist/parsers/interval.mjs +14 -0
  36. package/dist/parsers/interval.mjs.map +6 -0
  37. package/dist/parsers/range.cjs +97 -0
  38. package/dist/parsers/range.cjs.map +6 -0
  39. package/dist/parsers/range.d.ts +54 -0
  40. package/dist/parsers/range.mjs +50 -0
  41. package/dist/parsers/range.mjs.map +6 -0
  42. package/dist/parsers.cjs +104 -0
  43. package/dist/parsers.cjs.map +6 -0
  44. package/dist/parsers.d.ts +8 -0
  45. package/dist/parsers.mjs +86 -0
  46. package/dist/parsers.mjs.map +6 -0
  47. package/dist/registry.cjs +189 -0
  48. package/dist/registry.cjs.map +6 -0
  49. package/dist/registry.d.ts +81 -0
  50. package/dist/registry.mjs +200 -0
  51. package/dist/registry.mjs.map +6 -0
  52. package/dist/serializers/bytea.cjs +52 -0
  53. package/dist/serializers/bytea.cjs.map +6 -0
  54. package/dist/serializers/bytea.d.ts +13 -0
  55. package/dist/serializers/bytea.mjs +27 -0
  56. package/dist/serializers/bytea.mjs.map +6 -0
  57. package/dist/serializers/date.cjs +46 -0
  58. package/dist/serializers/date.cjs.map +6 -0
  59. package/dist/serializers/date.d.ts +2 -0
  60. package/dist/serializers/date.mjs +21 -0
  61. package/dist/serializers/date.mjs.map +6 -0
  62. package/dist/serializers.cjs +119 -0
  63. package/dist/serializers.cjs.map +6 -0
  64. package/dist/serializers.d.ts +20 -0
  65. package/dist/serializers.mjs +92 -0
  66. package/dist/serializers.mjs.map +6 -0
  67. package/package.json +49 -0
  68. package/src/index.ts +13 -0
  69. package/src/oids.ts +90 -0
  70. package/src/parsers/array.ts +176 -0
  71. package/src/parsers/basic.ts +55 -0
  72. package/src/parsers/bytea.ts +77 -0
  73. package/src/parsers/geometric.ts +96 -0
  74. package/src/parsers/interval.ts +40 -0
  75. package/src/parsers/range.ts +128 -0
  76. package/src/parsers.ts +57 -0
  77. package/src/registry.ts +168 -0
  78. package/src/serializers/bytea.ts +67 -0
  79. package/src/serializers/date.ts +63 -0
  80. package/src/serializers.ts +165 -0
@@ -0,0 +1,77 @@
1
+ /* ========================================================================== *
2
+ * INTERNALS *
3
+ * ========================================================================== */
4
+
5
+ /* Internal interface mimicking NodeJS's `Buffer`'s constructor */
6
+ interface NodeJSBuffer {
7
+ from(source:string, format: 'hex'): Uint8Array
8
+ from(source:Uint8Array): Uint8Array
9
+ }
10
+
11
+ /** Parse a BYTEA encoded in HEX */
12
+ function parseEncoded(input: string): Uint8Array {
13
+ const array = new Uint8Array((input.length - 2) / 2)
14
+ let index = 0
15
+ for (let i = 2; i < input.length; i += 2) {
16
+ array[index ++] = parseInt(input.substring(i, i + 2), 16)
17
+ }
18
+ return array
19
+ }
20
+
21
+ /** Parse a BYTEA using the _escaped_ format */
22
+ function parseEscaped(input: string, Buffer?: NodeJSBuffer | null): Uint8Array {
23
+ const result = new Uint8Array(input.length)
24
+ let pos = 0
25
+
26
+ for (let i = 0; i < input.length; i ++) {
27
+ const code = input.charCodeAt(i)
28
+ if (code !== 0x5c) {
29
+ /* Simple non-escaped character */
30
+ result[pos ++] = code
31
+ } else {
32
+ /* If we have a backslash, it may be followed by three octal digits */
33
+ const token = input.substring(i + 1, i + 4)
34
+ if (/[0-7]{3}/.test(token)) {
35
+ result[pos ++] = parseInt(token, 8)
36
+ i += 3 // advance after the octal number
37
+ } else {
38
+ /* Count how may backslashes we got... */
39
+ let backslashes = 1
40
+
41
+ for (
42
+ let char = input[++i];
43
+ (i < input.length) && (char === '\\');
44
+ char = input[++i]
45
+ ) backslashes ++
46
+
47
+ /* Fill the result with HALF the backslashes (escaped) */
48
+ result.fill(0x5c, pos, pos += backslashes >>> 1)
49
+
50
+ /* We consumed the character after the backslash */
51
+ i --
52
+ }
53
+ }
54
+ }
55
+
56
+ /* Return wrapping Buffer.from(array) with a subarray, or just a slice... */
57
+ return Buffer ? Buffer.from(result.subarray(0, pos)) : result.slice(0, pos)
58
+ }
59
+
60
+ /* ========================================================================== *
61
+ * EXPORTED PARSER *
62
+ * ========================================================================== */
63
+
64
+ /** Parse a PostgreSQL `BYTEA` string (escaped or encoded in hexadecimal) */
65
+ export function parseByteA(input: string, Buffer?: NodeJSBuffer | null): Uint8Array
66
+ /* Overload defaulting `Buffer` to `globalThis.Buffer` (Node's Buffer class) */
67
+ export function parseByteA(
68
+ input: string,
69
+ Buffer: NodeJSBuffer | null | undefined = (globalThis as any).Buffer,
70
+ ): Uint8Array {
71
+ if (input.startsWith('\\x')) {
72
+ /* Shortcut for NodeJS, use Buffer.from(str, 'hex') */
73
+ return Buffer ? Buffer.from(input.substring(2), 'hex') : parseEncoded(input)
74
+ } else {
75
+ return parseEscaped(input, Buffer)
76
+ }
77
+ }
@@ -0,0 +1,96 @@
1
+ import type { PGParser } from '../parsers'
2
+ import type { PGSerializable } from '../serializers'
3
+
4
+ /* ========================================================================== *
5
+ * GEOMETRIC TYPES *
6
+ * ========================================================================== */
7
+
8
+ /** A parsed PostgreSQL `point` */
9
+ export interface PGPoint extends PGSerializable {
10
+ readonly x: number,
11
+ readonly y: number,
12
+ }
13
+
14
+ /** A parsed PostgreSQL `circle` */
15
+ export interface PGCircle extends PGPoint {
16
+ readonly radius: number,
17
+ }
18
+
19
+ /** Constructor for {@link PGPoint} */
20
+ export interface PGPointConstructor {
21
+ new(x: number, y: number): PGPoint
22
+ }
23
+
24
+ /** Constructor for {@link PGCircle} */
25
+ export interface PGCircleConstructor {
26
+ new(x: number, y: number, radius: number): PGCircle
27
+ }
28
+
29
+
30
+ /** Create a new {@link PGPoint} instance */
31
+ export const PGPoint: PGPointConstructor = class PGPointImpl implements PGPoint {
32
+ constructor(public readonly x: number, public readonly y: number) {}
33
+
34
+ toPostgres(): string {
35
+ return `(${this.x},${this.y})`
36
+ }
37
+ }
38
+
39
+ /** Create a new {@link PGCircle} instance */
40
+ export const PGCircle: PGCircleConstructor = class PGCircleImpl extends PGPoint implements PGCircle {
41
+ constructor(x: number, y: number, public readonly radius: number) {
42
+ super(x, y)
43
+ }
44
+
45
+ toPostgres(): string {
46
+ return `<(${this.x},${this.y}),${this.radius}>`
47
+ }
48
+ }
49
+
50
+ /* ===== INVALID CONSTANTS ================================================== */
51
+
52
+ const INVALID_POINT = new PGPoint(NaN, NaN)
53
+ const INVALID_CIRCLE = new PGCircle(NaN, NaN, NaN)
54
+
55
+ /* ========================================================================== *
56
+ * PARSERS *
57
+ * ========================================================================== */
58
+
59
+ /** Parse a PostgreSQL `point` */
60
+ export const parsePoint: PGParser<PGPoint> = (value: string): PGPoint => {
61
+ if (value[0] !== '(') return INVALID_POINT
62
+
63
+ const values = value.substring(1, value.length - 1).split(',')
64
+
65
+ return new PGPoint(parseFloat(values[0]!), parseFloat(values[1]!))
66
+ }
67
+
68
+ /** Parse a PostgreSQL `circle` */
69
+ export const parseCircle: PGParser<PGCircle> = (value: string): PGCircle => {
70
+ if (value[0] !== '<' && value[1] !== '(') return INVALID_CIRCLE
71
+
72
+ let point = '('
73
+ let radius = ''
74
+ let pointParsed = false
75
+ for (let i = 2; i < value.length - 1; i++) {
76
+ if (!pointParsed) {
77
+ point += value[i]
78
+ }
79
+
80
+ if (value[i] === ')') {
81
+ pointParsed = true
82
+ continue
83
+ } else if (!pointParsed) {
84
+ continue
85
+ }
86
+
87
+ if (value[i] === ',') {
88
+ continue
89
+ }
90
+
91
+ radius += value[i]
92
+ }
93
+
94
+ const { x, y } = parsePoint(point)
95
+ return new PGCircle(x, y, parseFloat(radius))
96
+ }
@@ -0,0 +1,40 @@
1
+ import postgresInterval from 'postgres-interval'
2
+
3
+ import type { PGParser } from '../parsers'
4
+ import type { PGSerializable } from '../serializers'
5
+
6
+ /** A parsed PostgreSQL `interval` */
7
+ export interface PGInterval extends PGSerializable {
8
+ years: number;
9
+ months: number;
10
+ days: number;
11
+ hours: number;
12
+ minutes: number;
13
+ seconds: number;
14
+ milliseconds: number;
15
+
16
+ toISO(): string;
17
+ toISOString(): string;
18
+ toISOStringShort(): string;
19
+ }
20
+
21
+ /** Constructor for {@link PGInterval} */
22
+ export interface PGIntervalConstructor {
23
+ new (value: string): PGInterval
24
+ }
25
+
26
+ // The "postgres-interval" code exports a function, not a class, but still
27
+ // declares all its prototype and whatnot in there... Types are wrong!
28
+ const PostgresInterval: PGIntervalConstructor = postgresInterval as any
29
+
30
+ /** A parsed PostgreSQL `interval` */
31
+ export const PGInterval: PGIntervalConstructor = class PGIntervalImpl
32
+ extends PostgresInterval
33
+ implements PGInterval {
34
+ constructor(value: string) {
35
+ super(value)
36
+ }
37
+ }
38
+
39
+ /** Parse a PostgreSQL `interval` */
40
+ export const parseInterval: PGParser<PGInterval> = (value: string) => new PGInterval(value)
@@ -0,0 +1,128 @@
1
+ import postgresRange from 'postgres-range'
2
+
3
+ import { parseArray } from './array'
4
+ import { parseBigint, parseString, parseTimestamp, parseTimestampTz } from './basic'
5
+
6
+ import type { PGParser } from '../parsers'
7
+ import type { PGSerializable, PGSerialize } from '../serializers'
8
+ import type { PGArray } from './array'
9
+
10
+ /* ========================================================================== *
11
+ * PGRANGE TYPE *
12
+ * ========================================================================== */
13
+
14
+ /** A parsed PostgreSQL `range` */
15
+ export interface PGRange<T> {
16
+ readonly lower: T | null
17
+ readonly upper: T | null
18
+ readonly mask: number
19
+
20
+ hasMask(flags: number): boolean
21
+ isBounded(): boolean
22
+ isEmpty(): boolean
23
+ isLowerBoundClosed(): boolean
24
+ isUpperBoundClosed(): boolean
25
+ hasLowerBound(): boolean
26
+ hasUpperBound(): boolean
27
+
28
+ containsPoint(point: T): boolean
29
+ containsRange(range: PGRange<T>): boolean
30
+ }
31
+
32
+ /** Constructor (with static constants) for {@link PGRange} */
33
+ export interface PGRangeConstructor {
34
+ new <T>(lower: T | null, upper: T | null, flags: number): PGRange<T>
35
+
36
+ readonly RANGE_EMPTY: number
37
+ readonly RANGE_LB_INC: number
38
+ readonly RANGE_UB_INC: number
39
+ readonly RANGE_LB_INF: number
40
+ readonly RANGE_UB_INF: number
41
+ }
42
+
43
+ /** A parsed PostgreSQL `range` */
44
+ export const PGRange: PGRangeConstructor = class PGRangeImpl<T>
45
+ extends postgresRange.Range<T>
46
+ implements PGRange<T>, PGSerializable {
47
+ readonly mask: number
48
+
49
+ constructor(lower: T | null, upper: T | null, flags: number) {
50
+ super(lower, upper, flags)
51
+ this.mask = flags
52
+ }
53
+
54
+ toPostgres(serialize: PGSerialize): string {
55
+ return postgresRange.serialize(this, serialize)
56
+ }
57
+
58
+ static readonly RANGE_EMPTY = postgresRange.RANGE_EMPTY
59
+ static readonly RANGE_LB_INC = postgresRange.RANGE_LB_INC
60
+ static readonly RANGE_UB_INC = postgresRange.RANGE_UB_INC
61
+ static readonly RANGE_LB_INF = postgresRange.RANGE_LB_INF
62
+ static readonly RANGE_UB_INF = postgresRange.RANGE_UB_INF
63
+ }
64
+
65
+ /* ========================================================================== *
66
+ * PARSERS *
67
+ * ========================================================================== */
68
+
69
+ /** Parse a PostgreSQL `range` */
70
+ export function parseRange(value: string): PGRange<string>
71
+ /** Parse a PostgreSQL `range` */
72
+ export function parseRange<T>(value: string, parser: PGParser<T>): PGRange<T>
73
+ /* Overloaded implementation */
74
+ export function parseRange(
75
+ value: string,
76
+ parser: PGParser<any> = parseString,
77
+ ): PGRange<any> {
78
+ const range = postgresRange.parse(value, parser)
79
+ return new PGRange(range.lower, range.upper, (range as any).mask)
80
+ }
81
+
82
+ /* ===== SPECIALIZED TYPES ================================================== */
83
+
84
+ /** Parse a PostgreSQL `range` of _integers_ */
85
+ export const parseIntRange: PGParser<PGRange<number>> =
86
+ (value: string) => parseRange(value, parseInt)
87
+
88
+ /** Parse a PostgreSQL `range` of _floats_ */
89
+ export const parseFloatRange: PGParser<PGRange<number>> =
90
+ (value: string) => parseRange(value, parseFloat)
91
+
92
+ /** Parse a PostgreSQL `range` of _big integers_ */
93
+ export const parseBigintRange: PGParser<PGRange<bigint>> =
94
+ (value: string) => parseRange(value, parseBigint)
95
+
96
+ /** Parse a PostgreSQL `range` of _timestamps_ */
97
+ export const parseTimestampRange: PGParser<PGRange<Date>> =
98
+ (value: string) => parseRange(value, parseTimestamp)
99
+
100
+ /** Parse a PostgreSQL `range` of _timestamps with time zone_ */
101
+ export const parseTimestampTzRange: PGParser<PGRange<Date>> =
102
+ (value: string) => parseRange(value, parseTimestampTz)
103
+
104
+ /* ===== ARRAYS OF RANGES =================================================== */
105
+
106
+ /** Parse an array of PostgreSQL `range` of _strings_ */
107
+ export const parseRangeArray: PGParser<PGArray<PGRange<string>>> =
108
+ (value: string) => parseArray<PGRange<string>>(value, parseRange)
109
+
110
+ /** Parse an array of PostgreSQL `range` of _integers_ */
111
+ export const parseIntRangeArray: PGParser<PGArray<PGRange<number>>> =
112
+ (value: string) => parseArray(value, parseIntRange)
113
+
114
+ /** Parse an array of PostgreSQL `range` of _floats_ */
115
+ export const parseFloatRangeArray: PGParser<PGArray<PGRange<number>>> =
116
+ (value: string) => parseArray(value, parseFloatRange)
117
+
118
+ /** Parse an array of PostgreSQL `range` of _big integers_ */
119
+ export const parseBigintRangeArray: PGParser<PGArray<PGRange<bigint>>> =
120
+ (value: string) => parseArray(value, parseBigintRange)
121
+
122
+ /** Parse an array of PostgreSQL `range` of _timestamps_ */
123
+ export const parseTimestampRangeArray: PGParser<PGArray<PGRange<Date>>> =
124
+ (value: string) => parseArray(value, parseTimestampRange)
125
+
126
+ /** Parse an array of PostgreSQL `range` of _timestamps with time zone_ */
127
+ export const parseTimestampTzRangeArray: PGParser<PGArray<PGRange<Date>>> =
128
+ (value: string) => parseArray(value, parseTimestampTzRange)
package/src/parsers.ts ADDED
@@ -0,0 +1,57 @@
1
+ /* eslint-disable comma-dangle */
2
+
3
+ /** A function parsing a `string` returned from PostgreSQL */
4
+ export type PGParser<T = string> = (value: string) => T
5
+
6
+ export {
7
+ parseArray,
8
+ parseBigintArray,
9
+ parseBoolArray,
10
+ parseByteAArray,
11
+ parseCircleArray,
12
+ parseFloatArray,
13
+ parseIntArray,
14
+ parseIntervalArray,
15
+ parseJsonArray,
16
+ parsePointArray,
17
+ parseTimestampArray,
18
+ parseTimestampTzArray
19
+ } from './parsers/array'
20
+
21
+ export {
22
+ parseBigint,
23
+ parseBool,
24
+ parseJson,
25
+ parseString,
26
+ parseTimestamp,
27
+ parseTimestampTz,
28
+ parseVoid
29
+ } from './parsers/basic'
30
+
31
+ export {
32
+ parseByteA
33
+ } from './parsers/bytea'
34
+
35
+ export {
36
+ parseCircle,
37
+ parsePoint
38
+ } from './parsers/geometric'
39
+
40
+ export {
41
+ parseInterval
42
+ } from './parsers/interval'
43
+
44
+ export {
45
+ parseBigintRange,
46
+ parseBigintRangeArray,
47
+ parseFloatRange,
48
+ parseFloatRangeArray,
49
+ parseIntRange,
50
+ parseIntRangeArray,
51
+ parseRange,
52
+ parseRangeArray,
53
+ parseTimestampRange,
54
+ parseTimestampRangeArray,
55
+ parseTimestampTzRange,
56
+ parseTimestampTzRangeArray
57
+ } from './parsers/range'
@@ -0,0 +1,168 @@
1
+ import { PGOIDs } from './oids'
2
+ import {
3
+ parseArray,
4
+ parseBigint,
5
+ parseBigintArray,
6
+ parseBigintRange,
7
+ parseBigintRangeArray,
8
+ parseBool,
9
+ parseBoolArray,
10
+ parseByteA,
11
+ parseByteAArray,
12
+ parseCircle,
13
+ parseCircleArray,
14
+ parseFloatArray,
15
+ parseFloatRange,
16
+ parseFloatRangeArray,
17
+ parseIntArray,
18
+ parseIntRange,
19
+ parseIntRangeArray,
20
+ parseInterval,
21
+ parseIntervalArray,
22
+ parseJson,
23
+ parseJsonArray,
24
+ parsePoint,
25
+ parsePointArray,
26
+ parseRange,
27
+ parseRangeArray,
28
+ parseString,
29
+ parseTimestamp,
30
+ parseTimestampArray,
31
+ parseTimestampRange,
32
+ parseTimestampRangeArray,
33
+ parseTimestampTz,
34
+ parseTimestampTzArray,
35
+ parseTimestampTzRange,
36
+ parseTimestampTzRangeArray,
37
+ parseVoid,
38
+ } from './parsers'
39
+
40
+ import type { PGParser } from './parsers'
41
+
42
+ export interface Registry {
43
+ deregisterParser(oid: number): this
44
+ registerParser(oid: number, parser: PGParser<any>): this
45
+
46
+ getParser(oid: number): PGParser<any>
47
+ }
48
+
49
+ const oidParsers = {
50
+ /* Basic known types |_oid__|_typname______| */
51
+ [PGOIDs.bool]: parseBool, /* | 16 | bool | */
52
+ [PGOIDs.bytea]: parseByteA, /* | 17 | bytea | */
53
+ [PGOIDs.int8]: parseBigint, /* | 20 | int8 | */
54
+ [PGOIDs.int2]: parseInt, /* | 21 | int2 | */
55
+ [PGOIDs.int4]: parseInt, /* | 23 | int4 | */
56
+ [PGOIDs.oid]: parseInt, /* | 26 | oid | */
57
+ [PGOIDs.json]: parseJson, /* | 114 | json | */
58
+ [PGOIDs.point]: parsePoint, /* | 600 | point | */
59
+ [PGOIDs.float4]: parseFloat, /* | 700 | float4 | */
60
+ [PGOIDs.float8]: parseFloat, /* | 701 | float8 | */
61
+ [PGOIDs.circle]: parseCircle, /* | 718 | circle | */
62
+ [PGOIDs.varchar]: parseString, /* | 1043 | varchar | */
63
+ [PGOIDs.timestamp]: parseTimestamp, /* | 1114 | timestamp | */
64
+ [PGOIDs.timestamptz]: parseTimestampTz, /* | 1184 | timestamptz | */
65
+ [PGOIDs.interval]: parseInterval, /* | 1186 | interval | */
66
+ [PGOIDs.numeric]: parseString, /* | 1700 | numeric | */
67
+ [PGOIDs.jsonb]: parseJson, /* | 3802 | jsonb | */
68
+
69
+ /* Special types |_oid__|_typname______| */
70
+ [PGOIDs.void]: parseVoid, /* | 2278 | void | */
71
+ [PGOIDs.xid]: parseInt, /* | 28 | xid | */
72
+ [PGOIDs.xid8]: parseBigint, /* | 5069 | xid8 | */
73
+ [PGOIDs._xid]: parseIntArray, /* | 1011 | _xid | */
74
+ [PGOIDs._xid8]: parseBigintArray, /* | 271 | _xid8 | */
75
+
76
+ /* Native array types of the above |_oid__|_typname______| */
77
+ [PGOIDs._bool]: parseBoolArray, /* | 1000 | _bool | */
78
+ [PGOIDs._bytea]: parseByteAArray, /* | 1001 | _bytea | */
79
+ [PGOIDs._int8]: parseBigintArray, /* | 1016 | _int8 | */
80
+ [PGOIDs._int2]: parseIntArray, /* | 1005 | _int2 | */
81
+ [PGOIDs._int4]: parseIntArray, /* | 1007 | _int4 | */
82
+ [PGOIDs._oid]: parseIntArray, /* | 1028 | _oid | */
83
+ [PGOIDs._json]: parseJsonArray, /* | 199 | _json | */
84
+ [PGOIDs._point]: parsePointArray, /* | 1017 | _point | */
85
+ [PGOIDs._float4]: parseFloatArray, /* | 1021 | _float4 | */
86
+ [PGOIDs._float8]: parseFloatArray, /* | 1022 | _float8 | */
87
+ [PGOIDs._circle]: parseCircleArray, /* | 719 | _circle | */
88
+ [PGOIDs._timestamp]: parseTimestampArray, /* | 1115 | _timestamp | */
89
+ [PGOIDs._timestamptz]: parseTimestampTzArray, /* | 1185 | _timestamptz | */
90
+ [PGOIDs._interval]: parseIntervalArray, /* | 1187 | _interval | */
91
+ [PGOIDs._numeric]: parseArray, /* | 1231 | _numeric | */
92
+ [PGOIDs._jsonb]: parseJsonArray, /* | 3807 | _jsonb | */
93
+
94
+ /* Other known array types |_oid__|_typname______| */
95
+ [PGOIDs._cidr]: parseArray, /* | 651 | _cidr | */
96
+ [PGOIDs._money]: parseArray, /* | 791 | _money | */
97
+ [PGOIDs._regproc]: parseArray, /* | 1008 | _regproc | */
98
+ [PGOIDs._text]: parseArray, /* | 1009 | _text | */
99
+ [PGOIDs._bpchar]: parseArray, /* | 1014 | _bpchar | */
100
+ [PGOIDs._varchar]: parseArray, /* | 1015 | _varchar | */
101
+ [PGOIDs._macaddr]: parseArray, /* | 1040 | _macaddr | */
102
+ [PGOIDs._inet]: parseArray, /* | 1041 | _inet | */
103
+ [PGOIDs._date]: parseArray, /* | 1182 | _date | */
104
+ [PGOIDs._time]: parseArray, /* | 1183 | _time | */
105
+ [PGOIDs._timetz]: parseArray, /* | 1270 | _timetz | */
106
+ [PGOIDs._uuid]: parseArray, /* | 2951 | _uuid | */
107
+
108
+ /* Range types |_oid__|_typname______| */
109
+ [PGOIDs.int4range]: parseIntRange, /* | 3904 | int4range | */
110
+ [PGOIDs.numrange]: parseFloatRange, /* | 3906 | numrange | */
111
+ [PGOIDs.tsrange]: parseTimestampRange, /* | 3908 | tsrange | */
112
+ [PGOIDs.tstzrange]: parseTimestampTzRange, /* | 3910 | tstzrange | */
113
+ [PGOIDs.daterange]: parseRange, /* | 3912 | daterange | */
114
+ [PGOIDs.int8range]: parseBigintRange, /* | 3926 | int8range | */
115
+
116
+ /* Array of range types |_oid__|_typname______| */
117
+ [PGOIDs._int4range]: parseIntRangeArray, /* | 3905 | _int4range | */
118
+ [PGOIDs._numrange]: parseFloatRangeArray, /* | 3907 | _numrange | */
119
+ [PGOIDs._tsrange]: parseTimestampRangeArray, /* | 3909 | _tsrange | */
120
+ [PGOIDs._tstzrange]: parseTimestampTzRangeArray, /* | 3911 | _tstzrange | */
121
+ [PGOIDs._daterange]: parseRangeArray, /* | 3913 | _daterange | */
122
+ [PGOIDs._int8range]: parseBigintRangeArray, /* | 3927 | _int8range | */
123
+ } satisfies Record<PGOIDs[keyof PGOIDs], PGParser<any>>
124
+
125
+ export type RegistryTypes = {
126
+ [ key in keyof typeof oidParsers ] :
127
+ typeof oidParsers[key] extends PGParser<infer T> ? T : never
128
+ }
129
+
130
+ const defaultParsers: Record<number, PGParser<any>> = { ...oidParsers }
131
+
132
+ class RegistryImpl implements Registry {
133
+ private _parsers: Record<number, PGParser<any>>
134
+
135
+ constructor() {
136
+ this._parsers = { ...oidParsers }
137
+ }
138
+
139
+ deregisterParser(oid: number): this {
140
+ delete this._parsers[oid]
141
+ return this
142
+ }
143
+
144
+ registerParser(oid: number, parser: PGParser<any>): this {
145
+ this._parsers[oid] = parser
146
+ return this
147
+ }
148
+
149
+ getParser(oid: number): PGParser<any> {
150
+ return this._parsers[oid] || defaultParsers[oid] || parseString
151
+ }
152
+
153
+ static deregisterDefaultParser(oid: number): void {
154
+ delete defaultParsers[oid]
155
+ }
156
+
157
+ static registerDefaultParser(oid: number, parser: PGParser<any>): void {
158
+ defaultParsers[oid] = parser
159
+ }
160
+ }
161
+
162
+ export interface RegistryConstructor {
163
+ new (): Registry,
164
+ deregisterDefaultParser(oid: number): void
165
+ registerDefaultParser(oid: number, parser: PGParser<any>): void
166
+ }
167
+
168
+ export const Registry: RegistryConstructor = RegistryImpl
@@ -0,0 +1,67 @@
1
+ /* ========================================================================== *
2
+ * INTERNALS *
3
+ * ========================================================================== */
4
+
5
+ /* Internal interface mimicking NodeJS's `Buffer` */
6
+ interface NodeJSBuffer extends Uint8Array {
7
+ toString(format?: 'hex'): string
8
+ }
9
+
10
+ /* Internal interface mimicking NodeJS's `Buffer`'s constructor */
11
+ interface NodeJSBufferConstructor {
12
+ isBuffer(value: any): value is NodeJSBuffer
13
+ from(source:Uint8Array): NodeJSBuffer
14
+ }
15
+
16
+ /* Return a {@link Uint8Array} from an {@link ArrayBufferView} */
17
+ function getUint8Array(value: any): Uint8Array {
18
+ if (value instanceof Uint8Array) return value
19
+ if (ArrayBuffer.isView(value)) {
20
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength)
21
+ }
22
+
23
+ throw new TypeError('Unsupported type for serialization as BYTEA')
24
+ }
25
+
26
+ /** All HEX values (from "00" to "ff" in order) */
27
+ const hex = '0123456789abcdef'.split('') // [ '0', '1', '2', ... ]
28
+ .map((c1, _, a) => a.map((c2) => `${c1}${c2}`)) // [ [ '00', '01', ...], ...]
29
+ .flat() // [ '00', '01', '02', ... ]
30
+
31
+ /* ========================================================================== *
32
+ * EXPORTED SERIALIZER *
33
+ * ========================================================================== */
34
+
35
+ /**
36
+ * Serialize an {@link ArrayBufferView} (e.g. an {@link Uint8Array}, a NodeJS
37
+ * `Buffer`, ...) into a PostgreSQL _HEX-encoded_ `string` (e.g. `\\xdeadbeef`).
38
+ */
39
+ export function serializeByteA(
40
+ value: ArrayBufferView,
41
+ Buffer?: NodeJSBufferConstructor | null | undefined,
42
+ ): string
43
+ /* Overload */
44
+ export function serializeByteA(
45
+ value: any, // we need _any_ for type guards to work properly
46
+ Buffer: NodeJSBufferConstructor | null | undefined = (globalThis as any).Buffer,
47
+ ): string {
48
+ /* In NodeJS we can use some shortcuts with buffers */
49
+ if (Buffer) {
50
+ /* Get a NodeJS buffer, either the value itself or wrapping a Uint8Array */
51
+ const buffer = Buffer.isBuffer(value) ? value : Buffer.from(getUint8Array(value))
52
+ return `\\x${buffer.toString('hex')}`
53
+ }
54
+
55
+ /* No support for NodeJS "Buffer"... Gotta do manually */
56
+ const array = getUint8Array(value)
57
+ const result = new Array<string>(array.length + 1)
58
+ result[0] = '\\x'
59
+
60
+ /* Run a tight loop over our Uint8Array, converting it to HEX */
61
+ for (let i = 0, c = array[0]!; i < array.length; c = array[i]!) {
62
+ result[++i] = hex[c]!
63
+ }
64
+
65
+ /* Join up and return */
66
+ return result.join('')
67
+ }