import { SortDescriptor } from '../sort-descriptor'; import { isPresent, isBlank } from '../utils'; import { getter } from '../accessor'; import { Preprocessors } from '../common.interfaces'; // tslint:disable:max-line-length /** * A type that represents a function which compares two values and returns `1`, `0`, or `-1` (minus one). * * For more information, refer to the [`composeSortDescriptors`]({% slug api_kendo-data-query_composesortdescriptors %}) configuration. * * @example * ```ts-no-run * const isGreaterThan: Comparer = (a, b) => a > b ? 1 : -1; * isGreaterThan(42, 42); // 0 * isGreaterThan(22, 42); // -1 * isGreaterThan(42, 22); // 1 * ``` */ // tslint:enable:max-line-length export type Comparer = (a: T, b: T) => number; const compare = (a, b) => { if (isBlank(a)) { return a === b ? 0 : -1; } if (isBlank(b)) { return 1; } if (a.localeCompare) { return a.localeCompare(b); } return a > b ? 1 : (a < b ? -1 : 0); }; const compareDesc: Comparer = (a, b) => compare(b, a); const descriptorAsFunc = (descriptor: SortDescriptor, preprocessors: Preprocessors = {}): Comparer => { const prop = a => { const value = getter(descriptor.field, true)(a); const preprocessor = preprocessors[descriptor.field]; return preprocessor ? preprocessor(value) : value; }; return (a, b) => (descriptor.dir === 'asc' ? compare : compareDesc)(prop(a), prop(b)); }; const initial: Comparer = (_a, _b) => 0; // tslint:disable:max-line-length /** * Converts the `SortDescriptors` into a [`Comparer`]({% slug api_kendo-data-query_comparer %}) function that can be used through `Array.sort`. If multiple descriptors are provided, sorting is applied in a right-to-left order. * @param {SortDescriptor[]} descriptors - The descriptors which will be converted. * @returns {Comparer} - The produced function. * * @example * ```ts-no-run * import { composeSortDescriptors } from '@progress/kendo-data-query'; * * const data = [{ name: "Pork" }, { name: "Pepper" }, { name: "Beef" } ]; * const comparer = composeSortDescriptors([{ field: "name", dir: "asc" }]); * const result = data.sort(comparer); * // output: [{ name: "Beef" }, { name: "Pepper" }, { name: "Pork" }]; * ``` */ // tslint:enable:max-line-length export const composeSortDescriptors = (descriptors: SortDescriptor[], preprocessors: Preprocessors = {}): Comparer => ( descriptors .filter(x => isPresent(x.dir)) .map((descriptor: SortDescriptor) => descriptorAsFunc(descriptor, preprocessors)) .reduce( (acc: Comparer, curr: Function): Comparer => (a, b) => acc(a, b) || curr(a, b), initial ) );