import Ajv from 'ajv' ; import addFormats from 'ajv-formats' ; import Dexie , { DBCore , DBCoreMutateRequest , DBCoreMutateResponse , DBCoreTable , Middleware , } from 'dexie' ; import { JSONSchema4 , JSONSchema4Type } from 'json-schema' ; import { initOverrideCreateTransaction , initOverrideParseStoreSpec , } from '../overrides' ; const ajv = new Ajv ( { useDefaults : true } ) ; addFormats ( ajv ) ; export const SchemasTableName = '_schemas' ; export type JSONSchema = JSONSchema4 ; export type JSONType = JSONSchema4Type ; declare module 'dexie' { export interface Table { setSchema ( schema ? ) : Promise < void > ; getSchema ( ) : Promise < JSONSchema > ; } } const defaultSchema = { properties : { _id : { type : 'string' , } , } , } ; export function createSchemaMiddleware ( core ) { return { ... core , table ( tableName ) { const table = core . table ( tableName ) ; if ( tableName . startsWith ( '_' ) ) return table ; return { ... table , async mutate ( req ) { const pair = await core . table ( SchemasTableName ) . get ( { key : tableName , trans : req . trans } ) ; const schema = pair ?. schema ?? defaultSchema ; const validator = ajv . compile ( schema ) ; try { switch ( req . type ) { case 'add' : case 'put' : const values = Dexie . deepClone ( req . values ) ; values . forEach ( ( value ) => { if ( validator ( value ) === false && validator . errors ) { throw new Ajv . ValidationError ( validator . errors ) ; } } ) ; req = { ... req , values } ; } } catch ( err ) { throw err ; } return table . mutate ( req ) ; } , } ; } , } ; } export const schemaMiddleware = { stack : 'dbcore' , name : 'SchemaMiddleware' , create : createSchemaMiddleware , } ; /**
 * SchemaAddon function
 */ export function schemaAddon ( db ) { db . use ( schemaMiddleware ) ; const overrideCreateTransaction = initOverrideCreateTransaction ( db , SchemasTableName ) ; db . _createTransaction = Dexie . override ( db . _createTransaction , overrideCreateTransaction ) ; const overrideParseStoresSpec = initOverrideParseStoreSpec ( { [ SchemasTableName ] : '&name' , } ) ; ( db . Version . prototype as any ) . _parseStoresSpec = Dexie . override ( ( db . Version . prototype as any ) . _parseStoresSpec , overrideParseStoresSpec ) ; db . Table . prototype . setSchema = async function ( schema = defaultSchema ) : Promise < void > { await this . db . table ( SchemasTableName ) . put ( { name : this . name , schema } ) ; } ; db . Table . prototype . getSchema = async function ( ) : Promise < any > { const pair = await this . db . table ( SchemasTableName ) . get ( { name : this . name } ) ; const obj = pair ?. schema ; if ( obj === undefined || ( Object . keys ( obj ) . length === 0 && obj . constructor === Object ) ) { return defaultSchema ; } return obj ; } ; }