From 8fd7afeb32ccee0ac4f3139cc3662e0babdf255a Mon Sep 17 00:00:00 2001 From: Avior Date: Wed, 3 Jan 2024 23:24:52 +0100 Subject: [PATCH] fix: better sorting defaults Signed-off-by: Avior --- server/src/util.ts | 55 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/server/src/util.ts b/server/src/util.ts index c3a1dc852..f9927019e 100644 --- a/server/src/util.ts +++ b/server/src/util.ts @@ -109,10 +109,12 @@ export function handleSort(data: Array, query: Query) { if (data.length === 0) { return data } + + const defaultSortPriority = ['releaseDate', 'localId', 'id'] + const firstEntry = data[0] - const sort: Query['sort'] = query.sort ?? {field: 'releaseDate' in firstEntry ? 'releaseDate' : 'id', order: 'ASC'} - const field = sort.field - const order = sort.order ?? 'ASC' + const field = query.sort?.field ?? defaultSortPriority.find((it) => it in firstEntry) ?? 'id' + const order = query.sort?.order ?? 'ASC' // early exit if the order is not correctly set if (order !== 'ASC' && order !== 'DESC') { @@ -121,22 +123,43 @@ export function handleSort(data: Array, query: Query) { } if (!(field in firstEntry)) { + console.warn('can\'t sort using the field', field) return data } - const sortType = typeof data[0][field] - if (sortType === 'number') { - if (order === 'ASC') { - return data.sort((a, b) => a[field] - b[field]) - } else { - return data.sort((a, b) => b[field] - a[field]) - } - } else { - if (order === 'ASC') { - return data.sort((a, b) => a[field] > b[field] ? 1 : -1) - } else { - return data.sort((a, b) => a[field] > b[field] ? -1 : 1) - } + + return data.sort((a, b) => advSort(a[field], b[field], order)) +} + +/** + * + * @param order the base ordering + * @returns a function that is feed in the `sort` function + */ +const advSort = (a: string | number, b: string | number, order: 'ASC' | 'DESC' = 'ASC') => { + a = tryParse(a) ?? a + b = tryParse(b) ?? b + + if (order === 'DESC') { + const tmp = a + a = b + b = tmp } + + if (typeof a === 'number' && typeof b === 'number') { + return a - b + } + + return a.toString().localeCompare(b.toString()) +} + +function tryParse(value: string | number): number | null { + if (typeof value === 'number') { + return value + } + if (/^-?\d+$/.test(value)) { + return parseInt(value) + } + return null } /**