UNPKG

tubular-common

Version:

Tubular Common Models and Data Transformer

214 lines 10.2 kB
import { AggregateFunctions, ColumnDataType, ColumnSortDirection, CompareOperators, columnHasFilter, isDateColum, } from './Models'; import GridResponse from './Models/GridResponse'; import { areDatesEqual, dateIsBetween, isDateAfter, isDateBefore } from './dateUtils'; import { parsePayload } from './utils'; const partialfilteringCurry = (column) => (data, action) => data.filter((row) => typeof row[column.name] === 'undefined' || row[column.name] === null ? false : action(row[column.name])); const equalsDateFilter = (column) => (row) => areDatesEqual(column, row[column.name], column.filterText); const equalsStringFilter = (column) => (x) => x.toLowerCase() === column.filterText.toLowerCase(); const equalsFilter = (column) => (row) => row[column.name] === column.filterText; const filterBetween = (column) => (row) => row[column.name] >= column.filterText && row[column.name] <= column.filterArgument[0]; const filterByEquals = (column, isDate, subset, partialfiltering) => { if (isDate) return subset.filter(equalsDateFilter(column)); if (column.dataType === ColumnDataType.String) return partialfiltering(subset, equalsStringFilter(column)); return subset.filter(equalsFilter(column)); }; const sortColumnsByOrder = (a, b) => { if (a.sortOrder > b.sortOrder) return 1; return b.sortOrder > a.sortOrder ? -1 : 0; }; const distinctReducer = (column) => (list, r) => { if (list.indexOf(r[column.name]) === -1) list.push(r[column.name]); return list; }; const filterAggregateColumns = (column) => column.aggregate && column.aggregate.toLowerCase() !== AggregateFunctions.None.toLowerCase(); const minReducer = (column) => (min, r) => (r[column.name] < min ? r[column.name] : min); const maxReducer = (column) => (max, r) => (r[column.name] > max ? r[column.name] : max); const sumReducer = (column) => (sum, r) => typeof r[column.name] === 'undefined' ? sum : sum + r[column.name]; const sortData = (sorts) => (a, b) => { let result = 0; for (const current of sorts) { const reverse = current.asc ? 1 : -1; if (typeof a[current.name] === 'undefined' || typeof b[current.name] === 'undefined') { result = reverse * -1; break; } if (a[current.name] < b[current.name]) { result = reverse * -1; break; } if (a[current.name] > b[current.name]) { result = reverse * 1; break; } } return result; }; export const getResponse = (request, dataSource) => { const response = new GridResponse(request.counter); response.totalRecordCount = dataSource.length; let data = applyFreeTextSearch(request, dataSource); data = applyFiltering(request, data); data = applySorting(request, data); response.filteredRecordCount = data.length; if (request.take > -1) { response.totalPages = Math.ceil(response.filteredRecordCount / request.take); if (response.totalPages > 0) { response.currentPage = request.skip / request.take + 1; } } response.aggregationPayload = getAggregatePayload(request, data); const sliceSize = request.take === -1 ? data.length : request.skip + request.take; response.payload = data .slice(request.skip, sliceSize) .map((row) => parsePayload(row, request.columns)); return response; }; const applyFreeTextSearch = (request, subset) => { if (request.searchText) { const searchableColumns = request.columns.filter((x) => x.searchable); if (searchableColumns.length > 0) { const filter = request.searchText.toLowerCase(); if (filter === '') { return subset; } return subset.filter((item) => searchableColumns.some((x) => { if (typeof item[x.name] === 'undefined' || item[x.name] === null) { return false; } return item[x.name].toLowerCase().indexOf(filter) > -1; })); } } return subset; }; const applyFiltering = (request, subset) => { // biome-ignore lint/complexity/noForEach: <explanation> request.columns .filter((column) => columnHasFilter(column)) .forEach((column) => { const isDate = isDateColum(column); const partialfiltering = partialfilteringCurry(column); switch (column.filterOperator) { case CompareOperators.Equals: subset = filterByEquals(column, isDate, subset, partialfiltering); break; case CompareOperators.NotEquals: if (column.dataType === ColumnDataType.String) { subset = partialfiltering(subset, (x) => x.toLowerCase() !== column.filterText.toLowerCase()); } else { subset = subset.filter((row) => row[column.name] !== column.filterText); } break; case CompareOperators.Contains: subset = partialfiltering(subset, (x) => x.toLowerCase().indexOf(column.filterText.toLowerCase()) >= 0); subset = partialfiltering(subset, (x) => x.toLowerCase().indexOf(column.filterText.toLowerCase()) >= 0); break; case CompareOperators.NotContains: subset = partialfiltering(subset, (x) => x.toLowerCase().indexOf(column.filterText.toLowerCase()) < 0); break; case CompareOperators.StartsWith: subset = partialfiltering(subset, (x) => x.toLowerCase().startsWith(column.filterText.toLowerCase())); break; case CompareOperators.NotStartsWith: subset = partialfiltering(subset, (x) => !x.toLowerCase().startsWith(column.filterText.toLowerCase())); break; case CompareOperators.EndsWith: subset = partialfiltering(subset, (x) => x.toLowerCase().endsWith(column.filterText.toLowerCase())); break; case CompareOperators.NotEndsWith: subset = partialfiltering(subset, (x) => !x.toLowerCase().endsWith(column.filterText.toLowerCase())); break; case CompareOperators.Gt: if (isDate) { subset = subset.filter((row) => isDateAfter(column, row[column.name], column.filterText)); } else { subset = subset.filter((row) => row[column.name] > column.filterText); } break; case CompareOperators.Gte: if (isDate) { subset = subset.filter((row) => isDateAfter(column, row[column.name], column.filterText, true)); } else { subset = subset.filter((row) => row[column.name] >= column.filterText); } break; case CompareOperators.Lt: if (isDate) { subset = subset.filter((row) => isDateBefore(column, row[column.name], column.filterText)); } else { subset = subset.filter((row) => row[column.name] < column.filterText); } break; case CompareOperators.Lte: if (isDate) { subset = subset.filter((row) => isDateBefore(column, row[column.name], column.filterText, true)); } else { subset = subset.filter((row) => row[column.name] <= column.filterText); } break; case CompareOperators.Between: if (isDate) { subset = subset.filter((row) => dateIsBetween(column, column.filterText, column.filterArgument[0].toString(), row[column.name])); } else { subset = subset.filter(filterBetween(column)); } break; default: throw new Error('Unsupported Compare Operator'); } }); return subset; }; const applySorting = (request, subset) => { const sortedColumns = request.columns.filter((column) => column.sortOrder > 0); let sorts = [{ name: request.columns[0].name, asc: true }]; if (sortedColumns.length > 0) { sortedColumns.sort(sortColumnsByOrder); sorts = sortedColumns.map((y) => ({ name: y.name, asc: y.sortDirection === ColumnSortDirection.Ascending, })); } subset.sort(sortData(sorts)); return subset; }; const getAggregatePayload = (request, subset) => { const aggregateColumns = request.columns.filter(filterAggregateColumns); return aggregateColumns.reduce((prev, column) => { switch (column.aggregate.toLowerCase()) { case AggregateFunctions.Sum.toLowerCase(): prev[column.name] = subset.length === 0 ? 0 : subset.reduce(sumReducer(column), 0); break; case AggregateFunctions.Average.toLowerCase(): prev[column.name] = subset.length === 0 ? 0 : Number(subset.reduce(sumReducer(column), 0)) / subset.length; break; case AggregateFunctions.Max.toLowerCase(): prev[column.name] = subset.length === 0 ? 0 : subset.reduce(maxReducer(column), subset[0][column.name]); break; case AggregateFunctions.Min.toLowerCase(): prev[column.name] = subset.length === 0 ? 0 : subset.reduce(minReducer(column), subset[0][column.name]); break; case AggregateFunctions.Count.toLowerCase(): prev[column.name] = subset.length; break; case AggregateFunctions.DistinctCount.toLowerCase(): prev[column.name] = subset.length === 0 ? 0 : subset.reduce(distinctReducer(column), []).length; break; default: throw new Error('Unsupported aggregate function'); } return prev; }, {}); }; //# sourceMappingURL=getResponse.js.map