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

[Question]: How we can subscribe on state when all migrations will be applied ?

Open rkovalov opened this issue 3 years ago • 6 comments

Is there any way to subscribe on upgrading state ? As workaround we could set additional flag, wrapped all promises from upgrade function and set to true when all promises will be resolved

class DB extends Dexie {
  private static VERSION = 10;
   constructor(dbName: string) {
       this.version(Database.VERSION)
        .stores({ ... })
          .upgrade(tx => {
          if (Database.VERSION === 10) {
            void runLongTimeMigrations(tx, Database.VERSION);
          }
          console.log(`Database was upgraded to v.${Database.VERSION}`);
        });
   }
}

const db = new DB('DBName');
db.on('ready', () => {
    console.log('DB READY TO START');
   //  But actually DB is not ready and continue applied migrations
});



rkovalov avatar Oct 06 '21 16:10 rkovalov

Thanks. Trying to understand your goal with the question. So here are some questions for you:

What are you trying to achieve? Do you want to display some progress to the user or do you want to log or debug what's going on?

What do you mean by the comment in db.on('ready')? If you experience that the DB is NOT ready here but continue to do things, it leads me to the next question:

What does your runLongTimeMigrations() do and why don't you await it? Does it call non-dexie async functions such as fetch() or webCrypto calls? If so, are you wrapping them using Dexie.waitFor()?

dfahlander avatar Oct 07 '21 07:10 dfahlander

@dfahlander thanks for response,

  1. What I would like to achieve:
  • If db is not exist: start application when DB created schema and populate data.
  • if db is exist: start application only if all migrations on data or schema will be done.
  1. Callback on ready invoked when database in opened but I guess it better to run it when all migrations in upgrade function will be done or rename event open instead of ready

  2. runLongTimeMigrations just for ex. if we have a lot of data and we need to iterate and update smth, inside it called dexie's async func, interface of callback upgrade function returns void, thats why I dont await it

I dont use Dexie.waitFor()

rkovalov avatar Oct 07 '21 08:10 rkovalov

EDITED

db.on('ready') is invoked after upgrade transaction has completed. But if your upgrader calls non-dexie async calls such as fetch(), webcrypto calls etc, the upgrade transaction will commit too early and the rest of your upgrading code might execute outside the upgrade transaction (See bullet no 3 in best-practices).

It is normally not needed to distinguish whether the database needs to be created or not. You declare the database schema, the upgraders and the framework will solve that for you. See Understanding the basics

dfahlander avatar Oct 07 '21 08:10 dfahlander

@dfahlander I got your point, If I correctly understand how I can manage migrations is wrap all of them by Dexie.waitFor: for my example I use only Dexie transaction updater for tables and dont call third party async func

class DB extends Dexie {
  private static VERSION = 10;
   constructor(dbName: string) {
       this.version(Database.VERSION)
        .stores({ ... })
        .upgrade(tx => {
           // wrapped all promises here
            Dexie.waitFor( async () => {
                  await runLongTimeMigrationsOnFirstTable(tx, Database.VERSION);
                  await runLongTimeMigrationsOnSecondTable(tx, Database.VERSION);
                  console.log(`Database was upgraded to v.${Database.VERSION}`);
              });
            });      
        }
}
// migrations looks like
const runLongTimeMigrationsOnFirstTable = async (tx: Transaction, version: number): Promise<void> => {
 await tx.table('tableName').clear();
 // ..... populate with different data;
 console.log(`Migration for 'tableName' was applied to v.${version}`);
}




rkovalov avatar Oct 07 '21 11:10 rkovalov

No, only use Dexie.waitFor() to do things outside Dexie. If you access the upgrade transaction in there, you will have a deadlock. Only use waitFor around non-indexeddb work such as webCrypro calls or fetch.

dfahlander avatar Oct 23 '21 15:10 dfahlander

@dfahlander, I see, that's exactly what I want to reach, don't give access to application until all required migrations will be done. I have to properly manage offline applications and wanna be sure that all state in cold loading are actual for user before rendering smth.

rkovalov avatar Oct 25 '21 12:10 rkovalov