@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.
@@ -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
  */
@@ -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;AAevF;;;;;;;;;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;IAC3C,OAAO,CAAC,iBAAiB,CAAI;IAE7B,OAAO,CAAC,QAAQ,CAAsD;IACtE,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,aAAa,CAA2C;IAEhE,OAAO,CAAC,OAAO,CAAiB;IAEhC,OAAO,CAAC,OAAO,CAAuC;IACtD,OAAO,CAAC,QAAQ,CAA8D;IAE9E,OAAO,CAAC,mBAAmB,CAAyD;IACpF,OAAO,CAAC,YAAY,CAAI;IAExB,OAAO,CAAC,cAAc;IAKtB,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;IA+DrB;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAazD,OAAO,CAAC,eAAe;IA+DvB;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IA2BvE,OAAO,CAAC,cAAc;IAkEtB;;;;;;;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;IA8BzB,OAAO,CAAC,qBAAqB;IAW7B,OAAO,KAAK,aAAa,GAExB;IAGD,OAAO,CAAC,aAAa;IA6HrB,kDAAkD;IAClD,IAAI,QAAQ,YAEX;IAGD,mDAAmD;IACnD,IAAI,QAAQ,YAEX;IAGD;;OAEG;IACH,KAAK;CAwBR"}
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"}
@@ -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
- if (this.config.logLevel === 'query') {
117
- console.log(`\n\x1b[36m┌─ QUERY ─────────────────────────────────────────\x1b[0m\n`
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
- return query.resolvers.future;
144
+ this._logError(err);
131
145
  }
132
146
  return query.resolvers.future;
133
147
  }
134
- if (!this._parsing[text]) {
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[text] = parseQuery.resolvers.future;
151
+ this._parsing.set(text, parseQuery.resolvers.future);
138
152
  }
139
- const parsing = this._parsing[text];
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
- return query.resolvers.future;
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
- if (this.config.logLevel === 'query') {
168
- console.log(`\n\x1b[35m┌─ EXECUTE ──────────────────────────────────────\x1b[0m\n`
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
- return query.resolvers.future;
187
+ this._logError(err);
182
188
  }
183
189
  return query.resolvers.future;
184
190
  }
185
- if (!this._parsing[text]) {
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[text] = parseQuery.resolvers.future;
194
+ this._parsing.set(text, parseQuery.resolvers.future);
189
195
  }
190
- const parsing = this._parsing[text];
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
- return query.resolvers.future;
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
- if (this.config.logLevel === 'query') {
230
- console.log(`\n\x1b[34m┌─ STREAM ───────────────────────────────────────\x1b[0m\n`
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[text]) {
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[text] = parseQuery.resolvers.future;
248
+ this._parsing.set(text, parseQuery.resolvers.future);
250
249
  }
251
- const parsing = this._parsing[text];
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
- delete this._parsing[query.text];
386
- this._parsed[query.text] = query.meta;
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
- delete this._parsing[query.text];
394
- this._parsed[query.text] = query.meta;
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
- if (this.config.logLevel === 'error' || this.config.logLevel === 'notice' || this.config.logLevel === 'query') {
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 (error.isParseError) {
426
- delete this._parsing[query.text];
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._closing && !this._executingCounter && this._closing.resolve();
427
+ this._tryFinishClosing();
437
428
  }
438
429
  break;
439
430
  case ResponseTypes.Notice:
440
431
  {
441
- const message = reader.readErrorResponse();
442
- if (this.config.logLevel === 'notice' || this.config.logLevel === 'query') {
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,sBAAsB,CAAA;AAEhE,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;AAEzH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,GAAG,aAAa,CAcjH"}
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 = (index + 1).toString();
56
- const actualType = actualValue === null ? 'null' : typeof actualValue;
57
- const message = `Bind error: Parameter $${position} type mismatch. Expected ${expectedType}, received "${actualType}(${actualValue})".`;
58
- return new PostgresError(message, '22000', // code
59
- `The parameter at position $${position} failed client-side binary validation.`, // detail
60
- 'ERROR', // severity
61
- 'writeBind() inside driver', // where
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
  }
@@ -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,UAAU,WAAW;IACjB,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,CAsY9D,CAAA"}
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"}
@@ -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))),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m2k-5f/pgtx",
3
- "version": "2.8.0",
3
+ "version": "2.8.1",
4
4
  "type": "module",
5
5
  "description": "Blazing-fast PostgreSQL driver with pipeline support.",
6
6
  "files": [