Created
October 4, 2023 01:02
-
-
Save paralin/80e545b8e67cdeb027be6946b645b2fd to your computer and use it in GitHub Desktop.
IndexedDB filter by prefix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2019 Google LLC. | |
// SPDX-License-Identifier: Apache-2.0 | |
// https://gist.github.com/inexorabletash/5462871 | |
// https://github.com/w3c/IndexedDB/issues/47 | |
// IDBKeyRangeWithPrefix returns an IDBKeyRange from the given prefix. | |
// | |
// Basic p(r)olyfill for proposed feature | |
// | |
// This defines no successor of empty arrays, so the range for prefix | |
// [] or [[],[]] has no upper bound. | |
// An alternate definition would preclude adding additional nesting, | |
// so the range for prefix [] would have upper bound [[]] and the | |
// range for prefix [[], []] would have upper bound [[], [[]]]. | |
export function IDBKeyRangeWithPrefix(prefix: any): IDBKeyRange { | |
// Ensure prefix is a valid key itself: | |
if (indexedDB.cmp(prefix, prefix) !== 0) throw new TypeError() | |
const MAX_DATE_VALUE = 8640000000000000 | |
const UPPER_BOUND = { | |
NUMBER: new Date(-MAX_DATE_VALUE), | |
DATE: '', | |
STRING: [], | |
ARRAY: undefined, | |
} | |
const upperKey = successor(prefix) | |
if (upperKey === undefined) return IDBKeyRange.lowerBound(prefix) | |
return IDBKeyRange.bound(prefix, upperKey, false, true) | |
function successor(key: any) { | |
if (typeof key === 'number') { | |
if (key === Infinity) return UPPER_BOUND.NUMBER | |
if (key === -Infinity) return -Number.MAX_VALUE | |
if (key === 0) return Number.MIN_VALUE | |
let epsilon = Math.abs(key) | |
while (key + epsilon / 2 !== key) epsilon = epsilon / 2 | |
return key + epsilon | |
} | |
if (key instanceof Date) { | |
if (key.valueOf() + 1 > MAX_DATE_VALUE) return UPPER_BOUND.DATE | |
return new Date(key.valueOf() + 1) | |
} | |
if (typeof key === 'string') { | |
let len = key.length | |
while (len > 0) { | |
const head = key.substring(0, len - 1), | |
tail = key.charCodeAt(len - 1) | |
if (tail !== 0xffff) return head + String.fromCharCode(tail + 1) | |
key = head | |
--len | |
} | |
return UPPER_BOUND.STRING | |
} | |
if (Array.isArray(key)) { | |
key = key.slice() // Operate on a copy. | |
let len = key.length | |
while (len > 0) { | |
const tail = successor(key.pop()) | |
if (tail !== undefined) { | |
key.push(tail) | |
return key | |
} | |
--len | |
} | |
return UPPER_BOUND.ARRAY | |
} | |
throw new TypeError() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment