kern-db 0.3.0 → 0.4.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/dist/builder.d.mts +1 -1
- package/dist/{database-0i2749JZ.mjs → database-D4ql2RZ0.mjs} +3 -4
- package/dist/{driver-CSfbXOBJ.d.mts → driver-CZCBkque.d.mts} +7 -2
- package/dist/{driver-error-26zcdHeU.mjs → driver-error-D8D4UQ4F.mjs} +14 -5
- package/dist/index.d.mts +19 -7
- package/dist/index.mjs +2 -2
- package/dist/node-postgres.d.mts +1 -1
- package/dist/node-postgres.mjs +9 -5
- package/dist/postgres-js.d.mts +1 -1
- package/dist/postgres-js.mjs +30 -4
- package/dist/{query-BrvYBvWC.d.mts → query-Dxiy1HJD.d.mts} +1 -1
- package/dist/testing.d.mts +4 -2
- package/dist/testing.mjs +35 -7
- package/package.json +1 -1
package/dist/builder.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as takeOnlyRow, C as renderFragment, D as bindParameter, E as assertUntypedValue, H as toValueRows, L as createFieldDecodeError, O as encodeParameter, P as ResultMode, R as createResultDecodeError, V as toMissingResult, a as SqlQuery, c as StatementSource, l as startSqlQuery, v as ParameterBinder, y as SqlFragment, z as isRecordKey } from "./query-
|
|
1
|
+
import { B as takeOnlyRow, C as renderFragment, D as bindParameter, E as assertUntypedValue, H as toValueRows, L as createFieldDecodeError, O as encodeParameter, P as ResultMode, R as createResultDecodeError, V as toMissingResult, a as SqlQuery, c as StatementSource, l as startSqlQuery, v as ParameterBinder, y as SqlFragment, z as isRecordKey } from "./query-Dxiy1HJD.mjs";
|
|
2
2
|
/** Quotes `name` as a PostgreSQL identifier, which keeps its case and any characters in it. */
|
|
3
3
|
export declare function quoteIdentifier(name: string): string;
|
|
4
4
|
export { type ParameterBinder, type ResultMode, SqlFragment, SqlQuery, type StatementSource, assertUntypedValue, bindParameter, createFieldDecodeError, createResultDecodeError, encodeParameter, isRecordKey, renderFragment, startSqlQuery, takeOnlyRow, toMissingResult, toValueRows };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as decodeBoolean } from "./bytea-DNZ_ftio.mjs";
|
|
2
2
|
import { S as createStatement, _ as sql, f as compileFragment, n as startSqlQuery, p as compileScript, x as quoteIdentifier } from "./query-FKBN7BMY.mjs";
|
|
3
|
-
import { i as setBrand, n as QueryError, r as isInstance, t as ConnectionError } from "./driver-error-
|
|
3
|
+
import { i as setBrand, n as QueryError, r as isInstance, t as ConnectionError } from "./driver-error-D8D4UQ4F.mjs";
|
|
4
4
|
import { n as formatArray } from "./array-BLt8ZNR5.mjs";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
6
|
// src/transaction/release.ts
|
|
@@ -217,14 +217,13 @@ var TransactionConnectionError = class TransactionConnectionError extends Connec
|
|
|
217
217
|
*
|
|
218
218
|
* - `TransactionConnectionError` of phase `commit` gives `true`, since `COMMIT` may have succeeded.
|
|
219
219
|
* - `TransactionConnectionError` of another phase gives `false`, since the transaction was not committed.
|
|
220
|
+
* - A `ConnectionError` whose `unsent` is `true`, such as after a failure to get a connection or of a closed driver, gives `false`, since the statement was not sent.
|
|
220
221
|
* - Another `ConnectionError` gives `true`, since a statement outside a transaction may have run before its connection failed.
|
|
221
222
|
* - Any other error gives `false`, such as a `QueryError`, or a `ResultDecodeError` of a statement that has run: `false` does not mean that the operation applied nothing.
|
|
222
|
-
*
|
|
223
|
-
* Classification depends only on the error class, so failures before the statement was sent, such as a failure to acquire a connection, also give `true`.
|
|
224
223
|
*/
|
|
225
224
|
function isOutcomeUnknown(error) {
|
|
226
225
|
if (error instanceof TransactionConnectionError) return error.phase === "commit";
|
|
227
|
-
return error instanceof ConnectionError;
|
|
226
|
+
return error instanceof ConnectionError && error.unsent !== true;
|
|
228
227
|
}
|
|
229
228
|
/**
|
|
230
229
|
* Reserved connection of a transaction of `transaction` that records the first `ConnectionError` of its statements and scripts, including those of its nested levels.
|
|
@@ -24,6 +24,7 @@ interface DriverResult {
|
|
|
24
24
|
*
|
|
25
25
|
* A driver sends parameters as text without a declared type, so that the statement text alone determines their types, and returns values as text without parsing them.
|
|
26
26
|
* It rejects with `QueryError` a statement or script that PostgreSQL rejected, whose connection stays usable, and with `ConnectionError` any other failure of a statement, a script, or a connection.
|
|
27
|
+
* The driver sets `unsent` of a `ConnectionError` to `true` when it knows that the statement or script was not sent, such as after a failure to get a connection, and only then.
|
|
27
28
|
*/
|
|
28
29
|
interface Driver {
|
|
29
30
|
/**
|
|
@@ -40,12 +41,16 @@ interface Driver {
|
|
|
40
41
|
* Either way, no transaction stays open on the pool.
|
|
41
42
|
*/
|
|
42
43
|
executeScript(text: string): Promise<void>;
|
|
43
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Reserves a dedicated connection, such as for a transaction or a session.
|
|
46
|
+
*
|
|
47
|
+
* It rejects a failure to get a connection with `ConnectionError` whose `unsent` is `true`.
|
|
48
|
+
*/
|
|
44
49
|
acquire(): Promise<Connection>;
|
|
45
50
|
/**
|
|
46
51
|
* Closes the connections once the statements on the pool and the transactions and sessions on reserved connections end.
|
|
47
52
|
*
|
|
48
|
-
* From the call, it rejects a new statement or script on the pool and a new connection with `ConnectionError`.
|
|
53
|
+
* From the call, it rejects a new statement or script on the pool and a new connection with `ConnectionError` whose `unsent` is `true`.
|
|
49
54
|
*/
|
|
50
55
|
close(): Promise<void>;
|
|
51
56
|
}
|
|
@@ -42,12 +42,19 @@ var QueryError = class QueryError extends Error {
|
|
|
42
42
|
/**
|
|
43
43
|
* Error of a statement or connection that failed for another reason than PostgreSQL rejecting a statement, such as a lost connection, a timeout of the client, or a closed driver.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
45
|
+
* Unless `unsent` is `true`, the statement may have run or not, and its connection may be lost or in an unknown state of its transaction.
|
|
46
46
|
*/
|
|
47
47
|
var ConnectionError = class ConnectionError extends Error {
|
|
48
48
|
name = "ConnectionError";
|
|
49
|
+
/**
|
|
50
|
+
* Whether the statement was certainly not sent to the server, such as when the driver was closed or could not get a connection.
|
|
51
|
+
*
|
|
52
|
+
* `false` means that the statement may have been sent.
|
|
53
|
+
*/
|
|
54
|
+
unsent;
|
|
49
55
|
constructor(message, options) {
|
|
50
56
|
super(message, options);
|
|
57
|
+
this.unsent = options?.unsent ?? false;
|
|
51
58
|
setBrand(this, connectionErrorBrand);
|
|
52
59
|
}
|
|
53
60
|
/** Tells whether `value` is an instance of the class, including one of `ConnectionError` of another copy of kern-db. */
|
|
@@ -69,16 +76,18 @@ function isSessionEnding(severity, code) {
|
|
|
69
76
|
* Classifies an error of a client as `QueryError` or `ConnectionError`, by the fields of the PostgreSQL error it carries, for a driver to reject with.
|
|
70
77
|
*
|
|
71
78
|
* An error that kern-db has already classified returns as it is.
|
|
72
|
-
* An error without a severity or a SQLSTATE, such as of a client that lost its connection, is a `ConnectionError`, and so is one of severity `FATAL` or `PANIC`, which ends the session
|
|
79
|
+
* An error without a severity or a SQLSTATE, such as of a client that lost its connection, is a `ConnectionError`, and so is one of severity `FATAL` or `PANIC`, which ends the session; it gets `unsent` of `fields`.
|
|
73
80
|
* An error of severity `ERROR` is a `QueryError`.
|
|
74
81
|
* With a translated severity, the SQLSTATE tells an error that ends the session, so a few errors of other codes that end it give `QueryError`.
|
|
75
82
|
*/
|
|
76
83
|
function toDriverError(error, fields) {
|
|
77
84
|
if (error instanceof QueryError || error instanceof ConnectionError) return error;
|
|
78
85
|
const message = error instanceof Error ? error.message : String(error);
|
|
79
|
-
const { severity, code, constraint } = fields ?? {};
|
|
80
|
-
if (typeof severity !== "string" || typeof code !== "string" || !sqlState.test(code)) return new ConnectionError(message, {
|
|
81
|
-
|
|
86
|
+
const { severity, code, constraint, unsent } = fields ?? {};
|
|
87
|
+
if (typeof severity !== "string" || typeof code !== "string" || !sqlState.test(code) || isSessionEnding(severity, code)) return new ConnectionError(message, {
|
|
88
|
+
cause: error,
|
|
89
|
+
unsent
|
|
90
|
+
});
|
|
82
91
|
return new QueryError(message, {
|
|
83
92
|
code,
|
|
84
93
|
constraint: typeof constraint === "string" ? constraint : void 0,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as TextValue, i as SqlStatement, n as Driver, o as createStatement, r as DriverResult, s as isDriver, t as Connection } from "./driver-
|
|
1
|
+
import { a as TextValue, i as SqlStatement, n as Driver, o as createStatement, r as DriverResult, s as isDriver, t as Connection } from "./driver-CZCBkque.mjs";
|
|
2
2
|
import { a as BaseDerivableType, c as Type, d as TypeOutput, f as TypeTransform, h as typeValues, i as AnyType, l as TypeInput, m as isType, n as AcceptedValues, o as DerivableType, p as defineType, r as AnyDerivableType, s as DerivableTypeWithParameters, t as AcceptedNull, u as TypeOptions } from "./type-CbrtxvDF.mjs";
|
|
3
|
-
import { A as OneRow, F as ResultRows, I as ValueRows, M as ResultByRows, N as ResultDecodeError, S as param, T as UntypedValue, _ as isDatabase, a as SqlQuery, b as SqlValue, d as DatabaseOptions, f as IsolationLevel, g as createDatabase, h as TransactionOptions, i as InitialSqlQueryState, j as OneValueRows, k as NotFoundError, m as SessionOptions, n as DecodedFields, o as SqlQueryResult, p as PollLockOptions, r as FieldTypes, s as SqlQueryState, t as AnySqlQuery, u as Database, w as sql, x as identifier, y as SqlFragment } from "./query-
|
|
3
|
+
import { A as OneRow, F as ResultRows, I as ValueRows, M as ResultByRows, N as ResultDecodeError, S as param, T as UntypedValue, _ as isDatabase, a as SqlQuery, b as SqlValue, d as DatabaseOptions, f as IsolationLevel, g as createDatabase, h as TransactionOptions, i as InitialSqlQueryState, j as OneValueRows, k as NotFoundError, m as SessionOptions, n as DecodedFields, o as SqlQueryResult, p as PollLockOptions, r as FieldTypes, s as SqlQueryState, t as AnySqlQuery, u as Database, w as sql, x as identifier, y as SqlFragment } from "./query-Dxiy1HJD.mjs";
|
|
4
4
|
/**
|
|
5
5
|
* Error of a statement that PostgreSQL rejected, such as for a violated constraint; the connection of the statement stays usable.
|
|
6
6
|
*
|
|
@@ -24,17 +24,24 @@ export declare class QueryError extends Error {
|
|
|
24
24
|
/**
|
|
25
25
|
* Error of a statement or connection that failed for another reason than PostgreSQL rejecting a statement, such as a lost connection, a timeout of the client, or a closed driver.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
27
|
+
* Unless `unsent` is `true`, the statement may have run or not, and its connection may be lost or in an unknown state of its transaction.
|
|
28
28
|
*/
|
|
29
29
|
export declare class ConnectionError extends Error {
|
|
30
30
|
readonly name: string;
|
|
31
|
+
/**
|
|
32
|
+
* Whether the statement was certainly not sent to the server, such as when the driver was closed or could not get a connection.
|
|
33
|
+
*
|
|
34
|
+
* `false` means that the statement may have been sent.
|
|
35
|
+
*/
|
|
36
|
+
readonly unsent: boolean;
|
|
31
37
|
constructor(message: string, options?: {
|
|
32
38
|
cause?: unknown;
|
|
39
|
+
unsent?: boolean | undefined;
|
|
33
40
|
});
|
|
34
41
|
/** Tells whether `value` is an instance of the class, including one of `ConnectionError` of another copy of kern-db. */
|
|
35
42
|
static [Symbol.hasInstance]<T>(this: abstract new (...args: never) => T, value: unknown): value is T;
|
|
36
43
|
}
|
|
37
|
-
/** Fields of the PostgreSQL error that an error of a client carries, by which `toDriverError` classifies it. */
|
|
44
|
+
/** Fields of the PostgreSQL error that an error of a client carries, by which `toDriverError` classifies it, and whether the driver knows that the statement was not sent. */
|
|
38
45
|
interface DriverErrorFields {
|
|
39
46
|
/**
|
|
40
47
|
* Severity of the error, such as `ERROR` or `FATAL`.
|
|
@@ -46,12 +53,18 @@ interface DriverErrorFields {
|
|
|
46
53
|
readonly code?: unknown;
|
|
47
54
|
/** Name of the constraint that the statement violated. */
|
|
48
55
|
readonly constraint?: unknown;
|
|
56
|
+
/**
|
|
57
|
+
* Whether the statement was certainly not sent to the server, such as after a failure to get a connection, which `unsent` of a `ConnectionError` keeps.
|
|
58
|
+
*
|
|
59
|
+
* Leave it unset when the statement may have been sent.
|
|
60
|
+
*/
|
|
61
|
+
readonly unsent?: boolean | undefined;
|
|
49
62
|
}
|
|
50
63
|
/**
|
|
51
64
|
* Classifies an error of a client as `QueryError` or `ConnectionError`, by the fields of the PostgreSQL error it carries, for a driver to reject with.
|
|
52
65
|
*
|
|
53
66
|
* An error that kern-db has already classified returns as it is.
|
|
54
|
-
* An error without a severity or a SQLSTATE, such as of a client that lost its connection, is a `ConnectionError`, and so is one of severity `FATAL` or `PANIC`, which ends the session
|
|
67
|
+
* An error without a severity or a SQLSTATE, such as of a client that lost its connection, is a `ConnectionError`, and so is one of severity `FATAL` or `PANIC`, which ends the session; it gets `unsent` of `fields`.
|
|
55
68
|
* An error of severity `ERROR` is a `QueryError`.
|
|
56
69
|
* With a translated severity, the SQLSTATE tells an error that ends the session, so a few errors of other codes that end it give `QueryError`.
|
|
57
70
|
*/
|
|
@@ -365,10 +378,9 @@ export declare class TransactionConnectionError extends ConnectionError {
|
|
|
365
378
|
*
|
|
366
379
|
* - `TransactionConnectionError` of phase `commit` gives `true`, since `COMMIT` may have succeeded.
|
|
367
380
|
* - `TransactionConnectionError` of another phase gives `false`, since the transaction was not committed.
|
|
381
|
+
* - A `ConnectionError` whose `unsent` is `true`, such as after a failure to get a connection or of a closed driver, gives `false`, since the statement was not sent.
|
|
368
382
|
* - Another `ConnectionError` gives `true`, since a statement outside a transaction may have run before its connection failed.
|
|
369
383
|
* - Any other error gives `false`, such as a `QueryError`, or a `ResultDecodeError` of a statement that has run: `false` does not mean that the operation applied nothing.
|
|
370
|
-
*
|
|
371
|
-
* Classification depends only on the error class, so failures before the statement was sent, such as a failure to acquire a connection, also give `true`.
|
|
372
384
|
*/
|
|
373
385
|
export declare function isOutcomeUnknown(error: unknown): boolean;
|
|
374
386
|
export { type AcceptedNull, type AcceptedValues, type AnyDerivableType, type AnySqlQuery, type AnyType, type BaseDerivableType, type Connection, type Database, type DatabaseOptions, type DecodedFields, type DerivableType, type DerivableTypeWithParameters, type Driver, type DriverErrorFields, type DriverResult, type FieldTypes, type InitialSqlQueryState, type IsolationLevel, NotFoundError, type OneRow, type OneValueRows, type PollLockOptions, type QueryErrorCode, type QueryErrorCondition, type ResultByRows, ResultDecodeError, type ResultRows, type SessionOptions, type SqlFragment, type SqlQuery, type SqlQueryResult, type SqlQueryState, type SqlStatement, type SqlValue, type TextValue, type TransactionOptions, type Type, type TypeInput, type TypeOptions, type TypeOutput, type TypeTransform, type UntypedValue, type ValueRows, createDatabase, createStatement, defineType, identifier, isDatabase, isDriver, isType, param, sql, type typeValues };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { o as defineType, s as isType } from "./bytea-DNZ_ftio.mjs";
|
|
2
2
|
import { C as isDriver, S as createStatement, _ as sql, h as param, i as ResultDecodeError, m as identifier, r as NotFoundError } from "./query-FKBN7BMY.mjs";
|
|
3
|
-
import { a as toDriverError, n as QueryError, t as ConnectionError } from "./driver-error-
|
|
4
|
-
import { a as TransactionConnectionError, i as isQueryError, o as isOutcomeUnknown, r as isDatabase, t as createDatabase } from "./database-
|
|
3
|
+
import { a as toDriverError, n as QueryError, t as ConnectionError } from "./driver-error-D8D4UQ4F.mjs";
|
|
4
|
+
import { a as TransactionConnectionError, i as isQueryError, o as isOutcomeUnknown, r as isDatabase, t as createDatabase } from "./database-D4ql2RZ0.mjs";
|
|
5
5
|
export { ConnectionError, NotFoundError, QueryError, ResultDecodeError, TransactionConnectionError, createDatabase, createStatement, defineType, identifier, isDatabase, isDriver, isOutcomeUnknown, isQueryError, isType, param, sql, toDriverError };
|
package/dist/node-postgres.d.mts
CHANGED
package/dist/node-postgres.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as toDriverError, n as QueryError, t as ConnectionError } from "./driver-error-
|
|
1
|
+
import { a as toDriverError, n as QueryError, t as ConnectionError } from "./driver-error-D8D4UQ4F.mjs";
|
|
2
2
|
// src/drivers/node-postgres.ts
|
|
3
3
|
/** Parsers of a query that keep every value as its text, whatever parsers the client has. */
|
|
4
4
|
const textTypes = { getTypeParser: () => (value) => value };
|
|
@@ -89,21 +89,25 @@ function nodePostgresDriver(pool) {
|
|
|
89
89
|
function endCheckout() {
|
|
90
90
|
if (--checkouts === 0) drained?.resolve();
|
|
91
91
|
}
|
|
92
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* Gets a client from the pool for `operation`, which names it in the error once closing starts.
|
|
94
|
+
*
|
|
95
|
+
* Its errors have `unsent`: the statement waits for the client, so nothing is sent before it.
|
|
96
|
+
*/
|
|
93
97
|
async function checkOut(operation) {
|
|
94
|
-
if (closing) throw new ConnectionError(`Cannot ${operation}: the driver is closed
|
|
98
|
+
if (closing) throw new ConnectionError(`Cannot ${operation}: the driver is closed`, { unsent: true });
|
|
95
99
|
checkouts++;
|
|
96
100
|
try {
|
|
97
101
|
const client = await pool.connect();
|
|
98
102
|
const unsupported = getUnsupportedClientReason(client);
|
|
99
103
|
if (unsupported) {
|
|
100
104
|
client.release();
|
|
101
|
-
throw new ConnectionError(unsupported);
|
|
105
|
+
throw new ConnectionError(unsupported, { unsent: true });
|
|
102
106
|
}
|
|
103
107
|
return client;
|
|
104
108
|
} catch (error) {
|
|
105
109
|
endCheckout();
|
|
106
|
-
throw toDriverError(error);
|
|
110
|
+
throw toDriverError(error, { unsent: true });
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
/** Returns a client to the pool, which closes it with `destroy` or when its connection is lost. */
|
package/dist/postgres-js.d.mts
CHANGED
package/dist/postgres-js.mjs
CHANGED
|
@@ -1,14 +1,40 @@
|
|
|
1
|
-
import { a as toDriverError, t as ConnectionError } from "./driver-error-
|
|
1
|
+
import { a as toDriverError, t as ConnectionError } from "./driver-error-D8D4UQ4F.mjs";
|
|
2
2
|
// src/drivers/postgres-js.ts
|
|
3
3
|
/** OID of the PostgreSQL `unknown` pseudo-type; postgres.js sends such parameters as they are, and PostgreSQL infers their types. */
|
|
4
4
|
const unknownType = 705;
|
|
5
|
+
/**
|
|
6
|
+
* Codes of the errors that postgres.js 4 gives a statement only before it sends the statement.
|
|
7
|
+
*
|
|
8
|
+
* A statement on the pool waits for a connection that has started, and postgres.js rejects the waiting statements with the error of a failed start.
|
|
9
|
+
* The list has no code that a statement that postgres.js sent can also get:
|
|
10
|
+
*
|
|
11
|
+
* - `CONNECTION_CLOSED` and `CONNECTION_DESTROYED`, which a statement gets when its connection fails;
|
|
12
|
+
* - a SQLSTATE of the server, even of a failed start, such as `3D000` of a missing database: a sent statement gets its own `FATAL` error, and a function can raise one of any code, such as with `plpy.fatal` of PL/Python.
|
|
13
|
+
*/
|
|
14
|
+
const unsentCodes = /* @__PURE__ */ new Set([
|
|
15
|
+
"QUEUE_TIMEOUT",
|
|
16
|
+
"CONNECTION_ENDED",
|
|
17
|
+
"MAX_PARAMETERS_EXCEEDED",
|
|
18
|
+
"ECONNREFUSED",
|
|
19
|
+
"ENOTFOUND",
|
|
20
|
+
"EAI_AGAIN",
|
|
21
|
+
"CONNECT_TIMEOUT",
|
|
22
|
+
"SSL_NOT_SUPPORTED",
|
|
23
|
+
"AUTHENTICATION_INCOMPLETE",
|
|
24
|
+
"AUTH_TYPE_NOT_IMPLEMENTED",
|
|
25
|
+
"SASL_MECHANISM_NOT_SUPPORTED",
|
|
26
|
+
"SASL_NONCE_MISMATCH",
|
|
27
|
+
"SASL_SIGNATURE_MISMATCH",
|
|
28
|
+
"CHANNEL_BINDING_REQUIRED"
|
|
29
|
+
]);
|
|
5
30
|
/** Classifies an error of a statement of postgres.js, which gives the severity in English as `severity`, and the constraint as `constraint_name`. */
|
|
6
31
|
function toPostgresJsError(error) {
|
|
7
32
|
const fields = error ?? {};
|
|
8
33
|
return toDriverError(error, {
|
|
9
34
|
severity: fields.severity,
|
|
10
35
|
code: fields.code,
|
|
11
|
-
constraint: fields.constraint_name
|
|
36
|
+
constraint: fields.constraint_name,
|
|
37
|
+
unsent: unsentCodes.has(fields.code)
|
|
12
38
|
});
|
|
13
39
|
}
|
|
14
40
|
/**
|
|
@@ -52,7 +78,7 @@ function postgresJsDriver(sql) {
|
|
|
52
78
|
* `sql.end()` ends the pool only after a few microtasks, and the pool still queues and runs a statement sent before then.
|
|
53
79
|
*/
|
|
54
80
|
function assertOpen(operation) {
|
|
55
|
-
if (closing) throw new ConnectionError(`Cannot ${operation}: the driver is closed
|
|
81
|
+
if (closing) throw new ConnectionError(`Cannot ${operation}: the driver is closed`, { unsent: true });
|
|
56
82
|
}
|
|
57
83
|
return {
|
|
58
84
|
async execute(statement) {
|
|
@@ -69,7 +95,7 @@ function postgresJsDriver(sql) {
|
|
|
69
95
|
try {
|
|
70
96
|
connection = await sql.reserve();
|
|
71
97
|
} catch (error) {
|
|
72
|
-
throw toDriverError(error);
|
|
98
|
+
throw toDriverError(error, { unsent: true });
|
|
73
99
|
}
|
|
74
100
|
return {
|
|
75
101
|
execute: (statement) => execute(connection, statement),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as TextValue, i as SqlStatement, n as Driver, r as DriverResult } from "./driver-
|
|
1
|
+
import { a as TextValue, i as SqlStatement, n as Driver, r as DriverResult } from "./driver-CZCBkque.mjs";
|
|
2
2
|
import { c as Type, d as TypeOutput, i as AnyType } from "./type-CbrtxvDF.mjs";
|
|
3
3
|
/**
|
|
4
4
|
* How a query returns its rows: `many` as an array; `one` as one row, rejecting without it; `nullable` as one row or `null` without it; `optional` as one row or `undefined` without it.
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as Driver, t as Connection } from "./driver-
|
|
2
|
-
import { f as IsolationLevel, u as Database } from "./query-
|
|
1
|
+
import { n as Driver, t as Connection } from "./driver-CZCBkque.mjs";
|
|
2
|
+
import { f as IsolationLevel, u as Database } from "./query-Dxiy1HJD.mjs";
|
|
3
3
|
/** Test fixture of `useTestFixture`, open while the tests of its `describe` block or test file run. */
|
|
4
4
|
interface TestFixture<T = unknown> {
|
|
5
5
|
/** Result of the seed of the fixture; reading it while the fixture is not open throws. */
|
|
@@ -82,6 +82,8 @@ interface DriverContractOptions {
|
|
|
82
82
|
}): Driver;
|
|
83
83
|
/** Creates a driver over a new client of the test database whose parsers of result values throw; for a client without parsers, the same as `createDriver`. */
|
|
84
84
|
createDriverWithFailingParsers(): Driver;
|
|
85
|
+
/** Creates a driver over a new client of an address where no server accepts connections, such as a closed port of the local host, which refuses them at once. */
|
|
86
|
+
createUnreachableDriver(): Driver;
|
|
85
87
|
}
|
|
86
88
|
/**
|
|
87
89
|
* Functions of a test runner that declare the tests of `describeDriverContract`.
|
package/dist/testing.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { r as boolean, t as bytea } from "./bytea-DNZ_ftio.mjs";
|
|
2
2
|
import { S as createStatement, _ as sql, h as param, m as identifier } from "./query-FKBN7BMY.mjs";
|
|
3
|
-
import { n as QueryError, t as ConnectionError } from "./driver-error-
|
|
4
|
-
import { a as TransactionConnectionError, n as getCoordinator, s as pause, t as createDatabase } from "./database-
|
|
3
|
+
import { n as QueryError, t as ConnectionError } from "./driver-error-D8D4UQ4F.mjs";
|
|
4
|
+
import { a as TransactionConnectionError, n as getCoordinator, s as pause, t as createDatabase } from "./database-D4ql2RZ0.mjs";
|
|
5
5
|
import { t as array } from "./array-BLt8ZNR5.mjs";
|
|
6
6
|
import { _ as interval, a as bigint, b as timestamptz, c as numeric, f as inet, g as date, h as enumOf, m as jsonb, n as char, o as doublePrecision, r as text, s as integer, t as uuid, v as time, y as timestamp } from "./types-Dl2oicjV.mjs";
|
|
7
7
|
import assert from "node:assert/strict";
|
|
@@ -51,6 +51,14 @@ function createStatementRunners(target) {
|
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
+
/** Asserts that `promise` rejects with a `ConnectionError` of a statement that the driver did not send. */
|
|
55
|
+
async function assertRejectsUnsent(promise) {
|
|
56
|
+
await assert.rejects(promise, (error) => {
|
|
57
|
+
assert.ok(error instanceof ConnectionError, `Expected ConnectionError, got ${String(error)}`);
|
|
58
|
+
assert.equal(error.unsent, true, `Expected unsent ConnectionError, got ${String(error)}`);
|
|
59
|
+
return true;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
54
62
|
/** Creates the condition that each column named by a key of `types` equals the value of the key in `values`, as a parameter of its type. */
|
|
55
63
|
function equalsEach(types, values) {
|
|
56
64
|
let condition = sql`TRUE`;
|
|
@@ -63,7 +71,7 @@ function equalsEach(types, values) {
|
|
|
63
71
|
* They run in the empty database of its clients and leave it unchanged.
|
|
64
72
|
*/
|
|
65
73
|
function describeDriverContract(options, runner) {
|
|
66
|
-
const { createDriver, createDriverWithFailingParsers } = options;
|
|
74
|
+
const { createDriver, createDriverWithFailingParsers, createUnreachableDriver } = options;
|
|
67
75
|
const { describe, it, before, after } = runner;
|
|
68
76
|
describe("driver contract", () => {
|
|
69
77
|
const driver = createDriver({ max: 2 });
|
|
@@ -423,6 +431,26 @@ function describeDriverContract(options, runner) {
|
|
|
423
431
|
await own.close();
|
|
424
432
|
}
|
|
425
433
|
});
|
|
434
|
+
it("rejects a statement whose connection is lost while it runs with unsent false", async () => {
|
|
435
|
+
const own = createDriver({ max: 1 });
|
|
436
|
+
try {
|
|
437
|
+
const error = await own.execute(createStatement("SELECT pg_terminate_backend(pg_backend_pid())")).catch((error) => error);
|
|
438
|
+
assert.ok(error instanceof ConnectionError, `Expected ConnectionError, got ${String(error)}`);
|
|
439
|
+
assert.equal(error.unsent, false);
|
|
440
|
+
} finally {
|
|
441
|
+
await own.close();
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
it("rejects a statement, a script, and a connection without a server with unsent ConnectionError", async () => {
|
|
445
|
+
const unreachable = createUnreachableDriver();
|
|
446
|
+
try {
|
|
447
|
+
await assertRejectsUnsent(unreachable.execute(createStatement("SELECT 1")));
|
|
448
|
+
await assertRejectsUnsent(unreachable.executeScript("SELECT 1"));
|
|
449
|
+
await assertRejectsUnsent(unreachable.acquire());
|
|
450
|
+
} finally {
|
|
451
|
+
await unreachable.close();
|
|
452
|
+
}
|
|
453
|
+
});
|
|
426
454
|
it("replaces an idle connection whose backend exited", async () => {
|
|
427
455
|
const own = createDriver({ max: 2 });
|
|
428
456
|
const held = [];
|
|
@@ -530,15 +558,15 @@ function describeDriverContract(options, runner) {
|
|
|
530
558
|
assert.equal(await query, "slept");
|
|
531
559
|
assert.deepEqual(settled, ["query", "database"]);
|
|
532
560
|
});
|
|
533
|
-
it("rejects a statement, a script, and a connection requested right after it starts with ConnectionError", async () => {
|
|
561
|
+
it("rejects a statement, a script, and a connection requested right after it starts with unsent ConnectionError", async () => {
|
|
534
562
|
const driver = createDriver({ max: 1 });
|
|
535
563
|
const held = await driver.acquire();
|
|
536
564
|
const closing = driver.close();
|
|
537
565
|
const acquiring = driver.acquire();
|
|
538
566
|
const rejections = [
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
567
|
+
assertRejectsUnsent(driver.execute(createStatement("SELECT 1"))),
|
|
568
|
+
assertRejectsUnsent(driver.executeScript("SELECT 1")),
|
|
569
|
+
assertRejectsUnsent(acquiring)
|
|
542
570
|
];
|
|
543
571
|
acquiring.then((connection) => connection.release()).catch(() => {});
|
|
544
572
|
await held.release();
|