@dudousxd/nestjs-durable-store-mikro-orm 0.21.0 → 0.23.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 CHANGED
@@ -22,13 +22,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
24
  BufferedEventEntity: () => BufferedEventEntity,
25
+ BufferedEventRepository: () => BufferedEventRepository,
25
26
  BufferedSignalEntity: () => BufferedSignalEntity,
27
+ BufferedSignalRepository: () => BufferedSignalRepository,
26
28
  ENTITIES: () => ENTITIES,
27
29
  MikroOrmStateStore: () => MikroOrmStateStore,
28
30
  RunAttributeEntity: () => RunAttributeEntity,
31
+ RunAttributeRepository: () => RunAttributeRepository,
29
32
  SignalWaiterEntity: () => SignalWaiterEntity,
33
+ SignalWaiterRepository: () => SignalWaiterRepository,
30
34
  StepCheckpointEntity: () => StepCheckpointEntity,
35
+ StepCheckpointRepository: () => StepCheckpointRepository,
31
36
  WorkflowRunEntity: () => WorkflowRunEntity,
37
+ WorkflowRunRepository: () => WorkflowRunRepository,
32
38
  durableEntities: () => durableEntities,
33
39
  durableManagedTables: () => durableManagedTables,
34
40
  ensureMikroOrmDurableSchema: () => ensureMikroOrmDurableSchema
@@ -36,7 +42,42 @@ __export(index_exports, {
36
42
  module.exports = __toCommonJS(index_exports);
37
43
 
38
44
  // src/entities.ts
45
+ var import_core2 = require("@mikro-orm/core");
46
+
47
+ // src/repositories.ts
39
48
  var import_core = require("@mikro-orm/core");
49
+ var WorkflowRunRepository = class extends import_core.EntityRepository {
50
+ static {
51
+ __name(this, "WorkflowRunRepository");
52
+ }
53
+ };
54
+ var StepCheckpointRepository = class extends import_core.EntityRepository {
55
+ static {
56
+ __name(this, "StepCheckpointRepository");
57
+ }
58
+ };
59
+ var RunAttributeRepository = class extends import_core.EntityRepository {
60
+ static {
61
+ __name(this, "RunAttributeRepository");
62
+ }
63
+ };
64
+ var SignalWaiterRepository = class extends import_core.EntityRepository {
65
+ static {
66
+ __name(this, "SignalWaiterRepository");
67
+ }
68
+ };
69
+ var BufferedSignalRepository = class extends import_core.EntityRepository {
70
+ static {
71
+ __name(this, "BufferedSignalRepository");
72
+ }
73
+ };
74
+ var BufferedEventRepository = class extends import_core.EntityRepository {
75
+ static {
76
+ __name(this, "BufferedEventRepository");
77
+ }
78
+ };
79
+
80
+ // src/entities.ts
40
81
  function snakeCase(property) {
41
82
  return property.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
42
83
  }
@@ -51,6 +92,7 @@ var WorkflowRunEntity = class {
51
92
  static {
52
93
  __name(this, "WorkflowRunEntity");
53
94
  }
95
+ [import_core2.EntityRepositoryType];
54
96
  id;
55
97
  workflow;
56
98
  workflowVersion;
@@ -75,6 +117,7 @@ var StepCheckpointEntity = class {
75
117
  static {
76
118
  __name(this, "StepCheckpointEntity");
77
119
  }
120
+ [import_core2.EntityRepositoryType];
78
121
  runId;
79
122
  seq;
80
123
  name;
@@ -97,6 +140,7 @@ var RunAttributeEntity = class {
97
140
  static {
98
141
  __name(this, "RunAttributeEntity");
99
142
  }
143
+ [import_core2.EntityRepositoryType];
100
144
  runId;
101
145
  key;
102
146
  strValue;
@@ -106,6 +150,7 @@ var SignalWaiterEntity = class {
106
150
  static {
107
151
  __name(this, "SignalWaiterEntity");
108
152
  }
153
+ [import_core2.EntityRepositoryType];
109
154
  token;
110
155
  runId;
111
156
  seq;
@@ -115,6 +160,7 @@ var BufferedSignalEntity = class {
115
160
  static {
116
161
  __name(this, "BufferedSignalEntity");
117
162
  }
163
+ [import_core2.EntityRepositoryType];
118
164
  id;
119
165
  token;
120
166
  payload;
@@ -123,6 +169,7 @@ var BufferedEventEntity = class {
123
169
  static {
124
170
  __name(this, "BufferedEventEntity");
125
171
  }
172
+ [import_core2.EntityRepositoryType];
126
173
  id;
127
174
  name;
128
175
  payload;
@@ -137,9 +184,12 @@ function namespaceFilterCond(args) {
137
184
  __name(namespaceFilterCond, "namespaceFilterCond");
138
185
  function durableEntities(options = {}) {
139
186
  const col = columnNamer(options.naming ?? "snake_case");
140
- const workflowRuns = new import_core.EntitySchema({
187
+ const workflowRuns = new import_core2.EntitySchema({
141
188
  class: WorkflowRunEntity,
142
189
  tableName: "durable_workflow_runs",
190
+ // Wired per schema rather than once on the class: `durableEntities` can be called again with a
191
+ // different `naming`, and each call builds a distinct EntitySchema over the same class.
192
+ repository: /* @__PURE__ */ __name(() => WorkflowRunRepository, "repository"),
143
193
  // Global filter: confines every read to the tenant's namespace when the store is scoped.
144
194
  // The `cond` returns `{}` (no-op) when the `namespace` arg is `undefined`, so an unscoped
145
195
  // (operator / control-plane) store sees all rows unchanged — existing behaviour is preserved.
@@ -300,9 +350,10 @@ function durableEntities(options = {}) {
300
350
  }
301
351
  }
302
352
  });
303
- const stepCheckpoints = new import_core.EntitySchema({
353
+ const stepCheckpoints = new import_core2.EntitySchema({
304
354
  class: StepCheckpointEntity,
305
355
  tableName: "durable_step_checkpoints",
356
+ repository: /* @__PURE__ */ __name(() => StepCheckpointRepository, "repository"),
306
357
  properties: {
307
358
  runId: {
308
359
  type: "string",
@@ -388,9 +439,10 @@ function durableEntities(options = {}) {
388
439
  }
389
440
  }
390
441
  });
391
- const runAttributes = new import_core.EntitySchema({
442
+ const runAttributes = new import_core2.EntitySchema({
392
443
  class: RunAttributeEntity,
393
444
  tableName: "durable_run_attributes",
445
+ repository: /* @__PURE__ */ __name(() => RunAttributeRepository, "repository"),
394
446
  // The search-attribute EXISTS join (see the class docstring) pushes equality/range predicates down
395
447
  // onto `(key, numValue)` / `(key, strValue)`; mirror the Prisma adapter so those scans stay indexed.
396
448
  indexes: [
@@ -433,9 +485,10 @@ function durableEntities(options = {}) {
433
485
  }
434
486
  }
435
487
  });
436
- const signalWaiters = new import_core.EntitySchema({
488
+ const signalWaiters = new import_core2.EntitySchema({
437
489
  class: SignalWaiterEntity,
438
490
  tableName: "durable_signal_waiters",
491
+ repository: /* @__PURE__ */ __name(() => SignalWaiterRepository, "repository"),
439
492
  properties: {
440
493
  token: {
441
494
  type: "string",
@@ -460,9 +513,10 @@ function durableEntities(options = {}) {
460
513
  }
461
514
  }
462
515
  });
463
- const bufferedSignals = new import_core.EntitySchema({
516
+ const bufferedSignals = new import_core2.EntitySchema({
464
517
  class: BufferedSignalEntity,
465
518
  tableName: "durable_buffered_signals",
519
+ repository: /* @__PURE__ */ __name(() => BufferedSignalRepository, "repository"),
466
520
  properties: {
467
521
  id: {
468
522
  type: "integer",
@@ -482,9 +536,10 @@ function durableEntities(options = {}) {
482
536
  }
483
537
  }
484
538
  });
485
- const bufferedEvents = new import_core.EntitySchema({
539
+ const bufferedEvents = new import_core2.EntitySchema({
486
540
  class: BufferedEventEntity,
487
541
  tableName: "durable_buffered_events",
542
+ repository: /* @__PURE__ */ __name(() => BufferedEventRepository, "repository"),
488
543
  // `(name, publishedAt)` serves both `listBufferedEvents`'s name-scoped scan and its oldest-first
489
544
  // ordering in one index.
490
545
  indexes: [
@@ -533,6 +588,7 @@ var ENTITIES = durableEntities();
533
588
 
534
589
  // src/mikro-orm-state-store.ts
535
590
  var import_nestjs_durable_core = require("@dudousxd/nestjs-durable-core");
591
+ var import_core3 = require("@mikro-orm/core");
536
592
 
537
593
  // src/schema.ts
538
594
  var import_node_crypto = require("crypto");
@@ -1010,8 +1066,10 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
1010
1066
  });
1011
1067
  return affected === 1;
1012
1068
  }
1013
- async listRuns(query) {
1014
- const em = this.fork();
1069
+ /** The `where` every run query shares — {@link listRuns} pages it, {@link runFacets} groups it.
1070
+ * Only the predicates MikroORM can express declaratively; `tag`/`attributes` need raw SQL and are
1071
+ * applied by the QueryBuilder path in both callers. */
1072
+ runWhere(query) {
1015
1073
  const where = {};
1016
1074
  if (query.workflow) where.workflow = query.workflow;
1017
1075
  if (query.namespace !== void 0) where.namespace = query.namespace;
@@ -1034,23 +1092,16 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
1034
1092
  $in: query.statuses
1035
1093
  };
1036
1094
  }
1095
+ return where;
1096
+ }
1097
+ async listRuns(query) {
1098
+ const em = this.fork();
1099
+ const where = this.runWhere(query);
1037
1100
  const orderBy = {
1038
1101
  createdAt: "desc"
1039
1102
  };
1040
1103
  if (query.tag || query.attributes?.length) {
1041
- if (this.scopeNamespace !== void 0) where.namespace = this.scopeNamespace;
1042
- const quote = this.idQuote(em);
1043
- const cols = this.attributeColumns(em);
1044
- const qb = em.createQueryBuilder(WorkflowRunEntity, "r").where(where).orderBy(orderBy);
1045
- if (query.tag) {
1046
- const tagsCol = this.tagsColumn(em);
1047
- const pattern = `%"${query.tag.replace(/'/g, "''")}"%`;
1048
- const colExpr = this.jsonAsText(em, `${quote("r")}.${quote(tagsCol)}`);
1049
- qb.andWhere(`${colExpr} LIKE '${pattern}'`);
1050
- }
1051
- for (const f of query.attributes ?? []) {
1052
- qb.andWhere(this.attributeExistsSql(f, quote, "r", cols));
1053
- }
1104
+ const qb = this.runQueryBuilder(em, query, where).orderBy(orderBy);
1054
1105
  if (query.limit != null) qb.limit(query.limit);
1055
1106
  if (query.offset != null) qb.offset(query.offset);
1056
1107
  const rows2 = await qb.getResultList();
@@ -1067,6 +1118,45 @@ var MikroOrmStateStore = class _MikroOrmStateStore {
1067
1118
  });
1068
1119
  return rows.map(fromRunEntity);
1069
1120
  }
1121
+ /** A QueryBuilder over `durable_workflow_runs` (root alias `r`) carrying `where` plus the two
1122
+ * predicates only raw SQL can express — the `tag` JSON LIKE and one EXISTS per attribute filter.
1123
+ * Shared so a facet count and the page it labels are taken over the SAME set. */
1124
+ runQueryBuilder(em, query, where) {
1125
+ if (this.scopeNamespace !== void 0) where.namespace = this.scopeNamespace;
1126
+ const quote = this.idQuote(em);
1127
+ const cols = this.attributeColumns(em);
1128
+ const qb = em.createQueryBuilder(WorkflowRunEntity, "r").where(where);
1129
+ if (query.tag) {
1130
+ const tagsCol = this.tagsColumn(em);
1131
+ const pattern = `%"${query.tag.replace(/'/g, "''")}"%`;
1132
+ const colExpr = this.jsonAsText(em, `${quote("r")}.${quote(tagsCol)}`);
1133
+ qb.andWhere(`${colExpr} LIKE '${pattern}'`);
1134
+ }
1135
+ for (const f of query.attributes ?? []) {
1136
+ qb.andWhere(this.attributeExistsSql(f, quote, "r", cols));
1137
+ }
1138
+ return qb;
1139
+ }
1140
+ /** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a
1141
+ * console can show whole-set counts next to a bounded page instead of downloading every run to
1142
+ * count them in the browser. */
1143
+ async runFacets(query) {
1144
+ const em = this.fork();
1145
+ const meta = em.getMetadata().get(WorkflowRunEntity);
1146
+ const statusCol = meta.properties.status?.fieldNames?.[0] ?? "status";
1147
+ const originCol = meta.properties.origin?.fieldNames?.[0] ?? "origin";
1148
+ const rows = await this.runQueryBuilder(em, query, this.runWhere(query)).select([
1149
+ `r.${statusCol}`,
1150
+ `r.${originCol}`
1151
+ ]).addSelect((0, import_core3.raw)("count(*) as count")).groupBy([
1152
+ `r.${statusCol}`,
1153
+ `r.${originCol}`
1154
+ ]).execute();
1155
+ return (0, import_nestjs_durable_core.mergeRunFacetRows)(rows.map((r) => ({
1156
+ ...r,
1157
+ count: Number(r.count)
1158
+ })));
1159
+ }
1070
1160
  /** One attribute predicate as a raw EXISTS subquery on the side-table, correlated to the outer run
1071
1161
  * alias. `<>` (ne) also excludes runs where the attribute is absent (missing-key-never-matches):
1072
1162
  * EXISTS already requires a present row, so EXISTS(... <> ...) is exactly ne-with-present. Numeric
@@ -1361,13 +1451,19 @@ __name(fromCheckpointEntity, "fromCheckpointEntity");
1361
1451
  // Annotate the CommonJS export names for ESM import in node:
1362
1452
  0 && (module.exports = {
1363
1453
  BufferedEventEntity,
1454
+ BufferedEventRepository,
1364
1455
  BufferedSignalEntity,
1456
+ BufferedSignalRepository,
1365
1457
  ENTITIES,
1366
1458
  MikroOrmStateStore,
1367
1459
  RunAttributeEntity,
1460
+ RunAttributeRepository,
1368
1461
  SignalWaiterEntity,
1462
+ SignalWaiterRepository,
1369
1463
  StepCheckpointEntity,
1464
+ StepCheckpointRepository,
1370
1465
  WorkflowRunEntity,
1466
+ WorkflowRunRepository,
1371
1467
  durableEntities,
1372
1468
  durableManagedTables,
1373
1469
  ensureMikroOrmDurableSchema