@duraflows/kysely 4.0.1 → 4.1.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 +14 -1
- package/dist/cjs/index.d.ts +8 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/kysely-history-store.js +5 -1
- package/dist/cjs/kysely-transaction-runner.d.ts +39 -1
- package/dist/cjs/kysely-transaction-runner.js +48 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +2 -2
- package/dist/kysely-history-store.js +5 -1
- package/dist/kysely-transaction-runner.d.ts +39 -1
- package/dist/kysely-transaction-runner.js +48 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -103,7 +103,7 @@ See the [`@duraflows/pg` README](https://github.com/camcima/duraflows/tree/main/
|
|
|
103
103
|
|
|
104
104
|
## API
|
|
105
105
|
|
|
106
|
-
### `kyselyWorkflowProviders(db): WorkflowPersistenceProvider`
|
|
106
|
+
### `kyselyWorkflowProviders(db, options?): WorkflowPersistenceProvider`
|
|
107
107
|
|
|
108
108
|
Factory function that creates all required persistence providers from a `Kysely<WorkflowDatabase>` instance. Returns:
|
|
109
109
|
|
|
@@ -111,6 +111,19 @@ Factory function that creates all required persistence providers from a `Kysely<
|
|
|
111
111
|
- `historyStore` -- `KyselyWorkflowHistoryStore`
|
|
112
112
|
- `transactionRunner` -- `KyselyTransactionRunner`
|
|
113
113
|
|
|
114
|
+
Options (all optional; omitting them keeps the previous behaviour):
|
|
115
|
+
|
|
116
|
+
- `lockTimeoutMs` -- sets `lock_timeout` for the duration of each transaction. Bounds how long a statement **waits for a row lock**, so a stuck lock holder cannot hang `triggerEvent()` while it keeps a pooled connection checked out. **This is the recommended setting.**
|
|
117
|
+
- `statementTimeoutMs` -- sets `statement_timeout` for the duration of each transaction. Bounds how long **any single statement** may run — including SQL your own commands issue inside the transaction, which is why it is left unset by default: a legitimately slow command statement would be aborted and take the whole transition with it.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const persistence = kyselyWorkflowProviders(db, { lockTimeoutMs: 3000 });
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Both are applied transaction-locally via `set_config(name, value, true)` — the function form of `SET LOCAL` — so they are reverted on `COMMIT`/`ROLLBACK` and never leak to other users of the shared pool. Values must be non-negative integers in milliseconds (`0` means "no timeout"); anything else throws a `WorkflowError` at construction time.
|
|
124
|
+
|
|
125
|
+
`kyselyWorkflowProvidersFromTransaction()` takes no timeout options: the transaction is owned by the caller, so its settings are the caller's to configure.
|
|
126
|
+
|
|
114
127
|
### `kyselyWorkflowProvidersFromTransaction(trx): WorkflowPersistenceProvider`
|
|
115
128
|
|
|
116
129
|
Convenience factory for short-lived runtimes pre-bound to an existing transaction. The returned transaction runner seeds the context with the bound `trx` if no context already exists.
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { Kysely, Transaction } from "kysely";
|
|
2
2
|
import type { WorkflowPersistenceProvider } from "@duraflows/core";
|
|
3
3
|
import type { WorkflowDatabase } from "./kysely-database.js";
|
|
4
|
+
import { type KyselyTransactionRunnerOptions } from "./kysely-transaction-runner.js";
|
|
4
5
|
export { KyselyTransactionContext } from "./kysely-transaction-context.js";
|
|
5
6
|
export { KyselyTransactionRunner } from "./kysely-transaction-runner.js";
|
|
7
|
+
export type { KyselyTransactionRunnerOptions } from "./kysely-transaction-runner.js";
|
|
6
8
|
export { KyselyWorkflowInstanceStore } from "./kysely-instance-store.js";
|
|
7
9
|
export { KyselyWorkflowHistoryStore } from "./kysely-history-store.js";
|
|
8
10
|
export type { WorkflowDatabase, WorkflowInstancesTable, WorkflowHistoryTable } from "./kysely-database.js";
|
|
11
|
+
/**
|
|
12
|
+
* Options accepted by {@link kyselyWorkflowProviders}. Every field is optional
|
|
13
|
+
* and omitting the argument entirely reproduces the pre-existing behaviour.
|
|
14
|
+
*/
|
|
15
|
+
export type KyselyWorkflowProvidersOptions = KyselyTransactionRunnerOptions;
|
|
9
16
|
/**
|
|
10
17
|
* Creates long-lived persistence providers from a Kysely instance.
|
|
11
18
|
*
|
|
@@ -14,7 +21,7 @@ export type { WorkflowDatabase, WorkflowInstancesTable, WorkflowHistoryTable } f
|
|
|
14
21
|
* only access workflow tables; the `unknown` cast is needed because
|
|
15
22
|
* Kysely is invariant in its DB type parameter).
|
|
16
23
|
*/
|
|
17
|
-
export declare function kyselyWorkflowProviders<DB extends WorkflowDatabase>(db: Kysely<DB
|
|
24
|
+
export declare function kyselyWorkflowProviders<DB extends WorkflowDatabase>(db: Kysely<DB>, options?: KyselyWorkflowProvidersOptions): WorkflowPersistenceProvider;
|
|
18
25
|
/**
|
|
19
26
|
* Creates providers pre-bound to an existing Kysely transaction.
|
|
20
27
|
*
|
package/dist/cjs/index.js
CHANGED
|
@@ -23,9 +23,9 @@ Object.defineProperty(exports, "KyselyWorkflowHistoryStore", { enumerable: true,
|
|
|
23
23
|
* only access workflow tables; the `unknown` cast is needed because
|
|
24
24
|
* Kysely is invariant in its DB type parameter).
|
|
25
25
|
*/
|
|
26
|
-
function kyselyWorkflowProviders(db) {
|
|
26
|
+
function kyselyWorkflowProviders(db, options = {}) {
|
|
27
27
|
const narrowed = db;
|
|
28
|
-
const transactionRunner = new kysely_transaction_runner_js_1.KyselyTransactionRunner(narrowed);
|
|
28
|
+
const transactionRunner = new kysely_transaction_runner_js_1.KyselyTransactionRunner(narrowed, options);
|
|
29
29
|
const instanceStore = new kysely_instance_store_js_1.KyselyWorkflowInstanceStore(narrowed);
|
|
30
30
|
const historyStore = new kysely_history_store_js_1.KyselyWorkflowHistoryStore(narrowed);
|
|
31
31
|
return { instanceStore, historyStore, transactionRunner };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KyselyWorkflowHistoryStore = void 0;
|
|
4
|
+
const core_1 = require("@duraflows/core");
|
|
4
5
|
const kysely_transaction_context_js_1 = require("./kysely-transaction-context.js");
|
|
5
6
|
class KyselyWorkflowHistoryStore {
|
|
6
7
|
db;
|
|
@@ -26,7 +27,10 @@ class KyselyWorkflowHistoryStore {
|
|
|
26
27
|
trigger_metadata_json: JSON.stringify(entry.triggerMetadata ?? {}),
|
|
27
28
|
})
|
|
28
29
|
.returning("uuid")
|
|
29
|
-
|
|
30
|
+
// `INSERT ... RETURNING` always yields a row, so an empty result means the
|
|
31
|
+
// statement did not do what the adapter assumes. Surface that as the
|
|
32
|
+
// library's own error type rather than kysely's `NoResultError`.
|
|
33
|
+
.executeTakeFirstOrThrow(() => new core_1.WorkflowError("Failed to append workflow history: INSERT ... RETURNING uuid returned no row"));
|
|
30
34
|
return row.uuid;
|
|
31
35
|
}
|
|
32
36
|
async findByInstanceUuid(workflowInstanceUuid, options) {
|
|
@@ -1,9 +1,47 @@
|
|
|
1
1
|
import type { Kysely } from "kysely";
|
|
2
2
|
import type { WorkflowTransactionRunner } from "@duraflows/core";
|
|
3
3
|
import type { WorkflowDatabase } from "./kysely-database.js";
|
|
4
|
+
/**
|
|
5
|
+
* Transaction-scoped PostgreSQL timeouts.
|
|
6
|
+
*
|
|
7
|
+
* Both settings are optional and both default to unset: when neither is
|
|
8
|
+
* supplied the runner issues no extra statement at all, leaving the session and
|
|
9
|
+
* server defaults exactly as they were before this option existed.
|
|
10
|
+
*/
|
|
11
|
+
export interface KyselyTransactionRunnerOptions {
|
|
12
|
+
/**
|
|
13
|
+
* `lock_timeout` in milliseconds -- how long a statement waits for a row lock
|
|
14
|
+
* before it aborts. This is the recommended setting: it bounds the blocking
|
|
15
|
+
* `SELECT ... FOR UPDATE` behind `lockByUuid()`, so a stuck lock holder cannot
|
|
16
|
+
* hang a `triggerEvent()` call indefinitely while it keeps a pooled connection
|
|
17
|
+
* checked out. `0` disables the timeout (PostgreSQL's own default).
|
|
18
|
+
*/
|
|
19
|
+
lockTimeoutMs?: number;
|
|
20
|
+
/**
|
|
21
|
+
* `statement_timeout` in milliseconds -- how long any single statement may run
|
|
22
|
+
* before it aborts. Deliberately unset by default: commands run inside the
|
|
23
|
+
* same transaction and may legitimately issue slow statements on the shared
|
|
24
|
+
* connection, and aborting one of those rolls the whole transition back.
|
|
25
|
+
* `0` disables the timeout (PostgreSQL's own default).
|
|
26
|
+
*/
|
|
27
|
+
statementTimeoutMs?: number;
|
|
28
|
+
}
|
|
4
29
|
export declare class KyselyTransactionRunner implements WorkflowTransactionRunner {
|
|
5
30
|
private readonly db;
|
|
6
|
-
|
|
31
|
+
private readonly timeoutSettings;
|
|
32
|
+
constructor(db: Kysely<WorkflowDatabase>, options?: KyselyTransactionRunnerOptions);
|
|
7
33
|
runInTransaction<T>(callback: () => Promise<T>): Promise<T>;
|
|
34
|
+
/**
|
|
35
|
+
* Applies the configured timeouts to `trx` as transaction-local settings, so
|
|
36
|
+
* they are reverted on COMMIT/ROLLBACK and never leak to other users of the
|
|
37
|
+
* shared pool.
|
|
38
|
+
*
|
|
39
|
+
* `set_config(name, value, is_local = true)` is the function form of
|
|
40
|
+
* `SET LOCAL`, reached through the query builder rather than kysely's `sql`
|
|
41
|
+
* template on purpose: this package imports kysely for types only, which is
|
|
42
|
+
* what keeps its CommonJS build loadable (kysely itself is ESM-only). Both
|
|
43
|
+
* arguments are bound parameters, so no value is ever interpolated into SQL.
|
|
44
|
+
*/
|
|
45
|
+
private applyTimeouts;
|
|
8
46
|
}
|
|
9
47
|
//# sourceMappingURL=kysely-transaction-runner.d.ts.map
|
|
@@ -1,11 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.KyselyTransactionRunner = void 0;
|
|
4
|
+
const core_1 = require("@duraflows/core");
|
|
4
5
|
const kysely_transaction_context_js_1 = require("./kysely-transaction-context.js");
|
|
6
|
+
/**
|
|
7
|
+
* Rejects anything that is not a finite, non-negative integer. Called at
|
|
8
|
+
* construction time so an invalid value can never reach the database.
|
|
9
|
+
*/
|
|
10
|
+
function assertTimeoutMs(value, name) {
|
|
11
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
12
|
+
throw new core_1.WorkflowError(`${name} must be a non-negative integer number of milliseconds, got ${value}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the configured timeouts into `(setting, value)` pairs, or an empty
|
|
17
|
+
* list when neither is configured.
|
|
18
|
+
*/
|
|
19
|
+
function buildTimeoutSettings(options) {
|
|
20
|
+
const settings = [];
|
|
21
|
+
if (options.lockTimeoutMs !== undefined) {
|
|
22
|
+
assertTimeoutMs(options.lockTimeoutMs, "lockTimeoutMs");
|
|
23
|
+
settings.push(["lock_timeout", String(options.lockTimeoutMs)]);
|
|
24
|
+
}
|
|
25
|
+
if (options.statementTimeoutMs !== undefined) {
|
|
26
|
+
assertTimeoutMs(options.statementTimeoutMs, "statementTimeoutMs");
|
|
27
|
+
settings.push(["statement_timeout", String(options.statementTimeoutMs)]);
|
|
28
|
+
}
|
|
29
|
+
return settings;
|
|
30
|
+
}
|
|
5
31
|
class KyselyTransactionRunner {
|
|
6
32
|
db;
|
|
7
|
-
|
|
33
|
+
timeoutSettings;
|
|
34
|
+
constructor(db, options = {}) {
|
|
8
35
|
this.db = db;
|
|
36
|
+
this.timeoutSettings = buildTimeoutSettings(options);
|
|
9
37
|
}
|
|
10
38
|
async runInTransaction(callback) {
|
|
11
39
|
const existing = kysely_transaction_context_js_1.KyselyTransactionContext.getTransaction(this.db);
|
|
@@ -13,9 +41,28 @@ class KyselyTransactionRunner {
|
|
|
13
41
|
return callback();
|
|
14
42
|
}
|
|
15
43
|
return this.db.transaction().execute(async (trx) => {
|
|
44
|
+
await this.applyTimeouts(trx);
|
|
16
45
|
return kysely_transaction_context_js_1.KyselyTransactionContext.run(this.db, trx, callback);
|
|
17
46
|
});
|
|
18
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Applies the configured timeouts to `trx` as transaction-local settings, so
|
|
50
|
+
* they are reverted on COMMIT/ROLLBACK and never leak to other users of the
|
|
51
|
+
* shared pool.
|
|
52
|
+
*
|
|
53
|
+
* `set_config(name, value, is_local = true)` is the function form of
|
|
54
|
+
* `SET LOCAL`, reached through the query builder rather than kysely's `sql`
|
|
55
|
+
* template on purpose: this package imports kysely for types only, which is
|
|
56
|
+
* what keeps its CommonJS build loadable (kysely itself is ESM-only). Both
|
|
57
|
+
* arguments are bound parameters, so no value is ever interpolated into SQL.
|
|
58
|
+
*/
|
|
59
|
+
async applyTimeouts(trx) {
|
|
60
|
+
for (const [setting, value] of this.timeoutSettings) {
|
|
61
|
+
await trx
|
|
62
|
+
.selectNoFrom((eb) => eb.fn("set_config", [eb.val(setting), eb.val(value), eb.val(true)]).as("set_config"))
|
|
63
|
+
.executeTakeFirst();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
19
66
|
}
|
|
20
67
|
exports.KyselyTransactionRunner = KyselyTransactionRunner;
|
|
21
68
|
//# sourceMappingURL=kysely-transaction-runner.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { Kysely, Transaction } from "kysely";
|
|
2
2
|
import type { WorkflowPersistenceProvider } from "@duraflows/core";
|
|
3
3
|
import type { WorkflowDatabase } from "./kysely-database.js";
|
|
4
|
+
import { type KyselyTransactionRunnerOptions } from "./kysely-transaction-runner.js";
|
|
4
5
|
export { KyselyTransactionContext } from "./kysely-transaction-context.js";
|
|
5
6
|
export { KyselyTransactionRunner } from "./kysely-transaction-runner.js";
|
|
7
|
+
export type { KyselyTransactionRunnerOptions } from "./kysely-transaction-runner.js";
|
|
6
8
|
export { KyselyWorkflowInstanceStore } from "./kysely-instance-store.js";
|
|
7
9
|
export { KyselyWorkflowHistoryStore } from "./kysely-history-store.js";
|
|
8
10
|
export type { WorkflowDatabase, WorkflowInstancesTable, WorkflowHistoryTable } from "./kysely-database.js";
|
|
11
|
+
/**
|
|
12
|
+
* Options accepted by {@link kyselyWorkflowProviders}. Every field is optional
|
|
13
|
+
* and omitting the argument entirely reproduces the pre-existing behaviour.
|
|
14
|
+
*/
|
|
15
|
+
export type KyselyWorkflowProvidersOptions = KyselyTransactionRunnerOptions;
|
|
9
16
|
/**
|
|
10
17
|
* Creates long-lived persistence providers from a Kysely instance.
|
|
11
18
|
*
|
|
@@ -14,7 +21,7 @@ export type { WorkflowDatabase, WorkflowInstancesTable, WorkflowHistoryTable } f
|
|
|
14
21
|
* only access workflow tables; the `unknown` cast is needed because
|
|
15
22
|
* Kysely is invariant in its DB type parameter).
|
|
16
23
|
*/
|
|
17
|
-
export declare function kyselyWorkflowProviders<DB extends WorkflowDatabase>(db: Kysely<DB
|
|
24
|
+
export declare function kyselyWorkflowProviders<DB extends WorkflowDatabase>(db: Kysely<DB>, options?: KyselyWorkflowProvidersOptions): WorkflowPersistenceProvider;
|
|
18
25
|
/**
|
|
19
26
|
* Creates providers pre-bound to an existing Kysely transaction.
|
|
20
27
|
*
|
package/dist/index.js
CHANGED
|
@@ -14,9 +14,9 @@ export { KyselyWorkflowHistoryStore } from "./kysely-history-store.js";
|
|
|
14
14
|
* only access workflow tables; the `unknown` cast is needed because
|
|
15
15
|
* Kysely is invariant in its DB type parameter).
|
|
16
16
|
*/
|
|
17
|
-
export function kyselyWorkflowProviders(db) {
|
|
17
|
+
export function kyselyWorkflowProviders(db, options = {}) {
|
|
18
18
|
const narrowed = db;
|
|
19
|
-
const transactionRunner = new KyselyTransactionRunner(narrowed);
|
|
19
|
+
const transactionRunner = new KyselyTransactionRunner(narrowed, options);
|
|
20
20
|
const instanceStore = new KyselyWorkflowInstanceStore(narrowed);
|
|
21
21
|
const historyStore = new KyselyWorkflowHistoryStore(narrowed);
|
|
22
22
|
return { instanceStore, historyStore, transactionRunner };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WorkflowError } from "@duraflows/core";
|
|
1
2
|
import { KyselyTransactionContext } from "./kysely-transaction-context.js";
|
|
2
3
|
export class KyselyWorkflowHistoryStore {
|
|
3
4
|
db;
|
|
@@ -23,7 +24,10 @@ export class KyselyWorkflowHistoryStore {
|
|
|
23
24
|
trigger_metadata_json: JSON.stringify(entry.triggerMetadata ?? {}),
|
|
24
25
|
})
|
|
25
26
|
.returning("uuid")
|
|
26
|
-
|
|
27
|
+
// `INSERT ... RETURNING` always yields a row, so an empty result means the
|
|
28
|
+
// statement did not do what the adapter assumes. Surface that as the
|
|
29
|
+
// library's own error type rather than kysely's `NoResultError`.
|
|
30
|
+
.executeTakeFirstOrThrow(() => new WorkflowError("Failed to append workflow history: INSERT ... RETURNING uuid returned no row"));
|
|
27
31
|
return row.uuid;
|
|
28
32
|
}
|
|
29
33
|
async findByInstanceUuid(workflowInstanceUuid, options) {
|
|
@@ -1,9 +1,47 @@
|
|
|
1
1
|
import type { Kysely } from "kysely";
|
|
2
2
|
import type { WorkflowTransactionRunner } from "@duraflows/core";
|
|
3
3
|
import type { WorkflowDatabase } from "./kysely-database.js";
|
|
4
|
+
/**
|
|
5
|
+
* Transaction-scoped PostgreSQL timeouts.
|
|
6
|
+
*
|
|
7
|
+
* Both settings are optional and both default to unset: when neither is
|
|
8
|
+
* supplied the runner issues no extra statement at all, leaving the session and
|
|
9
|
+
* server defaults exactly as they were before this option existed.
|
|
10
|
+
*/
|
|
11
|
+
export interface KyselyTransactionRunnerOptions {
|
|
12
|
+
/**
|
|
13
|
+
* `lock_timeout` in milliseconds -- how long a statement waits for a row lock
|
|
14
|
+
* before it aborts. This is the recommended setting: it bounds the blocking
|
|
15
|
+
* `SELECT ... FOR UPDATE` behind `lockByUuid()`, so a stuck lock holder cannot
|
|
16
|
+
* hang a `triggerEvent()` call indefinitely while it keeps a pooled connection
|
|
17
|
+
* checked out. `0` disables the timeout (PostgreSQL's own default).
|
|
18
|
+
*/
|
|
19
|
+
lockTimeoutMs?: number;
|
|
20
|
+
/**
|
|
21
|
+
* `statement_timeout` in milliseconds -- how long any single statement may run
|
|
22
|
+
* before it aborts. Deliberately unset by default: commands run inside the
|
|
23
|
+
* same transaction and may legitimately issue slow statements on the shared
|
|
24
|
+
* connection, and aborting one of those rolls the whole transition back.
|
|
25
|
+
* `0` disables the timeout (PostgreSQL's own default).
|
|
26
|
+
*/
|
|
27
|
+
statementTimeoutMs?: number;
|
|
28
|
+
}
|
|
4
29
|
export declare class KyselyTransactionRunner implements WorkflowTransactionRunner {
|
|
5
30
|
private readonly db;
|
|
6
|
-
|
|
31
|
+
private readonly timeoutSettings;
|
|
32
|
+
constructor(db: Kysely<WorkflowDatabase>, options?: KyselyTransactionRunnerOptions);
|
|
7
33
|
runInTransaction<T>(callback: () => Promise<T>): Promise<T>;
|
|
34
|
+
/**
|
|
35
|
+
* Applies the configured timeouts to `trx` as transaction-local settings, so
|
|
36
|
+
* they are reverted on COMMIT/ROLLBACK and never leak to other users of the
|
|
37
|
+
* shared pool.
|
|
38
|
+
*
|
|
39
|
+
* `set_config(name, value, is_local = true)` is the function form of
|
|
40
|
+
* `SET LOCAL`, reached through the query builder rather than kysely's `sql`
|
|
41
|
+
* template on purpose: this package imports kysely for types only, which is
|
|
42
|
+
* what keeps its CommonJS build loadable (kysely itself is ESM-only). Both
|
|
43
|
+
* arguments are bound parameters, so no value is ever interpolated into SQL.
|
|
44
|
+
*/
|
|
45
|
+
private applyTimeouts;
|
|
8
46
|
}
|
|
9
47
|
//# sourceMappingURL=kysely-transaction-runner.d.ts.map
|
|
@@ -1,8 +1,36 @@
|
|
|
1
|
+
import { WorkflowError } from "@duraflows/core";
|
|
1
2
|
import { KyselyTransactionContext } from "./kysely-transaction-context.js";
|
|
3
|
+
/**
|
|
4
|
+
* Rejects anything that is not a finite, non-negative integer. Called at
|
|
5
|
+
* construction time so an invalid value can never reach the database.
|
|
6
|
+
*/
|
|
7
|
+
function assertTimeoutMs(value, name) {
|
|
8
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
9
|
+
throw new WorkflowError(`${name} must be a non-negative integer number of milliseconds, got ${value}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Resolves the configured timeouts into `(setting, value)` pairs, or an empty
|
|
14
|
+
* list when neither is configured.
|
|
15
|
+
*/
|
|
16
|
+
function buildTimeoutSettings(options) {
|
|
17
|
+
const settings = [];
|
|
18
|
+
if (options.lockTimeoutMs !== undefined) {
|
|
19
|
+
assertTimeoutMs(options.lockTimeoutMs, "lockTimeoutMs");
|
|
20
|
+
settings.push(["lock_timeout", String(options.lockTimeoutMs)]);
|
|
21
|
+
}
|
|
22
|
+
if (options.statementTimeoutMs !== undefined) {
|
|
23
|
+
assertTimeoutMs(options.statementTimeoutMs, "statementTimeoutMs");
|
|
24
|
+
settings.push(["statement_timeout", String(options.statementTimeoutMs)]);
|
|
25
|
+
}
|
|
26
|
+
return settings;
|
|
27
|
+
}
|
|
2
28
|
export class KyselyTransactionRunner {
|
|
3
29
|
db;
|
|
4
|
-
|
|
30
|
+
timeoutSettings;
|
|
31
|
+
constructor(db, options = {}) {
|
|
5
32
|
this.db = db;
|
|
33
|
+
this.timeoutSettings = buildTimeoutSettings(options);
|
|
6
34
|
}
|
|
7
35
|
async runInTransaction(callback) {
|
|
8
36
|
const existing = KyselyTransactionContext.getTransaction(this.db);
|
|
@@ -10,8 +38,27 @@ export class KyselyTransactionRunner {
|
|
|
10
38
|
return callback();
|
|
11
39
|
}
|
|
12
40
|
return this.db.transaction().execute(async (trx) => {
|
|
41
|
+
await this.applyTimeouts(trx);
|
|
13
42
|
return KyselyTransactionContext.run(this.db, trx, callback);
|
|
14
43
|
});
|
|
15
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Applies the configured timeouts to `trx` as transaction-local settings, so
|
|
47
|
+
* they are reverted on COMMIT/ROLLBACK and never leak to other users of the
|
|
48
|
+
* shared pool.
|
|
49
|
+
*
|
|
50
|
+
* `set_config(name, value, is_local = true)` is the function form of
|
|
51
|
+
* `SET LOCAL`, reached through the query builder rather than kysely's `sql`
|
|
52
|
+
* template on purpose: this package imports kysely for types only, which is
|
|
53
|
+
* what keeps its CommonJS build loadable (kysely itself is ESM-only). Both
|
|
54
|
+
* arguments are bound parameters, so no value is ever interpolated into SQL.
|
|
55
|
+
*/
|
|
56
|
+
async applyTimeouts(trx) {
|
|
57
|
+
for (const [setting, value] of this.timeoutSettings) {
|
|
58
|
+
await trx
|
|
59
|
+
.selectNoFrom((eb) => eb.fn("set_config", [eb.val(setting), eb.val(value), eb.val(true)]).as("set_config"))
|
|
60
|
+
.executeTakeFirst();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
16
63
|
}
|
|
17
64
|
//# sourceMappingURL=kysely-transaction-runner.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duraflows/kysely",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "PostgreSQL persistence adapter for duraflows using `kysely`. Integrates with kysely's type-safe query builder and AsyncLocalStorage-based transaction context.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"duraflows",
|
|
@@ -51,15 +51,15 @@
|
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@duraflows/core": "^4.0
|
|
54
|
+
"@duraflows/core": "^4.1.0",
|
|
55
55
|
"kysely": "^0.29.4"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@types/pg": "^8.20.4",
|
|
59
59
|
"kysely": "^0.29.4",
|
|
60
60
|
"pg": "^8.22.0",
|
|
61
|
-
"@duraflows/
|
|
62
|
-
"@duraflows/
|
|
61
|
+
"@duraflows/pg": "4.1.0",
|
|
62
|
+
"@duraflows/core": "4.1.0"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"build": "tsc --build"
|