@m2k-5f/pgtx 2.8.0 → 2.8.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.
- package/dist/connection.d.ts +4 -1
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +71 -75
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +39 -9
- package/dist/protocol/types.d.ts +5 -1
- package/dist/protocol/types.d.ts.map +1 -1
- package/dist/protocol/types.js +90 -0
- package/package.json +1 -1
package/dist/connection.d.ts
CHANGED
|
@@ -17,7 +17,6 @@ export declare class Connection {
|
|
|
17
17
|
private _writer;
|
|
18
18
|
private _sheduled;
|
|
19
19
|
private _queue;
|
|
20
|
-
private _executingCounter;
|
|
21
20
|
private _closing;
|
|
22
21
|
private _closed;
|
|
23
22
|
private _reconnecting;
|
|
@@ -27,6 +26,9 @@ export declare class Connection {
|
|
|
27
26
|
private _listeningCallbacks;
|
|
28
27
|
private _stmtCounter;
|
|
29
28
|
private _nextStatement;
|
|
29
|
+
private _logError;
|
|
30
|
+
private _logQuery;
|
|
31
|
+
private _logNotice;
|
|
30
32
|
private _registerShedule;
|
|
31
33
|
private _shedule;
|
|
32
34
|
private _registerQuery;
|
|
@@ -86,6 +88,7 @@ export declare class Connection {
|
|
|
86
88
|
get isOpened(): boolean;
|
|
87
89
|
/** Whether the connection is closed or closing. */
|
|
88
90
|
get isClosed(): boolean;
|
|
91
|
+
private _tryFinishClosing;
|
|
89
92
|
/**
|
|
90
93
|
* Closes the connection, awaiting for all pending queries. Not usable afterward.
|
|
91
94
|
*/
|
package/dist/connection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiC,uBAAuB,EAAuC,GAAG,EAAiB,MAAM,SAAS,CAAA;AACzI,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAK3C,OAAO,EAAS,MAAM,EAAM,MAAM,eAAe,CAAA;AACjD,OAAO,EAAkD,aAAa,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiC,uBAAuB,EAAuC,GAAG,EAAiB,MAAM,SAAS,CAAA;AACzI,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAK3C,OAAO,EAAS,MAAM,EAAM,MAAM,eAAe,CAAA;AACjD,OAAO,EAAkD,aAAa,EAAE,MAAM,SAAS,CAAA;AAgBvF;;;;;;;;;GASG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IAEzC,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,MAAM,CAA6B;IAE3C,OAAO,CAAC,QAAQ,CAAsD;IACtE,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,aAAa,CAA2C;IAEhE,OAAO,CAAC,OAAO,CAAiB;IAEhC,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,QAAQ,CAA6D;IAE7E,OAAO,CAAC,mBAAmB,CAAyD;IACpF,OAAO,CAAC,YAAY,CAAI;IAExB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,cAAc;IA6BtB,OAAO;IAYP;;;OAGG;IACH,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,uBAAuB;IAkB1C;;;;;;OAMG;IACH,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAatE,OAAO,CAAC,aAAa;IAmDrB;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAazD,OAAO,CAAC,eAAe;IAmDvB;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IA2BvE,OAAO,CAAC,cAAc;IAwDtB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;IAoB7D,2EAA2E;IAC3E,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW;IAOhD,sFAAsF;IACtF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;IAe/D,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC;IAoB/F,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,qBAAqB;IAW7B,OAAO,KAAK,aAAa,GAExB;IAGD,OAAO,CAAC,aAAa;IA4GrB,kDAAkD;IAClD,IAAI,QAAQ,YAEX;IAGD,mDAAmD;IACnD,IAAI,QAAQ,YAEX;IAGD,OAAO,CAAC,iBAAiB;IAczB;;OAEG;IACH,KAAK;CAoBR"}
|
package/dist/connection.js
CHANGED
|
@@ -29,6 +29,28 @@ export class Connection {
|
|
|
29
29
|
_nextStatement() {
|
|
30
30
|
return `s-${this._stmtCounter++}`;
|
|
31
31
|
}
|
|
32
|
+
_logError(error) {
|
|
33
|
+
if (this.config.logLevel === 'error' || this.config.logLevel === 'notice' || this.config.logLevel === 'query') {
|
|
34
|
+
console.log(`\n\x1b[31m┌─ ERROR ────────────────────────────────────────\x1b[0m\n`
|
|
35
|
+
+ `\x1b[31m│\x1b[0m ${error}\n`
|
|
36
|
+
+ `\x1b[31m└────────────────────────────────────────────────\x1b[0m\n`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
_logQuery(text, args) {
|
|
40
|
+
if (this.config.logLevel === 'query') {
|
|
41
|
+
console.log(`\n\x1b[36m┌─ QUERY ─────────────────────────────────────────\x1b[0m\n`
|
|
42
|
+
+ `\x1b[36m│\x1b[0m ${text}\n`
|
|
43
|
+
+ `${args.length !== 0 ? `\x1b[36m│\x1b[0m \x1b[90mArguments:\x1b[0m [${args}]\n` : ''}`
|
|
44
|
+
+ `\x1b[36m└────────────────────────────────────────────────\x1b[0m`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
_logNotice(notice) {
|
|
48
|
+
if (this.config.logLevel === 'notice' || this.config.logLevel === 'query') {
|
|
49
|
+
console.log(`\n\x1b[33m┌─ NOTICE ───────────────────────────────────────\x1b[0m\n`
|
|
50
|
+
+ `\x1b[33m│\x1b[0m ${notice}\n`
|
|
51
|
+
+ `\x1b[33m└────────────────────────────────────────────────\x1b[0m\n`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
32
54
|
_registerShedule() {
|
|
33
55
|
if (!this._sheduled) {
|
|
34
56
|
this._sheduled = true;
|
|
@@ -67,12 +89,11 @@ export class Connection {
|
|
|
67
89
|
this._writer = ConnectionRequestBuffer.new(65536);
|
|
68
90
|
this._sheduled = false;
|
|
69
91
|
this._queue = new Queue();
|
|
70
|
-
this._executingCounter = 0;
|
|
71
92
|
this._closing = null;
|
|
72
93
|
this._closed = false;
|
|
73
94
|
this._reconnecting = null;
|
|
74
|
-
this._parsed =
|
|
75
|
-
this._parsing =
|
|
95
|
+
this._parsed = new Map();
|
|
96
|
+
this._parsing = new Map();
|
|
76
97
|
this._listeningCallbacks = new Map();
|
|
77
98
|
this._stmtCounter = 0;
|
|
78
99
|
this.config = config;
|
|
@@ -113,37 +134,29 @@ export class Connection {
|
|
|
113
134
|
return this._performQuery(text, args, resolvers);
|
|
114
135
|
}
|
|
115
136
|
_performQuery(text, args, resolvers) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
+ `\x1b[36m│\x1b[0m ${text}\n`
|
|
119
|
-
+ `${args.length !== 0 ? `\x1b[36m│\x1b[0m \x1b[90mArguments:\x1b[0m [${args}]\n` : ''}`
|
|
120
|
-
+ `\x1b[36m└────────────────────────────────────────────────\x1b[0m`);
|
|
121
|
-
}
|
|
122
|
-
this._executingCounter++;
|
|
123
|
-
const parsed = this._parsed[text];
|
|
137
|
+
this._logQuery(text, args);
|
|
138
|
+
const parsed = this._parsed.get(text);
|
|
124
139
|
if (parsed) {
|
|
125
140
|
const query = new CollectQuery(parsed, text, args, parsed.columns, resolvers, this.config.queryTimeout);
|
|
126
141
|
const err = this._registerQuery(query);
|
|
127
142
|
if (err) {
|
|
128
|
-
this._executingCounter--;
|
|
129
143
|
query.error(err);
|
|
130
|
-
|
|
144
|
+
this._logError(err);
|
|
131
145
|
}
|
|
132
146
|
return query.resolvers.future;
|
|
133
147
|
}
|
|
134
|
-
if (!this._parsing
|
|
148
|
+
if (!this._parsing.has(text)) {
|
|
135
149
|
const parseQuery = new ParseQuery({ statement: this._nextStatement(), columns: EMPTY_ARRAY, parameters: EMPTY_ARRAY }, text, Future.withResolvers(), this.config.queryTimeout);
|
|
136
150
|
this._registerQuery(parseQuery);
|
|
137
|
-
this._parsing
|
|
151
|
+
this._parsing.set(text, parseQuery.resolvers.future);
|
|
138
152
|
}
|
|
139
|
-
const parsing = this._parsing
|
|
153
|
+
const parsing = this._parsing.get(text);
|
|
140
154
|
return parsing.andThen(meta => {
|
|
141
155
|
const query = new CollectQuery(meta, text, args, meta.columns, resolvers, this.config.queryTimeout);
|
|
142
156
|
const err = this._registerQuery(query);
|
|
143
157
|
if (err) {
|
|
144
|
-
this._executingCounter--;
|
|
145
158
|
query.error(err);
|
|
146
|
-
|
|
159
|
+
this._logError(err);
|
|
147
160
|
}
|
|
148
161
|
return query.resolvers.future;
|
|
149
162
|
});
|
|
@@ -164,37 +177,29 @@ export class Connection {
|
|
|
164
177
|
return this._performExecute(text, args, resolvers);
|
|
165
178
|
}
|
|
166
179
|
_performExecute(text, args, resolvers) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
+ `\x1b[35m│\x1b[0m ${text}\n`
|
|
170
|
-
+ `${args.length !== 0 ? `\x1b[35m│\x1b[0m \x1b[90mArguments:\x1b[0m [${args}]\n` : ''}`
|
|
171
|
-
+ `\x1b[35m└────────────────────────────────────────────────\x1b[0m`);
|
|
172
|
-
}
|
|
173
|
-
this._executingCounter++;
|
|
174
|
-
const parsed = this._parsed[text];
|
|
180
|
+
this._logQuery(text, args);
|
|
181
|
+
const parsed = this._parsed.get(text);
|
|
175
182
|
if (parsed) {
|
|
176
183
|
const query = new ExecuteQuery(parsed, text, args, resolvers, this.config.queryTimeout);
|
|
177
184
|
const err = this._registerQuery(query);
|
|
178
185
|
if (err) {
|
|
179
|
-
this._executingCounter--;
|
|
180
186
|
query.error(err);
|
|
181
|
-
|
|
187
|
+
this._logError(err);
|
|
182
188
|
}
|
|
183
189
|
return query.resolvers.future;
|
|
184
190
|
}
|
|
185
|
-
if (!this._parsing
|
|
191
|
+
if (!this._parsing.has(text)) {
|
|
186
192
|
const parseQuery = new ParseQuery({ statement: this._nextStatement(), columns: EMPTY_ARRAY, parameters: EMPTY_ARRAY }, text, Future.withResolvers(), this.config.queryTimeout);
|
|
187
193
|
this._registerQuery(parseQuery);
|
|
188
|
-
this._parsing
|
|
194
|
+
this._parsing.set(text, parseQuery.resolvers.future);
|
|
189
195
|
}
|
|
190
|
-
const parsing = this._parsing
|
|
196
|
+
const parsing = this._parsing.get(text);
|
|
191
197
|
return parsing.andThen(meta => {
|
|
192
198
|
const query = new ExecuteQuery(meta, text, args, resolvers, this.config.queryTimeout);
|
|
193
199
|
const err = this._registerQuery(query);
|
|
194
200
|
if (err) {
|
|
195
|
-
this._executingCounter--;
|
|
196
201
|
query.error(err);
|
|
197
|
-
|
|
202
|
+
this._logError(err);
|
|
198
203
|
}
|
|
199
204
|
return query.resolvers.future;
|
|
200
205
|
});
|
|
@@ -226,36 +231,30 @@ export class Connection {
|
|
|
226
231
|
return stream;
|
|
227
232
|
}
|
|
228
233
|
_performStream(text, args, controller) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
+ `\x1b[34m│\x1b[0m ${text}\n`
|
|
232
|
-
+ `${args.length !== 0 ? `\x1b[34m│\x1b[0m \x1b[90mArguments:\x1b[0m [${args}]\n` : ''}`
|
|
233
|
-
+ `\x1b[34m└────────────────────────────────────────────────\x1b[0m`);
|
|
234
|
-
}
|
|
235
|
-
this._executingCounter++;
|
|
236
|
-
const parsed = this._parsed[text];
|
|
234
|
+
this._logQuery(text, args);
|
|
235
|
+
const parsed = this._parsed.get(text);
|
|
237
236
|
if (parsed) {
|
|
238
237
|
const query = new StreamQuery(parsed, text, args, controller, parsed.columns, this.config.queryTimeout);
|
|
239
238
|
const err = this._registerQuery(query);
|
|
240
239
|
if (err) {
|
|
241
|
-
this._executingCounter--;
|
|
242
240
|
controller.error(err);
|
|
241
|
+
this._logError(err);
|
|
243
242
|
}
|
|
244
243
|
return;
|
|
245
244
|
}
|
|
246
|
-
if (!this._parsing
|
|
245
|
+
if (!this._parsing.has(text)) {
|
|
247
246
|
const parseQuery = new ParseQuery({ statement: this._nextStatement(), columns: EMPTY_ARRAY, parameters: EMPTY_ARRAY }, text, Future.withResolvers(), this.config.queryTimeout);
|
|
248
247
|
this._registerQuery(parseQuery);
|
|
249
|
-
this._parsing
|
|
248
|
+
this._parsing.set(text, parseQuery.resolvers.future);
|
|
250
249
|
}
|
|
251
|
-
const parsing = this._parsing
|
|
250
|
+
const parsing = this._parsing.get(text);
|
|
252
251
|
parsing
|
|
253
252
|
.tap(meta => {
|
|
254
253
|
const query = new StreamQuery(meta, text, args, controller, null, this.config.queryTimeout);
|
|
255
254
|
const err = this._registerQuery(query);
|
|
256
255
|
if (err) {
|
|
257
|
-
this._executingCounter--;
|
|
258
256
|
controller.error(err);
|
|
257
|
+
this._logError(err);
|
|
259
258
|
}
|
|
260
259
|
})
|
|
261
260
|
.tapErr(err => {
|
|
@@ -337,10 +336,9 @@ export class Connection {
|
|
|
337
336
|
}
|
|
338
337
|
_performReconnect() {
|
|
339
338
|
this._socket.destroy();
|
|
340
|
-
this._parsed
|
|
341
|
-
this._parsing
|
|
339
|
+
this._parsed.clear();
|
|
340
|
+
this._parsing.clear();
|
|
342
341
|
this._sheduled = false;
|
|
343
|
-
this._executingCounter = 0;
|
|
344
342
|
while (this._queue.hasMore) {
|
|
345
343
|
this._queue.shift.error(ErrConnectionReconnecting);
|
|
346
344
|
}
|
|
@@ -382,16 +380,16 @@ export class Connection {
|
|
|
382
380
|
const query = this._currentQuery;
|
|
383
381
|
const columns = reader.readRowDescription();
|
|
384
382
|
query.meta.columns = columns;
|
|
385
|
-
|
|
386
|
-
this._parsed
|
|
383
|
+
this._parsing.delete(query.text);
|
|
384
|
+
this._parsed.set(query.text, query.meta);
|
|
387
385
|
query.complete();
|
|
388
386
|
}
|
|
389
387
|
break;
|
|
390
388
|
case ResponseTypes.NoData:
|
|
391
389
|
{
|
|
392
390
|
const query = this._currentQuery;
|
|
393
|
-
|
|
394
|
-
this._parsed
|
|
391
|
+
this._parsing.delete(query.text);
|
|
392
|
+
this._parsed.set(query.text, query.meta);
|
|
395
393
|
query.complete();
|
|
396
394
|
}
|
|
397
395
|
break;
|
|
@@ -410,40 +408,29 @@ export class Connection {
|
|
|
410
408
|
reader.skipBytes(length);
|
|
411
409
|
const query = this._currentQuery;
|
|
412
410
|
query.complete();
|
|
413
|
-
this._executingCounter--;
|
|
414
411
|
}
|
|
415
412
|
break;
|
|
416
413
|
case ResponseTypes.ErrorResponse:
|
|
417
414
|
{
|
|
418
415
|
const error = reader.readErrorResponse();
|
|
419
|
-
|
|
420
|
-
console.log(`\n\x1b[31m┌─ ERROR ────────────────────────────────────────\x1b[0m\n`
|
|
421
|
-
+ `\x1b[31m│\x1b[0m ${error}\n`
|
|
422
|
-
+ `\x1b[31m└────────────────────────────────────────────────\x1b[0m\n`);
|
|
423
|
-
}
|
|
416
|
+
this._logError(error);
|
|
424
417
|
const query = this._currentQuery;
|
|
425
|
-
if (
|
|
426
|
-
|
|
427
|
-
}
|
|
418
|
+
if (query instanceof ParseQuery)
|
|
419
|
+
this._parsing.delete(query.text);
|
|
428
420
|
query.error(error);
|
|
429
|
-
this._executingCounter--;
|
|
430
421
|
}
|
|
431
422
|
break;
|
|
432
423
|
case ResponseTypes.ReadyForQuery:
|
|
433
424
|
{
|
|
434
425
|
reader.skipBytes(length);
|
|
435
426
|
this._queue.next();
|
|
436
|
-
this.
|
|
427
|
+
this._tryFinishClosing();
|
|
437
428
|
}
|
|
438
429
|
break;
|
|
439
430
|
case ResponseTypes.Notice:
|
|
440
431
|
{
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
console.log(`\n\x1b[33m┌─ NOTICE ───────────────────────────────────────\x1b[0m\n`
|
|
444
|
-
+ `\x1b[33m│\x1b[0m ${message}\n`
|
|
445
|
-
+ `\x1b[33m└────────────────────────────────────────────────\x1b[0m\n`);
|
|
446
|
-
}
|
|
432
|
+
const notice = reader.readErrorResponse();
|
|
433
|
+
this._logNotice(notice);
|
|
447
434
|
}
|
|
448
435
|
break;
|
|
449
436
|
case ResponseTypes.NotificationResponse:
|
|
@@ -470,6 +457,19 @@ export class Connection {
|
|
|
470
457
|
get isClosed() {
|
|
471
458
|
return this._closed || !!this._closing;
|
|
472
459
|
}
|
|
460
|
+
_tryFinishClosing() {
|
|
461
|
+
if (!this._closing)
|
|
462
|
+
return;
|
|
463
|
+
if (this._queue.hasMore)
|
|
464
|
+
return;
|
|
465
|
+
setTimeout(() => {
|
|
466
|
+
if (!this._closing)
|
|
467
|
+
return;
|
|
468
|
+
if (!this._queue.hasMore) {
|
|
469
|
+
this._closing.resolve();
|
|
470
|
+
}
|
|
471
|
+
}, 0);
|
|
472
|
+
}
|
|
473
473
|
/**
|
|
474
474
|
* Closes the connection, awaiting for all pending queries. Not usable afterward.
|
|
475
475
|
*/
|
|
@@ -479,11 +479,6 @@ export class Connection {
|
|
|
479
479
|
if (this._closing) {
|
|
480
480
|
return this._closing.future;
|
|
481
481
|
}
|
|
482
|
-
if (!this._executingCounter) {
|
|
483
|
-
this._closed = true;
|
|
484
|
-
this._socket.destroy();
|
|
485
|
-
return Future.resolve();
|
|
486
|
-
}
|
|
487
482
|
const closing = Future.withResolvers();
|
|
488
483
|
this._closing = closing;
|
|
489
484
|
closing.future.tap(() => {
|
|
@@ -491,6 +486,7 @@ export class Connection {
|
|
|
491
486
|
this._closed = true;
|
|
492
487
|
this._socket.destroy();
|
|
493
488
|
});
|
|
489
|
+
this._tryFinishClosing();
|
|
494
490
|
return closing.future;
|
|
495
491
|
}
|
|
496
492
|
}
|
package/dist/error.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,sBAAsB,CAAA;AAGhE,qBAAa,aAAc,SAAQ,KAAK;IAEhB,OAAO,EAAE,MAAM;IACxB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,MAAM;IACd,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,UAAU,EAAE,MAAM;gBART,OAAO,EAAE,MAAM,EACxB,IAAI,GAAE,MAAqB,EAC3B,MAAM,GAAE,MAAW,EACnB,QAAQ,GAAE,MAAW,EACrB,KAAK,GAAE,MAAW,EAClB,IAAI,GAAE,MAAW,EACjB,QAAQ,GAAE,MAAW,EACrB,QAAQ,GAAE,MAAW,EACrB,UAAU,GAAE,MAAW;IAMlC,IAAI,YAAY,IAAI,OAAO,CAK1B;IAED,IAAI,WAAW,IAAI,OAAO,CAKzB;IAED,IAAI,uBAAuB,IAAI,OAAO,CAErC;IAED,IAAI,8BAA8B,IAAI,OAAO,CAE5C;IAED,IAAI,qBAAqB,IAAI,OAAO,CAEnC;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,mBAAmB,IAAI,OAAO,CAEjC;CACJ;AAGD,eAAO,MAAM,gBAAgB,eAAmF,CAAA;AAChH,eAAO,MAAM,mBAAmB,eAAqE,CAAA;AACrG,eAAO,MAAM,yBAAyB,eAAiD,CAAA;AAEvF,eAAO,MAAM,eAAe,eAA8C,CAAA;AAE1E,eAAO,MAAM,aAAa,eAAkE,CAAA;AAE5F,eAAO,MAAM,oBAAoB,eAA6E,CAAA;AAE9G,eAAO,MAAM,mBAAmB,eAA8E,CAAA;AAC9G,eAAO,MAAM,yBAAyB,eAA2F,CAAA;AACjI,eAAO,MAAM,YAAY,eAA4D,CAAA;AACrF,eAAO,MAAM,mBAAmB,eAAwD,CAAA;AACxF,eAAO,MAAM,uBAAuB,eAA4E,CAAA;AAChH,eAAO,MAAM,0BAA0B,eAAkF,CAAA;AAgCzH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,GAAG,aAAa,CAqBjH"}
|
package/dist/error.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { handlers } from "./protocol/types";
|
|
1
2
|
export class PostgresError extends Error {
|
|
2
3
|
constructor(message, code = 'undeclared', detail = '', severity = '', where = '', hint = '', position = '', dataType = '', constraint = '') {
|
|
3
4
|
super(message);
|
|
@@ -51,14 +52,43 @@ export const ErrSSLDenied = new PostgresError("SSL is required but server denied
|
|
|
51
52
|
export const ErrDatabaseNotFound = new PostgresError('Database with that dsn not found');
|
|
52
53
|
export const ErrUntrustedCertificate = new PostgresError("Database SSL certificate is untrusted or self-signed");
|
|
53
54
|
export const ErrCertificateFileNotFound = new PostgresError("The SSL certificate file specified in caPath was not found");
|
|
55
|
+
function describeValue(value) {
|
|
56
|
+
if (value === null)
|
|
57
|
+
return 'null';
|
|
58
|
+
if (value === undefined)
|
|
59
|
+
return 'undefined';
|
|
60
|
+
if (typeof value === 'bigint')
|
|
61
|
+
return `${value}n`;
|
|
62
|
+
if (typeof value === 'string') {
|
|
63
|
+
return value.length > 60 ? `${JSON.stringify(value.slice(0, 60))}…` : JSON.stringify(value);
|
|
64
|
+
}
|
|
65
|
+
if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
66
|
+
return `Uint8Array(length=${value.length})`;
|
|
67
|
+
}
|
|
68
|
+
if (value instanceof Date) {
|
|
69
|
+
return `Date(${isNaN(value.getTime()) ? 'Invalid Date' : value.toISOString()})`;
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
const preview = value.slice(0, 5).map(describeValue).join(', ');
|
|
73
|
+
return `[${preview}${value.length > 5 ? ', …' : ''}] (length=${value.length})`;
|
|
74
|
+
}
|
|
75
|
+
if (typeof value === 'object') {
|
|
76
|
+
try {
|
|
77
|
+
const json = JSON.stringify(value);
|
|
78
|
+
return json.length > 120 ? `${json.slice(0, 120)}…` : json;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return Object.prototype.toString.call(value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return String(value);
|
|
85
|
+
}
|
|
54
86
|
export function createBindTypeError(index, expectedType, actualValue) {
|
|
55
|
-
const position =
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
`
|
|
60
|
-
|
|
61
|
-
'writeBind() inside driver',
|
|
62
|
-
`Ensure that the argument passed as $${position} matches the PostgreSQL schema requirements.` // hint
|
|
63
|
-
);
|
|
87
|
+
const position = index + 1;
|
|
88
|
+
const info = handlers[expectedType];
|
|
89
|
+
const expectedPgType = info?.pgType ?? `oid ${expectedType}`;
|
|
90
|
+
const expectedJsShape = info?.jsShape ?? '(тип не описан в справочнике)';
|
|
91
|
+
const message = `Bind error: Parameter $${position} type mismatch. ` +
|
|
92
|
+
`Expected PostgreSQL type "${expectedPgType}" (${expectedJsShape}), received: ${describeValue(actualValue)}.`;
|
|
93
|
+
return new PostgresError(message, '22000', `Parameter $${position} failed client-side binary validation for pg type "${expectedPgType}".`, 'ERROR', 'writeBind() inside driver', `Pass a value matching ${expectedJsShape} for $${position}.`, '', expectedPgType);
|
|
64
94
|
}
|
package/dist/protocol/types.d.ts
CHANGED
|
@@ -4,7 +4,11 @@ import { DataTypeOid } from "./constants";
|
|
|
4
4
|
type BindValidator = (value: unknown) => boolean;
|
|
5
5
|
type BindWriter = (request: ConnectionRequestBuffer, value: any) => void;
|
|
6
6
|
type FieldReader = (response: ConnectionResponseBuffer, fieldLength: number, int8toBigint: boolean) => unknown;
|
|
7
|
-
interface BindHandler {
|
|
7
|
+
export interface BindHandler {
|
|
8
|
+
/** Имя типа в PostgreSQL — используется в сообщениях об ошибках. */
|
|
9
|
+
pgType: string;
|
|
10
|
+
/** Ожидаемая JS-форма значения — используется в сообщениях об ошибках. */
|
|
11
|
+
jsShape: string;
|
|
8
12
|
validate: BindValidator;
|
|
9
13
|
write: BindWriter;
|
|
10
14
|
read: FieldReader;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/protocol/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAA;AACvE,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAA;AAEvD,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;AAChD,KAAK,UAAU,GAAG,CAAC,OAAO,EAAE,uBAAuB,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAA;AACxE,KAAK,WAAW,GAAG,CACf,QAAQ,EAAE,wBAAwB,EAClC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,OAAO,KACpB,OAAO,CAAA;AAEZ,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/protocol/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAA;AACvE,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAA;AAEvD,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;AAChD,KAAK,UAAU,GAAG,CAAC,OAAO,EAAE,uBAAuB,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAA;AACxE,KAAK,WAAW,GAAG,CACf,QAAQ,EAAE,wBAAwB,EAClC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,OAAO,KACpB,OAAO,CAAA;AAEZ,MAAM,WAAW,WAAW;IACxB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAA;IACd,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,aAAa,CAAA;IACvB,KAAK,EAAE,UAAU,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;CACpB;AASD,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CA2d9D,CAAA"}
|
package/dist/protocol/types.js
CHANGED
|
@@ -5,36 +5,50 @@ const isPoint = (value) => value !== null &&
|
|
|
5
5
|
'y' in value && typeof value.y === 'number';
|
|
6
6
|
export const handlers = {
|
|
7
7
|
[DataTypeOids.Bool]: {
|
|
8
|
+
pgType: 'bool',
|
|
9
|
+
jsShape: 'boolean',
|
|
8
10
|
validate: (v) => typeof v === 'boolean',
|
|
9
11
|
write: (req, v) => req.writeBinaryBool(v),
|
|
10
12
|
read: (res) => res.readBool(),
|
|
11
13
|
},
|
|
12
14
|
[DataTypeOids.Text]: {
|
|
15
|
+
pgType: 'text',
|
|
16
|
+
jsShape: 'string',
|
|
13
17
|
validate: (v) => typeof v === 'string',
|
|
14
18
|
write: (req, v) => req.writeBinaryString(v),
|
|
15
19
|
read: (res, len) => res.readRawString(len),
|
|
16
20
|
},
|
|
17
21
|
[DataTypeOids.Varchar]: {
|
|
22
|
+
pgType: 'varchar',
|
|
23
|
+
jsShape: 'string',
|
|
18
24
|
validate: (v) => typeof v === 'string',
|
|
19
25
|
write: (req, v) => req.writeBinaryString(v),
|
|
20
26
|
read: (res, len) => res.readRawString(len),
|
|
21
27
|
},
|
|
22
28
|
[DataTypeOids.Char]: {
|
|
29
|
+
pgType: 'char',
|
|
30
|
+
jsShape: 'string',
|
|
23
31
|
validate: (v) => typeof v === 'string',
|
|
24
32
|
write: (req, v) => req.writeBinaryString(v),
|
|
25
33
|
read: (res, len) => res.readRawString(len),
|
|
26
34
|
},
|
|
27
35
|
[DataTypeOids.Bpchar]: {
|
|
36
|
+
pgType: 'bpchar',
|
|
37
|
+
jsShape: 'string',
|
|
28
38
|
validate: (v) => typeof v === 'string',
|
|
29
39
|
write: (req, v) => req.writeBinaryString(v),
|
|
30
40
|
read: (res, len) => res.readRawString(len),
|
|
31
41
|
},
|
|
32
42
|
[DataTypeOids.Name]: {
|
|
43
|
+
pgType: 'name',
|
|
44
|
+
jsShape: 'string',
|
|
33
45
|
validate: (v) => typeof v === 'string' && Buffer.byteLength(v, 'utf-8') <= 63,
|
|
34
46
|
write: (req, v) => req.writeBinaryString(v),
|
|
35
47
|
read: (res, len) => res.readRawString(len),
|
|
36
48
|
},
|
|
37
49
|
[DataTypeOids.Int2]: {
|
|
50
|
+
pgType: 'int2',
|
|
51
|
+
jsShape: 'number (-32768..32767)',
|
|
38
52
|
validate: (v) => typeof v === 'number' &&
|
|
39
53
|
Number.isInteger(v) &&
|
|
40
54
|
v >= -32768 &&
|
|
@@ -43,6 +57,8 @@ export const handlers = {
|
|
|
43
57
|
read: (res) => res.readInt16(),
|
|
44
58
|
},
|
|
45
59
|
[DataTypeOids.Int4]: {
|
|
60
|
+
pgType: 'int4',
|
|
61
|
+
jsShape: 'number (-2147483648..2147483647)',
|
|
46
62
|
validate: (v) => typeof v === 'number' &&
|
|
47
63
|
Number.isInteger(v) &&
|
|
48
64
|
v >= -2147483648 &&
|
|
@@ -51,6 +67,8 @@ export const handlers = {
|
|
|
51
67
|
read: (res) => res.readInt32(),
|
|
52
68
|
},
|
|
53
69
|
[DataTypeOids.Int8]: {
|
|
70
|
+
pgType: 'int8',
|
|
71
|
+
jsShape: 'bigint | number (safe integer)',
|
|
54
72
|
validate: (v) => typeof v === 'bigint' ||
|
|
55
73
|
(typeof v === 'number' && Number.isSafeInteger(v)),
|
|
56
74
|
write: (req, v) => typeof v === 'bigint'
|
|
@@ -59,58 +77,80 @@ export const handlers = {
|
|
|
59
77
|
read: (res, _len, int8toBigint) => int8toBigint ? res.readBigInt64() : res.readInt64(),
|
|
60
78
|
},
|
|
61
79
|
[DataTypeOids.Float4]: {
|
|
80
|
+
pgType: 'float4',
|
|
81
|
+
jsShape: 'number',
|
|
62
82
|
validate: (v) => typeof v === 'number' && Number.isFinite(v),
|
|
63
83
|
write: (req, v) => req.writeBinaryFloat4(v),
|
|
64
84
|
read: (res) => res.readFloat32(),
|
|
65
85
|
},
|
|
66
86
|
[DataTypeOids.Float8]: {
|
|
87
|
+
pgType: 'float8',
|
|
88
|
+
jsShape: 'number',
|
|
67
89
|
validate: (v) => typeof v === 'number' && Number.isFinite(v),
|
|
68
90
|
write: (req, v) => req.writeBinaryFloat8(v),
|
|
69
91
|
read: (res) => res.readFloat64(),
|
|
70
92
|
},
|
|
71
93
|
[DataTypeOids.Bytea]: {
|
|
94
|
+
pgType: 'bytea',
|
|
95
|
+
jsShape: 'Buffer | Uint8Array',
|
|
72
96
|
validate: (v) => Buffer.isBuffer(v) || v instanceof Uint8Array,
|
|
73
97
|
write: (req, v) => req.writeBinaryBytea(v),
|
|
74
98
|
read: (res, len) => res.readBytes(len),
|
|
75
99
|
},
|
|
76
100
|
[DataTypeOids.Timestamp]: {
|
|
101
|
+
pgType: 'timestamp',
|
|
102
|
+
jsShape: 'Date',
|
|
77
103
|
validate: (v) => v instanceof Date,
|
|
78
104
|
write: (req, v) => req.writeBinaryTimestamp(v),
|
|
79
105
|
read: (res) => res.readBinaryTimestamp(),
|
|
80
106
|
},
|
|
81
107
|
[DataTypeOids.Timestamptz]: {
|
|
108
|
+
pgType: 'timestamptz',
|
|
109
|
+
jsShape: 'Date',
|
|
82
110
|
validate: (v) => v instanceof Date,
|
|
83
111
|
write: (req, v) => req.writeBinaryTimestamp(v),
|
|
84
112
|
read: (res) => res.readBinaryTimestamp(),
|
|
85
113
|
},
|
|
86
114
|
[DataTypeOids.Point]: {
|
|
115
|
+
pgType: 'point',
|
|
116
|
+
jsShape: '{ x: number, y: number }',
|
|
87
117
|
validate: isPoint,
|
|
88
118
|
write: (req, v) => req.writeBinaryPoint(v),
|
|
89
119
|
read: (res) => res.readBinaryPoint(),
|
|
90
120
|
},
|
|
91
121
|
[DataTypeOids.Numeric]: {
|
|
122
|
+
pgType: 'numeric',
|
|
123
|
+
jsShape: 'string ("[-]digits[.digits]")',
|
|
92
124
|
validate: (v) => (typeof v === 'string' && /^-?\d*\.?\d+$/.test(v)),
|
|
93
125
|
write: (req, v) => req.writeBinaryNumeric(v),
|
|
94
126
|
read: (res) => res.readBinaryNumeric(),
|
|
95
127
|
},
|
|
96
128
|
[DataTypeOids.Date]: {
|
|
129
|
+
pgType: 'date',
|
|
130
|
+
jsShape: 'Date',
|
|
97
131
|
validate: (v) => v instanceof Date,
|
|
98
132
|
write: (req, v) => req.writeBinaryDate(v),
|
|
99
133
|
read: (res) => res.readBinaryDate(),
|
|
100
134
|
},
|
|
101
135
|
[DataTypeOids.Time]: {
|
|
136
|
+
pgType: 'time',
|
|
137
|
+
jsShape: 'string ("HH:MM:SS.mmm")',
|
|
102
138
|
validate: (v) => typeof v === 'string' &&
|
|
103
139
|
/^(\d{2}):(\d{2}):(\d{2})\.(\d{3})$/.test(v),
|
|
104
140
|
write: (req, v) => req.writeBinaryTime(v),
|
|
105
141
|
read: (res) => res.readBinaryTime(),
|
|
106
142
|
},
|
|
107
143
|
[DataTypeOids.Timetz]: {
|
|
144
|
+
pgType: 'timetz',
|
|
145
|
+
jsShape: 'string ("HH:MM:SS.mmm±HH:MM")',
|
|
108
146
|
validate: (v) => typeof v === 'string' &&
|
|
109
147
|
/^(\d{2}):(\d{2}):(\d{2})\.(\d{3})([+-])(\d{2}):(\d{2})$/.test(v),
|
|
110
148
|
write: (req, v) => req.writeBinaryTimetz(v),
|
|
111
149
|
read: (res) => res.readBinaryTimetz(),
|
|
112
150
|
},
|
|
113
151
|
[DataTypeOids.Interval]: {
|
|
152
|
+
pgType: 'interval',
|
|
153
|
+
jsShape: '{ months: number, days: number, microseconds: number | bigint }',
|
|
114
154
|
validate: (v) => v !== null &&
|
|
115
155
|
typeof v === 'object' &&
|
|
116
156
|
'months' in v && typeof v.months === 'number' &&
|
|
@@ -121,64 +161,88 @@ export const handlers = {
|
|
|
121
161
|
read: (res) => res.readBinaryInterval(),
|
|
122
162
|
},
|
|
123
163
|
[DataTypeOids.Json]: {
|
|
164
|
+
pgType: 'json',
|
|
165
|
+
jsShape: 'unknown (JSON-serializable)',
|
|
124
166
|
validate: (_v) => true,
|
|
125
167
|
write: (req, v) => req.writeBinaryJson(v),
|
|
126
168
|
read: (res, len) => res.readBinaryJson(len),
|
|
127
169
|
},
|
|
128
170
|
[DataTypeOids.Jsonb]: {
|
|
171
|
+
pgType: 'jsonb',
|
|
172
|
+
jsShape: 'unknown (JSON-serializable)',
|
|
129
173
|
validate: (_v) => true,
|
|
130
174
|
write: (req, v) => req.writeBinaryJsonb(v),
|
|
131
175
|
read: (res, len) => res.readBinaryJsonb(len),
|
|
132
176
|
},
|
|
133
177
|
[DataTypeOids.Uuid]: {
|
|
178
|
+
pgType: 'uuid',
|
|
179
|
+
jsShape: 'string ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")',
|
|
134
180
|
validate: (v) => typeof v === 'string' &&
|
|
135
181
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v),
|
|
136
182
|
write: (req, v) => req.writeBinaryUuid(v),
|
|
137
183
|
read: (res) => res.readBinaryUuid(),
|
|
138
184
|
},
|
|
139
185
|
[DataTypeOids.Cidr]: {
|
|
186
|
+
pgType: 'cidr',
|
|
187
|
+
jsShape: 'string (IPv4/IPv6 address or CIDR)',
|
|
140
188
|
validate: (v) => typeof v === 'string',
|
|
141
189
|
write: (req, v) => req.writeBinaryCidr(v),
|
|
142
190
|
read: (res, len) => res.readBinaryInet(len),
|
|
143
191
|
},
|
|
144
192
|
[DataTypeOids.Inet]: {
|
|
193
|
+
pgType: 'inet',
|
|
194
|
+
jsShape: 'string (IPv4/IPv6 address or CIDR)',
|
|
145
195
|
validate: (v) => typeof v === 'string',
|
|
146
196
|
write: (req, v) => req.writeBinaryInet(v),
|
|
147
197
|
read: (res, len) => res.readBinaryInet(len),
|
|
148
198
|
},
|
|
149
199
|
[DataTypeOids.Macaddr]: {
|
|
200
|
+
pgType: 'macaddr',
|
|
201
|
+
jsShape: 'string ("xx:xx:xx:xx:xx:xx")',
|
|
150
202
|
validate: (v) => typeof v === 'string' &&
|
|
151
203
|
/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i.test(v),
|
|
152
204
|
write: (req, v) => req.writeBinaryMacaddr(v),
|
|
153
205
|
read: (res) => res.readBinaryMacaddr(),
|
|
154
206
|
},
|
|
155
207
|
[DataTypeOids.Oid]: {
|
|
208
|
+
pgType: 'oid',
|
|
209
|
+
jsShape: 'number',
|
|
156
210
|
validate: (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0,
|
|
157
211
|
write: (req, v) => req.writeBinaryOid(v),
|
|
158
212
|
read: (res) => res.readBinaryOid(),
|
|
159
213
|
},
|
|
160
214
|
[DataTypeOids.Xid]: {
|
|
215
|
+
pgType: 'xid',
|
|
216
|
+
jsShape: 'number',
|
|
161
217
|
validate: (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0,
|
|
162
218
|
write: (req, v) => req.writeBinaryXid(v),
|
|
163
219
|
read: (res) => res.readBinaryXid(),
|
|
164
220
|
},
|
|
165
221
|
[DataTypeOids.Cid]: {
|
|
222
|
+
pgType: 'cid',
|
|
223
|
+
jsShape: 'number',
|
|
166
224
|
validate: (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0,
|
|
167
225
|
write: (req, v) => req.writeBinaryCid(v),
|
|
168
226
|
read: (res) => res.readBinaryCid(),
|
|
169
227
|
},
|
|
170
228
|
[DataTypeOids.Regproc]: {
|
|
229
|
+
pgType: 'regproc',
|
|
230
|
+
jsShape: 'number',
|
|
171
231
|
validate: (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0,
|
|
172
232
|
write: (req, v) => req.writeBinaryRegproc(v),
|
|
173
233
|
read: (res) => res.readBinaryRegproc(),
|
|
174
234
|
},
|
|
175
235
|
[DataTypeOids.Lseg]: {
|
|
236
|
+
pgType: 'lseg',
|
|
237
|
+
jsShape: '{ a: Point, b: Point }',
|
|
176
238
|
validate: (v) => v !== null && typeof v === 'object' &&
|
|
177
239
|
isPoint(v.a) && isPoint(v.b),
|
|
178
240
|
write: (req, v) => req.writeBinaryLseg(v),
|
|
179
241
|
read: (res) => res.readBinaryLseg(),
|
|
180
242
|
},
|
|
181
243
|
[DataTypeOids.Path]: {
|
|
244
|
+
pgType: 'path',
|
|
245
|
+
jsShape: '{ closed: boolean, points: Point[] }',
|
|
182
246
|
validate: (v) => v !== null && typeof v === 'object' &&
|
|
183
247
|
typeof v.closed === 'boolean' &&
|
|
184
248
|
Array.isArray(v.points) &&
|
|
@@ -187,12 +251,16 @@ export const handlers = {
|
|
|
187
251
|
read: (res) => res.readBinaryPath(),
|
|
188
252
|
},
|
|
189
253
|
[DataTypeOids.Box]: {
|
|
254
|
+
pgType: 'box',
|
|
255
|
+
jsShape: '{ high: Point, low: Point }',
|
|
190
256
|
validate: (v) => v !== null && typeof v === 'object' &&
|
|
191
257
|
isPoint(v.high) && isPoint(v.low),
|
|
192
258
|
write: (req, v) => req.writeBinaryBox(v),
|
|
193
259
|
read: (res) => res.readBinaryBox(),
|
|
194
260
|
},
|
|
195
261
|
[DataTypeOids.Polygon]: {
|
|
262
|
+
pgType: 'polygon',
|
|
263
|
+
jsShape: '{ points: Point[] }',
|
|
196
264
|
validate: (v) => v !== null && typeof v === 'object' &&
|
|
197
265
|
Array.isArray(v.points) &&
|
|
198
266
|
v.points.every(isPoint),
|
|
@@ -200,6 +268,8 @@ export const handlers = {
|
|
|
200
268
|
read: (res) => res.readBinaryPolygon(),
|
|
201
269
|
},
|
|
202
270
|
[DataTypeOids.Line]: {
|
|
271
|
+
pgType: 'line',
|
|
272
|
+
jsShape: '{ a: number, b: number, c: number }',
|
|
203
273
|
validate: (v) => v !== null && typeof v === 'object' &&
|
|
204
274
|
typeof v.a === 'number' &&
|
|
205
275
|
typeof v.b === 'number' &&
|
|
@@ -208,21 +278,29 @@ export const handlers = {
|
|
|
208
278
|
read: (res) => res.readBinaryLine(),
|
|
209
279
|
},
|
|
210
280
|
[DataTypeOids.BoolArray]: {
|
|
281
|
+
pgType: 'bool[]',
|
|
282
|
+
jsShape: '(boolean | null)[]',
|
|
211
283
|
validate: (v) => Array.isArray(v) && v.every(el => el == null || typeof el === 'boolean'),
|
|
212
284
|
write: (req, v) => req.writeBinaryBoolArray(v),
|
|
213
285
|
read: (res, len) => res.readBinaryArray(len, () => res.readBool()),
|
|
214
286
|
},
|
|
215
287
|
[DataTypeOids.Int2Array]: {
|
|
288
|
+
pgType: 'int2[]',
|
|
289
|
+
jsShape: '(number | null)[]',
|
|
216
290
|
validate: (v) => Array.isArray(v) && v.every(el => el == null || (typeof el === 'number' && Number.isInteger(el) && el >= -32768 && el <= 32767)),
|
|
217
291
|
write: (req, v) => req.writeBinaryInt2Array(v),
|
|
218
292
|
read: (res, len) => res.readBinaryArray(len, () => res.readInt16()),
|
|
219
293
|
},
|
|
220
294
|
[DataTypeOids.Int4Array]: {
|
|
295
|
+
pgType: 'int4[]',
|
|
296
|
+
jsShape: '(number | null)[]',
|
|
221
297
|
validate: (v) => Array.isArray(v) && v.every(el => el == null || (typeof el === 'number' && Number.isInteger(el) && el >= -2147483648 && el <= 2147483647)),
|
|
222
298
|
write: (req, v) => req.writeBinaryInt4Array(v),
|
|
223
299
|
read: (res, len) => res.readBinaryArray(len, () => res.readInt32()),
|
|
224
300
|
},
|
|
225
301
|
[DataTypeOids.Int8Array]: {
|
|
302
|
+
pgType: 'int8[]',
|
|
303
|
+
jsShape: '(number | bigint | null)[]',
|
|
226
304
|
validate: (v) => Array.isArray(v) && v.every(el => el == null ||
|
|
227
305
|
typeof el === 'bigint' ||
|
|
228
306
|
(typeof el === 'number' && Number.isSafeInteger(el))),
|
|
@@ -230,31 +308,43 @@ export const handlers = {
|
|
|
230
308
|
read: (res, len, int8toBigint) => res.readBinaryArray(len, () => int8toBigint ? res.readBigInt64() : res.readInt64()),
|
|
231
309
|
},
|
|
232
310
|
[DataTypeOids.TextArray]: {
|
|
311
|
+
pgType: 'text[]',
|
|
312
|
+
jsShape: '(string | null)[]',
|
|
233
313
|
validate: (v) => Array.isArray(v) && v.every(el => el == null || typeof el === 'string'),
|
|
234
314
|
write: (req, v) => req.writeBinaryTextArray(v),
|
|
235
315
|
read: (res, len) => res.readBinaryArray(len, (l) => res.readRawString(l)),
|
|
236
316
|
},
|
|
237
317
|
[DataTypeOids.VarcharArray]: {
|
|
318
|
+
pgType: 'varchar[]',
|
|
319
|
+
jsShape: '(string | null)[]',
|
|
238
320
|
validate: (v) => Array.isArray(v) && v.every(el => el == null || typeof el === 'string'),
|
|
239
321
|
write: (req, v) => req.writeBinaryVarcharArray(v),
|
|
240
322
|
read: (res, len) => res.readBinaryArray(len, (l) => res.readRawString(l)),
|
|
241
323
|
},
|
|
242
324
|
[DataTypeOids.JsonArray]: {
|
|
325
|
+
pgType: 'json[]',
|
|
326
|
+
jsShape: 'unknown[]',
|
|
243
327
|
validate: (v) => Array.isArray(v),
|
|
244
328
|
write: (req, v) => req.writeBinaryJsonArray(v),
|
|
245
329
|
read: (res, len) => res.readBinaryArray(len, (l) => res.readBinaryJson(l)),
|
|
246
330
|
},
|
|
247
331
|
[DataTypeOids.JsonbArray]: {
|
|
332
|
+
pgType: 'jsonb[]',
|
|
333
|
+
jsShape: 'unknown[]',
|
|
248
334
|
validate: (v) => Array.isArray(v),
|
|
249
335
|
write: (req, v) => req.writeBinaryJsonbArray(v),
|
|
250
336
|
read: (res, len) => res.readBinaryArray(len, (l) => res.readBinaryJsonb(l)),
|
|
251
337
|
},
|
|
252
338
|
[DataTypeOids.UuidArray]: {
|
|
339
|
+
pgType: 'uuid[]',
|
|
340
|
+
jsShape: '(string | null)[]',
|
|
253
341
|
validate: (v) => Array.isArray(v) && v.every(el => el == null || (typeof el === 'string' && /^[0-9a-f-]{36}$/i.test(el))),
|
|
254
342
|
write: (req, v) => req.writeBinaryUuidArray(v),
|
|
255
343
|
read: (res, len) => res.readBinaryArray(len, () => res.readBinaryUuid()),
|
|
256
344
|
},
|
|
257
345
|
[DataTypeOids.NumericArray]: {
|
|
346
|
+
pgType: 'numeric[]',
|
|
347
|
+
jsShape: '(string | null)[]',
|
|
258
348
|
validate: (v) => Array.isArray(v) && v.every(el => el == null ||
|
|
259
349
|
(typeof el === 'number' && Number.isFinite(el)) ||
|
|
260
350
|
(typeof el === 'string' && /^-?\d*\.?\d+$/.test(el))),
|