@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.
- package/README.md +14 -0
- package/dist/index.cjs +48 -0
- package/dist/index.cjs.map +6 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.mjs +15 -0
- package/dist/index.mjs.map +6 -0
- package/dist/oids.cjs +163 -0
- package/dist/oids.cjs.map +6 -0
- package/dist/oids.d.ts +74 -0
- package/dist/oids.mjs +138 -0
- package/dist/oids.mjs.map +6 -0
- package/dist/parsers/array.cjs +140 -0
- package/dist/parsers/array.cjs.map +6 -0
- package/dist/parsers/array.d.ts +31 -0
- package/dist/parsers/array.mjs +111 -0
- package/dist/parsers/array.mjs.map +6 -0
- package/dist/parsers/basic.cjs +69 -0
- package/dist/parsers/basic.cjs.map +6 -0
- package/dist/parsers/basic.d.ts +15 -0
- package/dist/parsers/basic.mjs +28 -0
- package/dist/parsers/basic.mjs.map +6 -0
- package/dist/parsers/bytea.cjs +68 -0
- package/dist/parsers/bytea.cjs.map +6 -0
- package/dist/parsers/bytea.d.ts +7 -0
- package/dist/parsers/bytea.mjs +43 -0
- package/dist/parsers/bytea.mjs.map +6 -0
- package/dist/parsers/geometric.cjs +86 -0
- package/dist/parsers/geometric.cjs.map +6 -0
- package/dist/parsers/geometric.d.ts +27 -0
- package/dist/parsers/geometric.mjs +58 -0
- package/dist/parsers/geometric.mjs.map +6 -0
- package/dist/parsers/interval.cjs +50 -0
- package/dist/parsers/interval.cjs.map +6 -0
- package/dist/parsers/interval.d.ts +23 -0
- package/dist/parsers/interval.mjs +14 -0
- package/dist/parsers/interval.mjs.map +6 -0
- package/dist/parsers/range.cjs +97 -0
- package/dist/parsers/range.cjs.map +6 -0
- package/dist/parsers/range.d.ts +54 -0
- package/dist/parsers/range.mjs +50 -0
- package/dist/parsers/range.mjs.map +6 -0
- package/dist/parsers.cjs +104 -0
- package/dist/parsers.cjs.map +6 -0
- package/dist/parsers.d.ts +8 -0
- package/dist/parsers.mjs +86 -0
- package/dist/parsers.mjs.map +6 -0
- package/dist/registry.cjs +189 -0
- package/dist/registry.cjs.map +6 -0
- package/dist/registry.d.ts +81 -0
- package/dist/registry.mjs +200 -0
- package/dist/registry.mjs.map +6 -0
- package/dist/serializers/bytea.cjs +52 -0
- package/dist/serializers/bytea.cjs.map +6 -0
- package/dist/serializers/bytea.d.ts +13 -0
- package/dist/serializers/bytea.mjs +27 -0
- package/dist/serializers/bytea.mjs.map +6 -0
- package/dist/serializers/date.cjs +46 -0
- package/dist/serializers/date.cjs.map +6 -0
- package/dist/serializers/date.d.ts +2 -0
- package/dist/serializers/date.mjs +21 -0
- package/dist/serializers/date.mjs.map +6 -0
- package/dist/serializers.cjs +119 -0
- package/dist/serializers.cjs.map +6 -0
- package/dist/serializers.d.ts +20 -0
- package/dist/serializers.mjs +92 -0
- package/dist/serializers.mjs.map +6 -0
- package/package.json +49 -0
- package/src/index.ts +13 -0
- package/src/oids.ts +90 -0
- package/src/parsers/array.ts +176 -0
- package/src/parsers/basic.ts +55 -0
- package/src/parsers/bytea.ts +77 -0
- package/src/parsers/geometric.ts +96 -0
- package/src/parsers/interval.ts +40 -0
- package/src/parsers/range.ts +128 -0
- package/src/parsers.ts +57 -0
- package/src/registry.ts +168 -0
- package/src/serializers/bytea.ts +67 -0
- package/src/serializers/date.ts +63 -0
- 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'
|
package/src/registry.ts
ADDED
|
@@ -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
|
+
}
|