@epam/uui-db 5.12.0 → 5.13.0
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/index.esm.js +68 -107
- package/index.esm.js.map +1 -1
- package/index.js +68 -107
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/stats.html +7 -1
package/index.esm.js
CHANGED
|
@@ -64,7 +64,7 @@ class Db {
|
|
|
64
64
|
}
|
|
65
65
|
update(mutate) {
|
|
66
66
|
const clone = new this.constructor(this.tables, this.viewCache);
|
|
67
|
-
clone.tables =
|
|
67
|
+
clone.tables = { ...this.tables };
|
|
68
68
|
mutate(clone);
|
|
69
69
|
return clone;
|
|
70
70
|
}
|
|
@@ -117,50 +117,6 @@ class Db {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
/******************************************************************************
|
|
121
|
-
Copyright (c) Microsoft Corporation.
|
|
122
|
-
|
|
123
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
124
|
-
purpose with or without fee is hereby granted.
|
|
125
|
-
|
|
126
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
127
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
128
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
129
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
130
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
131
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
132
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
133
|
-
***************************************************************************** */
|
|
134
|
-
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
function __rest(s, e) {
|
|
138
|
-
var t = {};
|
|
139
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
140
|
-
t[p] = s[p];
|
|
141
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
142
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
143
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
144
|
-
t[p[i]] = s[p[i]];
|
|
145
|
-
}
|
|
146
|
-
return t;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
150
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
151
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
152
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
153
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
154
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
155
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
160
|
-
var e = new Error(message);
|
|
161
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
162
|
-
};
|
|
163
|
-
|
|
164
120
|
class DbTable {
|
|
165
121
|
constructor(schema, state, q) {
|
|
166
122
|
this.schema = schema;
|
|
@@ -210,7 +166,7 @@ class DbTable {
|
|
|
210
166
|
let isDeleted = false;
|
|
211
167
|
let updated = entityPatch;
|
|
212
168
|
if (existing) {
|
|
213
|
-
updated =
|
|
169
|
+
updated = { ...existing, ...entityPatch };
|
|
214
170
|
if (this.schema.deleteFlag) {
|
|
215
171
|
isDeleted = updated[this.schema.deleteFlag] === true;
|
|
216
172
|
}
|
|
@@ -242,33 +198,33 @@ class DbTable {
|
|
|
242
198
|
newMap = newMap.update(newKey, I.Set(), (set) => set.add(update.immId));
|
|
243
199
|
}
|
|
244
200
|
}
|
|
245
|
-
return
|
|
201
|
+
return { ...index, map: newMap };
|
|
246
202
|
});
|
|
247
203
|
const newState = { pk: newPk, indexes: newIndexes };
|
|
248
204
|
return this.update((t) => (t.state = newState));
|
|
249
205
|
}
|
|
250
206
|
/* Query */
|
|
251
207
|
find(filter) {
|
|
252
|
-
return this.update((t) => (t.q =
|
|
208
|
+
return this.update((t) => (t.q = { ...t.q, filter: { ...this.q.filter, ...filter } }));
|
|
253
209
|
}
|
|
254
210
|
order(order) {
|
|
255
|
-
return this.update((t) => (t.q =
|
|
211
|
+
return this.update((t) => (t.q = { ...t.q, sorting: order }));
|
|
256
212
|
}
|
|
257
213
|
orderBy(field, direction = 'asc') {
|
|
258
|
-
return this.update((t) => (t.q =
|
|
214
|
+
return this.update((t) => (t.q = { ...t.q, sorting: [{ field, direction }] }));
|
|
259
215
|
}
|
|
260
216
|
thenBy(field, direction) {
|
|
261
|
-
return this.update((t) => (t.q =
|
|
217
|
+
return this.update((t) => (t.q = { ...t.q, sorting: [...t.q.sorting, { field, direction }] }));
|
|
262
218
|
}
|
|
263
219
|
search(text) {
|
|
264
220
|
if (!this.schema.searchBy) {
|
|
265
221
|
throw new Error(`Can't search in the ${this.schema.typeName} table - searchBy is not defined in the schema.`);
|
|
266
222
|
}
|
|
267
|
-
return this.update((t) => (t.q =
|
|
223
|
+
return this.update((t) => (t.q = { ...t.q, search: text }));
|
|
268
224
|
}
|
|
269
225
|
/* Materializing */
|
|
270
226
|
range(from, count) {
|
|
271
|
-
return this.runQuery(
|
|
227
|
+
return this.runQuery({ ...this.q, range: { from, count } });
|
|
272
228
|
}
|
|
273
229
|
count() {
|
|
274
230
|
return this.runQuery(this.q).length;
|
|
@@ -292,13 +248,13 @@ class DbTable {
|
|
|
292
248
|
for (let n = 0; n < indexes.length; n++) {
|
|
293
249
|
const index = indexes[n];
|
|
294
250
|
if (index.field in filter) {
|
|
295
|
-
const
|
|
251
|
+
const { [index.field]: condition, ...rest } = filter;
|
|
296
252
|
let conditionValues = null;
|
|
297
253
|
if (condition != null && typeof condition === 'object') {
|
|
298
254
|
// Attempt to use index for 'in' and 'isNull' criteria.
|
|
299
255
|
// We need to be very conservative here, indexed field should work the same way as getPatternPredicate. So
|
|
300
256
|
// - it's better to leave corner cases to getPatternPredicate
|
|
301
|
-
const
|
|
257
|
+
const { in: inCriteria, isNull: nullCriteria, ...restCriteria } = condition;
|
|
302
258
|
if (inCriteria && Array.isArray(inCriteria)) {
|
|
303
259
|
conditionValues = inCriteria;
|
|
304
260
|
}
|
|
@@ -480,7 +436,10 @@ function isNew(entity, schema, clientIdsMap) {
|
|
|
480
436
|
return !clientIdsMap.clientToServer(id);
|
|
481
437
|
}
|
|
482
438
|
function hasServerFields(entity, schema, clientIdsMap, tables) {
|
|
483
|
-
const fullEntity =
|
|
439
|
+
const fullEntity = {
|
|
440
|
+
...(tables[schema.tableName].byId(entity.id) || {}),
|
|
441
|
+
...entity,
|
|
442
|
+
};
|
|
484
443
|
if (isClientOnly(fullEntity, schema)) {
|
|
485
444
|
return false;
|
|
486
445
|
}
|
|
@@ -494,7 +453,7 @@ function getParentEntities(patch, tables) {
|
|
|
494
453
|
objectKeys(patch).forEach((key) => {
|
|
495
454
|
const table = tables[key];
|
|
496
455
|
const tableSchema = table.schema;
|
|
497
|
-
const fields = filter(map(tableSchema.fields, (field, name) => (
|
|
456
|
+
const fields = filter(map(tableSchema.fields, (field, name) => ({ ...field, name })), (field) => field.fk && field.fk.relationType == DbRelationType.Aggregation);
|
|
498
457
|
const tablePatch = patch[key];
|
|
499
458
|
fields.forEach((field) => {
|
|
500
459
|
const { fk: { tableName }, name, } = field;
|
|
@@ -543,14 +502,14 @@ class TempIdMap {
|
|
|
543
502
|
this.clientToServer = (id) => this.clientToServerIds.get(id);
|
|
544
503
|
this.serverToClient = (tableName, id) => this.getServerToClientMap(tableName).get(id);
|
|
545
504
|
this.clientToServerRequest = (request) => {
|
|
546
|
-
request =
|
|
505
|
+
request = { ...request };
|
|
547
506
|
if (request.filter) {
|
|
548
507
|
request.filter = this.clientToServerDataFilter(request.filter);
|
|
549
508
|
}
|
|
550
509
|
return request;
|
|
551
510
|
};
|
|
552
511
|
this.clientToServerDataFilter = (filter) => {
|
|
553
|
-
filter =
|
|
512
|
+
filter = { ...filter };
|
|
554
513
|
const keys = Object.keys(filter);
|
|
555
514
|
// I hope that we can rely that there won't be any negative numbers, which are not IDs, in queries.
|
|
556
515
|
// We need to invent better heuristics or a schema otherwise.
|
|
@@ -567,7 +526,7 @@ class TempIdMap {
|
|
|
567
526
|
const key = keys[n];
|
|
568
527
|
let condition = filter[key];
|
|
569
528
|
if (condition != null && typeof condition === 'object') {
|
|
570
|
-
condition =
|
|
529
|
+
condition = { ...condition };
|
|
571
530
|
if ('in' in condition && Array.isArray(condition.in) && condition.in.length) {
|
|
572
531
|
condition.in = condition.in.map(clientToServer);
|
|
573
532
|
}
|
|
@@ -581,9 +540,9 @@ class TempIdMap {
|
|
|
581
540
|
};
|
|
582
541
|
}
|
|
583
542
|
copyPatch(patch) {
|
|
584
|
-
const newPatch =
|
|
543
|
+
const newPatch = { ...patch };
|
|
585
544
|
objectKeys(patch).forEach((tableName) => {
|
|
586
|
-
const tablePatch = patch[tableName].map((entityPatch) => (
|
|
545
|
+
const tablePatch = patch[tableName].map((entityPatch) => ({ ...entityPatch }));
|
|
587
546
|
newPatch[tableName] = tablePatch;
|
|
588
547
|
});
|
|
589
548
|
return newPatch;
|
|
@@ -790,10 +749,10 @@ class ListLoadingTracker {
|
|
|
790
749
|
constructor(options) {
|
|
791
750
|
this.options = options;
|
|
792
751
|
this.cache = new Map();
|
|
793
|
-
this.extractList =
|
|
752
|
+
this.extractList = options?.extractList || ((r) => r);
|
|
794
753
|
}
|
|
795
754
|
prepare(request) {
|
|
796
|
-
const { filter, sorting, search, range
|
|
755
|
+
const { filter, sorting, search, range, ...unknownFields } = request;
|
|
797
756
|
const options = {};
|
|
798
757
|
if (filter) {
|
|
799
758
|
options.filter = filter;
|
|
@@ -804,7 +763,7 @@ class ListLoadingTracker {
|
|
|
804
763
|
if (search) {
|
|
805
764
|
options.search = search;
|
|
806
765
|
}
|
|
807
|
-
const keyObject =
|
|
766
|
+
const keyObject = { ...options, ...unknownFields };
|
|
808
767
|
const key = JSON.stringify(keyObject);
|
|
809
768
|
let entry = this.cache.get(key);
|
|
810
769
|
if (!entry) {
|
|
@@ -832,7 +791,11 @@ class ListLoadingTracker {
|
|
|
832
791
|
missingCount = Math.min(missingCount, entry.maxCount);
|
|
833
792
|
}
|
|
834
793
|
if (missingCount > 0) {
|
|
835
|
-
return
|
|
794
|
+
return {
|
|
795
|
+
...options,
|
|
796
|
+
...unknownFields,
|
|
797
|
+
range: { from: entry.count, count: requestedMax - entry.count },
|
|
798
|
+
};
|
|
836
799
|
}
|
|
837
800
|
else {
|
|
838
801
|
return null;
|
|
@@ -894,44 +857,42 @@ function batch(runBatch, options) {
|
|
|
894
857
|
let batchPromise = null;
|
|
895
858
|
let queue = [];
|
|
896
859
|
let nextCallPossibleAtMs = new Date().getTime();
|
|
897
|
-
function batchedFn(arg, callOptions) {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
queue = [];
|
|
923
|
-
}
|
|
924
|
-
const results = yield batchPromise;
|
|
925
|
-
return results === null || results === void 0 ? void 0 : results[resultIndex];
|
|
926
|
-
}
|
|
927
|
-
finally {
|
|
928
|
-
const nowMs = new Date().getTime();
|
|
929
|
-
const delayMs = Math.max(0, nextCallPossibleAtMs - nowMs);
|
|
930
|
-
// It's safe to replace currentPromise here. All other requests are already awaiting
|
|
931
|
-
delayPromise = delay(delayMs);
|
|
932
|
-
batchedFn.isBusy = queue.length > 0;
|
|
860
|
+
async function batchedFn(arg, callOptions) {
|
|
861
|
+
options = { ...options, ...callOptions };
|
|
862
|
+
options.throttleMs = options.throttleMs || 0;
|
|
863
|
+
// Enqueue request
|
|
864
|
+
queue.push(arg);
|
|
865
|
+
const resultIndex = queue.length - 1; // an index of current item in queue. Result should be on the same index in batch.
|
|
866
|
+
batchedFn.isBusy = true;
|
|
867
|
+
// Wait current batch to complete
|
|
868
|
+
try {
|
|
869
|
+
await batchPromise;
|
|
870
|
+
}
|
|
871
|
+
catch {
|
|
872
|
+
// ignore errors here. They are thrown to previous batch
|
|
873
|
+
}
|
|
874
|
+
// Wait for throttling delay to pass
|
|
875
|
+
await delayPromise;
|
|
876
|
+
try {
|
|
877
|
+
// Start a batch if there are items.
|
|
878
|
+
// All calls that was awaiting will run this code.
|
|
879
|
+
// Only the first call will run batch, immediately clear the queue, and set batchPromise value
|
|
880
|
+
// Other calls will just await results of this call
|
|
881
|
+
if (queue.length > 0) {
|
|
882
|
+
nextCallPossibleAtMs = new Date().getTime() + options.throttleMs;
|
|
883
|
+
batchPromise = runBatch(queue);
|
|
884
|
+
queue = [];
|
|
933
885
|
}
|
|
934
|
-
|
|
886
|
+
const results = await batchPromise;
|
|
887
|
+
return results?.[resultIndex];
|
|
888
|
+
}
|
|
889
|
+
finally {
|
|
890
|
+
const nowMs = new Date().getTime();
|
|
891
|
+
const delayMs = Math.max(0, nextCallPossibleAtMs - nowMs);
|
|
892
|
+
// It's safe to replace currentPromise here. All other requests are already awaiting
|
|
893
|
+
delayPromise = delay(delayMs);
|
|
894
|
+
batchedFn.isBusy = queue.length > 0;
|
|
895
|
+
}
|
|
935
896
|
}
|
|
936
897
|
batchedFn.isBusy = false;
|
|
937
898
|
return batchedFn;
|
|
@@ -951,14 +912,14 @@ class DbRef {
|
|
|
951
912
|
/* Error Subscriptions */
|
|
952
913
|
this.saveErrorHandlers = [];
|
|
953
914
|
/* Save scheduling */
|
|
954
|
-
this.enqueueSave = batch(() =>
|
|
915
|
+
this.enqueueSave = batch(async () => {
|
|
955
916
|
const cumulativePatch = this.makeCumulativePatch();
|
|
956
917
|
const lastLogEntry = this.log.length;
|
|
957
918
|
if (isEmpty(cumulativePatch)) {
|
|
958
919
|
return;
|
|
959
920
|
}
|
|
960
921
|
try {
|
|
961
|
-
const response =
|
|
922
|
+
const response = await this.savePatch(cumulativePatch);
|
|
962
923
|
this.applyResponse(response, lastLogEntry);
|
|
963
924
|
this.update();
|
|
964
925
|
}
|
|
@@ -967,7 +928,7 @@ class DbRef {
|
|
|
967
928
|
this.update();
|
|
968
929
|
throw error;
|
|
969
930
|
}
|
|
970
|
-
})
|
|
931
|
+
});
|
|
971
932
|
this.handleBeforeUnload = (e) => {
|
|
972
933
|
if (this.enqueueSave.isBusy) {
|
|
973
934
|
e.returnValue = false;
|
|
@@ -1131,7 +1092,7 @@ function useDbRef() {
|
|
|
1131
1092
|
function useDbView(fn, params, options) {
|
|
1132
1093
|
const dbRef = useDbRef();
|
|
1133
1094
|
const [state, setState] = useState();
|
|
1134
|
-
const subscription = useMemo(() => dbRef.subscribe(
|
|
1095
|
+
const subscription = useMemo(() => dbRef.subscribe({ compute: fn, ...options }, params, setState), []);
|
|
1135
1096
|
subscription.update(params);
|
|
1136
1097
|
useEffect(() => {
|
|
1137
1098
|
return () => subscription.unsubscribe();
|