@dudousxd/nestjs-durable-store-prisma 0.16.0 → 0.18.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 +297 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +298 -26
- package/dist/index.js.map +1 -1
- package/package.json +13 -3
- package/prisma/schema.prisma +20 -0
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StateStore, WorkflowRun, StepCheckpoint, RunQuery, RunFacetQuery, RunFacetRow, SignalWaiter } from '@dudousxd/nestjs-durable-core';
|
|
1
|
+
import { StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, SignalWaiter } from '@dudousxd/nestjs-durable-core';
|
|
2
2
|
|
|
3
3
|
interface RunRow {
|
|
4
4
|
id: string;
|
|
@@ -82,10 +82,23 @@ interface Delegate<Row> {
|
|
|
82
82
|
deleteMany(args?: Args): Promise<{
|
|
83
83
|
count: number;
|
|
84
84
|
}>;
|
|
85
|
+
count(args?: Args): Promise<number>;
|
|
85
86
|
/** Aggregate form — used only by `runFacets`, whose rows are `(status, origin, count)` cells, not
|
|
86
87
|
* model rows, so the result type is stated at the call site rather than derived from `Row`. */
|
|
87
88
|
groupBy(args: Args): Promise<Record<string, unknown>[]>;
|
|
88
89
|
}
|
|
90
|
+
interface ScheduleRow {
|
|
91
|
+
id: string;
|
|
92
|
+
namespace: string;
|
|
93
|
+
workflow: string;
|
|
94
|
+
paused: boolean;
|
|
95
|
+
nextFireAt: bigint | null;
|
|
96
|
+
tags: unknown;
|
|
97
|
+
spec: unknown;
|
|
98
|
+
state: unknown;
|
|
99
|
+
createdAt: Date;
|
|
100
|
+
updatedAt: Date;
|
|
101
|
+
}
|
|
89
102
|
interface DurablePrismaTx {
|
|
90
103
|
durableWorkflowRun: Delegate<RunRow>;
|
|
91
104
|
durableStepCheckpoint: Delegate<CheckpointRow>;
|
|
@@ -93,6 +106,8 @@ interface DurablePrismaTx {
|
|
|
93
106
|
durableSignalWaiter: Delegate<WaiterRow>;
|
|
94
107
|
durableBufferedSignal: Delegate<BufferedSignalRow>;
|
|
95
108
|
durableBufferedEvent: Delegate<BufferedEventRow>;
|
|
109
|
+
/** Only needed for persisted schedules (`engine.schedules`) — add the `DurableSchedule` model. */
|
|
110
|
+
durableSchedule?: Delegate<ScheduleRow>;
|
|
96
111
|
}
|
|
97
112
|
interface DurablePrismaClient extends DurablePrismaTx {
|
|
98
113
|
/** Prisma's interactive-transaction form: runs `fn` with a tx-scoped client and commits on resolve. */
|
|
@@ -118,6 +133,8 @@ declare class PrismaStateStore implements StateStore {
|
|
|
118
133
|
private reindexAttributes;
|
|
119
134
|
getRun(runId: string): Promise<WorkflowRun | null>;
|
|
120
135
|
deleteRun(runId: string): Promise<void>;
|
|
136
|
+
deleteRuns(runIds: string[]): Promise<void>;
|
|
137
|
+
pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number>;
|
|
121
138
|
getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
|
|
122
139
|
saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
|
|
123
140
|
transaction<T>(work: (tx: {
|
|
@@ -133,10 +150,23 @@ declare class PrismaStateStore implements StateStore {
|
|
|
133
150
|
/** The `where` every run query shares — {@link listRuns} pages it, {@link runFacets} groups it. */
|
|
134
151
|
private runWhere;
|
|
135
152
|
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
153
|
+
countRuns(query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number>;
|
|
136
154
|
/** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a
|
|
137
155
|
* console can show whole-set counts next to a bounded page instead of downloading every run to
|
|
138
156
|
* count them in the browser. */
|
|
139
157
|
runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
158
|
+
/** Distinct values of one filter axis over the same predicates {@link listRuns} pages. A run-table
|
|
159
|
+
* column is a `groupBy` like {@link runFacets}, exact over the whole matching set; the tag and
|
|
160
|
+
* attribute axes live outside the row (json column / side table) and are counted from a bounded
|
|
161
|
+
* page of runs instead — see `RunValueFacetOptions.scan`. */
|
|
162
|
+
runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
|
|
163
|
+
private schedules;
|
|
164
|
+
saveSchedule(record: ScheduleRecord): Promise<void>;
|
|
165
|
+
getSchedule(id: string): Promise<ScheduleRecord | null>;
|
|
166
|
+
/** One conditional `updateMany`: the compare-and-set on `next_fire_at` is a single statement. */
|
|
167
|
+
updateSchedule(id: string, patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>, expectedNextFireAt?: number | null): Promise<boolean>;
|
|
168
|
+
deleteSchedule(id: string): Promise<boolean>;
|
|
169
|
+
listSchedules(query: ScheduleQuery): Promise<ScheduleRecord[]>;
|
|
140
170
|
listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
|
|
141
171
|
getLatestCheckpointByName(runId: string, name: string): Promise<StepCheckpoint | undefined>;
|
|
142
172
|
listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { StateStore, WorkflowRun, StepCheckpoint, RunQuery, RunFacetQuery, RunFacetRow, SignalWaiter } from '@dudousxd/nestjs-durable-core';
|
|
1
|
+
import { StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, SignalWaiter } from '@dudousxd/nestjs-durable-core';
|
|
2
2
|
|
|
3
3
|
interface RunRow {
|
|
4
4
|
id: string;
|
|
@@ -82,10 +82,23 @@ interface Delegate<Row> {
|
|
|
82
82
|
deleteMany(args?: Args): Promise<{
|
|
83
83
|
count: number;
|
|
84
84
|
}>;
|
|
85
|
+
count(args?: Args): Promise<number>;
|
|
85
86
|
/** Aggregate form — used only by `runFacets`, whose rows are `(status, origin, count)` cells, not
|
|
86
87
|
* model rows, so the result type is stated at the call site rather than derived from `Row`. */
|
|
87
88
|
groupBy(args: Args): Promise<Record<string, unknown>[]>;
|
|
88
89
|
}
|
|
90
|
+
interface ScheduleRow {
|
|
91
|
+
id: string;
|
|
92
|
+
namespace: string;
|
|
93
|
+
workflow: string;
|
|
94
|
+
paused: boolean;
|
|
95
|
+
nextFireAt: bigint | null;
|
|
96
|
+
tags: unknown;
|
|
97
|
+
spec: unknown;
|
|
98
|
+
state: unknown;
|
|
99
|
+
createdAt: Date;
|
|
100
|
+
updatedAt: Date;
|
|
101
|
+
}
|
|
89
102
|
interface DurablePrismaTx {
|
|
90
103
|
durableWorkflowRun: Delegate<RunRow>;
|
|
91
104
|
durableStepCheckpoint: Delegate<CheckpointRow>;
|
|
@@ -93,6 +106,8 @@ interface DurablePrismaTx {
|
|
|
93
106
|
durableSignalWaiter: Delegate<WaiterRow>;
|
|
94
107
|
durableBufferedSignal: Delegate<BufferedSignalRow>;
|
|
95
108
|
durableBufferedEvent: Delegate<BufferedEventRow>;
|
|
109
|
+
/** Only needed for persisted schedules (`engine.schedules`) — add the `DurableSchedule` model. */
|
|
110
|
+
durableSchedule?: Delegate<ScheduleRow>;
|
|
96
111
|
}
|
|
97
112
|
interface DurablePrismaClient extends DurablePrismaTx {
|
|
98
113
|
/** Prisma's interactive-transaction form: runs `fn` with a tx-scoped client and commits on resolve. */
|
|
@@ -118,6 +133,8 @@ declare class PrismaStateStore implements StateStore {
|
|
|
118
133
|
private reindexAttributes;
|
|
119
134
|
getRun(runId: string): Promise<WorkflowRun | null>;
|
|
120
135
|
deleteRun(runId: string): Promise<void>;
|
|
136
|
+
deleteRuns(runIds: string[]): Promise<void>;
|
|
137
|
+
pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number>;
|
|
121
138
|
getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
|
|
122
139
|
saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
|
|
123
140
|
transaction<T>(work: (tx: {
|
|
@@ -133,10 +150,23 @@ declare class PrismaStateStore implements StateStore {
|
|
|
133
150
|
/** The `where` every run query shares — {@link listRuns} pages it, {@link runFacets} groups it. */
|
|
134
151
|
private runWhere;
|
|
135
152
|
listRuns(query: RunQuery): Promise<WorkflowRun[]>;
|
|
153
|
+
countRuns(query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number>;
|
|
136
154
|
/** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a
|
|
137
155
|
* console can show whole-set counts next to a bounded page instead of downloading every run to
|
|
138
156
|
* count them in the browser. */
|
|
139
157
|
runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
|
|
158
|
+
/** Distinct values of one filter axis over the same predicates {@link listRuns} pages. A run-table
|
|
159
|
+
* column is a `groupBy` like {@link runFacets}, exact over the whole matching set; the tag and
|
|
160
|
+
* attribute axes live outside the row (json column / side table) and are counted from a bounded
|
|
161
|
+
* page of runs instead — see `RunValueFacetOptions.scan`. */
|
|
162
|
+
runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
|
|
163
|
+
private schedules;
|
|
164
|
+
saveSchedule(record: ScheduleRecord): Promise<void>;
|
|
165
|
+
getSchedule(id: string): Promise<ScheduleRecord | null>;
|
|
166
|
+
/** One conditional `updateMany`: the compare-and-set on `next_fire_at` is a single statement. */
|
|
167
|
+
updateSchedule(id: string, patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>, expectedNextFireAt?: number | null): Promise<boolean>;
|
|
168
|
+
deleteSchedule(id: string): Promise<boolean>;
|
|
169
|
+
listSchedules(query: ScheduleQuery): Promise<ScheduleRecord[]>;
|
|
140
170
|
listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
|
|
141
171
|
getLatestCheckpointByName(runId: string, name: string): Promise<StepCheckpoint | undefined>;
|
|
142
172
|
listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
4
|
// src/prisma-state-store.ts
|
|
5
|
-
import {
|
|
5
|
+
import { RUN_VALUE_FACET_SCAN, TERMINAL_RUN_STATUSES, attributePredicateOperands, axisIsRunColumn, mergeRunFacetRows, mergeRunValueFacetRows, normalizeAttributeRows, parseDuration, runValueFacetsFromRuns } from "@dudousxd/nestjs-durable-core";
|
|
6
6
|
function namespaceWhere(namespace) {
|
|
7
7
|
if (namespace === void 0) return {};
|
|
8
8
|
return {
|
|
@@ -76,6 +76,99 @@ var PrismaStateStore = class {
|
|
|
76
76
|
}
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
|
+
async deleteRuns(runIds) {
|
|
80
|
+
if (runIds.length === 0) return;
|
|
81
|
+
await this.db.$transaction(async (tx) => {
|
|
82
|
+
await tx.durableStepCheckpoint.deleteMany({
|
|
83
|
+
where: {
|
|
84
|
+
runId: {
|
|
85
|
+
in: runIds
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
await tx.durableSignalWaiter.deleteMany({
|
|
90
|
+
where: {
|
|
91
|
+
runId: {
|
|
92
|
+
in: runIds
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
await tx.durableRunAttribute.deleteMany({
|
|
97
|
+
where: {
|
|
98
|
+
runId: {
|
|
99
|
+
in: runIds
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
await tx.durableWorkflowRun.deleteMany({
|
|
104
|
+
where: {
|
|
105
|
+
id: {
|
|
106
|
+
in: runIds
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async pruneTerminalRuns(policy, nowMs, limit) {
|
|
113
|
+
const statuses = policy.statuses.filter((s) => TERMINAL_RUN_STATUSES.includes(s));
|
|
114
|
+
if (statuses.length === 0 || limit <= 0) return 0;
|
|
115
|
+
if (policy.maxAge == null && policy.maxCount == null) return 0;
|
|
116
|
+
const scoped = this.runWhere({
|
|
117
|
+
...policy.scope ?? {},
|
|
118
|
+
statuses
|
|
119
|
+
});
|
|
120
|
+
const ids = /* @__PURE__ */ new Set();
|
|
121
|
+
if (policy.maxAge != null) {
|
|
122
|
+
const cutoff = new Date(nowMs - parseDuration(policy.maxAge));
|
|
123
|
+
const rows = await this.db.durableWorkflowRun.findMany({
|
|
124
|
+
where: {
|
|
125
|
+
AND: [
|
|
126
|
+
scoped,
|
|
127
|
+
{
|
|
128
|
+
updatedAt: {
|
|
129
|
+
lt: cutoff
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
select: {
|
|
135
|
+
id: true
|
|
136
|
+
},
|
|
137
|
+
orderBy: {
|
|
138
|
+
updatedAt: "asc"
|
|
139
|
+
},
|
|
140
|
+
take: limit
|
|
141
|
+
});
|
|
142
|
+
for (const r of rows) ids.add(r.id);
|
|
143
|
+
}
|
|
144
|
+
if (policy.maxCount != null && ids.size < limit) {
|
|
145
|
+
const rows = await this.db.durableWorkflowRun.findMany({
|
|
146
|
+
where: scoped,
|
|
147
|
+
select: {
|
|
148
|
+
id: true
|
|
149
|
+
},
|
|
150
|
+
orderBy: [
|
|
151
|
+
{
|
|
152
|
+
updatedAt: "desc"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: "desc"
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
skip: policy.maxCount,
|
|
159
|
+
take: limit
|
|
160
|
+
});
|
|
161
|
+
for (const r of rows) {
|
|
162
|
+
if (ids.size >= limit) break;
|
|
163
|
+
ids.add(r.id);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const doomed = [
|
|
167
|
+
...ids
|
|
168
|
+
].slice(0, limit);
|
|
169
|
+
await this.deleteRuns(doomed);
|
|
170
|
+
return doomed.length;
|
|
171
|
+
}
|
|
79
172
|
async getCheckpoint(runId, seq) {
|
|
80
173
|
const row = await this.db.durableStepCheckpoint.findUnique({
|
|
81
174
|
where: {
|
|
@@ -208,19 +301,26 @@ var PrismaStateStore = class {
|
|
|
208
301
|
const where = {
|
|
209
302
|
...namespaceWhere(query.namespace)
|
|
210
303
|
};
|
|
304
|
+
const and = [];
|
|
211
305
|
if (query.workflow) where.workflow = query.workflow;
|
|
306
|
+
if (query.workflows) and.push(anyOf(query.workflows.map((w) => ({
|
|
307
|
+
workflow: w
|
|
308
|
+
}))));
|
|
309
|
+
if (query.namespaces) and.push(anyOf(query.namespaces.map((n) => ({
|
|
310
|
+
namespace: n
|
|
311
|
+
}))));
|
|
212
312
|
if (query.origin !== void 0) where.origin = query.origin;
|
|
313
|
+
if (query.origins) and.push(anyOf(query.origins.map((o) => ({
|
|
314
|
+
origin: o
|
|
315
|
+
}))));
|
|
213
316
|
if (query.status && query.statuses) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
status: {
|
|
220
|
-
in: query.statuses
|
|
221
|
-
}
|
|
317
|
+
and.push({
|
|
318
|
+
status: query.status
|
|
319
|
+
}, {
|
|
320
|
+
status: {
|
|
321
|
+
in: query.statuses
|
|
222
322
|
}
|
|
223
|
-
|
|
323
|
+
});
|
|
224
324
|
} else if (query.status) {
|
|
225
325
|
where.status = query.status;
|
|
226
326
|
} else if (query.statuses) {
|
|
@@ -231,13 +331,13 @@ var PrismaStateStore = class {
|
|
|
231
331
|
if (query.tag) where.tags = {
|
|
232
332
|
array_contains: query.tag
|
|
233
333
|
};
|
|
234
|
-
if (query.
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
334
|
+
if (query.tags) and.push(anyOf(query.tags.map((t) => ({
|
|
335
|
+
tags: {
|
|
336
|
+
array_contains: t
|
|
337
|
+
}
|
|
338
|
+
}))));
|
|
339
|
+
if (query.attributes?.length) and.push(...query.attributes.map((f) => attributeSome(f)));
|
|
340
|
+
if (and.length) where.AND = and;
|
|
241
341
|
return where;
|
|
242
342
|
}
|
|
243
343
|
async listRuns(query) {
|
|
@@ -252,6 +352,11 @@ var PrismaStateStore = class {
|
|
|
252
352
|
});
|
|
253
353
|
return rows.map(fromRunRow);
|
|
254
354
|
}
|
|
355
|
+
async countRuns(query) {
|
|
356
|
+
return this.db.durableWorkflowRun.count({
|
|
357
|
+
where: this.runWhere(query)
|
|
358
|
+
});
|
|
359
|
+
}
|
|
255
360
|
/** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a
|
|
256
361
|
* console can show whole-set counts next to a bounded page instead of downloading every run to
|
|
257
362
|
* count them in the browser. */
|
|
@@ -272,6 +377,127 @@ var PrismaStateStore = class {
|
|
|
272
377
|
count: r._count._all
|
|
273
378
|
})));
|
|
274
379
|
}
|
|
380
|
+
/** Distinct values of one filter axis over the same predicates {@link listRuns} pages. A run-table
|
|
381
|
+
* column is a `groupBy` like {@link runFacets}, exact over the whole matching set; the tag and
|
|
382
|
+
* attribute axes live outside the row (json column / side table) and are counted from a bounded
|
|
383
|
+
* page of runs instead — see `RunValueFacetOptions.scan`. */
|
|
384
|
+
async runValueFacets(axis, query, opts) {
|
|
385
|
+
if (!axisIsRunColumn(axis)) {
|
|
386
|
+
const runs = await this.listRuns({
|
|
387
|
+
...query,
|
|
388
|
+
limit: opts?.scan ?? RUN_VALUE_FACET_SCAN
|
|
389
|
+
});
|
|
390
|
+
return runValueFacetsFromRuns(runs, axis, opts);
|
|
391
|
+
}
|
|
392
|
+
const rows = await this.db.durableWorkflowRun.groupBy({
|
|
393
|
+
by: [
|
|
394
|
+
axis.field
|
|
395
|
+
],
|
|
396
|
+
where: this.runWhere(query),
|
|
397
|
+
_count: {
|
|
398
|
+
_all: true
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
return mergeRunValueFacetRows(rows.map((r) => ({
|
|
402
|
+
value: r[axis.field] ?? null,
|
|
403
|
+
count: r._count._all
|
|
404
|
+
})), opts);
|
|
405
|
+
}
|
|
406
|
+
// ---- persisted schedules ----------------------------------------------------------------------
|
|
407
|
+
schedules() {
|
|
408
|
+
const delegate = this.db.durableSchedule;
|
|
409
|
+
if (!delegate) {
|
|
410
|
+
throw new Error("persisted schedules need the DurableSchedule model \u2014 copy it from prisma/schema.prisma into your schema and re-run `prisma generate`");
|
|
411
|
+
}
|
|
412
|
+
return delegate;
|
|
413
|
+
}
|
|
414
|
+
async saveSchedule(record) {
|
|
415
|
+
const data = toScheduleData(record);
|
|
416
|
+
await this.schedules().upsert({
|
|
417
|
+
where: {
|
|
418
|
+
id: record.id
|
|
419
|
+
},
|
|
420
|
+
create: data,
|
|
421
|
+
update: data
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
async getSchedule(id) {
|
|
425
|
+
const row = await this.schedules().findUnique({
|
|
426
|
+
where: {
|
|
427
|
+
id
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
return row ? fromScheduleRow(row) : null;
|
|
431
|
+
}
|
|
432
|
+
/** One conditional `updateMany`: the compare-and-set on `next_fire_at` is a single statement. */
|
|
433
|
+
async updateSchedule(id, patch, expectedNextFireAt) {
|
|
434
|
+
const data = {};
|
|
435
|
+
if (patch.namespace !== void 0) data.namespace = patch.namespace;
|
|
436
|
+
if (patch.workflow !== void 0) data.workflow = patch.workflow;
|
|
437
|
+
if (patch.paused !== void 0) data.paused = patch.paused;
|
|
438
|
+
if ("nextFireAt" in patch) data.nextFireAt = patch.nextFireAt == null ? null : BigInt(patch.nextFireAt);
|
|
439
|
+
if ("tags" in patch) data.tags = jsonOrNull(patch.tags);
|
|
440
|
+
if (patch.spec !== void 0) data.spec = patch.spec;
|
|
441
|
+
if (patch.state !== void 0) data.state = patch.state;
|
|
442
|
+
if (patch.updatedAt !== void 0) data.updatedAt = patch.updatedAt;
|
|
443
|
+
if (!Object.keys(data).length) return await this.getSchedule(id) !== null;
|
|
444
|
+
const where = {
|
|
445
|
+
id
|
|
446
|
+
};
|
|
447
|
+
if (expectedNextFireAt !== void 0) where.nextFireAt = expectedNextFireAt === null ? null : BigInt(expectedNextFireAt);
|
|
448
|
+
const { count } = await this.schedules().updateMany({
|
|
449
|
+
where,
|
|
450
|
+
data
|
|
451
|
+
});
|
|
452
|
+
return count > 0;
|
|
453
|
+
}
|
|
454
|
+
async deleteSchedule(id) {
|
|
455
|
+
const { count } = await this.schedules().deleteMany({
|
|
456
|
+
where: {
|
|
457
|
+
id
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
return count > 0;
|
|
461
|
+
}
|
|
462
|
+
async listSchedules(query) {
|
|
463
|
+
const where = {};
|
|
464
|
+
if (query.namespace !== void 0) where.namespace = query.namespace;
|
|
465
|
+
if (query.workflow !== void 0) where.workflow = query.workflow;
|
|
466
|
+
if (query.paused !== void 0) where.paused = query.paused;
|
|
467
|
+
if (query.tag !== void 0) where.tags = {
|
|
468
|
+
array_contains: query.tag
|
|
469
|
+
};
|
|
470
|
+
if (query.dueBy !== void 0) {
|
|
471
|
+
where.AND = [
|
|
472
|
+
{
|
|
473
|
+
paused: false
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
nextFireAt: {
|
|
477
|
+
lte: BigInt(query.dueBy)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
];
|
|
481
|
+
}
|
|
482
|
+
const rows = await this.schedules().findMany({
|
|
483
|
+
where,
|
|
484
|
+
// Soonest-due first, never-firing (NULL) last, id as the stable tie-break.
|
|
485
|
+
orderBy: [
|
|
486
|
+
{
|
|
487
|
+
nextFireAt: {
|
|
488
|
+
sort: "asc",
|
|
489
|
+
nulls: "last"
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
id: "asc"
|
|
494
|
+
}
|
|
495
|
+
],
|
|
496
|
+
take: query.limit,
|
|
497
|
+
skip: query.offset
|
|
498
|
+
});
|
|
499
|
+
return rows.map(fromScheduleRow);
|
|
500
|
+
}
|
|
275
501
|
async listCheckpoints(runId) {
|
|
276
502
|
const rows = await this.db.durableStepCheckpoint.findMany({
|
|
277
503
|
where: {
|
|
@@ -436,23 +662,35 @@ var PrismaStateStore = class {
|
|
|
436
662
|
}
|
|
437
663
|
};
|
|
438
664
|
function attributeSome(f) {
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
};
|
|
665
|
+
const comparisons = attributePredicateOperands(f).map(({ column, comparator, operand }) => ({
|
|
666
|
+
[column]: comparator === "=" ? operand : comparator === "<>" ? {
|
|
667
|
+
not: operand
|
|
668
|
+
} : {
|
|
669
|
+
[f.op]: operand
|
|
670
|
+
}
|
|
671
|
+
}));
|
|
672
|
+
if (comparisons.length === 0) return MATCHES_NOTHING;
|
|
446
673
|
return {
|
|
447
674
|
attributes: {
|
|
448
675
|
some: {
|
|
449
676
|
key: f.key,
|
|
450
|
-
|
|
677
|
+
...anyOf(comparisons)
|
|
451
678
|
}
|
|
452
679
|
}
|
|
453
680
|
};
|
|
454
681
|
}
|
|
455
682
|
__name(attributeSome, "attributeSome");
|
|
683
|
+
var MATCHES_NOTHING = {
|
|
684
|
+
id: {
|
|
685
|
+
in: []
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
function anyOf(branches) {
|
|
689
|
+
return branches.length ? {
|
|
690
|
+
OR: branches
|
|
691
|
+
} : MATCHES_NOTHING;
|
|
692
|
+
}
|
|
693
|
+
__name(anyOf, "anyOf");
|
|
456
694
|
var bigOrNull = /* @__PURE__ */ __name((n) => n == null ? null : BigInt(n), "bigOrNull");
|
|
457
695
|
var numOrUndef = /* @__PURE__ */ __name((n) => n == null ? void 0 : Number(n), "numOrUndef");
|
|
458
696
|
var jsonOrNull = /* @__PURE__ */ __name((v) => v ?? null, "jsonOrNull");
|
|
@@ -581,6 +819,39 @@ function fromCheckpointRow(row) {
|
|
|
581
819
|
};
|
|
582
820
|
}
|
|
583
821
|
__name(fromCheckpointRow, "fromCheckpointRow");
|
|
822
|
+
function toScheduleData(r) {
|
|
823
|
+
return {
|
|
824
|
+
id: r.id,
|
|
825
|
+
namespace: r.namespace,
|
|
826
|
+
workflow: r.workflow,
|
|
827
|
+
paused: r.paused,
|
|
828
|
+
nextFireAt: r.nextFireAt == null ? null : BigInt(r.nextFireAt),
|
|
829
|
+
tags: jsonOrNull(r.tags),
|
|
830
|
+
spec: r.spec,
|
|
831
|
+
state: r.state,
|
|
832
|
+
createdAt: r.createdAt,
|
|
833
|
+
updatedAt: r.updatedAt
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
__name(toScheduleData, "toScheduleData");
|
|
837
|
+
function fromScheduleRow(row) {
|
|
838
|
+
const tags = Array.isArray(row.tags) ? row.tags : void 0;
|
|
839
|
+
return {
|
|
840
|
+
id: row.id,
|
|
841
|
+
namespace: row.namespace,
|
|
842
|
+
workflow: row.workflow,
|
|
843
|
+
paused: row.paused,
|
|
844
|
+
nextFireAt: row.nextFireAt == null ? null : Number(row.nextFireAt),
|
|
845
|
+
...tags?.length ? {
|
|
846
|
+
tags
|
|
847
|
+
} : {},
|
|
848
|
+
spec: row.spec ?? {},
|
|
849
|
+
state: row.state ?? {},
|
|
850
|
+
createdAt: row.createdAt,
|
|
851
|
+
updatedAt: row.updatedAt
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
__name(fromScheduleRow, "fromScheduleRow");
|
|
584
855
|
|
|
585
856
|
// src/schema.ts
|
|
586
857
|
function durableManagedTables() {
|
|
@@ -590,7 +861,8 @@ function durableManagedTables() {
|
|
|
590
861
|
"durable_run_attributes",
|
|
591
862
|
"durable_signal_waiters",
|
|
592
863
|
"durable_buffered_signals",
|
|
593
|
-
"durable_buffered_events"
|
|
864
|
+
"durable_buffered_events",
|
|
865
|
+
"durable_schedules"
|
|
594
866
|
];
|
|
595
867
|
}
|
|
596
868
|
__name(durableManagedTables, "durableManagedTables");
|