diff --git a/packages/common/infra/src/modules/doc/constants.ts b/packages/common/infra/src/modules/doc/constants.ts index cde7a6b465..31a526fa85 100644 --- a/packages/common/infra/src/modules/doc/constants.ts +++ b/packages/common/infra/src/modules/doc/constants.ts @@ -2,10 +2,13 @@ import type { DocCustomPropertyInfo } from '../db'; /** * default built-in custom property, user can update and delete them + * + * 'id' and 'type' is request, 'index' is a manually maintained incremental key. */ export const BUILT_IN_CUSTOM_PROPERTY_TYPE = [ { id: 'tags', type: 'tags', + index: 'a0000001', }, ] as DocCustomPropertyInfo[]; diff --git a/packages/common/infra/src/utils/__tests__/fractional-indexing.spec.ts b/packages/common/infra/src/utils/__tests__/fractional-indexing.spec.ts index b5ed42853c..aa5d7e9b4c 100644 --- a/packages/common/infra/src/utils/__tests__/fractional-indexing.spec.ts +++ b/packages/common/infra/src/utils/__tests__/fractional-indexing.spec.ts @@ -39,3 +39,21 @@ test('fractional-indexing', () => { } } }); + +test('no postfix', () => { + expect( + generateFractionalIndexingKeyBetween('a0', null).startsWith('a1') + ).toBe(true); + expect( + generateFractionalIndexingKeyBetween('a01', null).startsWith('a1') + ).toBe(true); + expect( + generateFractionalIndexingKeyBetween('a0001', null).startsWith('a1') + ).toBe(true); + expect( + generateFractionalIndexingKeyBetween(null, 'a0').startsWith('Zz') + ).toBe(true); + expect( + generateFractionalIndexingKeyBetween('a0', 'a01').startsWith('a00V') + ).toBe(true); +}); diff --git a/packages/common/infra/src/utils/fractional-indexing.ts b/packages/common/infra/src/utils/fractional-indexing.ts index 7e0cf0d919..a5adaab78d 100644 --- a/packages/common/infra/src/utils/fractional-indexing.ts +++ b/packages/common/infra/src/utils/fractional-indexing.ts @@ -150,17 +150,19 @@ export function createFractionalIndexingSortableHelper< * 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 generateFractionalIndexingKeyBetween( a: string | null, b: string | null ) { const randomSize = 32; - function randomString(length: number = randomSize) { - const values = new Uint8Array(length); - crypto.getRandomValues(values); + 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); @@ -193,20 +195,20 @@ export function generateFractionalIndexingKeyBetween( if (aSubkey === null && bSubkey === null) { // generate a new key - return generateKeyBetween(null, null) + '0' + randomString(); + return generateKeyBetween(null, null) + '0' + postfix(); } else if (aSubkey === null && bSubkey !== null) { // generate a key before b - return generateKeyBetween(null, bSubkey) + '0' + randomString(); + return generateKeyBetween(null, bSubkey) + '0' + postfix(); } else if (bSubkey === null && aSubkey !== null) { // generate a key after a - return generateKeyBetween(aSubkey, null) + '0' + randomString(); + return generateKeyBetween(aSubkey, null) + '0' + postfix(); } else if (aSubkey !== null && bSubkey !== null) { // generate a key between a and b if (aSubkey === bSubkey && a !== null && b !== null) { // conflict, if the subkeys are the same, generate a key between fullkeys - return generateKeyBetween(a, b) + '0' + randomString(); + return generateKeyBetween(a, b) + '0' + postfix(); } else { - return generateKeyBetween(aSubkey, bSubkey) + '0' + randomString(); + return generateKeyBetween(aSubkey, bSubkey) + '0' + postfix(); } } throw new Error('Never reach here');