neonctl 2.28.0 → 2.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -71
- package/dist/analytics.js +35 -33
- package/dist/api.js +34 -34
- package/dist/auth.js +50 -44
- package/dist/cli.js +2 -2
- package/dist/commands/auth.js +58 -52
- package/dist/commands/bootstrap.js +115 -157
- package/dist/commands/branches.js +154 -147
- package/dist/commands/bucket.js +124 -118
- package/dist/commands/checkout.js +49 -49
- package/dist/commands/config.js +212 -88
- package/dist/commands/connection_string.js +62 -62
- package/dist/commands/data_api.js +96 -96
- package/dist/commands/databases.js +23 -23
- package/dist/commands/deploy.js +12 -12
- package/dist/commands/dev.js +114 -114
- package/dist/commands/env.js +43 -43
- package/dist/commands/functions.js +97 -98
- package/dist/commands/index.js +26 -26
- package/dist/commands/init.js +23 -22
- package/dist/commands/ip_allow.js +29 -29
- package/dist/commands/link.js +223 -166
- package/dist/commands/neon_auth.js +381 -363
- package/dist/commands/operations.js +11 -11
- package/dist/commands/orgs.js +8 -8
- package/dist/commands/projects.js +101 -99
- package/dist/commands/psql.js +31 -31
- package/dist/commands/roles.js +21 -21
- package/dist/commands/schema_diff.js +23 -23
- package/dist/commands/set_context.js +17 -17
- package/dist/commands/status.js +17 -17
- package/dist/commands/user.js +5 -5
- package/dist/commands/vpc_endpoints.js +50 -50
- package/dist/config.js +7 -7
- package/dist/config_format.js +5 -5
- package/dist/context.js +23 -16
- package/dist/current_branch_fast_path.js +6 -6
- package/dist/dev/env.js +34 -34
- package/dist/dev/functions.js +4 -4
- package/dist/dev/inputs.js +6 -6
- package/dist/dev/runtime.js +25 -25
- package/dist/env.js +14 -14
- package/dist/env_file.js +13 -13
- package/dist/errors.js +19 -19
- package/dist/functions_api.js +10 -10
- package/dist/help.js +15 -15
- package/dist/index.js +94 -92
- package/dist/log.js +2 -2
- package/dist/pkg.js +5 -5
- package/dist/psql/cli.js +4 -2
- package/dist/psql/command/cmd_cond.js +61 -61
- package/dist/psql/command/cmd_connect.js +159 -154
- package/dist/psql/command/cmd_copy.js +107 -97
- package/dist/psql/command/cmd_describe.js +368 -363
- package/dist/psql/command/cmd_format.js +276 -263
- package/dist/psql/command/cmd_io.js +269 -263
- package/dist/psql/command/cmd_lo.js +74 -66
- package/dist/psql/command/cmd_meta.js +148 -148
- package/dist/psql/command/cmd_misc.js +17 -17
- package/dist/psql/command/cmd_pipeline.js +142 -135
- package/dist/psql/command/cmd_restrict.js +25 -25
- package/dist/psql/command/cmd_show.js +183 -168
- package/dist/psql/command/dispatch.js +26 -26
- package/dist/psql/command/shared.js +14 -14
- package/dist/psql/complete/filenames.js +16 -16
- package/dist/psql/complete/index.js +4 -4
- package/dist/psql/complete/matcher.js +33 -32
- package/dist/psql/complete/psqlVars.js +173 -173
- package/dist/psql/complete/queries.js +5 -3
- package/dist/psql/complete/rules.js +900 -863
- package/dist/psql/core/common.js +136 -133
- package/dist/psql/core/help.js +343 -343
- package/dist/psql/core/mainloop.js +160 -153
- package/dist/psql/core/prompt.js +126 -123
- package/dist/psql/core/settings.js +111 -111
- package/dist/psql/core/sqlHelp.js +150 -150
- package/dist/psql/core/startup.js +211 -205
- package/dist/psql/core/syncVars.js +14 -14
- package/dist/psql/core/variables.js +24 -24
- package/dist/psql/describe/formatters.js +302 -289
- package/dist/psql/describe/processNamePattern.js +28 -28
- package/dist/psql/describe/queries.js +656 -651
- package/dist/psql/index.js +436 -411
- package/dist/psql/io/history.js +36 -36
- package/dist/psql/io/input.js +15 -15
- package/dist/psql/io/lineEditor/buffer.js +27 -25
- package/dist/psql/io/lineEditor/complete.js +15 -15
- package/dist/psql/io/lineEditor/filename.js +22 -22
- package/dist/psql/io/lineEditor/index.js +65 -62
- package/dist/psql/io/lineEditor/keymap.js +325 -318
- package/dist/psql/io/lineEditor/vt100.js +60 -60
- package/dist/psql/io/pgpass.js +18 -18
- package/dist/psql/io/pgservice.js +14 -14
- package/dist/psql/io/psqlrc.js +46 -46
- package/dist/psql/print/aligned.js +175 -166
- package/dist/psql/print/asciidoc.js +51 -51
- package/dist/psql/print/crosstab.js +34 -31
- package/dist/psql/print/csv.js +25 -22
- package/dist/psql/print/html.js +54 -54
- package/dist/psql/print/json.js +12 -12
- package/dist/psql/print/latex.js +118 -118
- package/dist/psql/print/pager.js +28 -26
- package/dist/psql/print/troff.js +48 -48
- package/dist/psql/print/unaligned.js +15 -14
- package/dist/psql/print/units.js +17 -17
- package/dist/psql/scanner/slash.js +48 -46
- package/dist/psql/scanner/sql.js +88 -84
- package/dist/psql/scanner/stringutils.js +21 -17
- package/dist/psql/types/index.js +7 -7
- package/dist/psql/types/scanner.js +8 -8
- package/dist/psql/wire/connection.js +341 -327
- package/dist/psql/wire/copy.js +7 -7
- package/dist/psql/wire/pipeline.js +26 -24
- package/dist/psql/wire/protocol.js +102 -102
- package/dist/psql/wire/sasl.js +62 -62
- package/dist/psql/wire/tls.js +79 -73
- package/dist/storage_api.js +15 -15
- package/dist/test_utils/fixtures.js +34 -31
- package/dist/test_utils/oauth_server.js +5 -5
- package/dist/utils/api_enums.js +13 -13
- package/dist/utils/branch_notice.js +5 -5
- package/dist/utils/branch_picker.js +26 -26
- package/dist/utils/compute_units.js +4 -4
- package/dist/utils/enrichers.js +20 -15
- package/dist/utils/esbuild.js +28 -28
- package/dist/utils/formats.js +1 -1
- package/dist/utils/middlewares.js +3 -3
- package/dist/utils/package_manager.js +68 -0
- package/dist/utils/point_in_time.js +12 -12
- package/dist/utils/psql.js +30 -30
- package/dist/utils/string.js +2 -2
- package/dist/utils/ui.js +9 -9
- package/dist/utils/zip.js +1 -1
- package/dist/writer.js +17 -17
- package/package.json +6 -7
package/dist/psql/wire/copy.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* doorbell — call `connection.startCopyIn(sql)` to get a `CopyInStream`, then
|
|
27
27
|
* pipe a Readable into it via `pumpReadable()`.
|
|
28
28
|
*/
|
|
29
|
-
import { Buffer } from
|
|
29
|
+
import { Buffer } from "node:buffer";
|
|
30
30
|
/**
|
|
31
31
|
* Pump every chunk from a Node Readable into a CopyInStream, then end it.
|
|
32
32
|
*
|
|
@@ -43,8 +43,8 @@ export const pumpReadable = async (conn, readable, copyIn) => {
|
|
|
43
43
|
let aborted = null;
|
|
44
44
|
try {
|
|
45
45
|
for await (const chunk of readable) {
|
|
46
|
-
const buf = typeof chunk ===
|
|
47
|
-
? Buffer.from(chunk,
|
|
46
|
+
const buf = typeof chunk === "string"
|
|
47
|
+
? Buffer.from(chunk, "utf8")
|
|
48
48
|
: Buffer.isBuffer(chunk)
|
|
49
49
|
? chunk
|
|
50
50
|
: Buffer.from(chunk);
|
|
@@ -95,14 +95,14 @@ export const drainCopyOut = async (copyOut, writable) => {
|
|
|
95
95
|
const abortReason = (v) => {
|
|
96
96
|
if (v instanceof Error)
|
|
97
97
|
return v.message;
|
|
98
|
-
if (typeof v ===
|
|
98
|
+
if (typeof v === "string")
|
|
99
99
|
return v;
|
|
100
|
-
if (typeof v ===
|
|
100
|
+
if (typeof v === "number" || typeof v === "boolean")
|
|
101
101
|
return String(v);
|
|
102
102
|
try {
|
|
103
|
-
return JSON.stringify(v) ??
|
|
103
|
+
return JSON.stringify(v) ?? "unknown error";
|
|
104
104
|
}
|
|
105
105
|
catch {
|
|
106
|
-
return
|
|
106
|
+
return "unknown error";
|
|
107
107
|
}
|
|
108
108
|
};
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
* concatenated ResultSets in execute-order. After end() the connection
|
|
24
24
|
* drops back to `idle`.
|
|
25
25
|
*/
|
|
26
|
-
import { Buffer } from
|
|
27
|
-
import { Bind, Close, Describe, Execute, Flush, Parse, Sync, } from
|
|
26
|
+
import { Buffer } from "node:buffer";
|
|
27
|
+
import { Bind, Close, Describe, Execute, Flush, Parse, Sync, } from "./protocol.js";
|
|
28
28
|
export class PipelineSession {
|
|
29
29
|
constructor(conn) {
|
|
30
30
|
this.conn = conn;
|
|
@@ -151,7 +151,7 @@ export class PipelineSession {
|
|
|
151
151
|
*/
|
|
152
152
|
static voidToPlaceholderResult(p) {
|
|
153
153
|
return p.then(() => ({
|
|
154
|
-
command:
|
|
154
|
+
command: "",
|
|
155
155
|
rowCount: null,
|
|
156
156
|
oid: null,
|
|
157
157
|
fields: [],
|
|
@@ -208,7 +208,7 @@ export class PipelineSession {
|
|
|
208
208
|
this.conn.startExtendedBatch();
|
|
209
209
|
const p = this.conn.enqueueBind();
|
|
210
210
|
const encoded = values.map(toBindValue);
|
|
211
|
-
this.conn.writeRaw(Bind(
|
|
211
|
+
this.conn.writeRaw(Bind("", name, [], encoded, [0]));
|
|
212
212
|
const silenced = PipelineSession.silenceUnhandled(p);
|
|
213
213
|
this.pending.push(silenced);
|
|
214
214
|
// Stage on the current command group so the next slot-pushing op
|
|
@@ -230,7 +230,7 @@ export class PipelineSession {
|
|
|
230
230
|
// Stage DescribePortal on the current group too — its rejection
|
|
231
231
|
// would otherwise be invisible to the slot.
|
|
232
232
|
this.currentGroup.push(silencedDp);
|
|
233
|
-
this.conn.writeRaw(Describe(
|
|
233
|
+
this.conn.writeRaw(Describe("P", name));
|
|
234
234
|
const ep = this.conn.enqueueExecute();
|
|
235
235
|
this.results.push(PipelineSession.silenceUnhandled(ep));
|
|
236
236
|
// Each Execute is one libpq-level user command (the Parse + Bind
|
|
@@ -248,7 +248,7 @@ export class PipelineSession {
|
|
|
248
248
|
this.conn.startExtendedBatch();
|
|
249
249
|
// psql's `\describe` in pipeline context is portal-targeted.
|
|
250
250
|
const p = this.conn.enqueueDescribePortal();
|
|
251
|
-
this.conn.writeRaw(Describe(
|
|
251
|
+
this.conn.writeRaw(Describe("P", name));
|
|
252
252
|
this.pending.push(PipelineSession.silenceUnhandled(p));
|
|
253
253
|
return Promise.resolve();
|
|
254
254
|
}
|
|
@@ -270,7 +270,7 @@ export class PipelineSession {
|
|
|
270
270
|
closeRaw(name) {
|
|
271
271
|
this.conn.startExtendedBatch();
|
|
272
272
|
const p = this.conn.enqueueClose();
|
|
273
|
-
this.conn.writeRaw(Close(
|
|
273
|
+
this.conn.writeRaw(Close("S", name));
|
|
274
274
|
const silenced = PipelineSession.silenceUnhandled(p);
|
|
275
275
|
this.pending.push(silenced);
|
|
276
276
|
this.currentGroup.push(silenced);
|
|
@@ -297,7 +297,7 @@ export class PipelineSession {
|
|
|
297
297
|
// printing it (the empty-fields guard) but advances `drainedCount`
|
|
298
298
|
// by one, matching upstream's libpq queue layout.
|
|
299
299
|
const syncMarker = {
|
|
300
|
-
command:
|
|
300
|
+
command: "",
|
|
301
301
|
rowCount: null,
|
|
302
302
|
oid: null,
|
|
303
303
|
fields: [],
|
|
@@ -334,7 +334,7 @@ export class PipelineSession {
|
|
|
334
334
|
// rejection becomes the sticky `_lastError` if Sync itself was clean.
|
|
335
335
|
const settled = await Promise.allSettled(this.pending.splice(0));
|
|
336
336
|
for (const r of settled) {
|
|
337
|
-
if (r.status ===
|
|
337
|
+
if (r.status === "rejected" && this._lastError === null) {
|
|
338
338
|
this._lastError = r.reason;
|
|
339
339
|
}
|
|
340
340
|
}
|
|
@@ -382,7 +382,7 @@ export class PipelineSession {
|
|
|
382
382
|
*/
|
|
383
383
|
async peekRealError() {
|
|
384
384
|
const allP = [...this.pending, ...this.results];
|
|
385
|
-
const sentinel = Symbol(
|
|
385
|
+
const sentinel = Symbol("pending");
|
|
386
386
|
// Race each candidate against a `setImmediate`-deferred sentinel so
|
|
387
387
|
// any promise that was already settled (synchronously, e.g. by the
|
|
388
388
|
// wire layer's cascade-reject inside its ErrorResponse handler) has
|
|
@@ -397,22 +397,23 @@ export class PipelineSession {
|
|
|
397
397
|
for (const p of allP) {
|
|
398
398
|
const r = (await Promise.race([
|
|
399
399
|
p.then((v) => ({
|
|
400
|
-
status:
|
|
400
|
+
status: "fulfilled",
|
|
401
401
|
value: v,
|
|
402
402
|
}), (e) => ({
|
|
403
|
-
status:
|
|
403
|
+
status: "rejected",
|
|
404
404
|
reason: e,
|
|
405
405
|
})),
|
|
406
406
|
deferred(),
|
|
407
407
|
]));
|
|
408
408
|
if (r === sentinel)
|
|
409
409
|
continue;
|
|
410
|
-
if (r.status !==
|
|
410
|
+
if (r.status !== "rejected")
|
|
411
411
|
continue;
|
|
412
412
|
const reason = r.reason;
|
|
413
|
-
const isAborted = typeof reason ===
|
|
413
|
+
const isAborted = typeof reason === "object" &&
|
|
414
414
|
reason !== null &&
|
|
415
|
-
reason.pipelineAborted ===
|
|
415
|
+
reason.pipelineAborted ===
|
|
416
|
+
true;
|
|
416
417
|
if (!isAborted)
|
|
417
418
|
return reason;
|
|
418
419
|
}
|
|
@@ -440,7 +441,7 @@ export class PipelineSession {
|
|
|
440
441
|
const settled = await Promise.allSettled(this.results);
|
|
441
442
|
const out = [];
|
|
442
443
|
for (const r of settled) {
|
|
443
|
-
if (r.status ===
|
|
444
|
+
if (r.status === "fulfilled")
|
|
444
445
|
out.push(r.value);
|
|
445
446
|
}
|
|
446
447
|
// FATAL-class pipeline aborts (e.g. "COPY in a pipeline is not
|
|
@@ -451,10 +452,11 @@ export class PipelineSession {
|
|
|
451
452
|
// `_lastError` so the cmd layer can print them inline.
|
|
452
453
|
if (fatal !== null) {
|
|
453
454
|
const sev = fatal.severity;
|
|
454
|
-
if (sev ===
|
|
455
|
+
if (sev === "FATAL") {
|
|
455
456
|
if (fatal instanceof Error)
|
|
456
457
|
throw fatal;
|
|
457
|
-
const msg = fatal.message ??
|
|
458
|
+
const msg = fatal.message ??
|
|
459
|
+
"pipeline aborted";
|
|
458
460
|
throw Object.assign(new Error(msg), fatal);
|
|
459
461
|
}
|
|
460
462
|
// Non-FATAL (typically ERROR) — keep for the cmd layer, unless
|
|
@@ -488,7 +490,7 @@ export class PipelineSession {
|
|
|
488
490
|
// first-wins capture.
|
|
489
491
|
for (let i = this._externalDrained; i < settled.length; i++) {
|
|
490
492
|
const r = settled[i];
|
|
491
|
-
if (r.status ===
|
|
493
|
+
if (r.status === "rejected") {
|
|
492
494
|
this._lastError = r.reason;
|
|
493
495
|
break;
|
|
494
496
|
}
|
|
@@ -502,11 +504,11 @@ function toBindValue(v) {
|
|
|
502
504
|
return null;
|
|
503
505
|
if (Buffer.isBuffer(v))
|
|
504
506
|
return v;
|
|
505
|
-
if (typeof v ===
|
|
507
|
+
if (typeof v === "string")
|
|
506
508
|
return v;
|
|
507
|
-
if (typeof v ===
|
|
508
|
-
return v ?
|
|
509
|
-
if (typeof v ===
|
|
509
|
+
if (typeof v === "boolean")
|
|
510
|
+
return v ? "t" : "f";
|
|
511
|
+
if (typeof v === "number" || typeof v === "bigint")
|
|
510
512
|
return v.toString();
|
|
511
513
|
// Objects, arrays, etc: JSON-stringify deterministically. Falls back to ''
|
|
512
514
|
// if the value is not representable.
|
|
@@ -514,6 +516,6 @@ function toBindValue(v) {
|
|
|
514
516
|
return JSON.stringify(v);
|
|
515
517
|
}
|
|
516
518
|
catch {
|
|
517
|
-
return
|
|
519
|
+
return "";
|
|
518
520
|
}
|
|
519
521
|
}
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
* fields as named properties on the Error/Notice instance. We re-pack
|
|
40
40
|
* them into the Map<tag,value> shape our `fieldsToNotice` helper consumes.
|
|
41
41
|
*/
|
|
42
|
-
import { Buffer } from
|
|
42
|
+
import { Buffer } from "node:buffer";
|
|
43
43
|
// pg-protocol@1.14 ships two entry points via its `exports` map:
|
|
44
44
|
// - `./esm/index.js` (the `"import"` key) — a thin ESM wrapper that does
|
|
45
45
|
// `import * as protocol from '../dist/index.js'`.
|
|
@@ -53,13 +53,13 @@ import { Buffer } from 'node:buffer';
|
|
|
53
53
|
// key as a forced-ESM hint and avoids this. To stay portable across both,
|
|
54
54
|
// we import the CJS implementation directly — same pattern node-postgres
|
|
55
55
|
// uses for the `Parser` subpath, and what we already do on the next line.
|
|
56
|
-
import pgProtocol from
|
|
56
|
+
import pgProtocol from "pg-protocol/dist/index.js";
|
|
57
57
|
const { serialize } = pgProtocol;
|
|
58
|
-
import { Parser } from
|
|
58
|
+
import { Parser } from "pg-protocol/dist/parser.js";
|
|
59
59
|
export class ProtocolError extends Error {
|
|
60
60
|
constructor(message) {
|
|
61
61
|
super(message);
|
|
62
|
-
this.name =
|
|
62
|
+
this.name = "ProtocolError";
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
// ---------------------------------------------------------------------------
|
|
@@ -79,7 +79,7 @@ export function StartupMessage(params) {
|
|
|
79
79
|
for (const [key, value] of Object.entries(params)) {
|
|
80
80
|
if (value === undefined)
|
|
81
81
|
continue;
|
|
82
|
-
if (key ===
|
|
82
|
+
if (key === "client_encoding")
|
|
83
83
|
continue;
|
|
84
84
|
filtered[key] = value;
|
|
85
85
|
}
|
|
@@ -166,11 +166,11 @@ export function PasswordMessage(password) {
|
|
|
166
166
|
* losslessly via UTF-8.
|
|
167
167
|
*/
|
|
168
168
|
export function SASLInitialResponse(mechanism, response) {
|
|
169
|
-
return serialize.sendSASLInitialResponseMessage(mechanism, response.toString(
|
|
169
|
+
return serialize.sendSASLInitialResponseMessage(mechanism, response.toString("utf8"));
|
|
170
170
|
}
|
|
171
171
|
/** SASLResponse: 'p' + opaque body (no NUL terminator). */
|
|
172
172
|
export function SASLResponse(response) {
|
|
173
|
-
return serialize.sendSCRAMClientFinalMessage(response.toString(
|
|
173
|
+
return serialize.sendSCRAMClientFinalMessage(response.toString("utf8"));
|
|
174
174
|
}
|
|
175
175
|
/** CopyData: 'd' + opaque bytes. */
|
|
176
176
|
export function CopyData(data) {
|
|
@@ -237,50 +237,50 @@ export class MessageParser {
|
|
|
237
237
|
function adaptBackendMessage(raw) {
|
|
238
238
|
const msg = raw;
|
|
239
239
|
switch (msg.name) {
|
|
240
|
-
case
|
|
241
|
-
return { type:
|
|
242
|
-
case
|
|
243
|
-
return { type:
|
|
244
|
-
case
|
|
240
|
+
case "authenticationOk":
|
|
241
|
+
return { type: "AuthenticationOk" };
|
|
242
|
+
case "authenticationCleartextPassword":
|
|
243
|
+
return { type: "AuthenticationCleartextPassword" };
|
|
244
|
+
case "authenticationMD5Password":
|
|
245
245
|
return {
|
|
246
|
-
type:
|
|
246
|
+
type: "AuthenticationMD5Password",
|
|
247
247
|
salt: Buffer.from(msg.salt),
|
|
248
248
|
};
|
|
249
|
-
case
|
|
249
|
+
case "authenticationSASL":
|
|
250
250
|
return {
|
|
251
|
-
type:
|
|
251
|
+
type: "AuthenticationSASL",
|
|
252
252
|
mechanisms: msg.mechanisms,
|
|
253
253
|
};
|
|
254
|
-
case
|
|
254
|
+
case "authenticationSASLContinue":
|
|
255
255
|
return {
|
|
256
|
-
type:
|
|
257
|
-
data: Buffer.from(msg.data,
|
|
256
|
+
type: "AuthenticationSASLContinue",
|
|
257
|
+
data: Buffer.from(msg.data, "utf8"),
|
|
258
258
|
};
|
|
259
|
-
case
|
|
259
|
+
case "authenticationSASLFinal":
|
|
260
260
|
return {
|
|
261
|
-
type:
|
|
262
|
-
data: Buffer.from(msg.data,
|
|
261
|
+
type: "AuthenticationSASLFinal",
|
|
262
|
+
data: Buffer.from(msg.data, "utf8"),
|
|
263
263
|
};
|
|
264
|
-
case
|
|
264
|
+
case "parameterStatus":
|
|
265
265
|
return {
|
|
266
|
-
type:
|
|
266
|
+
type: "ParameterStatus",
|
|
267
267
|
name: msg.parameterName,
|
|
268
268
|
value: msg.parameterValue,
|
|
269
269
|
};
|
|
270
|
-
case
|
|
270
|
+
case "backendKeyData":
|
|
271
271
|
return {
|
|
272
|
-
type:
|
|
272
|
+
type: "BackendKeyData",
|
|
273
273
|
processId: msg.processID,
|
|
274
274
|
secretKey: msg.secretKey,
|
|
275
275
|
};
|
|
276
|
-
case
|
|
276
|
+
case "readyForQuery": {
|
|
277
277
|
const status = msg.status;
|
|
278
|
-
if (status !==
|
|
278
|
+
if (status !== "I" && status !== "T" && status !== "E") {
|
|
279
279
|
throw new ProtocolError(`ReadyForQuery: unexpected status ${JSON.stringify(status)}`);
|
|
280
280
|
}
|
|
281
|
-
return { type:
|
|
281
|
+
return { type: "ReadyForQuery", status };
|
|
282
282
|
}
|
|
283
|
-
case
|
|
283
|
+
case "rowDescription": {
|
|
284
284
|
const fields = msg.fields.map((f) => ({
|
|
285
285
|
name: f.name,
|
|
286
286
|
tableID: f.tableID,
|
|
@@ -288,11 +288,11 @@ function adaptBackendMessage(raw) {
|
|
|
288
288
|
dataTypeID: f.dataTypeID,
|
|
289
289
|
dataTypeSize: f.dataTypeSize,
|
|
290
290
|
dataTypeModifier: f.dataTypeModifier,
|
|
291
|
-
format: f.format ===
|
|
291
|
+
format: f.format === "binary" ? 1 : 0,
|
|
292
292
|
}));
|
|
293
|
-
return { type:
|
|
293
|
+
return { type: "RowDescription", fields };
|
|
294
294
|
}
|
|
295
|
-
case
|
|
295
|
+
case "dataRow": {
|
|
296
296
|
// pg-protocol always parses values as UTF-8 strings (or null for SQL
|
|
297
297
|
// NULL). Our connection layer expects (Buffer | null)[] so it can hand
|
|
298
298
|
// text-format columns through `.toString('utf8')` and pass binary
|
|
@@ -301,30 +301,30 @@ function adaptBackendMessage(raw) {
|
|
|
301
301
|
const values = new Array(fields.length);
|
|
302
302
|
for (let i = 0; i < fields.length; i++) {
|
|
303
303
|
const v = fields[i];
|
|
304
|
-
values[i] = v === null ? null : Buffer.from(v,
|
|
304
|
+
values[i] = v === null ? null : Buffer.from(v, "utf8");
|
|
305
305
|
}
|
|
306
|
-
return { type:
|
|
306
|
+
return { type: "DataRow", values };
|
|
307
307
|
}
|
|
308
|
-
case
|
|
309
|
-
return { type:
|
|
310
|
-
case
|
|
311
|
-
return { type:
|
|
312
|
-
case
|
|
313
|
-
return { type:
|
|
314
|
-
case
|
|
315
|
-
return { type:
|
|
316
|
-
case
|
|
308
|
+
case "commandComplete":
|
|
309
|
+
return { type: "CommandComplete", tag: msg.text };
|
|
310
|
+
case "emptyQuery":
|
|
311
|
+
return { type: "EmptyQueryResponse" };
|
|
312
|
+
case "error":
|
|
313
|
+
return { type: "ErrorResponse", fields: errorOrNoticeFields(msg) };
|
|
314
|
+
case "notice":
|
|
315
|
+
return { type: "NoticeResponse", fields: errorOrNoticeFields(msg) };
|
|
316
|
+
case "notification":
|
|
317
317
|
return {
|
|
318
|
-
type:
|
|
318
|
+
type: "NotificationResponse",
|
|
319
319
|
processId: msg.processId,
|
|
320
320
|
channel: msg.channel,
|
|
321
321
|
payload: msg.payload,
|
|
322
322
|
};
|
|
323
|
-
case
|
|
324
|
-
return adaptCopyResponse(
|
|
325
|
-
case
|
|
326
|
-
return adaptCopyResponse(
|
|
327
|
-
case
|
|
323
|
+
case "copyInResponse":
|
|
324
|
+
return adaptCopyResponse("CopyInResponse", msg);
|
|
325
|
+
case "copyOutResponse":
|
|
326
|
+
return adaptCopyResponse("CopyOutResponse", msg);
|
|
327
|
+
case "replicationStart":
|
|
328
328
|
// pg-protocol emits a bare marker for the 'W' (CopyBothResponse) byte
|
|
329
329
|
// — its `Parser` recognises the message code but does not decode the
|
|
330
330
|
// payload (overall format + per-column format bytes). The body shape
|
|
@@ -332,24 +332,24 @@ function adaptBackendMessage(raw) {
|
|
|
332
332
|
// those fields: the connection layer reacts to CopyBothResponse by
|
|
333
333
|
// raising a clean diagnostic because this client does not implement
|
|
334
334
|
// CopyBoth streaming.
|
|
335
|
-
return { type:
|
|
336
|
-
case
|
|
337
|
-
return { type:
|
|
338
|
-
case
|
|
339
|
-
return { type:
|
|
340
|
-
case
|
|
341
|
-
return { type:
|
|
342
|
-
case
|
|
343
|
-
return { type:
|
|
344
|
-
case
|
|
345
|
-
return { type:
|
|
346
|
-
case
|
|
347
|
-
return { type:
|
|
348
|
-
case
|
|
349
|
-
return { type:
|
|
350
|
-
case
|
|
335
|
+
return { type: "CopyBothResponse" };
|
|
336
|
+
case "copyData":
|
|
337
|
+
return { type: "CopyData", data: Buffer.from(msg.chunk) };
|
|
338
|
+
case "copyDone":
|
|
339
|
+
return { type: "CopyDone" };
|
|
340
|
+
case "noData":
|
|
341
|
+
return { type: "NoData" };
|
|
342
|
+
case "parseComplete":
|
|
343
|
+
return { type: "ParseComplete" };
|
|
344
|
+
case "bindComplete":
|
|
345
|
+
return { type: "BindComplete" };
|
|
346
|
+
case "closeComplete":
|
|
347
|
+
return { type: "CloseComplete" };
|
|
348
|
+
case "portalSuspended":
|
|
349
|
+
return { type: "PortalSuspended" };
|
|
350
|
+
case "parameterDescription":
|
|
351
351
|
return {
|
|
352
|
-
type:
|
|
352
|
+
type: "ParameterDescription",
|
|
353
353
|
oids: msg.dataTypeIDs,
|
|
354
354
|
};
|
|
355
355
|
default:
|
|
@@ -380,27 +380,27 @@ function errorOrNoticeFields(msg) {
|
|
|
380
380
|
// tags), we copy S = V = severity when severity is defined. Consumers like
|
|
381
381
|
// `fieldsToNotice` look at V then S so this matches.
|
|
382
382
|
const set = (tag, value) => {
|
|
383
|
-
if (typeof value ===
|
|
383
|
+
if (typeof value === "string")
|
|
384
384
|
out.set(tag, value);
|
|
385
385
|
};
|
|
386
|
-
set(
|
|
387
|
-
set(
|
|
388
|
-
set(
|
|
389
|
-
set(
|
|
390
|
-
set(
|
|
391
|
-
set(
|
|
392
|
-
set(
|
|
393
|
-
set(
|
|
394
|
-
set(
|
|
395
|
-
set(
|
|
396
|
-
set(
|
|
397
|
-
set(
|
|
398
|
-
set(
|
|
399
|
-
set(
|
|
400
|
-
set(
|
|
401
|
-
set(
|
|
402
|
-
set(
|
|
403
|
-
set(
|
|
386
|
+
set("S", msg.severity);
|
|
387
|
+
set("V", msg.severity);
|
|
388
|
+
set("C", msg.code);
|
|
389
|
+
set("M", msg.message);
|
|
390
|
+
set("D", msg.detail);
|
|
391
|
+
set("H", msg.hint);
|
|
392
|
+
set("P", msg.position);
|
|
393
|
+
set("p", msg.internalPosition);
|
|
394
|
+
set("q", msg.internalQuery);
|
|
395
|
+
set("W", msg.where);
|
|
396
|
+
set("s", msg.schema);
|
|
397
|
+
set("t", msg.table);
|
|
398
|
+
set("c", msg.column);
|
|
399
|
+
set("d", msg.dataType);
|
|
400
|
+
set("n", msg.constraint);
|
|
401
|
+
set("F", msg.file);
|
|
402
|
+
set("L", msg.line);
|
|
403
|
+
set("R", msg.routine);
|
|
404
404
|
return out;
|
|
405
405
|
}
|
|
406
406
|
// ---------------------------------------------------------------------------
|
|
@@ -414,52 +414,52 @@ function errorOrNoticeFields(msg) {
|
|
|
414
414
|
export function fieldsToNotice(fields) {
|
|
415
415
|
// Per PG docs: V is the non-localized severity (preferred when present),
|
|
416
416
|
// S is the localized severity (always present). Message M is mandatory.
|
|
417
|
-
const severity = fields.get(
|
|
418
|
-
const message = fields.get(
|
|
417
|
+
const severity = fields.get("V") ?? fields.get("S") ?? "";
|
|
418
|
+
const message = fields.get("M") ?? "";
|
|
419
419
|
const out = { severity, message };
|
|
420
|
-
const code = fields.get(
|
|
420
|
+
const code = fields.get("C");
|
|
421
421
|
if (code !== undefined)
|
|
422
422
|
out.code = code;
|
|
423
|
-
const detail = fields.get(
|
|
423
|
+
const detail = fields.get("D");
|
|
424
424
|
if (detail !== undefined)
|
|
425
425
|
out.detail = detail;
|
|
426
|
-
const hint = fields.get(
|
|
426
|
+
const hint = fields.get("H");
|
|
427
427
|
if (hint !== undefined)
|
|
428
428
|
out.hint = hint;
|
|
429
|
-
const position = fields.get(
|
|
429
|
+
const position = fields.get("P");
|
|
430
430
|
if (position !== undefined)
|
|
431
431
|
out.position = position;
|
|
432
|
-
const internalPosition = fields.get(
|
|
432
|
+
const internalPosition = fields.get("p");
|
|
433
433
|
if (internalPosition !== undefined)
|
|
434
434
|
out.internalPosition = internalPosition;
|
|
435
|
-
const internalQuery = fields.get(
|
|
435
|
+
const internalQuery = fields.get("q");
|
|
436
436
|
if (internalQuery !== undefined)
|
|
437
437
|
out.internalQuery = internalQuery;
|
|
438
|
-
const where = fields.get(
|
|
438
|
+
const where = fields.get("W");
|
|
439
439
|
if (where !== undefined)
|
|
440
440
|
out.where = where;
|
|
441
|
-
const schema = fields.get(
|
|
441
|
+
const schema = fields.get("s");
|
|
442
442
|
if (schema !== undefined)
|
|
443
443
|
out.schema = schema;
|
|
444
|
-
const table = fields.get(
|
|
444
|
+
const table = fields.get("t");
|
|
445
445
|
if (table !== undefined)
|
|
446
446
|
out.table = table;
|
|
447
|
-
const column = fields.get(
|
|
447
|
+
const column = fields.get("c");
|
|
448
448
|
if (column !== undefined)
|
|
449
449
|
out.column = column;
|
|
450
|
-
const dataType = fields.get(
|
|
450
|
+
const dataType = fields.get("d");
|
|
451
451
|
if (dataType !== undefined)
|
|
452
452
|
out.dataType = dataType;
|
|
453
|
-
const constraint = fields.get(
|
|
453
|
+
const constraint = fields.get("n");
|
|
454
454
|
if (constraint !== undefined)
|
|
455
455
|
out.constraint = constraint;
|
|
456
|
-
const file = fields.get(
|
|
456
|
+
const file = fields.get("F");
|
|
457
457
|
if (file !== undefined)
|
|
458
458
|
out.file = file;
|
|
459
|
-
const line = fields.get(
|
|
459
|
+
const line = fields.get("L");
|
|
460
460
|
if (line !== undefined)
|
|
461
461
|
out.line = line;
|
|
462
|
-
const routine = fields.get(
|
|
462
|
+
const routine = fields.get("R");
|
|
463
463
|
if (routine !== undefined)
|
|
464
464
|
out.routine = routine;
|
|
465
465
|
return out;
|