@m2k-5f/pgtx 2.7.2 → 2.8.0
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 +65 -37
- 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 +231 -175
- package/dist/error.d.ts +6 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +26 -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 +107 -11
- package/dist/protocol/connection-request-writer.d.ts.map +1 -1
- package/dist/protocol/connection-request-writer.js +442 -48
- package/dist/protocol/connection-response-reader.d.ts +75 -30
- package/dist/protocol/connection-response-reader.d.ts.map +1 -1
- package/dist/protocol/connection-response-reader.js +285 -289
- package/dist/protocol/constants.d.ts +37 -30
- package/dist/protocol/constants.d.ts.map +1 -1
- package/dist/protocol/constants.js +43 -37
- package/dist/protocol/socket-authorization.d.ts.map +1 -1
- package/dist/protocol/socket-authorization.js +3 -3
- 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/protocol/types.d.ts +14 -0
- package/dist/protocol/types.d.ts.map +1 -0
- package/dist/protocol/types.js +264 -0
- package/dist/query.d.ts +34 -24
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +45 -30
- 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,16 +1,15 @@
|
|
|
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";
|
|
7
|
-
import { CollectQuery, StreamQuery, ExecuteQuery } from "./query";
|
|
6
|
+
import { CollectQuery, StreamQuery, ExecuteQuery, ParseQuery } 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,50 @@ 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._writer.hasMore && this._socket.write(this._writer);
|
|
43
|
+
this._writer.clear();
|
|
44
|
+
this._sheduled = false;
|
|
45
|
+
}
|
|
46
|
+
_registerQuery(query) {
|
|
47
|
+
this._registerShedule();
|
|
48
|
+
if (query instanceof ParseQuery) {
|
|
49
|
+
this._writer
|
|
50
|
+
.writeParse(query.meta.statement, query.text)
|
|
51
|
+
.writeDescribe(DescribeType.Statement, query.meta.statement)
|
|
52
|
+
.writeSync();
|
|
53
|
+
this._queue.push(query);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const err = this._writer
|
|
57
|
+
.writeBind("", query.meta, query.args);
|
|
58
|
+
if (err)
|
|
59
|
+
return err;
|
|
60
|
+
this._writer
|
|
61
|
+
.writeExecute("")
|
|
62
|
+
.writeSync();
|
|
63
|
+
this._queue.push(query);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
33
66
|
constructor(socket, config) {
|
|
34
|
-
this.
|
|
67
|
+
this._writer = ConnectionRequestBuffer.new(65536);
|
|
68
|
+
this._sheduled = false;
|
|
69
|
+
this._queue = new Queue();
|
|
70
|
+
this._executingCounter = 0;
|
|
35
71
|
this._closing = null;
|
|
36
72
|
this._closed = false;
|
|
37
73
|
this._reconnecting = null;
|
|
38
|
-
this.
|
|
39
|
-
this.
|
|
40
|
-
this._parsed = new Map();
|
|
41
|
-
this._parsing = new Map();
|
|
74
|
+
this._parsed = {};
|
|
75
|
+
this._parsing = {};
|
|
42
76
|
this._listeningCallbacks = new Map();
|
|
43
77
|
this._stmtCounter = 0;
|
|
44
78
|
this.config = config;
|
|
@@ -54,7 +88,7 @@ export class Connection {
|
|
|
54
88
|
logLevel: config.logLevel || 'error',
|
|
55
89
|
int8toBigint: config.int8toBigint || false,
|
|
56
90
|
queryTimeout: config.queryTimeout || 30000,
|
|
57
|
-
syncShedule: config.syncShedule || '
|
|
91
|
+
syncShedule: config.syncShedule || 'Immediate',
|
|
58
92
|
ssl: config.caPath ? 'require' : (config.ssl || 'prefer')
|
|
59
93
|
};
|
|
60
94
|
return createSocket(conf)
|
|
@@ -62,22 +96,6 @@ export class Connection {
|
|
|
62
96
|
.andThen(socket => authorizeSocket(socket, conf))
|
|
63
97
|
.andThen(socket => Ok(new Connection(socket, conf)));
|
|
64
98
|
}
|
|
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
99
|
/**
|
|
82
100
|
* Runs a query, binding template values as `$1, $2, ...`.
|
|
83
101
|
* Parameterized queries are cached as prepared statements.
|
|
@@ -88,32 +106,47 @@ export class Connection {
|
|
|
88
106
|
query(templates, ...params) {
|
|
89
107
|
if (this.isClosed)
|
|
90
108
|
return Future.reject(ErrConnectionClosed);
|
|
109
|
+
const { text, args } = compileSqlTemplate(templates, params);
|
|
110
|
+
const resolvers = Future.withResolvers();
|
|
91
111
|
if (this._reconnecting)
|
|
92
|
-
return this._reconnecting.andThen(() => this._performQuery(
|
|
93
|
-
return this._performQuery(
|
|
112
|
+
return this._reconnecting.andThen(() => this._performQuery(text, args, resolvers));
|
|
113
|
+
return this._performQuery(text, args, resolvers);
|
|
94
114
|
}
|
|
95
|
-
_performQuery(
|
|
96
|
-
const { text, args } = compileSqlTemplate(templates, params);
|
|
115
|
+
_performQuery(text, args, resolvers) {
|
|
97
116
|
if (this.config.logLevel === 'query') {
|
|
98
|
-
console.log(`\
|
|
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`);
|
|
99
121
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this.
|
|
104
|
-
|
|
122
|
+
this._executingCounter++;
|
|
123
|
+
const parsed = this._parsed[text];
|
|
124
|
+
if (parsed) {
|
|
125
|
+
const query = new CollectQuery(parsed, text, args, parsed.columns, resolvers, this.config.queryTimeout);
|
|
126
|
+
const err = this._registerQuery(query);
|
|
127
|
+
if (err) {
|
|
128
|
+
this._executingCounter--;
|
|
129
|
+
query.error(err);
|
|
130
|
+
return query.resolvers.future;
|
|
131
|
+
}
|
|
132
|
+
return query.resolvers.future;
|
|
105
133
|
}
|
|
106
|
-
if (this._parsing
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
this.
|
|
110
|
-
return query.future;
|
|
134
|
+
if (!this._parsing[text]) {
|
|
135
|
+
const parseQuery = new ParseQuery({ statement: this._nextStatement(), columns: EMPTY_ARRAY, parameters: EMPTY_ARRAY }, text, Future.withResolvers(), this.config.queryTimeout);
|
|
136
|
+
this._registerQuery(parseQuery);
|
|
137
|
+
this._parsing[text] = parseQuery.resolvers.future;
|
|
111
138
|
}
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
139
|
+
const parsing = this._parsing[text];
|
|
140
|
+
return parsing.andThen(meta => {
|
|
141
|
+
const query = new CollectQuery(meta, text, args, meta.columns, resolvers, this.config.queryTimeout);
|
|
142
|
+
const err = this._registerQuery(query);
|
|
143
|
+
if (err) {
|
|
144
|
+
this._executingCounter--;
|
|
145
|
+
query.error(err);
|
|
146
|
+
return query.resolvers.future;
|
|
147
|
+
}
|
|
148
|
+
return query.resolvers.future;
|
|
149
|
+
});
|
|
117
150
|
}
|
|
118
151
|
/**
|
|
119
152
|
* Like {@link query}, but for statements that don't return rows (INSERT/UPDATE/DDL/etc).
|
|
@@ -124,32 +157,111 @@ export class Connection {
|
|
|
124
157
|
execute(templates, ...params) {
|
|
125
158
|
if (this.isClosed)
|
|
126
159
|
return Future.reject(ErrConnectionClosed);
|
|
160
|
+
const { text, args } = compileSqlTemplate(templates, params);
|
|
161
|
+
const resolvers = Future.withResolvers();
|
|
127
162
|
if (this._reconnecting)
|
|
128
|
-
return this._reconnecting.andThen(() => this._performExecute(
|
|
129
|
-
return this._performExecute(
|
|
163
|
+
return this._reconnecting.andThen(() => this._performExecute(text, args, resolvers));
|
|
164
|
+
return this._performExecute(text, args, resolvers);
|
|
165
|
+
}
|
|
166
|
+
_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];
|
|
175
|
+
if (parsed) {
|
|
176
|
+
const query = new ExecuteQuery(parsed, text, args, resolvers, this.config.queryTimeout);
|
|
177
|
+
const err = this._registerQuery(query);
|
|
178
|
+
if (err) {
|
|
179
|
+
this._executingCounter--;
|
|
180
|
+
query.error(err);
|
|
181
|
+
return query.resolvers.future;
|
|
182
|
+
}
|
|
183
|
+
return query.resolvers.future;
|
|
184
|
+
}
|
|
185
|
+
if (!this._parsing[text]) {
|
|
186
|
+
const parseQuery = new ParseQuery({ statement: this._nextStatement(), columns: EMPTY_ARRAY, parameters: EMPTY_ARRAY }, text, Future.withResolvers(), this.config.queryTimeout);
|
|
187
|
+
this._registerQuery(parseQuery);
|
|
188
|
+
this._parsing[text] = parseQuery.resolvers.future;
|
|
189
|
+
}
|
|
190
|
+
const parsing = this._parsing[text];
|
|
191
|
+
return parsing.andThen(meta => {
|
|
192
|
+
const query = new ExecuteQuery(meta, text, args, resolvers, this.config.queryTimeout);
|
|
193
|
+
const err = this._registerQuery(query);
|
|
194
|
+
if (err) {
|
|
195
|
+
this._executingCounter--;
|
|
196
|
+
query.error(err);
|
|
197
|
+
return query.resolvers.future;
|
|
198
|
+
}
|
|
199
|
+
return query.resolvers.future;
|
|
200
|
+
});
|
|
130
201
|
}
|
|
131
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Streams query results as a `ReadableStream`, without buffering rows in memory.
|
|
204
|
+
* Ideal for large result sets or piping straight into an HTTP response.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* for await (const row of conn.stream<User>`SELECT * FROM orders`) { ... }
|
|
208
|
+
*/
|
|
209
|
+
stream(templates, ...params) {
|
|
210
|
+
if (this.isClosed)
|
|
211
|
+
throw ErrConnectionClosed;
|
|
132
212
|
const { text, args } = compileSqlTemplate(templates, params);
|
|
213
|
+
let controller;
|
|
214
|
+
const stream = new ReadableStream({
|
|
215
|
+
start: c => {
|
|
216
|
+
controller = c;
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
if (this._reconnecting) {
|
|
220
|
+
this._reconnecting
|
|
221
|
+
.tap(() => this._performStream(text, args, controller))
|
|
222
|
+
.tapErr(err => controller.error(err));
|
|
223
|
+
return stream;
|
|
224
|
+
}
|
|
225
|
+
this._performStream(text, args, controller);
|
|
226
|
+
return stream;
|
|
227
|
+
}
|
|
228
|
+
_performStream(text, args, controller) {
|
|
133
229
|
if (this.config.logLevel === 'query') {
|
|
134
|
-
console.log(`\
|
|
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`);
|
|
135
234
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.
|
|
140
|
-
|
|
235
|
+
this._executingCounter++;
|
|
236
|
+
const parsed = this._parsed[text];
|
|
237
|
+
if (parsed) {
|
|
238
|
+
const query = new StreamQuery(parsed, text, args, controller, parsed.columns, this.config.queryTimeout);
|
|
239
|
+
const err = this._registerQuery(query);
|
|
240
|
+
if (err) {
|
|
241
|
+
this._executingCounter--;
|
|
242
|
+
controller.error(err);
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
141
245
|
}
|
|
142
|
-
if (this._parsing
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
this.
|
|
146
|
-
return query.future;
|
|
246
|
+
if (!this._parsing[text]) {
|
|
247
|
+
const parseQuery = new ParseQuery({ statement: this._nextStatement(), columns: EMPTY_ARRAY, parameters: EMPTY_ARRAY }, text, Future.withResolvers(), this.config.queryTimeout);
|
|
248
|
+
this._registerQuery(parseQuery);
|
|
249
|
+
this._parsing[text] = parseQuery.resolvers.future;
|
|
147
250
|
}
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
251
|
+
const parsing = this._parsing[text];
|
|
252
|
+
parsing
|
|
253
|
+
.tap(meta => {
|
|
254
|
+
const query = new StreamQuery(meta, text, args, controller, null, this.config.queryTimeout);
|
|
255
|
+
const err = this._registerQuery(query);
|
|
256
|
+
if (err) {
|
|
257
|
+
this._executingCounter--;
|
|
258
|
+
controller.error(err);
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
.tapErr(err => {
|
|
262
|
+
controller.error(err);
|
|
263
|
+
})
|
|
264
|
+
.recover();
|
|
153
265
|
}
|
|
154
266
|
/**
|
|
155
267
|
* Runs `txCallback` inside `BEGIN`/`COMMIT`, rolling back on error.
|
|
@@ -209,53 +321,6 @@ export class Connection {
|
|
|
209
321
|
}
|
|
210
322
|
return Ok();
|
|
211
323
|
}
|
|
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
324
|
_reconnect() {
|
|
260
325
|
if (this.isClosed)
|
|
261
326
|
return;
|
|
@@ -272,13 +337,14 @@ export class Connection {
|
|
|
272
337
|
}
|
|
273
338
|
_performReconnect() {
|
|
274
339
|
this._socket.destroy();
|
|
275
|
-
this._parsed
|
|
276
|
-
this._parsing
|
|
277
|
-
this.
|
|
278
|
-
this.
|
|
279
|
-
while (this.
|
|
280
|
-
this.
|
|
340
|
+
this._parsed = {};
|
|
341
|
+
this._parsing = {};
|
|
342
|
+
this._sheduled = false;
|
|
343
|
+
this._executingCounter = 0;
|
|
344
|
+
while (this._queue.hasMore) {
|
|
345
|
+
this._queue.shift.error(ErrConnectionReconnecting);
|
|
281
346
|
}
|
|
347
|
+
this._writer.clear();
|
|
282
348
|
return createSocket(this.config)
|
|
283
349
|
.andThen(socket => upgradeSocket(socket, this.config))
|
|
284
350
|
.andThen(socket => authorizeSocket(socket, this.config))
|
|
@@ -296,98 +362,87 @@ export class Connection {
|
|
|
296
362
|
});
|
|
297
363
|
return Future.all(futures).map(() => { });
|
|
298
364
|
}
|
|
299
|
-
|
|
300
|
-
return this.
|
|
365
|
+
get _currentQuery() {
|
|
366
|
+
return this._queue.current;
|
|
301
367
|
}
|
|
302
368
|
_handlePacket(type, length, reader) {
|
|
303
369
|
switch (type) {
|
|
304
370
|
case ResponseTypes.ParseComplete:
|
|
305
|
-
{
|
|
306
|
-
reader.readParseComplete();
|
|
307
|
-
}
|
|
308
|
-
break;
|
|
309
371
|
case ResponseTypes.BindComplete:
|
|
310
|
-
|
|
311
|
-
reader.readBindComplete();
|
|
312
|
-
const query = this._getCurrentQuery();
|
|
313
|
-
if (query instanceof ExecuteQuery) {
|
|
314
|
-
break;
|
|
315
|
-
}
|
|
316
|
-
if (!query.columns) {
|
|
317
|
-
query.columns = this._parsed.get(query.text).columns;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
break;
|
|
321
|
-
case ResponseTypes.CloseComplete:
|
|
322
|
-
{
|
|
323
|
-
reader.readBindComplete();
|
|
324
|
-
}
|
|
325
|
-
break;
|
|
372
|
+
case ResponseTypes.CloseComplete: break;
|
|
326
373
|
case ResponseTypes.ParameterDescription:
|
|
327
374
|
{
|
|
328
|
-
|
|
375
|
+
const query = this._currentQuery;
|
|
376
|
+
const parameters = reader.readParameterDescription();
|
|
377
|
+
query.meta.parameters = parameters;
|
|
329
378
|
}
|
|
330
379
|
break;
|
|
331
|
-
case ResponseTypes.
|
|
380
|
+
case ResponseTypes.RowDescription:
|
|
332
381
|
{
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
this._parsing
|
|
337
|
-
this._parsed
|
|
382
|
+
const query = this._currentQuery;
|
|
383
|
+
const columns = reader.readRowDescription();
|
|
384
|
+
query.meta.columns = columns;
|
|
385
|
+
delete this._parsing[query.text];
|
|
386
|
+
this._parsed[query.text] = query.meta;
|
|
387
|
+
query.complete();
|
|
338
388
|
}
|
|
339
389
|
break;
|
|
340
|
-
case ResponseTypes.
|
|
390
|
+
case ResponseTypes.NoData:
|
|
341
391
|
{
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
};
|
|
347
|
-
this._parsing.delete(query.text);
|
|
348
|
-
this._parsed.set(query.text, meta);
|
|
392
|
+
const query = this._currentQuery;
|
|
393
|
+
delete this._parsing[query.text];
|
|
394
|
+
this._parsed[query.text] = query.meta;
|
|
395
|
+
query.complete();
|
|
349
396
|
}
|
|
350
397
|
break;
|
|
351
398
|
case ResponseTypes.DataRow:
|
|
352
399
|
{
|
|
353
|
-
let query = this.
|
|
400
|
+
let query = this._currentQuery;
|
|
354
401
|
if (query instanceof ExecuteQuery) {
|
|
355
|
-
reader.
|
|
402
|
+
reader.skipBytes(length);
|
|
356
403
|
break;
|
|
357
404
|
}
|
|
358
|
-
query.push(reader.readDataRow(query.columns, this.config.int8toBigint));
|
|
405
|
+
query.push(reader.readDataRow(query.meta.columns, this.config.int8toBigint));
|
|
359
406
|
}
|
|
360
407
|
break;
|
|
361
408
|
case ResponseTypes.ComandComplete:
|
|
362
409
|
{
|
|
363
|
-
reader.
|
|
364
|
-
const query = this.
|
|
365
|
-
query.
|
|
366
|
-
this.
|
|
410
|
+
reader.skipBytes(length);
|
|
411
|
+
const query = this._currentQuery;
|
|
412
|
+
query.complete();
|
|
413
|
+
this._executingCounter--;
|
|
367
414
|
}
|
|
368
415
|
break;
|
|
369
416
|
case ResponseTypes.ErrorResponse:
|
|
370
417
|
{
|
|
371
418
|
const error = reader.readErrorResponse();
|
|
372
419
|
if (this.config.logLevel === 'error' || this.config.logLevel === 'notice' || this.config.logLevel === 'query') {
|
|
373
|
-
console.log(`\
|
|
420
|
+
console.log(`\n\x1b[31m┌─ ERROR ────────────────────────────────────────\x1b[0m\n`
|
|
421
|
+
+ `\x1b[31m│\x1b[0m ${error}\n`
|
|
422
|
+
+ `\x1b[31m└────────────────────────────────────────────────\x1b[0m\n`);
|
|
423
|
+
}
|
|
424
|
+
const query = this._currentQuery;
|
|
425
|
+
if (error.isParseError) {
|
|
426
|
+
delete this._parsing[query.text];
|
|
374
427
|
}
|
|
375
|
-
|
|
376
|
-
this.
|
|
428
|
+
query.error(error);
|
|
429
|
+
this._executingCounter--;
|
|
377
430
|
}
|
|
378
431
|
break;
|
|
379
432
|
case ResponseTypes.ReadyForQuery:
|
|
380
433
|
{
|
|
381
|
-
reader.
|
|
382
|
-
this.
|
|
383
|
-
this._closing && !this.
|
|
434
|
+
reader.skipBytes(length);
|
|
435
|
+
this._queue.next();
|
|
436
|
+
this._closing && !this._executingCounter && this._closing.resolve();
|
|
384
437
|
}
|
|
385
438
|
break;
|
|
386
439
|
case ResponseTypes.Notice:
|
|
387
440
|
{
|
|
388
441
|
const message = reader.readErrorResponse();
|
|
389
442
|
if (this.config.logLevel === 'notice' || this.config.logLevel === 'query') {
|
|
390
|
-
console.log(`\
|
|
443
|
+
console.log(`\n\x1b[33m┌─ NOTICE ───────────────────────────────────────\x1b[0m\n`
|
|
444
|
+
+ `\x1b[33m│\x1b[0m ${message}\n`
|
|
445
|
+
+ `\x1b[33m└────────────────────────────────────────────────\x1b[0m\n`);
|
|
391
446
|
}
|
|
392
447
|
}
|
|
393
448
|
break;
|
|
@@ -400,12 +455,13 @@ export class Connection {
|
|
|
400
455
|
callbackSet.forEach(cb => cb(payload));
|
|
401
456
|
}
|
|
402
457
|
break;
|
|
403
|
-
default:
|
|
458
|
+
default:
|
|
459
|
+
{
|
|
460
|
+
reader.skipBytes(length);
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
404
463
|
}
|
|
405
464
|
}
|
|
406
|
-
get _hasQueries() {
|
|
407
|
-
return this._batchQueue.hasMore || this._activeBatch;
|
|
408
|
-
}
|
|
409
465
|
/** Whether the connection is alive and usable. */
|
|
410
466
|
get isOpened() {
|
|
411
467
|
return !this._closing && !this._closed;
|
|
@@ -423,7 +479,7 @@ export class Connection {
|
|
|
423
479
|
if (this._closing) {
|
|
424
480
|
return this._closing.future;
|
|
425
481
|
}
|
|
426
|
-
if (!this.
|
|
482
|
+
if (!this._executingCounter) {
|
|
427
483
|
this._closed = true;
|
|
428
484
|
this._socket.destroy();
|
|
429
485
|
return Future.resolve();
|
package/dist/error.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DataTypeOid } from "./protocol/constants";
|
|
1
2
|
export declare class PostgresError extends Error {
|
|
2
3
|
message: string;
|
|
3
4
|
code: string;
|
|
@@ -10,8 +11,11 @@ export declare class PostgresError extends Error {
|
|
|
10
11
|
constraint: string;
|
|
11
12
|
constructor(message: string, code?: string, detail?: string, severity?: string, where?: string, hint?: string, position?: string, dataType?: string, constraint?: string);
|
|
12
13
|
get isParseError(): boolean;
|
|
13
|
-
get
|
|
14
|
+
get isBindError(): boolean;
|
|
15
|
+
get isPlanInvalidationError(): boolean;
|
|
16
|
+
get shouldInvalidateStatementCache(): boolean;
|
|
14
17
|
get isConstraintViolation(): boolean;
|
|
18
|
+
get isDeadlock(): boolean;
|
|
15
19
|
get isTimeout(): boolean;
|
|
16
20
|
get isConnectionFailure(): boolean;
|
|
17
21
|
}
|
|
@@ -27,4 +31,5 @@ export declare const ErrSSLDenied: PostgresError;
|
|
|
27
31
|
export declare const ErrDatabaseNotFound: PostgresError;
|
|
28
32
|
export declare const ErrUntrustedCertificate: PostgresError;
|
|
29
33
|
export declare const ErrCertificateFileNotFound: PostgresError;
|
|
34
|
+
export declare function createBindTypeError(index: number, expectedType: DataTypeOid, actualValue: unknown): PostgresError;
|
|
30
35
|
//# sourceMappingURL=error.d.ts.map
|
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,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"}
|
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");
|
|
@@ -43,3 +51,14 @@ export const ErrSSLDenied = new PostgresError("SSL is required but server denied
|
|
|
43
51
|
export const ErrDatabaseNotFound = new PostgresError('Database with that dsn not found');
|
|
44
52
|
export const ErrUntrustedCertificate = new PostgresError("Database SSL certificate is untrusted or self-signed");
|
|
45
53
|
export const ErrCertificateFileNotFound = new PostgresError("The SSL certificate file specified in caPath was not found");
|
|
54
|
+
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
|
+
);
|
|
64
|
+
}
|
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"}
|