Skip to content

Instantly share code, notes, and snippets.

@ctwowt
Forked from loilo/idb-backup-and-restore.js
Created April 18, 2020 04:54
Show Gist options
  • Save ctwowt/00edb36e1134f2bb0a9fdf43ab6e3f9b to your computer and use it in GitHub Desktop.
Save ctwowt/00edb36e1134f2bb0a9fdf43ab6e3f9b to your computer and use it in GitHub Desktop.

Revisions

  1. @loilo loilo revised this gist Jan 8, 2020. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions idb-backup-and-restore.md
    Original file line number Diff line number Diff line change
    @@ -41,6 +41,7 @@ Depending on your use case, it can be reasonable to clear a database before impo

    ```js
    import { idb } from 'some-database'
    import { serializedData } from 'some-serialized-data'

    import { importFromJson, clearDatabase } from 'idb-backup-and-restore.mjs'

  2. @loilo loilo revised this gist Jan 8, 2020. 1 changed file with 7 additions and 8 deletions.
    15 changes: 7 additions & 8 deletions idb-backup-and-restore.md
    Original file line number Diff line number Diff line change
    @@ -7,9 +7,9 @@ For each of the provided functionalities, you need a connected [`IDBDatabase`](h

    ### Export Data
    ```js
    import { idb } from 'get-database-from-somewhere.js'
    import { idb } from 'some-database'

    import { exportToJson } from 'idb-backup-and-restore.js'
    import { exportToJson } from 'idb-backup-and-restore.mjs'

    exportToJson(idb)
    .then(result => {
    @@ -22,10 +22,10 @@ exportToJson(idb)

    ### Import Data
    ```js
    import { idb } from 'get-database-from-somewhere.js'
    import { serializedData } from 'get-serialized-data-from-somewhere.js'
    import { idb } from 'some-database'
    import { serializedData } from 'some-serialized-data'

    import { importFromJson } from 'idb-backup-and-restore.js'
    import { importFromJson } from 'idb-backup-and-restore.mjs'

    importFromJson(idb, serializedData)
    .then(() => {
    @@ -40,10 +40,9 @@ importFromJson(idb, serializedData)
    Depending on your use case, it can be reasonable to clear a database before importing serialized data:

    ```js
    import { idb } from 'get-database-from-somewhere.js'
    import { serializedData } from 'get-serialized-data-from-somewhere.js'
    import { idb } from 'some-database'

    import { importFromJson, clearDatabase } from 'idb-backup-and-restore.js'
    import { importFromJson, clearDatabase } from 'idb-backup-and-restore.mjs'

    clearDatabase(idb)
    .then(() => importFromJson(idb, serializedData))
  3. @loilo loilo revised this gist Sep 27, 2019. 2 changed files with 0 additions and 0 deletions.
    File renamed without changes.
    File renamed without changes.
  4. @loilo loilo revised this gist Sep 25, 2019. 1 changed file with 20 additions and 18 deletions.
    38 changes: 20 additions & 18 deletions idb-backup-and-restore.js
    Original file line number Diff line number Diff line change
    @@ -90,23 +90,25 @@ export function importFromJson(idbDatabase, json) {
    * @return {Promise<void>}
    */
    export function clearDatabase(idbDatabase) {
    const transaction = idbDatabase.transaction(
    idbDatabase.objectStoreNames,
    'readwrite'
    )
    transaction.addEventListener('error', reject)
    return new Promise((resolve, reject) => {
    const transaction = idbDatabase.transaction(
    idbDatabase.objectStoreNames,
    'readwrite'
    )
    transaction.addEventListener('error', reject)

    let count = 0
    for (const storeName of idbDatabase.objectStoreNames) {
    transaction
    .objectStore(storeName)
    .clear()
    .addEventListener('success', () => {
    count++
    if (count === idbDatabase.objectStoreNames.length) {
    // Cleared all object stores
    resolve()
    }
    })
    }
    let count = 0
    for (const storeName of idbDatabase.objectStoreNames) {
    transaction
    .objectStore(storeName)
    .clear()
    .addEventListener('success', () => {
    count++
    if (count === idbDatabase.objectStoreNames.length) {
    // Cleared all object stores
    resolve()
    }
    })
    }
    })
    }
  5. @loilo loilo created this gist Sep 25, 2019.
    112 changes: 112 additions & 0 deletions idb-backup-and-restore.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,112 @@
    /**
    * Export all data from an IndexedDB database
    *
    * @param {IDBDatabase} idbDatabase The database to export from
    * @return {Promise<string>}
    */
    export function exportToJson(idbDatabase) {
    return new Promise((resolve, reject) => {
    const exportObject = {}
    if (idbDatabase.objectStoreNames.length === 0) {
    resolve(JSON.stringify(exportObject))
    } else {
    const transaction = idbDatabase.transaction(
    idbDatabase.objectStoreNames,
    'readonly'
    )

    transaction.addEventListener('error', reject)

    for (const storeName of idbDatabase.objectStoreNames) {
    const allObjects = []
    transaction
    .objectStore(storeName)
    .openCursor()
    .addEventListener('success', event => {
    const cursor = event.target.result
    if (cursor) {
    // Cursor holds value, put it into store data
    allObjects.push(cursor.value)
    cursor.continue()
    } else {
    // No more values, store is done
    exportObject[storeName] = allObjects

    // Last store was handled
    if (
    idbDatabase.objectStoreNames.length ===
    Object.keys(exportObject).length
    ) {
    resolve(JSON.stringify(exportObject))
    }
    }
    })
    }
    }
    })
    }

    /**
    * Import data from JSON into an IndexedDB database.
    * This does not delete any existing data from the database, so keys may clash.
    *
    * @param {IDBDatabase} idbDatabase Database to import into
    * @param {string} json Data to import, one key per object store
    * @return {Promise<void>}
    */
    export function importFromJson(idbDatabase, json) {
    return new Promise((resolve, reject) => {
    const transaction = idbDatabase.transaction(
    idbDatabase.objectStoreNames,
    'readwrite'
    )
    transaction.addEventListener('error', reject)

    var importObject = JSON.parse(json)
    for (const storeName of idbDatabase.objectStoreNames) {
    let count = 0
    for (const toAdd of importObject[storeName]) {
    const request = transaction.objectStore(storeName).add(toAdd)
    request.addEventListener('success', () => {
    count++
    if (count === importObject[storeName].length) {
    // Added all objects for this store
    delete importObject[storeName]
    if (Object.keys(importObject).length === 0) {
    // Added all object stores
    resolve()
    }
    }
    })
    }
    }
    })
    }

    /**
    * Clear a database
    *
    * @param {IDBDatabase} idbDatabase The database to delete all data from
    * @return {Promise<void>}
    */
    export function clearDatabase(idbDatabase) {
    const transaction = idbDatabase.transaction(
    idbDatabase.objectStoreNames,
    'readwrite'
    )
    transaction.addEventListener('error', reject)

    let count = 0
    for (const storeName of idbDatabase.objectStoreNames) {
    transaction
    .objectStore(storeName)
    .clear()
    .addEventListener('success', () => {
    count++
    if (count === idbDatabase.objectStoreNames.length) {
    // Cleared all object stores
    resolve()
    }
    })
    }
    }
    56 changes: 56 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,56 @@
    # Back up and restore an IndexedDB database

    This gist is an [ES module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) which provides functions to import and export data from an [IndexedDB](https://developer.mozilla.org/en-US/docs/IndexedDB) database as JSON. It's based on Justin Emery's [`indexeddb-export-import`](https://github.com/Polarisation/indexeddb-export-import) package, but applies some adjustments that reflect better on the current browser landscape (i.e. better developer ergonomics but no support for Internet Explorer).

    ## Usage
    For each of the provided functionalities, you need a connected [`IDBDatabase`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase) instance.

    ### Export Data
    ```js
    import { idb } from 'get-database-from-somewhere.js'

    import { exportToJson } from 'idb-backup-and-restore.js'

    exportToJson(idb)
    .then(result => {
    console.log('Exported JSON string:', result)
    })
    .catch(error => {
    console.error('Something went wrong during export:', error)
    })
    ```

    ### Import Data
    ```js
    import { idb } from 'get-database-from-somewhere.js'
    import { serializedData } from 'get-serialized-data-from-somewhere.js'

    import { importFromJson } from 'idb-backup-and-restore.js'

    importFromJson(idb, serializedData)
    .then(() => {
    console.log('Successfully imported data')
    })
    .catch(error => {
    console.error('Something went wrong during import:', error)
    })
    ```

    ### Clear Database
    Depending on your use case, it can be reasonable to clear a database before importing serialized data:

    ```js
    import { idb } from 'get-database-from-somewhere.js'
    import { serializedData } from 'get-serialized-data-from-somewhere.js'

    import { importFromJson, clearDatabase } from 'idb-backup-and-restore.js'

    clearDatabase(idb)
    .then(() => importFromJson(idb, serializedData))
    .then(() => {
    console.log('Successfully cleared database and imported data')
    })
    .catch(error => {
    console.error('Could not clear & import database:', error)
    })
    ```