Dexie.js
Dexie.js copied to clipboard
[Question]: How we can subscribe on state when all migrations will be applied ?
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
});
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 thanks for response,
- 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.
-
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 eventopen
instead ofready
-
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 callbackupgrade
function returnsvoid
, thats why I dont await it
I dont use Dexie.waitFor()
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 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}`);
}
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, 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.