@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.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(pg_exports, {
|
|
|
25
25
|
DURABLE_PG_DDL: () => DURABLE_PG_DDL,
|
|
26
26
|
DrizzlePgStateStore: () => DrizzlePgStateStore,
|
|
27
27
|
drizzlePgExecutor: () => drizzlePgExecutor,
|
|
28
|
+
drizzlePgSchemaRepairWarning: () => drizzlePgSchemaRepairWarning,
|
|
28
29
|
durableBufferedEvents: () => durableBufferedEvents,
|
|
29
30
|
durableBufferedSignals: () => durableBufferedSignals,
|
|
30
31
|
durablePgManagedTables: () => durablePgManagedTables,
|
|
@@ -41,7 +42,41 @@ __export(pg_exports, {
|
|
|
41
42
|
module.exports = __toCommonJS(pg_exports);
|
|
42
43
|
|
|
43
44
|
// src/pg/ddl.ts
|
|
45
|
+
var import_drizzle_orm2 = require("drizzle-orm");
|
|
46
|
+
|
|
47
|
+
// src/pg/executor.ts
|
|
44
48
|
var import_drizzle_orm = require("drizzle-orm");
|
|
49
|
+
function toDrizzleSql(text2, params = []) {
|
|
50
|
+
const chunks = [];
|
|
51
|
+
let last = 0;
|
|
52
|
+
for (const match of text2.matchAll(/\$(\d+)/g)) {
|
|
53
|
+
const index2 = Number(match[1]) - 1;
|
|
54
|
+
if (index2 < 0 || index2 >= params.length) throw new Error(`placeholder ${match[0]} has no bound parameter`);
|
|
55
|
+
chunks.push(import_drizzle_orm.sql.raw(text2.slice(last, match.index)), import_drizzle_orm.sql`${params[index2]}`);
|
|
56
|
+
last = (match.index ?? 0) + match[0].length;
|
|
57
|
+
}
|
|
58
|
+
chunks.push(import_drizzle_orm.sql.raw(text2.slice(last)));
|
|
59
|
+
return import_drizzle_orm.sql.join(chunks);
|
|
60
|
+
}
|
|
61
|
+
__name(toDrizzleSql, "toDrizzleSql");
|
|
62
|
+
function rowsOf(result) {
|
|
63
|
+
if (Array.isArray(result)) return result;
|
|
64
|
+
return result?.rows ?? [];
|
|
65
|
+
}
|
|
66
|
+
__name(rowsOf, "rowsOf");
|
|
67
|
+
function drizzlePgExecutor(db) {
|
|
68
|
+
return {
|
|
69
|
+
dialect: "postgres",
|
|
70
|
+
escapeId: /* @__PURE__ */ __name((id) => `"${id.replace(/"/g, '""')}"`, "escapeId"),
|
|
71
|
+
query: /* @__PURE__ */ __name(async (text2, params) => rowsOf(await db.execute(toDrizzleSql(text2, params))), "query"),
|
|
72
|
+
transaction: /* @__PURE__ */ __name((fn) => db.transaction((tx) => fn({
|
|
73
|
+
query: /* @__PURE__ */ __name(async (text2, params) => rowsOf(await tx.execute(toDrizzleSql(text2, params))), "query")
|
|
74
|
+
})), "transaction")
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
__name(drizzlePgExecutor, "drizzlePgExecutor");
|
|
78
|
+
|
|
79
|
+
// src/pg/ddl.ts
|
|
45
80
|
var DURABLE_PG_DDL = [
|
|
46
81
|
`CREATE TABLE IF NOT EXISTS "durable_workflow_runs" (
|
|
47
82
|
"id" text PRIMARY KEY NOT NULL,
|
|
@@ -134,11 +169,71 @@ var DURABLE_PG_DDL = [
|
|
|
134
169
|
`CREATE INDEX IF NOT EXISTS "durable_schedules_due_idx" ON "durable_schedules" USING btree ("paused","next_fire_at")`
|
|
135
170
|
];
|
|
136
171
|
var SCHEMA_LOCK_KEY = "durable_schema";
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
172
|
+
function drizzlePgSchemaRepairWarning(repairs) {
|
|
173
|
+
return [
|
|
174
|
+
`[nestjs-durable] store-drizzle repaired the durable schema at boot: ${repairs.join("; ")}.`,
|
|
175
|
+
"The database had drifted from the schema this library version expects (it was created by an",
|
|
176
|
+
"older version, or a migration left these out), so they were applied at runtime and nothing",
|
|
177
|
+
"recorded them in your migration history. To make them permanent, generate a drizzle-kit",
|
|
178
|
+
"migration from `durablePgSchema` (or apply `DURABLE_PG_DDL` in a migration). This warning",
|
|
179
|
+
"appears only when a repair was applied; a schema that is already current logs nothing."
|
|
180
|
+
].join(" ");
|
|
181
|
+
}
|
|
182
|
+
__name(drizzlePgSchemaRepairWarning, "drizzlePgSchemaRepairWarning");
|
|
183
|
+
function ddlTarget(statement) {
|
|
184
|
+
const table = statement.match(/^CREATE TABLE IF NOT EXISTS "([^"]+)"/i);
|
|
185
|
+
if (table?.[1]) return {
|
|
186
|
+
kind: "table",
|
|
187
|
+
table: table[1]
|
|
188
|
+
};
|
|
189
|
+
const index2 = statement.match(/^CREATE (?:UNIQUE )?INDEX (?:CONCURRENTLY )?IF NOT EXISTS "([^"]+)" ON "([^"]+)"/i);
|
|
190
|
+
if (index2?.[1] && index2[2]) return {
|
|
191
|
+
kind: "index",
|
|
192
|
+
index: index2[1],
|
|
193
|
+
table: index2[2]
|
|
194
|
+
};
|
|
195
|
+
const column = statement.match(/^ALTER TABLE "([^"]+)" ADD COLUMN IF NOT EXISTS "([^"]+)"/i);
|
|
196
|
+
if (column?.[1] && column[2]) return {
|
|
197
|
+
kind: "column",
|
|
198
|
+
table: column[1],
|
|
199
|
+
column: column[2]
|
|
200
|
+
};
|
|
201
|
+
return void 0;
|
|
202
|
+
}
|
|
203
|
+
__name(ddlTarget, "ddlTarget");
|
|
204
|
+
async function ensureDrizzlePgDurableSchema(db, options = {}) {
|
|
205
|
+
const logger = options.logger ?? console;
|
|
206
|
+
const { repairs, freshInstall } = await db.transaction(async (tx) => {
|
|
207
|
+
await tx.execute(import_drizzle_orm2.sql`SELECT pg_advisory_xact_lock(hashtext(${SCHEMA_LOCK_KEY}))`);
|
|
208
|
+
const tables = new Set(rowsOf(await tx.execute(import_drizzle_orm2.sql.raw("SELECT tablename AS name FROM pg_tables WHERE schemaname = current_schema() AND left(tablename, 8) = 'durable_'"))).map((row) => row.name));
|
|
209
|
+
const indexes = new Set(rowsOf(await tx.execute(import_drizzle_orm2.sql.raw("SELECT indexname AS name FROM pg_indexes WHERE schemaname = current_schema() AND left(tablename, 8) = 'durable_'"))).map((row) => row.name));
|
|
210
|
+
const columns = new Set(rowsOf(await tx.execute(import_drizzle_orm2.sql.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));
|
|
211
|
+
const created = /* @__PURE__ */ new Set();
|
|
212
|
+
const ddlTables = /* @__PURE__ */ new Set();
|
|
213
|
+
const applied = [];
|
|
214
|
+
for (const statement of DURABLE_PG_DDL) {
|
|
215
|
+
const target = ddlTarget(statement);
|
|
216
|
+
await tx.execute(import_drizzle_orm2.sql.raw(statement));
|
|
217
|
+
if (!target) continue;
|
|
218
|
+
if (target.kind === "table") {
|
|
219
|
+
ddlTables.add(target.table);
|
|
220
|
+
if (!tables.has(target.table)) {
|
|
221
|
+
created.add(target.table);
|
|
222
|
+
applied.push(`created table ${target.table}`);
|
|
223
|
+
}
|
|
224
|
+
} else if (created.has(target.table)) {
|
|
225
|
+
} else if (target.kind === "index" && !indexes.has(target.index)) {
|
|
226
|
+
applied.push(`created index ${target.index} on ${target.table}`);
|
|
227
|
+
} else if (target.kind === "column" && !columns.has(`${target.table}.${target.column}`)) {
|
|
228
|
+
applied.push(`added column ${target.table}.${target.column}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
repairs: applied,
|
|
233
|
+
freshInstall: created.size === ddlTables.size
|
|
234
|
+
};
|
|
141
235
|
});
|
|
236
|
+
if (repairs.length > 0 && !freshInstall) logger.warn(drizzlePgSchemaRepairWarning(repairs));
|
|
142
237
|
}
|
|
143
238
|
__name(ensureDrizzlePgDurableSchema, "ensureDrizzlePgDurableSchema");
|
|
144
239
|
|
|
@@ -146,38 +241,6 @@ __name(ensureDrizzlePgDurableSchema, "ensureDrizzlePgDurableSchema");
|
|
|
146
241
|
var import_nestjs_durable_core = require("@dudousxd/nestjs-durable-core");
|
|
147
242
|
var import_drizzle_orm4 = require("drizzle-orm");
|
|
148
243
|
|
|
149
|
-
// src/pg/executor.ts
|
|
150
|
-
var import_drizzle_orm2 = require("drizzle-orm");
|
|
151
|
-
function toDrizzleSql(text2, params = []) {
|
|
152
|
-
const chunks = [];
|
|
153
|
-
let last = 0;
|
|
154
|
-
for (const match of text2.matchAll(/\$(\d+)/g)) {
|
|
155
|
-
const index2 = Number(match[1]) - 1;
|
|
156
|
-
if (index2 < 0 || index2 >= params.length) throw new Error(`placeholder ${match[0]} has no bound parameter`);
|
|
157
|
-
chunks.push(import_drizzle_orm2.sql.raw(text2.slice(last, match.index)), import_drizzle_orm2.sql`${params[index2]}`);
|
|
158
|
-
last = (match.index ?? 0) + match[0].length;
|
|
159
|
-
}
|
|
160
|
-
chunks.push(import_drizzle_orm2.sql.raw(text2.slice(last)));
|
|
161
|
-
return import_drizzle_orm2.sql.join(chunks);
|
|
162
|
-
}
|
|
163
|
-
__name(toDrizzleSql, "toDrizzleSql");
|
|
164
|
-
function rowsOf(result) {
|
|
165
|
-
if (Array.isArray(result)) return result;
|
|
166
|
-
return result?.rows ?? [];
|
|
167
|
-
}
|
|
168
|
-
__name(rowsOf, "rowsOf");
|
|
169
|
-
function drizzlePgExecutor(db) {
|
|
170
|
-
return {
|
|
171
|
-
dialect: "postgres",
|
|
172
|
-
escapeId: /* @__PURE__ */ __name((id) => `"${id.replace(/"/g, '""')}"`, "escapeId"),
|
|
173
|
-
query: /* @__PURE__ */ __name(async (text2, params) => rowsOf(await db.execute(toDrizzleSql(text2, params))), "query"),
|
|
174
|
-
transaction: /* @__PURE__ */ __name((fn) => db.transaction((tx) => fn({
|
|
175
|
-
query: /* @__PURE__ */ __name(async (text2, params) => rowsOf(await tx.execute(toDrizzleSql(text2, params))), "query")
|
|
176
|
-
})), "transaction")
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
__name(drizzlePgExecutor, "drizzlePgExecutor");
|
|
180
|
-
|
|
181
244
|
// src/pg/schema.ts
|
|
182
245
|
var import_drizzle_orm3 = require("drizzle-orm");
|
|
183
246
|
var import_pg_core = require("drizzle-orm/pg-core");
|
|
@@ -349,7 +412,14 @@ function anyOf(conditions) {
|
|
|
349
412
|
}
|
|
350
413
|
__name(anyOf, "anyOf");
|
|
351
414
|
function namespaceFilter(namespace) {
|
|
352
|
-
|
|
415
|
+
if (namespace === void 0) return void 0;
|
|
416
|
+
if (namespace === DEFAULT_NAMESPACE || namespace === "") {
|
|
417
|
+
return (0, import_drizzle_orm4.inArray)(durableWorkflowRuns.namespace, [
|
|
418
|
+
DEFAULT_NAMESPACE,
|
|
419
|
+
""
|
|
420
|
+
]);
|
|
421
|
+
}
|
|
422
|
+
return (0, import_drizzle_orm4.eq)(durableWorkflowRuns.namespace, namespace);
|
|
353
423
|
}
|
|
354
424
|
__name(namespaceFilter, "namespaceFilter");
|
|
355
425
|
function hasTag(tag) {
|
|
@@ -383,7 +453,9 @@ var DrizzlePgStateStore = class _DrizzlePgStateStore {
|
|
|
383
453
|
/** Idempotent CREATE TABLE / INDEX IF NOT EXISTS under an advisory lock — called on boot when the
|
|
384
454
|
* module's `autoSchema` is on. Turn `autoSchema` off if drizzle-kit owns these tables. */
|
|
385
455
|
async ensureSchema() {
|
|
386
|
-
await ensureDrizzlePgDurableSchema(this.db
|
|
456
|
+
await ensureDrizzlePgDurableSchema(this.db, {
|
|
457
|
+
logger: this.options.schemaLogger
|
|
458
|
+
});
|
|
387
459
|
}
|
|
388
460
|
/** The read-scope predicate on the runs table (undefined when the store is unscoped). */
|
|
389
461
|
scope() {
|
|
@@ -548,12 +620,17 @@ var DrizzlePgStateStore = class _DrizzlePgStateStore {
|
|
|
548
620
|
]), namespaceFilter(namespace), this.scope()));
|
|
549
621
|
return rows.map(fromRunRow);
|
|
550
622
|
}
|
|
551
|
-
async listOrphanedRuns(nowMs, limit, namespace) {
|
|
623
|
+
async listOrphanedRuns(nowMs, limit, namespace, ownedBy) {
|
|
552
624
|
if (limit <= 0) return [];
|
|
553
625
|
const rows = await this.db.select().from(durableWorkflowRuns).where((0, import_drizzle_orm4.and)((0, import_drizzle_orm4.inArray)(durableWorkflowRuns.status, [
|
|
554
626
|
"running",
|
|
555
627
|
"cancelling"
|
|
556
|
-
]), (0, import_drizzle_orm4.or)(
|
|
628
|
+
]), (0, import_drizzle_orm4.or)(
|
|
629
|
+
(0, import_drizzle_orm4.isNull)(durableWorkflowRuns.lockedUntil),
|
|
630
|
+
(0, import_drizzle_orm4.lte)(durableWorkflowRuns.lockedUntil, new Date(nowMs)),
|
|
631
|
+
// A live lease left by a previous process with the caller's own instance id.
|
|
632
|
+
ownedBy ? (0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(durableWorkflowRuns.lockedBy, ownedBy.owner), (0, import_drizzle_orm4.lt)(durableWorkflowRuns.lockedUntil, new Date(ownedBy.lockedBefore))) : void 0
|
|
633
|
+
), namespaceFilter(namespace), this.scope())).orderBy((0, import_drizzle_orm4.asc)(durableWorkflowRuns.createdAt)).limit(limit);
|
|
557
634
|
return rows.map(fromRunRow);
|
|
558
635
|
}
|
|
559
636
|
/** FIFO pick-up, served by `durable_workflow_runs_namespace_status_idx`. The engine then leases
|
|
@@ -576,11 +653,11 @@ var DrizzlePgStateStore = class _DrizzlePgStateStore {
|
|
|
576
653
|
});
|
|
577
654
|
return rows.length === 1;
|
|
578
655
|
}
|
|
579
|
-
async releaseRunLock(runId) {
|
|
656
|
+
async releaseRunLock(runId, owner) {
|
|
580
657
|
await this.db.update(durableWorkflowRuns).set({
|
|
581
658
|
lockedBy: null,
|
|
582
659
|
lockedUntil: null
|
|
583
|
-
}).where((0, import_drizzle_orm4.eq)(durableWorkflowRuns.id, runId));
|
|
660
|
+
}).where(owner === void 0 ? (0, import_drizzle_orm4.eq)(durableWorkflowRuns.id, runId) : (0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(durableWorkflowRuns.id, runId), (0, import_drizzle_orm4.eq)(durableWorkflowRuns.lockedBy, owner)));
|
|
584
661
|
}
|
|
585
662
|
async renewRunLock(runId, owner, leaseUntilMs) {
|
|
586
663
|
const rows = await this.db.update(durableWorkflowRuns).set({
|
|
@@ -971,7 +1048,7 @@ function toRunRow(run) {
|
|
|
971
1048
|
tags: run.tags ?? null,
|
|
972
1049
|
searchAttributes: run.searchAttributes ?? null,
|
|
973
1050
|
priority: run.priority ?? null,
|
|
974
|
-
namespace: run.namespace
|
|
1051
|
+
namespace: run.namespace || DEFAULT_NAMESPACE,
|
|
975
1052
|
origin: run.origin ?? null,
|
|
976
1053
|
createdAt: run.createdAt,
|
|
977
1054
|
updatedAt: run.updatedAt
|
|
@@ -994,7 +1071,7 @@ function toRunPatch(patch) {
|
|
|
994
1071
|
if ("tags" in patch) row.tags = patch.tags ?? null;
|
|
995
1072
|
if ("searchAttributes" in patch) row.searchAttributes = patch.searchAttributes ?? null;
|
|
996
1073
|
if ("priority" in patch) row.priority = patch.priority ?? null;
|
|
997
|
-
if ("namespace" in patch) row.namespace = patch.namespace
|
|
1074
|
+
if ("namespace" in patch) row.namespace = patch.namespace || DEFAULT_NAMESPACE;
|
|
998
1075
|
if ("origin" in patch) row.origin = patch.origin ?? null;
|
|
999
1076
|
if (patch.createdAt != null) row.createdAt = patch.createdAt;
|
|
1000
1077
|
if (patch.updatedAt != null) row.updatedAt = patch.updatedAt;
|
|
@@ -1018,7 +1095,7 @@ function fromRunRow(row) {
|
|
|
1018
1095
|
tags: row.tags ?? void 0,
|
|
1019
1096
|
searchAttributes: row.searchAttributes ?? void 0,
|
|
1020
1097
|
priority: row.priority ?? void 0,
|
|
1021
|
-
namespace: row.namespace,
|
|
1098
|
+
namespace: row.namespace || DEFAULT_NAMESPACE,
|
|
1022
1099
|
origin: row.origin ?? void 0,
|
|
1023
1100
|
createdAt: row.createdAt,
|
|
1024
1101
|
updatedAt: row.updatedAt
|
|
@@ -1128,6 +1205,7 @@ __name(excludedSet, "excludedSet");
|
|
|
1128
1205
|
DURABLE_PG_DDL,
|
|
1129
1206
|
DrizzlePgStateStore,
|
|
1130
1207
|
drizzlePgExecutor,
|
|
1208
|
+
drizzlePgSchemaRepairWarning,
|
|
1131
1209
|
durableBufferedEvents,
|
|
1132
1210
|
durableBufferedSignals,
|
|
1133
1211
|
durablePgManagedTables,
|