mardi 3 août 2021

IndexedDB fully backup and restore of databases (without Dexie.js)

I want to backup IndexedDB into json file, and restore it on another machine / browser.

the goal is to fully backup and import website session (localStorage, cookies etc...)

I think that dumpIndexedDb() function works correctly,

the problem occur when I try to get this data and restore it back using restoreIndexedDbDump(data). there's no errors.

but only few databases restored. I'm pretty sure I was missed something with indexedDB api in the restore operation.

thanks in advance.

function dumpDB(dbName) {
    return new Promise((resolve, reject) => {
        var request = indexedDB.open(dbName)
        request.onerror = e => reject(e)
        request.onsuccess = (e) => {
            var data = {} // { dbVersion: 1, oName: {keyPath: 'key', data: [{},{}]} }
            var db = e.target.result
            var dbVersion = db.version
            data['dbVersion'] = dbVersion
            data['objectStores'] = {}
            var oStores = db.objectStoreNames
            for (let osName of oStores) {
                var transaction = db.transaction(osName, "readonly")
                var oStore = transaction.objectStore(osName)
                var keyPath = oStore.keyPath
                data['objectStores'][osName] = {}
                data['objectStores'][osName]['keyPath'] = keyPath
                var request = oStore.getAll()
                request.onerror = e => reject(e)
                request.onsuccess = (e) => {
                    data['objectStores'][osName]['data'] = e.target.result
                }
            }
            db.close()
            resolve(data)
        }
    })
}

async function dumpIndexedDb() {
    var data = {}
    var dbs = await indexedDB.databases() // not working in firefox, tested in chrome.
    for (let db of dbs) {
        var dbData = await dumpDB(db.name)
        data[db.name] = dbData
    }
    return data // {dbName: { dbVersion: 1, oName: {keyPath: 'key', data: [{},{}]} } }
}


function restoreObjectStore(dbName, version, oName, keyPath, data) {
    return new Promise((resolve, reject) => {
        request = window.indexedDB.open(dbName, version);
        request.onerror = e => reject(e)
        request.onupgradeneeded = function (e) {
            try {
                var db = e.target.result
                if (keyPath) var objectStore = db.createObjectStore(oName, { keyPath: keyPath, autoIncrement: false })
                else var objectStore = db.createObjectStore(oName, { autoIncrement: false })
                for (let row of data) {
                    console.log(`adding row of ${oName}`)
                }
                objectStore.transaction.commit()
                db.close()
                resolve("ok")
            } catch(e) {
                reject(e)
            }
        }
    })
}

async function restoreIndexedDbDump(data) {
    for (let dbName in data) {
        console.log(`deleting db ${dbName}`)
        indexedDB.deleteDatabase(dbName)
        for (let oStoreName in data[dbName]['objectStores']) {
            let odata = data[dbName]['objectStores'][oStoreName]['data']
            let dbVersion = data[dbName]['dbVersion']
            if ( data[dbName]['objectStores'][oStoreName]['keyPath'] ) {
                var keyPath = data[dbName]['objectStores'][oStoreName]['keyPath']
                await restoreObjectStore(dbName, dbVersion, oStoreName, keyPath, odata)
            }
            else {
                await restoreObjectStore(dbName, dbVersion, oStoreName, null, odata)
            }
        }
    }
}

async function testBackupandRestore() {
    var data = await dumpIndexedDb()
    await restoreIndexedDbDump(data)
}



Aucun commentaire:

Enregistrer un commentaire