/** * In-memory unique-constraint enforcement for eager-mode collections. * * Each `UniqueConstraintSet` holds one or more constraints, each covering * an ordered tuple of field names. On every `put()` the caller invokes * `check()` BEFORE the store write; on success it calls `upsert()` to * update the maps. `remove()` is called on `delete()`. * * Null-distinct semantics: if ANY constrained field is `null` or * `undefined` in the record, that record is exempt from the constraint — * `keyFor` returns `null` and the record is silently skipped. * This matches standard SQL NULL-distinct behavior. * * Only used in eager mode (`prefetch !== false`). Lazy-mode collections * throw at registration instead (see Collection constructor). */ import type { IndexDef } from './eager-indexes.js'; export declare class UniqueConstraintSet { private readonly collectionName; private readonly constraints; constructor(collectionName: string, uniqueDefs: readonly (readonly string[])[]); get size(): number; /** * Compute the canonical key for a record under a given constraint. * Returns `null` if any constrained field is `null` or `undefined` * (the record is exempt — no constraint is checked). */ private keyFor; /** * Throw `UniqueConstraintError` if writing `id` with `record` would * collide with a DIFFERENT existing record. Call BEFORE the store write. */ check(id: string, record: unknown): void; /** * Update the constraint maps after a successful write. * Pass `previous` when updating an existing record (so the old key * is removed first). Pass `null` or `undefined` for a fresh insert. */ upsert(id: string, record: unknown, previous?: unknown): void; /** * Remove a record from all constraint maps. * Called by `Collection.delete()`. */ remove(id: string, record: unknown): void; /** * Rebuild all constraint maps from a full snapshot. * Called after hydration (ensureHydrated / hydrateFromSnapshot). * * **Last-writer-wins**: this method does NOT validate pre-existing data * for duplicates. If the store already contains two records sharing a * constrained value (written before the unique index was declared), the * last one processed wins the map slot and the duplicate is silently * displaced — no error is thrown, and the earlier holder is evicted from * the map. Callers retrofitting a unique index onto populated data should * run a one-time uniqueness scan before relying on enforcement. */ build(entries: Iterable): void; } /** * Build the `UniqueConstraintSet` for a collection from its `IndexDef[]`, * or return `null` when no `unique: true` index is declared. * * Unique enforcement is **eager-mode only**. If any `unique` index is * declared on a lazy (`prefetch:false`), CRDT, or tiered collection, this * throws `UnsupportedIndexOptionError` at registration rather than letting * those write paths (which bypass `check()`/`upsert()`) silently skip * enforcement. Kept out of the Collection constructor to keep that * always-on kernel file lean (kernel-surface invariant). */ export declare function buildUniqueConstraintSet(collectionName: string, indexes: readonly IndexDef[] | undefined, mode: { readonly lazy: boolean; readonly crdt: boolean; readonly tiered: boolean; }): UniqueConstraintSet | null;