jakearchibald / idb

IndexedDB, but with promises
https://www.npmjs.com/package/idb
ISC License
6.29k stars 353 forks source link

enhancement: get current DB version #192

Closed helgasoft closed 4 years ago

helgasoft commented 4 years ago

Is there a possibility to add a function which will return the current (highest) version of the database? Similar to verno in Dexie.

The actual goal is to build another, more useful function, for adding(creating) ObjectStores without specifying explicitly any version, just a name, like addNewStore('name1').

jakearchibald commented 4 years ago

db.version will give you that.

If you want to get the version number before opening the database, there's https://developer.mozilla.org/en-US/docs/Web/API/IDBFactory/databases, but unfortunately it's only implemented in Chrome. It can't really be polyfilled, other than trying to open the database with incrementing numbers, which would be bad for performance.

helgasoft commented 4 years ago

Thank you for the prompt reply. Yes, the link provides a solution, too bad it's only for Chrome.
However, the other option - incrementing version numbers looks promising. I presume on each browser IndexedDB keeps just one version - the latest, leaving versioning logic entirely to the developer.
Could you please elaborate on why frequent/multiple schema(version) changes "would be bad for performance" ?

jakearchibald commented 4 years ago

I presume on each browser IndexedDB keeps just one version - the latest, leaving versioning logic entirely to the developer.

Yep!

Could you please elaborate on why frequent/multiple schema(version) changes "would be bad for performance" ?

Well, if you were trying to find out the version number of database foo, which was at version 100, that means you'd try to open it 100 times before successfully opening it. I don't imagine that would be fast.

helgasoft commented 4 years ago

Luckily we can use the error on open to do it in just one call.

function getVersion(dbn) {  // find current version of database dbn
   // requires the version to be > 1, i.e. the database has been updated twice initially
   idb.openDB(dbn, 1 ).then(db => { db.close(); })   // close if opened with version<2
      .catch(err => {
    if (err.name == 'VersionError') {
           let version = parseInt(err.message.split(' ').pop().replace(/[{(.)}]/g, ''), 10);
           console.log (dbn+' - found version '+version);
           return version;
    }
    else  throw new Error('verErr: '+err.message);
   });  
}
jakearchibald commented 4 years ago

Hah, that's pretty smart! The format of the error message isn't in the spec, so that workaround might break in future, but still, smart.

ivanjeremic commented 3 years ago

What about using the idb-keyval package to store version numbers and if needed increment it and store it there any downsides to that?

jakearchibald commented 3 years ago

I think the right answer here is to open the dB with an undefined version number, then read db.version.

ivanjeremic commented 3 years ago

I think the right answer here is to open the dB with an undefined version number, then read db.version.

This is how I solved it, this function is used everywhere where a new version is needed like on new store creation, any suggestions is it ok to do it like that?

async function incrVersion() {
  const db = await openDB('myDB');
  const v = db.version;
  return v + 1;
}

Then use it where needed.

export async function addStore(store) {
  openDB('myDB', await incrVersion(), {   // here is how I use it
    upgrade(db) {
      db.createObjectStore(store, { keyPath: 'id' });
    },
  });
}