@sankhyalabs/core 5.17.4 → 5.18.0-ms.1
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/Change.md +11 -11
- package/.docs/classes/ColumnFilterManager.md +145 -0
- package/.docs/classes/DataUnit.md +334 -136
- package/.docs/classes/DataUnitInMemoryLoader.md +303 -0
- package/.docs/classes/DataUnitLoaderUtils.md +151 -0
- package/.docs/classes/FieldComparator.md +2 -2
- package/.docs/classes/IDBRepository.md +22 -0
- package/.docs/classes/LockManager.md +249 -0
- package/.docs/classes/MaskFormatter.md +66 -14
- package/.docs/classes/ObjectUtils.md +95 -2
- package/.docs/classes/SelectionInfo.md +25 -11
- package/.docs/classes/ServiceUtils.md +67 -0
- package/.docs/classes/SilentException.md +193 -0
- package/.docs/classes/UserAgentUtils.md +15 -1
- package/.docs/enumerations/Action.md +32 -22
- package/.docs/enumerations/ChangeOperation.md +4 -4
- package/.docs/enumerations/LockManagerOperation.md +33 -0
- package/.docs/enumerations/RECORD_DATE_FORMAT.md +27 -0
- package/.docs/enumerations/SelectionMode.md +2 -2
- package/.docs/enumerations/StorageType.md +37 -0
- package/.docs/globals.md +11 -0
- package/.docs/interfaces/DUActionInterceptor.md +1 -1
- package/.docs/interfaces/DataUnitInMemoryLoaderConfig.md +37 -0
- package/.docs/interfaces/IRepository.md +18 -0
- package/.docs/interfaces/LoadDataRequest.md +1 -1
- package/.docs/interfaces/PageRequest.md +3 -3
- package/.docs/interfaces/PaginationInfo.md +25 -0
- package/.docs/interfaces/PaginationInfoBuilderParams.md +37 -0
- package/.docs/interfaces/QuickFilter.md +3 -3
- package/.docs/interfaces/Record.md +4 -4
- package/.docs/interfaces/SavedRecord.md +5 -5
- package/.docs/interfaces/WaitingChange.md +3 -3
- package/.docs/namespaces/MaskFormatter/type-aliases/MaskCharacter.md +1 -1
- package/.docs/namespaces/MaskFormatter/variables/MaskCharacter.md +1 -1
- package/.docs/type-aliases/DataUnitEventOptions.md +1 -1
- package/.releaserc +1 -0
- package/bun.lockb +0 -0
- package/dist/dataunit/DataUnit.d.ts +60 -10
- package/dist/dataunit/DataUnit.js +151 -50
- package/dist/dataunit/DataUnit.js.map +1 -1
- package/dist/dataunit/formatting/PrettyFormatter.js +8 -2
- package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
- 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/loading/LoadDataRequest.d.ts +1 -1
- package/dist/dataunit/loading/PaginationInfo.d.ts +8 -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/dataunit/state/action/DataUnitAction.d.ts +1 -0
- package/dist/dataunit/state/action/DataUnitAction.js +1 -0
- package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
- package/dist/dataunit/state/slice/LoadingControlSlice.js +16 -0
- package/dist/dataunit/state/slice/LoadingControlSlice.js.map +1 -1
- package/dist/dataunit/state/slice/RecordsSlice.js +1 -1
- package/dist/dataunit/state/slice/RecordsSlice.js.map +1 -1
- package/dist/dataunit/state/slice/SelectionSlice.js +2 -2
- package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
- package/dist/exceptions/SilentException.d.ts +14 -0
- package/dist/exceptions/SilentException.js +13 -0
- package/dist/exceptions/SilentException.js.map +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/repository/IRepository.d.ts +6 -0
- package/dist/repository/indexeddb/IDBRepository.d.ts +1 -0
- package/dist/repository/indexeddb/IDBRepository.js +3 -0
- package/dist/repository/indexeddb/IDBRepository.js.map +1 -1
- package/dist/utils/CacheManager/index.d.ts +52 -0
- package/dist/utils/CacheManager/index.js +101 -0
- package/dist/utils/CacheManager/index.js.map +1 -0
- package/dist/utils/CacheManager/interfaces/index.d.ts +5 -0
- package/dist/utils/CacheManager/interfaces/index.js +7 -0
- package/dist/utils/CacheManager/interfaces/index.js.map +1 -0
- package/dist/utils/ColumnFilterManager.d.ts +19 -0
- package/dist/utils/ColumnFilterManager.js +73 -0
- package/dist/utils/ColumnFilterManager.js.map +1 -0
- package/dist/utils/LockManager.d.ts +58 -0
- package/dist/utils/LockManager.js +191 -0
- package/dist/utils/LockManager.js.map +1 -0
- package/dist/utils/MaskFormatter.d.ts +16 -1
- package/dist/utils/MaskFormatter.js +82 -2
- package/dist/utils/MaskFormatter.js.map +1 -1
- package/dist/utils/ObjectUtils.d.ts +24 -0
- package/dist/utils/ObjectUtils.js +33 -0
- package/dist/utils/ObjectUtils.js.map +1 -1
- package/dist/utils/ServiceUtils.d.ts +24 -0
- package/dist/utils/ServiceUtils.js +40 -0
- package/dist/utils/ServiceUtils.js.map +1 -0
- package/dist/utils/SortingUtils.d.ts +9 -0
- package/dist/utils/SortingUtils.js +24 -0
- package/dist/utils/SortingUtils.js.map +1 -0
- package/dist/utils/UserAgentUtils/index.d.ts +1 -0
- package/dist/utils/UserAgentUtils/index.js +5 -0
- package/dist/utils/UserAgentUtils/index.js.map +1 -1
- package/package.json +1 -1
- package/reports/test-report.xml +148 -84
- package/src/dataunit/DataUnit.ts +191 -68
- package/src/dataunit/formatting/PrettyFormatter.ts +10 -2
- 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/loading/LoadDataRequest.ts +1 -1
- package/src/dataunit/loading/PaginationInfo.ts +10 -0
- package/src/dataunit/sorting/FieldComparator.ts +18 -32
- package/src/dataunit/state/action/DataUnitAction.ts +1 -0
- package/src/dataunit/state/slice/LoadingControlSlice.ts +42 -0
- package/src/dataunit/state/slice/RecordsSlice.ts +1 -1
- package/src/dataunit/state/slice/SelectionSlice.ts +2 -2
- package/src/dataunit/state/slice/test/RecordsSlice.spec.ts +45 -0
- package/src/dataunit/test/DataUnit.spec.ts +44 -0
- package/src/exceptions/SilentException.ts +25 -0
- package/src/index.ts +20 -1
- package/src/repository/IRepository.ts +7 -0
- package/src/repository/indexeddb/IDBRepository.ts +4 -0
- package/src/utils/CacheManager/index.ts +103 -0
- package/src/utils/CacheManager/interfaces/index.ts +5 -0
- package/src/utils/ColumnFilterManager.ts +104 -0
- package/src/utils/LockManager.ts +213 -0
- package/src/utils/MaskFormatter.ts +93 -2
- package/src/utils/ObjectUtils.ts +36 -0
- package/src/utils/ServiceUtils.ts +36 -0
- package/src/utils/SortingUtils.ts +30 -0
- package/src/utils/UserAgentUtils/index.ts +6 -1
- package/src/utils/test/objectUtils.spec.ts +109 -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
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Change,
|
|
3
|
+
ChangeOperation,
|
|
4
|
+
DataType,
|
|
5
|
+
DataUnit,
|
|
6
|
+
DateUtils,
|
|
7
|
+
FieldDescriptor,
|
|
8
|
+
LoadDataRequest,
|
|
9
|
+
LoadDataResponse,
|
|
10
|
+
Record,
|
|
11
|
+
SavedRecord,
|
|
12
|
+
StringUtils,
|
|
13
|
+
UnitMetadata,
|
|
14
|
+
} from '../../index.js';
|
|
15
|
+
import { DataUnitInMemoryLoaderConfig, RECORD_DATE_FORMAT } from './DataUnitInMemoryLoaderConfig.js';
|
|
16
|
+
import { DataUnitLoaderUtils } from './utils/dataUnitLoaderUtils.js';
|
|
17
|
+
|
|
18
|
+
export class DataUnitInMemoryLoader {
|
|
19
|
+
private _dataUnit: DataUnit;
|
|
20
|
+
private _metadata: UnitMetadata | undefined;
|
|
21
|
+
private _initialRecords: Array<Record> = [];
|
|
22
|
+
private recordDateFormat: RECORD_DATE_FORMAT;
|
|
23
|
+
public static readonly IN_MEMORY_DATA_UNIT_NAME = 'InMemoryDataUnit';
|
|
24
|
+
public static readonly DEFAULT_PAGE_SIZE = 150;
|
|
25
|
+
|
|
26
|
+
constructor(metadata?: UnitMetadata, records?: Array<Record>, config?: DataUnitInMemoryLoaderConfig) {
|
|
27
|
+
|
|
28
|
+
this.metadata = metadata as UnitMetadata;
|
|
29
|
+
this.recordDateFormat = config?.recordDateFormat ?? RECORD_DATE_FORMAT.DD_MM_YYYY;
|
|
30
|
+
this.records = records ?? [] as Array<Record>;
|
|
31
|
+
|
|
32
|
+
this._dataUnit = new DataUnit(DataUnitInMemoryLoader.IN_MEMORY_DATA_UNIT_NAME);
|
|
33
|
+
this._dataUnit.pageSize = config?.pageSize ?? DataUnitInMemoryLoader.DEFAULT_PAGE_SIZE;
|
|
34
|
+
this._dataUnit.metadataLoader = () => this.metadaLoader();
|
|
35
|
+
this._dataUnit.dataLoader = (dataUnit: DataUnit, request: LoadDataRequest) => this.inMemoryLoader(dataUnit, request, this.getRecordsToLoad());
|
|
36
|
+
this._dataUnit.saveLoader = (_dataUnit: DataUnit, changes: Array<Change>) => this.saveLoader(_dataUnit, changes);
|
|
37
|
+
this._dataUnit.removeLoader = (_dataUnit: DataUnit, recordIds: Array<string>) => this.removeLoader(_dataUnit, recordIds);
|
|
38
|
+
|
|
39
|
+
this.dataUnit.loadMetadata().then(() => {
|
|
40
|
+
if (config?.autoLoad !== false) {
|
|
41
|
+
this.dataUnit.loadData();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private getRecordsToLoad(): Array<Record> {
|
|
47
|
+
if (this._initialRecords == undefined && this.dataUnit.records.length > 0) {
|
|
48
|
+
this._initialRecords = this.dataUnit.records;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const addedRecords = this.dataUnit.getAddedRecords();
|
|
52
|
+
if (addedRecords) {
|
|
53
|
+
return [...this._initialRecords, ...addedRecords];
|
|
54
|
+
}
|
|
55
|
+
return this._initialRecords;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public get dataUnit(): DataUnit {
|
|
59
|
+
return this._dataUnit;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public get records(): Array<Record> {
|
|
63
|
+
return this.dataUnit.records;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public set records(records: Array<Record>) {
|
|
67
|
+
const columns = this.buildColumns();
|
|
68
|
+
|
|
69
|
+
this._initialRecords = this.buildInitialRecords(records, columns);
|
|
70
|
+
|
|
71
|
+
if (!this._dataUnit) return;
|
|
72
|
+
|
|
73
|
+
//Isso força o refresh internamente no datunit
|
|
74
|
+
this._dataUnit.loadData();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public static getConvertedValue(descriptor: FieldDescriptor, strValue: string, dateFormat?: RECORD_DATE_FORMAT) {
|
|
78
|
+
if (!descriptor) return strValue;
|
|
79
|
+
if (descriptor.dataType === DataType.BOOLEAN) return strValue === 'S';
|
|
80
|
+
if (descriptor.dataType === DataType.NUMBER) return Number(strValue);
|
|
81
|
+
if (descriptor.dataType === DataType.OBJECT) return JSON.parse(strValue);
|
|
82
|
+
|
|
83
|
+
if (descriptor.dataType === DataType.DATE) {
|
|
84
|
+
return dateFormat === RECORD_DATE_FORMAT.ISO
|
|
85
|
+
? DateUtils.validateDate(new Date(strValue), true)
|
|
86
|
+
: DateUtils.strToDate(strValue, true);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return strValue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private buildColumns() {
|
|
93
|
+
return this._metadata
|
|
94
|
+
? new Map(this._metadata.fields.map(descriptor => [descriptor.name, descriptor]))
|
|
95
|
+
: undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private buildInitialRecords(records: Array<Record>, columns: Map<string, FieldDescriptor> | undefined) {
|
|
99
|
+
const newRecords = records?.map(record => {
|
|
100
|
+
|
|
101
|
+
if (!record['__record__id__']) {
|
|
102
|
+
record['__record__id__'] = this.generateUniqueId();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!columns) return record;
|
|
106
|
+
|
|
107
|
+
for (const fieldName in record) {
|
|
108
|
+
const value = record[fieldName];
|
|
109
|
+
const fieldDescriptor = columns.get(fieldName);
|
|
110
|
+
|
|
111
|
+
if (typeof value === 'string' && fieldDescriptor) {
|
|
112
|
+
record[fieldName] = DataUnitInMemoryLoader.getConvertedValue(fieldDescriptor, value, this.recordDateFormat);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return record;
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return newRecords;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public get metadata(): UnitMetadata {
|
|
123
|
+
return this._metadata as UnitMetadata;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public set metadata(metadata: UnitMetadata) {
|
|
127
|
+
this._metadata = metadata;
|
|
128
|
+
|
|
129
|
+
if (this._dataUnit) {
|
|
130
|
+
this._dataUnit.metadata = metadata as UnitMetadata;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private generateUniqueId(): string {
|
|
135
|
+
return StringUtils.generateUUID();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private inMemoryLoader(dataUnit: DataUnit, request: LoadDataRequest, recordsIn: Array<Record>): Promise<LoadDataResponse> {
|
|
139
|
+
return DataUnitLoaderUtils.buildLoadDataResponse(recordsIn, dataUnit, request);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private metadaLoader(): Promise<UnitMetadata> {
|
|
143
|
+
return Promise.resolve(this._metadata as UnitMetadata);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private saveLoader(_dataUnit: DataUnit, changes: Array<Change>): Promise<Array<SavedRecord>> {
|
|
147
|
+
return new Promise((resolve) => {
|
|
148
|
+
let dataUnitRecords: SavedRecord[] = [];
|
|
149
|
+
|
|
150
|
+
changes.forEach(change => {
|
|
151
|
+
let { record, updatingFields, operation } = change;
|
|
152
|
+
|
|
153
|
+
const changedRecord = { ...record, ...updatingFields };
|
|
154
|
+
|
|
155
|
+
if (operation === ChangeOperation.INSERT ||
|
|
156
|
+
operation === ChangeOperation.COPY) {
|
|
157
|
+
changedRecord['__old__id__'] = record['__record__id__'];
|
|
158
|
+
changedRecord['__record__id__'] = this.generateUniqueId();
|
|
159
|
+
|
|
160
|
+
this.records.push(changedRecord);
|
|
161
|
+
} else {
|
|
162
|
+
const recordIndex = this.records.findIndex(r => r['__record__id__'] == changedRecord['__record__id__']);
|
|
163
|
+
this.records[recordIndex] = changedRecord;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
dataUnitRecords.push(changedRecord);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
resolve(dataUnitRecords);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public removeLoader(_dataUnit: DataUnit, recordIds: Array<string>): Promise<Array<string>> {
|
|
174
|
+
return new Promise((resolve) => resolve(recordIds));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import DataUnit, { Record } from '../../DataUnit.js';
|
|
2
|
+
import { Filter, Sort } from '../../metadata/UnitMetadata.js';
|
|
3
|
+
import { LoadDataRequest } from '../../loading/LoadDataRequest.js';
|
|
4
|
+
import { PaginationInfo } from '../../loading/PaginationInfo.js';
|
|
5
|
+
import { IColumnFilter, ColumnFilterManager } from '../../../utils/ColumnFilterManager.js';
|
|
6
|
+
import SortingUtils from '../../../utils/SortingUtils.js';
|
|
7
|
+
|
|
8
|
+
export class DataUnitLoaderUtils {
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
public static applyFilter(records: Array<Record>, dataUnit: DataUnit, filters: Array<Filter>): Array<Record> {
|
|
12
|
+
const columnFilters: Map<string, IColumnFilter> = ColumnFilterManager.getColumnFilters(filters, "");
|
|
13
|
+
if (!columnFilters?.size) return records;
|
|
14
|
+
|
|
15
|
+
const filterFunction: ((record: Record) => boolean) | undefined = ColumnFilterManager.getFilterFunction(dataUnit, Array.from(columnFilters.values()));
|
|
16
|
+
return (filterFunction) ? records.filter(filterFunction) : records;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
public static buildLoadDataResponse(recordsIn: Array<Record>, dataUnit: DataUnit, request: LoadDataRequest) {
|
|
21
|
+
let records = recordsIn ? [...recordsIn] : [];
|
|
22
|
+
records = DataUnitLoaderUtils.applyFilter(records, dataUnit, request?.filters ?? []);
|
|
23
|
+
records = DataUnitLoaderUtils.applySorting(records, dataUnit, request?.sort ?? []);
|
|
24
|
+
|
|
25
|
+
const { offset, limit } = request;
|
|
26
|
+
|
|
27
|
+
const paginationInfoBuilderParams = {
|
|
28
|
+
recordsLength: records.length,
|
|
29
|
+
offset,
|
|
30
|
+
recordsPerPage: limit,
|
|
31
|
+
} as PaginationInfoBuilderParams;
|
|
32
|
+
|
|
33
|
+
return Promise.resolve({
|
|
34
|
+
records: DataUnitLoaderUtils.getPagesByRecords(records, offset, limit),
|
|
35
|
+
paginationInfo: dataUnit.pageSize ? DataUnitLoaderUtils.buildPaginationInfo(paginationInfoBuilderParams) : undefined,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
public static applySorting(records: Array<Record>, dataUnit: DataUnit, sorting: Array<Sort>): Array<Record> {
|
|
41
|
+
if (sorting == undefined || sorting.length == 0) {
|
|
42
|
+
return records;
|
|
43
|
+
}
|
|
44
|
+
const sortingFunction = SortingUtils.getSortingFunction(dataUnit, sorting);
|
|
45
|
+
if (sortingFunction == undefined) {
|
|
46
|
+
return records;
|
|
47
|
+
}
|
|
48
|
+
return records.sort(sortingFunction);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public static getPagesByRecords(records: Record[], offset = 0, limit = 0){
|
|
52
|
+
if(!records || !records.length || !this.hasValidLimitAndOffset(offset, limit)) return [];
|
|
53
|
+
if(limit === 0 && offset === 0) return records;
|
|
54
|
+
return records.slice(offset, offset + limit);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private static hasValidLimitAndOffset(offset: number, limit: number) {
|
|
58
|
+
return offset >= 0 && limit >= 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public static buildPaginationInfo({recordsLength = 0, offset = 0, recordsPerPage = 0}: PaginationInfoBuilderParams): PaginationInfo | undefined {
|
|
62
|
+
|
|
63
|
+
if (!recordsLength) {
|
|
64
|
+
return { currentPage: 0, firstRecord: 0, lastRecord: 0, total: 0, hasMore: false };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const lastRecordIndex = offset + recordsPerPage;
|
|
68
|
+
const lastRecord = lastRecordIndex ? Math.min(lastRecordIndex, recordsLength) : recordsLength;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
currentPage: recordsPerPage === 0 ? 0 : Math.ceil(offset / recordsPerPage),
|
|
72
|
+
firstRecord: offset + 1,
|
|
73
|
+
lastRecord: lastRecord,
|
|
74
|
+
total: recordsLength,
|
|
75
|
+
hasMore: lastRecord < recordsLength,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
export interface PaginationInfoBuilderParams {
|
|
83
|
+
recordsLength: number,
|
|
84
|
+
offset: number,
|
|
85
|
+
recordsPerPage: number
|
|
86
|
+
}
|
|
@@ -4,7 +4,7 @@ import { Filter, Sort } from "../metadata/UnitMetadata.js";
|
|
|
4
4
|
/** Atributos enviados na requisição de carregamento dos registros */
|
|
5
5
|
export interface LoadDataRequest {
|
|
6
6
|
/** De onde partiu o refresh. Por padrão a fonte não é identificada */
|
|
7
|
-
source?:
|
|
7
|
+
source?: string;
|
|
8
8
|
|
|
9
9
|
/** Indice inicial dos registros que será retornado */
|
|
10
10
|
offset?: number;
|
|
@@ -18,4 +18,14 @@ export interface PaginationInfo {
|
|
|
18
18
|
|
|
19
19
|
/** Se ainda existem mais registros */
|
|
20
20
|
hasMore: boolean;
|
|
21
|
+
|
|
22
|
+
/** Informa se o carregamento de dados em background está sendo executado
|
|
23
|
+
* Caso o dataunit não tenha carga paralela o valor será indefinido
|
|
24
|
+
*/
|
|
25
|
+
loadingInProgress?: boolean;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Informa se deve exibir diálogo para cancelar carregamento de registros
|
|
29
|
+
*/
|
|
30
|
+
askRowsLimit?: number;
|
|
21
31
|
}
|
|
@@ -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
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
|
|
2
|
+
import { ChangeOperation } from "../../DataUnit.js";
|
|
2
3
|
import { LoadDataRequest } from "../../loading/LoadDataRequest.js";
|
|
3
4
|
import { PaginationInfo } from "../../loading/PaginationInfo.js";
|
|
4
5
|
import { Action } from "../action/DataUnitAction.js";
|
|
@@ -16,6 +17,9 @@ class LoadingControlReducerImpl implements ActionReducer {
|
|
|
16
17
|
return {...currentState, paginationInfo: action.payload?.paginationInfo};
|
|
17
18
|
case Action.PAGINATION_UPDATED:
|
|
18
19
|
return {...currentState, paginationInfo: action.payload};
|
|
20
|
+
case Action.DATA_SAVED:
|
|
21
|
+
return {...currentState, paginationInfo: updatePaginationInfo(stateManager, action.payload)};
|
|
22
|
+
|
|
19
23
|
}
|
|
20
24
|
return currentState;
|
|
21
25
|
}
|
|
@@ -56,7 +60,45 @@ export const hasPreviousPages = (stateManager: StateManager): boolean => {
|
|
|
56
60
|
return paginationInfo ? paginationInfo.currentPage > 0 : false;
|
|
57
61
|
}
|
|
58
62
|
|
|
63
|
+
const updatePaginationInfo = (stateManager: StateManager, payload: Payload): PaginationInfo =>{
|
|
64
|
+
const paginationInfo = getPaginationInfo(stateManager);
|
|
65
|
+
let { records, changes } = payload;
|
|
66
|
+
|
|
67
|
+
if(!records || !changes || !paginationInfo || !validateNewRecordOperation(changes)) return paginationInfo as PaginationInfo;
|
|
68
|
+
|
|
69
|
+
const { count, firstRecord, lastRecord, total } = paginationInfo;
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
...paginationInfo,
|
|
73
|
+
count: (count ?? 0) + records.length,
|
|
74
|
+
firstRecord: firstRecord === 0 && records.length > 0 ? 1 : firstRecord,
|
|
75
|
+
lastRecord: lastRecord + records.length,
|
|
76
|
+
total: (total ?? 0) + records.length
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const validateNewRecordOperation = (changes: Array<Change>): boolean => {
|
|
82
|
+
return changes.every(change => isNewRecordOperation(change._operation));
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const isNewRecordOperation = (operation: string): operation is ChangeOperation => {
|
|
86
|
+
return ["INSERT", "COPY"].includes(operation);
|
|
87
|
+
};
|
|
88
|
+
|
|
59
89
|
interface LoadingControlState{
|
|
60
90
|
lastRequest: LoadDataRequest;
|
|
61
91
|
paginationInfo: PaginationInfo;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface Change {
|
|
95
|
+
dataUnit: string;
|
|
96
|
+
record: Record<string, any>;
|
|
97
|
+
updatingFields: Record<string, any>;
|
|
98
|
+
_operation: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
interface Payload {
|
|
102
|
+
changes: Change[];
|
|
103
|
+
records: Record<string, any>[];
|
|
62
104
|
}
|
|
@@ -47,7 +47,7 @@ class RecordsReducerImpl implements ActionReducer {
|
|
|
47
47
|
newRecords.push(newRecord);
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
|
-
return
|
|
50
|
+
return Array.from(recordsMap.values()).concat(newRecords);
|
|
51
51
|
|
|
52
52
|
case Action.RECORD_LOADED:
|
|
53
53
|
action.payload.forEach((record: any) => {
|
|
@@ -94,8 +94,8 @@ export const getSelection = (stateManager: StateManager): Array<string> => {
|
|
|
94
94
|
export const getSelectionInfo = (stateManager: StateManager): SelectionInfo => {
|
|
95
95
|
|
|
96
96
|
const selection = getSelectionState(stateManager);
|
|
97
|
+
const currentRequest = getCurrentRequest(stateManager);
|
|
97
98
|
if(selection && selection.mode === SelectionMode.ALL_RECORDS){
|
|
98
|
-
const currentRequest = getCurrentRequest(stateManager);
|
|
99
99
|
const paginationInfo: PaginationInfo | undefined = getPaginationInfo(stateManager);
|
|
100
100
|
return new SelectionInfo(
|
|
101
101
|
[],
|
|
@@ -106,7 +106,7 @@ export const getSelectionInfo = (stateManager: StateManager): SelectionInfo => {
|
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
return new SelectionInfo(getSelectionRecords(stateManager) || [], SelectionMode.SOME_RECORDS, undefined);
|
|
109
|
+
return new SelectionInfo(getSelectionRecords(stateManager) || [], SelectionMode.SOME_RECORDS, undefined, undefined, currentRequest?.sort);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
export const hasNext = (stateManager: StateManager): boolean => {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
|
|
2
|
+
import * as RecordsReducerModule from '../RecordsSlice';
|
|
3
|
+
import StateManager from '../../StateManager';
|
|
4
|
+
import { Record } from '../../../DataUnit';
|
|
5
|
+
import { Action } from '../../action/DataUnitAction';
|
|
6
|
+
|
|
7
|
+
jest.spyOn(RecordsReducerModule, "getRecords").mockImplementation(() => [
|
|
8
|
+
{
|
|
9
|
+
__record__id__: '0',
|
|
10
|
+
}, {
|
|
11
|
+
__record__id__: '1',
|
|
12
|
+
}]);
|
|
13
|
+
|
|
14
|
+
describe('RecordsSlice', () => {
|
|
15
|
+
let stateManager: StateManager;
|
|
16
|
+
let currentState: Array<Record>;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
stateManager = new StateManager([RecordsReducerModule.RecordsReducer]);
|
|
20
|
+
currentState = [{
|
|
21
|
+
__record__id__: '0',
|
|
22
|
+
}, {
|
|
23
|
+
__record__id__: '1',
|
|
24
|
+
}]
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should return newlines at the end', () => {
|
|
28
|
+
let records = RecordsReducerModule.RecordsReducer.reduce(stateManager, currentState, {
|
|
29
|
+
type: Action.DATA_SAVED,
|
|
30
|
+
payload: {
|
|
31
|
+
records: [
|
|
32
|
+
{__record__id__: '0'},
|
|
33
|
+
{__record__id__: '2'},
|
|
34
|
+
{__record__id__: '1'},
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
expect(records).toEqual([
|
|
39
|
+
{__record__id__: '0'},
|
|
40
|
+
{__record__id__: '1'},
|
|
41
|
+
{__record__id__: '2'}
|
|
42
|
+
]);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import DataUnit from '../DataUnit';
|
|
2
|
+
import { Action } from '../state/action/DataUnitAction';
|
|
3
|
+
|
|
4
|
+
describe('DataUnit', () => {
|
|
5
|
+
|
|
6
|
+
let dataUnit: DataUnit;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
dataUnit = new DataUnit();
|
|
10
|
+
|
|
11
|
+
dataUnit['dispatchAction'] = jest.fn();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should return false when not waiting to reload', () => {
|
|
15
|
+
expect(dataUnit.isWaitingToReload()).toBe(false);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should set waitingToReload to true', () => {
|
|
19
|
+
dataUnit.setWaitingToReload(true);
|
|
20
|
+
expect(dataUnit.isWaitingToReload()).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should set waitingToReload to false', () => {
|
|
24
|
+
dataUnit.setWaitingToReload(true);
|
|
25
|
+
dataUnit.setWaitingToReload(false);
|
|
26
|
+
expect(dataUnit.isWaitingToReload()).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should dispatch SAVING_CANCELED action with correct fields and recordId', () => {
|
|
30
|
+
const fields = [
|
|
31
|
+
{ name: 'field1', message: 'error1' },
|
|
32
|
+
{ name: 'field2', message: 'error2' }
|
|
33
|
+
];
|
|
34
|
+
const recordId = '12345';
|
|
35
|
+
|
|
36
|
+
dataUnit.savingCanceled(fields, recordId);
|
|
37
|
+
|
|
38
|
+
expect(dataUnit['dispatchAction']).toHaveBeenCalledWith(
|
|
39
|
+
Action.SAVING_CANCELED,
|
|
40
|
+
{ fields, recordId },
|
|
41
|
+
undefined
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `SilentException`: Exceção lançada quando uma exception silenciosa é.
|
|
3
|
+
*/
|
|
4
|
+
export default class SilentException extends Error {
|
|
5
|
+
|
|
6
|
+
/** Nome da exceção. */
|
|
7
|
+
public name: string;
|
|
8
|
+
|
|
9
|
+
/** Titulo do erro. */
|
|
10
|
+
public title: string;
|
|
11
|
+
|
|
12
|
+
/** Descrição do erro. */
|
|
13
|
+
public message: string;
|
|
14
|
+
|
|
15
|
+
/** Código do erro, indica o erro disparado pelo backend. */
|
|
16
|
+
public errorCode: string;
|
|
17
|
+
|
|
18
|
+
constructor(title: string = "", message: string = "", errorCode: string = "") {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = "SilentException";
|
|
21
|
+
this.title = title;
|
|
22
|
+
this.message = message;
|
|
23
|
+
this.errorCode = errorCode;
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ import WarningException from "./exceptions/WarningException.js";
|
|
|
20
20
|
import WaitingChangeException from "./exceptions/WaitingChangeException.js";
|
|
21
21
|
import ErrorException from "./exceptions/ErrorException.js";
|
|
22
22
|
import ServiceCanceledException from "./exceptions/ServiceCanceledException.js";
|
|
23
|
+
import SilentException from "./exceptions/SilentException.js";
|
|
23
24
|
import { ErrorTracking } from "./traking/ErrorTraking.js";
|
|
24
25
|
import { PaginationInfo } from "./dataunit/loading/PaginationInfo.js";
|
|
25
26
|
import { LoadDataRequest } from "./dataunit/loading/LoadDataRequest.js";
|
|
@@ -40,10 +41,19 @@ import { IRepositoryIndex } from "./repository/indexeddb/IRepositoryIndex.js"
|
|
|
40
41
|
import { FieldComparator } from "./dataunit/sorting/FieldComparator.js";
|
|
41
42
|
import { KeyboardManager } from "./utils/KeyboardManager/index.js";
|
|
42
43
|
import { SearchUtils } from "./utils/SearchUtils.js";
|
|
44
|
+
import { ServiceUtils } from "./utils/ServiceUtils.js";
|
|
45
|
+
import { StorageType } from "./utils/CacheManager/index.js";
|
|
43
46
|
import OverflowWatcher, { OnOverflowCallBack, OverflowDirection, OverFlowWatcherParams, OVERFLOWED_CLASS_NAME } from "./utils/OverflowWatcher/index.js";
|
|
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";
|
|
44
52
|
|
|
45
53
|
/*Classes públicas no pacote*/
|
|
46
54
|
export {
|
|
55
|
+
LockManager,
|
|
56
|
+
LockManagerOperation,
|
|
47
57
|
StringUtils,
|
|
48
58
|
MaskFormatter,
|
|
49
59
|
NumberUtils,
|
|
@@ -108,11 +118,20 @@ export {
|
|
|
108
118
|
defaultDataLoader,
|
|
109
119
|
KeyboardManager,
|
|
110
120
|
SearchUtils,
|
|
121
|
+
ServiceUtils,
|
|
122
|
+
StorageType,
|
|
111
123
|
OverflowWatcher,
|
|
112
124
|
OnOverflowCallBack,
|
|
113
125
|
OverflowDirection,
|
|
114
126
|
OverFlowWatcherParams,
|
|
115
127
|
OVERFLOWED_CLASS_NAME,
|
|
116
128
|
DataUnitEventOptions,
|
|
117
|
-
ServiceCanceledException
|
|
129
|
+
ServiceCanceledException,
|
|
130
|
+
SilentException,
|
|
131
|
+
DataUnitInMemoryLoader,
|
|
132
|
+
DataUnitLoaderUtils,
|
|
133
|
+
PaginationInfoBuilderParams,
|
|
134
|
+
ColumnFilterManager,
|
|
135
|
+
DataUnitInMemoryLoaderConfig,
|
|
136
|
+
RECORD_DATE_FORMAT
|
|
118
137
|
};
|
|
@@ -79,4 +79,11 @@ export interface IRepository<T>{
|
|
|
79
79
|
* @returns Promessa de quantidade
|
|
80
80
|
*/
|
|
81
81
|
count(): Promise<number>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Retorna todos os registros que estão em cache no momento
|
|
85
|
+
*
|
|
86
|
+
* @returns Todos registros que estão em cache no momento
|
|
87
|
+
*/
|
|
88
|
+
getFromCache(): Array<T> | undefined
|
|
82
89
|
}
|
|
@@ -320,6 +320,10 @@ export class IDBRepository<T> implements IRepository<T>{
|
|
|
320
320
|
const tx = db.transaction(this._addedStoreName);
|
|
321
321
|
return tx.objectStore(this._addedStoreName).getAll();
|
|
322
322
|
}
|
|
323
|
+
|
|
324
|
+
public getFromCache(): Array<T> | undefined{
|
|
325
|
+
return undefined;
|
|
326
|
+
}
|
|
323
327
|
}
|
|
324
328
|
|
|
325
329
|
/**
|