@dudousxd/nestjs-durable-store-drizzle 0.22.0 → 0.24.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/index.cjs +13 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +13 -8
- package/dist/index.js.map +1 -1
- package/dist/pg/index.cjs +123 -45
- package/dist/pg/index.cjs.map +1 -1
- package/dist/pg/index.d.cts +39 -5
- package/dist/pg/index.d.ts +39 -5
- package/dist/pg/index.js +122 -45
- package/dist/pg/index.js.map +1 -1
- package/package.json +3 -3
package/dist/pg/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
2
2
|
import { PgDatabase } from 'drizzle-orm/pg-core';
|
|
3
|
-
import { StateStore, WorkflowRun, RunStatus, RetentionPolicy, StepCheckpoint, StoreTransaction, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, CheckpointStat, CheckpointQuery, SignalWaiter, ChildWait } from '@dudousxd/nestjs-durable-core';
|
|
3
|
+
import { StateStore, WorkflowRun, RunStatus, RetentionPolicy, StepCheckpoint, StoreTransaction, OwnedLeaseReclaim, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, CheckpointStat, CheckpointQuery, SignalWaiter, ChildWait } from '@dudousxd/nestjs-durable-core';
|
|
4
4
|
import { SQL } from 'drizzle-orm';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -22,12 +22,40 @@ import { SQL } from 'drizzle-orm';
|
|
|
22
22
|
* an existing database heals on the next boot exactly like the MikroORM / TypeORM auto-schema does.
|
|
23
23
|
*/
|
|
24
24
|
declare const DURABLE_PG_DDL: readonly string[];
|
|
25
|
+
/**
|
|
26
|
+
* Where {@link ensureDrizzlePgDurableSchema} reports a schema repair it actually applied. `console`
|
|
27
|
+
* (the default) satisfies it, and so does NestJS's `Logger`, so an app can route the warning into
|
|
28
|
+
* its own log stream.
|
|
29
|
+
*/
|
|
30
|
+
interface DurableSchemaLogger {
|
|
31
|
+
warn(message: string): void;
|
|
32
|
+
}
|
|
33
|
+
interface EnsureDrizzlePgDurableSchemaOptions {
|
|
34
|
+
/** Sink for the schema-repair warning. Defaults to `console`. */
|
|
35
|
+
logger?: DurableSchemaLogger | undefined;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The warning logged when the boot-time check changed an EXISTING durable schema: created a table
|
|
39
|
+
* that was missing next to ones that exist, added a column, or created an index. Never logged when
|
|
40
|
+
* the schema was already current, and never on a fresh install (no durable table existed, so
|
|
41
|
+
* creating them all is the expected first boot, not a drift).
|
|
42
|
+
*
|
|
43
|
+
* The discriminator matters more than the wording: a warning on every boot would be filtered as
|
|
44
|
+
* noise, and a silent repair hides a drizzle-kit-managed schema that has drifted from the library.
|
|
45
|
+
*/
|
|
46
|
+
declare function drizzlePgSchemaRepairWarning(repairs: readonly string[]): string;
|
|
25
47
|
/**
|
|
26
48
|
* Idempotently create the durable tables + indexes on `db` (any drizzle Postgres driver). Runs in one
|
|
27
49
|
* transaction under a `pg_advisory_xact_lock`, so N pods booting together heal the schema once and
|
|
28
50
|
* the rest see it done. Only ever touches the `durable_*` tables.
|
|
51
|
+
*
|
|
52
|
+
* The DDL is all `IF NOT EXISTS`, which does not say whether it created anything, so the current
|
|
53
|
+
* durable tables, columns and indexes are read from the catalog first (inside the lock) and each
|
|
54
|
+
* statement that will create something is recorded. When anything was created on an EXISTING durable
|
|
55
|
+
* schema, ONE warning listing it goes to `options.logger` (default `console`) after the transaction
|
|
56
|
+
* commits; see {@link drizzlePgSchemaRepairWarning}. A current schema and a fresh install log nothing.
|
|
29
57
|
*/
|
|
30
|
-
declare function ensureDrizzlePgDurableSchema(db: PgDatabase<any, any, any
|
|
58
|
+
declare function ensureDrizzlePgDurableSchema(db: PgDatabase<any, any, any>, options?: EnsureDrizzlePgDurableSchemaOptions): Promise<void>;
|
|
31
59
|
|
|
32
60
|
/**
|
|
33
61
|
* Any drizzle Postgres database — `drizzle-orm/node-postgres`, `drizzle-orm/postgres-js`,
|
|
@@ -45,6 +73,12 @@ interface DrizzlePgStateStoreOptions {
|
|
|
45
73
|
scope?: {
|
|
46
74
|
namespace?: string | undefined;
|
|
47
75
|
} | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Where `ensureSchema()` (the boot-time auto-schema) reports a schema repair it actually applied
|
|
78
|
+
* — a missing table or index it had to create. Defaults to `console`. NestJS's `Logger`
|
|
79
|
+
* satisfies it.
|
|
80
|
+
*/
|
|
81
|
+
schemaLogger?: DurableSchemaLogger | undefined;
|
|
48
82
|
}
|
|
49
83
|
/**
|
|
50
84
|
* Drizzle `StateStore` for **PostgreSQL**. Pass any drizzle Postgres db (see {@link DrizzlePgDatabase});
|
|
@@ -91,13 +125,13 @@ declare class DrizzlePgStateStore implements StateStore {
|
|
|
91
125
|
transaction<T>(work: (tx: StoreTransaction) => Promise<T>): Promise<T>;
|
|
92
126
|
/** Crash recovery. Namespace-scoped: a worker re-drives only its own tenant's runs. */
|
|
93
127
|
listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
|
|
94
|
-
listOrphanedRuns(nowMs: number, limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
128
|
+
listOrphanedRuns(nowMs: number, limit: number, namespace?: string, ownedBy?: OwnedLeaseReclaim): Promise<WorkflowRun[]>;
|
|
95
129
|
/** FIFO pick-up, served by `durable_workflow_runs_namespace_status_idx`. The engine then leases
|
|
96
130
|
* each run with {@link tryLockRun}; the listing itself takes no locks (it runs outside a tx). */
|
|
97
131
|
listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
98
132
|
listDueTimers(nowMs: number, namespace?: string, limit?: number): Promise<WorkflowRun[]>;
|
|
99
133
|
tryLockRun(runId: string, owner: string, leaseUntilMs: number, nowMs: number): Promise<boolean>;
|
|
100
|
-
releaseRunLock(runId: string): Promise<void>;
|
|
134
|
+
releaseRunLock(runId: string, owner?: string): Promise<void>;
|
|
101
135
|
renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean>;
|
|
102
136
|
/** The predicates every run query shares — {@link listRuns} pages them, the facets group them. */
|
|
103
137
|
private runFilters;
|
|
@@ -2397,4 +2431,4 @@ declare const durablePgSchema: {
|
|
|
2397
2431
|
*/
|
|
2398
2432
|
declare function durablePgManagedTables(): string[];
|
|
2399
2433
|
|
|
2400
|
-
export { DEFAULT_NAMESPACE, DURABLE_PG_DDL, type DrizzlePgDatabase, type DrizzlePgSqlExecutor, DrizzlePgStateStore, type DrizzlePgStateStoreOptions, drizzlePgExecutor, durableBufferedEvents, durableBufferedSignals, durablePgManagedTables, durablePgSchema, durableRunAttributes, durableSchedules, durableSignalWaiters, durableStepCheckpoints, durableWorkflowRuns, ensureDrizzlePgDurableSchema, rowsOf, toDrizzleSql };
|
|
2434
|
+
export { DEFAULT_NAMESPACE, DURABLE_PG_DDL, type DrizzlePgDatabase, type DrizzlePgSqlExecutor, DrizzlePgStateStore, type DrizzlePgStateStoreOptions, type DurableSchemaLogger, type EnsureDrizzlePgDurableSchemaOptions, drizzlePgExecutor, drizzlePgSchemaRepairWarning, durableBufferedEvents, durableBufferedSignals, durablePgManagedTables, durablePgSchema, durableRunAttributes, durableSchedules, durableSignalWaiters, durableStepCheckpoints, durableWorkflowRuns, ensureDrizzlePgDurableSchema, rowsOf, toDrizzleSql };
|
package/dist/pg/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
2
2
|
import { PgDatabase } from 'drizzle-orm/pg-core';
|
|
3
|
-
import { StateStore, WorkflowRun, RunStatus, RetentionPolicy, StepCheckpoint, StoreTransaction, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, CheckpointStat, CheckpointQuery, SignalWaiter, ChildWait } from '@dudousxd/nestjs-durable-core';
|
|
3
|
+
import { StateStore, WorkflowRun, RunStatus, RetentionPolicy, StepCheckpoint, StoreTransaction, OwnedLeaseReclaim, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, CheckpointStat, CheckpointQuery, SignalWaiter, ChildWait } from '@dudousxd/nestjs-durable-core';
|
|
4
4
|
import { SQL } from 'drizzle-orm';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -22,12 +22,40 @@ import { SQL } from 'drizzle-orm';
|
|
|
22
22
|
* an existing database heals on the next boot exactly like the MikroORM / TypeORM auto-schema does.
|
|
23
23
|
*/
|
|
24
24
|
declare const DURABLE_PG_DDL: readonly string[];
|
|
25
|
+
/**
|
|
26
|
+
* Where {@link ensureDrizzlePgDurableSchema} reports a schema repair it actually applied. `console`
|
|
27
|
+
* (the default) satisfies it, and so does NestJS's `Logger`, so an app can route the warning into
|
|
28
|
+
* its own log stream.
|
|
29
|
+
*/
|
|
30
|
+
interface DurableSchemaLogger {
|
|
31
|
+
warn(message: string): void;
|
|
32
|
+
}
|
|
33
|
+
interface EnsureDrizzlePgDurableSchemaOptions {
|
|
34
|
+
/** Sink for the schema-repair warning. Defaults to `console`. */
|
|
35
|
+
logger?: DurableSchemaLogger | undefined;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The warning logged when the boot-time check changed an EXISTING durable schema: created a table
|
|
39
|
+
* that was missing next to ones that exist, added a column, or created an index. Never logged when
|
|
40
|
+
* the schema was already current, and never on a fresh install (no durable table existed, so
|
|
41
|
+
* creating them all is the expected first boot, not a drift).
|
|
42
|
+
*
|
|
43
|
+
* The discriminator matters more than the wording: a warning on every boot would be filtered as
|
|
44
|
+
* noise, and a silent repair hides a drizzle-kit-managed schema that has drifted from the library.
|
|
45
|
+
*/
|
|
46
|
+
declare function drizzlePgSchemaRepairWarning(repairs: readonly string[]): string;
|
|
25
47
|
/**
|
|
26
48
|
* Idempotently create the durable tables + indexes on `db` (any drizzle Postgres driver). Runs in one
|
|
27
49
|
* transaction under a `pg_advisory_xact_lock`, so N pods booting together heal the schema once and
|
|
28
50
|
* the rest see it done. Only ever touches the `durable_*` tables.
|
|
51
|
+
*
|
|
52
|
+
* The DDL is all `IF NOT EXISTS`, which does not say whether it created anything, so the current
|
|
53
|
+
* durable tables, columns and indexes are read from the catalog first (inside the lock) and each
|
|
54
|
+
* statement that will create something is recorded. When anything was created on an EXISTING durable
|
|
55
|
+
* schema, ONE warning listing it goes to `options.logger` (default `console`) after the transaction
|
|
56
|
+
* commits; see {@link drizzlePgSchemaRepairWarning}. A current schema and a fresh install log nothing.
|
|
29
57
|
*/
|
|
30
|
-
declare function ensureDrizzlePgDurableSchema(db: PgDatabase<any, any, any
|
|
58
|
+
declare function ensureDrizzlePgDurableSchema(db: PgDatabase<any, any, any>, options?: EnsureDrizzlePgDurableSchemaOptions): Promise<void>;
|
|
31
59
|
|
|
32
60
|
/**
|
|
33
61
|
* Any drizzle Postgres database — `drizzle-orm/node-postgres`, `drizzle-orm/postgres-js`,
|
|
@@ -45,6 +73,12 @@ interface DrizzlePgStateStoreOptions {
|
|
|
45
73
|
scope?: {
|
|
46
74
|
namespace?: string | undefined;
|
|
47
75
|
} | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Where `ensureSchema()` (the boot-time auto-schema) reports a schema repair it actually applied
|
|
78
|
+
* — a missing table or index it had to create. Defaults to `console`. NestJS's `Logger`
|
|
79
|
+
* satisfies it.
|
|
80
|
+
*/
|
|
81
|
+
schemaLogger?: DurableSchemaLogger | undefined;
|
|
48
82
|
}
|
|
49
83
|
/**
|
|
50
84
|
* Drizzle `StateStore` for **PostgreSQL**. Pass any drizzle Postgres db (see {@link DrizzlePgDatabase});
|
|
@@ -91,13 +125,13 @@ declare class DrizzlePgStateStore implements StateStore {
|
|
|
91
125
|
transaction<T>(work: (tx: StoreTransaction) => Promise<T>): Promise<T>;
|
|
92
126
|
/** Crash recovery. Namespace-scoped: a worker re-drives only its own tenant's runs. */
|
|
93
127
|
listIncompleteRuns(namespace?: string): Promise<WorkflowRun[]>;
|
|
94
|
-
listOrphanedRuns(nowMs: number, limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
128
|
+
listOrphanedRuns(nowMs: number, limit: number, namespace?: string, ownedBy?: OwnedLeaseReclaim): Promise<WorkflowRun[]>;
|
|
95
129
|
/** FIFO pick-up, served by `durable_workflow_runs_namespace_status_idx`. The engine then leases
|
|
96
130
|
* each run with {@link tryLockRun}; the listing itself takes no locks (it runs outside a tx). */
|
|
97
131
|
listPendingRuns(limit: number, namespace?: string): Promise<WorkflowRun[]>;
|
|
98
132
|
listDueTimers(nowMs: number, namespace?: string, limit?: number): Promise<WorkflowRun[]>;
|
|
99
133
|
tryLockRun(runId: string, owner: string, leaseUntilMs: number, nowMs: number): Promise<boolean>;
|
|
100
|
-
releaseRunLock(runId: string): Promise<void>;
|
|
134
|
+
releaseRunLock(runId: string, owner?: string): Promise<void>;
|
|
101
135
|
renewRunLock(runId: string, owner: string, leaseUntilMs: number): Promise<boolean>;
|
|
102
136
|
/** The predicates every run query shares — {@link listRuns} pages them, the facets group them. */
|
|
103
137
|
private runFilters;
|
|
@@ -2397,4 +2431,4 @@ declare const durablePgSchema: {
|
|
|
2397
2431
|
*/
|
|
2398
2432
|
declare function durablePgManagedTables(): string[];
|
|
2399
2433
|
|
|
2400
|
-
export { DEFAULT_NAMESPACE, DURABLE_PG_DDL, type DrizzlePgDatabase, type DrizzlePgSqlExecutor, DrizzlePgStateStore, type DrizzlePgStateStoreOptions, drizzlePgExecutor, durableBufferedEvents, durableBufferedSignals, durablePgManagedTables, durablePgSchema, durableRunAttributes, durableSchedules, durableSignalWaiters, durableStepCheckpoints, durableWorkflowRuns, ensureDrizzlePgDurableSchema, rowsOf, toDrizzleSql };
|
|
2434
|
+
export { DEFAULT_NAMESPACE, DURABLE_PG_DDL, type DrizzlePgDatabase, type DrizzlePgSqlExecutor, DrizzlePgStateStore, type DrizzlePgStateStoreOptions, type DurableSchemaLogger, type EnsureDrizzlePgDurableSchemaOptions, drizzlePgExecutor, drizzlePgSchemaRepairWarning, durableBufferedEvents, durableBufferedSignals, durablePgManagedTables, durablePgSchema, durableRunAttributes, durableSchedules, durableSignalWaiters, durableStepCheckpoints, durableWorkflowRuns, ensureDrizzlePgDurableSchema, rowsOf, toDrizzleSql };
|
package/dist/pg/index.js
CHANGED
|
@@ -2,7 +2,41 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
4
|
// src/pg/ddl.ts
|
|
5
|
+
import { sql as sql2 } from "drizzle-orm";
|
|
6
|
+
|
|
7
|
+
// src/pg/executor.ts
|
|
5
8
|
import { sql } from "drizzle-orm";
|
|
9
|
+
function toDrizzleSql(text2, params = []) {
|
|
10
|
+
const chunks = [];
|
|
11
|
+
let last = 0;
|
|
12
|
+
for (const match of text2.matchAll(/\$(\d+)/g)) {
|
|
13
|
+
const index2 = Number(match[1]) - 1;
|
|
14
|
+
if (index2 < 0 || index2 >= params.length) throw new Error(`placeholder ${match[0]} has no bound parameter`);
|
|
15
|
+
chunks.push(sql.raw(text2.slice(last, match.index)), sql`${params[index2]}`);
|
|
16
|
+
last = (match.index ?? 0) + match[0].length;
|
|
17
|
+
}
|
|
18
|
+
chunks.push(sql.raw(text2.slice(last)));
|
|
19
|
+
return sql.join(chunks);
|
|
20
|
+
}
|
|
21
|
+
__name(toDrizzleSql, "toDrizzleSql");
|
|
22
|
+
function rowsOf(result) {
|
|
23
|
+
if (Array.isArray(result)) return result;
|
|
24
|
+
return result?.rows ?? [];
|
|
25
|
+
}
|
|
26
|
+
__name(rowsOf, "rowsOf");
|
|
27
|
+
function drizzlePgExecutor(db) {
|
|
28
|
+
return {
|
|
29
|
+
dialect: "postgres",
|
|
30
|
+
escapeId: /* @__PURE__ */ __name((id) => `"${id.replace(/"/g, '""')}"`, "escapeId"),
|
|
31
|
+
query: /* @__PURE__ */ __name(async (text2, params) => rowsOf(await db.execute(toDrizzleSql(text2, params))), "query"),
|
|
32
|
+
transaction: /* @__PURE__ */ __name((fn) => db.transaction((tx) => fn({
|
|
33
|
+
query: /* @__PURE__ */ __name(async (text2, params) => rowsOf(await tx.execute(toDrizzleSql(text2, params))), "query")
|
|
34
|
+
})), "transaction")
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
__name(drizzlePgExecutor, "drizzlePgExecutor");
|
|
38
|
+
|
|
39
|
+
// src/pg/ddl.ts
|
|
6
40
|
var DURABLE_PG_DDL = [
|
|
7
41
|
`CREATE TABLE IF NOT EXISTS "durable_workflow_runs" (
|
|
8
42
|
"id" text PRIMARY KEY NOT NULL,
|
|
@@ -95,11 +129,71 @@ var DURABLE_PG_DDL = [
|
|
|
95
129
|
`CREATE INDEX IF NOT EXISTS "durable_schedules_due_idx" ON "durable_schedules" USING btree ("paused","next_fire_at")`
|
|
96
130
|
];
|
|
97
131
|
var SCHEMA_LOCK_KEY = "durable_schema";
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
132
|
+
function drizzlePgSchemaRepairWarning(repairs) {
|
|
133
|
+
return [
|
|
134
|
+
`[nestjs-durable] store-drizzle repaired the durable schema at boot: ${repairs.join("; ")}.`,
|
|
135
|
+
"The database had drifted from the schema this library version expects (it was created by an",
|
|
136
|
+
"older version, or a migration left these out), so they were applied at runtime and nothing",
|
|
137
|
+
"recorded them in your migration history. To make them permanent, generate a drizzle-kit",
|
|
138
|
+
"migration from `durablePgSchema` (or apply `DURABLE_PG_DDL` in a migration). This warning",
|
|
139
|
+
"appears only when a repair was applied; a schema that is already current logs nothing."
|
|
140
|
+
].join(" ");
|
|
141
|
+
}
|
|
142
|
+
__name(drizzlePgSchemaRepairWarning, "drizzlePgSchemaRepairWarning");
|
|
143
|
+
function ddlTarget(statement) {
|
|
144
|
+
const table = statement.match(/^CREATE TABLE IF NOT EXISTS "([^"]+)"/i);
|
|
145
|
+
if (table?.[1]) return {
|
|
146
|
+
kind: "table",
|
|
147
|
+
table: table[1]
|
|
148
|
+
};
|
|
149
|
+
const index2 = statement.match(/^CREATE (?:UNIQUE )?INDEX (?:CONCURRENTLY )?IF NOT EXISTS "([^"]+)" ON "([^"]+)"/i);
|
|
150
|
+
if (index2?.[1] && index2[2]) return {
|
|
151
|
+
kind: "index",
|
|
152
|
+
index: index2[1],
|
|
153
|
+
table: index2[2]
|
|
154
|
+
};
|
|
155
|
+
const column = statement.match(/^ALTER TABLE "([^"]+)" ADD COLUMN IF NOT EXISTS "([^"]+)"/i);
|
|
156
|
+
if (column?.[1] && column[2]) return {
|
|
157
|
+
kind: "column",
|
|
158
|
+
table: column[1],
|
|
159
|
+
column: column[2]
|
|
160
|
+
};
|
|
161
|
+
return void 0;
|
|
162
|
+
}
|
|
163
|
+
__name(ddlTarget, "ddlTarget");
|
|
164
|
+
async function ensureDrizzlePgDurableSchema(db, options = {}) {
|
|
165
|
+
const logger = options.logger ?? console;
|
|
166
|
+
const { repairs, freshInstall } = await db.transaction(async (tx) => {
|
|
167
|
+
await tx.execute(sql2`SELECT pg_advisory_xact_lock(hashtext(${SCHEMA_LOCK_KEY}))`);
|
|
168
|
+
const tables = new Set(rowsOf(await tx.execute(sql2.raw("SELECT tablename AS name FROM pg_tables WHERE schemaname = current_schema() AND left(tablename, 8) = 'durable_'"))).map((row) => row.name));
|
|
169
|
+
const indexes = new Set(rowsOf(await tx.execute(sql2.raw("SELECT indexname AS name FROM pg_indexes WHERE schemaname = current_schema() AND left(tablename, 8) = 'durable_'"))).map((row) => row.name));
|
|
170
|
+
const columns = new Set(rowsOf(await tx.execute(sql2.raw("SELECT table_name || '.' || column_name AS name FROM information_schema.columns WHERE table_schema = current_schema() AND left(table_name, 8) = 'durable_'"))).map((row) => row.name));
|
|
171
|
+
const created = /* @__PURE__ */ new Set();
|
|
172
|
+
const ddlTables = /* @__PURE__ */ new Set();
|
|
173
|
+
const applied = [];
|
|
174
|
+
for (const statement of DURABLE_PG_DDL) {
|
|
175
|
+
const target = ddlTarget(statement);
|
|
176
|
+
await tx.execute(sql2.raw(statement));
|
|
177
|
+
if (!target) continue;
|
|
178
|
+
if (target.kind === "table") {
|
|
179
|
+
ddlTables.add(target.table);
|
|
180
|
+
if (!tables.has(target.table)) {
|
|
181
|
+
created.add(target.table);
|
|
182
|
+
applied.push(`created table ${target.table}`);
|
|
183
|
+
}
|
|
184
|
+
} else if (created.has(target.table)) {
|
|
185
|
+
} else if (target.kind === "index" && !indexes.has(target.index)) {
|
|
186
|
+
applied.push(`created index ${target.index} on ${target.table}`);
|
|
187
|
+
} else if (target.kind === "column" && !columns.has(`${target.table}.${target.column}`)) {
|
|
188
|
+
applied.push(`added column ${target.table}.${target.column}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
repairs: applied,
|
|
193
|
+
freshInstall: created.size === ddlTables.size
|
|
194
|
+
};
|
|
102
195
|
});
|
|
196
|
+
if (repairs.length > 0 && !freshInstall) logger.warn(drizzlePgSchemaRepairWarning(repairs));
|
|
103
197
|
}
|
|
104
198
|
__name(ensureDrizzlePgDurableSchema, "ensureDrizzlePgDurableSchema");
|
|
105
199
|
|
|
@@ -107,38 +201,6 @@ __name(ensureDrizzlePgDurableSchema, "ensureDrizzlePgDurableSchema");
|
|
|
107
201
|
import { RUN_VALUE_FACET_SCAN, SINGLETON_ACTIVE_STATUSES, TERMINAL_RUN_STATUSES, attributePredicateOperands, axisIsRunColumn, clearTerminalSingletonAdmission, mergeRunFacetRows, mergeRunValueFacetRows, normalizeAttributeRows, parseDuration, runValueFacetsFromRuns, singletonAdmissionDenialPatch, singletonAdmissionTags } from "@dudousxd/nestjs-durable-core";
|
|
108
202
|
import { and, asc, desc, eq, exists, getTableColumns, gte, inArray, isNotNull, isNull, like, lt, lte, notInArray, or, sql as sql3 } from "drizzle-orm";
|
|
109
203
|
|
|
110
|
-
// src/pg/executor.ts
|
|
111
|
-
import { sql as sql2 } from "drizzle-orm";
|
|
112
|
-
function toDrizzleSql(text2, params = []) {
|
|
113
|
-
const chunks = [];
|
|
114
|
-
let last = 0;
|
|
115
|
-
for (const match of text2.matchAll(/\$(\d+)/g)) {
|
|
116
|
-
const index2 = Number(match[1]) - 1;
|
|
117
|
-
if (index2 < 0 || index2 >= params.length) throw new Error(`placeholder ${match[0]} has no bound parameter`);
|
|
118
|
-
chunks.push(sql2.raw(text2.slice(last, match.index)), sql2`${params[index2]}`);
|
|
119
|
-
last = (match.index ?? 0) + match[0].length;
|
|
120
|
-
}
|
|
121
|
-
chunks.push(sql2.raw(text2.slice(last)));
|
|
122
|
-
return sql2.join(chunks);
|
|
123
|
-
}
|
|
124
|
-
__name(toDrizzleSql, "toDrizzleSql");
|
|
125
|
-
function rowsOf(result) {
|
|
126
|
-
if (Array.isArray(result)) return result;
|
|
127
|
-
return result?.rows ?? [];
|
|
128
|
-
}
|
|
129
|
-
__name(rowsOf, "rowsOf");
|
|
130
|
-
function drizzlePgExecutor(db) {
|
|
131
|
-
return {
|
|
132
|
-
dialect: "postgres",
|
|
133
|
-
escapeId: /* @__PURE__ */ __name((id) => `"${id.replace(/"/g, '""')}"`, "escapeId"),
|
|
134
|
-
query: /* @__PURE__ */ __name(async (text2, params) => rowsOf(await db.execute(toDrizzleSql(text2, params))), "query"),
|
|
135
|
-
transaction: /* @__PURE__ */ __name((fn) => db.transaction((tx) => fn({
|
|
136
|
-
query: /* @__PURE__ */ __name(async (text2, params) => rowsOf(await tx.execute(toDrizzleSql(text2, params))), "query")
|
|
137
|
-
})), "transaction")
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
__name(drizzlePgExecutor, "drizzlePgExecutor");
|
|
141
|
-
|
|
142
204
|
// src/pg/schema.ts
|
|
143
205
|
import { getTableName } from "drizzle-orm";
|
|
144
206
|
import { bigserial, boolean, doublePrecision, index, integer, jsonb, pgTable, primaryKey, text, timestamp } from "drizzle-orm/pg-core";
|
|
@@ -310,7 +372,14 @@ function anyOf(conditions) {
|
|
|
310
372
|
}
|
|
311
373
|
__name(anyOf, "anyOf");
|
|
312
374
|
function namespaceFilter(namespace) {
|
|
313
|
-
|
|
375
|
+
if (namespace === void 0) return void 0;
|
|
376
|
+
if (namespace === DEFAULT_NAMESPACE || namespace === "") {
|
|
377
|
+
return inArray(durableWorkflowRuns.namespace, [
|
|
378
|
+
DEFAULT_NAMESPACE,
|
|
379
|
+
""
|
|
380
|
+
]);
|
|
381
|
+
}
|
|
382
|
+
return eq(durableWorkflowRuns.namespace, namespace);
|
|
314
383
|
}
|
|
315
384
|
__name(namespaceFilter, "namespaceFilter");
|
|
316
385
|
function hasTag(tag) {
|
|
@@ -344,7 +413,9 @@ var DrizzlePgStateStore = class _DrizzlePgStateStore {
|
|
|
344
413
|
/** Idempotent CREATE TABLE / INDEX IF NOT EXISTS under an advisory lock — called on boot when the
|
|
345
414
|
* module's `autoSchema` is on. Turn `autoSchema` off if drizzle-kit owns these tables. */
|
|
346
415
|
async ensureSchema() {
|
|
347
|
-
await ensureDrizzlePgDurableSchema(this.db
|
|
416
|
+
await ensureDrizzlePgDurableSchema(this.db, {
|
|
417
|
+
logger: this.options.schemaLogger
|
|
418
|
+
});
|
|
348
419
|
}
|
|
349
420
|
/** The read-scope predicate on the runs table (undefined when the store is unscoped). */
|
|
350
421
|
scope() {
|
|
@@ -509,12 +580,17 @@ var DrizzlePgStateStore = class _DrizzlePgStateStore {
|
|
|
509
580
|
]), namespaceFilter(namespace), this.scope()));
|
|
510
581
|
return rows.map(fromRunRow);
|
|
511
582
|
}
|
|
512
|
-
async listOrphanedRuns(nowMs, limit, namespace) {
|
|
583
|
+
async listOrphanedRuns(nowMs, limit, namespace, ownedBy) {
|
|
513
584
|
if (limit <= 0) return [];
|
|
514
585
|
const rows = await this.db.select().from(durableWorkflowRuns).where(and(inArray(durableWorkflowRuns.status, [
|
|
515
586
|
"running",
|
|
516
587
|
"cancelling"
|
|
517
|
-
]), or(
|
|
588
|
+
]), or(
|
|
589
|
+
isNull(durableWorkflowRuns.lockedUntil),
|
|
590
|
+
lte(durableWorkflowRuns.lockedUntil, new Date(nowMs)),
|
|
591
|
+
// A live lease left by a previous process with the caller's own instance id.
|
|
592
|
+
ownedBy ? and(eq(durableWorkflowRuns.lockedBy, ownedBy.owner), lt(durableWorkflowRuns.lockedUntil, new Date(ownedBy.lockedBefore))) : void 0
|
|
593
|
+
), namespaceFilter(namespace), this.scope())).orderBy(asc(durableWorkflowRuns.createdAt)).limit(limit);
|
|
518
594
|
return rows.map(fromRunRow);
|
|
519
595
|
}
|
|
520
596
|
/** FIFO pick-up, served by `durable_workflow_runs_namespace_status_idx`. The engine then leases
|
|
@@ -537,11 +613,11 @@ var DrizzlePgStateStore = class _DrizzlePgStateStore {
|
|
|
537
613
|
});
|
|
538
614
|
return rows.length === 1;
|
|
539
615
|
}
|
|
540
|
-
async releaseRunLock(runId) {
|
|
616
|
+
async releaseRunLock(runId, owner) {
|
|
541
617
|
await this.db.update(durableWorkflowRuns).set({
|
|
542
618
|
lockedBy: null,
|
|
543
619
|
lockedUntil: null
|
|
544
|
-
}).where(eq(durableWorkflowRuns.id, runId));
|
|
620
|
+
}).where(owner === void 0 ? eq(durableWorkflowRuns.id, runId) : and(eq(durableWorkflowRuns.id, runId), eq(durableWorkflowRuns.lockedBy, owner)));
|
|
545
621
|
}
|
|
546
622
|
async renewRunLock(runId, owner, leaseUntilMs) {
|
|
547
623
|
const rows = await this.db.update(durableWorkflowRuns).set({
|
|
@@ -932,7 +1008,7 @@ function toRunRow(run) {
|
|
|
932
1008
|
tags: run.tags ?? null,
|
|
933
1009
|
searchAttributes: run.searchAttributes ?? null,
|
|
934
1010
|
priority: run.priority ?? null,
|
|
935
|
-
namespace: run.namespace
|
|
1011
|
+
namespace: run.namespace || DEFAULT_NAMESPACE,
|
|
936
1012
|
origin: run.origin ?? null,
|
|
937
1013
|
createdAt: run.createdAt,
|
|
938
1014
|
updatedAt: run.updatedAt
|
|
@@ -955,7 +1031,7 @@ function toRunPatch(patch) {
|
|
|
955
1031
|
if ("tags" in patch) row.tags = patch.tags ?? null;
|
|
956
1032
|
if ("searchAttributes" in patch) row.searchAttributes = patch.searchAttributes ?? null;
|
|
957
1033
|
if ("priority" in patch) row.priority = patch.priority ?? null;
|
|
958
|
-
if ("namespace" in patch) row.namespace = patch.namespace
|
|
1034
|
+
if ("namespace" in patch) row.namespace = patch.namespace || DEFAULT_NAMESPACE;
|
|
959
1035
|
if ("origin" in patch) row.origin = patch.origin ?? null;
|
|
960
1036
|
if (patch.createdAt != null) row.createdAt = patch.createdAt;
|
|
961
1037
|
if (patch.updatedAt != null) row.updatedAt = patch.updatedAt;
|
|
@@ -979,7 +1055,7 @@ function fromRunRow(row) {
|
|
|
979
1055
|
tags: row.tags ?? void 0,
|
|
980
1056
|
searchAttributes: row.searchAttributes ?? void 0,
|
|
981
1057
|
priority: row.priority ?? void 0,
|
|
982
|
-
namespace: row.namespace,
|
|
1058
|
+
namespace: row.namespace || DEFAULT_NAMESPACE,
|
|
983
1059
|
origin: row.origin ?? void 0,
|
|
984
1060
|
createdAt: row.createdAt,
|
|
985
1061
|
updatedAt: row.updatedAt
|
|
@@ -1088,6 +1164,7 @@ export {
|
|
|
1088
1164
|
DURABLE_PG_DDL,
|
|
1089
1165
|
DrizzlePgStateStore,
|
|
1090
1166
|
drizzlePgExecutor,
|
|
1167
|
+
drizzlePgSchemaRepairWarning,
|
|
1091
1168
|
durableBufferedEvents,
|
|
1092
1169
|
durableBufferedSignals,
|
|
1093
1170
|
durablePgManagedTables,
|