import { generateKeyBetween } from 'fractional-indexing'; function hasSamePrefix(a: string, b: string) { return a.startsWith(b) || b.startsWith(a); } /** * generate a key between a and b, the result key is always satisfied with a < result < b. * the key always has a random suffix, so there is no need to worry about collision. * * make sure a and b are generated by this function. * * @param customPostfix custom postfix for the key, only letters and numbers are allowed */ export function generateKeyBetweenV2(a: string | null, b: string | null) { const randomSize = 32; function postfix(length: number = randomSize) { const chars = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; const values = new Uint8Array(length); crypto.getRandomValues(values); let result = ''; for (let i = 0; i < length; i++) { result += chars.charAt(values[i] % chars.length); } return result; } if (a !== null && b !== null && a >= b) { throw new Error('a should be smaller than b'); } // get the subkey in full key // e.g. // a0xxxx -> a // a0x0xxxx -> a0x function subkey(key: string | null) { if (key === null) { return null; } if (key.length <= randomSize + 1) { // no subkey return key; } const splitAt = key.substring(0, key.length - randomSize - 1); return splitAt; } const aSubkey = subkey(a); const bSubkey = subkey(b); if (aSubkey === null && bSubkey === null) { // generate a new key return generateKeyBetween(null, null) + '0' + postfix(); } else if (aSubkey === null && bSubkey !== null) { // generate a key before b return generateKeyBetween(null, bSubkey) + '0' + postfix(); } else if (bSubkey === null && aSubkey !== null) { // generate a key after a return generateKeyBetween(aSubkey, null) + '0' + postfix(); } else if (aSubkey !== null && bSubkey !== null) { // generate a key between a and b if (hasSamePrefix(aSubkey, bSubkey) && a !== null && b !== null) { // conflict, if the subkeys are the same, generate a key between fullkeys return generateKeyBetween(a, b) + '0' + postfix(); } else { return generateKeyBetween(aSubkey, bSubkey) + '0' + postfix(); } } throw new Error('Never reach here'); }