Lightweight promise-based wrapper for fast & simple access to IndexedDB API. With React integration βοΈ
To start using IDB.js
install it from npm
npm i @lr0pb/idb
Provide name
, version
and stores
to IDB constructor
import { IDB } from '@lr0pb/idb';
const db = new IDB('library', 1, [
{ name: 'books', index: { keyPath: 'id' } },
{ name: 'authors', index: { keyPath: 'name' } },
{ name: 'manufacturers', index: { autoIncrement: true } }
]);
stores
is an array of StoreDefinition
objects: name
of store and index
object, which described how should be indexed data inside the store. This is a IDBObjectStoreParameters
object, which is a part of original IndexedDB API
You can also provide optional fourth argument options
described in new IDB
You can add or delete stores from database by called IDB constructor with upgraded version
and relevant changes in stores
array
-const db = new IDB('library', 1, [
+const db = new IDB('library', 2, [
{ name: 'books', index: { keyPath: 'id' } },
{ name: 'authors', index: { keyPath: 'name' } },
- { name: 'manufacturers', index: { autoIncrement: true } }
+ { name: 'visitors', index: { keyPath: 'id' } }
]);
// 'manufacturers' store will be deleted and cannot be longer accessed
// 'visitors' store instead will be created in database
You can delete and add as much stores in a single database update as you want
Operate with data:
Other helpful methods:
IDB come out-of-the-box with types declaration.
While using IDB in TS project, every data related method (exludes deleteAll
) have a type parameters, where T
stands for Type
of data you operate and K
stands for Key
to access this data in the store.
You can learn detailed types annotation for the concrete method by clicking [Ref]
link in the method description within this Readme or you can explore all types stuff on docs site
[Ref] Add item to the store via db.set(store, item | items[])
method
await db.set('authors', {
name: 'Agatha Christie',
books: [...]
});
await db.set('authors', [
author1, author2, ...
]);
[Ref] Get one or more items by keys with db.get(store, key | keys[])
method
const author = await db.get('author', 'Agatha Christie');
// {
// name: 'Agatha Christie',
// books: [12345, 67890, ...],
// ...
// }
const authorsBooks = await db.get('books', author.books);
// [
// {
// id: 12345,
// title: `Hercule Poirot's Christmas`,
// ...
// },
// {
// id: 67890,
// title: `Murder on the Orient Express`,
// ...
// },
// ...
// ]
[Ref] Read all items in the store with db.getAll(store, DataReceivingCallback?)
method
const books = await db.getAll('books');
books.forEach((book) => {
renderBook(book);
});
Additionally, you can set DataReceivingCallback
that will be called every time new item receives from the database
await db.getAll('books', (book) => {
renderBook(book);
});
DataReceivingCallback
function must be sync
[Ref] Use db.update(store, key | keys[], UpdateCallback)
to easier updating items in the store. It is actually simple wrapper for get
and set
methods
async function addBookToAuthor(book) {
await db.update('authors', book.author, async (author) => {
// this callback function receives item object, to update it,
// you should apply changes directly to this object
author.books.push(book.id);
await sendAnalytics();
});
}
UpdateCallback
function can be async If you provide multiple keys,UpdateCallback
will be called for each received item. If you want to use separateUpdateCallback
functions for each item, provide array ofUpdateCallback
functions same length askeys
array length
[Ref] Delete one or more items by keys with db.delete(store, key | keys[])
method and clear all store entries with db.deleteAll(store)
method [Ref]
await db.delete('books', 12345);
await db.delete('books', [
67890, 34567, ...
]);
await db.deleteAll('author');
// `authors` store is still available but have zero items
[Ref] Check if store have certain items via db.has(store, key | keys[] | void)
or get amount of all items in the store by not passing key
argument
const book = {
id: 12345,
title: `Hercule Poirot's Christmas`,
...
};
await db.set('books', book);
const isBookSaved = await db.has('books', book.id); // true
const booksCount = await db.has('books'); // 1
[Ref] You can register multiple listeners to spot changes that happened in the store with db.onDataUpdate(store, StoreUpdatesListener)
method. These callbacks will be called after actual operation with data in order to time they are registered
To unregister callback, call returned from db.onDataUpdate
UnregisterListener
function
const unregister = await db.onDataUpdate('books', async ({store, type, item}) => {
// `item` argument not presented when it was a deleting operation
if (type === 'set' && isNewBook(item)) {
await notifyUserAboutNewBookAdded(item);
}
});
...
unregister();
StoreUpdatesListener
function can be async
View whole detailed API documentation with all the types and overloads on docs site
- 2.1.0 Explicitly throw errors when something goes wrong in IDB methods call
View all changes during versions in CHANGELOG
As this project initially was a data layer part of my another project, I maintain it preferably for those project, but any issues and pull requests are welcome!
For start to develop IDB: clone this repo on your machine and run npm i
Write your code and create tests for it in test
directory. Each .test.js
file should be structered as shown below:
import { assert } from 'chai/index.mjs';
export default function (container, checkStore) {
it('test', ...);
...
}
Every call to IDB should be accessed through container.db
variable. checkStore(store, count)
is helper function to check amount of items in store.
After new test file created, it should be imported inside test/__index__.test.js
file and passed to tests
object to automatically run with other tests. To disable some test suite - comment its desclaration within tests
object.
Run tests via npm test
- it will start a development server and open default browser window with tests page