• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 20960087204

13 Jan 2026 02:19PM UTC coverage: 12.713% (-78.8%) from 91.5%
20960087204

Pull #16746

github

web-flow
Merge 9afce6e5d into a967f087e
Pull Request #16746: fix(csv): export summaries - master

1008 of 16803 branches covered (6.0%)

19 of 23 new or added lines in 2 files covered. (82.61%)

24693 existing lines in 336 files now uncovered.

3985 of 31345 relevant lines covered (12.71%)

2.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/projects/igniteui-angular/core/src/data-operations/data-util.ts
1
import { IGroupByResult } from './grouping-result.interface';
2

3
import { IPagingState, PagingError } from './paging-state.interface';
4

5
import { IGroupByKey } from './groupby-expand-state.interface';
6
import { IGroupByRecord } from './groupby-record.interface';
7
import { IGroupingState } from './groupby-state.interface';
8
import { cloneArray, mergeObjects } from '../core/utils';
9
import { Transaction, TransactionType, HierarchicalTransaction } from '../services/transaction/transaction';
10
import { getHierarchy, isHierarchyMatch } from './operations';
11
import type { ColumnType, GridTypeBase, ITreeGridRecord } from './grid-types';
12
import { ISortingExpression } from './sorting-strategy';
13
import {
14
    IGridSortingStrategy,
15
    IGridGroupingStrategy,
16
    IgxDataRecordSorting,
17
    IgxSorting,
18
    IgxGrouping
19
} from './grid-sorting-strategy';
20
import { DefaultDataCloneStrategy, IDataCloneStrategy } from '../data-operations/data-clone-strategy';
21
import { IGroupingExpression } from './grouping-expression.interface';
22
import { DefaultMergeStrategy, IGridMergeStrategy } from './merge-strategy';
23
import { IFilteringExpressionsTree } from './filtering-expressions-tree';
24
import { FilteringStrategy, FilterUtil } from './filtering-strategy';
25
import { GridColumnDataType } from './grid-types';
26

27
/**
28
 * @hidden
29
 */
30
export class DataUtil {
31
    public static sort<T>(data: T[], expressions: ISortingExpression[], sorting: IGridSortingStrategy = new IgxSorting(),
×
32
        grid?: GridTypeBase): T[] {
UNCOV
33
        return sorting.sort(data, expressions, grid);
×
34
    }
35

36
    public static treeGridSort(hierarchicalData: ITreeGridRecord[],
37
        expressions: ISortingExpression[],
38
        sorting: IGridSortingStrategy = new IgxDataRecordSorting(),
×
39
        grid?: GridTypeBase): ITreeGridRecord[] {
UNCOV
40
        const res: ITreeGridRecord[] = [];
×
41
        const stack: {
42
            original: ITreeGridRecord[];
43
            parent?: ITreeGridRecord;
44
            result: ITreeGridRecord[];
UNCOV
45
        }[] = [];
×
46

UNCOV
47
        stack.push({ original: hierarchicalData, parent: null, result: res });
×
48

UNCOV
49
        while (stack.length > 0) {
×
UNCOV
50
            const { original, parent, result } = stack.pop()!;
×
51

UNCOV
52
            const clonedRecords: ITreeGridRecord[] = [];
×
53

UNCOV
54
            for (const treeRecord of original) {
×
UNCOV
55
                const rec: ITreeGridRecord = DataUtil.cloneTreeGridRecord(treeRecord);
×
UNCOV
56
                rec.parent = parent;
×
UNCOV
57
                clonedRecords.push(rec);
×
58

59
                // If it has children, process them later
UNCOV
60
                if (rec.children && rec.children.length > 0) {
×
UNCOV
61
                    const childClones: ITreeGridRecord[] = [];
×
UNCOV
62
                    rec.children = childClones;
×
UNCOV
63
                    stack.push({
×
64
                        original: treeRecord.children,
65
                        parent: rec,
66
                        result: childClones
67
                    });
68
                }
69
            }
70

71
            // Sort the clonedRecords before assigning to the result
UNCOV
72
            const sorted = DataUtil.sort(clonedRecords, expressions, sorting, grid);
×
UNCOV
73
            for (const item of sorted) {
×
UNCOV
74
                result.push(item);
×
75
            }
76
        }
77

UNCOV
78
        return res;
×
79
    }
80

81
    public static cloneTreeGridRecord(hierarchicalRecord: ITreeGridRecord) {
UNCOV
82
        const rec: ITreeGridRecord = {
×
83
            key: hierarchicalRecord.key,
84
            data: hierarchicalRecord.data,
85
            children: hierarchicalRecord.children,
86
            isFilteredOutParent: hierarchicalRecord.isFilteredOutParent,
87
            level: hierarchicalRecord.level,
88
            expanded: hierarchicalRecord.expanded
89
        };
UNCOV
90
        return rec;
×
91
    }
92

93
    public static group<T>(data: T[], state: IGroupingState, grouping: IGridGroupingStrategy = new IgxGrouping(), grid: GridTypeBase = null,
×
94
        groupsRecords: any[] = [], fullResult: IGroupByResult = { data: [], metadata: [] }): IGroupByResult {
×
UNCOV
95
        groupsRecords.splice(0, groupsRecords.length);
×
UNCOV
96
        return grouping.groupBy(data, state, grid, groupsRecords, fullResult);
×
97
    }
98

99
    public static merge<T>(data: T[], columns: ColumnType[], strategy: IGridMergeStrategy = new DefaultMergeStrategy(), activeRowIndexes = [], grid: GridTypeBase = null,
×
100
    ): any[] {
UNCOV
101
        const result = [];
×
UNCOV
102
        for (const col of columns) {
×
UNCOV
103
            const isDate = col?.dataType === 'date' || col?.dataType === 'dateTime';
×
UNCOV
104
            const isTime = col?.dataType === 'time' || col?.dataType === 'dateTime';
×
UNCOV
105
            strategy.merge(
×
106
                data,
107
                col.field,
108
                col.mergingComparer,
109
                result,
110
                activeRowIndexes,
111
                isDate,
112
                isTime,
113
                grid);
114
        }
UNCOV
115
        return result;
×
116
    }
117

118
    public static page<T>(data: T[], state: IPagingState, dataLength?: number): T[] {
UNCOV
119
        if (!state) {
×
UNCOV
120
            return data;
×
121
        }
UNCOV
122
        const len = dataLength !== undefined ? dataLength : data.length;
×
UNCOV
123
        const index = state.index;
×
UNCOV
124
        const res = [];
×
UNCOV
125
        const recordsPerPage = dataLength !== undefined && state.recordsPerPage > dataLength ? dataLength : state.recordsPerPage;
×
UNCOV
126
        state.metadata = {
×
127
            countPages: 0,
128
            countRecords: len,
129
            error: PagingError.None
130
        };
UNCOV
131
        if (index < 0 || isNaN(index)) {
×
UNCOV
132
            state.metadata.error = PagingError.IncorrectPageIndex;
×
UNCOV
133
            return res;
×
134
        }
UNCOV
135
        if (recordsPerPage <= 0 || isNaN(recordsPerPage)) {
×
UNCOV
136
            state.metadata.error = PagingError.IncorrectRecordsPerPage;
×
UNCOV
137
            return res;
×
138
        }
UNCOV
139
        state.metadata.countPages = Math.ceil(len / recordsPerPage);
×
UNCOV
140
        if (!len) {
×
141
            return data;
×
142
        }
UNCOV
143
        if (index >= state.metadata.countPages) {
×
UNCOV
144
            state.metadata.error = PagingError.IncorrectPageIndex;
×
UNCOV
145
            return res;
×
146
        }
UNCOV
147
        return data.slice(index * recordsPerPage, (index + 1) * recordsPerPage);
×
148
    }
149

150
    public static correctPagingState(state: IPagingState, length: number) {
UNCOV
151
        const maxPage = Math.ceil(length / state.recordsPerPage) - 1;
×
UNCOV
152
        if (!isNaN(maxPage) && state.index > maxPage) {
×
UNCOV
153
            state.index = maxPage;
×
154
        }
155
    }
156

157
    public static getHierarchy(gRow: IGroupByRecord): Array<IGroupByKey> {
UNCOV
158
        return getHierarchy(gRow);
×
159
    }
160

161
    public static isHierarchyMatch(h1: Array<IGroupByKey>, h2: Array<IGroupByKey>, expressions: IGroupingExpression[]): boolean {
UNCOV
162
        return isHierarchyMatch(h1, h2, expressions);
×
163
    }
164

165
    /**
166
     * Merges all changes from provided transactions into provided data collection
167
     *
168
     * @param data Collection to merge
169
     * @param transactions Transactions to merge into data
170
     * @param primaryKey Primary key of the collection, if any
171
     * @param deleteRows Should delete rows with DELETE transaction type from data
172
     * @returns Provided data collections updated with all provided transactions
173
     */
174
    public static mergeTransactions<T>(data: T[], transactions: Transaction[], primaryKey?: any, cloneStrategy: IDataCloneStrategy = new DefaultDataCloneStrategy(), deleteRows = false): T[] {
×
UNCOV
175
        data.forEach((item: any, index: number) => {
×
UNCOV
176
            const rowId = primaryKey ? item[primaryKey] : item;
×
UNCOV
177
            const transaction = transactions.find(t => t.id === rowId);
×
UNCOV
178
            if (transaction && transaction.type === TransactionType.UPDATE) {
×
UNCOV
179
                data[index] = mergeObjects(cloneStrategy.clone(data[index]), transaction.newValue);
×
180
            }
181
        });
182

UNCOV
183
        if (deleteRows) {
×
UNCOV
184
            transactions
×
UNCOV
185
                .filter(t => t.type === TransactionType.DELETE)
×
186
                .forEach(t => {
UNCOV
187
                    const index = primaryKey ? data.findIndex(d => d[primaryKey] === t.id) : data.findIndex(d => d === t.id);
×
UNCOV
188
                    if (0 <= index && index < data.length) {
×
UNCOV
189
                        data.splice(index, 1);
×
190
                    }
191
                });
192
        }
193

UNCOV
194
        data.push(...transactions
×
UNCOV
195
            .filter(t => t.type === TransactionType.ADD)
×
UNCOV
196
            .map(t => t.newValue));
×
197

UNCOV
198
        return data;
×
199
    }
200

201
    /**
202
     * Merges all changes from provided transactions into provided hierarchical data collection
203
     *
204
     * @param data Collection to merge
205
     * @param transactions Transactions to merge into data
206
     * @param childDataKey Data key of child collections
207
     * @param primaryKey Primary key of the collection, if any
208
     * @param deleteRows Should delete rows with DELETE transaction type from data
209
     * @returns Provided data collections updated with all provided transactions
210
     */
211
    public static mergeHierarchicalTransactions(
212
        data: any[],
213
        transactions: HierarchicalTransaction[],
214
        childDataKey: any,
215
        primaryKey?: any,
216
        cloneStrategy: IDataCloneStrategy = new DefaultDataCloneStrategy(),
×
217
        deleteRows = false): any[] {
×
UNCOV
218
        for (const transaction of transactions) {
×
UNCOV
219
            if (transaction.path) {
×
UNCOV
220
                const parent = this.findParentFromPath(data, primaryKey, childDataKey, transaction.path);
×
UNCOV
221
                let collection: any[] = parent ? parent[childDataKey] : data;
×
UNCOV
222
                switch (transaction.type) {
×
223
                    case TransactionType.ADD:
224
                        //  if there is no parent this is ADD row at root level
UNCOV
225
                        if (parent && !parent[childDataKey]) {
×
UNCOV
226
                            parent[childDataKey] = collection = [];
×
227
                        }
UNCOV
228
                        collection.push(transaction.newValue);
×
UNCOV
229
                        break;
×
230
                    case TransactionType.UPDATE:
UNCOV
231
                        const updateIndex = collection.findIndex(x => x[primaryKey] === transaction.id);
×
UNCOV
232
                        if (updateIndex !== -1) {
×
UNCOV
233
                            collection[updateIndex] = mergeObjects(cloneStrategy.clone(collection[updateIndex]), transaction.newValue);
×
234
                        }
UNCOV
235
                        break;
×
236
                    case TransactionType.DELETE:
UNCOV
237
                        if (deleteRows) {
×
UNCOV
238
                            const deleteIndex = collection.findIndex(r => r[primaryKey] === transaction.id);
×
UNCOV
239
                            if (deleteIndex !== -1) {
×
UNCOV
240
                                collection.splice(deleteIndex, 1);
×
241
                            }
242
                        }
UNCOV
243
                        break;
×
244
                }
245
            } else {
246
                //  if there is no path this is ADD row in root. Push the newValue to data
UNCOV
247
                data.push(transaction.newValue);
×
248
            }
249
        }
UNCOV
250
        return data;
×
251
    }
252

253
    public static parseValue(dataType: GridColumnDataType, value: any): any {
UNCOV
254
        if (dataType === GridColumnDataType.Number || dataType === GridColumnDataType.Currency || dataType === GridColumnDataType.Percent) {
×
UNCOV
255
            value = parseFloat(value);
×
256
        }
257

UNCOV
258
        return value;
×
259
    }
260

261
    public static filterDataByExpressions(data: any[], expressionsTree: IFilteringExpressionsTree, grid: GridTypeBase): any {
UNCOV
262
        if (expressionsTree.filteringOperands.length) {
×
263
            const state = { expressionsTree, strategy: FilteringStrategy.instance() };
×
264
            data = FilterUtil.filter(cloneArray(data), state, grid);
×
265
        }
266

UNCOV
267
        return data;
×
268
    }
269

270
    private static findParentFromPath(data: any[], primaryKey: any, childDataKey: any, path: any[]): any {
UNCOV
271
        let collection: any[] = data;
×
272
        let result: any;
273

UNCOV
274
        for (const id of path) {
×
UNCOV
275
            result = collection && collection.find(x => x[primaryKey] === id);
×
UNCOV
276
            if (!result) {
×
277
                break;
×
278
            }
279

UNCOV
280
            collection = result[childDataKey];
×
281
        }
282

UNCOV
283
        return result;
×
284
    }
285
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc