2014年2月14日金曜日

[HTML5]IndexedDBでCRUDするサンプル

HTML5標準APIのIndexedDBでCRUDを理解するための簡単なChromeアプリです。


manifest.json
{
  "name": "IndexedDB example App",
  "description": "example app using the IndexedDB API.",
  "version": "0.1",
  "app": {
    "background": {
      "scripts": ["background.js"]
    }
  },
  "icons": { "128": "128.png" },
  "permissions": [
    "unlimitedStorage"
  ]
}

background.js
chrome.app.runtime.onLaunched.addListener(function() {
  chrome.app.window.create('main.html', {
    'bounds': {
      'width': 600,
      'height': 600
    }
  });
});

main.html
<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8'>
</head>
<body>
  1) open DB.<br>
  <button id="btn_open">Open</button>
  <hr>
  2) add data.<br>
  name:
  <input type="text" id="name"><br>
  email:
  <input type="text" id="email"><br>
  <button id="btn_add">Add</button>
  <hr>
  3) find by key(email).<br>
  email:
  <input type="text" id="key"><br>
  <button id="btn_find">Find</button>
  <hr>
  4) find all.<br>
  <button id="btn_findAll">FindAll</button>
  <hr>
  5) find by range. Range: "A" &lt;= name &lt; "C"<br>
  <button id="btn_findByRange">FindByRange</button>
  <hr>
  6) remove by key(email).<br>
  email:
  <input type="text" id="key4remove"><br>
  <button id="btn_remove">Remove</button>
  <hr>
  7) update by key(email). Updates name to UpperCase<br>
  email:
  <input type="text" id="key4update"><br>
  <button id="btn_update">Update</button>
  <hr>
  8) delete DB.<br>
  <button id="btn_deleteDB">Delete DB</button>
  <hr>
  <script src="main.js"></script>
</body>
</html>

main.js
var db = null;
var DBNAME = "people_db";
var DBVER = 1;

document.getElementById('btn_open').onclick = function (e) {
  openDB();
};
document.getElementById('btn_add').onclick = function (e) {
  var name = document.getElementById("name").value;
  var email = document.getElementById("email").value;
  add({ name: name, email: email});
};
document.getElementById('btn_find').onclick = function (e) {
  var key = document.getElementById('key').value;
  findByKey(key);
};
document.getElementById('btn_findAll').onclick = function (e) {
  findAll();
};
document.getElementById('btn_findByRange').onclick = function (e) {
  findByRange("A", "C");
};
document.getElementById('btn_remove').onclick = function (e) {
  var key = document.getElementById('key4remove').value;
  removeByKey(key);
};
document.getElementById('btn_update').onclick = function (e) {
  var key = document.getElementById('key4update').value;
  updateByKey(key);
};
document.getElementById('btn_deleteDB').onclick = function (e) {
  deleteDB(DBNAME);
};


// open a database
function openDB() {
  var request = indexedDB.open(DBNAME, DBVER);

  request.onupgradeneeded = function (e) {
    console.log("Upgrading...");
    var thisDB = e.target.result;
    var store = null;
    if (!thisDB.objectStoreNames.contains("people")) {
      // create objectStore as keyPath="email"
      store = thisDB.createObjectStore("people", {
        keyPath: "email"
      });
      //thisDB.createObjectStore("people", { autoIncrement: true });
      
      // create index to 'name' for conditional search
      store.createIndex('name', 'name', {
        unique: false
      });
      //store.deleteIndex('name');
    }
  };

  request.onsuccess = function (e) {
    console.log("openDB success!");
    db = e.target.result;
  };

  request.onerror = function (e) {
    console.log("openDB error");
  };
}

// add data
function add(o) {
  var tx = db.transaction(["people"], "readwrite");
  var store = tx.objectStore("people");

  // add 'created' param
  o.created = new Date();

  // add to store
  var request = store.add(o);

  request.onsuccess = function (e) {
    console.log("Add 'person' successful! person=" + JSON.stringify(o));
  };

  request.onerror = function (e) {
    console.log("Add error", e.target.error.name);
  };
}

// find by key(email)
function findByKey(key) {
  var tx = db.transaction(["people"], "readonly");
  var store = tx.objectStore("people");
  var request = store.get(key);

  request.onsuccess = function (e) {
    console.log(e.target.result);
  };
}

// find all
function findAll() {
  var tx = db.transaction(["people"], "readonly");
  var objectStore = tx.objectStore("people");
  var cursor = objectStore.openCursor();

  cursor.onsuccess = function (e) {
    var res = e.target.result;
    if (res) {
      console.log("key", res.key);
      console.log("value", res.value);
      res.continue ();
    }
  };
}

// find by range
function findByRange(from, to) {
  var tx = db.transaction(["people"], "readonly");
  var objectStore = tx.objectStore("people");
  // find by range. condition: from <= 'name' < to 
  var range = IDBKeyRange.bound(from, to, false, true);
  var cursor = objectStore.index('name').openCursor(range);

  cursor.onsuccess = function (e) {
    var res = e.target.result;
    if (res) {
      console.log("key", res.key);
      console.log("value", res.value);
      res.continue();
    }
  };
}

// remove by key(email)
function removeByKey(key) {
  var tx = db.transaction(["people"], "readwrite");
  var store = tx.objectStore("people");

  var request = store.delete(key);
  //var request = store.clear(); // delete all from the store

  request.onsuccess = function (e) {
    // calls even when nothing to remove.
    console.log("removeByKey success!");
  };

  request.onerror = function (e) {
    console.log("removeByKey error!");
  };
}

// update by key(email)
function updateByKey(key) {
  var tx = db.transaction(["people"], "readwrite");
  var store = tx.objectStore("people");

  store.get(key).onsuccess = function (e) {
    console.log("store.get", key);
    var data = e.target.result;
    if (!data) {
      console.log("nothing matched.");
      return;
    }
    // modify 'name' to upperCase
    data.name = data.name.toUpperCase();
    var request = store.put(data);

    request.onsuccess = function (e) {
      console.log("put success!");
    };

    request.onerror = function (e) {
      console.log("put error!");
    };
  };
}

// delete db
function deleteDB(dbname) {
  var request = indexedDB.deleteDatabase(dbname);

  request.onsuccess = function (e) {
    console.log("deleteDB success!");
  };

  request.onerror = function (e) {
    console.log("deleteDB error!");
  };
}

検索について
IDBKeyRangeを使った範囲検索が基本です。
検索対象となるカラムには必ずインデックスを張る必要があります。
正規表現などを使った複雑な条件検索については、現時点ではまだ実装されていないようですね。


IndexedDB用ライブラリ
IndexedDBの複雑な処理を単純化するためのUtilityというかWrapperのようなものを公開してみました。
niichrome-idbutil

0 件のコメント:

コメントを投稿