import type { ClassConstructor } from "@3fv/guard" import type { DexieTableConfig, DexieTableOptions, DexieTableOptionsArg } from "./types/index" import { createDexieDatabase } from "./createDexieDatabase" import { openDexieDatabase } from "./openDexieDatabase" import Dexie from "dexie" const tableDefaults: DexieTableOptions = { mapToClass: true } export class DexieDatabaseBuilder< Schema extends {}, DB extends Dexie = Dexie > { /** * Add a table to the schema. * The current {@link DexieDatabaseBuilder.schema} is shallow * copied along with the new: * * ``` * { [tableName]: DexieTableConfig } * ``` * @template TableName, T, PrimaryKeyField * @param {TableName} name * @param {ClassConstructor} ctor * @param {PrimaryKeyField} primaryKeyField * @param {string} indexConfig * @returns {DexieDatabaseBuilder< * Schema & { * [Name in TableName]: DexieTableConfig * } * >} * @param options */ table< TableName extends string, T extends {}, PrimaryKeyField extends readonly (keyof T)[] >( name: TableName, ctor: ClassConstructor, primaryKeyField: PrimaryKeyField, indexConfig: string, options?: DexieTableOptionsArg ): DexieDatabaseBuilder< Schema & { [Name in TableName]: DexieTableConfig }, Dexie & DB & { [Name in TableName]: Dexie.Table< T, { [I in keyof PrimaryKeyField]: PrimaryKeyField[I] extends keyof T ? T[PrimaryKeyField[I]] : undefined } > } > table< TableName extends string, T extends {}, PrimaryKeyField extends keyof T >( name: TableName, ctor: ClassConstructor, primaryKeyField: PrimaryKeyField, indexConfig: string, options?: DexieTableOptionsArg ): DexieDatabaseBuilder< Schema & { [Name in TableName]: DexieTableConfig }, Dexie & DB & { [Name in TableName]: Dexie.Table } > table( name: string, ctor: ClassConstructor, primaryKeyField: any, indexConfig: string, options: DexieTableOptionsArg = {} ) { const config: DexieTableOptions = { ...tableDefaults, ...options } // Create next schema const nextSchema = { ...this.schema, [name]: [ctor, primaryKeyField, indexConfig, config] } return new DexieDatabaseBuilder(this.dbName, this.version, nextSchema) } /** * Create the database * * @param dbName * @param version * @return {Promise>} */ create(dbName: string = this.dbName, version: number = this.version): DB { return createDexieDatabase(dbName, version, this.schema) } /** * Create & Open the database * * @param dbName * @param version * @return {Promise>} */ open( dbName: string = this.dbName, version: number = this.version ): Promise { return openDexieDatabase(dbName, version, this.schema) } /** * Private constructor, accepts current schema * and stores as readonly, it is immutable, * but not frozen for performance * * @param schema instance * @param dbName * @private * @param version */ private constructor( readonly dbName: string, readonly version: number, readonly schema: Schema ) {} /** * Create a new instance, constructor is private to * simplify typing demands * * @param dbName * @param version * @return {DexieDatabaseBuilder<{}>} */ static new(dbName: string = "dexie", version: number = 1) { return new DexieDatabaseBuilder(dbName, version, {}) } } /** * Get a new database builder * * @param dbName * @param version * @return {DexieDatabaseBuilder<{}>} */ export function dexieDatabaseBuilder(dbName?: string, version?: number) { return DexieDatabaseBuilder.new(dbName) } export default dexieDatabaseBuilder