Dexie.js icon indicating copy to clipboard operation
Dexie.js copied to clipboard

how to handle Dexie db version downgraded because of rollback to a previous checkpoint?

Open anurasin opened this issue 2 years ago • 7 comments

I have a question, lets's say a code having indexedDB version N has reached production. Users' browsers will now be having DB with version N.

db.version(2).stores(/* schema */) Now, let's say because of some production issue, we have to roll back to a previous checkpoint where the DB verison was N-1.

db.version(1).stores(/* schema */) when this code will be deployed, DB open will fail on user's machine as a greater version is already installed on the machine.

How to handle such cases of indexedDB?

I hope my query is clear. Sorry if it's unclear I will try to explain it with code if that is required.

anurasin avatar Jul 22 '22 16:07 anurasin

Hello, I am struggling with the same problem, the stackoverflow link no longer works. I can't find any info in the documentation. Thanks in advance.

maosin77 avatar Oct 30 '23 07:10 maosin77

This is a valid scenario and a nice solution for this has been planned in dexie@4.

For the time being, you might need to call db.open() explicitely and catch. If error.name === "VersionError", do appropriate action, which cloud be either to delete and recreate the db, or to set the db in autoOpen mode


const dbName = 'myDB';
const dbSchema = {
  friends: '++id, name, age';
};
const dbVersion = 3;

let db = new Dexie('mydb');
db.version(dbVersion).stores(dbSchema);

function openDb() {
  return db.open().catch(async error => {
    if (error.name !== 'VersionError') {
      throw error;
    }

    // Extract current installed version:
    const tmpDb = await new Dexie(db.name).open();
    const currentVersion = tmpDb.verno;
    tmpDb.close();

    // Create a new instance with an upgraded schema:
    db.version(currentVersion + 1).stores(schema); // Will replace schema with previous version's schema
    return db.open();
  });
}

Dexie@4 recently went from alpha to beta and we are about to pospone some features to dexie@5 in order to get dexie@4 out sooner. This change should be a prioritised change for dexie@4 inclusion.

dfahlander avatar Oct 30 '23 10:10 dfahlander

Thanks. We use dexie for the offline scenario. We write migrations manually, which is cumbersome and error-prone. So far we do not have a rollback strategy. It's much easier if you can simply delete and recreate db. Then you don't really need any migrations. The problem is when you need to deal with limited bandwidth, and you don't continueosly sync indexedDb with remote database.

Thanks for you reply, it is a way how we can implement rollback strategy.. but from I can see, I would need to implement migration for each version update and migration for rollback..

maosin77 avatar Oct 30 '23 14:10 maosin77

I see! Thanks for this feedback. Would having the option to attach a downgrade callback to a version be what you would solve your use case?

dfahlander avatar Oct 30 '23 15:10 dfahlander

Yes. It's still painfull, beacuse right now we maintain chain of upgrades, with such a callback, we would have additional method in this.. chain of chain methods. 😅 You can imagine such a code after some time of development. But it sounds much better than some ifology catching an exception when opening the base.

// for context: this is how our versioning looks like right now:

        this.version(20)
            .stores({
                  ...schemaChanges
            })
            .upgrade(async () => await this.onAllUpgrades(20)); // onAllUpgrades is a method that that runs on every upgrade
        
       this.version(21)
            .stores({
                  ...schemaChanges
            })
            .upgrade(async () => await this.onAllUpgrades(21));
            // downgrade method doesn't exist today (it's just an example)!
            .downgrade(downgradeFrom22()) // This is how I imagine it. 
                  // We would have to add this callback if we decide to rollback. 
                  // So we would have first rollback all changes, and then add this line as a hotfix, to 'repare' db on user end.

        this.version(22)
            .stores({
                 ...schemaChanges
            })
            .upgrade(async () => {
                await this.onAllUpgrades(22);
                await onUpgradeTo22(this); // onUpgrateToX are methods with specific migrations.
            });
            
            

maosin77 avatar Oct 30 '23 17:10 maosin77

I get it. It's logical to have a corresponding downgrade.

dfahlander avatar Oct 30 '23 19:10 dfahlander