@m2k-5f/pgtx 2.7.1 → 2.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +48 -31
  2. package/dist/batch.d.ts +4 -1
  3. package/dist/batch.d.ts.map +1 -1
  4. package/dist/batch.js +14 -7
  5. package/dist/clauses/fragment.clause.js +1 -1
  6. package/dist/connection.d.ts +17 -16
  7. package/dist/connection.d.ts.map +1 -1
  8. package/dist/connection.js +182 -166
  9. package/dist/error.d.ts +4 -1
  10. package/dist/error.d.ts.map +1 -1
  11. package/dist/error.js +15 -7
  12. package/dist/pool.d.ts +1 -1
  13. package/dist/pool.d.ts.map +1 -1
  14. package/dist/pool.js +5 -3
  15. package/dist/protocol/connection-request-writer.d.ts +24 -11
  16. package/dist/protocol/connection-request-writer.d.ts.map +1 -1
  17. package/dist/protocol/connection-request-writer.js +217 -47
  18. package/dist/protocol/connection-response-reader.d.ts +5 -15
  19. package/dist/protocol/connection-response-reader.d.ts.map +1 -1
  20. package/dist/protocol/connection-response-reader.js +116 -76
  21. package/dist/protocol/constants.d.ts +37 -30
  22. package/dist/protocol/constants.d.ts.map +1 -1
  23. package/dist/protocol/constants.js +35 -29
  24. package/dist/protocol/socket-authorization.d.ts.map +1 -1
  25. package/dist/protocol/socket-authorization.js +7 -7
  26. package/dist/protocol/socket-connector.d.ts +4 -4
  27. package/dist/protocol/socket-connector.d.ts.map +1 -1
  28. package/dist/protocol/socket-connector.js +2 -2
  29. package/dist/query.d.ts +16 -20
  30. package/dist/query.d.ts.map +1 -1
  31. package/dist/query.js +15 -22
  32. package/dist/queue.d.ts +1 -0
  33. package/dist/queue.d.ts.map +1 -1
  34. package/dist/queue.js +1 -0
  35. package/dist/types.d.ts +3 -1
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/utils/template-compiler.d.ts +5 -2
  38. package/dist/utils/template-compiler.d.ts.map +1 -1
  39. package/dist/utils/template-compiler.js +4 -1
  40. package/dist/utils.d.ts +8 -0
  41. package/dist/utils.d.ts.map +1 -0
  42. package/dist/utils.js +73 -0
  43. package/package.json +2 -2
@@ -1,6 +1,5 @@
1
- import { ConnectionRequestWriter } from "./protocol/connection-request-writer";
2
- import { ResponseTypes } from "./protocol/constants";
3
- import { compileSqlTemplate } from "./utils/template-compiler";
1
+ import { DescribeType, EMPTY_ARRAY, ResponseTypes } from "./protocol/constants";
2
+ import { compileSqlTemplate } from "./utils";
4
3
  import { Transaction } from "./transaction";
5
4
  import { SocketConnector } from "./protocol/socket-connector";
6
5
  import { Queue } from "./queue";
@@ -8,9 +7,9 @@ import { CollectQuery, StreamQuery, ExecuteQuery } from "./query";
8
7
  import { sql } from ".";
9
8
  import { Begin, Future, Ok } from 'fluent-future';
10
9
  import { ErrConnectionClosed, ErrConnectionReconnecting } from "./error";
11
- import { Batch } from "./batch";
12
10
  import { nextTick } from "process";
13
11
  import { authorizeSocket, createSocket, upgradeSocket } from "./protocol/socket-authorization";
12
+ import { ConnectionRequestBuffer } from "./protocol/connection-request-writer";
14
13
  const shedule = {
15
14
  Immediate: setImmediate,
16
15
  afterMicrotask: setTimeout,
@@ -30,15 +29,43 @@ export class Connection {
30
29
  _nextStatement() {
31
30
  return `s-${this._stmtCounter++}`;
32
31
  }
32
+ _registerShedule() {
33
+ if (!this._sheduled) {
34
+ this._sheduled = true;
35
+ this._writer.clear();
36
+ shedule[this.config.syncShedule](() => this._shedule());
37
+ }
38
+ }
39
+ _shedule() {
40
+ if (this._reconnecting)
41
+ return;
42
+ this._socket.write(this._writer);
43
+ this._writer.clear();
44
+ this._sheduled = false;
45
+ }
46
+ _parseQuery(query) {
47
+ this._registerShedule();
48
+ this._writer
49
+ .writeParse(query.statement, query.text)
50
+ .writeDescribe(DescribeType.Statement, query.statement);
51
+ }
52
+ _registerQuery(query) {
53
+ this._registerShedule();
54
+ this._queue.push(query);
55
+ this._writer
56
+ .writeBind("", query.statement, query.args, this._parsed[query.text]?.parameters)
57
+ .writeExecute("")
58
+ .writeSync();
59
+ }
33
60
  constructor(socket, config) {
34
- this._activeBatch = null;
61
+ this._writer = ConnectionRequestBuffer.new(65536);
62
+ this._sheduled = false;
63
+ this._queue = new Queue();
35
64
  this._closing = null;
36
65
  this._closed = false;
37
66
  this._reconnecting = null;
38
- this._cachedBuffer = ConnectionRequestWriter.new();
39
- this._batchQueue = new Queue();
40
- this._parsed = new Map();
41
- this._parsing = new Map();
67
+ this._parsed = {};
68
+ this._parsing = {};
42
69
  this._listeningCallbacks = new Map();
43
70
  this._stmtCounter = 0;
44
71
  this.config = config;
@@ -54,7 +81,7 @@ export class Connection {
54
81
  logLevel: config.logLevel || 'error',
55
82
  int8toBigint: config.int8toBigint || false,
56
83
  queryTimeout: config.queryTimeout || 30000,
57
- syncShedule: config.syncShedule || 'afterMicrotask',
84
+ syncShedule: config.syncShedule || 'Immediate',
58
85
  ssl: config.caPath ? 'require' : (config.ssl || 'prefer')
59
86
  };
60
87
  return createSocket(conf)
@@ -62,22 +89,6 @@ export class Connection {
62
89
  .andThen(socket => authorizeSocket(socket, conf))
63
90
  .andThen(socket => Ok(new Connection(socket, conf)));
64
91
  }
65
- _registerBatch() {
66
- if (!this._activeBatch) {
67
- const batch = new Batch(this._cachedBuffer.clear());
68
- this._activeBatch = batch;
69
- shedule[this.config.syncShedule](() => this._sync(batch));
70
- return batch;
71
- }
72
- return this._activeBatch;
73
- }
74
- _sync(batch) {
75
- if (this._reconnecting)
76
- return;
77
- this._socket.write(batch.end());
78
- this._activeBatch = null;
79
- this._batchQueue.push(batch);
80
- }
81
92
  /**
82
93
  * Runs a query, binding template values as `$1, $2, ...`.
83
94
  * Parameterized queries are cached as prepared statements.
@@ -88,32 +99,36 @@ export class Connection {
88
99
  query(templates, ...params) {
89
100
  if (this.isClosed)
90
101
  return Future.reject(ErrConnectionClosed);
102
+ const { text, args } = compileSqlTemplate(templates, params);
103
+ const resolvers = Future.withResolvers();
91
104
  if (this._reconnecting)
92
- return this._reconnecting.andThen(() => this._performQuery(templates, ...params));
93
- return this._performQuery(templates, ...params);
105
+ return this._reconnecting.andThen(() => this._performQuery(text, args, resolvers));
106
+ return this._performQuery(text, args, resolvers);
94
107
  }
95
- _performQuery(templates, ...params) {
96
- const { text, args } = compileSqlTemplate(templates, params);
108
+ _performQuery(text, args, resolvers) {
97
109
  if (this.config.logLevel === 'query') {
98
- console.log(`\nQUERY: ${text}\n${args.length !== 0 ? `ARGUMENTS: [${args}]\n` : ""}`);
110
+ console.log(`\n\x1b[36m┌─ QUERY ─────────────────────────────────────────\x1b[0m\n`
111
+ + `\x1b[36m│\x1b[0m ${text}\n`
112
+ + `${args.length !== 0 ? `\x1b[36m│\x1b[0m \x1b[90mArguments:\x1b[0m [${args}]\n` : ''}`
113
+ + `\x1b[36m└────────────────────────────────────────────────\x1b[0m`);
99
114
  }
100
- if (this._parsed.has(text)) {
101
- const meta = this._parsed.get(text);
102
- const query = new CollectQuery(meta.statement, text, args, meta.columns, this.config.queryTimeout);
103
- this._registerBatch().registerQuery(query);
104
- return query.future;
115
+ const parsed = this._parsed[text];
116
+ if (parsed) {
117
+ const query = new CollectQuery(parsed.statement, text, args, parsed.columns, this.config.queryTimeout, resolvers);
118
+ this._registerQuery(query);
119
+ return query.resolvers.future;
105
120
  }
106
- if (this._parsing.has(text)) {
107
- const statement = this._parsing.get(text);
108
- const query = new CollectQuery(statement, text, args, null, this.config.queryTimeout);
109
- this._registerBatch().registerQuery(query);
110
- return query.future;
121
+ const parsing = this._parsing[text];
122
+ if (parsing) {
123
+ const query = new CollectQuery(parsing, text, args, null, this.config.queryTimeout, resolvers);
124
+ this._registerQuery(query);
125
+ return query.resolvers.future;
111
126
  }
112
- const query = new CollectQuery(this._nextStatement(), text, args, null, this.config.queryTimeout);
113
- this._parsing.set(text, query.statement);
114
- this._registerBatch().registerParse(query);
115
- this._registerBatch().registerQuery(query);
116
- return query.future;
127
+ const query = new CollectQuery(this._nextStatement(), text, args, null, this.config.queryTimeout, resolvers);
128
+ this._parsing[text] = query.statement;
129
+ this._parseQuery(query);
130
+ this._registerQuery(query);
131
+ return query.resolvers.future;
117
132
  }
118
133
  /**
119
134
  * Like {@link query}, but for statements that don't return rows (INSERT/UPDATE/DDL/etc).
@@ -124,32 +139,86 @@ export class Connection {
124
139
  execute(templates, ...params) {
125
140
  if (this.isClosed)
126
141
  return Future.reject(ErrConnectionClosed);
142
+ const { text, args } = compileSqlTemplate(templates, params);
143
+ const resolvers = Future.withResolvers();
127
144
  if (this._reconnecting)
128
- return this._reconnecting.andThen(() => this._performExecute(templates, ...params));
129
- return this._performExecute(templates, ...params);
145
+ return this._reconnecting.andThen(() => this._performExecute(text, args, resolvers));
146
+ return this._performExecute(text, args, resolvers);
147
+ }
148
+ _performExecute(text, args, resolvers) {
149
+ if (this.config.logLevel === 'query') {
150
+ console.log(`\n\x1b[35m┌─ EXECUTE ──────────────────────────────────────\x1b[0m\n`
151
+ + `\x1b[35m│\x1b[0m ${text}\n`
152
+ + `${args.length !== 0 ? `\x1b[35m│\x1b[0m \x1b[90mArguments:\x1b[0m [${args}]\n` : ''}`
153
+ + `\x1b[35m└────────────────────────────────────────────────\x1b[0m`);
154
+ }
155
+ const parsed = this._parsed[text];
156
+ if (parsed) {
157
+ const query = new ExecuteQuery(parsed.statement, text, args, this.config.queryTimeout, resolvers);
158
+ this._registerQuery(query);
159
+ return query.resolvers.future;
160
+ }
161
+ const parsing = this._parsing[text];
162
+ if (parsing) {
163
+ const query = new ExecuteQuery(parsing, text, args, this.config.queryTimeout, resolvers);
164
+ this._registerQuery(query);
165
+ return query.resolvers.future;
166
+ }
167
+ const query = new ExecuteQuery(this._nextStatement(), text, args, this.config.queryTimeout, resolvers);
168
+ this._parsing[text] = query.statement;
169
+ this._parseQuery(query);
170
+ this._registerQuery(query);
171
+ return query.resolvers.future;
130
172
  }
131
- _performExecute(templates, ...params) {
173
+ /**
174
+ * Streams query results as a `ReadableStream`, without buffering rows in memory.
175
+ * Ideal for large result sets or piping straight into an HTTP response.
176
+ *
177
+ * @example
178
+ * for await (const row of conn.stream<User>`SELECT * FROM orders`) { ... }
179
+ */
180
+ stream(templates, ...params) {
181
+ if (this.isClosed)
182
+ throw ErrConnectionClosed;
132
183
  const { text, args } = compileSqlTemplate(templates, params);
184
+ let controller;
185
+ const stream = new ReadableStream({
186
+ start: c => {
187
+ controller = c;
188
+ }
189
+ });
190
+ if (this._reconnecting) {
191
+ this._reconnecting
192
+ .tap(() => this._performStream(text, args, controller))
193
+ .tapErr(err => controller.error(err));
194
+ return stream;
195
+ }
196
+ this._performStream(text, args, controller);
197
+ return stream;
198
+ }
199
+ _performStream(text, args, controller) {
133
200
  if (this.config.logLevel === 'query') {
134
- console.log(`\nQUERY: ${text}\n${args.length !== 0 ? `ARGUMENTS: [${args}]\n` : ""}`);
201
+ console.log(`\n\x1b[34m┌─ STREAM ───────────────────────────────────────\x1b[0m\n`
202
+ + `\x1b[34m│\x1b[0m ${text}\n`
203
+ + `${args.length !== 0 ? `\x1b[34m│\x1b[0m \x1b[90mArguments:\x1b[0m [${args}]\n` : ''}`
204
+ + `\x1b[34m└────────────────────────────────────────────────\x1b[0m`);
135
205
  }
136
- if (this._parsed.has(text)) {
137
- const meta = this._parsed.get(text);
138
- const query = new ExecuteQuery(meta.statement, text, args, this.config.queryTimeout);
139
- this._registerBatch().registerQuery(query);
140
- return query.future;
206
+ const parsed = this._parsed[text];
207
+ if (parsed) {
208
+ const query = new StreamQuery(parsed.statement, text, args, controller, parsed.columns, this.config.queryTimeout);
209
+ this._registerQuery(query);
210
+ return;
141
211
  }
142
- if (this._parsing.has(text)) {
143
- const statement = this._parsing.get(text);
144
- const query = new ExecuteQuery(statement, text, args, this.config.queryTimeout);
145
- this._registerBatch().registerQuery(query);
146
- return query.future;
212
+ const parsing = this._parsing[text];
213
+ if (parsing) {
214
+ const query = new StreamQuery(parsing, text, args, controller, null, this.config.queryTimeout);
215
+ this._registerQuery(query);
216
+ return;
147
217
  }
148
- const query = new ExecuteQuery(this._nextStatement(), text, args, this.config.queryTimeout);
149
- this._parsing.set(text, query.statement);
150
- this._registerBatch().registerParse(query);
151
- this._registerBatch().registerQuery(query);
152
- return query.future;
218
+ const query = new StreamQuery(this._nextStatement(), text, args, controller, null, this.config.queryTimeout);
219
+ this._parsing[text] = query.statement;
220
+ this._parseQuery(query);
221
+ this._registerQuery(query);
153
222
  }
154
223
  /**
155
224
  * Runs `txCallback` inside `BEGIN`/`COMMIT`, rolling back on error.
@@ -209,53 +278,6 @@ export class Connection {
209
278
  }
210
279
  return Ok();
211
280
  }
212
- /**
213
- * Streams query results as a `ReadableStream`, without buffering rows in memory.
214
- * Ideal for large result sets or piping straight into an HTTP response.
215
- *
216
- * @example
217
- * for await (const row of conn.stream<User>`SELECT * FROM orders`) { ... }
218
- */
219
- stream(templates, ...params) {
220
- if (this.isClosed)
221
- throw ErrConnectionClosed;
222
- let controller;
223
- const stream = new ReadableStream({
224
- start: c => {
225
- controller = c;
226
- }
227
- });
228
- if (this._reconnecting) {
229
- this._reconnecting
230
- .tap(() => this._performStream(templates, params, controller))
231
- .tapErr(err => controller.error(err));
232
- return stream;
233
- }
234
- this._performStream(templates, params, controller);
235
- return stream;
236
- }
237
- _performStream(templates, params, controller) {
238
- const { text, args } = compileSqlTemplate(templates, params);
239
- if (this.config.logLevel === 'query') {
240
- console.log(`\nQUERY: ${text}\n${args.length !== 0 ? `ARGUMENTS: [${args}]\n` : ""}`);
241
- }
242
- if (this._parsed.has(text)) {
243
- const meta = this._parsed.get(text);
244
- const query = new StreamQuery(meta.statement, text, args, controller, meta.columns, this.config.queryTimeout);
245
- this._registerBatch().registerQuery(query);
246
- return;
247
- }
248
- if (this._parsing.has(text)) {
249
- const statement = this._parsing.get(text);
250
- const query = new StreamQuery(statement, text, args, controller, null, this.config.queryTimeout);
251
- this._registerBatch().registerQuery(query);
252
- return;
253
- }
254
- const query = new StreamQuery(this._nextStatement(), text, args, controller, null, this.config.queryTimeout);
255
- this._parsing.set(text, query.statement);
256
- this._registerBatch().registerParse(query);
257
- this._registerBatch().registerQuery(query);
258
- }
259
281
  _reconnect() {
260
282
  if (this.isClosed)
261
283
  return;
@@ -272,13 +294,13 @@ export class Connection {
272
294
  }
273
295
  _performReconnect() {
274
296
  this._socket.destroy();
275
- this._parsed.clear();
276
- this._parsing.clear();
277
- this._activeBatch?.reject(ErrConnectionReconnecting);
278
- this._activeBatch = null;
279
- while (this._batchQueue.hasMore) {
280
- this._batchQueue.shift.reject(ErrConnectionReconnecting);
297
+ this._parsed = {};
298
+ this._parsing = {};
299
+ this._sheduled = false;
300
+ while (this._queue.hasMore) {
301
+ this._queue.shift.error(ErrConnectionReconnecting);
281
302
  }
303
+ this._writer.clear();
282
304
  return createSocket(this.config)
283
305
  .andThen(socket => upgradeSocket(socket, this.config))
284
306
  .andThen(socket => authorizeSocket(socket, this.config))
@@ -296,63 +318,50 @@ export class Connection {
296
318
  });
297
319
  return Future.all(futures).map(() => { });
298
320
  }
299
- _getCurrentQuery() {
300
- return this._batchQueue.current.current;
321
+ get _currentQuery() {
322
+ return this._queue.current;
301
323
  }
302
324
  _handlePacket(type, length, reader) {
303
325
  switch (type) {
304
326
  case ResponseTypes.ParseComplete:
305
- {
306
- reader.readParseComplete();
307
- }
308
- break;
327
+ case ResponseTypes.NoData:
328
+ case ResponseTypes.CloseComplete: break;
309
329
  case ResponseTypes.BindComplete:
310
330
  {
311
- reader.readBindComplete();
312
- const query = this._getCurrentQuery();
331
+ const query = this._currentQuery;
313
332
  if (query instanceof ExecuteQuery) {
314
333
  break;
315
334
  }
316
335
  if (!query.columns) {
317
- query.columns = this._parsed.get(query.text).columns;
336
+ query.columns = this._parsed[query.text].columns;
318
337
  }
319
338
  }
320
339
  break;
321
- case ResponseTypes.CloseComplete:
322
- {
323
- reader.readBindComplete();
324
- }
325
- break;
326
340
  case ResponseTypes.ParameterDescription:
327
341
  {
328
- reader.readParameterDescription();
329
- }
330
- break;
331
- case ResponseTypes.NoData:
332
- {
333
- reader.readNoData();
334
- const query = this._getCurrentQuery();
335
- const meta = { statement: query.statement, columns: [] };
336
- this._parsing.delete(query.text);
337
- this._parsed.set(query.text, meta);
342
+ const query = this._currentQuery;
343
+ const description = reader.readParameterDescription();
344
+ const meta = {
345
+ statement: query.statement,
346
+ parameters: description,
347
+ columns: EMPTY_ARRAY
348
+ };
349
+ delete this._parsing[query.text];
350
+ this._parsed[query.text] = meta;
338
351
  }
339
352
  break;
340
353
  case ResponseTypes.RowDescription:
341
354
  {
355
+ const query = this._currentQuery;
342
356
  const columns = reader.readRowDescription();
343
- const query = this._getCurrentQuery();
344
- const meta = {
345
- statement: query.statement, columns
346
- };
347
- this._parsing.delete(query.text);
348
- this._parsed.set(query.text, meta);
357
+ this._parsed[query.text].columns = columns;
349
358
  }
350
359
  break;
351
360
  case ResponseTypes.DataRow:
352
361
  {
353
- let query = this._getCurrentQuery();
362
+ let query = this._currentQuery;
354
363
  if (query instanceof ExecuteQuery) {
355
- reader.skip(length - 4);
364
+ reader.skipBytes(length);
356
365
  break;
357
366
  }
358
367
  query.push(reader.readDataRow(query.columns, this.config.int8toBigint));
@@ -360,34 +369,40 @@ export class Connection {
360
369
  break;
361
370
  case ResponseTypes.ComandComplete:
362
371
  {
363
- reader.readCommandComplete();
364
- const query = this._getCurrentQuery();
365
- query.resolve();
366
- this._batchQueue.current.next();
372
+ reader.skipBytes(length);
373
+ const query = this._currentQuery;
374
+ query.complete();
367
375
  }
368
376
  break;
369
377
  case ResponseTypes.ErrorResponse:
370
378
  {
371
379
  const error = reader.readErrorResponse();
372
380
  if (this.config.logLevel === 'error' || this.config.logLevel === 'notice' || this.config.logLevel === 'query') {
373
- console.log(`\nError: ${error}\n`);
381
+ console.log(`\n\x1b[31m┌─ ERROR ────────────────────────────────────────\x1b[0m\n`
382
+ + `\x1b[31m│\x1b[0m ${error}\n`
383
+ + `\x1b[31m└────────────────────────────────────────────────\x1b[0m\n`);
384
+ }
385
+ const query = this._currentQuery;
386
+ if (error.isParseError) {
387
+ delete this._parsing[query.text];
374
388
  }
375
- this._parsing.clear();
376
- this._batchQueue.current.reject(error);
389
+ query.error(error);
377
390
  }
378
391
  break;
379
392
  case ResponseTypes.ReadyForQuery:
380
393
  {
381
- reader.readReadyForQuery();
382
- this._batchQueue.next();
383
- this._closing && !this._hasQueries && this._closing.resolve();
394
+ reader.skipBytes(length);
395
+ this._queue.next();
396
+ this._closing && this._queue.isFree && this._closing.resolve();
384
397
  }
385
398
  break;
386
399
  case ResponseTypes.Notice:
387
400
  {
388
401
  const message = reader.readErrorResponse();
389
402
  if (this.config.logLevel === 'notice' || this.config.logLevel === 'query') {
390
- console.log(`\nError: ${message}\n`);
403
+ console.log(`\n\x1b[33m┌─ NOTICE ───────────────────────────────────────\x1b[0m\n`
404
+ + `\x1b[33m│\x1b[0m ${message}\n`
405
+ + `\x1b[33m└────────────────────────────────────────────────\x1b[0m\n`);
391
406
  }
392
407
  }
393
408
  break;
@@ -400,12 +415,13 @@ export class Connection {
400
415
  callbackSet.forEach(cb => cb(payload));
401
416
  }
402
417
  break;
403
- default: console.log('Undeclared response type: ', type);
418
+ default:
419
+ {
420
+ reader.skipBytes(length);
421
+ }
422
+ break;
404
423
  }
405
424
  }
406
- get _hasQueries() {
407
- return this._batchQueue.hasMore || this._activeBatch;
408
- }
409
425
  /** Whether the connection is alive and usable. */
410
426
  get isOpened() {
411
427
  return !this._closing && !this._closed;
@@ -423,7 +439,7 @@ export class Connection {
423
439
  if (this._closing) {
424
440
  return this._closing.future;
425
441
  }
426
- if (!this._hasQueries) {
442
+ if (this._queue.isFree) {
427
443
  this._closed = true;
428
444
  this._socket.destroy();
429
445
  return Future.resolve();
package/dist/error.d.ts CHANGED
@@ -10,8 +10,11 @@ export declare class PostgresError extends Error {
10
10
  constraint: string;
11
11
  constructor(message: string, code?: string, detail?: string, severity?: string, where?: string, hint?: string, position?: string, dataType?: string, constraint?: string);
12
12
  get isParseError(): boolean;
13
- get isDeadlock(): boolean;
13
+ get isBindError(): boolean;
14
+ get isPlanInvalidationError(): boolean;
15
+ get shouldInvalidateStatementCache(): boolean;
14
16
  get isConstraintViolation(): boolean;
17
+ get isDeadlock(): boolean;
15
18
  get isTimeout(): boolean;
16
19
  get isConnectionFailure(): boolean;
17
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,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;IAQlC,IAAI,YAAY,IAAI,OAAO,CAE1B;IAID,IAAI,UAAU,IAAI,OAAO,CAExB;IAID,IAAI,qBAAqB,IAAI,OAAO,CAEnC;IAGD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAGD,IAAI,mBAAmB,IAAI,OAAO,CAEjC;CACJ;AAED,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"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,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"}
package/dist/error.js CHANGED
@@ -12,23 +12,31 @@ export class PostgresError extends Error {
12
12
  this.constraint = constraint;
13
13
  this.name = "PostgresError";
14
14
  }
15
- // Parse error
16
15
  get isParseError() {
17
- return this.code.startsWith('42');
16
+ return (this.code.startsWith('42') ||
17
+ this.code === '26000');
18
18
  }
19
- // Execute error
20
- get isDeadlock() {
21
- return this.code === '40P01';
19
+ get isBindError() {
20
+ return (this.code.startsWith('22') ||
21
+ this.code === '0A000');
22
+ }
23
+ get isPlanInvalidationError() {
24
+ return this.code === '0A000' || this.code === '42P05';
25
+ }
26
+ get shouldInvalidateStatementCache() {
27
+ return this.isParseError || this.isBindError || this.isPlanInvalidationError;
22
28
  }
23
- // Execute error
24
29
  get isConstraintViolation() {
25
30
  return this.code.startsWith('23');
26
31
  }
32
+ get isDeadlock() {
33
+ return this.code === '40P01';
34
+ }
27
35
  get isTimeout() {
28
36
  return this.code === '57014';
29
37
  }
30
38
  get isConnectionFailure() {
31
- return this.code.startsWith('08') || this.code.startsWith('57') && this.code !== '57014';
39
+ return this.code.startsWith('08') || (this.code.startsWith('57') && this.code !== '57014');
32
40
  }
33
41
  }
34
42
  export const ErrNonceMismatch = new PostgresError("Protocol violation: server nonce doesn't match client nonce");
package/dist/pool.d.ts CHANGED
@@ -57,7 +57,7 @@ export declare class Pool {
57
57
  * @example
58
58
  * for await (const row of pool.stream<User>`SELECT * FROM orders`) { ... }
59
59
  */
60
- stream<T extends Row>(templates: TemplateStringsArray, ...args: any[]): ReadableStream<T>;
60
+ stream<T extends Row>(templates: TemplateStringsArray, ...params: any[]): ReadableStream<T>;
61
61
  /** Sends a `pg_notify` message on `channelName` (payload ≤ 8000 bytes). */
62
62
  notify(channelName: string, payload?: string): Future<void, PostgresError>;
63
63
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,OAAO,EAAS,MAAM,EAAM,MAAM,eAAe,CAAC;AAClD,OAAO,EAAiB,aAAa,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,EAAc,iBAAiB,EAAE,GAAG,EAAU,MAAM,SAAS,CAAC;AAGrE;;;;;;;;GAQG;AACH,qBAAa,IAAI;IACb,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,SAAS,CAAO;gBAEZ,MAAM,EAAE,iBAAiB;IAOrC;;;OAGG;IACH,OAAO;IA2BP;;;;;OAKG;IACH,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC;IAUnD,wFAAwF;IACxF,OAAO,CAAC,IAAI,EAAE,UAAU;IAoBxB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;IAU7D;;;;;OAKG;IACH,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;IAuBpE,qEAAqE;IACrE,OAAO,CAAC,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAuBzD;;;;;OAKG;IACH,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC;IAoCzF,2EAA2E;IAC3E,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW;IAQhD;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;IAY3D,kCAAkC;IAClC,IAAI,IAAI,WAEP;IAGD,iDAAiD;IACjD,IAAI,KAAK,WAER;IAGD;;OAEG;IACH,KAAK;CAiBR"}
1
+ {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,OAAO,EAAS,MAAM,EAAM,MAAM,eAAe,CAAC;AAClD,OAAO,EAAiB,aAAa,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,EAAc,iBAAiB,EAAE,GAAG,EAAU,MAAM,SAAS,CAAC;AAIrE;;;;;;;;GAQG;AACH,qBAAa,IAAI;IACb,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,SAAS,CAAO;gBAEZ,MAAM,EAAE,iBAAiB;IAOrC;;;OAGG;IACH,OAAO;IA2BP;;;;;OAKG;IACH,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC;IAUnD,wFAAwF;IACxF,OAAO,CAAC,IAAI,EAAE,UAAU;IAoBxB;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;IAU7D;;;;;OAKG;IACH,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE;IAuBpE,qEAAqE;IACrE,OAAO,CAAC,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAuBzD;;;;;OAKG;IACH,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC;IAsC3F,2EAA2E;IAC3E,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW;IAQhD;;;;;;;OAOG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI;IAY3D,kCAAkC;IAClC,IAAI,IAAI,WAEP;IAGD,iDAAiD;IACjD,IAAI,KAAK,WAER;IAGD;;OAEG;IACH,KAAK;CAiBR"}
package/dist/pool.js CHANGED
@@ -2,6 +2,7 @@ import { Connection } from "./connection";
2
2
  import { Queue, RingQueue } from "./queue";
3
3
  import { Begin, Future, Ok } from "fluent-future";
4
4
  import { ErrPoolClosed } from "./error";
5
+ import { compileSqlTemplate } from "./utils";
5
6
  /**
6
7
  * Connection pool and the main entry point for Pgtx.
7
8
  *
@@ -134,7 +135,7 @@ export class Pool {
134
135
  * @example
135
136
  * for await (const row of pool.stream<User>`SELECT * FROM orders`) { ... }
136
137
  */
137
- stream(templates, ...args) {
138
+ stream(templates, ...params) {
138
139
  if (!this._isOpened)
139
140
  throw ErrPoolClosed;
140
141
  while (this._available.hasMore) {
@@ -144,7 +145,7 @@ export class Pool {
144
145
  continue;
145
146
  }
146
147
  this._available.push(conn);
147
- return conn.stream(templates, ...args);
148
+ return conn.stream(templates, ...params);
148
149
  }
149
150
  let controller;
150
151
  const stream = new ReadableStream({
@@ -155,7 +156,8 @@ export class Pool {
155
156
  this.acquire()
156
157
  .tap(conn => {
157
158
  this.release(conn);
158
- conn['_performStream'](templates, args, controller);
159
+ const { text, args } = compileSqlTemplate(templates, params);
160
+ conn['_performStream'](text, args, controller);
159
161
  })
160
162
  .catch(err => {
161
163
  controller.error(err);