IndexedDB: Can you manually initiate a version change transaction?

I am writing a chrome extension that uses IndexedDB

to store some client side information IDBObjectStore

in a IDBDatabase

.

The nature of the data is such that I need my users to be able to modify the object store at their whim. (add new objects, modify existing ones, etc.). I accomplish this using the settings page and everything is still fine and dandy.

The caveat comes up when I want to release a new version of the object store (default). If I didn't have to rewrite my users' data, I could just handle the event the onupgradeneeded

same way I handle it when it fires in response to a fresh install. What was that:

var request = window.indexedDB.open(DB_NAME, CURRENT_DB_VERSION);
request.onupgradeneeded = upgrade;
function upgrade(event){
  var db = event.target.result;
  var objectStore = db.createObjectStore("domains", {keyPath: "id", autoIncrement: true});
  objectStore.createIndex("domain", "domain", {multiEntry: true });
  for(var i=0; i<tags.length; i++){
    objectStore.add(tags[i]);
    console.log("added " + tags[i]["domain"] + " to the IDBObjectStore 'domains' in the IDBDatabase 'Tags' (Format)");
  }
}

      

... but I do not care.

So what I'm doing now is that you put the condition inside a function upgrade(event)

that checks for plausibility event.oldVersion

(its 0 on a fresh install). If the value is greater than 0, I open a new tab containing an options page where the user can select which objects he wants to update.

Now the tricky part: . When this page closes, I need to send a message to the background image containing the necessary update information. I usually just get a message in my listener and do the update using the information provided. However, it IDBDatabase.createObjectStore()

issues InvalidStateError

if:

The [is] method is not called from the versionchange transaction callback.

When I look at the spec for IDBDatabase.transaction(storenames, mode)

, the parameter description mode

says:

versionchange

not specified here.

So, it seems to me that I need to fire the event onupgradeneeded

, but I also need to pass an additional parameter to the event handler, besides the event itself, which contains information that it can use to decide how to perform the update.

I don't know how to do this though.

Can anyone offer me some insight?

+3


source to share


2 answers


You get InvalidStateError

because you cannot call IDBDatabase.createObjectStore()

from onupgradeneeded

an event handler. In the case of IDBs, all creation and manipulation of the object store must occur from within the event handler onupgradeneeded

or after being fired onupgradeneeded

.

If I understand your requirement correctly, you do not want to override the existing user object store under certain conditions, and for that you want to pass some information in an event handler onupgradeneeded

to indicate whether to create an additional object store or do some modification on top of the existing object store.

My recommendation would be 2 global array variables DB_SCHEMA_DROP_QUERIES

and DB_SCHEMA_CREATE_QUERIES

which you can prepare with drop and create data before opening the database withwindow.indexedDB.open(DB_NAME, CURRENT_DB_VERSION);



Then enter the following code (I'm just giving a heads-up), so when you want to 1. create a new database, first drop all existing data storage from the database and create a new one (which means filling like DB_SCHEMA_DROP_QUERIES

, and so DB_SCHEMA_CREATE_QUERIES

). 2. simply add another object store and then prepare DB_SCHEMA_CREATE_QUERIES

3. modify existing repository objects, then how to prepare DB_SCHEMA_DROP_QUERIES

, and DB_SCHEMA_CREATE_QUERIES

, but for this particular object store

Basically we are trying to make things dynamic instead of creating a hard-coded datastore like this one db.createObjectStore("domains", {keyPath: "id", autoIncrement: true});

. It will also help you get rid of keeping version records.

var dropQueriesLength = DB_SCHEMA_DROP_QUERIES.length;
for(var i =0; i < dropQueriesLength; i++){
try{
    DB_HANDLER.deleteObjectStore(DB_SCHEMA_DROP_QUERIES[i].name);
} catch(e){

}
}

for(var i =0; i < DB_SCHEMA_CREATE_QUERIES.length; i++){
  var objectStore = null;
    if(DB_SCHEMA_CREATE_QUERIES[i].primaryKeyCol != null && DB_SCHEMA_CREATE_QUERIES[i].primaryKeyCol != undefined){
        objectStore = DB_HANDLER.createObjectStore(DB_SCHEMA_CREATE_QUERIES[i].name, { keyPath: DB_SCHEMA_CREATE_QUERIES[i].primaryKeyCol});
    }
}

      

+3


source


The only way to initiate an update type transaction (version change transaction) is to open a connection with a higher version number.



+2


source







All Articles