@voltro/database 0.9.0 → 0.11.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.ts CHANGED
@@ -424,6 +424,10 @@ export declare interface CdcConfig {
424
424
  readonly keepAliveInitialDelayMs?: number;
425
425
  }
426
426
 
427
+ /** Maximum `onChange` listeners a DataStore's change bus accepts before Node
428
+ * warns. See this file's header for why it is 512 and why it is not `0`. */
429
+ export declare const CHANGE_LISTENER_CEILING = 512;
430
+
427
431
  /**
428
432
  * A row-change event emitted by the data store (in-memory) or the CDC
429
433
  * consumer (Postgres logical replication). Drives the reactive engine.
@@ -1452,7 +1456,10 @@ export declare interface DataStore {
1452
1456
  * mutation.
1453
1457
  */
1454
1458
  transactional<T>(work: (tx: DataStore) => Promise<T>): Promise<T>;
1455
- /** Subscribe to row-change events. Returns an unsubscribe function. */
1459
+ /** Subscribe to row-change events. Returns an unsubscribe function.
1460
+ *
1461
+ * See `CHANGE_LISTENER_CEILING` for why an EventEmitter-backed
1462
+ * implementation must raise its listener limit before binding. */
1456
1463
  onChange(listener: (event: ChangeEvent) => void): () => void;
1457
1464
  /**
1458
1465
  * Inject a ChangeEvent that originated OUTSIDE this process — the
@@ -3800,6 +3807,16 @@ declare interface QueryWithDescriptorAny {
3800
3807
  */
3801
3808
  export declare const quoteIdent: (name: string, dialect: DialectId) => string;
3802
3809
 
3810
+ /** Raise a change bus's listener limit to `CHANGE_LISTENER_CEILING`.
3811
+ *
3812
+ * Structurally typed rather than taking a `node:events` EventEmitter — this
3813
+ * package is browser-safe and must not import `node:*`. Every dialect store
3814
+ * calls this on the emitter it ends up using (its own or an injected shared
3815
+ * one) before any listener binds. */
3816
+ export declare const raiseChangeListenerCeiling: (bus: {
3817
+ setMaxListeners: (n: number) => unknown;
3818
+ }) => void;
3819
+
3803
3820
  export declare const rank: (alias?: string) => WindowBuilder;
3804
3821
 
3805
3822
  /**
@@ -4262,12 +4279,45 @@ export declare interface SeedStepResult {
4262
4279
  readonly rowsTouched?: number;
4263
4280
  }
4264
4281
 
4282
+ /**
4283
+ * The store a seed step gets.
4284
+ *
4285
+ * **Reads are unscoped and include soft-deleted rows**, by construction rather
4286
+ * than by flag: a seed runs at boot with no request and no subject, so there is
4287
+ * no tenant to filter by and nothing applies the `deletedAt IS NULL` predicate.
4288
+ * A restore therefore sees the whole table, which is what a restore needs — and
4289
+ * why there is no `.unscoped()` / `.withDeleted()` to reach for here. If a seed
4290
+ * wants only one tenant's rows, it says so in its own predicate.
4291
+ */
4265
4292
  export declare interface SeedStore {
4293
+ /** Full descriptor read — `order` / `take` / `skip` / `projection` are
4294
+ * accepted so a large restore can page and sort rather than pulling every
4295
+ * row of every table into memory. */
4266
4296
  query(descriptor: {
4267
4297
  table: string;
4268
4298
  predicate?: Predicate;
4299
+ order?: ReadonlyArray<{
4300
+ column: string;
4301
+ direction: 'asc' | 'desc';
4302
+ }>;
4303
+ take?: number;
4304
+ skip?: number;
4305
+ projection?: ReadonlyArray<string>;
4269
4306
  }): Promise<ReadonlyArray<Record<string, unknown>>>;
4270
4307
  insert(table: string, row: Record<string, unknown>): Promise<Record<string, unknown>>;
4308
+ /**
4309
+ * Insert, or do nothing when a row already conflicts on `conflictColumns`.
4310
+ *
4311
+ * The primitive an idempotent restore is actually built on: `upsertByUnique`
4312
+ * costs a read per row and OVERWRITES what it finds, which is wrong when the
4313
+ * live row is newer than the snapshot. This is one statement per row and
4314
+ * leaves an existing row alone. Reported by a consumer restoring 1361 rows
4315
+ * across 167 tables in multiple passes for FK order — with only
4316
+ * `upsertByUnique` available, every pass re-read and re-wrote everything.
4317
+ */
4318
+ insertIgnore(table: string, row: Record<string, unknown>, options: {
4319
+ conflictColumns: ReadonlyArray<string>;
4320
+ }): Promise<Record<string, unknown>>;
4271
4321
  update(table: string, primaryKey: string, patch: Record<string, unknown>): Promise<Record<string, unknown> | null>;
4272
4322
  delete(table: string, primaryKey: string): Promise<boolean>;
4273
4323
  }
@@ -4395,6 +4445,25 @@ export declare interface SqlDialect {
4395
4445
  readonly retryFilter: (error: unknown) => RetryDecision;
4396
4446
  }
4397
4447
 
4448
+ /**
4449
+ * Fill `row.id` from the table's declared scheme when it is absent.
4450
+ *
4451
+ * Three behaviours worth stating, because each has bitten somewhere:
4452
+ *
4453
+ * - an explicit id is NEVER overwritten (tests pin deterministic ids, and
4454
+ * signup self-stamps before a subject exists);
4455
+ * - a `numeric` scheme DELETES the key instead of generating, so the
4456
+ * dialect's SERIAL / AUTO_INCREMENT / IDENTITY fires and the store's
4457
+ * RETURNING path hands the assigned value back;
4458
+ * - an UNREGISTERED table is left alone. The row is passed through
4459
+ * untouched rather than guessed at — a table we do not know is one whose
4460
+ * id column we cannot reason about.
4461
+ */
4462
+ export declare const stampGeneratedId: <T extends Record<string, unknown>>(table: string, row: T) => T;
4463
+
4464
+ /** `stampGeneratedId` over a batch. */
4465
+ export declare const stampGeneratedIds: <T extends Record<string, unknown>>(table: string, rows: ReadonlyArray<T>) => ReadonlyArray<T>;
4466
+
4398
4467
  /**
4399
4468
  * Stream every row of a table as a lazy `Stream<Row>`, keyset-paginated so
4400
4469
  * memory stays flat regardless of table size. Backpressure is inherent: a