prototypes for lumia idb changes (removing array keys, etc ...)
This commit is contained in:
parent
59a303daa0
commit
4b17871322
5 changed files with 296 additions and 0 deletions
30
prototypes/base256.html
Normal file
30
prototypes/base256.html
Normal file
|
@ -0,0 +1,30 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
function encodeNumber(n) {
|
||||
const a = (n & 0xFFFF);
|
||||
const b = (n & 0xFFFF0000) >> 16;
|
||||
const c = (n & 0xFFFF00000000) >> 32;
|
||||
const d = (n & 0xFFFF000000000000) >> 48;
|
||||
return String.fromCharCode(a, b, c, d);
|
||||
}
|
||||
|
||||
function printN(n) {
|
||||
//document.write(`<p>fn(${n}) = ${encodeNumber(n)}</p>`);
|
||||
console.log(n, encodeNumber(n));
|
||||
}
|
||||
|
||||
printN(0);
|
||||
printN(9);
|
||||
printN(1000);
|
||||
printN(Number.MAX_SAFE_INTEGER);
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
110
prototypes/idb-cmp-numbers.html
Normal file
110
prototypes/idb-cmp-numbers.html
Normal file
|
@ -0,0 +1,110 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style type="text/css">
|
||||
pre {
|
||||
font-family: monospace;
|
||||
display: block;
|
||||
white-space: pre;
|
||||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
||||
const MIN = 0;
|
||||
const MAX = 0xFFFFFFFF;
|
||||
|
||||
function zeropad(a, n) {
|
||||
return "0".repeat(n - a.length) + a;
|
||||
}
|
||||
|
||||
// const encodeNumber = n => zeropad((n >>> 0).toString(16), 8);
|
||||
|
||||
function encodeNumber(n) {
|
||||
const a = (n & 0xFFFF0000) >>> 16;
|
||||
const b = (n & 0xFFFF) >>> 0;
|
||||
//return zeropad(a.toString(16), 4) + zeropad(b.toString(16), 4);
|
||||
return String.fromCharCode(a, b);
|
||||
}
|
||||
|
||||
function decodeNumber(s) {
|
||||
const a = s.charCodeAt(0);
|
||||
const b = s.charCodeAt(1);
|
||||
//return `${a.toString(16)} ${b}`;
|
||||
return ((a << 16) | b) >>> 0;
|
||||
}
|
||||
|
||||
function formatArg(a) {
|
||||
if (typeof a === "string") {
|
||||
return `"${a}"`;
|
||||
}
|
||||
if (Array.isArray(a)) {
|
||||
return `[${a.map(formatArg)}]`;
|
||||
}
|
||||
return a+"";
|
||||
}
|
||||
function cmp(a, b) {
|
||||
let value;
|
||||
try {
|
||||
const result = indexedDB.cmp(encodeNumber(a), encodeNumber(b));
|
||||
if (result < 0) {
|
||||
value = "a < b";
|
||||
} else if (result === 0) {
|
||||
value = "a = b";
|
||||
} else if (result > 0) {
|
||||
value = "a > b";
|
||||
}
|
||||
} catch(err) {
|
||||
value = err.message;
|
||||
}
|
||||
return `cmp(${formatArg(a)} as ${formatArg(encodeNumber(a))},\n ${formatArg(b)} as ${formatArg(encodeNumber(b))}): ${value}`;
|
||||
}
|
||||
|
||||
try {
|
||||
const tests = [
|
||||
// see https://stackoverflow.com/questions/28413947/space-efficient-way-to-encode-numbers-as-sortable-strings
|
||||
// need to encode numbers with base 256 and zero padded at start
|
||||
// should still fit in 8 bytes then?
|
||||
(cmp) => cmp(9, 100000),
|
||||
(cmp) => cmp(1, 2),
|
||||
(cmp) => cmp(MIN, 1),
|
||||
(cmp) => cmp(MIN, MIN),
|
||||
(cmp) => cmp(MIN, MAX),
|
||||
(cmp) => cmp(MAX >>> 1, MAX),
|
||||
(cmp) => cmp(0x7fffffff, 0xffff7fff),
|
||||
(cmp) => cmp(MAX, MAX),
|
||||
(cmp) => cmp(MAX - 1, MAX),
|
||||
];
|
||||
|
||||
for (const fn of tests) {
|
||||
const txt = document.createTextNode(fn(cmp));
|
||||
const p = document.createElement("pre");
|
||||
p.appendChild(txt);
|
||||
document.body.appendChild(p);
|
||||
}
|
||||
} catch(err) {
|
||||
alert(err.message);
|
||||
}
|
||||
|
||||
let prev;
|
||||
for (let i = MIN; i <= MAX; i += 100) {
|
||||
if (decodeNumber(encodeNumber(i)) !== i) {
|
||||
document.write(`<p>${i} decodes back to ${decodeNumber(encodeNumber(i))}</p>`);
|
||||
break;
|
||||
}
|
||||
if (typeof prev === "number") {
|
||||
if (indexedDB.cmp(encodeNumber(prev), encodeNumber(i)) >= 0) {
|
||||
document.write(`<p>${i} <= ${prev}</p>`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
prev = i;
|
||||
}
|
||||
document.write(`<p>check from ${MIN} to ${prev}</p>`);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
76
prototypes/idb-cmp.html
Normal file
76
prototypes/idb-cmp.html
Normal file
|
@ -0,0 +1,76 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style type="text/css">
|
||||
pre {
|
||||
font-family: "courier";
|
||||
display: block;
|
||||
white-space: pre;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
function encodeNumber(n) {
|
||||
const a = (n & 0xFFFF);
|
||||
const b = (n & 0xFFFF0000) >> 16;
|
||||
const c = (n & 0xFFFF00000000) >> 32;
|
||||
const d = (n & 0xFFFF000000000000) >> 48;
|
||||
return String.fromCharCode(a, b, c, d);
|
||||
}
|
||||
function formatArg(a) {
|
||||
if (typeof a === "string") {
|
||||
return `"${a}"`;
|
||||
}
|
||||
if (Array.isArray(a)) {
|
||||
return `[${a.map(formatArg)}]`;
|
||||
}
|
||||
return a+"";
|
||||
}
|
||||
function cmp(a, b) {
|
||||
let value;
|
||||
try {
|
||||
const result = indexedDB.cmp(encodeNumber(a), encodeNumber(b));
|
||||
if (result < 0) {
|
||||
value = "a < b";
|
||||
} else if (result === 0) {
|
||||
value = "a = b";
|
||||
} else if (result > 0) {
|
||||
value = "a > b";
|
||||
}
|
||||
} catch(err) {
|
||||
value = err.message;
|
||||
}
|
||||
return `cmp(${formatArg(a)},\n ${formatArg(b)}): ${value}`;
|
||||
}
|
||||
|
||||
try {
|
||||
const tests = [
|
||||
(cmp) => cmp(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER),
|
||||
(cmp) => cmp([Number.MIN_SAFE_INTEGER], [Number.MAX_SAFE_INTEGER]),
|
||||
// see https://stackoverflow.com/questions/28413947/space-efficient-way-to-encode-numbers-as-sortable-strings
|
||||
// need to encode numbers with base 256 and zero padded at start
|
||||
// should still fit in 8 bytes then?
|
||||
(cmp) => cmp("foo-9", "foo-10000"),
|
||||
(cmp) => cmp("foo-\u0000", "foo-\uFFFF"),
|
||||
(cmp) => cmp("foo-\u0000", "foo-0"),
|
||||
(cmp) => cmp("foo-" + Number.MAX_SAFE_INTEGER, "foo-\uFFFF"),
|
||||
(cmp) => cmp("!abc:host.tld,"+Number.MIN_SAFE_INTEGER, "!abc:host.tld,"+(Number.MIN_SAFE_INTEGER + 1)),
|
||||
(cmp) => cmp("!abc:host.tld,"+0, "!abc:host.tld,"+(Number.MAX_SAFE_INTEGER)),
|
||||
(cmp) => cmp("!abc:host.tld,"+Math.floor(Number.MAX_SAFE_INTEGER / 2), "!abc:host.tld,"+(Number.MAX_SAFE_INTEGER)),
|
||||
];
|
||||
|
||||
for (const fn of tests) {
|
||||
const txt = document.createTextNode(fn(cmp));
|
||||
const p = document.createElement("pre");
|
||||
p.appendChild(txt);
|
||||
document.body.appendChild(p);
|
||||
}
|
||||
} catch(err) {
|
||||
alert(err.message);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -2,6 +2,11 @@
|
|||
<head><meta charset="utf-8"></head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
||||
console.log = (...params) => {
|
||||
document.write(params.join(" ")+"<br>");
|
||||
};
|
||||
|
||||
function reqAsPromise(req) {
|
||||
return new Promise((resolve, reject) => {
|
||||
req.onsuccess = () => resolve(req);
|
||||
|
|
75
prototypes/idb-multi-key.html
Normal file
75
prototypes/idb-multi-key.html
Normal file
|
@ -0,0 +1,75 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
function reqAsPromise(req) {
|
||||
return new Promise((resolve, reject) => {
|
||||
req.onsuccess = () => resolve(req);
|
||||
req.onerror = (err) => reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
class Storage {
|
||||
constructor(databaseName) {
|
||||
this._databaseName = databaseName;
|
||||
this._database = null;
|
||||
}
|
||||
|
||||
async open() {
|
||||
const req = window.indexedDB.open(this._databaseName);
|
||||
req.onupgradeneeded = (ev) => {
|
||||
const db = ev.target.result;
|
||||
const oldVersion = ev.oldVersion;
|
||||
this._createStores(db, oldVersion);
|
||||
};
|
||||
await reqAsPromise(req);
|
||||
this._database = req.result;
|
||||
}
|
||||
|
||||
_createStores(db) {
|
||||
db.createObjectStore("files", {keyPath: ["idName"]});
|
||||
}
|
||||
|
||||
async storeFoo(id, name) {
|
||||
const tx = this._database.transaction(["files"], "readwrite");
|
||||
const store = tx.objectStore("files");
|
||||
await reqAsPromise(store.add(value(id, name)));
|
||||
}
|
||||
}
|
||||
|
||||
function value(id, name) {
|
||||
return {idName: key(id, name)};
|
||||
}
|
||||
|
||||
function key(id, name) {
|
||||
return id+","+name;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
let storage = new Storage("idb-multi-key2");
|
||||
try {
|
||||
await storage.open();
|
||||
await storage.storeFoo(5, "foo");
|
||||
await storage.storeFoo(6, "bar");
|
||||
alert("all good");
|
||||
} catch(err) {
|
||||
alert(err.message);
|
||||
}
|
||||
try {
|
||||
const result = indexedDB.cmp(key(5, "foo"), key(6, "bar"));
|
||||
//IDBKeyRange.bound(["aaa", "111"],["zzz", "999"], false, false);
|
||||
alert("all good: " + result);
|
||||
} catch (err) {
|
||||
alert(`IDBKeyRange.bound: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Reference in a new issue