diff --git a/src/classes/dexie/dexie.ts b/src/classes/dexie/dexie.ts index 0abacfab7..3f229b70a 100644 --- a/src/classes/dexie/dexie.ts +++ b/src/classes/dexie/dexie.ts @@ -56,6 +56,7 @@ export interface DbReadyState { openCanceller: Promise & { _stackHolder?: Error }; autoSchema: boolean; vcFired?: boolean; + PR1398_maxLoop?: number; } export class Dexie implements IDexie { @@ -120,7 +121,8 @@ export class Dexie implements IDexie { dbReadyPromise: null as Promise, cancelOpen: nop, openCanceller: null as Promise, - autoSchema: true + autoSchema: true, + PR1398_maxLoop: 3 }; state.dbReadyPromise = new Promise(resolve => { state.dbReadyResolve = resolve; diff --git a/src/classes/dexie/transaction-helpers.ts b/src/classes/dexie/transaction-helpers.ts index 0aa94e9b9..0eda94c6d 100644 --- a/src/classes/dexie/transaction-helpers.ts +++ b/src/classes/dexie/transaction-helpers.ts @@ -1,5 +1,5 @@ import { TransactionMode } from '../../public/types/transaction-mode'; -import { exceptions } from '../../errors'; +import { errnames, exceptions } from '../../errors'; import { flatten, isAsyncFunction } from '../../functions/utils'; import { Dexie } from './dexie'; import { Transaction } from '../transaction'; @@ -49,7 +49,23 @@ export function enterTransactionScope( // Emulate transaction commit awareness for inner transaction (must 'commit' when the inner transaction has no more operations ongoing) trans.idbtrans = parentTransaction.idbtrans; } else { - trans.create(); // Create the backend transaction so that complete() or error() will trigger even if no operation is made upon it. + try { + trans.create(); // Create the native transaction so that complete() or error() will trigger even if no operation is made upon it. + db._state.PR1398_maxLoop = 3; + } catch (ex) { + if (ex.name === errnames.InvalidState && db.isOpen() && --db._state.PR1398_maxLoop > 0) { + console.warn('Dexie: Need to reopen db'); + db._close(); + return db.open().then(() => enterTransactionScope( + db, + mode, + storeNames, + null, + scopeFunc + )); + } + return rejection(ex); + } } // Support for native async await. diff --git a/src/functions/temp-transaction.ts b/src/functions/temp-transaction.ts index d61948656..73de7128e 100644 --- a/src/functions/temp-transaction.ts +++ b/src/functions/temp-transaction.ts @@ -1,6 +1,6 @@ import { PSD, rejection, newScope } from "../helpers/promise"; import { DexieOptions } from "../public/types/dexie-constructor"; -import { exceptions } from "../errors"; +import { errnames, exceptions } from "../errors"; import { nop } from "./chaining-functions"; import { Transaction } from "../classes/transaction"; import { Dexie } from '../classes/dexie'; @@ -28,7 +28,17 @@ export function tempTransaction ( return db._state.dbReadyPromise.then(() => tempTransaction(db, mode, storeNames, fn)); } else { var trans = db._createTransaction(mode, storeNames, db._dbSchema); - try { trans.create(); } catch (ex) { return rejection(ex); } + try { + trans.create(); + db._state.PR1398_maxLoop = 3; + } catch (ex) { + if (ex.name === errnames.InvalidState && db.isOpen() && --db._state.PR1398_maxLoop > 0) { + console.warn('Dexie: Need to reopen db'); + db._close(); + return db.open().then(()=>tempTransaction(db, mode, storeNames, fn)); + } + return rejection(ex); + } return trans._promise(mode, (resolve, reject) => { return newScope(() => { // OPTIMIZATION POSSIBLE? newScope() not needed because it's already done in _promise. PSD.trans = trans;