@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.
Files changed (135) hide show
  1. package/.docs/classes/Change.md +11 -11
  2. package/.docs/classes/ColumnFilterManager.md +145 -0
  3. package/.docs/classes/DataUnit.md +334 -136
  4. package/.docs/classes/DataUnitInMemoryLoader.md +303 -0
  5. package/.docs/classes/DataUnitLoaderUtils.md +151 -0
  6. package/.docs/classes/FieldComparator.md +2 -2
  7. package/.docs/classes/IDBRepository.md +22 -0
  8. package/.docs/classes/LockManager.md +249 -0
  9. package/.docs/classes/MaskFormatter.md +66 -14
  10. package/.docs/classes/ObjectUtils.md +95 -2
  11. package/.docs/classes/SelectionInfo.md +25 -11
  12. package/.docs/classes/ServiceUtils.md +67 -0
  13. package/.docs/classes/SilentException.md +193 -0
  14. package/.docs/classes/UserAgentUtils.md +15 -1
  15. package/.docs/enumerations/Action.md +32 -22
  16. package/.docs/enumerations/ChangeOperation.md +4 -4
  17. package/.docs/enumerations/LockManagerOperation.md +33 -0
  18. package/.docs/enumerations/RECORD_DATE_FORMAT.md +27 -0
  19. package/.docs/enumerations/SelectionMode.md +2 -2
  20. package/.docs/enumerations/StorageType.md +37 -0
  21. package/.docs/globals.md +11 -0
  22. package/.docs/interfaces/DUActionInterceptor.md +1 -1
  23. package/.docs/interfaces/DataUnitInMemoryLoaderConfig.md +37 -0
  24. package/.docs/interfaces/IRepository.md +18 -0
  25. package/.docs/interfaces/LoadDataRequest.md +1 -1
  26. package/.docs/interfaces/PageRequest.md +3 -3
  27. package/.docs/interfaces/PaginationInfo.md +25 -0
  28. package/.docs/interfaces/PaginationInfoBuilderParams.md +37 -0
  29. package/.docs/interfaces/QuickFilter.md +3 -3
  30. package/.docs/interfaces/Record.md +4 -4
  31. package/.docs/interfaces/SavedRecord.md +5 -5
  32. package/.docs/interfaces/WaitingChange.md +3 -3
  33. package/.docs/namespaces/MaskFormatter/type-aliases/MaskCharacter.md +1 -1
  34. package/.docs/namespaces/MaskFormatter/variables/MaskCharacter.md +1 -1
  35. package/.docs/type-aliases/DataUnitEventOptions.md +1 -1
  36. package/.releaserc +1 -0
  37. package/bun.lockb +0 -0
  38. package/dist/dataunit/DataUnit.d.ts +60 -10
  39. package/dist/dataunit/DataUnit.js +151 -50
  40. package/dist/dataunit/DataUnit.js.map +1 -1
  41. package/dist/dataunit/formatting/PrettyFormatter.js +8 -2
  42. package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
  43. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.d.ts +9 -0
  44. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js +6 -0
  45. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js.map +1 -0
  46. package/dist/dataunit/loader/dataUnitInMemoryLoader.d.ts +25 -0
  47. package/dist/dataunit/loader/dataUnitInMemoryLoader.js +131 -0
  48. package/dist/dataunit/loader/dataUnitInMemoryLoader.js.map +1 -0
  49. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.d.ts +20 -0
  50. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js +62 -0
  51. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js.map +1 -0
  52. package/dist/dataunit/loading/LoadDataRequest.d.ts +1 -1
  53. package/dist/dataunit/loading/PaginationInfo.d.ts +8 -0
  54. package/dist/dataunit/sorting/FieldComparator.d.ts +2 -2
  55. package/dist/dataunit/sorting/FieldComparator.js +4 -9
  56. package/dist/dataunit/sorting/FieldComparator.js.map +1 -1
  57. package/dist/dataunit/state/action/DataUnitAction.d.ts +1 -0
  58. package/dist/dataunit/state/action/DataUnitAction.js +1 -0
  59. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  60. package/dist/dataunit/state/slice/LoadingControlSlice.js +16 -0
  61. package/dist/dataunit/state/slice/LoadingControlSlice.js.map +1 -1
  62. package/dist/dataunit/state/slice/RecordsSlice.js +1 -1
  63. package/dist/dataunit/state/slice/RecordsSlice.js.map +1 -1
  64. package/dist/dataunit/state/slice/SelectionSlice.js +2 -2
  65. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  66. package/dist/exceptions/SilentException.d.ts +14 -0
  67. package/dist/exceptions/SilentException.js +13 -0
  68. package/dist/exceptions/SilentException.js.map +1 -0
  69. package/dist/index.d.ts +9 -1
  70. package/dist/index.js +9 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/repository/IRepository.d.ts +6 -0
  73. package/dist/repository/indexeddb/IDBRepository.d.ts +1 -0
  74. package/dist/repository/indexeddb/IDBRepository.js +3 -0
  75. package/dist/repository/indexeddb/IDBRepository.js.map +1 -1
  76. package/dist/utils/CacheManager/index.d.ts +52 -0
  77. package/dist/utils/CacheManager/index.js +101 -0
  78. package/dist/utils/CacheManager/index.js.map +1 -0
  79. package/dist/utils/CacheManager/interfaces/index.d.ts +5 -0
  80. package/dist/utils/CacheManager/interfaces/index.js +7 -0
  81. package/dist/utils/CacheManager/interfaces/index.js.map +1 -0
  82. package/dist/utils/ColumnFilterManager.d.ts +19 -0
  83. package/dist/utils/ColumnFilterManager.js +73 -0
  84. package/dist/utils/ColumnFilterManager.js.map +1 -0
  85. package/dist/utils/LockManager.d.ts +58 -0
  86. package/dist/utils/LockManager.js +191 -0
  87. package/dist/utils/LockManager.js.map +1 -0
  88. package/dist/utils/MaskFormatter.d.ts +16 -1
  89. package/dist/utils/MaskFormatter.js +82 -2
  90. package/dist/utils/MaskFormatter.js.map +1 -1
  91. package/dist/utils/ObjectUtils.d.ts +24 -0
  92. package/dist/utils/ObjectUtils.js +33 -0
  93. package/dist/utils/ObjectUtils.js.map +1 -1
  94. package/dist/utils/ServiceUtils.d.ts +24 -0
  95. package/dist/utils/ServiceUtils.js +40 -0
  96. package/dist/utils/ServiceUtils.js.map +1 -0
  97. package/dist/utils/SortingUtils.d.ts +9 -0
  98. package/dist/utils/SortingUtils.js +24 -0
  99. package/dist/utils/SortingUtils.js.map +1 -0
  100. package/dist/utils/UserAgentUtils/index.d.ts +1 -0
  101. package/dist/utils/UserAgentUtils/index.js +5 -0
  102. package/dist/utils/UserAgentUtils/index.js.map +1 -1
  103. package/package.json +1 -1
  104. package/reports/test-report.xml +148 -84
  105. package/src/dataunit/DataUnit.ts +191 -68
  106. package/src/dataunit/formatting/PrettyFormatter.ts +10 -2
  107. package/src/dataunit/loader/DataUnitInMemoryLoaderConfig.ts +10 -0
  108. package/src/dataunit/loader/dataUnitInMemoryLoader.ts +176 -0
  109. package/src/dataunit/loader/utils/dataUnitLoaderUtils.ts +86 -0
  110. package/src/dataunit/loading/LoadDataRequest.ts +1 -1
  111. package/src/dataunit/loading/PaginationInfo.ts +10 -0
  112. package/src/dataunit/sorting/FieldComparator.ts +18 -32
  113. package/src/dataunit/state/action/DataUnitAction.ts +1 -0
  114. package/src/dataunit/state/slice/LoadingControlSlice.ts +42 -0
  115. package/src/dataunit/state/slice/RecordsSlice.ts +1 -1
  116. package/src/dataunit/state/slice/SelectionSlice.ts +2 -2
  117. package/src/dataunit/state/slice/test/RecordsSlice.spec.ts +45 -0
  118. package/src/dataunit/test/DataUnit.spec.ts +44 -0
  119. package/src/exceptions/SilentException.ts +25 -0
  120. package/src/index.ts +20 -1
  121. package/src/repository/IRepository.ts +7 -0
  122. package/src/repository/indexeddb/IDBRepository.ts +4 -0
  123. package/src/utils/CacheManager/index.ts +103 -0
  124. package/src/utils/CacheManager/interfaces/index.ts +5 -0
  125. package/src/utils/ColumnFilterManager.ts +104 -0
  126. package/src/utils/LockManager.ts +213 -0
  127. package/src/utils/MaskFormatter.ts +93 -2
  128. package/src/utils/ObjectUtils.ts +36 -0
  129. package/src/utils/ServiceUtils.ts +36 -0
  130. package/src/utils/SortingUtils.ts +30 -0
  131. package/src/utils/UserAgentUtils/index.ts +6 -1
  132. package/src/utils/test/objectUtils.spec.ts +109 -0
  133. package/test/dataunit/loader/dataUnitInMemoryLoader.spec.ts +221 -0
  134. package/test/dataunit/loader/utils/dataUnitLoaderUtils.spec.ts +158 -0
  135. 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?: String;
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 "../DataUnit.js";
2
- import { compareValues } from "../metadata/DataType.js";
3
- import { FieldDescriptor } from "../metadata/UnitMetadata.js";
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
- public static compare(field: FieldDescriptor, recordA: Record, recordB: Record, asc: boolean = true): number{
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
- const valueA = (asc ? recordA : recordB)[field.name];
10
- const valueB = (asc ? recordB : recordA)[field.name];
11
+ return FieldComparator.compareValues(field, valueA, valueB);
12
+ }
11
13
 
12
-
13
- return FieldComparator.compareValues(field, valueA, valueB);
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
- return compareValues(valueA, valueB, descriptor)
24
- }
25
-
26
- public static compareUndefined(isUndefinedA: boolean, isUndefinedB: boolean): number | undefined {
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
  }
@@ -36,6 +36,7 @@ export enum Action{
36
36
  SAVING_DATA = "savingData",
37
37
  DATA_SAVED = "dataSaved",
38
38
  SAVING_ERROR = "savingError",
39
+ SAVING_CANCELED = "savingCanceled",
39
40
 
40
41
  REMOVING_RECORDS = "removingRecords",
41
42
  RECORDS_REMOVED = "recordsRemoved",
@@ -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 newRecords.concat(Array.from(recordsMap.values()));
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
  /**