import { sort, defaultComparer } from 'fast-sort' import type { GridColumnSort, GridColumnSortEmptyAs, GridRowId, GridRowMeta, } from '../types' import type { ColumnSortInfo } from '../state/types' const NO_META = {} export function buildSort( sortConfig: GridColumnSort[], locale: string, columns: ColumnSortInfo ) { const comparer = new Intl.Collator(locale, { sensitivity: 'base', numeric: true, }) if (sortConfig.length === 0) { return (rowIds: GridRowId[], _entities: any, _meta: any) => rowIds } return ( rowIds: GridRowId[], entities: Map, meta: Map ) => { const getRow = (rowId: GridRowId) => entities.get(rowId) const getMeta = (rowId: GridRowId) => meta.get(rowId) || NO_META return sort(rowIds).by( sortConfig.map((sc) => { const column = columns[sc.columnId] const sortStrategy = column?.sortStrategy ?? 'fast' const valueLookup = column?.valueLookup const sortEmptyAs = column?.sortEmptyAs ?? 'low' const columnCompare = ( a: unknown, b: unknown, order: number ) => { const aIsBlank = a == null || a === '' const bIsBlank = b == null || b === '' const emptyLookup: Record = { low: 1, high: -1, 'always-first': order, 'always-last': -order, } if (aIsBlank && bIsBlank) return 0 if (aIsBlank && !bIsBlank) return -emptyLookup[sortEmptyAs] if (!aIsBlank && bIsBlank) return emptyLookup[sortEmptyAs] if (sortStrategy === 'fast') { return defaultComparer(a, b, 1) } return comparer.compare(a as string, b as string) } return sc.direction === 'desc' ? { desc: (rowId) => { const rowData = getRow(rowId) return valueLookup && rowData ? valueLookup({ columnId: sc.columnId, row: getRow(rowId), rowMeta: getMeta(rowId), }) : rowData?.[sc.columnId] }, comparer: columnCompare, } : { asc: (rowId) => { const rowData = getRow(rowId) return valueLookup && rowData ? valueLookup({ columnId: sc.columnId, row: getRow(rowId), rowMeta: getMeta(rowId), }) : rowData?.[sc.columnId] }, comparer: columnCompare, } }) ) } }