import { useCallback } from 'react' ; import { validateBeforeTransaction } from './Utils' ; import { ObjectStoreMeta , ObjectStoreSchema } from './indexed-hooks' ; import { createReadwriteTransaction } from './createReadwriteTransaction' ; import { createReadonlyTransaction } from './createReadonlyTransaction' ; export type Key = string | number | Date | ArrayBufferView | ArrayBuffer | IDBArrayKey | IDBKeyRange ; export interface IndexDetails { indexName : string ; order : string ; } const indexedDB = window . indexedDB || ( < any > window ) . mozIndexedDB || ( < any > window ) . webkitIndexedDB || ( < any > window ) . msIndexedDB ; export function openDatabase ( dbName , version , upgradeCallback ? ) { return new Promise < IDBDatabase > ( ( resolve , reject ) => { const request = indexedDB . open ( dbName , version ) ; let db ; request . onsuccess = ( event ) => { db = request . result ; resolve ( db ) ; } ; request . onerror = ( event ) => { reject ( `IndexedDB error: ${ request . error }` ) ; } ; if ( typeof upgradeCallback === 'function' ) { request . onupgradeneeded = ( event ) => { upgradeCallback ( event , db ) ; } ; } } ) ; } export function CreateObjectStore ( dbName , version , storeSchemas ) { const request = indexedDB . open ( dbName , version ) ; request . onupgradeneeded = function ( event ) { const database = ( event . target as any ) . result ; storeSchemas . forEach ( ( storeSchema ) => { if ( ! database . objectStoreNames . contains ( storeSchema . store ) ) { const objectStore = database . createObjectStore ( storeSchema . store , storeSchema . storeConfig ) ; storeSchema . storeSchema . forEach ( ( schema ) => { objectStore . createIndex ( schema . name , schema . keypath , schema . options ) ; } ) ; } } ) ; database . close ( ) ; } ; request . onsuccess = function ( e ) { e . target . result . close ( ) ; } ; } export function DBOperations ( dbName , version , currentStore ) { const getAll = useCallback ( < T > ( ) => new Promise < T [ ] > ( ( resolve , reject ) => { openDatabase ( dbName , version ) . then ( db => { validateBeforeTransaction ( db , currentStore , reject ) ; const { store } = createReadonlyTransaction ( db , currentStore , resolve , reject ) ; const request = store . getAll ( ) ; request . onerror = error => reject ( error ) ; request . onsuccess = function ( { target : { result } } ) { resolve ( result as T [ ] ) ; } ; } ) ; } ) , [ dbName , version , currentStore ] ) ; const getByID = useCallback ( < T > ( id ) => new Promise < T > ( ( resolve , reject ) => { openDatabase ( dbName , version ) . then ( ( db ) => { validateBeforeTransaction ( db , currentStore , reject ) ; const { store } = createReadonlyTransaction ( db , currentStore , resolve , reject ) ; const request = store . get ( id ) ; request . onsuccess = function ( event ) { resolve ( ( event . target as any ) . result as T ) ; } ; } ) ; } ) , [ dbName , version , currentStore ] ) ; const openCursor = useCallback ( ( cursorCallback , keyRange ? ) => { return new Promise < void > ( ( resolve , reject ) => { openDatabase ( dbName , version ) . then ( db => { validateBeforeTransaction ( db , currentStore , reject ) ; const { store } = createReadonlyTransaction ( db , currentStore , resolve , reject ) ; const request = store . openCursor ( keyRange ) ; request . onsuccess = ( event ) => { cursorCallback ( event ) ; resolve ( ) ; } ; } ) ; } ) ; } , [ dbName , version , currentStore ] ) ; const getByIndex = useCallback ( ( indexName , key ) => new Promise < any > ( ( resolve , reject ) => { openDatabase ( dbName , version ) . then ( db => { validateBeforeTransaction ( db , currentStore , reject ) ; const { store } = createReadonlyTransaction ( db , currentStore , resolve , reject ) ; const index = store . index ( indexName ) ; const request = index . get ( key ) ; request . onsuccess = ( event ) => { resolve ( ( < IDBOpenDBRequest > event . target ) . result ) ; } ; } ) ; } ) , [ dbName , version , currentStore ] ) ; const add = useCallback ( < T > ( value , key ? ) => new Promise < number > ( ( resolve , reject ) => { openDatabase ( dbName , version ) . then ( ( db ) => { const { store } = createReadwriteTransaction ( db , currentStore , resolve , reject ) ; const request = store . add ( value , key ) ; request . onsuccess = ( evt ) => { key = evt . target . result ; resolve ( key ) ; } ; request . onerror = error => reject ( error ) ; } ) ; } ) , [ dbName , version , currentStore ] ) ; const update = useCallback ( < T > ( value , key ? ) => new Promise < any > ( ( resolve , reject ) => { openDatabase ( dbName , version ) . then ( db => { validateBeforeTransaction ( db , currentStore , reject ) ; const { transaction , store , } = createReadwriteTransaction ( db , currentStore , resolve , reject ) ; transaction . oncomplete = event => resolve ( event ) ; store . put ( value , key ) ; } ) ; } ) , [ dbName , version , currentStore ] ) ; const deleteRecord = useCallback ( ( key ) => new Promise < any > ( ( resolve , reject ) => { openDatabase ( dbName , version ) . then ( db => { validateBeforeTransaction ( db , currentStore , reject ) ; const { store } = createReadwriteTransaction ( db , currentStore , resolve , reject ) ; const request = store . delete ( key ) ; request . onsuccess = event => resolve ( event ) ; } ) ; } ) , [ dbName , version , currentStore ] ) ; const clear = useCallback ( ( ) => new Promise < any > ( ( resolve , reject ) => { openDatabase ( dbName , version ) . then ( db => { validateBeforeTransaction ( db , currentStore , reject ) ; const { store , transaction } = createReadwriteTransaction ( db , currentStore , resolve , reject ) ; transaction . oncomplete = ( ) => resolve ( ) ; store . clear ( ) ; } ) ; } ) , [ dbName , version , currentStore ] ) ; return { add , getByID , getAll , update , deleteRecord , clear , openCursor , getByIndex , } ; } export enum DBMode { readonly = 'readonly' , readwrite = 'readwrite' }