@dudousxd/nestjs-durable-store-typeorm 0.17.0 → 0.19.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 +298 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -2
- package/dist/index.d.ts +32 -2
- package/dist/index.js +298 -11
- package/dist/index.js.map +1 -1
- package/package.json +14 -4
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
ENTITIES: () => ENTITIES,
|
|
27
27
|
JSON_BLOB_COLUMNS: () => JSON_BLOB_COLUMNS,
|
|
28
28
|
RunAttributeEntity: () => RunAttributeEntity,
|
|
29
|
+
ScheduleEntity: () => ScheduleEntity,
|
|
29
30
|
SignalWaiterEntity: () => SignalWaiterEntity,
|
|
30
31
|
StepCheckpointEntity: () => StepCheckpointEntity,
|
|
31
32
|
TypeOrmStateStore: () => TypeOrmStateStore,
|
|
@@ -152,6 +153,23 @@ var BufferedEventEntity = class {
|
|
|
152
153
|
payload;
|
|
153
154
|
publishedAt;
|
|
154
155
|
};
|
|
156
|
+
var ScheduleEntity = class {
|
|
157
|
+
static {
|
|
158
|
+
__name(this, "ScheduleEntity");
|
|
159
|
+
}
|
|
160
|
+
id;
|
|
161
|
+
namespace;
|
|
162
|
+
workflow;
|
|
163
|
+
paused;
|
|
164
|
+
/** Epoch ms as a `bigint` (drivers hand it back as a string) — an exact integer, so the
|
|
165
|
+
* compare-and-set in `updateSchedule` can't be defeated by a DATETIME's truncated milliseconds. */
|
|
166
|
+
nextFireAt;
|
|
167
|
+
tags;
|
|
168
|
+
spec;
|
|
169
|
+
state;
|
|
170
|
+
createdAt;
|
|
171
|
+
updatedAt;
|
|
172
|
+
};
|
|
155
173
|
function durableEntities(options = {}) {
|
|
156
174
|
const col = columnNamer(options.naming ?? "snake_case");
|
|
157
175
|
const workflowRuns = new import_typeorm.EntitySchema({
|
|
@@ -479,13 +497,69 @@ function durableEntities(options = {}) {
|
|
|
479
497
|
}
|
|
480
498
|
}
|
|
481
499
|
});
|
|
500
|
+
const schedules = new import_typeorm.EntitySchema({
|
|
501
|
+
name: "ScheduleEntity",
|
|
502
|
+
target: ScheduleEntity,
|
|
503
|
+
tableName: "durable_schedules",
|
|
504
|
+
columns: {
|
|
505
|
+
id: {
|
|
506
|
+
type: "text",
|
|
507
|
+
primary: true,
|
|
508
|
+
name: col("id")
|
|
509
|
+
},
|
|
510
|
+
namespace: {
|
|
511
|
+
type: "text",
|
|
512
|
+
name: col("namespace"),
|
|
513
|
+
default: "default"
|
|
514
|
+
},
|
|
515
|
+
workflow: {
|
|
516
|
+
type: "text",
|
|
517
|
+
name: col("workflow")
|
|
518
|
+
},
|
|
519
|
+
paused: {
|
|
520
|
+
type: Boolean,
|
|
521
|
+
name: col("paused"),
|
|
522
|
+
default: false
|
|
523
|
+
},
|
|
524
|
+
nextFireAt: {
|
|
525
|
+
type: "bigint",
|
|
526
|
+
nullable: true,
|
|
527
|
+
name: col("nextFireAt")
|
|
528
|
+
},
|
|
529
|
+
tags: {
|
|
530
|
+
type: "text",
|
|
531
|
+
nullable: true,
|
|
532
|
+
name: col("tags"),
|
|
533
|
+
transformer: jsonColumnTransformer("schedules.tags")
|
|
534
|
+
},
|
|
535
|
+
spec: {
|
|
536
|
+
type: "text",
|
|
537
|
+
name: col("spec"),
|
|
538
|
+
transformer: jsonColumnTransformer("schedules.spec")
|
|
539
|
+
},
|
|
540
|
+
state: {
|
|
541
|
+
type: "text",
|
|
542
|
+
name: col("state"),
|
|
543
|
+
transformer: jsonColumnTransformer("schedules.state")
|
|
544
|
+
},
|
|
545
|
+
createdAt: {
|
|
546
|
+
type: Date,
|
|
547
|
+
name: col("createdAt")
|
|
548
|
+
},
|
|
549
|
+
updatedAt: {
|
|
550
|
+
type: Date,
|
|
551
|
+
name: col("updatedAt")
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
});
|
|
482
555
|
return [
|
|
483
556
|
workflowRuns,
|
|
484
557
|
stepCheckpoints,
|
|
485
558
|
runAttributes,
|
|
486
559
|
signalWaiters,
|
|
487
560
|
bufferedSignals,
|
|
488
|
-
bufferedEvents
|
|
561
|
+
bufferedEvents,
|
|
562
|
+
schedules
|
|
489
563
|
];
|
|
490
564
|
}
|
|
491
565
|
__name(durableEntities, "durableEntities");
|
|
@@ -513,7 +587,8 @@ var TABLE_TO_ENTITY = {
|
|
|
513
587
|
durable_run_attributes: RunAttributeEntity,
|
|
514
588
|
durable_signal_waiters: SignalWaiterEntity,
|
|
515
589
|
durable_buffered_signals: BufferedSignalEntity,
|
|
516
|
-
durable_buffered_events: BufferedEventEntity
|
|
590
|
+
durable_buffered_events: BufferedEventEntity,
|
|
591
|
+
durable_schedules: ScheduleEntity
|
|
517
592
|
};
|
|
518
593
|
function durableManagedTables() {
|
|
519
594
|
return Object.keys(TABLE_TO_ENTITY);
|
|
@@ -571,6 +646,8 @@ async function ensureTypeOrmDurableSchema(dataSource) {
|
|
|
571
646
|
const waiterCol = /* @__PURE__ */ __name((property) => q(resolve("durable_signal_waiters", property)), "waiterCol");
|
|
572
647
|
const bufCol = /* @__PURE__ */ __name((property) => q(resolve("durable_buffered_signals", property)), "bufCol");
|
|
573
648
|
const bevCol = /* @__PURE__ */ __name((property) => q(resolve("durable_buffered_events", property)), "bevCol");
|
|
649
|
+
const schedules = q("durable_schedules");
|
|
650
|
+
const schCol = /* @__PURE__ */ __name((property) => q(resolve("durable_schedules", property)), "schCol");
|
|
574
651
|
const num = isPg ? "double precision" : isMysql ? "double" : "real";
|
|
575
652
|
const bufferedId = isSqlite ? `${bufCol("id")} integer PRIMARY KEY AUTOINCREMENT` : isMysql ? `${bufCol("id")} bigint NOT NULL AUTO_INCREMENT PRIMARY KEY` : isPg ? `${bufCol("id")} bigserial PRIMARY KEY` : `${bufCol("id")} bigint NOT NULL AUTO_INCREMENT PRIMARY KEY`;
|
|
576
653
|
const tables = [
|
|
@@ -614,6 +691,16 @@ async function ensureTypeOrmDurableSchema(dataSource) {
|
|
|
614
691
|
`CREATE TABLE IF NOT EXISTS ${bufferedEvents} (
|
|
615
692
|
${bevCol("id")} ${str} PRIMARY KEY, ${bevCol("name")} ${str} NOT NULL,
|
|
616
693
|
${bevCol("payload")} ${txt}, ${bevCol("publishedAt")} ${ts} NOT NULL
|
|
694
|
+
)`,
|
|
695
|
+
// Persisted schedules. `next_fire_at` is epoch ms as a bigint (exact, so the compare-and-set on
|
|
696
|
+
// it survives MySQL's DATETIME millisecond truncation); `spec`/`state` are engine-owned JSON.
|
|
697
|
+
`CREATE TABLE IF NOT EXISTS ${schedules} (
|
|
698
|
+
${schCol("id")} ${str} PRIMARY KEY, ${schCol("namespace")} ${nsCol},
|
|
699
|
+
${schCol("workflow")} ${str} NOT NULL,
|
|
700
|
+
${schCol("paused")} boolean NOT NULL DEFAULT ${isPg ? "false" : "0"},
|
|
701
|
+
${schCol("nextFireAt")} bigint, ${schCol("tags")} ${txt},
|
|
702
|
+
${schCol("spec")} ${txt} NOT NULL, ${schCol("state")} ${txt} NOT NULL,
|
|
703
|
+
${schCol("createdAt")} ${ts} NOT NULL, ${schCol("updatedAt")} ${ts} NOT NULL
|
|
617
704
|
)`
|
|
618
705
|
];
|
|
619
706
|
const additive = {
|
|
@@ -757,6 +844,11 @@ async function ensureTypeOrmDurableSchema(dataSource) {
|
|
|
757
844
|
],
|
|
758
845
|
// Search-attribute pushdown: equality + range predicates probe by (key, value). Two composite
|
|
759
846
|
// indexes — one per typed column — so a numeric range or a string equality is an index scan.
|
|
847
|
+
// Persisted schedules: the poll's "due by T" scan (`paused = false AND next_fire_at <= T`).
|
|
848
|
+
[
|
|
849
|
+
"durable_schedules_due_idx",
|
|
850
|
+
`${schedules} (${schCol("paused")}, ${schCol("nextFireAt")})`
|
|
851
|
+
],
|
|
760
852
|
[
|
|
761
853
|
"durable_run_attributes_num_idx",
|
|
762
854
|
`${runAttributes} (${attrCol("key")}, ${attrCol("numValue")})`
|
|
@@ -823,6 +915,9 @@ var TypeOrmStateStore = class {
|
|
|
823
915
|
attributes() {
|
|
824
916
|
return this.dataSource.getRepository(RunAttributeEntity);
|
|
825
917
|
}
|
|
918
|
+
schedules() {
|
|
919
|
+
return this.dataSource.getRepository(ScheduleEntity);
|
|
920
|
+
}
|
|
826
921
|
/** Rewrite a run's normalized attribute rows: delete the old set, insert the current one. Mirrors
|
|
827
922
|
* the in-memory store's reindex so the side-table always reflects the run's live searchAttributes. */
|
|
828
923
|
async reindexAttributes(runId, attributes, em) {
|
|
@@ -883,6 +978,52 @@ var TypeOrmStateStore = class {
|
|
|
883
978
|
id: runId
|
|
884
979
|
});
|
|
885
980
|
}
|
|
981
|
+
async deleteRuns(runIds) {
|
|
982
|
+
if (runIds.length === 0) return;
|
|
983
|
+
await this.dataSource.transaction(async (em) => {
|
|
984
|
+
await em.getRepository(StepCheckpointEntity).delete({
|
|
985
|
+
runId: (0, import_typeorm2.In)(runIds)
|
|
986
|
+
});
|
|
987
|
+
await em.getRepository(SignalWaiterEntity).delete({
|
|
988
|
+
runId: (0, import_typeorm2.In)(runIds)
|
|
989
|
+
});
|
|
990
|
+
await em.getRepository(RunAttributeEntity).delete({
|
|
991
|
+
runId: (0, import_typeorm2.In)(runIds)
|
|
992
|
+
});
|
|
993
|
+
await em.getRepository(WorkflowRunEntity).delete({
|
|
994
|
+
id: (0, import_typeorm2.In)(runIds)
|
|
995
|
+
});
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
async pruneTerminalRuns(policy, nowMs, limit) {
|
|
999
|
+
const statuses = policy.statuses.filter((s) => import_nestjs_durable_core.TERMINAL_RUN_STATUSES.includes(s));
|
|
1000
|
+
if (statuses.length === 0 || limit <= 0) return 0;
|
|
1001
|
+
if (policy.maxAge == null && policy.maxCount == null) return 0;
|
|
1002
|
+
const scoped = /* @__PURE__ */ __name(() => this.runQueryBuilder({
|
|
1003
|
+
...policy.scope ?? {},
|
|
1004
|
+
statuses
|
|
1005
|
+
}).select("r.id", "id"), "scoped");
|
|
1006
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1007
|
+
if (policy.maxAge != null) {
|
|
1008
|
+
const cutoff = new Date(nowMs - (0, import_nestjs_durable_core.parseDuration)(policy.maxAge));
|
|
1009
|
+
const rows = await scoped().andWhere("r.updatedAt < :cutoff", {
|
|
1010
|
+
cutoff
|
|
1011
|
+
}).orderBy("r.updatedAt", "ASC").limit(limit).getRawMany();
|
|
1012
|
+
for (const r of rows) ids.add(r.id);
|
|
1013
|
+
}
|
|
1014
|
+
if (policy.maxCount != null && ids.size < limit) {
|
|
1015
|
+
const rows = await scoped().orderBy("r.updatedAt", "DESC").addOrderBy("r.id", "DESC").limit(limit).offset(policy.maxCount).getRawMany();
|
|
1016
|
+
for (const r of rows) {
|
|
1017
|
+
if (ids.size >= limit) break;
|
|
1018
|
+
ids.add(r.id);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
const doomed = [
|
|
1022
|
+
...ids
|
|
1023
|
+
].slice(0, limit);
|
|
1024
|
+
await this.deleteRuns(doomed);
|
|
1025
|
+
return doomed.length;
|
|
1026
|
+
}
|
|
886
1027
|
async getCheckpoint(runId, seq) {
|
|
887
1028
|
const e = await this.checkpoints().findOneBy({
|
|
888
1029
|
runId,
|
|
@@ -987,13 +1128,28 @@ var TypeOrmStateStore = class {
|
|
|
987
1128
|
if (query.workflow) qb.andWhere("r.workflow = :workflow", {
|
|
988
1129
|
workflow: query.workflow
|
|
989
1130
|
});
|
|
1131
|
+
if (query.workflows) qb.andWhere(query.workflows.length ? "r.workflow IN (:...workflows)" : "1 = 0", query.workflows.length ? {
|
|
1132
|
+
workflows: query.workflows
|
|
1133
|
+
} : {});
|
|
990
1134
|
if (query.namespace !== void 0) qb.andWhere("r.namespace = :namespace", {
|
|
991
1135
|
namespace: query.namespace
|
|
992
1136
|
});
|
|
1137
|
+
if (query.namespaces) qb.andWhere(query.namespaces.length ? "r.namespace IN (:...namespaces)" : "1 = 0", query.namespaces.length ? {
|
|
1138
|
+
namespaces: query.namespaces
|
|
1139
|
+
} : {});
|
|
993
1140
|
if (query.origin === null) qb.andWhere("r.origin IS NULL");
|
|
994
1141
|
else if (query.origin !== void 0) qb.andWhere("r.origin = :origin", {
|
|
995
1142
|
origin: query.origin
|
|
996
1143
|
});
|
|
1144
|
+
if (query.origins) {
|
|
1145
|
+
const named = query.origins.filter((o) => o !== null);
|
|
1146
|
+
const branches = [];
|
|
1147
|
+
if (named.length) branches.push("r.origin IN (:...origins)");
|
|
1148
|
+
if (query.origins.some((o) => o === null)) branches.push("r.origin IS NULL");
|
|
1149
|
+
qb.andWhere(branches.length ? `(${branches.join(" OR ")})` : "1 = 0", named.length ? {
|
|
1150
|
+
origins: named
|
|
1151
|
+
} : {});
|
|
1152
|
+
}
|
|
997
1153
|
if (query.status) qb.andWhere("r.status = :status", {
|
|
998
1154
|
status: query.status
|
|
999
1155
|
});
|
|
@@ -1003,6 +1159,13 @@ var TypeOrmStateStore = class {
|
|
|
1003
1159
|
if (query.tag) qb.andWhere("r.tags LIKE :tagPattern", {
|
|
1004
1160
|
tagPattern: `%"${query.tag}"%`
|
|
1005
1161
|
});
|
|
1162
|
+
if (query.tags) {
|
|
1163
|
+
const branches = query.tags.map((_, i) => `r.tags LIKE :tagPattern${i}`);
|
|
1164
|
+
qb.andWhere(branches.length ? `(${branches.join(" OR ")})` : "1 = 0", Object.fromEntries(query.tags.map((t, i) => [
|
|
1165
|
+
`tagPattern${i}`,
|
|
1166
|
+
`%"${t}"%`
|
|
1167
|
+
])));
|
|
1168
|
+
}
|
|
1006
1169
|
if (query.attributes?.length) {
|
|
1007
1170
|
query.attributes.forEach((f, i) => this.applyAttributeExists(qb, f, i));
|
|
1008
1171
|
}
|
|
@@ -1016,6 +1179,9 @@ var TypeOrmStateStore = class {
|
|
|
1016
1179
|
const rows = await qb.getMany();
|
|
1017
1180
|
return rows.map(fromRunEntity);
|
|
1018
1181
|
}
|
|
1182
|
+
async countRuns(query) {
|
|
1183
|
+
return this.runQueryBuilder(query).getCount();
|
|
1184
|
+
}
|
|
1019
1185
|
/** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a
|
|
1020
1186
|
* console can show whole-set counts next to a bounded page instead of downloading every run to
|
|
1021
1187
|
* count them in the browser. */
|
|
@@ -1026,33 +1192,121 @@ var TypeOrmStateStore = class {
|
|
|
1026
1192
|
count: Number(r.count)
|
|
1027
1193
|
})));
|
|
1028
1194
|
}
|
|
1195
|
+
/** Distinct values of one filter axis over the same predicates {@link listRuns} pages. A run-table
|
|
1196
|
+
* column is a `GROUP BY` like {@link runFacets}, exact over the whole matching set; the tag and
|
|
1197
|
+
* attribute axes live outside the row (json text / side table) and are counted from a bounded page
|
|
1198
|
+
* of runs instead — see `RunValueFacetOptions.scan`. */
|
|
1199
|
+
async runValueFacets(axis, query, opts) {
|
|
1200
|
+
if (!(0, import_nestjs_durable_core.axisIsRunColumn)(axis)) {
|
|
1201
|
+
const runs = await this.listRuns({
|
|
1202
|
+
...query,
|
|
1203
|
+
limit: opts?.scan ?? import_nestjs_durable_core.RUN_VALUE_FACET_SCAN
|
|
1204
|
+
});
|
|
1205
|
+
return (0, import_nestjs_durable_core.runValueFacetsFromRuns)(runs, axis, opts);
|
|
1206
|
+
}
|
|
1207
|
+
const rows = await this.runQueryBuilder(query).select(`r.${axis.field}`, "value").addSelect("COUNT(*)", "count").groupBy(`r.${axis.field}`).getRawMany();
|
|
1208
|
+
return (0, import_nestjs_durable_core.mergeRunValueFacetRows)(rows.map((r) => ({
|
|
1209
|
+
value: r.value ?? null,
|
|
1210
|
+
count: Number(r.count)
|
|
1211
|
+
})), opts);
|
|
1212
|
+
}
|
|
1029
1213
|
/** Add one attribute predicate to `qb` as an EXISTS subquery on the side-table. `i` namespaces the
|
|
1030
1214
|
* bind params so multiple ANDed filters don't collide. */
|
|
1031
1215
|
applyAttributeExists(qb, f, i) {
|
|
1032
|
-
const
|
|
1033
|
-
const cmp = (0, import_nestjs_durable_core.sqlComparator)(f.op);
|
|
1216
|
+
const comparisons = (0, import_nestjs_durable_core.attributePredicateOperands)(f);
|
|
1034
1217
|
const keyParam = `attrKey${i}`;
|
|
1035
|
-
const valParam = `attrVal${i}`;
|
|
1036
1218
|
const resolve = durableColumnResolver(this.dataSource);
|
|
1037
1219
|
const q = this.idQuote();
|
|
1038
1220
|
const wrap = /* @__PURE__ */ __name((name) => `${q}${name}${q}`, "wrap");
|
|
1039
1221
|
const runIdCol = wrap(resolve("durable_run_attributes", "runId"));
|
|
1040
1222
|
const keyCol = wrap(resolve("durable_run_attributes", "key"));
|
|
1041
|
-
const valueCol = wrap(resolve("durable_run_attributes", valueProperty));
|
|
1042
1223
|
const runPkCol = wrap(resolve("durable_workflow_runs", "id"));
|
|
1043
1224
|
const table = wrap("durable_run_attributes");
|
|
1044
1225
|
const a = `a${i}`;
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1226
|
+
const params = {
|
|
1227
|
+
[keyParam]: f.key
|
|
1228
|
+
};
|
|
1229
|
+
const branches = comparisons.map(({ column, comparator, operand }, j) => {
|
|
1230
|
+
const valParam = `attrVal${i}_${j}`;
|
|
1231
|
+
params[valParam] = operand;
|
|
1232
|
+
return `${a}.${wrap(resolve("durable_run_attributes", column))} ${comparator} :${valParam}`;
|
|
1049
1233
|
});
|
|
1234
|
+
if (branches.length === 0) {
|
|
1235
|
+
qb.andWhere("1 = 0");
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
const match = branches.length === 1 ? branches[0] : `(${branches.join(" OR ")})`;
|
|
1239
|
+
const sql = `EXISTS (SELECT 1 FROM ${table} ${a} WHERE ${a}.${runIdCol} = r.${runPkCol} AND ${a}.${keyCol} = :${keyParam} AND ${match})`;
|
|
1240
|
+
qb.andWhere(sql, params);
|
|
1050
1241
|
}
|
|
1051
1242
|
/** The identifier quote char for the active driver (MySQL backtick, others double-quote). */
|
|
1052
1243
|
idQuote() {
|
|
1053
1244
|
const type = String(this.dataSource.options.type);
|
|
1054
1245
|
return type === "mysql" || type === "mariadb" || type === "aurora-mysql" ? "`" : '"';
|
|
1055
1246
|
}
|
|
1247
|
+
// ---- persisted schedules ----------------------------------------------------------------------
|
|
1248
|
+
async saveSchedule(record) {
|
|
1249
|
+
await this.schedules().save(toScheduleEntity(record));
|
|
1250
|
+
}
|
|
1251
|
+
async getSchedule(id) {
|
|
1252
|
+
const e = await this.schedules().findOneBy({
|
|
1253
|
+
id
|
|
1254
|
+
});
|
|
1255
|
+
return e ? fromScheduleEntity(e) : null;
|
|
1256
|
+
}
|
|
1257
|
+
/** One conditional UPDATE: the compare-and-set on `next_fire_at` (an exact bigint) is atomic. */
|
|
1258
|
+
async updateSchedule(id, patch, expectedNextFireAt) {
|
|
1259
|
+
const set = {};
|
|
1260
|
+
if (patch.namespace !== void 0) set.namespace = patch.namespace;
|
|
1261
|
+
if (patch.workflow !== void 0) set.workflow = patch.workflow;
|
|
1262
|
+
if (patch.paused !== void 0) set.paused = patch.paused;
|
|
1263
|
+
if ("nextFireAt" in patch) set.nextFireAt = patch.nextFireAt ?? null;
|
|
1264
|
+
if ("tags" in patch) set.tags = patch.tags ?? null;
|
|
1265
|
+
if (patch.spec !== void 0) set.spec = patch.spec;
|
|
1266
|
+
if (patch.state !== void 0) set.state = patch.state;
|
|
1267
|
+
if (patch.updatedAt !== void 0) set.updatedAt = patch.updatedAt;
|
|
1268
|
+
if (!Object.keys(set).length) return await this.getSchedule(id) !== null;
|
|
1269
|
+
const qb = this.schedules().createQueryBuilder().update().set(set).where({
|
|
1270
|
+
id
|
|
1271
|
+
});
|
|
1272
|
+
if (expectedNextFireAt === null) qb.andWhere({
|
|
1273
|
+
nextFireAt: (0, import_typeorm2.IsNull)()
|
|
1274
|
+
});
|
|
1275
|
+
else if (expectedNextFireAt !== void 0) qb.andWhere({
|
|
1276
|
+
nextFireAt: expectedNextFireAt
|
|
1277
|
+
});
|
|
1278
|
+
const result = await qb.execute();
|
|
1279
|
+
return (result.affected ?? 0) > 0;
|
|
1280
|
+
}
|
|
1281
|
+
async deleteSchedule(id) {
|
|
1282
|
+
const result = await this.schedules().delete({
|
|
1283
|
+
id
|
|
1284
|
+
});
|
|
1285
|
+
return (result.affected ?? 0) > 0;
|
|
1286
|
+
}
|
|
1287
|
+
async listSchedules(query) {
|
|
1288
|
+
const qb = this.schedules().createQueryBuilder("s");
|
|
1289
|
+
if (query.namespace !== void 0) qb.andWhere("s.namespace = :namespace", {
|
|
1290
|
+
namespace: query.namespace
|
|
1291
|
+
});
|
|
1292
|
+
if (query.workflow !== void 0) qb.andWhere("s.workflow = :workflow", {
|
|
1293
|
+
workflow: query.workflow
|
|
1294
|
+
});
|
|
1295
|
+
if (query.paused !== void 0) qb.andWhere("s.paused = :paused", {
|
|
1296
|
+
paused: query.paused
|
|
1297
|
+
});
|
|
1298
|
+
if (query.tag !== void 0) qb.andWhere("s.tags LIKE :tag", {
|
|
1299
|
+
tag: `%"${query.tag}"%`
|
|
1300
|
+
});
|
|
1301
|
+
if (query.dueBy !== void 0) qb.andWhere("s.paused = :notPaused AND s.nextFireAt <= :dueBy", {
|
|
1302
|
+
notPaused: false,
|
|
1303
|
+
dueBy: query.dueBy
|
|
1304
|
+
});
|
|
1305
|
+
qb.orderBy("CASE WHEN s.nextFireAt IS NULL THEN 1 ELSE 0 END", "ASC").addOrderBy("s.nextFireAt", "ASC").addOrderBy("s.id", "ASC");
|
|
1306
|
+
if (query.limit != null) qb.take(query.limit);
|
|
1307
|
+
if (query.offset != null) qb.skip(query.offset);
|
|
1308
|
+
return (await qb.getMany()).map(fromScheduleEntity);
|
|
1309
|
+
}
|
|
1056
1310
|
async listCheckpoints(runId) {
|
|
1057
1311
|
const rows = await this.checkpoints().find({
|
|
1058
1312
|
where: {
|
|
@@ -1296,6 +1550,39 @@ function fromCheckpointEntity(e) {
|
|
|
1296
1550
|
};
|
|
1297
1551
|
}
|
|
1298
1552
|
__name(fromCheckpointEntity, "fromCheckpointEntity");
|
|
1553
|
+
function toScheduleEntity(r) {
|
|
1554
|
+
const e = new ScheduleEntity();
|
|
1555
|
+
e.id = r.id;
|
|
1556
|
+
e.namespace = r.namespace;
|
|
1557
|
+
e.workflow = r.workflow;
|
|
1558
|
+
e.paused = r.paused;
|
|
1559
|
+
e.nextFireAt = r.nextFireAt;
|
|
1560
|
+
e.tags = r.tags ?? null;
|
|
1561
|
+
e.spec = r.spec;
|
|
1562
|
+
e.state = r.state;
|
|
1563
|
+
e.createdAt = r.createdAt;
|
|
1564
|
+
e.updatedAt = r.updatedAt;
|
|
1565
|
+
return e;
|
|
1566
|
+
}
|
|
1567
|
+
__name(toScheduleEntity, "toScheduleEntity");
|
|
1568
|
+
function fromScheduleEntity(e) {
|
|
1569
|
+
return {
|
|
1570
|
+
id: e.id,
|
|
1571
|
+
namespace: e.namespace,
|
|
1572
|
+
workflow: e.workflow,
|
|
1573
|
+
// SQLite/MySQL hand a boolean column back as 0/1.
|
|
1574
|
+
paused: Boolean(e.paused),
|
|
1575
|
+
nextFireAt: e.nextFireAt == null ? null : Number(e.nextFireAt),
|
|
1576
|
+
...e.tags ? {
|
|
1577
|
+
tags: e.tags
|
|
1578
|
+
} : {},
|
|
1579
|
+
spec: e.spec ?? {},
|
|
1580
|
+
state: e.state ?? {},
|
|
1581
|
+
createdAt: e.createdAt,
|
|
1582
|
+
updatedAt: e.updatedAt
|
|
1583
|
+
};
|
|
1584
|
+
}
|
|
1585
|
+
__name(fromScheduleEntity, "fromScheduleEntity");
|
|
1299
1586
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1300
1587
|
0 && (module.exports = {
|
|
1301
1588
|
BufferedEventEntity,
|
|
@@ -1303,6 +1590,7 @@ __name(fromCheckpointEntity, "fromCheckpointEntity");
|
|
|
1303
1590
|
ENTITIES,
|
|
1304
1591
|
JSON_BLOB_COLUMNS,
|
|
1305
1592
|
RunAttributeEntity,
|
|
1593
|
+
ScheduleEntity,
|
|
1306
1594
|
SignalWaiterEntity,
|
|
1307
1595
|
StepCheckpointEntity,
|
|
1308
1596
|
TypeOrmStateStore,
|