IndexedDBにはまってます。(その7)

はじめに、try文の挿入について断り書きします。

はまってシリーズ」で紹介する内容が少し複雑になってきました。これ以上複雑になる前に、try文による例外の処理について確認しておきます。

indexedDB(indexed DataBase)のAPI利用にあっては、操作階層を潜る都度に複数のメソッドを利用することになります。いままではイベント発火を受けた処理ばかりを紹介してきましたが、初っ端のopen()メソッドからして条件によってなんやかやと例外も返してきます。ちゃん?とした処理を望むのであれば、これらもフォローしなくてはなりません。

でも操作階層を潜る度にtry文を仕込んでいくのは煩雑ですし、何より端末機のメモリやパフォーマンスを蝕む?ことになると聞いてます。もったいない根性の旺盛な私は、try文の記述をできるだけ避け、せめて二階層分までに留めたいと希望します。

よって、プログラミングによる運用で回避できないと考えられる例外だけを対応してまいります。疑問に思うこともあるやもしれませんが、私の理解の範疇による最小限度の記述であることをご了解ください。あとあと変更するやもしれません。

改めまして主題にかかります。

IndexedDBにはまってます。(その6)では、プライマリキー(主キー)によるレコードの格納と削除を紹介しました。

今回は、プライマリキー(主キー)の指定がシンプル(単一キーワード)なうちに、まずはキージェネレータをオンにした場合の挙動を紹介します。オフの場合は後回しにします。

つぎのコードをWebブラウザ(Google Chromeを利用)のコンソールにコピー&ペーストし、エンターキーで実行して、まずはオブジェクトストアStore_nameを生成します。

const openRequest = indexedDB.open('DB_name');
openRequest.addEventListener('upgradeneeded', (event) => {
	const db = event.target.result;
	//const tx = event.target.transaction;
	console.log(`UPGRADE_DB_VER_>${db.version}_OLD_>${event.oldVersion}_NEW_>${event.newVersion}`);
	const Store_option = {keyPath:'member', autoIncrement:true};

	try {

		//他のオブジェクトストア操作の差し替え箇所
		const objectStore = db.createObjectStore('Store_name', Store_option);
		objectStore.transaction.addEventListener('complete', (event)=>{
			if(event.target.objectStoreNames.contains('Store_name')) {
				console.log(`オブジェクトストアを生成しました。`);
			}
		}, false);
		objectStore.transaction.addEventListener('abort', (event)=>{console.error(`トランザクションが中断しました。`);}, false);
		objectStore.transaction.addEventListener('error', (event)=>{console.error(`トランザクションでエラーが発生しました。`);}, false);

	} catch(exception) {
		console.error(`例外が発生しました。_>${exception.message}`);
	}

}, false);
openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開始しました。`);
	//db.close();
	db.addEventListener('close', ()=>{console.log(`データベースが閉鎖されました。`);}, false);
}, false);
openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始に失敗しました。`);}, false);
コードを実行したコンソール画面

ここのtry文に触れておきます。db.createObjectStore()メソッドの例外は、すでに同じ名前のオブジェクトストアがあったり、keyPathが空なのにautoIncrementが真(true)であったりすると発生します。詳しくはcreateObjectStore()メソッドの案内で確認してください。

また、データベース閉鎖のclose()メソッドですが、他のブラウザでもイベント発火を受け取れないことを確認しましたのでコメントアウトして記載しておきます。

ここでまた余計な一行になりますが、今後の対応に期待して受け取り処理枠を記述しておきます。間違っていないと思います。いつか「データベースの開始に失敗しました。」という文字列がコンソールに現れるのを期待します。

アプリケーション画面でオブジェクトストアStore_nameの生成を確認してください。

生成されたオブジェクトストアStore_name

データレコード(以後レコード)を格納していきます。

キージェネレータがオン設定ですから、つぎのようにプライマリキー(主キー)’member’を記述しないで格納します。

const storeRequest = objectStore.add({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn'});
const openRequest = indexedDB.open('DB_name');
openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開始しました。`);
	if(db.objectStoreNames.contains('Store_name')) {
		const tx = db.transaction('Store_name', 'readwrite');
		tx.addEventListener('complete', (event)=>{console.log(`トランザクションが完遂しました。`);}, false);
		tx.addEventListener('error', (event)=>{console.error(`トランザクションでエラーが発生しました。`);}, false);
		tx.addEventListener('abort', (event)=>{console.error(`トランザクションが中断しました。`);}, false);
		const objectStore = tx.objectStore('Store_name');

		try {

			//他のレコード操作の差し替え箇所
			const storeRequest = objectStore.add({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn'});

			storeRequest.addEventListener('success', (event)=>{console.log(`レコードの書き込みに成功しました。`);}, false);	
			storeRequest.addEventListener('error', (event)=>{console.error(`レコードの書き込みに失敗しました。`);}, false);

		} catch(exception) {
			console.error(`例外が発生しました。_>${exception.message}`);
		}
		
	} else console.error(`目的のオブジェクトストアはありませんでした。`);
	//db.close();
	db.addEventListener('close', ()=>{console.log(`データベースが閉鎖されました。`);}, false);
}, false);
openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始に失敗しました。`);}, false);
コードを実行したコンソール画面
レコードが登録された画面

キージェネレータがオンの場合は勝手にプライマリキー(主キー)に値(整数)を入れてくれます。add()される度にmemberの値が生成されますから、memberの値に重複はありえません。

たとえ、memberに値を割り当てても必ず一意の値が保証されます。

さらに続けて、同じレコードを何度でも加えていくことができます。

(キーボードの上矢印カーソルキーを押すと、直前に実行したコードが現れます。ご存知かと思いますが、老婆心まで。)

同じレコードが複数登録された画面

put()メソッドでも同じことです。試しにaddをputに変更して実行してみてください。

const storeRequest = objectStore.put({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn'});
コードを実行したコンソール画面
put()でもレコードが追加された画面

同じレコードばかりが格納されましたね。

では、clear()メソッドを使って、一度すっきりさせましょう。

操作手続きはput()やadd()のと同じです。put()やadd()の行をclear()の行に差し替えるだけです。これもオブジェクトストアの操作になるので、トランザクションはreadwriteモードです。

const storeRequest = objectStore.clear();

つぎのコードをWebブラウザのコンソールにコピー&ペーストし、エンターキーで実行します。

const openRequest = indexedDB.open('DB_name');
openRequest.addEventListener('success', (event)=>{
	const db = event.target.result;
	console.log(`データベースを開始しました。`);
	if(db.objectStoreNames.contains('Store_name')) {
		const tx = db.transaction('Store_name', 'readwrite');
		tx.addEventListener('complete', (event)=>{console.log(`トランザクションが完遂しました。`);}, false);
		tx.addEventListener('error', (event)=>{console.error(`トランザクションでエラーが発生しました。`);}, false);
		tx.addEventListener('abort', (event)=>{console.error(`トランザクションが中断しました。`);}, false);
		const objectStore = tx.objectStore('Store_name');

		try {

			//他のレコード操作の差し替え箇所
			const storeRequest = objectStore.clear();
			
			storeRequest.addEventListener('success', (event)=>{console.log(`レコードの一掃に成功しました。`);}, false);	
			storeRequest.addEventListener('error', (event)=>{console.error(`レコードの一掃に失敗しました。`);}, false);

		} catch(exception) {
			console.error(`例外が発生しました。_>${exception.message}`);
		}
		
	} else console.error(`目的のオブジェクトストアはありませんでした。`);
	//db.close();
	db.addEventListener('close', ()=>{console.log(`データベースが閉鎖されました。`);}, false);
}, false);
openRequest.addEventListener('error', (event)=>{console.error(`データベースの開始に失敗しました。`);}, false);
コードを実行したコンソール画面
一掃されたオブジェクトストアStore_name

スッキリしましたね。それではもう一度レコードをadd()メソッドで追加してみましょう。

レコードを再登録した画面

あれ?空っぽのオブジェクトストアにレコードを登録したのにプライマリキー(主キー)’member’の値が1ではありません。キージェネレータがオンになっている既存のオブジェクトストアでは、一掃しても以前のカウントが生きているようです。

でも、レコードにmember:1と指定してレコード登録をすれば、put()メソッドはもちろん、add()メソッドでも登録が可能です。

const storeRequest = objectStore.add({index:{en:1, sn:'SN0003'}, date:Date.now(), title:'ZINC', author:'hustlemouse', tag:['red','blue','yellow'], note:'Zn', member:1});
member:1でレコードを登録した画面

また、たとえば一つ飛ばしてmember:7と入れて、つぎにmemberを指定しないでレコードを格納するとmemberの値が8になったり…と、キージェネレータがオンならではの挙動は他にもある様子です。(いろいろあって全てを確認できてませんで申し訳ない。)

とりあえず、ここでは基本的な動作を紹介しました。

次回はキージェネレータをオフにした操作を紹介します。

データベースでは、バックアップしたレコードを再利用したりすることが多いと想定できるのでオフが主流になるように感じます。でも、もしくは一意であることをキージェネレータに丸投げしておいた方がいいのだろうか?

長くなりました。先々のデータベース設計までの道程を思うと頭がクラクラしてきます。そかさ。