IDB reference

Basic IDB objects

Database manipulation

Stores

Indices

Object manipulation functions

Object query functions

Basic IDB Objects

IDB.sentinel(function handler)

Params

handler a function called on unexpected database events. It receives object parameter describing the error. Default handler is console.error, which is in action until redefined. IDB functions returning Promise don't reject unless the sentinel throws - in that case, the error can be caught immediately in .catch() Promise chain method.

Parameter object

The handler parametr object has these properties:

source name of the IDB function that caused the issue

message the issue message

params the parameter values to the IDB function

Promise IDB.promise(IDBRequest request)

Promise resolve

Resolves on req.onsuccess with value req.result

Promise reject

Rejects on req.onerror with value req.error

Examples

IDB.promise(indexedDB.open("IDB")) // Promise from IDBOpenDBRequest .then(db => db.transaction("users")) // create transaction from the db .then(tx => tx.objectStore("users")) // get store from the transaction .then(s => s.index("name")) // get index from the store .then(i =>IDB.promise(i.get("John"))) // Promise from request for the key value .then(console.log)

logs object from store users with index name=John


const teenagers = IDB.range("gte", 13, "lt", 20); IDB.store("users") // returns Promise .then(st => st.index("age")) // returns directly .then(i => IDB.promise(i.getAll(teenagers))) // returns IDBRequest .then(console.log); });

logs teenagers from users store

Promise IDB.version()

Promise resolve

unsigned int current version of IDB database. If it is not created, random number 1 to 10e7 is picked as initial version (so the age of the page/database can not be guessed by clients)

Promise IDB.dbPromise

Methods creating or dropping stores or indices can be run only during onupgradeneeded event soon after the database is opened. When they are called, the database needs to be closed and reopened. During the closing the database waits for running transactions to finish and doesn't accept new ones. Reopening is also made in separate thread and is not instantious. dbPromise avoids this gap when IDBRequest would cause error.

Promise resolve

safe IDBDatabase object with with opened connection to IDB database

Example

IDB.dbPromise.then(db => db.objectStoreNames).then(console.log);

List all available databases (including versions)

IDBDatabase IDB.db

Returned object may be null during the database opening period or unusable during the closing period when database manipulation functions are called. If such events don't happen (like clicking the button to retrieve some storage data) it is more or less safe to call the db object directly to simplify the code. (Keep in mind the IDB database can be changed in another browser tab in the same domain and the browser or OS may decide to close the connection for various reasons.)

Example

<button onclick="console.log(IDB.db.objectStoreNames)">Databases</button>

List all available databases (including versions)

Promise|IDBTransaction IDB.transaction([bool promise,] string|array stores[, bool w])

Params

promise if true is provided as the first argument, Promise to IDBTransaction is returned. This can be skipped if the unsafe phase does not occur diring the call in which case the object is returned directly. Optional, default false.

stores can be a string (single store) or string[] (multiple stores) involved in the transaction. Multiple stores allows to revert the data changes in the middle of the writing process simply by calling abort() on the transaction.

w truthy value means transaction with writing priviledges, otherwise it is read-only (multiple read-only transaction may access the same store simultaneously)

Example

function createAccounts() { IDaccounts.innerHTML = ""; var tx = IDB.transaction(["users","accounts"], true); IDB.cursor(tx, "users").then(IDB.walk(createUserAccount)); } function createUserAccount(rec, pk, tx) { const acc = val => ({userId: pk, credit: val}); if(rec.name=="Kyle") IDB.insert(tx, "accounts", acc(200)); }

Create account with 200 credits for every user named Kyle

Promise|IDBObjectStore IDB.store([bool promise,] string store[, bool w])

Params

promise see transaction

store the store name on which a single-store transaction is opened

w see transaction

Example

const getUser = id => IDB.promise(IDB.store("users").get(id)); const showUser = async id => output.innerHTML = await getUser(id); <button onclick="showUser(23)">Show 23</button> <output id="output"></output>

place user with id=23 into output element

Promise|IDBIndex IDB.index([bool promise,] string store, string name)

Params

promise see transaction

store the store name on which the index is defined

name the name of the index which should be returned

Example

IDB.promise(IDB.index("users","age").getAll("gte",13,"lt",20)).then(console.log)

log all teenagers from users store

IDBKeyRange IDB.range("eq", value1)

IDBKeyRange IDB.range("lt"|"lte", value1)

IDBKeyRange IDB.range("gt"|"gte", value1[, "lt"|"lte", value2])

Notes

Creates a IDBKeyRange object in a way common in XSL or bash habits, not the weird way the ad-hoc standard defines. This object is created internally in IDB.cursor and IDB.delete functions and (together with IDB.store) provides tools to work directly with IndexedDB.

Params

functors identifiers are: eq (equals), lt (lower than), lte (lower than or equal), gt (greater than), gte (greater than or equal)

value1, value2 second parameter to the above function (the first one is the key of the object).

Example

const teenagers = IDB.range("gte", 13, "lt", 20);

Creates a functor that (applied on age index) selects all teenagers from storage (sorted by age). See the full example below.

Database manipulation

Promise IDB.upgrade()

Upgrades (closes and reopens) the database with incremented version number without doing any change in the structure.

Promise resolve

undefined, IDB.db is safe after the operation

Promise|DOMStringList IDB.stores([bool promise])

Params

promise see transaction

Example

IDB.sentinel = function() { throw arguments; } IDB.stores(true).then(console.log).catch(_=>console.error("IDB is blocked"));

Log all stores in IDB and handle the blocked state

Promise IDB.storeCreate(string name[, string[] indices[, bool force]])

Params

name The name of the store to create

indices Names of the stored objects attributes to be used as indices (index name is the same as attribute name in IDB). Indices allows to sort and filter records from store. First index serves as primary key, which is unique. Each index (and primary key) can be array of strings itself (compound index) which can filter records in OR logic. If the store should not have unique key, null can be set as the first key which creates autoincrement generator. Optional, default [null].

force true if the store already exists, it is dropped and re-created. false if the store already exists, do nothing. Optional, default false.

Promise resolve

true if the store was created, false if not

Promise reject

string the store name which could not be created, when force is set to true (likely due to HW problem or resources locked).

Examples

IDB.storeCreate("users1", ["id", "name"]); // store users1 with id as primary key and name as index IDB.storeCreate("users2", [null, ["name", "surname"]]); // without primary key, with compound index IDB.storeCreate("log").then( result => result && console.log("Log created") ); // store log without keys with action after successfull creation

Notes

MultiEntry or unique indices can be created only with IDB.createIndex(). If not called during the upgrade phase, this method closes and reopens the database.

Promise IDB.storeDelete(string name)

Params

name The name of the store to delete

Promise resolve

true if store existed and has been deleted, false otherwise

Promise reject

string the store name which could not be deleted, when force is set to true (likely due to HW problem or resources locked).

Example

var stack = []; stack.push(IDB.storeDelete("users1")); stack.push(IDB.storeDelete("users2")); stack.push(IDB.storeDelete("log")); Promise.all(stack).then(_=> console.log("All stores were deleted"));

The deletion requests are run in 3 separate concurrent threads.

Notes

Also deletes all keys in the object store. If not called during the upgrade phase, this method closes and reopens the database.

Promise IDB.indices([bool promise,] string storage)

Params

promise see transaction

storage the storage name to get the indices from

Example

IDB.indices(true,"users").then(console.log);

Promise IDB.indexCreate(string store, string|array index[, object params])

Params

store store where the index should be created

index the key of the index; can be string[] to create compound index. In that case, the name is created by joining the array items with underscore separator (i.e. ["name","age"] leads to name_age index name.

params object with keys unique, multiEntry or locale, described here. Default non-unique, single-entry, without locale.

Promise resolve

IDBIndex, the newly created index

Promise reject

[store,index,params] the store on which the index with provided params could not be created.

Example

// simple index IDB.indexCreate("users", "age"); // multiEntry index IDB.indexCreate("users", "titles", {multiEntry: true}); // compound index IDB.indexCreate("users", ["width", "height"]);

Notes

Don't confuse compound and multiEntry index. Compound indices are usually single-entry. MultiEntry indices are usually not unique. If not called during the upgrade phase, this method closes and reopens the database.

Promise IDB.indexDelete(string store, string|array index)

Params

store store to delete the index from

index name of the index to delete (array only for compound index, string is also accepted)

Promise resolve

bool, true if the index existed and was deleted, false otherwise

Promise reject

[store,index] the store on which the index could not be deleted.

Example

IDB.indexDelete("users", "width_height");

Notes

If not called during the upgrade phase, this method closes and reopens the database.

Object manipulation functions

Promise IDB.insert(string name, object data[, keyPath])

Params

name name of the store where the data goes

data can be object or array of objects - in that case all the array items are added as records one by one in the order in the array.

keyPath the unique key path, if the store was created without keys (see out-of-line keys). If the object store was created by IDB.storeCreate function with first key set to null, it is autoincrement out-of-line key. Optional, do not use with inline keys.

Promise resolve

int the number of records inserted, resolves only if all the records were inserted successfully.

Promise reject

[name,data,keyPath,fn] the parameters that caused the insert fail. Data can be array (if the whole insert failed, i.e. non-existent store) or a single record (i.e. its keyPath already exists in the store). fn is "add"; the same underlying function is used for IDB.upsert, where fn is "put".

Example

const now = new Date.toLocaleString(); IDB.insert("log", [ {date: now, "script started"}, {date: now, {status: "OK"}, append: false} ]) .then(_=> console.log("OK")).catch(n => console.error(`Insert failed after ${n} records`) .then(_=> IDB.insert("log", {date: now, "script finished"}));

Notes

Records are structural clones of the original objects, which is functionally equivalent to serialized and then deserialized original object (references are transformed to values). If inline keyPath was specified on the object store, keyPath parameter must not be used.

Promise IDB.upsert(string name, object data[, keyPath])

This function acts like IDB.insert when the record with the same primary key (or keyPath) doesn't exist in the store. When it does, IDB.insert rejects, while IDB.update updates existing record.

IDB.update(string name[, string index[, IDBKeyRange range]], function updator)

Params

name name of the store where to update the records

index name of the index for the range constraints. Optional.

range Only records that match the index and the range will be passed to updator. Can boost the performance if updator is slow. Optional, take all available records to updator by default.

updator Takes the record as the parameter. To update it in the store, it must return non-falsy value, otherwise the record is not updated.

Promise resolve

int, the number of affected records

Promise reject

[name,index,range,fn] the params that caused the update to fail. fn is "update". Same underlying function is used for IDB.delete, where the fn is "delete".

Example

IDB.update("users", o=>o.age++).then(console.log);

Raise the age of all users by 1 and log the number of affected users.

Notes

If index is used, its value must not be updated in updator, otherwise deadlock may happen.

IDB.delete(string name[, string index[, IDBKeyRange range]], function deletor)

Act similarly like the IDB.update above, the only difference is the last parameter, deletor function.

Params

deletor Takes the record as the parameter. If it returns truthy value, the record is deleted from the store.

Promise IDB.deleteOne(string store, pk)

Params

store store name to delete the record from

pk the primary key value

Promise resolve

undefined

Promise reject

[store, pk] the params that caused the delete to fail.

Notes

Deletes a single record based on the primary key value, which is safe as far as you can guarantee the PK value is not compromised. IDB.update and IDB.delete can destroy a lot of data and should be therefore called with special care.

Promise IDB.clear(string name)

Params

name name of the store to delete all records from

Promise resolve

undefined

Promise reject

string the name of the store that failed to clear

Notes

This function was intentionally separated from IDB.delete to avoid deleting all records by mistake.

Object query functions

Promise IDB.count(string store[, string index])

Params

store The name of the store to count the records from.

index Optional. If provided, the count is limited to records in the index.

Promise resolve

int the number of the records in the object

Example

IDB.count("log").then(console.log); // logs to console the number of records in the log store

Promise IDB.record(string name, pk)

Params

name the name of the store to retrieve a record from

pk the value of the primary key of the requested record; type must also match

Promise resolve

The object with the specified primary key (if found), undefined if not found

Example

// reset, next, prev buttons to browse users store with log to console id = 0; reset.onclick = _ => id = 0; next.onclick = _ => IDB.record("users",++id).then(console.log); prev.onclick = async function(id) { var user = await IDB.record("users",--id); console.log(user); }

Promise IDB.cursor([IDBTransaction tx,] string name
[, string index[, IDBKeyRange range][, string dir]])

Params

tx transaction on which the cursor is defined. If ommited, it is created as single-store read-only transaction from the name parameter.

name name of the storage to sort or filter.

index index to use for sorting or filtering. Optional, if falsy it sorts the store by primary key (default).

range see IDB.range. Optional, falsy values means no filtering.

dir next, nextunique (ASC), prev, prevunique (DESC). Optional, default next.

Promise resolve

IDBRequest that resolves in IDBCursor in read-only transaction (so the request.onsuccess event can be handled).

Example

function walk(req) { req.onsuccess = e => { let cursor = e.target.result; if(cursor) { console.log(c.value); cursor.continue(); } } } IDB.cursor("users",null,"prev").then(walk);

log all users one by one to console, last inserted first

Notes

IDBCursor calls its onsuccess method for each record found. This method creates cursor in read-only transaction. But IDBCursor has also update method: this is utilized in IDB.update function, while read only scenarios can be mostly solved with IDB.walk and IDB.filter below. These functions are to be called in IDB.cursor().then(). Their only parameter is a function, that gets called for every record the cursor yields.

The following functions get these parameters:

record structural clone of the record as their only parameter

pk primary key value

tx the transaction of the cursor (meaningful on for write transactions)

IDB.walk

The return value of the parameter function is ignored, it is meant just to traverse all the records.

IDB.cursor("users",null,"prev").then(IDB.walk(console.log));

log all users one by one to console, last inserted first

IDB.filter

The parameter function should return truthy value iff the record shall pass the filter. The IDB.filter function itself then returns array of filtered data (in Promise) for further processing.

var myFilter = o => o.name.includes("an"); IDB.cursor("users","name").then(IDB.filter(myFilter)).then(console.log);

log all users, sorted by name and having "an" in their name