Skip to content

blakewatson/datastore

Repository files navigation

DataStore

DataStore is a JavaScript module that makes it easy to save key value/pairs to IndexedDB with an API similar to localStorage.

IndexedDB is allowed more storage space than localStorage. It can also store more data types than strings. That means you can save structured data without having to convert it to JSON first. IndexedDB, unlike localStorage, isn’t blocking—all operations are asynchronous.

IndexedDB can do a lot more, but the reasons above are enough to use it even in relatively simple cases. This DataStore class is woefully underusing IndexedDB features. It merely replicates localStorage but by using IndexedDB behind the scenes for its advantages.

Install

If you are using npm, you can install DataStore with:

npm install @blakewatson/datastore

Or you can use the CDN version:

<script src="https://unpkg.com/@blakewatson/datastore@latest/dist/datastore.global.min.js"></script>

There exists both a module version (.esm) that exports the DataStore class as a default export, and a global version (.global) that places the DataStore class in your global scope. Both are available minified or not.

Browse dist files: https://unpkg.com/browse/@blakewatson/datastore/dist/

Usage

While DataStore aims to be as simple as localStorage, it does have one extra setup step: you must create an instance.

// if using npm
import DataStore from '@blakewatson/datastore';
// if using esm dist file
import DataStore from './path/to/datastore.esm.js';

const store = new DataStore();

If you want to use it just like localStorage, and you don't care about naming or versioning the database, then you can instantiate it with no parameters.

Retrieve data

Get data out of your store using getItem(key). Every operation on the store returns a promise. For this example, I will show both promise chaining and async/await. For further examples, I will show only async/await for brevity.

const store = new DataStore();

// with promise chaining
store.getItem('email').then((email) => console.log(email));

// with async/await
async function main() {
  const email = await store.getItem('email');
  console.log(email);
}

Add data

Add or overwrite data with setItem(key, value).

async function main() {
  await store.setItem('email', '[email protected]');
  // do something afterward
}

Unlike localStorage you can also save structured data:

async function main() {
  await store.setItem('[email protected]', { name: 'Jane Doe', age: 31 });
  // do something afterward
}

Remove data

You can remove an entry from your data store with removeItem(key).

async function main() {
  await store.removeItem('email');
  // do something afterward
}

Clear a data store

You can remove every entry in a data store with clear.

async function main() {
  await store.clear();
  // do something afterward
}

Get a list of keys

You can get back an array of all the keys in your data store with keys().

async function main() {
  const keys = await store.keys();
  console.log(keys);
  // Example: ['email', 'token', 'loginDate']
}

Get the number of entries

While localStorage gives you a length property that you can read from, DataStore provides you a count of all the entries in your store with the count() function.

async function main() {
  let num = await store.count();
  // Ex: 3

  // if you prefer the word "length," this method is identical
  num = await store.length();
  // still 3
}

Using a named database with one or more named stores

Unlike localStorage, IndexedDB has the concept of an object store and a database can have multiple object stores. This is handy for grouping data. You can name a database and specify one or more named stores by using this extra setup step.

Set up named database and stores

setupDb is a static method on the DataStore class that opens a database and creates any object stores that you specify. You can also provide a version number and an onUpgradeNeeded callback. That callback gives you an opportunity to do any database setup that you need to do after the object stores are created. You can omit this callback if all you want to do is create the object stores because that happens automatically.

The database name is required, but all of the other SetupDbOptions are optional.

DataStore.setupDb({
  name: 'My Database',
  version: 1, // default value
  // can be string or array of strings. default is 'data'.
  storesToCreate: ['users', 'posts'],
  onUpgradeNeeded: async (db, stores) => {
    // Perform any database operations you want to do.
    // `stores` represents a DataStore instance for each store you created.
  },
});

Get a named DataStore instance

If you use the setupDb method to create a named database and one or more named stores, then you must instantiate DataStore by specifying the database name and the store name you want to use.

// This isn't necessarily a smart way to structure posts and likes but
// is just an example of how to use multiple data stores on a database.

async function main() {
  // set up the database with 2 stores
  DataStore.setupDb({
    name: 'My Database',
    storesToCreate: ['data', 'metadata'],
  });

  // 'data' is the default object store name so we can omit it
  const store = new DataStore('My Database');
  // let’s say we’re using post id for the key.
  // number keys get turned into strings under the hood.
  const post = await store.getItem(1);

  // specify database name and object store name if not using default.
  const metaStore = new DataStore('My Database', 'metadata');
  const likes = await metaStore.getItem(1);

  return { post, likes };
}

Keys are strings

DataStore only supports strings as keys. That said, you can use numbers in getItem, setItem, and removeItem. Just be aware that they get converted to strings under the hood. The keys() method always returns an array of strings.

Upgrading

To upgrade a database, you can simply change the version number. With new storesToCreate in the list, they will get added.

// Original setup of the database with 2 stores
DataStore.setupDb({
  name: 'My Database',
  storesToCreate: ['data', 'metadata'],
});

// Adding a new store
DataStore.setupDb({
  name: 'My Database',
  storesToCreate: ['data', 'metadata', 'resumes'],
  version: 2,
});

About

Barebones IndexedDB implementation of localStorage APIs.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •