IndexedDBにはまってます。(その15)で少し触れた最新版?ラングオブジェクトを生成するメソッドの紹介をします。
IndexedDBのカーソルの紹介を続けて、ラングオブジェクト生成メソッドの変更については以前のバージョンのままやり過ごし、インデックスの紹介の時にでも先送りにしようとしてました。
ところがどっこい、カーソルのupdateメソッドの紹介を検討していたら、とうしてもindexedDB.cmpメソッドを使う必要になりまして…。それなら、cmpメソッドの紹介がてら新しい生成メソッドを先にお披露目しようとなりました。
自信のほどは怪しいのですが、いまのところ、ちゃんと動作してくれています。
確認(保険)まで、このメソッドは私のオリジナルであって、はっきり言って独り善がりな代物です。賢明なる諸兄には参考程度に思っていただけますことお願いします。
つぎのコードがメソッドの全体になります。いつものようにWebブラウザ(Google Chromeを利用)のコンソールにコピー&ペーストし、エンターキーで登録できます。
newRange = function({start, end}) {
let r = null;
console.log(`ラング作ります_>>_はじめ_>${start.v}_${start.b}_おわり_>${end.v}_${end.b}`);
//対象キーの値(start.vとend.v)が存在しない、もしくは連想配列(オブジェクト)であった場合は、付随する開閉値も併せてnullとする。
if(typeof(start.v)==='undefined') [start.v,start.b] = [null,null];
else if(!Array.isArray(start.v)) {
if(typeof(start.v)==='object') [start.v,start.b] = [null,null];
}
if(typeof(end.v)==='undefined') [end.v,end.b] = [null,null];
else if(!Array.isArray(end.v)) {
if(typeof(end.v)==='object') [end.v,end.b] = [null,null];
}
//開閉の真偽値(start.bとend.b)がそれぞれ有効であるかどうかを真偽の配列にしてflagに代入する。
const flag = {s:typeof(start.b)==='boolean', e:typeof(end.b)==='boolean'};
if(flag.s && flag.e) {
//始端と終端の双方の開閉真偽値が有効である。
let cmp = null;
try {
cmp = indexedDB.cmp(start.v, end.v);
} catch(e) {
console.error(`キーの値が無効です。`);
}
switch(cmp) {
case -1://(start.v < end.v)
r = IDBKeyRange.bound(start.v,end.v,start.b,end.b);
break;
case 0://(start.v === end.v)
r = IDBKeyRange.only(start.v);
break;
case 1://(start.v > end.v)
r = IDBKeyRange.bound(end.v,start.v,end.b,start.b);
break;
default:
r = null;
}
} else if(flag.s && !flag.e) {
//始端の開閉真偽値が有効である。
if(start.v) r = IDBKeyRange.lowerBound(start.v, start.b);
} else if(!flag.s && flag.e) {
//終端の開閉真偽値が有効である。
if(end.v) r = IDBKeyRange.upperBound(end.v, end.b);
} else {
//始端と終端の双方の開閉真偽値が無効である。
if(start.v && !end.v) r = IDBKeyRange.only(start.v);
else if(!start.v && end.v) r = IDBKeyRange.only(end.v);
}
console.log(`RANGE_>${r}`);
//ラングオブジェクトをコンソールに出力する。
console.dir(r);
return r;
}
メソッドの旧バージョンを紹介したIndexedDBにはまってます。(その11)に掲載されているコードと比較してみてください。また、動作確認については、(その11)と同様に試行してみてください。
それでは、コードの説明をします。
まず、冒頭にある「対象キーの値」をチェックする部分のコードを変更してます。
対象キーの値が無かったら付随している「開閉の真偽値」も併せてnullにしています。強力に、後腐れのないようにしました。
//対象キーの値(start.vとend.v)が存在しない、もしくは連想配列(オブジェクト)であった場合は、付随する開閉値も併せてnullとする。
if(typeof(start.v)==='undefined') [start.v,start.b] = [null,null];
else if(!Array.isArray(start.v)) {
if(typeof(start.v)==='object') [start.v,start.b] = [null,null];
}
if(typeof(end.v)==='undefined') [end.v,end.b] = [null,null];
else if(!Array.isArray(end.v)) {
if(typeof(end.v)==='object') [end.v,end.b] = [null,null];
}
そして「開閉の真偽値」が両方ともブーリアン型(真偽値)である条件下の、「始端と終端の双方の開閉真偽値が有効である。」の部分です。
旧バージョンのコードはつぎの通りでした。
//始端と終端の双方の開閉真偽値が有効である。
if((start.v && end.v) && (start.v <= end.v)) {
r = IDBKeyRange.bound(start.v, end.v, start.b, end.b);
}
まあ、キーの値が単一の値、もしくは単純な配列であれば、なんとなく動作してしまうのです。でも、値が多次元配列とか日付オブジェクトを利用する場合もあるのでちゃんとしておこうと改善しました。
「とっくにやれよ。」と思われるやもしれませんが、indexedDBの泥沼にはまりながらの暗中模索では考えが及びませんでした。(気がついた時には溜息が出ましたけどね。)
ということで、indexedDBにあるキーの値を比較してくれるcmpメソッドをつぎのように利用しました。「indexedDB.cmp(start.v, end.v)」という部分です。
//始端と終端の双方の開閉真偽値が有効である。
let cmp = null;
try {
cmp = indexedDB.cmp(start.v, end.v);
} catch(e) {
console.error(`キーの値が無効です。`);
}
switch(cmp) {
case -1://(start.v < end.v)
r = IDBKeyRange.bound(start.v,end.v,start.b,end.b);
break;
case 0://(start.v === end.v)
r = IDBKeyRange.only(start.v);
break;
case 1://(start.v > end.v)
r = IDBKeyRange.bound(end.v,start.v,end.b,start.b);
break;
default:
r = null;
}
メソッドと同じ名前で、返り値を代入する変数cmpを先に宣言してます。cmpは「compare(比較する)」の略ですね。
indexedDBでは頻出しますが、cmpメソッドも例外が返ってくるのでtry文で包んでます。
cmpメソッドは、前後二つのプロパティを比較して「前 < 後」であれば「-1」、「前 === 後」であれば「0」、「前 > 後」であれば「1」を返します。
switch文を使ってそれぞれの条件に合わせた処理をしてます。細かく説明するほどでもないと思います。「default:」ではnullが返るようにして、cmpメソッドで例外が発生してもnullだけは返されるようになっています。
(そうそう、私は例外が発生すると必ず処理が止まると信じていなくて、また例外が発生するとも限らないので、かならず逃げ道を作ります。いままで不審に思われる方がいたかもしれないので言い訳です。)
現在、「前 > 後」の場合は前後のセットを逆転させて指定してますが、運用上の正しい処理なのか疑問の残るところです。
でも、つぎのようなパッと見では前後の大小がよく分からない場合でも、indexedDBのお約束に則ってcmpメソッドが比較してくれます。(この場合は、前プロパティの方が大きいのです。)
rng = newRange({start:{v:[[2, 8], 'SN0001'], b:false}, end:{v:[6, 'SN0005'], b:false}});
これでカーソルの紹介を続けてまいりますが、さては、本メソッドが最適解に近いことを祈ります。そかさ。