@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.
- package/README.md +48 -31
- package/dist/batch.d.ts +4 -1
- package/dist/batch.d.ts.map +1 -1
- package/dist/batch.js +14 -7
- package/dist/clauses/fragment.clause.js +1 -1
- package/dist/connection.d.ts +17 -16
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +182 -166
- package/dist/error.d.ts +4 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +15 -7
- package/dist/pool.d.ts +1 -1
- package/dist/pool.d.ts.map +1 -1
- package/dist/pool.js +5 -3
- package/dist/protocol/connection-request-writer.d.ts +24 -11
- package/dist/protocol/connection-request-writer.d.ts.map +1 -1
- package/dist/protocol/connection-request-writer.js +217 -47
- package/dist/protocol/connection-response-reader.d.ts +5 -15
- package/dist/protocol/connection-response-reader.d.ts.map +1 -1
- package/dist/protocol/connection-response-reader.js +116 -76
- package/dist/protocol/constants.d.ts +37 -30
- package/dist/protocol/constants.d.ts.map +1 -1
- package/dist/protocol/constants.js +35 -29
- package/dist/protocol/socket-authorization.d.ts.map +1 -1
- package/dist/protocol/socket-authorization.js +7 -7
- package/dist/protocol/socket-connector.d.ts +4 -4
- package/dist/protocol/socket-connector.d.ts.map +1 -1
- package/dist/protocol/socket-connector.js +2 -2
- package/dist/query.d.ts +16 -20
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +15 -22
- package/dist/queue.d.ts +1 -0
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +1 -0
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/template-compiler.d.ts +5 -2
- package/dist/utils/template-compiler.d.ts.map +1 -1
- package/dist/utils/template-compiler.js +4 -1
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +73 -0
- package/package.json +2 -2
package/dist/connection.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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.
|
|
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.
|
|
39
|
-
this.
|
|
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 || '
|
|
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(
|
|
93
|
-
return this._performQuery(
|
|
105
|
+
return this._reconnecting.andThen(() => this._performQuery(text, args, resolvers));
|
|
106
|
+
return this._performQuery(text, args, resolvers);
|
|
94
107
|
}
|
|
95
|
-
_performQuery(
|
|
96
|
-
const { text, args } = compileSqlTemplate(templates, params);
|
|
108
|
+
_performQuery(text, args, resolvers) {
|
|
97
109
|
if (this.config.logLevel === 'query') {
|
|
98
|
-
console.log(`\
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
const query = new CollectQuery(
|
|
103
|
-
this.
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
const query = new CollectQuery(
|
|
109
|
-
this.
|
|
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
|
|
114
|
-
this.
|
|
115
|
-
this.
|
|
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(
|
|
129
|
-
return this._performExecute(
|
|
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
|
-
|
|
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(`\
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
const query = new
|
|
139
|
-
this.
|
|
140
|
-
return
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
const query = new
|
|
145
|
-
this.
|
|
146
|
-
return
|
|
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
|
|
149
|
-
this._parsing
|
|
150
|
-
this.
|
|
151
|
-
this.
|
|
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
|
|
276
|
-
this._parsing
|
|
277
|
-
this.
|
|
278
|
-
this.
|
|
279
|
-
|
|
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
|
-
|
|
300
|
-
return this.
|
|
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
|
-
|
|
307
|
-
}
|
|
308
|
-
break;
|
|
327
|
+
case ResponseTypes.NoData:
|
|
328
|
+
case ResponseTypes.CloseComplete: break;
|
|
309
329
|
case ResponseTypes.BindComplete:
|
|
310
330
|
{
|
|
311
|
-
|
|
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
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
this.
|
|
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
|
-
|
|
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.
|
|
362
|
+
let query = this._currentQuery;
|
|
354
363
|
if (query instanceof ExecuteQuery) {
|
|
355
|
-
reader.
|
|
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.
|
|
364
|
-
const query = this.
|
|
365
|
-
query.
|
|
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(`\
|
|
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
|
-
|
|
376
|
-
this._batchQueue.current.reject(error);
|
|
389
|
+
query.error(error);
|
|
377
390
|
}
|
|
378
391
|
break;
|
|
379
392
|
case ResponseTypes.ReadyForQuery:
|
|
380
393
|
{
|
|
381
|
-
reader.
|
|
382
|
-
this.
|
|
383
|
-
this._closing &&
|
|
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(`\
|
|
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:
|
|
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 (
|
|
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
|
|
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
|
}
|
package/dist/error.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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, ...
|
|
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
|
/**
|
package/dist/pool.d.ts.map
CHANGED
|
@@ -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;
|
|
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, ...
|
|
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, ...
|
|
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
|
-
|
|
159
|
+
const { text, args } = compileSqlTemplate(templates, params);
|
|
160
|
+
conn['_performStream'](text, args, controller);
|
|
159
161
|
})
|
|
160
162
|
.catch(err => {
|
|
161
163
|
controller.error(err);
|