WWWDC で Safari 10 が発表されていました。その新機能の一つが IndexedDB サポートです。 IndexedDB は Web ブラウザでデータベースを扱える API で、本格的なオフラインアプリを作ろうとすれば必要になるはずです。

というわけで、そのラッパーである Dexie.js を使ってみます。

Hello, Dexie.js

早速作っていきます。まずは適当なデータを保存して取り出してみます。

// a.js

const db = new Dexie('app_db');

db.version(1).stores({
    records: '++id'
});

db.open();

new Dexie('app_db') でデータベースを作成しています。 app_db はデータベース名です。

db.version(1).stores({ ... }) はストアを定義しています。この例だと records という名前のストアを id というプロパティを主キーとして定義します。 ++ をつけるとオートインクリメントになります。

もしストアの定義を変更する場合は db.version(1) の記述を残したまま、 db.version(2) を定義します。

次にこれを読み込む HTML を用意します。

<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://npmcdn.com/dexie@latest/dist/dexie.js"></script>
<script src="a.js"></script>

Chrome でこの HTML を開き、 DevTool から API を触っていきます。

db.records
    .put({
        title: 'ABCDEF',
        date: new Date(),
        content: 'abcdef'
    })
    .then((id) => {
        console.log('record saved:', id);
    });

dv.records.put({ ... })records ストアにデータを保存できます。プロミスで id を返してきます。

これを実際に実行すると最初なので record saved: 1 と表示されるはずです。実際に IndexedDB に保存されているデータは Resources タブの中から触れます。

次にこの 1 という値から保存したデータ全体を取得してみます。

db.records
    .get(1)
    .then((record) => {
        console.log('record:', record);
    });

db.records.get(1) でプロミスでデータが返ってきます。

値の検索

値の更新は where() メソッドでできます。

db.records.where('id').equals(1).first().then((r) => { console.log(r); });

.where('id').equals(1) で条件を絞って、 first() で最初のデータを取得しています。

id は主キーなので特に何もせず検索できましたが、他の title などのプロパティで検索するにはインデックスを作成する必要があります。 IndexedDB なので。

// a.js の `db.version(1)...` の下に追記

db.version(2).stores({
    records: '++id,title'
});

version(2) を定義しています。 records の主キーのとなりにコンマ区切りで title を加えました。これで title プロパティのインデックスが作られます。

db.records.where('title').equals('ABCDEF').toArray().then((records) => { console.log(records); });

データを配列で受け取るには toArray() を使います。

値の更新

値の更新は update() メソッドです。

db.records.update(1, { title: 'GHIJKL' });

これで id1recordstitle"GHIJKL" に更新されます。

さいごに

IndexedDB のラッパーである Dexie.js を使ってみました。

IndexedDB は直接使うと API 的に結構辛いのでこういう層があると楽できるかもしれません。ドキュメント もきちんと書かれているみたいです。