-
Notifications
You must be signed in to change notification settings - Fork 94
/
Copy pathdecode.ts
260 lines (250 loc) · 7.11 KB
/
decode.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
import { bold, yellow } from "@std/fmt/colors";
import type { OidType, OidValue } from "./oid.ts";
import { Oid, OidTypes } from "./oid.ts";
import {
decodeBigint,
decodeBigintArray,
decodeBoolean,
decodeBooleanArray,
decodeBox,
decodeBoxArray,
decodeBytea,
decodeByteaArray,
decodeCircle,
decodeCircleArray,
decodeDate,
decodeDateArray,
decodeDatetime,
decodeDatetimeArray,
decodeFloat,
decodeFloatArray,
decodeInt,
decodeIntArray,
decodeJson,
decodeJsonArray,
decodeLine,
decodeLineArray,
decodeLineSegment,
decodeLineSegmentArray,
decodePath,
decodePathArray,
decodePoint,
decodePointArray,
decodePolygon,
decodePolygonArray,
decodeStringArray,
decodeTid,
decodeTidArray,
} from "./decoders.ts";
import type { ClientControls } from "../connection/connection_params.ts";
import { parseArray } from "./array_parser.ts";
export class Column {
constructor(
public name: string,
public tableOid: number,
public index: number,
public typeOid: number,
public columnLength: number,
public typeModifier: number,
public format: Format,
) {}
}
enum Format {
TEXT = 0,
BINARY = 1,
}
const decoder = new TextDecoder();
// TODO
// Decode binary fields
function decodeBinary() {
throw new Error("Decoding binary data is not implemented!");
}
function decodeText(value: string, typeOid: number) {
try {
switch (typeOid) {
case Oid.bpchar:
case Oid.char:
case Oid.cidr:
case Oid.float8:
case Oid.inet:
case Oid.macaddr:
case Oid.name:
case Oid.numeric:
case Oid.oid:
case Oid.regclass:
case Oid.regconfig:
case Oid.regdictionary:
case Oid.regnamespace:
case Oid.regoper:
case Oid.regoperator:
case Oid.regproc:
case Oid.regprocedure:
case Oid.regrole:
case Oid.regtype:
case Oid.text:
case Oid.time:
case Oid.timetz:
case Oid.uuid:
case Oid.varchar:
case Oid.void:
return value;
case Oid.bpchar_array:
case Oid.char_array:
case Oid.cidr_array:
case Oid.float8_array:
case Oid.inet_array:
case Oid.macaddr_array:
case Oid.name_array:
case Oid.numeric_array:
case Oid.oid_array:
case Oid.regclass_array:
case Oid.regconfig_array:
case Oid.regdictionary_array:
case Oid.regnamespace_array:
case Oid.regoper_array:
case Oid.regoperator_array:
case Oid.regproc_array:
case Oid.regprocedure_array:
case Oid.regrole_array:
case Oid.regtype_array:
case Oid.text_array:
case Oid.time_array:
case Oid.timetz_array:
case Oid.uuid_array:
case Oid.varchar_array:
return decodeStringArray(value);
case Oid.float4:
return decodeFloat(value);
case Oid.float4_array:
return decodeFloatArray(value);
case Oid.int2:
case Oid.int4:
case Oid.xid:
return decodeInt(value);
case Oid.int2_array:
case Oid.int4_array:
case Oid.xid_array:
return decodeIntArray(value);
case Oid.bool:
return decodeBoolean(value);
case Oid.bool_array:
return decodeBooleanArray(value);
case Oid.box:
return decodeBox(value);
case Oid.box_array:
return decodeBoxArray(value);
case Oid.circle:
return decodeCircle(value);
case Oid.circle_array:
return decodeCircleArray(value);
case Oid.bytea:
return decodeBytea(value);
case Oid.byte_array:
return decodeByteaArray(value);
case Oid.date:
return decodeDate(value);
case Oid.date_array:
return decodeDateArray(value);
case Oid.int8:
return decodeBigint(value);
case Oid.int8_array:
return decodeBigintArray(value);
case Oid.json:
case Oid.jsonb:
return decodeJson(value);
case Oid.json_array:
case Oid.jsonb_array:
return decodeJsonArray(value);
case Oid.line:
return decodeLine(value);
case Oid.line_array:
return decodeLineArray(value);
case Oid.lseg:
return decodeLineSegment(value);
case Oid.lseg_array:
return decodeLineSegmentArray(value);
case Oid.path:
return decodePath(value);
case Oid.path_array:
return decodePathArray(value);
case Oid.point:
return decodePoint(value);
case Oid.point_array:
return decodePointArray(value);
case Oid.polygon:
return decodePolygon(value);
case Oid.polygon_array:
return decodePolygonArray(value);
case Oid.tid:
return decodeTid(value);
case Oid.tid_array:
return decodeTidArray(value);
case Oid.timestamp:
case Oid.timestamptz:
return decodeDatetime(value);
case Oid.timestamp_array:
case Oid.timestamptz_array:
return decodeDatetimeArray(value);
default:
// A separate category for not handled values
// They might or might not be represented correctly as strings,
// returning them to the user as raw strings allows them to parse
// them as they see fit
return value;
}
} catch (_e) {
console.error(
`${
bold(yellow(`Error decoding type Oid ${typeOid} value`))
}${_e.message}\n${bold("Defaulting to null.")}`,
);
// If an error occurred during decoding, return null
return null;
}
}
export function decode(
value: Uint8Array,
column: Column,
controls?: ClientControls,
) {
const strValue = decoder.decode(value);
// check if there is a custom decoder
if (controls?.decoders) {
const oidType = OidTypes[column.typeOid as OidValue];
// check if there is a custom decoder by oid (number) or by type name (string)
const decoderFunc = controls.decoders?.[column.typeOid] ||
controls.decoders?.[oidType];
if (decoderFunc) {
return decoderFunc(strValue, column.typeOid, parseArray);
}
// if no custom decoder is found and the oid is for an array type, check if there is
// a decoder for the base type and use that with the array parser
if (oidType?.includes("_array")) {
const baseOidType = oidType.replace("_array", "") as OidType;
// check if the base type is in the Oid object
if (baseOidType in Oid) {
// check if there is a custom decoder for the base type by oid (number) or by type name (string)
const decoderFunc = controls.decoders?.[Oid[baseOidType]] ||
controls.decoders?.[baseOidType];
if (decoderFunc) {
return parseArray(
strValue,
(value: string) => decoderFunc(value, column.typeOid, parseArray),
);
}
}
}
}
// check if the decode strategy is `string`
if (controls?.decodeStrategy === "string") {
return strValue;
}
// else, default to 'auto' mode, which uses the typeOid to determine the decoding strategy
if (column.format === Format.BINARY) {
return decodeBinary();
}
if (column.format === Format.TEXT) {
return decodeText(strValue, column.typeOid);
}
throw new Error(`Unknown column format: ${column.format}`);
}