Consistent API to IndexedDB
Treo is a lightweight wrapper around IndexedDB to make browser storage more enjoyable to use. Think about it as jQuery for IndexedDB. It does not add new abstractions, but simplifies the API and increases code reliability.
I spent a lot of time reading the official specification and understanding its nuances. With treo I want to save this time for other developers, and help to focus on real problems and making the web better, instead of fighting with the complex IndexedDB API and stumbling on simple tasks.
IndexedDB is powerful technology with support of indexes, stores, transactions and cursors. It allows us to build any kind of client databases. And let's be clear, it's the only real option to store data in browser, because localStorage is synchronous and WebSQL is deprecated.
versionchageevent automatically, to safely close and reopen database connection
Let's rewrite the official w3c example with treo:
var treo = require('treo'); // or window.treo// define db schema var schema = treo.schema() .version(1) .addStore('books', { key: 'isbn' }) .addIndex('byTitle', 'title', { unique: true }) .addIndex('byAuthor', 'author') .version(2) .getStore('books') .addIndex('byYear', 'year') .version(3) .addStore('magazines') .addIndex('byPublisher', 'publisher') .addIndex('byFrequency', 'frequency');
// open db var db = treo('library', schema); db.version; // 3
// put some data in one transaction var books = db.store('books'); books.batch([ { isbn: 123456, title: 'Quarry Memories', author: 'Fred', year: 2012 }, { isbn: 234567, title: 'Water Buffaloes', author: 'Fred', year: 2012 }, { isbn: 345678, title: 'Bedrock Nights', author: 'Barney', year: 2013 }, ], function(err) { // Before this point, all actions were synchronous, and you don't need to wait // for db.open, initialize onupgradeneeded event, create readwrite transaction, // and handle all possible errors, blocks, aborts. // If any error happen on one of this steps, you get it as
err
. });// get a single book by title using an index books.index('byTitle').get('Bedrock Nights', function(err, book) {});
// get all books filtered by author books.index('byAuthor').get('Fred', function(err, all) {}); // all.length == 2
For more examples check out /examples:
$ npm install treo --save $ bower install treo $ component install treojs/treo
Standalone build available as dist/treo.js.
IndexedDB does not support ES6-Promises, but treo enables it with treo-promise plugin.
var promise = require('treo/plugins/treo-promise'); // or window.treoPromise var db = treo('library', schema) .use(promise());var books = db.store('books');
Promise.all([ books.get('123456'), books.get('234567'), books.get('345678'), ]).then(function(records) { console.log(records); // records.length == 3
books.count().then(function(count) { console.log(count); // total count of records }); });
IndexedDB is available only in modern browsers, but we still need to support Safari <= 7 and legacy mobile browsers. Treo ships with treo-websql plugin, which enables fallback to WebSQL and fix all issues of buggy IndexedDBShim. In fact all treo's tests pass even in phantomjs environment.
Usage:
var websql = require('treo/plugins/treo-websql'); // or window.treoWebsql var db = treo('library', schema) .use(websql());
To initialize a new
dbinstance, create a
schemaand pass it to main function.
// define schema with one storage var schema = treo.schema() .version(1) .addStore('storage');// create db var db = treo('key-value-storage', schema); db.store('storage') .put('foo', 'value 1', fn); // connect, create db, put value
Treo uses
treo.schema()to setup internal objects like stores and indexes for right away access. Also, based on schema, treo generates
onupgradeneededcallback.
Change current version.
Declare store with
name. Available options: *
key- setup keyPath for easy work with objects [default false] *
increment- generate incremental key automatically [default false]
Declare index with
nameto one specific
field. It can be called after store declaration or use
schema.getStore(name)to change current store. Available options: *
unique- index is unique [default false] *
multi- declare multi index for array type field [dafault false]
Change current store.
Delete store by
name.
Delete index by
namefrom current store.
It's an interface to manage db connections, create transactions and get access to stores, where real work happen.
Use plugin
fn(db, treo), it calls with
dbinstance and
treoobject, so you don't need to require treo as dependencies.
Get store by
name. See Store API for more information.
Close db connection. Callback is optional when
db.status == 'open'.
Close connection and drop database.
Store is the primary storage mechanism for storing data. Think about it as table in SQL database.
Get value by
key.
Put
valto
key. Put means create or replace. If it's an object store with key property, you pass the whole object.
fncallback returns error and key of new value.
var schema = treo.schema() .version(1) .addStore('books', { key: 'isbn' });var db = treo('key-value-storage', schema); db.get('books').put({ isbn: 123456, title: 'Quarry Memories', author: 'Fred' }, fn); // key is isbn field and equal 123456
Delete value by
key.
Create/update/remove objects in one transaction.
optscan be an object or an array (when key option is specified).
var db = treo('key-value-storage', schema); var storage = db.store('storage');storage.put('key1', 'value 1', fn); storage.put('key2', 'value 2', fn);
storage.batch({ key1: 'update value', key2: null, // delete value key3: 'new value', }, fn);
Count records in store.
Get all records.
Clear store.
Get index by
name.
Index is a way to filter your data.
Get values by
key. When index is unique it returns only one value.
keycan be string, range, or IDBKeyRange object.
books.index('byTitle').get('Bedrock Nights', fn); // get unique value books.index('byAuthor').get('Fred', fn); // get array of matching values books.index('byYear').get({ gte: 2012 }); books.index('byAuthor', IDBKeyRange.only('Barney'));
Count records by
key, similar to get, but returns number.
Connect to db and create defined stores. It's useful, when you need to handle edge cases related with using origin database object.
Create new transaction to list of stores. Available types:
readonlyand
readwrite.
Create custom cursors, see example and article for more detailed usage.
Treo exposes core objects for plugins extension.
Compare 2 values using indexeddb's internal key compassion algorithm.
MIT