@mvd/memrel 0.0.0-stage → 0.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/encode.ts","../src/model.ts","../src/store.ts","../src/db.ts"],"sourcesContent":["/**\n * What went wrong, as a stable machine-readable code.\n *\n * - `INVALID_SCHEMA`: the config passed to `createDb` is inconsistent.\n * - `DUPLICATE_KEY`: a primary key is already taken.\n * - `UNIQUE_VIOLATION`: a `unique` key is already taken.\n * - `FOREIGN_KEY_VIOLATION`: a reference points at a row that doesn't exist, or is partly null.\n * - `RESTRICT_VIOLATION`: a delete or key change is blocked by a `restrict` rule.\n * - `NOT_FOUND`: a key passed to `update`, `delete` or `rel` doesn't exist.\n * - `INVALID_ARGUMENT`: an argument has the wrong shape, such as an unknown relation name.\n */\nexport type MemrelErrorCode =\n | 'INVALID_SCHEMA'\n | 'DUPLICATE_KEY'\n | 'UNIQUE_VIOLATION'\n | 'FOREIGN_KEY_VIOLATION'\n | 'RESTRICT_VIOLATION'\n | 'NOT_FOUND'\n | 'INVALID_ARGUMENT';\n\n/** Every error memrel throws on purpose is a `MemrelError`. */\nexport class MemrelError extends Error {\n override readonly name = 'MemrelError';\n readonly code: MemrelErrorCode;\n\n constructor(code: MemrelErrorCode, message: string) {\n super(message);\n this.code = code;\n }\n}\n","/**\n * Key encoding.\n *\n * Every index is a `Map` keyed by an encoded tuple of field values. The encoding keeps value\n * types apart, so `1` and `'1'` never collide, and the same encoder is used for primary keys,\n * unique keys, foreign keys and secondary indexes. That is what lets a child's foreign key tuple\n * be used directly as a lookup into its target's index.\n */\n\nconst objectIds = new WeakMap<object, number>();\nconst symbolIds = new Map<symbol, number>();\nlet nextObjectId = 0;\n\n/** Encodes one value. Objects other than dates compare by identity. */\nexport function encodeValue(value: unknown): string {\n switch (typeof value) {\n case 'string':\n return `s:${value}`;\n case 'number':\n return `n:${value}`;\n case 'boolean':\n return value ? 'b:1' : 'b:0';\n case 'bigint':\n return `i:${value}`;\n case 'undefined':\n return 'u';\n case 'symbol': {\n let id = symbolIds.get(value);\n if (id === undefined) {\n id = nextObjectId++;\n symbolIds.set(value, id);\n }\n return `y:${id}`;\n }\n default: {\n if (value === null) return 'z';\n if (value instanceof Date) return `d:${value.getTime()}`;\n let id = objectIds.get(value as object);\n if (id === undefined) {\n id = nextObjectId++;\n objectIds.set(value as object, id);\n }\n return `o:${id}`;\n }\n }\n}\n\n/** Encodes the values of `fields` in `row`, in order. */\nexport function encodeFields(row: object, fields: readonly string[]): string {\n const r = row as Record<string, unknown>;\n if (fields.length === 1) return encodeValue(r[fields[0]!]);\n let out = '[';\n for (let i = 0; i < fields.length; i++) {\n if (i > 0) out += ',';\n out += JSON.stringify(encodeValue(r[fields[i]!]));\n }\n return `${out}]`;\n}\n\n/** Readable form of a row's key, for error messages: `[\"u1\"]`, `[1,\"u1\"]`. */\nexport function displayKey(row: object, fields: readonly string[]): string {\n const r = row as Record<string, unknown>;\n return `[${fields.map((f) => displayValue(r[f])).join(',')}]`;\n}\n\nfunction displayValue(value: unknown): string {\n if (typeof value === 'bigint') return `${value}n`;\n if (typeof value === 'symbol') return value.toString();\n if (value instanceof Date) return value.toISOString();\n if (value === undefined) return 'undefined';\n try {\n const json = JSON.stringify(value);\n if (json !== undefined) return json;\n } catch {\n // Cyclic or otherwise unserializable; fall through.\n }\n return Object.prototype.toString.call(value);\n}\n","/**\n * The runtime model built from a config: one {@link Table} per collection, with its refs, the\n * refs pointing at it, and its mutable index state. The config is validated here, once, when\n * the database is created.\n */\n\nimport { MemrelError } from './errors.ts';\nimport type { Action } from './types.ts';\n\n/** A stored row with its insertion sequence number, which `update` keeps. */\nexport interface Entry {\n readonly row: Record<string, unknown>;\n readonly seq: number;\n}\n\n/** All mutable state of one collection. Rows are never mutated, only replaced. */\nexport interface TableState {\n /** Primary index: encoded primary key → entry. */\n rows: Map<string, Entry>;\n /** One per unique key: encoded values → encoded primary key. */\n uniques: Map<string, string>[];\n /** One per declared index: encoded values → encoded primary keys. */\n indexes: Map<string, Set<string>>[];\n /** One per outgoing ref: encoded referenced values → encoded primary keys of children. */\n reverse: Map<string, Set<string>>[];\n /** Next insertion sequence number. */\n seq: number;\n}\n\nexport interface UniqueKey {\n readonly fields: readonly string[];\n readonly index: number;\n}\n\nexport interface SecondaryIndex {\n readonly fields: readonly string[];\n readonly index: number;\n}\n\nexport interface Ref {\n /** Ref name, unique within its collection. */\n readonly name: string;\n /** `collection.ref`, for messages. */\n readonly id: string;\n /** Position in `from.refs` and `from.state.reverse`. */\n readonly index: number;\n readonly from: Table;\n readonly to: Table;\n readonly fields: readonly string[];\n readonly references: readonly string[];\n /** The target's unique key this ref points at, or `null` for its primary key. */\n readonly targetUnique: UniqueKey | null;\n readonly onDelete: Action;\n readonly onUpdate: Action;\n /** Fields cleared by `setNull`. When these are all null, the row references nothing. */\n readonly nullFields: readonly string[];\n readonly inverse: string | undefined;\n /** Whether the inverse yields at most one row (the foreign key is a key of the child). */\n readonly inverseSingle: boolean;\n}\n\nexport interface Table {\n readonly name: string;\n readonly key: readonly string[];\n readonly uniques: UniqueKey[];\n readonly indexes: SecondaryIndex[];\n readonly refs: Ref[];\n readonly refsByName: Map<string, Ref>;\n /** Refs of any collection that point at this one. */\n readonly incoming: Ref[];\n /** Inverse relation name → the ref it reverses. */\n readonly inverses: Map<string, Ref>;\n state: TableState;\n}\n\nconst ACTIONS: readonly Action[] = ['cascade', 'restrict', 'setNull'];\nconst COLLECTION_OPTIONS = new Set(['key', 'unique', 'indexes', 'refs']);\nconst REF_OPTIONS = new Set([\n 'fields',\n 'to',\n 'references',\n 'onDelete',\n 'onUpdate',\n 'setNullFields',\n 'inverse',\n]);\n\n/** Names used by database-wide methods, which collections can't take. */\nexport const RESERVED_NAMES: ReadonlySet<string> = new Set([\n 'load',\n 'remove',\n 'transaction',\n 'snapshot',\n 'restore',\n]);\n\nfunction fail(message: string): never {\n throw new MemrelError('INVALID_SCHEMA', message);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction fieldList(value: unknown, where: string): string[] {\n if (!Array.isArray(value) || value.length === 0) {\n fail(`${where} must be a non-empty array of field names`);\n }\n for (const f of value) {\n if (typeof f !== 'string') fail(`${where} must only contain field names`);\n }\n if (new Set(value).size !== value.length) fail(`${where} contains a field twice`);\n return [...value];\n}\n\nfunction sameList(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((f, i) => f === b[i]);\n}\n\nfunction sameSet(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((f) => b.includes(f));\n}\n\n/** Creates empty state for a table. */\nexport function emptyState(table: Table): TableState {\n return {\n rows: new Map(),\n uniques: table.uniques.map(() => new Map()),\n indexes: table.indexes.map(() => new Map()),\n reverse: table.refs.map(() => new Map()),\n seq: 0,\n };\n}\n\n/** Validates a config and builds the runtime model. */\nexport function buildModel(config: unknown): Map<string, Table> {\n if (!isRecord(config)) fail('config must be an object of collections');\n const tables = new Map<string, Table>();\n\n for (const [name, raw] of Object.entries(config)) {\n if (RESERVED_NAMES.has(name)) fail(`'${name}' is reserved and can't be a collection name`);\n if (!isRecord(raw)) fail(`${name}: config must be an object`);\n for (const option of Object.keys(raw)) {\n if (!COLLECTION_OPTIONS.has(option)) fail(`${name}: unknown option '${option}'`);\n }\n const key = fieldList(raw.key, `${name}.key`);\n const lists = (value: unknown, label: string): string[][] => {\n if (value === undefined) return [];\n if (!Array.isArray(value)) fail(`${name}.${label} must be an array of field lists`);\n return value.map((v, i) => fieldList(v, `${name}.${label}[${i}]`));\n };\n tables.set(name, {\n name,\n key,\n uniques: lists(raw.unique, 'unique').map((fields, index) => ({ fields, index })),\n indexes: lists(raw.indexes, 'indexes').map((fields, index) => ({ fields, index })),\n refs: [],\n refsByName: new Map(),\n incoming: [],\n inverses: new Map(),\n state: undefined as unknown as TableState,\n });\n }\n\n for (const [name, raw] of Object.entries(config as Record<string, Record<string, unknown>>)) {\n const from = tables.get(name)!;\n if (raw.refs === undefined) continue;\n if (!isRecord(raw.refs)) fail(`${name}.refs must be an object of refs`);\n\n for (const [refName, r] of Object.entries(raw.refs)) {\n const id = `${name}.${refName}`;\n if (!isRecord(r)) fail(`${id}: ref must be an object`);\n for (const option of Object.keys(r)) {\n if (!REF_OPTIONS.has(option)) fail(`${id}: unknown option '${option}'`);\n }\n const fields = fieldList(r.fields, `${id}.fields`);\n const to = typeof r.to === 'string' ? tables.get(r.to) : undefined;\n if (!to) fail(`${id}.to must name a collection`);\n\n let references: string[];\n if (r.references === undefined) {\n if (fields.length !== 1 || to.key.length !== 1) {\n fail(`${id}: composite foreign keys need explicit 'references'`);\n }\n references = [...to.key];\n } else {\n references = fieldList(r.references, `${id}.references`);\n }\n if (references.length !== fields.length) {\n fail(`${id}: 'fields' and 'references' must have the same length`);\n }\n\n let targetUnique: UniqueKey | null = null;\n if (!sameList(references, to.key)) {\n targetUnique = to.uniques.find((u) => sameList(u.fields, references)) ?? null;\n if (!targetUnique) {\n fail(`${id}: 'references' must be the key or a unique key of '${to.name}', in order`);\n }\n }\n\n const onDelete = r.onDelete as Action;\n if (!ACTIONS.includes(onDelete)) fail(`${id}.onDelete must be one of ${ACTIONS.join(', ')}`);\n const onUpdate = (r.onUpdate ?? 'restrict') as Action;\n if (!ACTIONS.includes(onUpdate)) fail(`${id}.onUpdate must be one of ${ACTIONS.join(', ')}`);\n\n const nullFields =\n r.setNullFields === undefined ? fields : fieldList(r.setNullFields, `${id}.setNullFields`);\n if (!nullFields.every((f) => fields.includes(f))) {\n fail(`${id}: 'setNullFields' must be a subset of 'fields'`);\n }\n\n if (r.inverse !== undefined && typeof r.inverse !== 'string') {\n fail(`${id}.inverse must be a string`);\n }\n\n const ref: Ref = {\n name: refName,\n id,\n index: from.refs.length,\n from,\n to,\n fields,\n references,\n targetUnique,\n onDelete,\n onUpdate,\n nullFields,\n inverse: r.inverse,\n inverseSingle:\n sameSet(fields, from.key) || from.uniques.some((u) => sameSet(u.fields, fields)),\n };\n from.refs.push(ref);\n from.refsByName.set(refName, ref);\n to.incoming.push(ref);\n }\n }\n\n for (const table of tables.values()) {\n for (const ref of table.refs) {\n if (ref.inverse === undefined) continue;\n const target = ref.to;\n if (target.refsByName.has(ref.inverse) || target.inverses.has(ref.inverse)) {\n fail(`${ref.id}: inverse '${ref.inverse}' is already a relation of '${target.name}'`);\n }\n target.inverses.set(ref.inverse, ref);\n }\n\n // A setNull rule must not clear a column another foreign key shares.\n for (const ref of table.refs) {\n if (ref.onDelete !== 'setNull' && ref.onUpdate !== 'setNull') continue;\n for (const other of table.refs) {\n if (other !== ref && other.fields.some((f) => ref.nullFields.includes(f))) {\n fail(\n `${ref.id}: setNull would clear a column ${other.id} shares; ` +\n `use 'setNullFields' to clear only the others`,\n );\n }\n }\n }\n\n table.state = emptyState(table);\n }\n\n return tables;\n}\n","/**\n * The engine: storage, index maintenance, reads, writes, the undo log and snapshots.\n *\n * Every write runs inside a savepoint of the undo log. Each primitive change (store a row,\n * remove a row, add to or remove from an index) appends its inverse, so a write that throws\n * midway is rolled back and the store is unchanged. Integrity checks run at the end of each\n * write against the final state, which is what lets a batch reference rows later in the same\n * batch, and a delete remove a row together with the rows `restrict`-ing it.\n */\n\nimport { displayKey, encodeFields, encodeValue } from './encode.ts';\nimport { MemrelError } from './errors.ts';\nimport { buildModel, type Entry, type Ref, type Table, type TableState } from './model.ts';\nimport type { OnConflict } from './types.ts';\n\ntype Row = Record<string, unknown>;\ntype Undo = () => void;\n\nexport interface DeleteOutcome {\n deleted: Record<string, Row[]>;\n nulled: Record<string, Row[]>;\n}\n\n/** State of one write: what to check once it is complete. */\ninterface Op {\n /** Rows this write stored, by table and primary key. Their refs are checked at the end. */\n readonly touched: [Table, string][];\n /** Referenced values that disappeared while `restrict` children still pointed at them. */\n readonly vacated: Vacated[];\n}\n\ninterface Vacated {\n readonly ref: Ref;\n readonly value: string;\n readonly verb: 'delete' | 'update';\n readonly row: Row;\n}\n\n/** A way to find rows by the values of some fields: a primary, unique, reverse or secondary index. */\ninterface AccessPath {\n readonly fields: readonly string[];\n /** Unique and reverse indexes leave out rows with nulls, so they can't answer null conditions. */\n readonly skipsNulls: boolean;\n lookup(state: TableState, key: string): string | ReadonlySet<string> | undefined;\n}\n\ninterface Condition {\n readonly field: string;\n readonly encoded: readonly string[];\n readonly set: ReadonlySet<string>;\n readonly hasNull: boolean;\n}\n\nconst MAX_CASCADE_DEPTH = 1000;\n\ninterface SnapshotData {\n readonly store: Store;\n readonly states: ReadonlyMap<Table, TableState>;\n}\n\nfunction bySeq(a: Entry, b: Entry): number {\n return a.seq - b.seq;\n}\n\n/** Sorts entries into insertion order, skipping the sort when they already are. */\nfunction inOrder(entries: Entry[]): Entry[] {\n for (let i = 1; i < entries.length; i++) {\n if (entries[i - 1]!.seq > entries[i]!.seq) return entries.sort(bySeq);\n }\n return entries;\n}\n\nfunction isInCondition(value: unknown): value is { in: readonly unknown[] } {\n if (typeof value !== 'object' || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return false;\n const keys = Object.keys(value);\n return keys.length === 1 && keys[0] === 'in' && Array.isArray((value as { in: unknown }).in);\n}\n\n/** Every combination of one encoded value per field, encoded as a tuple. */\nfunction combine(parts: readonly (readonly string[])[]): string[] {\n if (parts.length === 1) return [...parts[0]!];\n let out: string[][] = [[]];\n for (const part of parts) {\n const next: string[][] = [];\n for (const prefix of out) for (const v of part) next.push([...prefix, v]);\n out = next;\n }\n return out.map((tuple) => `[${tuple.map((v) => JSON.stringify(v)).join(',')}]`);\n}\n\nfunction cloneBuckets(map: Map<string, Set<string>>): Map<string, Set<string>> {\n const out = new Map<string, Set<string>>();\n for (const [k, s] of map) out.set(k, new Set(s));\n return out;\n}\n\nfunction cloneState(state: TableState): TableState {\n return {\n rows: new Map(state.rows),\n uniques: state.uniques.map((m) => new Map(m)),\n indexes: state.indexes.map(cloneBuckets),\n reverse: state.reverse.map(cloneBuckets),\n seq: state.seq,\n };\n}\n\nfunction isNullish(value: unknown): boolean {\n return value === null || value === undefined;\n}\n\nfunction push(target: Record<string, Row[]>, name: string, row: Row): void {\n const list = target[name];\n if (list) list.push(row);\n else target[name] = [row];\n}\n\nexport class Store {\n readonly tables: Map<string, Table>;\n private readonly paths = new Map<Table, AccessPath[]>();\n private journal: Undo[] | null = null;\n\n constructor(config: unknown) {\n this.tables = buildModel(config);\n for (const table of this.tables.values()) {\n const paths: AccessPath[] = [\n { fields: table.key, skipsNulls: false, lookup: (s, k) => (s.rows.has(k) ? k : undefined) },\n ];\n for (const u of table.uniques) {\n paths.push({\n fields: u.fields,\n skipsNulls: true,\n lookup: (s, k) => s.uniques[u.index]!.get(k),\n });\n }\n for (const ref of table.refs) {\n paths.push({\n fields: ref.fields,\n skipsNulls: true,\n lookup: (s, k) => s.reverse[ref.index]!.get(k),\n });\n }\n for (const idx of table.indexes) {\n paths.push({\n fields: idx.fields,\n skipsNulls: false,\n lookup: (s, k) => s.indexes[idx.index]!.get(k),\n });\n }\n this.paths.set(table, paths);\n }\n }\n\n // -------------------------------------------------------------------------------------------\n // Undo log\n // -------------------------------------------------------------------------------------------\n\n /** Runs `fn`; if it throws, undoes everything it changed. Nests. */\n savepoint<T>(fn: () => T): T {\n const outer = this.journal;\n const journal = outer ?? [];\n const mark = journal.length;\n this.journal = journal;\n try {\n const result = fn();\n if (\n typeof result === 'object' &&\n result !== null &&\n typeof (result as { then?: unknown }).then === 'function'\n ) {\n throw new MemrelError('INVALID_ARGUMENT', 'Transaction callbacks must be synchronous');\n }\n return result;\n } catch (error) {\n while (journal.length > mark) journal.pop()!();\n throw error;\n } finally {\n this.journal = outer;\n }\n }\n\n private log(undo: Undo): void {\n this.journal?.push(undo);\n }\n\n private mapSet<K, V>(map: Map<K, V>, key: K, value: V): void {\n if (map.has(key)) {\n const prev = map.get(key) as V;\n this.log(() => map.set(key, prev));\n } else {\n this.log(() => map.delete(key));\n }\n map.set(key, value);\n }\n\n private mapDelete<K, V>(map: Map<K, V>, key: K): void {\n if (!map.has(key)) return;\n const prev = map.get(key) as V;\n map.delete(key);\n this.log(() => map.set(key, prev));\n }\n\n private bucketAdd(map: Map<string, Set<string>>, key: string, member: string): void {\n let bucket = map.get(key);\n if (!bucket) {\n bucket = new Set();\n this.mapSet(map, key, bucket);\n }\n if (bucket.has(member)) return;\n bucket.add(member);\n const b = bucket;\n this.log(() => b.delete(member));\n }\n\n private bucketDelete(map: Map<string, Set<string>>, key: string, member: string): void {\n const bucket = map.get(key);\n if (!bucket?.delete(member)) return;\n this.log(() => bucket.add(member));\n if (bucket.size === 0) this.mapDelete(map, key);\n }\n\n /** Runs one write: rolled back as a whole, and checked once complete. */\n private write<T>(fn: (op: Op) => T): T {\n return this.savepoint(() => {\n const op: Op = { touched: [], vacated: [] };\n const result = fn(op);\n this.verify(op);\n return result;\n });\n }\n\n // -------------------------------------------------------------------------------------------\n // Keys and references\n // -------------------------------------------------------------------------------------------\n\n /**\n * The encoded foreign key of `row` for `ref`: `null` when it references nothing (all of the\n * ref's null fields are null), `undefined` when it is partly null, which is an error.\n */\n private foreignKey(ref: Ref, row: Row): string | null | undefined {\n if (ref.nullFields.every((f) => isNullish(row[f]))) return null;\n if (ref.fields.some((f) => isNullish(row[f]))) return undefined;\n return encodeFields(row, ref.fields);\n }\n\n /** The encoded values of `row` that `ref` points at, or `null` when they aren't indexed. */\n private referencedValue(ref: Ref, row: Row): string | null {\n if (ref.targetUnique && ref.references.some((f) => isNullish(row[f]))) return null;\n return encodeFields(row, ref.references);\n }\n\n private findTarget(ref: Ref, value: string): Entry | undefined {\n const state = ref.to.state;\n if (!ref.targetUnique) return state.rows.get(value);\n const pk = state.uniques[ref.targetUnique.index]!.get(value);\n return pk === undefined ? undefined : state.rows.get(pk);\n }\n\n private describe(table: Table, row: Row): string {\n return `${table.name} ${displayKey(row, table.key)}`;\n }\n\n private verify(op: Op): void {\n for (const v of op.vacated) {\n const children = v.ref.from.state.reverse[v.ref.index]!.get(v.value);\n if (!children || children.size === 0 || this.findTarget(v.ref, v.value)) continue;\n const n = children.size;\n throw new MemrelError(\n 'RESTRICT_VIOLATION',\n `Cannot ${v.verb} ${this.describe(v.ref.to, v.row)}: restricted by ${n} ${\n n === 1 ? 'row' : 'rows'\n } in ${v.ref.id}`,\n );\n }\n for (const [table, pk] of op.touched) {\n const entry = table.state.rows.get(pk);\n if (entry) this.checkRefs(table, entry.row);\n }\n }\n\n private checkRefs(table: Table, row: Row): void {\n for (const ref of table.refs) {\n const fk = this.foreignKey(ref, row);\n if (fk === null) continue;\n if (fk === undefined) {\n throw new MemrelError(\n 'FOREIGN_KEY_VIOLATION',\n `${this.describe(table, row)}: foreign key ${ref.id} ${displayKey(row, ref.fields)} is partly null`,\n );\n }\n if (!this.findTarget(ref, fk)) {\n throw new MemrelError(\n 'FOREIGN_KEY_VIOLATION',\n `${this.describe(table, row)}: ${ref.id} references missing ${ref.to.name} ${displayKey(\n row,\n ref.fields,\n )}`,\n );\n }\n }\n }\n\n // -------------------------------------------------------------------------------------------\n // Index maintenance\n // -------------------------------------------------------------------------------------------\n\n private uniqueValue(row: Row, fields: readonly string[]): string | null {\n return fields.some((f) => isNullish(row[f])) ? null : encodeFields(row, fields);\n }\n\n private addRow(op: Op, table: Table, pk: string, row: Row, seq: number): void {\n const s = table.state;\n for (const u of table.uniques) {\n const value = this.uniqueValue(row, u.fields);\n if (value === null) continue;\n const map = s.uniques[u.index]!;\n const holder = map.get(value);\n if (holder !== undefined && holder !== pk) {\n throw new MemrelError(\n 'UNIQUE_VIOLATION',\n `${this.describe(table, row)}: unique key (${u.fields.join(', ')}) ${displayKey(\n row,\n u.fields,\n )} is already taken by ${this.describe(table, s.rows.get(holder)!.row)}`,\n );\n }\n this.mapSet(map, value, pk);\n }\n for (const idx of table.indexes) {\n this.bucketAdd(s.indexes[idx.index]!, encodeFields(row, idx.fields), pk);\n }\n for (const ref of table.refs) {\n const fk = this.foreignKey(ref, row);\n if (typeof fk === 'string') this.bucketAdd(s.reverse[ref.index]!, fk, pk);\n }\n this.mapSet(s.rows, pk, { row, seq });\n op.touched.push([table, pk]);\n }\n\n private removeRow(table: Table, pk: string, row: Row): void {\n const s = table.state;\n for (const u of table.uniques) {\n const value = this.uniqueValue(row, u.fields);\n if (value !== null && s.uniques[u.index]!.get(value) === pk) {\n this.mapDelete(s.uniques[u.index]!, value);\n }\n }\n for (const idx of table.indexes) {\n this.bucketDelete(s.indexes[idx.index]!, encodeFields(row, idx.fields), pk);\n }\n for (const ref of table.refs) {\n const fk = this.foreignKey(ref, row);\n if (typeof fk === 'string') this.bucketDelete(s.reverse[ref.index]!, fk, pk);\n }\n this.mapDelete(s.rows, pk);\n }\n\n // -------------------------------------------------------------------------------------------\n // Reads\n // -------------------------------------------------------------------------------------------\n\n get(table: Table, key: object): Row | undefined {\n return table.state.rows.get(encodeFields(key, table.key))?.row;\n }\n\n where(table: Table, conditions: Row): Row[] {\n const state = table.state;\n const conds = new Map<string, Condition>();\n for (const field of Object.keys(conditions)) {\n const raw = conditions[field];\n if (raw === undefined) continue;\n const values = isInCondition(raw) ? raw.in : [raw];\n const encoded = [...new Set(values.map(encodeValue))];\n conds.set(field, { field, encoded, set: new Set(encoded), hasNull: values.some(isNullish) });\n }\n if (conds.size === 0) return inOrder([...state.rows.values()]).map((e) => e.row);\n\n let best: { path: AccessPath; keys: string[]; size: number } | undefined;\n for (const path of this.paths.get(table)!) {\n const parts: (readonly string[])[] = [];\n for (const f of path.fields) {\n const c = conds.get(f);\n if (!c || (path.skipsNulls && c.hasNull)) break;\n parts.push(c.encoded);\n }\n if (parts.length !== path.fields.length) continue;\n const keys = combine(parts);\n let size = 0;\n for (const k of keys) {\n const hit = path.lookup(state, k);\n if (hit !== undefined) size += typeof hit === 'string' ? 1 : hit.size;\n }\n if (!best || size < best.size) best = { path, keys, size };\n if (size === 0) return [];\n }\n\n let candidates: Iterable<Entry>;\n if (best) {\n const found: Entry[] = [];\n for (const k of best.keys) {\n const hit = best.path.lookup(state, k);\n if (hit === undefined) continue;\n if (typeof hit === 'string') found.push(state.rows.get(hit)!);\n else for (const pk of hit) found.push(state.rows.get(pk)!);\n }\n candidates = found;\n } else {\n candidates = state.rows.values();\n }\n\n const checks = [...conds.values()];\n const out: Entry[] = [];\n for (const entry of candidates) {\n if (checks.every((c) => c.set.has(encodeValue(entry.row[c.field])))) out.push(entry);\n }\n return inOrder(out).map((e) => e.row);\n }\n\n rel(table: Table, input: Row, name: string): unknown {\n const resolve = (fields: readonly string[]): Row | undefined => {\n if (fields.every((f) => f in input)) return input;\n return table.state.rows.get(encodeFields(input, table.key))?.row;\n };\n\n const ref = table.refsByName.get(name);\n if (ref) {\n const row = resolve(ref.fields);\n if (!row) {\n throw new MemrelError(\n 'NOT_FOUND',\n `${table.name} ${displayKey(input, table.key)} not found`,\n );\n }\n const fk = this.foreignKey(ref, row);\n if (fk === null) return null;\n const target = fk === undefined ? undefined : this.findTarget(ref, fk);\n if (!target) {\n throw new MemrelError(\n 'FOREIGN_KEY_VIOLATION',\n `${this.describe(table, row)}: ${ref.id} references missing ${ref.to.name} ${displayKey(\n row,\n ref.fields,\n )}`,\n );\n }\n return target.row;\n }\n\n const inverse = table.inverses.get(name);\n if (inverse) {\n const row = resolve(inverse.references);\n const value = row ? this.referencedValue(inverse, row) : null;\n const child = inverse.from;\n const bucket = value === null ? undefined : child.state.reverse[inverse.index]!.get(value);\n if (inverse.inverseSingle) {\n if (!bucket) return undefined;\n for (const pk of bucket) return child.state.rows.get(pk)!.row;\n return undefined;\n }\n if (!bucket) return [];\n const entries: Entry[] = [];\n for (const pk of bucket) entries.push(child.state.rows.get(pk)!);\n return inOrder(entries).map((e) => e.row);\n }\n\n const names = [...table.refsByName.keys(), ...table.inverses.keys()];\n throw new MemrelError(\n 'INVALID_ARGUMENT',\n `'${name}' is not a relation of ${table.name}${\n names.length ? `; expected one of: ${names.join(', ')}` : ''\n }`,\n );\n }\n\n // -------------------------------------------------------------------------------------------\n // Insert\n // -------------------------------------------------------------------------------------------\n\n private insertRow(op: Op, table: Table, input: Row, mode: OnConflict): string {\n const row = { ...input };\n const pk = encodeFields(row, table.key);\n const existing = table.state.rows.get(pk);\n if (!existing) {\n this.addRow(op, table, pk, row, table.state.seq++);\n } else if (mode === 'replace') {\n this.updateRows(op, table, [[pk, row]], 0);\n } else if (mode === 'throw') {\n throw new MemrelError('DUPLICATE_KEY', `${this.describe(table, row)} already exists`);\n }\n return pk;\n }\n\n insert(table: Table, input: Row | readonly Row[], mode: OnConflict): Row | Row[] {\n return this.write((op) => {\n if (!Array.isArray(input)) {\n const pk = this.insertRow(op, table, input as Row, mode);\n return () => table.state.rows.get(pk)!.row;\n }\n const pks = input.map((row) => this.insertRow(op, table, row, mode));\n return () => pks.map((pk) => table.state.rows.get(pk)!.row);\n })();\n }\n\n load(data: Record<string, readonly Row[] | undefined>, mode: OnConflict): void {\n this.write((op) => {\n for (const [name, rows] of Object.entries(data)) {\n if (rows === undefined) continue;\n const table = this.table(name);\n for (const row of rows) this.insertRow(op, table, row, mode);\n }\n });\n }\n\n table(name: string): Table {\n const table = this.tables.get(name);\n if (!table) throw new MemrelError('INVALID_ARGUMENT', `'${name}' is not a collection`);\n return table;\n }\n\n // -------------------------------------------------------------------------------------------\n // Update\n // -------------------------------------------------------------------------------------------\n\n update(\n table: Table,\n keys: object | readonly object[],\n patch: Row | ((row: Row) => Row),\n ): Row | Row[] {\n return this.write((op) => {\n const many = Array.isArray(keys);\n const list: readonly object[] = many ? keys : [keys];\n const changes = new Map<string, Row>();\n const pks = list.map((key) => {\n const pk = encodeFields(key, table.key);\n const entry = table.state.rows.get(pk);\n if (!entry) {\n throw new MemrelError(\n 'NOT_FOUND',\n `${table.name} ${displayKey(key, table.key)} not found`,\n );\n }\n if (!changes.has(pk)) {\n const p = typeof patch === 'function' ? patch(entry.row) : patch;\n changes.set(pk, { ...entry.row, ...p });\n }\n return pk;\n });\n const newPks = this.updateRows(op, table, [...changes], 0);\n const moved = new Map([...changes.keys()].map((pk, i) => [pk, newPks[i]!]));\n return () => {\n const rows = pks.map((pk) => table.state.rows.get(moved.get(pk)!)!.row);\n return many ? rows : rows[0]!;\n };\n })();\n }\n\n /**\n * Replaces rows and applies the `onUpdate` rules of refs pointing at changed values. All old\n * rows leave the indexes before the new ones enter, so rows in one call may swap keys.\n * Returns the new primary keys, in order.\n */\n private updateRows(op: Op, table: Table, changes: [string, Row][], depth: number): string[] {\n if (depth > MAX_CASCADE_DEPTH) {\n throw new MemrelError('INVALID_ARGUMENT', `Cascade through ${table.name} doesn't terminate`);\n }\n const s = table.state;\n const olds = changes.map(([pk]) => s.rows.get(pk)!);\n for (let i = 0; i < changes.length; i++) this.removeRow(table, changes[i]![0], olds[i]!.row);\n\n const newPks = changes.map(([, row], i) => {\n const pk = encodeFields(row, table.key);\n if (s.rows.has(pk)) {\n throw new MemrelError(\n 'DUPLICATE_KEY',\n `Cannot update ${this.describe(table, olds[i]!.row)}: ${this.describe(table, row)} already exists`,\n );\n }\n this.addRow(op, table, pk, row, olds[i]!.seq);\n return pk;\n });\n\n for (const ref of table.incoming) {\n const child = ref.from;\n const childChanges = new Map<string, Row>();\n for (let i = 0; i < changes.length; i++) {\n const row = changes[i]![1];\n const oldRow = olds[i]!.row;\n const before = this.referencedValue(ref, oldRow);\n if (before === null || before === this.referencedValue(ref, row)) continue;\n const bucket = child.state.reverse[ref.index]!.get(before);\n if (!bucket || bucket.size === 0) continue;\n\n if (ref.onUpdate === 'restrict') {\n op.vacated.push({ ref, value: before, verb: 'update', row: oldRow });\n continue;\n }\n for (const childPk of bucket) {\n const next = { ...(childChanges.get(childPk) ?? child.state.rows.get(childPk)!.row) };\n if (ref.onUpdate === 'cascade') {\n for (let j = 0; j < ref.fields.length; j++) {\n next[ref.fields[j]!] = row[ref.references[j]!];\n }\n } else {\n for (const f of ref.nullFields) next[f] = null;\n }\n childChanges.set(childPk, next);\n }\n }\n if (childChanges.size > 0) this.updateRows(op, child, [...childChanges], depth + 1);\n }\n\n return newPks;\n }\n\n // -------------------------------------------------------------------------------------------\n // Delete\n // -------------------------------------------------------------------------------------------\n\n delete(roots: [Table, object][]): DeleteOutcome {\n return this.write((op) => {\n // Plan: the rows to delete, in visiting order, and the set-null updates.\n const plan = new Map<Table, Map<string, Row>>();\n const queue: [Table, Row][] = [];\n const planned = (table: Table): Map<string, Row> => {\n let rows = plan.get(table);\n if (!rows) {\n rows = new Map();\n plan.set(table, rows);\n }\n return rows;\n };\n\n for (const [table, key] of roots) {\n const pk = encodeFields(key, table.key);\n const entry = table.state.rows.get(pk);\n if (!entry) {\n throw new MemrelError(\n 'NOT_FOUND',\n `${table.name} ${displayKey(key, table.key)} not found`,\n );\n }\n const rows = planned(table);\n if (rows.has(pk)) continue;\n rows.set(pk, entry.row);\n queue.push([table, entry.row]);\n }\n\n const nulls = new Map<Table, Map<string, Ref[]>>();\n for (let i = 0; i < queue.length; i++) {\n const [table, row] = queue[i]!;\n for (const ref of table.incoming) {\n const value = this.referencedValue(ref, row);\n if (value === null) continue;\n const child = ref.from;\n const bucket = child.state.reverse[ref.index]!.get(value);\n if (!bucket || bucket.size === 0) continue;\n\n if (ref.onDelete === 'restrict') {\n op.vacated.push({ ref, value, verb: 'delete', row });\n } else if (ref.onDelete === 'cascade') {\n const rows = planned(child);\n for (const childPk of bucket) {\n if (rows.has(childPk)) continue;\n const childRow = child.state.rows.get(childPk)!.row;\n rows.set(childPk, childRow);\n queue.push([child, childRow]);\n }\n } else {\n let byPk = nulls.get(child);\n if (!byPk) {\n byPk = new Map();\n nulls.set(child, byPk);\n }\n for (const childPk of bucket) {\n const refs = byPk.get(childPk);\n if (refs) refs.push(ref);\n else byPk.set(childPk, [ref]);\n }\n }\n }\n }\n\n // Execute.\n const outcome: DeleteOutcome = { deleted: {}, nulled: {} };\n for (const [table, rows] of plan) {\n for (const [pk, row] of rows) {\n this.removeRow(table, pk, row);\n push(outcome.deleted, table.name, row);\n }\n }\n const nulled: [Table, string[]][] = [];\n for (const [table, byPk] of nulls) {\n const changes: [string, Row][] = [];\n for (const [pk, refs] of byPk) {\n const entry = table.state.rows.get(pk);\n if (!entry) continue; // deleted by the plan after all\n const next = { ...entry.row };\n for (const ref of refs) for (const f of ref.nullFields) next[f] = null;\n changes.push([pk, next]);\n }\n if (changes.length > 0) nulled.push([table, this.updateRows(op, table, changes, 0)]);\n }\n return () => {\n for (const [table, pks] of nulled) {\n for (const pk of pks) {\n const entry = table.state.rows.get(pk);\n if (entry) push(outcome.nulled, table.name, entry.row);\n }\n }\n return outcome;\n };\n })();\n }\n\n // -------------------------------------------------------------------------------------------\n // Snapshots\n // -------------------------------------------------------------------------------------------\n\n snapshot(): SnapshotData {\n const states = new Map<Table, TableState>();\n for (const table of this.tables.values()) states.set(table, cloneState(table.state));\n return { store: this, states };\n }\n\n restore(snapshot: SnapshotData): void {\n if (snapshot?.store !== this) {\n throw new MemrelError('INVALID_ARGUMENT', 'Snapshot was not taken from this database');\n }\n this.savepoint(() => {\n for (const table of this.tables.values()) {\n const prev = table.state;\n table.state = cloneState(snapshot.states.get(table)!);\n this.log(() => {\n table.state = prev;\n });\n }\n });\n }\n}\n","import { MemrelError } from './errors.ts';\nimport type { Table } from './model.ts';\nimport { Store } from './store.ts';\nimport type { CheckConfig, Db, DbConfig, InsertOptions } from './types.ts';\n\ntype Row = Record<string, unknown>;\n\nfunction conflictMode(options: InsertOptions | undefined) {\n const mode = options?.onConflict ?? 'throw';\n if (mode !== 'throw' && mode !== 'ignore' && mode !== 'replace') {\n throw new MemrelError('INVALID_ARGUMENT', `Unknown onConflict mode '${String(mode)}'`);\n }\n return mode;\n}\n\nclass CollectionApi {\n readonly #store: Store;\n readonly #table: Table;\n\n constructor(store: Store, table: Table) {\n this.#store = store;\n this.#table = table;\n }\n\n get(key: object) {\n return this.#store.get(this.#table, key);\n }\n\n where(conditions: Row) {\n return this.#store.where(this.#table, conditions);\n }\n\n rel(row: Row, name: string) {\n return this.#store.rel(this.#table, row, name);\n }\n\n insert(rows: Row | readonly Row[], options?: InsertOptions) {\n return this.#store.insert(this.#table, rows, conflictMode(options));\n }\n\n update(keys: object | readonly object[], patch: Row | ((row: Row) => Row)) {\n return this.#store.update(this.#table, keys, patch);\n }\n\n delete(keys: object | readonly object[]) {\n const list: readonly object[] = Array.isArray(keys) ? keys : [keys];\n return this.#store.delete(list.map((key) => [this.#table, key]));\n }\n}\n\n/**\n * Creates a database. The double call is deliberate: the first call fixes the row types, the\n * second infers the exact config, which TypeScript can't do in one call.\n *\n * @example\n * ```ts\n * const db = createDb<{ user: User; post: Post }>()({\n * user: { key: ['id'], unique: [['email']] },\n * post: {\n * key: ['id'],\n * refs: {\n * author: { fields: ['authorId'], to: 'user', onDelete: 'cascade', inverse: 'posts' },\n * },\n * },\n * });\n * ```\n */\nexport function createDb<S extends { [N in keyof S]: object }>(): DefineDb<S> {\n return defineDb as DefineDb<S>;\n}\n\n/** The second step of {@link createDb}: takes the config and returns the database. */\nexport type DefineDb<S> = <const C extends DbConfig<S>>(config: C & CheckConfig<S, C>) => Db<S, C>;\n\nfunction defineDb(config: unknown): unknown {\n const store = new Store(config);\n const db: Record<string, unknown> = {\n load(data: Record<string, readonly Row[] | undefined>, options?: InsertOptions) {\n store.load(data, conflictMode(options));\n },\n remove(keys: Record<string, readonly object[] | undefined>) {\n const roots: [Table, object][] = [];\n for (const [name, list] of Object.entries(keys)) {\n const table = store.table(name);\n for (const key of list ?? []) roots.push([table, key]);\n }\n return store.delete(roots);\n },\n transaction<T>(fn: () => T): T {\n return store.savepoint(fn);\n },\n snapshot() {\n return store.snapshot();\n },\n restore(snapshot: ReturnType<Store['snapshot']>) {\n store.restore(snapshot);\n },\n };\n for (const table of store.tables.values()) {\n db[table.name] = new CollectionApi(store, table);\n }\n return db;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,60 @@
1
1
  {
2
2
  "name": "@mvd/memrel",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.0.0",
4
+ "description": "A small, synchronous, in-memory relational store for typed mock data: composite keys, foreign keys, cascades, transactions and snapshots.",
5
+ "keywords": [
6
+ "database",
7
+ "fixtures",
8
+ "foreign-key",
9
+ "in-memory",
10
+ "mock",
11
+ "msw",
12
+ "relational",
13
+ "testing",
14
+ "typescript"
15
+ ],
16
+ "homepage": "https://github.com/meesvandongen/memrel#readme",
17
+ "bugs": "https://github.com/meesvandongen/memrel/issues",
18
+ "license": "MIT",
19
+ "author": "Mees van Dongen",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/meesvandongen/memrel.git",
23
+ "directory": "packages/memrel"
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "README.md",
28
+ "LICENSE"
29
+ ],
30
+ "type": "module",
31
+ "sideEffects": false,
32
+ "main": "./dist/index.js",
33
+ "module": "./dist/index.js",
34
+ "types": "./dist/index.d.ts",
35
+ "exports": {
36
+ ".": "./dist/index.js",
37
+ "./package.json": "./package.json"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^24",
44
+ "publint": "^0.3.25",
45
+ "tinybench": "^6.2.2",
46
+ "typescript": "^7.0.2",
47
+ "vite-plus": "1.4.0"
48
+ },
49
+ "engines": {
50
+ "node": ">=20"
51
+ },
52
+ "scripts": {
53
+ "build": "vp pack",
54
+ "dev": "vp pack --watch",
55
+ "test": "vp test",
56
+ "test:watch": "vp test watch",
57
+ "coverage": "vp test run --coverage",
58
+ "bench": "vpx bench/memrel.bench.ts"
59
+ }
6
60
  }