dexie / Dexie.js

A Minimalistic Wrapper for IndexedDB
https://dexie.org
Apache License 2.0
11.64k stars 641 forks source link

Re-initialize dexie #521

Open kamleshchandnani opened 7 years ago

kamleshchandnani commented 7 years ago

I am using dexie for authenticated web app. Now when a user logs out I need to purge db and recreate it, in short I am trying to re initialize DB to it's initial state.

DB.delete().then(() => {
        console.log('DB deleted successfully');
    }).finally(() => {
        console.log('reinitializing DB');
        DB.close()
        DB = new Dexie('dbinstance', { autoOpen: false });
        // populateTables()
        DB.version(version).stores({
        reasons: 'id,name,reasoncategory_id,reasoncategory_name',
        reports: 'id,role_id,report_name,report_type,url,is_active,created,modified',
    })
    DB.open()
    })

It works as expected but there are two issues here There are two issues

  1. delete is blocked
  2. When I query DB after this process gets executed, I get error 'database has been closed' though I have opened db
dfahlander commented 7 years ago

First of all, you don't really need to create new Dexie instance. Just do

function recreateDB(db) {
    return db.delete().then (()=>db.open());
} 

Your issues :

  1. Delete is blocked. Happens if you have non - Dexie connection open to it as Dexie instances by default listens to 'versionchange' event and releases their connection, allowing deletes to resume.

  2. That's because you need to return the promise from DB.open() to wait for it before resuming your db facing code (since you explicitly specify {autoOpen: false})

kamleshchandnani commented 7 years ago

@dfahlander Thanks a lot! Dexie is a great library. Great work!

lddubeau commented 6 years ago

@dfahlander I believe this explanation to be misleading:

Delete is blocked. Happens if you have non - Dexie connection open to it as Dexie instances by default listens to 'versionchange' event and releases their connection, allowing deletes to resume.

I've seen this notion of "non-Dexie connections" a number of times in comments on Dexie issues but, looking at the spec, and testing with some code, this does not appear correct to me: Dexie can step on its own toes, so to speak, and the delete being blocked can happen even of there are no "non-Dexie connections" involved. It is true that Dexie will get a versionchange event and will immediately call close() to close the database. However, close() only initiates the closure of the database. The closure may not become effective until some undetermined time in the future. If an IndexedDB transaction needs to complete, for instance, the closure is not immediate. The problem is that if the connections are not closed by the time the versionchange handlers that are called finish running, IndexedDB will immediately issue a blocked event.

I have a fairly complex test suite I run through Karma. There's only one tab, and there's no other code that uses IndexedDB, besides Dexie, and I get blocked messages every now and then.

I have a plunk here with which I'm able to get Dexie to generate a Dexie.delete('library-dexie') was blocked event, even though the only thing using IndexedDB is Dexie.

dfahlander commented 6 years ago

Thanks for that clarification. It's true that the "blocked" event can occur in case there are running transactions. However, it will succeed with the delete or upgrade operation as soon as those transactions complete, despite blocked event was triggered. We could see it as a warning only - a sign that there might take a while until the delete() or open() promise will resolve.

What happened in your plunker example is the following:

  1. You open a db
  2. You request a transaction (using db.transaction())
  3. You close the same db instance by calling db.delete(). This happens during the same tick as the transaction starts, so either it fails with DatabaseClosedError or the delete operation blocks very temporarily, but succeeds after a few milliseconds.

I laborated with the plunker and added catch()-clauses on the promise and the result is that the transaction promise is rejected immediately and the delete() promise is sometimes resolves. But since you used Promise.all() the whole promise will reject if either of the involved promises rejects.

Here's a modified sample that tests to do the two operation with 2 different connections instead. That plunker works better as the transaction finishes, the delete operation blocks temporarily and then immediately succeeds deleting when transaction is done. https://plnkr.co/edit/GMRzffPTSzxw1sItvJcZ?p=info