fix: orderable has incorrect sort results depending on capitalization (#12758)

### What?
The results when querying orderable collections can be incorrect due to
how the underlying database handles sorting when capitalized letters are
introduced.

### Why?
The original fractional indexing logic uses base 62 characters to
maximize the amount of data per character. This optimization saves a few
characters of text in the database but fails to return accurate results
when mixing uppercase and lowercase characters.

### How?
Instead we can use base 36 values instead (0-9,a-z) so that all
databases handle the sort consistently without needing to introduce
collation or other alternate solutions.

Fixes #12397
This commit is contained in:
Dan Ribbens
2025-06-11 09:49:53 -04:00
committed by GitHub
parent 458a04b77c
commit 37afbe6c04
2 changed files with 66 additions and 3 deletions

View File

@@ -628,6 +628,69 @@ describe('Sort', () => {
parseInt(docDuplicatedAfterReorder._order!, 16),
)
})
it('should not break with existing base 62 digits', async () => {
const collection = orderableSlug
// create seed docs with aa, aA, AA
const aa = await payload.create({
collection,
data: {
title: 'Base62 aa',
_order: 'aa',
},
})
const aA = await payload.create({
collection,
data: {
title: 'Base62 aA',
_order: 'aA',
},
})
const AA = await payload.create({
collection,
data: {
title: 'Base62 AA',
_order: 'AA',
},
})
const orderableDoc = await payload.create({
collection,
data: {
title: 'Base62 new',
},
})
const res = await restClient.POST('/reorder', {
body: JSON.stringify({
collectionSlug: orderableSlug,
docsToMove: [orderableDoc.id],
newKeyWillBe: 'greater',
orderableFieldName: '_order',
target: {
id: aA.id,
key: aA._order,
},
}),
})
expect(res.status).toStrictEqual(200)
const { docs } = await payload.find({
collection,
sort: '-_order',
where: {
title: {
contains: 'Base62 ',
},
},
})
expect(docs[0]?.id).toStrictEqual(aa.id)
expect(docs[1]?.id).toStrictEqual(aA.id)
expect(docs[2]?.id).toStrictEqual(orderableDoc.id)
expect(docs[3]?.id).toStrictEqual(AA.id)
})
})
describe('Orderable join', () => {