@epam/uui-db 5.12.1 → 5.14.0-alpha.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 +1 -7
package/index.js
CHANGED
|
@@ -99,7 +99,7 @@ class Db {
|
|
|
99
99
|
}
|
|
100
100
|
update(mutate) {
|
|
101
101
|
const clone = new this.constructor(this.tables, this.viewCache);
|
|
102
|
-
clone.tables =
|
|
102
|
+
clone.tables = { ...this.tables };
|
|
103
103
|
mutate(clone);
|
|
104
104
|
return clone;
|
|
105
105
|
}
|
|
@@ -152,50 +152,6 @@ class Db {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
/******************************************************************************
|
|
156
|
-
Copyright (c) Microsoft Corporation.
|
|
157
|
-
|
|
158
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
159
|
-
purpose with or without fee is hereby granted.
|
|
160
|
-
|
|
161
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
162
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
163
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
164
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
165
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
166
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
167
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
168
|
-
***************************************************************************** */
|
|
169
|
-
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
function __rest(s, e) {
|
|
173
|
-
var t = {};
|
|
174
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
175
|
-
t[p] = s[p];
|
|
176
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
177
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
178
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
179
|
-
t[p[i]] = s[p[i]];
|
|
180
|
-
}
|
|
181
|
-
return t;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
185
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
186
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
187
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
188
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
189
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
190
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
195
|
-
var e = new Error(message);
|
|
196
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
197
|
-
};
|
|
198
|
-
|
|
199
155
|
class DbTable {
|
|
200
156
|
constructor(schema, state, q) {
|
|
201
157
|
this.schema = schema;
|
|
@@ -245,7 +201,7 @@ class DbTable {
|
|
|
245
201
|
let isDeleted = false;
|
|
246
202
|
let updated = entityPatch;
|
|
247
203
|
if (existing) {
|
|
248
|
-
updated =
|
|
204
|
+
updated = { ...existing, ...entityPatch };
|
|
249
205
|
if (this.schema.deleteFlag) {
|
|
250
206
|
isDeleted = updated[this.schema.deleteFlag] === true;
|
|
251
207
|
}
|
|
@@ -277,33 +233,33 @@ class DbTable {
|
|
|
277
233
|
newMap = newMap.update(newKey, I__namespace.Set(), (set) => set.add(update.immId));
|
|
278
234
|
}
|
|
279
235
|
}
|
|
280
|
-
return
|
|
236
|
+
return { ...index, map: newMap };
|
|
281
237
|
});
|
|
282
238
|
const newState = { pk: newPk, indexes: newIndexes };
|
|
283
239
|
return this.update((t) => (t.state = newState));
|
|
284
240
|
}
|
|
285
241
|
/* Query */
|
|
286
242
|
find(filter) {
|
|
287
|
-
return this.update((t) => (t.q =
|
|
243
|
+
return this.update((t) => (t.q = { ...t.q, filter: { ...this.q.filter, ...filter } }));
|
|
288
244
|
}
|
|
289
245
|
order(order) {
|
|
290
|
-
return this.update((t) => (t.q =
|
|
246
|
+
return this.update((t) => (t.q = { ...t.q, sorting: order }));
|
|
291
247
|
}
|
|
292
248
|
orderBy(field, direction = 'asc') {
|
|
293
|
-
return this.update((t) => (t.q =
|
|
249
|
+
return this.update((t) => (t.q = { ...t.q, sorting: [{ field, direction }] }));
|
|
294
250
|
}
|
|
295
251
|
thenBy(field, direction) {
|
|
296
|
-
return this.update((t) => (t.q =
|
|
252
|
+
return this.update((t) => (t.q = { ...t.q, sorting: [...t.q.sorting, { field, direction }] }));
|
|
297
253
|
}
|
|
298
254
|
search(text) {
|
|
299
255
|
if (!this.schema.searchBy) {
|
|
300
256
|
throw new Error(`Can't search in the ${this.schema.typeName} table - searchBy is not defined in the schema.`);
|
|
301
257
|
}
|
|
302
|
-
return this.update((t) => (t.q =
|
|
258
|
+
return this.update((t) => (t.q = { ...t.q, search: text }));
|
|
303
259
|
}
|
|
304
260
|
/* Materializing */
|
|
305
261
|
range(from, count) {
|
|
306
|
-
return this.runQuery(
|
|
262
|
+
return this.runQuery({ ...this.q, range: { from, count } });
|
|
307
263
|
}
|
|
308
264
|
count() {
|
|
309
265
|
return this.runQuery(this.q).length;
|
|
@@ -327,13 +283,13 @@ class DbTable {
|
|
|
327
283
|
for (let n = 0; n < indexes.length; n++) {
|
|
328
284
|
const index = indexes[n];
|
|
329
285
|
if (index.field in filter) {
|
|
330
|
-
const
|
|
286
|
+
const { [index.field]: condition, ...rest } = filter;
|
|
331
287
|
let conditionValues = null;
|
|
332
288
|
if (condition != null && typeof condition === 'object') {
|
|
333
289
|
// Attempt to use index for 'in' and 'isNull' criteria.
|
|
334
290
|
// We need to be very conservative here, indexed field should work the same way as getPatternPredicate. So
|
|
335
291
|
// - it's better to leave corner cases to getPatternPredicate
|
|
336
|
-
const
|
|
292
|
+
const { in: inCriteria, isNull: nullCriteria, ...restCriteria } = condition;
|
|
337
293
|
if (inCriteria && Array.isArray(inCriteria)) {
|
|
338
294
|
conditionValues = inCriteria;
|
|
339
295
|
}
|
|
@@ -515,7 +471,10 @@ function isNew(entity, schema, clientIdsMap) {
|
|
|
515
471
|
return !clientIdsMap.clientToServer(id);
|
|
516
472
|
}
|
|
517
473
|
function hasServerFields(entity, schema, clientIdsMap, tables) {
|
|
518
|
-
const fullEntity =
|
|
474
|
+
const fullEntity = {
|
|
475
|
+
...(tables[schema.tableName].byId(entity.id) || {}),
|
|
476
|
+
...entity,
|
|
477
|
+
};
|
|
519
478
|
if (isClientOnly(fullEntity, schema)) {
|
|
520
479
|
return false;
|
|
521
480
|
}
|
|
@@ -529,7 +488,7 @@ function getParentEntities(patch, tables) {
|
|
|
529
488
|
objectKeys(patch).forEach((key) => {
|
|
530
489
|
const table = tables[key];
|
|
531
490
|
const tableSchema = table.schema;
|
|
532
|
-
const fields = filter__default.default(map__default.default(tableSchema.fields, (field, name) => (
|
|
491
|
+
const fields = filter__default.default(map__default.default(tableSchema.fields, (field, name) => ({ ...field, name })), (field) => field.fk && field.fk.relationType == exports.DbRelationType.Aggregation);
|
|
533
492
|
const tablePatch = patch[key];
|
|
534
493
|
fields.forEach((field) => {
|
|
535
494
|
const { fk: { tableName }, name, } = field;
|
|
@@ -578,14 +537,14 @@ class TempIdMap {
|
|
|
578
537
|
this.clientToServer = (id) => this.clientToServerIds.get(id);
|
|
579
538
|
this.serverToClient = (tableName, id) => this.getServerToClientMap(tableName).get(id);
|
|
580
539
|
this.clientToServerRequest = (request) => {
|
|
581
|
-
request =
|
|
540
|
+
request = { ...request };
|
|
582
541
|
if (request.filter) {
|
|
583
542
|
request.filter = this.clientToServerDataFilter(request.filter);
|
|
584
543
|
}
|
|
585
544
|
return request;
|
|
586
545
|
};
|
|
587
546
|
this.clientToServerDataFilter = (filter) => {
|
|
588
|
-
filter =
|
|
547
|
+
filter = { ...filter };
|
|
589
548
|
const keys = Object.keys(filter);
|
|
590
549
|
// I hope that we can rely that there won't be any negative numbers, which are not IDs, in queries.
|
|
591
550
|
// We need to invent better heuristics or a schema otherwise.
|
|
@@ -602,7 +561,7 @@ class TempIdMap {
|
|
|
602
561
|
const key = keys[n];
|
|
603
562
|
let condition = filter[key];
|
|
604
563
|
if (condition != null && typeof condition === 'object') {
|
|
605
|
-
condition =
|
|
564
|
+
condition = { ...condition };
|
|
606
565
|
if ('in' in condition && Array.isArray(condition.in) && condition.in.length) {
|
|
607
566
|
condition.in = condition.in.map(clientToServer);
|
|
608
567
|
}
|
|
@@ -616,9 +575,9 @@ class TempIdMap {
|
|
|
616
575
|
};
|
|
617
576
|
}
|
|
618
577
|
copyPatch(patch) {
|
|
619
|
-
const newPatch =
|
|
578
|
+
const newPatch = { ...patch };
|
|
620
579
|
objectKeys(patch).forEach((tableName) => {
|
|
621
|
-
const tablePatch = patch[tableName].map((entityPatch) => (
|
|
580
|
+
const tablePatch = patch[tableName].map((entityPatch) => ({ ...entityPatch }));
|
|
622
581
|
newPatch[tableName] = tablePatch;
|
|
623
582
|
});
|
|
624
583
|
return newPatch;
|
|
@@ -825,10 +784,10 @@ class ListLoadingTracker {
|
|
|
825
784
|
constructor(options) {
|
|
826
785
|
this.options = options;
|
|
827
786
|
this.cache = new Map();
|
|
828
|
-
this.extractList =
|
|
787
|
+
this.extractList = options?.extractList || ((r) => r);
|
|
829
788
|
}
|
|
830
789
|
prepare(request) {
|
|
831
|
-
const { filter, sorting, search, range
|
|
790
|
+
const { filter, sorting, search, range, ...unknownFields } = request;
|
|
832
791
|
const options = {};
|
|
833
792
|
if (filter) {
|
|
834
793
|
options.filter = filter;
|
|
@@ -839,7 +798,7 @@ class ListLoadingTracker {
|
|
|
839
798
|
if (search) {
|
|
840
799
|
options.search = search;
|
|
841
800
|
}
|
|
842
|
-
const keyObject =
|
|
801
|
+
const keyObject = { ...options, ...unknownFields };
|
|
843
802
|
const key = JSON.stringify(keyObject);
|
|
844
803
|
let entry = this.cache.get(key);
|
|
845
804
|
if (!entry) {
|
|
@@ -867,7 +826,11 @@ class ListLoadingTracker {
|
|
|
867
826
|
missingCount = Math.min(missingCount, entry.maxCount);
|
|
868
827
|
}
|
|
869
828
|
if (missingCount > 0) {
|
|
870
|
-
return
|
|
829
|
+
return {
|
|
830
|
+
...options,
|
|
831
|
+
...unknownFields,
|
|
832
|
+
range: { from: entry.count, count: requestedMax - entry.count },
|
|
833
|
+
};
|
|
871
834
|
}
|
|
872
835
|
else {
|
|
873
836
|
return null;
|
|
@@ -929,44 +892,42 @@ function batch(runBatch, options) {
|
|
|
929
892
|
let batchPromise = null;
|
|
930
893
|
let queue = [];
|
|
931
894
|
let nextCallPossibleAtMs = new Date().getTime();
|
|
932
|
-
function batchedFn(arg, callOptions) {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
queue = [];
|
|
958
|
-
}
|
|
959
|
-
const results = yield batchPromise;
|
|
960
|
-
return results === null || results === void 0 ? void 0 : results[resultIndex];
|
|
961
|
-
}
|
|
962
|
-
finally {
|
|
963
|
-
const nowMs = new Date().getTime();
|
|
964
|
-
const delayMs = Math.max(0, nextCallPossibleAtMs - nowMs);
|
|
965
|
-
// It's safe to replace currentPromise here. All other requests are already awaiting
|
|
966
|
-
delayPromise = delay(delayMs);
|
|
967
|
-
batchedFn.isBusy = queue.length > 0;
|
|
895
|
+
async function batchedFn(arg, callOptions) {
|
|
896
|
+
options = { ...options, ...callOptions };
|
|
897
|
+
options.throttleMs = options.throttleMs || 0;
|
|
898
|
+
// Enqueue request
|
|
899
|
+
queue.push(arg);
|
|
900
|
+
const resultIndex = queue.length - 1; // an index of current item in queue. Result should be on the same index in batch.
|
|
901
|
+
batchedFn.isBusy = true;
|
|
902
|
+
// Wait current batch to complete
|
|
903
|
+
try {
|
|
904
|
+
await batchPromise;
|
|
905
|
+
}
|
|
906
|
+
catch {
|
|
907
|
+
// ignore errors here. They are thrown to previous batch
|
|
908
|
+
}
|
|
909
|
+
// Wait for throttling delay to pass
|
|
910
|
+
await delayPromise;
|
|
911
|
+
try {
|
|
912
|
+
// Start a batch if there are items.
|
|
913
|
+
// All calls that was awaiting will run this code.
|
|
914
|
+
// Only the first call will run batch, immediately clear the queue, and set batchPromise value
|
|
915
|
+
// Other calls will just await results of this call
|
|
916
|
+
if (queue.length > 0) {
|
|
917
|
+
nextCallPossibleAtMs = new Date().getTime() + options.throttleMs;
|
|
918
|
+
batchPromise = runBatch(queue);
|
|
919
|
+
queue = [];
|
|
968
920
|
}
|
|
969
|
-
|
|
921
|
+
const results = await batchPromise;
|
|
922
|
+
return results?.[resultIndex];
|
|
923
|
+
}
|
|
924
|
+
finally {
|
|
925
|
+
const nowMs = new Date().getTime();
|
|
926
|
+
const delayMs = Math.max(0, nextCallPossibleAtMs - nowMs);
|
|
927
|
+
// It's safe to replace currentPromise here. All other requests are already awaiting
|
|
928
|
+
delayPromise = delay(delayMs);
|
|
929
|
+
batchedFn.isBusy = queue.length > 0;
|
|
930
|
+
}
|
|
970
931
|
}
|
|
971
932
|
batchedFn.isBusy = false;
|
|
972
933
|
return batchedFn;
|
|
@@ -986,14 +947,14 @@ class DbRef {
|
|
|
986
947
|
/* Error Subscriptions */
|
|
987
948
|
this.saveErrorHandlers = [];
|
|
988
949
|
/* Save scheduling */
|
|
989
|
-
this.enqueueSave = batch(() =>
|
|
950
|
+
this.enqueueSave = batch(async () => {
|
|
990
951
|
const cumulativePatch = this.makeCumulativePatch();
|
|
991
952
|
const lastLogEntry = this.log.length;
|
|
992
953
|
if (isEmpty__default.default(cumulativePatch)) {
|
|
993
954
|
return;
|
|
994
955
|
}
|
|
995
956
|
try {
|
|
996
|
-
const response =
|
|
957
|
+
const response = await this.savePatch(cumulativePatch);
|
|
997
958
|
this.applyResponse(response, lastLogEntry);
|
|
998
959
|
this.update();
|
|
999
960
|
}
|
|
@@ -1002,7 +963,7 @@ class DbRef {
|
|
|
1002
963
|
this.update();
|
|
1003
964
|
throw error;
|
|
1004
965
|
}
|
|
1005
|
-
})
|
|
966
|
+
});
|
|
1006
967
|
this.handleBeforeUnload = (e) => {
|
|
1007
968
|
if (this.enqueueSave.isBusy) {
|
|
1008
969
|
e.returnValue = false;
|
|
@@ -1166,7 +1127,7 @@ function useDbRef() {
|
|
|
1166
1127
|
function useDbView(fn, params, options) {
|
|
1167
1128
|
const dbRef = useDbRef();
|
|
1168
1129
|
const [state, setState] = react.useState();
|
|
1169
|
-
const subscription = react.useMemo(() => dbRef.subscribe(
|
|
1130
|
+
const subscription = react.useMemo(() => dbRef.subscribe({ compute: fn, ...options }, params, setState), []);
|
|
1170
1131
|
subscription.update(params);
|
|
1171
1132
|
react.useEffect(() => {
|
|
1172
1133
|
return () => subscription.unsubscribe();
|