@sankhyalabs/core 5.20.0-dev.69 → 5.20.0-dev.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docs/classes/ColumnFilterManager.md +145 -0
- package/.docs/classes/DataUnitInMemoryLoader.md +303 -0
- package/.docs/classes/DataUnitLoaderUtils.md +151 -0
- package/.docs/classes/FieldComparator.md +2 -2
- package/.docs/enumerations/RECORD_DATE_FORMAT.md +27 -0
- package/.docs/globals.md +6 -0
- package/.docs/interfaces/DataUnitInMemoryLoaderConfig.md +37 -0
- package/.docs/interfaces/PaginationInfoBuilderParams.md +37 -0
- package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.d.ts +9 -0
- package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js +6 -0
- package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js.map +1 -0
- package/dist/dataunit/loader/dataUnitInMemoryLoader.d.ts +25 -0
- package/dist/dataunit/loader/dataUnitInMemoryLoader.js +131 -0
- package/dist/dataunit/loader/dataUnitInMemoryLoader.js.map +1 -0
- package/dist/dataunit/loader/utils/dataUnitLoaderUtils.d.ts +20 -0
- package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js +62 -0
- package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js.map +1 -0
- package/dist/dataunit/sorting/FieldComparator.d.ts +2 -2
- package/dist/dataunit/sorting/FieldComparator.js +4 -9
- package/dist/dataunit/sorting/FieldComparator.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/ColumnFilterManager.d.ts +19 -0
- package/dist/utils/ColumnFilterManager.js +73 -0
- package/dist/utils/ColumnFilterManager.js.map +1 -0
- package/package.json +1 -1
- package/reports/test-report.xml +136 -96
- package/src/dataunit/loader/DataUnitInMemoryLoaderConfig.ts +10 -0
- package/src/dataunit/loader/dataUnitInMemoryLoader.ts +176 -0
- package/src/dataunit/loader/utils/dataUnitLoaderUtils.ts +86 -0
- package/src/dataunit/sorting/FieldComparator.ts +18 -32
- package/src/index.ts +11 -1
- package/src/utils/ColumnFilterManager.ts +104 -0
- package/test/dataunit/loader/dataUnitInMemoryLoader.spec.ts +221 -0
- package/test/dataunit/loader/utils/dataUnitLoaderUtils.spec.ts +158 -0
- package/test/util/ColumnFilterManager.spec.ts +133 -0
|
@@ -1,38 +1,24 @@
|
|
|
1
|
-
import { Record } from
|
|
2
|
-
import { compareValues } from
|
|
3
|
-
import { FieldDescriptor } from
|
|
1
|
+
import { Record } from '../DataUnit.js';
|
|
2
|
+
import { compareValues } from '../metadata/DataType.js';
|
|
3
|
+
import { FieldDescriptor } from '../metadata/UnitMetadata.js';
|
|
4
4
|
|
|
5
|
-
export class FieldComparator{
|
|
5
|
+
export class FieldComparator {
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
public static compare(field: FieldDescriptor, recordA: Record, recordB: Record, asc: boolean = true): number {
|
|
8
|
+
const valueA = (asc ? recordA : recordB)[field.name];
|
|
9
|
+
const valueB = (asc ? recordB : recordA)[field.name];
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
return FieldComparator.compareValues(field, valueA, valueB);
|
|
12
|
+
}
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
public static compareValues(descriptor: FieldDescriptor, valueA: any, valueB: any): number{
|
|
17
|
-
const undefinedComparison = this.compareUndefined(valueA == undefined, valueB == undefined);
|
|
18
|
-
|
|
19
|
-
if(undefinedComparison != undefined){
|
|
20
|
-
return undefinedComparison;
|
|
21
|
-
}
|
|
14
|
+
public static compareValues(descriptor: FieldDescriptor, valueA: any, valueB: any): number {
|
|
15
|
+
const undefinedComparison = this.compareUndefined(valueA == undefined, valueB == undefined);
|
|
16
|
+
return (undefinedComparison != undefined) ? undefinedComparison : compareValues(valueA, valueB, descriptor);
|
|
17
|
+
}
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if(!isUndefinedA && !isUndefinedB){
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if(isUndefinedA && isUndefinedB){
|
|
33
|
-
return 0;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return isUndefinedA ? -1 : 1;
|
|
37
|
-
}
|
|
19
|
+
public static compareUndefined(isUndefinedA: boolean, isUndefinedB: boolean): number | undefined {
|
|
20
|
+
if (!isUndefinedA && !isUndefinedB) return;
|
|
21
|
+
if (isUndefinedA && isUndefinedB) return 0;
|
|
22
|
+
return isUndefinedA ? -1 : 1;
|
|
23
|
+
}
|
|
38
24
|
}
|
package/src/index.ts
CHANGED
|
@@ -45,6 +45,10 @@ import { ServiceUtils } from "./utils/ServiceUtils.js";
|
|
|
45
45
|
import { StorageType } from "./utils/CacheManager/index.js";
|
|
46
46
|
import OverflowWatcher, { OnOverflowCallBack, OverflowDirection, OverFlowWatcherParams, OVERFLOWED_CLASS_NAME } from "./utils/OverflowWatcher/index.js";
|
|
47
47
|
import {LockManager, LockManagerOperation} from "./utils/LockManager.js";
|
|
48
|
+
import { DataUnitInMemoryLoader } from "./dataunit/loader/dataUnitInMemoryLoader.js";
|
|
49
|
+
import { DataUnitLoaderUtils, PaginationInfoBuilderParams } from "./dataunit/loader/utils/dataUnitLoaderUtils.js";
|
|
50
|
+
import { ColumnFilterManager } from "./utils/ColumnFilterManager.js";
|
|
51
|
+
import { DataUnitInMemoryLoaderConfig, RECORD_DATE_FORMAT } from "./dataunit/loader/DataUnitInMemoryLoaderConfig.js";
|
|
48
52
|
|
|
49
53
|
/*Classes públicas no pacote*/
|
|
50
54
|
export {
|
|
@@ -123,5 +127,11 @@ export {
|
|
|
123
127
|
OVERFLOWED_CLASS_NAME,
|
|
124
128
|
DataUnitEventOptions,
|
|
125
129
|
ServiceCanceledException,
|
|
126
|
-
SilentException
|
|
130
|
+
SilentException,
|
|
131
|
+
DataUnitInMemoryLoader,
|
|
132
|
+
DataUnitLoaderUtils,
|
|
133
|
+
PaginationInfoBuilderParams,
|
|
134
|
+
ColumnFilterManager,
|
|
135
|
+
DataUnitInMemoryLoaderConfig,
|
|
136
|
+
RECORD_DATE_FORMAT
|
|
127
137
|
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Filter } from '../dataunit/metadata/UnitMetadata.js';
|
|
2
|
+
import DataUnit, { Record } from '../dataunit/DataUnit.js';
|
|
3
|
+
import { FieldComparator } from '../dataunit/sorting/FieldComparator.js';
|
|
4
|
+
import { LoadDataRequest } from '../dataunit/loading/LoadDataRequest.js';
|
|
5
|
+
|
|
6
|
+
const COLUMN_FILTER_PATTERN = /FILTRO_COLUNA_(.+)/;
|
|
7
|
+
|
|
8
|
+
export class ColumnFilterManager {
|
|
9
|
+
|
|
10
|
+
public static getColumnFilters(filters: Array<Filter>, fieldName: string): Map<string, IColumnFilter> {
|
|
11
|
+
const columnFilters: Map<string, IColumnFilter> = new Map();
|
|
12
|
+
|
|
13
|
+
if (!filters?.length) {
|
|
14
|
+
return columnFilters;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
filters.forEach(filter => {
|
|
18
|
+
const result = COLUMN_FILTER_PATTERN.exec(filter.name);
|
|
19
|
+
if (result) {
|
|
20
|
+
if (fieldName !== result[1]) {
|
|
21
|
+
columnFilters.set(filter.name, { columnName: result[1], ...filter });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return columnFilters;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public static getFilterFunction(dataUnit: DataUnit, filters?: Array<IColumnFilter>): ((record: Record) => boolean) | undefined {
|
|
30
|
+
if (!filters?.length) return undefined;
|
|
31
|
+
|
|
32
|
+
return record => {
|
|
33
|
+
for (const filter of filters) {
|
|
34
|
+
if (!ColumnFilterManager.recordMatchesFilter(dataUnit, record, filter)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private static recordMatchesFilter(dataUnit: DataUnit, record: Record, columnFilter: IColumnFilter): boolean {
|
|
43
|
+
const fieldDescriptor = dataUnit.getField(columnFilter.columnName);
|
|
44
|
+
|
|
45
|
+
if (!columnFilter.params || !fieldDescriptor) return false;
|
|
46
|
+
|
|
47
|
+
const fieldValue = record[columnFilter.columnName];
|
|
48
|
+
|
|
49
|
+
for (let param of columnFilter.params) {
|
|
50
|
+
const paramValue = dataUnit.valueFromString(columnFilter.columnName, param.value);
|
|
51
|
+
if (FieldComparator.compareValues(fieldDescriptor, fieldValue, paramValue) === 0) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public static compileDistinct(fieldName: string, dataUnit: DataUnit): Array<IMultiSelectionOption> {
|
|
60
|
+
const request = dataUnit.getLastLoadRequest();
|
|
61
|
+
let list = dataUnit.records;
|
|
62
|
+
return this.doCompileDistinct(request, fieldName, dataUnit, list);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public static compileDistinctFromArray(fieldName: string, dataUnit: DataUnit, records: Array<Record>): Array<IMultiSelectionOption> {
|
|
66
|
+
const request = dataUnit.getLastLoadRequest();
|
|
67
|
+
return this.doCompileDistinct(request, fieldName, dataUnit, records);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private static doCompileDistinct(request: LoadDataRequest | undefined, fieldName: string, dataUnit: DataUnit, list: Array<Record>) {
|
|
71
|
+
if (request != undefined) {
|
|
72
|
+
const columnFilters: Array<IColumnFilter> = Array.from(ColumnFilterManager.getColumnFilters(request?.filters ?? [], fieldName).values());
|
|
73
|
+
const filterFunction = ColumnFilterManager.getFilterFunction(dataUnit, columnFilters);
|
|
74
|
+
if (filterFunction != undefined) {
|
|
75
|
+
list = list.filter(filterFunction);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const distinct: Map<string, IMultiSelectionOption> = new Map(
|
|
80
|
+
list.map(record => {
|
|
81
|
+
const fieldValue = record[fieldName];
|
|
82
|
+
if (fieldValue == undefined) {
|
|
83
|
+
return [null, { label: null, value: null, check: true }];
|
|
84
|
+
}
|
|
85
|
+
const item = { label: dataUnit.getFormattedValue(fieldName, fieldValue), value: fieldValue, check: true };
|
|
86
|
+
return [item.label, item];
|
|
87
|
+
}) as any,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return Array.from(distinct.values());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
interface IMultiSelectionOption {
|
|
97
|
+
value: string;
|
|
98
|
+
label: string;
|
|
99
|
+
check: boolean;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface IColumnFilter extends Filter {
|
|
103
|
+
columnName: string;
|
|
104
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { DataUnitInMemoryLoader } from '../../../src/dataunit/loader/dataUnitInMemoryLoader.js';
|
|
2
|
+
import {
|
|
3
|
+
DataUnitInMemoryLoaderConfig,
|
|
4
|
+
RECORD_DATE_FORMAT,
|
|
5
|
+
} from '../../../src/dataunit/loader/DataUnitInMemoryLoaderConfig.js';
|
|
6
|
+
import { FieldDescriptor, UnitMetadata } from '../../../src/dataunit/metadata/UnitMetadata.js';
|
|
7
|
+
import { DataType } from '../../../src/dataunit/metadata/DataType.js';
|
|
8
|
+
import DateUtils from '../../../src/utils/DateUtils.js';
|
|
9
|
+
import DataUnit, { Record } from '../../../src/dataunit/DataUnit.js';
|
|
10
|
+
|
|
11
|
+
describe('DataUnitInMemoryLoader - loadData', () => {
|
|
12
|
+
const dataUnitMetetadata: UnitMetadata = {
|
|
13
|
+
name: 'test',
|
|
14
|
+
label: 'test',
|
|
15
|
+
fields: [],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
it('should be called load data when auto load is true', async () => {
|
|
19
|
+
const config: DataUnitInMemoryLoaderConfig = {
|
|
20
|
+
autoLoad: true,
|
|
21
|
+
};
|
|
22
|
+
const inMemoryLoader = new DataUnitInMemoryLoader(dataUnitMetetadata, [], config);
|
|
23
|
+
const loadData = jest.spyOn(inMemoryLoader.dataUnit, 'loadData');
|
|
24
|
+
await inMemoryLoader.dataUnit.loadMetadata();
|
|
25
|
+
expect(loadData).toHaveBeenCalled();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should be called load data when auto load is undefined', async () => {
|
|
29
|
+
const config: DataUnitInMemoryLoaderConfig = {
|
|
30
|
+
autoLoad: undefined,
|
|
31
|
+
};
|
|
32
|
+
const inMemoryLoader = new DataUnitInMemoryLoader(dataUnitMetetadata, [], config);
|
|
33
|
+
const loadData = jest.spyOn(inMemoryLoader.dataUnit, 'loadData');
|
|
34
|
+
await inMemoryLoader.dataUnit.loadMetadata();
|
|
35
|
+
expect(loadData).toHaveBeenCalled();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should not be called load data when auto load is false', async () => {
|
|
39
|
+
const config: DataUnitInMemoryLoaderConfig = {
|
|
40
|
+
autoLoad: false,
|
|
41
|
+
};
|
|
42
|
+
const inMemoryLoader = new DataUnitInMemoryLoader(dataUnitMetetadata, [], config);
|
|
43
|
+
const loadData = jest.spyOn(inMemoryLoader.dataUnit, 'loadData');
|
|
44
|
+
await inMemoryLoader.dataUnit.loadMetadata();
|
|
45
|
+
expect(loadData).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should be called load data when config is undefined', async () => {
|
|
49
|
+
const inMemoryLoader = new DataUnitInMemoryLoader(dataUnitMetetadata, []);
|
|
50
|
+
const loadData = jest.spyOn(inMemoryLoader.dataUnit, 'loadData');
|
|
51
|
+
await inMemoryLoader.dataUnit.loadMetadata();
|
|
52
|
+
expect(loadData).toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('DataUnitInMemoryLoader - getConvertedValue', () => {
|
|
57
|
+
let descriptor: FieldDescriptor;
|
|
58
|
+
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
descriptor = { name: 'testField', dataType: DataType.TEXT, label: 'mock' }; // Valor padrão para inicialização
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should return the original string if descriptor is undefined', () => {
|
|
64
|
+
const result = DataUnitInMemoryLoader.getConvertedValue(undefined as any, 'testValue');
|
|
65
|
+
expect(result).toBe('testValue');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should return the original string if dataType is TEXT', () => {
|
|
69
|
+
descriptor.dataType = DataType.TEXT;
|
|
70
|
+
const result = DataUnitInMemoryLoader.getConvertedValue(descriptor, 'testValue');
|
|
71
|
+
expect(result).toBe('testValue');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should convert to boolean when dataType is BOOLEAN', () => {
|
|
75
|
+
descriptor.dataType = DataType.BOOLEAN;
|
|
76
|
+
expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, 'S')).toBe(true);
|
|
77
|
+
expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, 'N')).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should convert to number when dataType is NUMBER', () => {
|
|
81
|
+
descriptor.dataType = DataType.NUMBER;
|
|
82
|
+
expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, '123')).toBe(123);
|
|
83
|
+
expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, '45.67')).toBe(45.67);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should parse JSON when dataType is OBJECT', () => {
|
|
87
|
+
descriptor.dataType = DataType.OBJECT;
|
|
88
|
+
const jsonString = '{"key": "value"}';
|
|
89
|
+
const expectedObject = { key: 'value' };
|
|
90
|
+
expect(DataUnitInMemoryLoader.getConvertedValue(descriptor, jsonString)).toEqual(expectedObject);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should convert to date when dataType is DATE and format is ISO', () => {
|
|
94
|
+
descriptor.dataType = DataType.DATE;
|
|
95
|
+
|
|
96
|
+
const isoDate = '2023-01-01T00:00:00Z';
|
|
97
|
+
jest.spyOn(DateUtils, 'validateDate').mockImplementation((date) => date);
|
|
98
|
+
|
|
99
|
+
const result = DataUnitInMemoryLoader.getConvertedValue(descriptor, isoDate, RECORD_DATE_FORMAT.ISO);
|
|
100
|
+
expect(DateUtils.validateDate).toHaveBeenCalledWith(new Date(isoDate), true);
|
|
101
|
+
expect(result).toEqual(new Date(isoDate));
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should convert to date when dataType is DATE and format is not ISO', () => {
|
|
105
|
+
descriptor.dataType = DataType.DATE;
|
|
106
|
+
|
|
107
|
+
const dateString = '01/01/2023';
|
|
108
|
+
jest.spyOn(DateUtils, 'strToDate').mockImplementation(() => new Date(2023, 0, 1));
|
|
109
|
+
|
|
110
|
+
const result = DataUnitInMemoryLoader.getConvertedValue(descriptor, dateString, RECORD_DATE_FORMAT.DD_MM_YYYY);
|
|
111
|
+
expect(DateUtils.strToDate).toHaveBeenCalledWith(dateString, true);
|
|
112
|
+
expect(result).toEqual(new Date(2023, 0, 1));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should return the original string if no dataType matches', () => {
|
|
116
|
+
descriptor.dataType = undefined as any; // Simula um caso inválido
|
|
117
|
+
const result = DataUnitInMemoryLoader.getConvertedValue(descriptor, 'testValue');
|
|
118
|
+
expect(result).toBe('testValue');
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('DataUnitInMemoryLoader - removeLoader', () => {
|
|
123
|
+
let loader: DataUnitInMemoryLoader;
|
|
124
|
+
const mockedDataUnit = {} as DataUnit;
|
|
125
|
+
|
|
126
|
+
beforeEach(() => {
|
|
127
|
+
loader = new DataUnitInMemoryLoader();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should resolve with the provided record IDs', async () => {
|
|
131
|
+
const mockRecordIds = ['record1', 'record2', 'record3'];
|
|
132
|
+
|
|
133
|
+
const result = await loader.removeLoader(mockedDataUnit, mockRecordIds);
|
|
134
|
+
|
|
135
|
+
expect(result).toEqual(mockRecordIds);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should handle empty record ID array', async () => {
|
|
139
|
+
const mockRecordIds: string[] = [];
|
|
140
|
+
|
|
141
|
+
const result = await loader.removeLoader(mockedDataUnit, mockRecordIds);
|
|
142
|
+
|
|
143
|
+
expect(result).toEqual([]);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should resolve the promise', async () => {
|
|
147
|
+
const mockRecordIds = ['record1'];
|
|
148
|
+
|
|
149
|
+
await expect(loader.removeLoader(mockedDataUnit, mockRecordIds)).resolves.toEqual(mockRecordIds);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('DataUnitInMemoryLoader - buildInitialRecords (indiretamente via set records)', () => {
|
|
154
|
+
let loader: DataUnitInMemoryLoader;
|
|
155
|
+
let mockRecords: Array<Record> = [
|
|
156
|
+
{ id: '1', amount: '100', isActive: 'S', createdAt: '01/01/2023' },
|
|
157
|
+
{ id: '2', amount: '200.50', isActive: 'N', createdAt: '02/01/2023' },
|
|
158
|
+
] as unknown as Record[];
|
|
159
|
+
|
|
160
|
+
let mockMetadata = {
|
|
161
|
+
fields: [
|
|
162
|
+
{ name: 'id', label: 'id', dataType: DataType.TEXT },
|
|
163
|
+
{ name: 'amount', label: 'amount', dataType: DataType.NUMBER },
|
|
164
|
+
{ name: 'isActive', label: 'isActive', dataType: DataType.BOOLEAN },
|
|
165
|
+
{ name: 'createdAt', label: 'createdAt', dataType: DataType.DATE },
|
|
166
|
+
],
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
beforeEach(() => {
|
|
170
|
+
loader = new DataUnitInMemoryLoader(mockMetadata as any, [], { recordDateFormat: RECORD_DATE_FORMAT.DD_MM_YYYY });
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should build initial records and convert field values based on metadata', () => {
|
|
174
|
+
loader.records = mockRecords;
|
|
175
|
+
const initialRecords = loader['_initialRecords'];
|
|
176
|
+
|
|
177
|
+
expect(initialRecords).toHaveLength(2);
|
|
178
|
+
|
|
179
|
+
expect(initialRecords[0]).toEqual({
|
|
180
|
+
id: '1',
|
|
181
|
+
amount: 100,
|
|
182
|
+
isActive: true,
|
|
183
|
+
createdAt: expect.any(Date),
|
|
184
|
+
__record__id__: expect.any(String),
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(initialRecords[1]).toEqual({
|
|
188
|
+
id: '2',
|
|
189
|
+
amount: 200.5,
|
|
190
|
+
isActive: false,
|
|
191
|
+
createdAt: expect.any(Date),
|
|
192
|
+
__record__id__: expect.any(String),
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should generate unique IDs for records without "__record__id__"', () => {
|
|
197
|
+
loader.records = [{ id: '3', amount: '300' }] as unknown as Record[];
|
|
198
|
+
|
|
199
|
+
const builtRecords = loader['_initialRecords'];
|
|
200
|
+
expect(builtRecords).toHaveLength(1);
|
|
201
|
+
|
|
202
|
+
expect(builtRecords[0]).toHaveProperty('__record__id__');
|
|
203
|
+
expect(typeof builtRecords[0]['__record__id__']).toBe('string');
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should leave fields untouched if no matching metadata exists', () => {
|
|
207
|
+
mockRecords[0]['extraField'] = 'unchanged';
|
|
208
|
+
loader.records = mockRecords;
|
|
209
|
+
|
|
210
|
+
const builtRecords = loader['_initialRecords'];
|
|
211
|
+
expect(builtRecords[0]).toHaveProperty('extraField', 'unchanged');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('should skip conversion for non-string field values', () => {
|
|
215
|
+
mockRecords[0].amount = 500;
|
|
216
|
+
loader.records = mockRecords;
|
|
217
|
+
|
|
218
|
+
const builtRecords = loader['_initialRecords'];
|
|
219
|
+
expect(builtRecords[0].amount).toBe(500);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
jest.mock('../../../../src/utils/ColumnFilterManager', () => ({
|
|
2
|
+
ColumnFilterManager: {
|
|
3
|
+
getColumnFilters: jest.fn(),
|
|
4
|
+
getFilterFunction: jest.fn(),
|
|
5
|
+
},
|
|
6
|
+
}));
|
|
7
|
+
|
|
8
|
+
jest.mock('../../../../src/utils/SortingUtils', () => {
|
|
9
|
+
return {
|
|
10
|
+
__esModule: true, // Indica que este módulo possui uma exportação padrão
|
|
11
|
+
default: {
|
|
12
|
+
getSortingFunction: jest.fn(),
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import { DataUnitLoaderUtils } from '../../../../src/dataunit/loader/utils/dataUnitLoaderUtils';
|
|
19
|
+
import { IColumnFilter } from '../../../../src/utils/ColumnFilterManager';
|
|
20
|
+
import { Record } from '../../../../src/dataunit/DataUnit';
|
|
21
|
+
import { Filter, Sort, SortMode } from '../../../../src/dataunit/metadata/UnitMetadata';
|
|
22
|
+
import { DataType } from '../../../../src/dataunit/metadata/DataType';
|
|
23
|
+
import { ColumnFilterManager } from '../../../../src/utils/ColumnFilterManager';
|
|
24
|
+
import SortingUtils from '../../../../src/utils/SortingUtils';
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
describe('Utility Functions', () => {
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
jest.clearAllMocks();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('applyFilter', () => {
|
|
33
|
+
it('should return the original records if no filters are provided', () => {
|
|
34
|
+
const records: Record[] = [{ __record__id__: '1' }, { __record__id__: '2' }];
|
|
35
|
+
const filters: Filter[] = [];
|
|
36
|
+
const columnFilterMock = new Map<string, IColumnFilter>();
|
|
37
|
+
|
|
38
|
+
(ColumnFilterManager.getColumnFilters as jest.Mock).mockReturnValue(columnFilterMock);
|
|
39
|
+
(ColumnFilterManager.getFilterFunction as jest.Mock).mockReturnValue(undefined);
|
|
40
|
+
|
|
41
|
+
const result = DataUnitLoaderUtils.applyFilter(records, {} as any, filters);
|
|
42
|
+
|
|
43
|
+
expect(result).toEqual(records);
|
|
44
|
+
expect(ColumnFilterManager.getColumnFilters).toHaveBeenCalledWith(filters, '');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should filter records based on provided filters', () => {
|
|
48
|
+
const records: Record[] = [{ __record__id__: '1' }, { __record__id__: '2' }];
|
|
49
|
+
const filters: Filter[] = [{ name: 'test', expression: '1' }];
|
|
50
|
+
const columnFilterMock = new Map<string, IColumnFilter>();
|
|
51
|
+
columnFilterMock.set('test', { columnName: 'name', ...filters[0] } as IColumnFilter);
|
|
52
|
+
|
|
53
|
+
(ColumnFilterManager.getColumnFilters as jest.Mock).mockReturnValue(columnFilterMock);
|
|
54
|
+
(ColumnFilterManager.getFilterFunction as jest.Mock).mockReturnValue((record: Record) => record.__record__id__ === '1');
|
|
55
|
+
|
|
56
|
+
const result = DataUnitLoaderUtils.applyFilter(records, {} as any, filters);
|
|
57
|
+
|
|
58
|
+
expect(result).toEqual([{ __record__id__: '1' }]);
|
|
59
|
+
expect(ColumnFilterManager.getFilterFunction).toHaveBeenCalledWith({}, Array.from(columnFilterMock.values()));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('buildPaginationInfo function', () => {
|
|
64
|
+
it('should return correct pagination info with default values', () => {
|
|
65
|
+
|
|
66
|
+
const result = DataUnitLoaderUtils.buildPaginationInfo({
|
|
67
|
+
recordsLength: 0,
|
|
68
|
+
offset: 0,
|
|
69
|
+
recordsPerPage: 5,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(result).toEqual({
|
|
73
|
+
currentPage: 0,
|
|
74
|
+
firstRecord: 0,
|
|
75
|
+
lastRecord: 0,
|
|
76
|
+
total: 0,
|
|
77
|
+
hasMore: false,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should redosLenth as same size as recordsPerPage', () => {
|
|
82
|
+
const result = DataUnitLoaderUtils.buildPaginationInfo({
|
|
83
|
+
recordsLength: 10,
|
|
84
|
+
offset: 0,
|
|
85
|
+
recordsPerPage: 10,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(result).toEqual({
|
|
89
|
+
currentPage: 0,
|
|
90
|
+
firstRecord: 1,
|
|
91
|
+
lastRecord: 10,
|
|
92
|
+
total: 10,
|
|
93
|
+
hasMore: false,
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
it('should handle case when totalRecordsLength and offset 0', () => {
|
|
99
|
+
const result = DataUnitLoaderUtils.buildPaginationInfo({
|
|
100
|
+
recordsLength: 10,
|
|
101
|
+
offset: 0,
|
|
102
|
+
recordsPerPage: 5,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(result).toEqual({
|
|
106
|
+
currentPage: 0,
|
|
107
|
+
firstRecord: 1,
|
|
108
|
+
lastRecord: 5,
|
|
109
|
+
total: 10,
|
|
110
|
+
hasMore: true,
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should handle case when currentPageLength is less than totalRecordsLength and lastPage', () => {
|
|
115
|
+
const result = DataUnitLoaderUtils.buildPaginationInfo({
|
|
116
|
+
recordsLength: 10,
|
|
117
|
+
offset: 5,
|
|
118
|
+
recordsPerPage: 5,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
expect(result).toEqual({
|
|
122
|
+
currentPage: 1,
|
|
123
|
+
firstRecord: 6,
|
|
124
|
+
lastRecord: 10,
|
|
125
|
+
total: 10,
|
|
126
|
+
hasMore: false,
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('applySorting function', () => {
|
|
132
|
+
|
|
133
|
+
it('should return the original records if no sorting is provided', () => {
|
|
134
|
+
const records: Record[] = [{ __record__id__: '1' }, { __record__id__: '2' }];
|
|
135
|
+
const sorting: Sort[] = [];
|
|
136
|
+
|
|
137
|
+
const result = DataUnitLoaderUtils.applySorting(records, {} as any, sorting);
|
|
138
|
+
|
|
139
|
+
expect(result).toEqual(records);
|
|
140
|
+
expect(SortingUtils.getSortingFunction).not.toHaveBeenCalled();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should sort records based on provided sorting criteria', () => {
|
|
144
|
+
const records: Record[] = [{ __record__id__: '2' }, { __record__id__: '1' }];
|
|
145
|
+
const sorting: Sort[] = [{ field: '__record__id__', mode: SortMode.ASC, dataType: DataType.TEXT }];
|
|
146
|
+
|
|
147
|
+
const sortingFunction = (a: Record, b: Record) => (a.__record__id__ > b.__record__id__ ? 1 : -1);
|
|
148
|
+
(SortingUtils.getSortingFunction as jest.Mock).mockReturnValue(sortingFunction);
|
|
149
|
+
|
|
150
|
+
const result = DataUnitLoaderUtils.applySorting(records, {} as any, sorting);
|
|
151
|
+
|
|
152
|
+
expect(result).toEqual([{ __record__id__: '1' }, { __record__id__: '2' }]);
|
|
153
|
+
expect(SortingUtils.getSortingFunction).toHaveBeenCalledWith({}, sorting);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
});
|