mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-12 15:46:29 +08:00
205cd7a86d
Closes: BS-2946
67 lines
2.3 KiB
TypeScript
67 lines
2.3 KiB
TypeScript
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');
|
|
}
|