@dudousxd/nestjs-catalog 0.33.0 → 0.34.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.
@@ -344,6 +344,70 @@ export interface CatalogReadStore {
344
344
  */
345
345
  read(type: CatalogObjectTypeDef, fields: string[], query: CatalogReadQuery): Promise<CatalogReadResult>;
346
346
  listSnapshots?(type: CatalogObjectTypeDef): Promise<SnapshotRef[]>;
347
+ /**
348
+ * The type's snapshots **that still hold rows**, newest first, with the
349
+ * tombstones excluded by the statement rather than by the caller.
350
+ *
351
+ * ## Why this is a method and not a `.filter()` on {@link listSnapshots}
352
+ *
353
+ * Because `listSnapshots` is bounded, and a bound applied before a predicate
354
+ * is a different question from a bound applied after it. A caller that lists
355
+ * the newest N *records* and then drops the tombstones among them is holding
356
+ * the live snapshots **of that window**, not the newest N live snapshots — and
357
+ * since a tombstone is what a dropped snapshot leaves behind, a type that has
358
+ * been swept for long enough has a window made almost entirely of them. Past
359
+ * N tombstones the filtered list is empty, and empty is indistinguishable from
360
+ * "nothing to do" to every caller that has ever asked this question.
361
+ *
362
+ * The ClickHouse adapter learned this first and put `dropped_at IS NULL`
363
+ * inside the statement for `pruneSnapshots`; this is that lesson given a name
364
+ * on the interface, so the next adapter inherits it instead of rediscovering
365
+ * it. See `listSnapshotsWithRows` in `@dudousxd/nestjs-catalog-store-clickhouse`.
366
+ *
367
+ * ## What the bound means here
368
+ *
369
+ * `limit` bounds the **live** snapshots, so a result shorter than it is the
370
+ * complete answer and a result exactly at it means there may be more — and,
371
+ * unlike the same signal on `listSnapshots`, that is a real finding rather
372
+ * than an artefact of how long the type has been retained: a type with more
373
+ * live snapshots than the window is a type whose retention is not keeping up.
374
+ * A caller that needs to act on completeness should read the length back
375
+ * against the `limit` it passed.
376
+ *
377
+ * ## Optional, and the fallback is worth stating
378
+ *
379
+ * A caller that finds it absent has `listSnapshots` and the filter-after-bound
380
+ * problem above. It should degrade to that — the answer is a *prefix* of the
381
+ * truth, never a wrong answer about what it did see — but it must say that the
382
+ * answer may be partial rather than reporting a short list as a complete one.
383
+ */
384
+ listSnapshotsWithRows?(type: CatalogObjectTypeDef, limit?: number): Promise<SnapshotRef[]>;
385
+ /**
386
+ * One snapshot of one type, by id, tombstone included — or `undefined` when
387
+ * this type never had a load by that name.
388
+ *
389
+ * ## Why a lookup, when a list already contains it
390
+ *
391
+ * Because every list here is bounded and this question is not about recency.
392
+ * A caller holding an id got it from somewhere that outlives a window — a
393
+ * `catalog_connector_run` row, a durable step's checkpoint, a person pasting
394
+ * from a screen — and answering it by scanning the newest N records turns
395
+ * "this snapshot is older than N loads" into "there is no such snapshot".
396
+ * Those two sentences send a reader to entirely different places, and the
397
+ * second one is a lie a scan cannot know it is telling.
398
+ *
399
+ * It is scoped to a type, which is what separates it from {@link
400
+ * CatalogSnapshotLookupStore.locateSnapshot}: that one exists to answer for an
401
+ * id whose type is *unknown*, and it costs a scan across every type to do it.
402
+ * This is the cheap, exact read a caller that already knows the type wants,
403
+ * and it is the one an eviction uses to find the row count and the archive ref
404
+ * it is about to check.
405
+ *
406
+ * A tombstone comes back rather than reading as absent, for the same reason it
407
+ * stays in `listSnapshots`: a caller that could not see it would report a
408
+ * dropped snapshot as one that never existed.
409
+ */
410
+ findSnapshot?(type: CatalogObjectTypeDef, snapshotId: string): Promise<SnapshotRef | undefined>;
347
411
  }
348
412
  /**
349
413
  * A store that can hand over the whole of one snapshot, a row at a time.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-catalog",
3
- "version": "0.33.0",
3
+ "version": "0.34.0",
4
4
  "description": "A metadata registry for NestJS: object types, properties and relations, derived from your ORM and enriched with decorators.",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",