// builders import {StoreBuilder, StoreUpdater} from './builder.store' import type { DatabaseDef, ExtantKey, Increment, IndexesConstraint, MigrationDef, MigrationFn, RowConstraint, SchemaConstraint, Simplify, StoreDef, UnusedKey, } from './schema' // Helper: merge row type changes into schema, preserving indexes for existing stores type MergeRowChanges< Current extends SchemaConstraint, Changes extends Record > = { [K in keyof Current | keyof Changes]: K extends keyof Changes ? K extends keyof Current // Existing store: update row, preserve indexes ? StoreDef // New store: no indexes : StoreDef // Unchanged store : K extends keyof Current ? Current[K] : never } export class DatabaseBuilder< Name extends string, Version extends number = 0, Schema extends SchemaConstraint = {}, > { #name: Name #stores: Record> #migrations: MigrationDef[] constructor(name: Name) { this.#name = name this.#stores = {} this.#migrations = [] } create>( name: UnusedKey, callback: (builder: StoreBuilder<{}>) => Builder ) { if (this.#stores[name]) throw new Error('cannot add store ${name} - already exists') const builder = callback(new StoreBuilder()) const store = builder.build(name) this.#stores[name] = store this.#migrations.push(['create', name, store]) type FinalStore = Builder extends StoreBuilder ? StoreDef : never return this as unknown as DatabaseBuilder< Name, Increment, Simplify > } modify>( name: ExtantKey, callback: (b: StoreUpdater< SName, Schema[SName]['__row'], Schema[SName]['__doc'], Schema[SName]['__indexes'] >) => Builder ) { if (this.#stores[name] === undefined) throw new Error('cannot update store ${name} - does not exist') const extant = this.#stores[name satisfies string] type InputUpdater = StoreUpdater< SName, Schema[SName]['__row'], Schema[SName]['__doc'], Schema[SName]['__indexes'] > const builder = new StoreUpdater(extant as any) as InputUpdater const store = callback(builder).build() this.#stores[name] = store this.#migrations.push(['update', name, store]) type FinalStore = Builder extends StoreUpdater ? StoreDef : never return this as unknown as DatabaseBuilder< Name, Increment, Simplify & {[K in SName]: FinalStore}> > } drop(name: ExtantKey) { if (this.#stores[name] === undefined) throw new Error('cannot remove store ${name} - does not exist') this.#migrations.push(['drop', name, this.#stores[name]]) delete this.#stores[name] return this as unknown as DatabaseBuilder, Simplify>> } migrate< Write extends Record, NextSchema extends SchemaConstraint = Simplify>, >(fn: MigrationFn) { this.#migrations.push(fn) return this as unknown as DatabaseBuilder, NextSchema> } build(): DatabaseDef { return { name: this.#name, version: this.#migrations.length as Version, migrations: this.#migrations, stores: this.#stores, __schema: undefined as unknown as Schema, } } }