From 84210dd19721809fd019036fd1627c8dcd06c9e9 Mon Sep 17 00:00:00 2001 From: EYHN Date: Mon, 2 Dec 2024 05:31:07 +0000 Subject: [PATCH] fix(infra): fix fractional indexing edge cases (#8978) --- .../utils/__tests__/fractional-indexing.spec.ts | 16 ++++++++++++++++ .../infra/src/utils/fractional-indexing.ts | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) 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 aa5d7e9b4c..848138756e 100644 --- a/packages/common/infra/src/utils/__tests__/fractional-indexing.spec.ts +++ b/packages/common/infra/src/utils/__tests__/fractional-indexing.spec.ts @@ -57,3 +57,19 @@ test('no postfix', () => { generateFractionalIndexingKeyBetween('a0', 'a01').startsWith('a00V') ).toBe(true); }); + +test('edge cases', () => { + for (let i = 0; i < 100; i++) { + let a = generateFractionalIndexingKeyBetween(null, null); + let b = generateFractionalIndexingKeyBetween(null, null); + if (a > b) { + [a, b] = [b, a]; + } + const c = generateFractionalIndexingKeyBetween(a, b); + const d = generateFractionalIndexingKeyBetween(c, b); + expect(a < c).toBeTruthy(); + expect(c < b).toBeTruthy(); + expect(c < d).toBeTruthy(); + expect(d < b).toBeTruthy(); + } +}); diff --git a/packages/common/infra/src/utils/fractional-indexing.ts b/packages/common/infra/src/utils/fractional-indexing.ts index 37f74d4a35..c577a00bd4 100644 --- a/packages/common/infra/src/utils/fractional-indexing.ts +++ b/packages/common/infra/src/utils/fractional-indexing.ts @@ -1,5 +1,9 @@ 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. @@ -59,7 +63,7 @@ export function generateFractionalIndexingKeyBetween( 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) { + 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 {