@dudousxd/nestjs-durable-store-mikro-orm 0.25.0 → 0.27.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.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _mikro_orm_core from '@mikro-orm/core';
2
2
  import { EntityRepository, EntityRepositoryType, EntitySchema, MikroORM } from '@mikro-orm/core';
3
- import { StepKind, RunStatus, StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, SignalWaiter } from '@dudousxd/nestjs-durable-core';
3
+ import { StepKind, RunStatus, StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, SignalWaiter } from '@dudousxd/nestjs-durable-core';
4
4
 
5
5
  /**
6
6
  * Custom repositories for the durable entities, so a host app can `@InjectRepository`/inject a
@@ -29,6 +29,8 @@ declare class BufferedSignalRepository extends EntityRepository<BufferedSignalEn
29
29
  }
30
30
  declare class BufferedEventRepository extends EntityRepository<BufferedEventEntity> {
31
31
  }
32
+ declare class ScheduleRepository extends EntityRepository<ScheduleEntity> {
33
+ }
32
34
 
33
35
  /**
34
36
  * How property names map to physical column names. The durable tables are adapter-agnostic: a run
@@ -121,6 +123,22 @@ declare class BufferedEventEntity {
121
123
  payload?: unknown;
122
124
  publishedAt: Date;
123
125
  }
126
+ /** A persisted schedule (`engine.schedules`). `spec`/`state` are engine-owned JSON documents. */
127
+ declare class ScheduleEntity {
128
+ [EntityRepositoryType]?: ScheduleRepository;
129
+ id: string;
130
+ namespace: string;
131
+ workflow: string;
132
+ paused: boolean;
133
+ /** Epoch ms as a `bigint` column — exact, so `updateSchedule`'s compare-and-set can't be defeated
134
+ * by a DATETIME's truncated milliseconds. Drivers may hand it back as a string. */
135
+ nextFireAt?: number | string | bigint | null;
136
+ tags?: string[] | null;
137
+ spec: Record<string, unknown>;
138
+ state: Record<string, unknown>;
139
+ createdAt: Date;
140
+ updatedAt: Date;
141
+ }
124
142
  declare function durableEntities(options?: {
125
143
  naming?: DurableColumnNaming;
126
144
  }): EntitySchema[];
@@ -174,6 +192,7 @@ declare class MikroOrmStateStore implements StateStore {
174
192
  private reindexAttributes;
175
193
  getRun(runId: string): Promise<WorkflowRun | null>;
176
194
  deleteRun(runId: string): Promise<void>;
195
+ deleteRuns(runIds: string[]): Promise<void>;
177
196
  pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number>;
178
197
  getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
179
198
  saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
@@ -199,26 +218,45 @@ declare class MikroOrmStateStore implements StateStore {
199
218
  /** `tags LIKE '%"etl"%'` — the quoted token, so `etl` doesn't match `etl-foo`. See the note in
200
219
  * {@link listRuns} for why this is raw SQL rather than a MikroORM condition. */
201
220
  private tagLikeSql;
221
+ countRuns(query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number>;
202
222
  /** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a
203
223
  * console can show whole-set counts next to a bounded page instead of downloading every run to
204
224
  * count them in the browser. */
205
225
  runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
206
- /** Distinct values of one filter axis over the same predicates {@link listRuns} pages. A run-table
207
- * column is a `GROUP BY` like {@link runFacets}, exact over the whole matching set; the tag and
208
- * attribute axes live outside the row (json array / side table) and are counted from a bounded
209
- * page of runs instead — see {@link RunValueFacetOptions.scan}. */
210
- runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
211
226
  /**
212
- * The axes whose values do not live in a column of the run row: `tag` (inside a JSON array) and the
213
- * two search-attribute axes (a side table). Both read the newest `scan` matching runs.
227
+ * Distinct values of one filter axis over the same predicates {@link listRuns} pages, with counts —
228
+ * what a console's value pickers list.
229
+ *
230
+ * All three axis families are answered by ONE grouped query against the filtered run set, so the
231
+ * counts are exact over that whole set (not a sample), the ordering is stable, and a picker can
232
+ * page and search server-side. That last part is what makes a picker usable on the axis that needs
233
+ * it most: tag cardinality grows with the data, so the values an operator is looking for are
234
+ * routinely outside any top slice, and a search that only filtered the fetched page could never
235
+ * find them.
214
236
  *
215
- * Neither reads a run's PAYLOAD. The obvious implementation — page `listRuns` and count in
216
- * memory — pulls `input`, `output` and `error` for every run in the window, which on a control
217
- * plane with real payloads is tens of megabytes fetched to produce a list of a hundred short
218
- * strings, every time a picker opens. These project the one column each question needs instead:
219
- * the tags column, or the run ids that then drive one grouped read of the side table.
237
+ * The predicates come from {@link runQueryBuilder} as a subquery rather than being rewritten here,
238
+ * so a picker and the list it filters can never disagree about which runs they are talking about.
239
+ */
240
+ runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
241
+ /** The filtered run set as a derived table, carrying only the columns the axis needs. One source
242
+ * of truth with `listRuns`: the same builder, the same predicates. */
243
+ private runSubquery;
244
+ /** Where the values of an axis come from, and how to name one — a column of the filtered runs, an
245
+ * element of their tags array, or a row of the attribute side table. */
246
+ private valueSource;
247
+ /**
248
+ * The dialect's way of turning a JSON array column into one row per element — the only portable
249
+ * thing about it being that all three have one. Without it a tag picker cannot be grouped in the
250
+ * database at all, and falls back to deduping a bounded page of runs in memory: counts that
251
+ * describe a sample, and an order that cannot be paged.
220
252
  */
221
- private scannedValueFacets;
253
+ private jsonArrayJoin;
254
+ /** `lower(value) like '%needle%'` — the picker's search box, applied BEFORE the page is cut so a
255
+ * match outside the top slice is still reachable. */
256
+ private searchCondition;
257
+ /** A grouped value as the string a picker shows. Drivers return a JSON element or a numeric
258
+ * attribute as something other than a string; `null` stays null (the absent bucket). */
259
+ private text;
222
260
  /** One attribute predicate as a raw EXISTS subquery on the side-table, correlated to the outer run
223
261
  * alias. `<>` (ne) also excludes runs where the attribute is absent (missing-key-never-matches):
224
262
  * EXISTS already requires a present row, so EXISTS(... <> ...) is exactly ne-with-present. Numeric
@@ -239,6 +277,13 @@ declare class MikroOrmStateStore implements StateStore {
239
277
  private jsonAsText;
240
278
  /** Quote an identifier per the active SQL driver (MySQL/MariaDB backtick, others double-quote). */
241
279
  private idQuote;
280
+ saveSchedule(record: ScheduleRecord): Promise<void>;
281
+ getSchedule(id: string): Promise<ScheduleRecord | null>;
282
+ /** One conditional `nativeUpdate`: the compare-and-set on `next_fire_at` (an exact bigint) is a
283
+ * single statement. */
284
+ updateSchedule(id: string, patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>, expectedNextFireAt?: number | null): Promise<boolean>;
285
+ deleteSchedule(id: string): Promise<boolean>;
286
+ listSchedules(query: ScheduleQuery): Promise<ScheduleRecord[]>;
242
287
  listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
243
288
  getLatestCheckpointByName(runId: string, name: string): Promise<StepCheckpoint | undefined>;
244
289
  listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
@@ -309,4 +354,4 @@ declare function durableManagedTables(): string[];
309
354
  */
310
355
  declare function ensureMikroOrmDurableSchema(orm: MikroORM): Promise<void>;
311
356
 
312
- export { BufferedEventEntity, BufferedEventRepository, BufferedSignalEntity, BufferedSignalRepository, type DurableColumnNaming, ENTITIES, MikroOrmStateStore, type MikroOrmStateStoreOptions, RunAttributeEntity, RunAttributeRepository, SignalWaiterEntity, SignalWaiterRepository, StepCheckpointEntity, StepCheckpointRepository, WorkflowRunEntity, WorkflowRunRepository, durableEntities, durableManagedTables, ensureMikroOrmDurableSchema };
357
+ export { BufferedEventEntity, BufferedEventRepository, BufferedSignalEntity, BufferedSignalRepository, type DurableColumnNaming, ENTITIES, MikroOrmStateStore, type MikroOrmStateStoreOptions, RunAttributeEntity, RunAttributeRepository, ScheduleEntity, ScheduleRepository, SignalWaiterEntity, SignalWaiterRepository, StepCheckpointEntity, StepCheckpointRepository, WorkflowRunEntity, WorkflowRunRepository, durableEntities, durableManagedTables, ensureMikroOrmDurableSchema };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as _mikro_orm_core from '@mikro-orm/core';
2
2
  import { EntityRepository, EntityRepositoryType, EntitySchema, MikroORM } from '@mikro-orm/core';
3
- import { StepKind, RunStatus, StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, SignalWaiter } from '@dudousxd/nestjs-durable-core';
3
+ import { StepKind, RunStatus, StateStore, WorkflowRun, RetentionPolicy, StepCheckpoint, RunQuery, RunFacetQuery, RunFacetRow, RunValueAxis, RunValueFacetOptions, RunValueFacetRow, ScheduleRecord, ScheduleQuery, SignalWaiter } from '@dudousxd/nestjs-durable-core';
4
4
 
5
5
  /**
6
6
  * Custom repositories for the durable entities, so a host app can `@InjectRepository`/inject a
@@ -29,6 +29,8 @@ declare class BufferedSignalRepository extends EntityRepository<BufferedSignalEn
29
29
  }
30
30
  declare class BufferedEventRepository extends EntityRepository<BufferedEventEntity> {
31
31
  }
32
+ declare class ScheduleRepository extends EntityRepository<ScheduleEntity> {
33
+ }
32
34
 
33
35
  /**
34
36
  * How property names map to physical column names. The durable tables are adapter-agnostic: a run
@@ -121,6 +123,22 @@ declare class BufferedEventEntity {
121
123
  payload?: unknown;
122
124
  publishedAt: Date;
123
125
  }
126
+ /** A persisted schedule (`engine.schedules`). `spec`/`state` are engine-owned JSON documents. */
127
+ declare class ScheduleEntity {
128
+ [EntityRepositoryType]?: ScheduleRepository;
129
+ id: string;
130
+ namespace: string;
131
+ workflow: string;
132
+ paused: boolean;
133
+ /** Epoch ms as a `bigint` column — exact, so `updateSchedule`'s compare-and-set can't be defeated
134
+ * by a DATETIME's truncated milliseconds. Drivers may hand it back as a string. */
135
+ nextFireAt?: number | string | bigint | null;
136
+ tags?: string[] | null;
137
+ spec: Record<string, unknown>;
138
+ state: Record<string, unknown>;
139
+ createdAt: Date;
140
+ updatedAt: Date;
141
+ }
124
142
  declare function durableEntities(options?: {
125
143
  naming?: DurableColumnNaming;
126
144
  }): EntitySchema[];
@@ -174,6 +192,7 @@ declare class MikroOrmStateStore implements StateStore {
174
192
  private reindexAttributes;
175
193
  getRun(runId: string): Promise<WorkflowRun | null>;
176
194
  deleteRun(runId: string): Promise<void>;
195
+ deleteRuns(runIds: string[]): Promise<void>;
177
196
  pruneTerminalRuns(policy: RetentionPolicy, nowMs: number, limit: number): Promise<number>;
178
197
  getCheckpoint(runId: string, seq: number): Promise<StepCheckpoint | null>;
179
198
  saveCheckpoint(checkpoint: StepCheckpoint): Promise<void>;
@@ -199,26 +218,45 @@ declare class MikroOrmStateStore implements StateStore {
199
218
  /** `tags LIKE '%"etl"%'` — the quoted token, so `etl` doesn't match `etl-foo`. See the note in
200
219
  * {@link listRuns} for why this is raw SQL rather than a MikroORM condition. */
201
220
  private tagLikeSql;
221
+ countRuns(query: Omit<RunQuery, 'limit' | 'offset'>): Promise<number>;
202
222
  /** `GROUP BY status, origin` over the same predicates {@link listRuns} pages — one aggregate, so a
203
223
  * console can show whole-set counts next to a bounded page instead of downloading every run to
204
224
  * count them in the browser. */
205
225
  runFacets(query: RunFacetQuery): Promise<RunFacetRow[]>;
206
- /** Distinct values of one filter axis over the same predicates {@link listRuns} pages. A run-table
207
- * column is a `GROUP BY` like {@link runFacets}, exact over the whole matching set; the tag and
208
- * attribute axes live outside the row (json array / side table) and are counted from a bounded
209
- * page of runs instead — see {@link RunValueFacetOptions.scan}. */
210
- runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
211
226
  /**
212
- * The axes whose values do not live in a column of the run row: `tag` (inside a JSON array) and the
213
- * two search-attribute axes (a side table). Both read the newest `scan` matching runs.
227
+ * Distinct values of one filter axis over the same predicates {@link listRuns} pages, with counts —
228
+ * what a console's value pickers list.
229
+ *
230
+ * All three axis families are answered by ONE grouped query against the filtered run set, so the
231
+ * counts are exact over that whole set (not a sample), the ordering is stable, and a picker can
232
+ * page and search server-side. That last part is what makes a picker usable on the axis that needs
233
+ * it most: tag cardinality grows with the data, so the values an operator is looking for are
234
+ * routinely outside any top slice, and a search that only filtered the fetched page could never
235
+ * find them.
214
236
  *
215
- * Neither reads a run's PAYLOAD. The obvious implementation — page `listRuns` and count in
216
- * memory — pulls `input`, `output` and `error` for every run in the window, which on a control
217
- * plane with real payloads is tens of megabytes fetched to produce a list of a hundred short
218
- * strings, every time a picker opens. These project the one column each question needs instead:
219
- * the tags column, or the run ids that then drive one grouped read of the side table.
237
+ * The predicates come from {@link runQueryBuilder} as a subquery rather than being rewritten here,
238
+ * so a picker and the list it filters can never disagree about which runs they are talking about.
239
+ */
240
+ runValueFacets(axis: RunValueAxis, query: RunFacetQuery, opts?: RunValueFacetOptions): Promise<RunValueFacetRow[]>;
241
+ /** The filtered run set as a derived table, carrying only the columns the axis needs. One source
242
+ * of truth with `listRuns`: the same builder, the same predicates. */
243
+ private runSubquery;
244
+ /** Where the values of an axis come from, and how to name one — a column of the filtered runs, an
245
+ * element of their tags array, or a row of the attribute side table. */
246
+ private valueSource;
247
+ /**
248
+ * The dialect's way of turning a JSON array column into one row per element — the only portable
249
+ * thing about it being that all three have one. Without it a tag picker cannot be grouped in the
250
+ * database at all, and falls back to deduping a bounded page of runs in memory: counts that
251
+ * describe a sample, and an order that cannot be paged.
220
252
  */
221
- private scannedValueFacets;
253
+ private jsonArrayJoin;
254
+ /** `lower(value) like '%needle%'` — the picker's search box, applied BEFORE the page is cut so a
255
+ * match outside the top slice is still reachable. */
256
+ private searchCondition;
257
+ /** A grouped value as the string a picker shows. Drivers return a JSON element or a numeric
258
+ * attribute as something other than a string; `null` stays null (the absent bucket). */
259
+ private text;
222
260
  /** One attribute predicate as a raw EXISTS subquery on the side-table, correlated to the outer run
223
261
  * alias. `<>` (ne) also excludes runs where the attribute is absent (missing-key-never-matches):
224
262
  * EXISTS already requires a present row, so EXISTS(... <> ...) is exactly ne-with-present. Numeric
@@ -239,6 +277,13 @@ declare class MikroOrmStateStore implements StateStore {
239
277
  private jsonAsText;
240
278
  /** Quote an identifier per the active SQL driver (MySQL/MariaDB backtick, others double-quote). */
241
279
  private idQuote;
280
+ saveSchedule(record: ScheduleRecord): Promise<void>;
281
+ getSchedule(id: string): Promise<ScheduleRecord | null>;
282
+ /** One conditional `nativeUpdate`: the compare-and-set on `next_fire_at` (an exact bigint) is a
283
+ * single statement. */
284
+ updateSchedule(id: string, patch: Partial<Omit<ScheduleRecord, 'id' | 'createdAt'>>, expectedNextFireAt?: number | null): Promise<boolean>;
285
+ deleteSchedule(id: string): Promise<boolean>;
286
+ listSchedules(query: ScheduleQuery): Promise<ScheduleRecord[]>;
242
287
  listCheckpoints(runId: string): Promise<StepCheckpoint[]>;
243
288
  getLatestCheckpointByName(runId: string, name: string): Promise<StepCheckpoint | undefined>;
244
289
  listCheckpointsByNamePrefix(runId: string, prefixes: string[]): Promise<StepCheckpoint[]>;
@@ -309,4 +354,4 @@ declare function durableManagedTables(): string[];
309
354
  */
310
355
  declare function ensureMikroOrmDurableSchema(orm: MikroORM): Promise<void>;
311
356
 
312
- export { BufferedEventEntity, BufferedEventRepository, BufferedSignalEntity, BufferedSignalRepository, type DurableColumnNaming, ENTITIES, MikroOrmStateStore, type MikroOrmStateStoreOptions, RunAttributeEntity, RunAttributeRepository, SignalWaiterEntity, SignalWaiterRepository, StepCheckpointEntity, StepCheckpointRepository, WorkflowRunEntity, WorkflowRunRepository, durableEntities, durableManagedTables, ensureMikroOrmDurableSchema };
357
+ export { BufferedEventEntity, BufferedEventRepository, BufferedSignalEntity, BufferedSignalRepository, type DurableColumnNaming, ENTITIES, MikroOrmStateStore, type MikroOrmStateStoreOptions, RunAttributeEntity, RunAttributeRepository, ScheduleEntity, ScheduleRepository, SignalWaiterEntity, SignalWaiterRepository, StepCheckpointEntity, StepCheckpointRepository, WorkflowRunEntity, WorkflowRunRepository, durableEntities, durableManagedTables, ensureMikroOrmDurableSchema };