@sankhyalabs/core 5.17.3 → 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 (140) 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/ServiceCanceledException.md +193 -0
  13. package/.docs/classes/ServiceUtils.md +67 -0
  14. package/.docs/classes/SilentException.md +193 -0
  15. package/.docs/classes/UserAgentUtils.md +15 -1
  16. package/.docs/enumerations/Action.md +32 -22
  17. package/.docs/enumerations/ChangeOperation.md +4 -4
  18. package/.docs/enumerations/LockManagerOperation.md +33 -0
  19. package/.docs/enumerations/RECORD_DATE_FORMAT.md +27 -0
  20. package/.docs/enumerations/SelectionMode.md +2 -2
  21. package/.docs/enumerations/StorageType.md +37 -0
  22. package/.docs/globals.md +12 -0
  23. package/.docs/interfaces/DUActionInterceptor.md +1 -1
  24. package/.docs/interfaces/DataUnitInMemoryLoaderConfig.md +37 -0
  25. package/.docs/interfaces/IRepository.md +18 -0
  26. package/.docs/interfaces/LoadDataRequest.md +1 -1
  27. package/.docs/interfaces/PageRequest.md +3 -3
  28. package/.docs/interfaces/PaginationInfo.md +25 -0
  29. package/.docs/interfaces/PaginationInfoBuilderParams.md +37 -0
  30. package/.docs/interfaces/QuickFilter.md +3 -3
  31. package/.docs/interfaces/Record.md +4 -4
  32. package/.docs/interfaces/SavedRecord.md +5 -5
  33. package/.docs/interfaces/WaitingChange.md +3 -3
  34. package/.docs/namespaces/MaskFormatter/type-aliases/MaskCharacter.md +1 -1
  35. package/.docs/namespaces/MaskFormatter/variables/MaskCharacter.md +1 -1
  36. package/.docs/type-aliases/DataUnitEventOptions.md +1 -1
  37. package/.releaserc +1 -0
  38. package/bun.lockb +0 -0
  39. package/dist/dataunit/DataUnit.d.ts +60 -10
  40. package/dist/dataunit/DataUnit.js +156 -48
  41. package/dist/dataunit/DataUnit.js.map +1 -1
  42. package/dist/dataunit/formatting/PrettyFormatter.js +8 -2
  43. package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
  44. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.d.ts +9 -0
  45. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js +6 -0
  46. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js.map +1 -0
  47. package/dist/dataunit/loader/dataUnitInMemoryLoader.d.ts +25 -0
  48. package/dist/dataunit/loader/dataUnitInMemoryLoader.js +131 -0
  49. package/dist/dataunit/loader/dataUnitInMemoryLoader.js.map +1 -0
  50. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.d.ts +20 -0
  51. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js +62 -0
  52. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js.map +1 -0
  53. package/dist/dataunit/loading/LoadDataRequest.d.ts +1 -1
  54. package/dist/dataunit/loading/PaginationInfo.d.ts +8 -0
  55. package/dist/dataunit/sorting/FieldComparator.d.ts +2 -2
  56. package/dist/dataunit/sorting/FieldComparator.js +4 -9
  57. package/dist/dataunit/sorting/FieldComparator.js.map +1 -1
  58. package/dist/dataunit/state/action/DataUnitAction.d.ts +1 -0
  59. package/dist/dataunit/state/action/DataUnitAction.js +1 -0
  60. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  61. package/dist/dataunit/state/slice/LoadingControlSlice.js +16 -0
  62. package/dist/dataunit/state/slice/LoadingControlSlice.js.map +1 -1
  63. package/dist/dataunit/state/slice/RecordsSlice.js +1 -1
  64. package/dist/dataunit/state/slice/RecordsSlice.js.map +1 -1
  65. package/dist/dataunit/state/slice/SelectionSlice.js +2 -2
  66. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  67. package/dist/exceptions/ServiceCanceledException.d.ts +14 -0
  68. package/dist/exceptions/ServiceCanceledException.js +13 -0
  69. package/dist/exceptions/ServiceCanceledException.js.map +1 -0
  70. package/dist/exceptions/SilentException.d.ts +14 -0
  71. package/dist/exceptions/SilentException.js +13 -0
  72. package/dist/exceptions/SilentException.js.map +1 -0
  73. package/dist/index.d.ts +10 -1
  74. package/dist/index.js +10 -1
  75. package/dist/index.js.map +1 -1
  76. package/dist/repository/IRepository.d.ts +6 -0
  77. package/dist/repository/indexeddb/IDBRepository.d.ts +1 -0
  78. package/dist/repository/indexeddb/IDBRepository.js +3 -0
  79. package/dist/repository/indexeddb/IDBRepository.js.map +1 -1
  80. package/dist/utils/CacheManager/index.d.ts +52 -0
  81. package/dist/utils/CacheManager/index.js +101 -0
  82. package/dist/utils/CacheManager/index.js.map +1 -0
  83. package/dist/utils/CacheManager/interfaces/index.d.ts +5 -0
  84. package/dist/utils/CacheManager/interfaces/index.js +7 -0
  85. package/dist/utils/CacheManager/interfaces/index.js.map +1 -0
  86. package/dist/utils/ColumnFilterManager.d.ts +19 -0
  87. package/dist/utils/ColumnFilterManager.js +73 -0
  88. package/dist/utils/ColumnFilterManager.js.map +1 -0
  89. package/dist/utils/LockManager.d.ts +58 -0
  90. package/dist/utils/LockManager.js +191 -0
  91. package/dist/utils/LockManager.js.map +1 -0
  92. package/dist/utils/MaskFormatter.d.ts +16 -1
  93. package/dist/utils/MaskFormatter.js +82 -2
  94. package/dist/utils/MaskFormatter.js.map +1 -1
  95. package/dist/utils/ObjectUtils.d.ts +24 -0
  96. package/dist/utils/ObjectUtils.js +33 -0
  97. package/dist/utils/ObjectUtils.js.map +1 -1
  98. package/dist/utils/ServiceUtils.d.ts +24 -0
  99. package/dist/utils/ServiceUtils.js +40 -0
  100. package/dist/utils/ServiceUtils.js.map +1 -0
  101. package/dist/utils/SortingUtils.d.ts +9 -0
  102. package/dist/utils/SortingUtils.js +24 -0
  103. package/dist/utils/SortingUtils.js.map +1 -0
  104. package/dist/utils/UserAgentUtils/index.d.ts +1 -0
  105. package/dist/utils/UserAgentUtils/index.js +5 -0
  106. package/dist/utils/UserAgentUtils/index.js.map +1 -1
  107. package/package.json +1 -1
  108. package/reports/test-report.xml +142 -78
  109. package/src/dataunit/DataUnit.ts +193 -64
  110. package/src/dataunit/formatting/PrettyFormatter.ts +10 -2
  111. package/src/dataunit/loader/DataUnitInMemoryLoaderConfig.ts +10 -0
  112. package/src/dataunit/loader/dataUnitInMemoryLoader.ts +176 -0
  113. package/src/dataunit/loader/utils/dataUnitLoaderUtils.ts +86 -0
  114. package/src/dataunit/loading/LoadDataRequest.ts +1 -1
  115. package/src/dataunit/loading/PaginationInfo.ts +10 -0
  116. package/src/dataunit/sorting/FieldComparator.ts +18 -32
  117. package/src/dataunit/state/action/DataUnitAction.ts +1 -0
  118. package/src/dataunit/state/slice/LoadingControlSlice.ts +42 -0
  119. package/src/dataunit/state/slice/RecordsSlice.ts +1 -1
  120. package/src/dataunit/state/slice/SelectionSlice.ts +2 -2
  121. package/src/dataunit/state/slice/test/RecordsSlice.spec.ts +45 -0
  122. package/src/dataunit/test/DataUnit.spec.ts +44 -0
  123. package/src/exceptions/ServiceCanceledException.ts +25 -0
  124. package/src/exceptions/SilentException.ts +25 -0
  125. package/src/index.ts +22 -1
  126. package/src/repository/IRepository.ts +7 -0
  127. package/src/repository/indexeddb/IDBRepository.ts +4 -0
  128. package/src/utils/CacheManager/index.ts +103 -0
  129. package/src/utils/CacheManager/interfaces/index.ts +5 -0
  130. package/src/utils/ColumnFilterManager.ts +104 -0
  131. package/src/utils/LockManager.ts +213 -0
  132. package/src/utils/MaskFormatter.ts +93 -2
  133. package/src/utils/ObjectUtils.ts +36 -0
  134. package/src/utils/ServiceUtils.ts +36 -0
  135. package/src/utils/SortingUtils.ts +30 -0
  136. package/src/utils/UserAgentUtils/index.ts +6 -1
  137. package/src/utils/test/objectUtils.spec.ts +109 -0
  138. package/test/dataunit/loader/dataUnitInMemoryLoader.spec.ts +221 -0
  139. package/test/dataunit/loader/utils/dataUnitLoaderUtils.spec.ts +158 -0
  140. 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
+ * `ServiceCanceledException`: Exceção lançada quando ocorre o cancelamento de um serviço.
3
+ */
4
+ export default class ServiceCanceledException 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 = "Service Canceled";
21
+ this.title = title;
22
+ this.message = message;
23
+ this.errorCode = errorCode;
24
+ }
25
+ }
@@ -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
@@ -19,6 +19,8 @@ import ObjectUtils from "./utils/ObjectUtils.js";
19
19
  import WarningException from "./exceptions/WarningException.js";
20
20
  import WaitingChangeException from "./exceptions/WaitingChangeException.js";
21
21
  import ErrorException from "./exceptions/ErrorException.js";
22
+ import ServiceCanceledException from "./exceptions/ServiceCanceledException.js";
23
+ import SilentException from "./exceptions/SilentException.js";
22
24
  import { ErrorTracking } from "./traking/ErrorTraking.js";
23
25
  import { PaginationInfo } from "./dataunit/loading/PaginationInfo.js";
24
26
  import { LoadDataRequest } from "./dataunit/loading/LoadDataRequest.js";
@@ -39,10 +41,19 @@ import { IRepositoryIndex } from "./repository/indexeddb/IRepositoryIndex.js"
39
41
  import { FieldComparator } from "./dataunit/sorting/FieldComparator.js";
40
42
  import { KeyboardManager } from "./utils/KeyboardManager/index.js";
41
43
  import { SearchUtils } from "./utils/SearchUtils.js";
44
+ import { ServiceUtils } from "./utils/ServiceUtils.js";
45
+ import { StorageType } from "./utils/CacheManager/index.js";
42
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";
43
52
 
44
53
  /*Classes públicas no pacote*/
45
54
  export {
55
+ LockManager,
56
+ LockManagerOperation,
46
57
  StringUtils,
47
58
  MaskFormatter,
48
59
  NumberUtils,
@@ -107,10 +118,20 @@ export {
107
118
  defaultDataLoader,
108
119
  KeyboardManager,
109
120
  SearchUtils,
121
+ ServiceUtils,
122
+ StorageType,
110
123
  OverflowWatcher,
111
124
  OnOverflowCallBack,
112
125
  OverflowDirection,
113
126
  OverFlowWatcherParams,
114
127
  OVERFLOWED_CLASS_NAME,
115
- DataUnitEventOptions
128
+ DataUnitEventOptions,
129
+ ServiceCanceledException,
130
+ SilentException,
131
+ DataUnitInMemoryLoader,
132
+ DataUnitLoaderUtils,
133
+ PaginationInfoBuilderParams,
134
+ ColumnFilterManager,
135
+ DataUnitInMemoryLoaderConfig,
136
+ RECORD_DATE_FORMAT
116
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
  /**