@epam/uui-db 5.0.0-alpha.0 → 5.0.0-alpha.2
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 +107 -91
- package/index.esm.js.map +1 -1
- package/index.js +107 -91
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/src/Db.d.ts.map +1 -1
- package/src/DbRef.d.ts +1 -1
- package/src/DbRef.d.ts.map +1 -1
- package/src/DbTable.d.ts +1 -1
- package/src/DbTable.d.ts.map +1 -1
- package/src/IxSet.d.ts.map +1 -1
- package/src/ListLoadingTracker.d.ts.map +1 -1
- package/src/Loader.d.ts.map +1 -1
- package/src/Scheduler.d.ts.map +1 -1
- package/src/SimpleLoadingTracker.d.ts.map +1 -1
- package/src/__benchmarks__/testData.d.ts.map +1 -1
- package/src/patchHelpers.d.ts +3 -3
- package/src/patchHelpers.d.ts.map +1 -1
- package/src/reactHooks.d.ts.map +1 -1
- package/src/tempIds.d.ts +2 -2
- package/src/tempIds.d.ts.map +1 -1
- package/src/types.d.ts +2 -2
- package/src/types.d.ts.map +1 -1
- package/src/utils.d.ts +1 -1
- package/src/utils.d.ts.map +1 -1
- package/stats.html +2462 -329
package/index.esm.js
CHANGED
|
@@ -22,7 +22,7 @@ var DbRelationType;
|
|
|
22
22
|
})(DbRelationType || (DbRelationType = {}));
|
|
23
23
|
|
|
24
24
|
// TBD: New typescript would contain better typing for this. Remove this hack after update.
|
|
25
|
-
|
|
25
|
+
const objectKeys = Object.keys;
|
|
26
26
|
function defaultCompareViewDependencies(prev, next) {
|
|
27
27
|
if (Array.isArray(prev) && Array.isArray(next)) {
|
|
28
28
|
if (prev.length === next.length) {
|
|
@@ -42,7 +42,7 @@ function difference(object, base) {
|
|
|
42
42
|
function changes(object, base) {
|
|
43
43
|
return transform(object, function (result, value, key) {
|
|
44
44
|
if (!isEqual(value, base[key])) {
|
|
45
|
-
result[key] =
|
|
45
|
+
result[key] = typeof value === 'object' && typeof base[key] === 'object' ? changes(value, base[key]) : value;
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
}
|
|
@@ -54,7 +54,7 @@ class Db {
|
|
|
54
54
|
this.tables = tables;
|
|
55
55
|
this.viewCache = new Map();
|
|
56
56
|
/* Views (cached db projections) */
|
|
57
|
-
this.valueAbsent = Symbol(
|
|
57
|
+
this.valueAbsent = Symbol('ValueAbsent');
|
|
58
58
|
if (reusedCache) {
|
|
59
59
|
this.viewCache = new Map(reusedCache);
|
|
60
60
|
}
|
|
@@ -69,8 +69,8 @@ class Db {
|
|
|
69
69
|
return clone;
|
|
70
70
|
}
|
|
71
71
|
with(patch) {
|
|
72
|
-
return this.update(db => {
|
|
73
|
-
objectKeys(db.tables).forEach(entityName => {
|
|
72
|
+
return this.update((db) => {
|
|
73
|
+
objectKeys(db.tables).forEach((entityName) => {
|
|
74
74
|
if (patch[entityName]) {
|
|
75
75
|
db.tables[entityName] = db.tables[entityName].with(patch[entityName]);
|
|
76
76
|
}
|
|
@@ -100,12 +100,12 @@ class Db {
|
|
|
100
100
|
dependencies = view.getDependencies(this, params);
|
|
101
101
|
shouldUpdate = !compare(cacheItem.dependencies, dependencies);
|
|
102
102
|
}
|
|
103
|
-
|
|
103
|
+
const previousValue = cacheItem.currentValue;
|
|
104
104
|
if (shouldUpdate) {
|
|
105
105
|
cacheItem.dependencies = dependencies;
|
|
106
|
-
|
|
106
|
+
const newValue = view.compute(this, params, dependencies);
|
|
107
107
|
cacheItem.computedOnDb = this;
|
|
108
|
-
|
|
108
|
+
const compareResults = view.compareResults || isEqual;
|
|
109
109
|
if (!compareResults(previousValue, newValue)) {
|
|
110
110
|
if (view.traceDiff) {
|
|
111
111
|
console.debug(difference(previousValue, newValue));
|
|
@@ -160,7 +160,7 @@ class DbTable {
|
|
|
160
160
|
this.state = state;
|
|
161
161
|
this.q = q;
|
|
162
162
|
if (!state) {
|
|
163
|
-
const indexes = (schema.indexes || []).map(indexDef => {
|
|
163
|
+
const indexes = (schema.indexes || []).map((indexDef) => {
|
|
164
164
|
return {
|
|
165
165
|
field: indexDef,
|
|
166
166
|
map: I.Map(),
|
|
@@ -196,7 +196,7 @@ class DbTable {
|
|
|
196
196
|
}
|
|
197
197
|
/* Mutation */
|
|
198
198
|
with(patch) {
|
|
199
|
-
const updates = patch.map(entityPatch => {
|
|
199
|
+
const updates = patch.map((entityPatch) => {
|
|
200
200
|
const id = this.getId(entityPatch);
|
|
201
201
|
const immId = this.keyToImmutable(id);
|
|
202
202
|
const existing = this.state.pk.get(immId);
|
|
@@ -208,52 +208,56 @@ class DbTable {
|
|
|
208
208
|
isDeleted = updated[this.schema.deleteFlag] === true;
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
-
return {
|
|
211
|
+
return {
|
|
212
|
+
id, immId, patch: entityPatch, existing, updated, isNew: !existing, isDeleted,
|
|
213
|
+
};
|
|
212
214
|
});
|
|
213
|
-
const idVal = Seq.Keyed(updates.map(entity => [entity.immId, entity.updated]));
|
|
215
|
+
const idVal = Seq.Keyed(updates.map((entity) => [entity.immId, entity.updated]));
|
|
214
216
|
let newPk = this.state.pk.merge(idVal);
|
|
215
217
|
// TBD: replace with deleteAll after migrating to immutable 4
|
|
216
|
-
updates
|
|
218
|
+
updates
|
|
219
|
+
.filter((u) => u.isDeleted)
|
|
220
|
+
.forEach((u) => {
|
|
217
221
|
newPk = newPk.delete(u.immId);
|
|
218
222
|
});
|
|
219
|
-
const newIndexes = this.state.indexes.map(index => {
|
|
223
|
+
const newIndexes = this.state.indexes.map((index) => {
|
|
220
224
|
let newMap = index.map;
|
|
221
225
|
for (let n = 0; n < updates.length; n++) {
|
|
222
|
-
|
|
226
|
+
const update = updates[n];
|
|
223
227
|
const newKey = update.updated[index.field];
|
|
224
228
|
if (update.existing) {
|
|
225
229
|
const oldKey = update.existing[index.field];
|
|
226
230
|
if (oldKey !== newKey || update.isDeleted) {
|
|
227
|
-
newMap = newMap.update(oldKey, set => set.remove(update.immId));
|
|
231
|
+
newMap = newMap.update(oldKey, (set) => set.remove(update.immId));
|
|
228
232
|
}
|
|
229
233
|
}
|
|
230
234
|
if (!update.isDeleted) {
|
|
231
|
-
newMap = newMap.update(newKey, I.Set(), set => set.add(update.immId));
|
|
235
|
+
newMap = newMap.update(newKey, I.Set(), (set) => set.add(update.immId));
|
|
232
236
|
}
|
|
233
237
|
}
|
|
234
238
|
return Object.assign(Object.assign({}, index), { map: newMap });
|
|
235
239
|
});
|
|
236
240
|
const newState = { pk: newPk, indexes: newIndexes };
|
|
237
|
-
return this.update(t => t.state = newState);
|
|
241
|
+
return this.update((t) => (t.state = newState));
|
|
238
242
|
}
|
|
239
243
|
/* Query */
|
|
240
244
|
find(filter) {
|
|
241
|
-
return this.update(t => t.q = Object.assign(Object.assign({}, t.q), { filter: Object.assign(Object.assign({}, this.q.filter), filter) }));
|
|
245
|
+
return this.update((t) => (t.q = Object.assign(Object.assign({}, t.q), { filter: Object.assign(Object.assign({}, this.q.filter), filter) })));
|
|
242
246
|
}
|
|
243
247
|
order(order) {
|
|
244
|
-
return this.update(t => t.q = Object.assign(Object.assign({}, t.q), { sorting: order }));
|
|
248
|
+
return this.update((t) => (t.q = Object.assign(Object.assign({}, t.q), { sorting: order })));
|
|
245
249
|
}
|
|
246
250
|
orderBy(field, direction = 'asc') {
|
|
247
|
-
return this.update(t => t.q = Object.assign(Object.assign({}, t.q), { sorting: [{ field, direction }] }));
|
|
251
|
+
return this.update((t) => (t.q = Object.assign(Object.assign({}, t.q), { sorting: [{ field, direction }] })));
|
|
248
252
|
}
|
|
249
253
|
thenBy(field, direction) {
|
|
250
|
-
return this.update(t => t.q = Object.assign(Object.assign({}, t.q), { sorting: [...t.q.sorting, { field, direction }] }));
|
|
254
|
+
return this.update((t) => (t.q = Object.assign(Object.assign({}, t.q), { sorting: [...t.q.sorting, { field, direction }] })));
|
|
251
255
|
}
|
|
252
256
|
search(text) {
|
|
253
257
|
if (!this.schema.searchBy) {
|
|
254
258
|
throw new Error(`Can't search in the ${this.schema.typeName} table - searchBy is not defined in the schema.`);
|
|
255
259
|
}
|
|
256
|
-
return this.update(t => t.q = Object.assign(Object.assign({}, t.q), { search: text }));
|
|
260
|
+
return this.update((t) => (t.q = Object.assign(Object.assign({}, t.q), { search: text })));
|
|
257
261
|
}
|
|
258
262
|
/* Materializing */
|
|
259
263
|
range(from, count) {
|
|
@@ -276,14 +280,14 @@ class DbTable {
|
|
|
276
280
|
let result = null;
|
|
277
281
|
let filter = q.filter;
|
|
278
282
|
if (filter) {
|
|
279
|
-
|
|
283
|
+
const indexes = this.state.indexes;
|
|
280
284
|
// Try to use indexes to fulfill filter conditions
|
|
281
285
|
for (let n = 0; n < indexes.length; n++) {
|
|
282
286
|
const index = indexes[n];
|
|
283
287
|
if (index.field in filter) {
|
|
284
288
|
const _a = filter, _b = index.field, condition = _a[_b], rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
|
|
285
289
|
let conditionValues = null;
|
|
286
|
-
if (condition != null && typeof condition ===
|
|
290
|
+
if (condition != null && typeof condition === 'object') {
|
|
287
291
|
// Attempt to use index for 'in' and 'isNull' criteria.
|
|
288
292
|
// We need to be very conservative here, indexed field should work the same way as getPatternPredicate. So
|
|
289
293
|
// - it's better to leave corner cases to getPatternPredicate
|
|
@@ -334,15 +338,15 @@ class DbTable {
|
|
|
334
338
|
result = this.state.pk.toArray();
|
|
335
339
|
}
|
|
336
340
|
if (filter) {
|
|
337
|
-
|
|
341
|
+
const predicate = getFilterPredicate(q.filter);
|
|
338
342
|
result = result.filter(predicate);
|
|
339
343
|
}
|
|
340
344
|
if (q.search) {
|
|
341
|
-
|
|
342
|
-
result = result.filter(item => searchFilter(this.schema.searchBy.map(field => item[field])));
|
|
345
|
+
const searchFilter = getSearchFilter(q.search);
|
|
346
|
+
result = result.filter((item) => searchFilter(this.schema.searchBy.map((field) => item[field])));
|
|
343
347
|
}
|
|
344
348
|
if (q.sorting) {
|
|
345
|
-
|
|
349
|
+
const comparer = getOrderComparer(q.sorting);
|
|
346
350
|
result = result.sort(comparer);
|
|
347
351
|
}
|
|
348
352
|
if (q.range) {
|
|
@@ -354,8 +358,8 @@ class DbTable {
|
|
|
354
358
|
|
|
355
359
|
function unionPatches(patches) {
|
|
356
360
|
const result = {};
|
|
357
|
-
patches.forEach(patch => {
|
|
358
|
-
objectKeys(patch).forEach(tableName => {
|
|
361
|
+
patches.forEach((patch) => {
|
|
362
|
+
objectKeys(patch).forEach((tableName) => {
|
|
359
363
|
result[tableName] = result[tableName] ? [...result[tableName], ...patch[tableName]] : patch[tableName];
|
|
360
364
|
});
|
|
361
365
|
});
|
|
@@ -363,13 +367,13 @@ function unionPatches(patches) {
|
|
|
363
367
|
}
|
|
364
368
|
function mergeEntityPatches(tables, patch) {
|
|
365
369
|
const result = {};
|
|
366
|
-
objectKeys(patch).forEach(key => {
|
|
370
|
+
objectKeys(patch).forEach((key) => {
|
|
367
371
|
const table = tables[key];
|
|
368
|
-
const groupedEntities = groupBy(patch[key], item => table.getId(item));
|
|
369
|
-
const tablePatch = map(groupedEntities, entities => {
|
|
372
|
+
const groupedEntities = groupBy(patch[key], (item) => table.getId(item));
|
|
373
|
+
const tablePatch = map(groupedEntities, (entities) => {
|
|
370
374
|
const result = merge({}, ...entities);
|
|
371
375
|
if (process.env.NODE_ENV !== 'production') {
|
|
372
|
-
const props = objectKeys(result).filter(prop => Object.keys(countBy(entities.filter(entity => entity[prop] !== undefined), entity => entity[prop])).length > 1);
|
|
376
|
+
const props = objectKeys(result).filter((prop) => Object.keys(countBy(entities.filter((entity) => entity[prop] !== undefined), (entity) => entity[prop])).length > 1);
|
|
373
377
|
if (props.length) {
|
|
374
378
|
console.warn('mergeEntityPatches: Different property values found for the same entity.\nProperty names:\n', props, '\nEntities:\n', ...entities);
|
|
375
379
|
}
|
|
@@ -382,7 +386,7 @@ function mergeEntityPatches(tables, patch) {
|
|
|
382
386
|
}
|
|
383
387
|
function flattenResponseHelper(result, object, tablesByTypeName) {
|
|
384
388
|
if (Array.isArray(object)) {
|
|
385
|
-
object.forEach(item => flattenResponseHelper(result, item, tablesByTypeName));
|
|
389
|
+
object.forEach((item) => flattenResponseHelper(result, item, tablesByTypeName));
|
|
386
390
|
}
|
|
387
391
|
else if (typeof object === 'object') {
|
|
388
392
|
const clone = {};
|
|
@@ -395,13 +399,13 @@ function flattenResponseHelper(result, object, tablesByTypeName) {
|
|
|
395
399
|
fields = table.schema.fields;
|
|
396
400
|
}
|
|
397
401
|
}
|
|
398
|
-
for (
|
|
402
|
+
for (const key in object) {
|
|
399
403
|
const value = object[key];
|
|
400
404
|
const field = fields[key];
|
|
401
405
|
if ((field && !!field.disableFlatten)
|
|
402
406
|
|| typeof value !== 'object'
|
|
403
407
|
|| value === null
|
|
404
|
-
|| (Array.isArray(value) && value.every(item => typeof item !== 'object'))) {
|
|
408
|
+
|| (Array.isArray(value) && value.every((item) => typeof item !== 'object'))) {
|
|
405
409
|
clone[key] = value;
|
|
406
410
|
}
|
|
407
411
|
else {
|
|
@@ -415,32 +419,32 @@ function flattenResponseHelper(result, object, tablesByTypeName) {
|
|
|
415
419
|
}
|
|
416
420
|
function flattenResponse(response, tables) {
|
|
417
421
|
const result = {};
|
|
418
|
-
|
|
419
|
-
Object.values(tables).forEach(table => tablesByTypeName[table.schema.typeName] = table);
|
|
420
|
-
objectKeys(tables).forEach(tableName => tablesByTypeName);
|
|
421
|
-
objectKeys(tables).forEach(key => result[key] = []);
|
|
422
|
+
const tablesByTypeName = {};
|
|
423
|
+
Object.values(tables).forEach((table) => (tablesByTypeName[table.schema.typeName] = table));
|
|
424
|
+
objectKeys(tables).forEach((tableName) => tablesByTypeName);
|
|
425
|
+
objectKeys(tables).forEach((key) => (result[key] = []));
|
|
422
426
|
flattenResponseHelper(result, response, tablesByTypeName);
|
|
423
427
|
return result;
|
|
424
428
|
}
|
|
425
429
|
function isPatchBlank(patch) {
|
|
426
|
-
return !objectKeys(patch).some(key => patch[key].length > 0);
|
|
430
|
+
return !objectKeys(patch).some((key) => patch[key].length > 0);
|
|
427
431
|
}
|
|
428
432
|
/**
|
|
429
433
|
* Given several patches, creates a new single patch with all fields from all entities in all patches.
|
|
430
434
|
*/
|
|
431
435
|
function makeCumulativePatch(updatedDb, patches, clientIdsMap) {
|
|
432
436
|
const result = {};
|
|
433
|
-
objectKeys(updatedDb.tables).forEach(entityName => {
|
|
437
|
+
objectKeys(updatedDb.tables).forEach((entityName) => {
|
|
434
438
|
const table = updatedDb.tables[entityName];
|
|
435
439
|
const schema = table.schema;
|
|
436
440
|
let ids = I.Set();
|
|
437
|
-
patches.forEach(patch => {
|
|
438
|
-
|
|
439
|
-
ids = ids.union(filteredPatch.map(e => table.getId(e)));
|
|
441
|
+
patches.forEach((patch) => {
|
|
442
|
+
const filteredPatch = (patch[entityName] || []).filter((entity) => hasServerFields(entity, schema, clientIdsMap, updatedDb.tables));
|
|
443
|
+
ids = ids.union(filteredPatch.map((e) => table.getId(e)));
|
|
440
444
|
});
|
|
441
445
|
const entities = ids
|
|
442
|
-
.map(id => table.byId(id))
|
|
443
|
-
.filter(e => !isClientOnly(e, schema))
|
|
446
|
+
.map((id) => table.byId(id))
|
|
447
|
+
.filter((e) => !isClientOnly(e, schema))
|
|
444
448
|
.toArray();
|
|
445
449
|
if (entities.length > 0) {
|
|
446
450
|
result[entityName] = entities;
|
|
@@ -469,25 +473,25 @@ function isNew(entity, schema, clientIdsMap) {
|
|
|
469
473
|
return !clientIdsMap.clientToServer(id);
|
|
470
474
|
}
|
|
471
475
|
function hasServerFields(entity, schema, clientIdsMap, tables) {
|
|
472
|
-
const fullEntity = Object.assign(Object.assign({}, tables[schema.tableName].byId(entity.id) || {}), entity);
|
|
476
|
+
const fullEntity = Object.assign(Object.assign({}, (tables[schema.tableName].byId(entity.id) || {})), entity);
|
|
473
477
|
if (isClientOnly(fullEntity, schema)) {
|
|
474
478
|
return false;
|
|
475
479
|
}
|
|
476
|
-
return objectKeys(entity).some(fieldName => {
|
|
480
|
+
return objectKeys(entity).some((fieldName) => {
|
|
477
481
|
const fieldSchema = schema.fields[fieldName];
|
|
478
482
|
return !fieldSchema || !(fieldSchema.isClientOnly || fieldSchema.isReadOnly || (fieldSchema.isGenerated && !isNew(entity, schema, clientIdsMap)));
|
|
479
483
|
});
|
|
480
484
|
}
|
|
481
485
|
function getParentEntities(patch, tables) {
|
|
482
486
|
const dependenciesPatch = {};
|
|
483
|
-
objectKeys(patch).forEach(key => {
|
|
487
|
+
objectKeys(patch).forEach((key) => {
|
|
484
488
|
const table = tables[key];
|
|
485
489
|
const tableSchema = table.schema;
|
|
486
|
-
const fields = filter(map(tableSchema.fields, (field, name) => (Object.assign(Object.assign({}, field), { name }))), field => field.fk && field.fk.relationType == DbRelationType.Aggregation);
|
|
490
|
+
const fields = filter(map(tableSchema.fields, (field, name) => (Object.assign(Object.assign({}, field), { name }))), (field) => field.fk && field.fk.relationType == DbRelationType.Aggregation);
|
|
487
491
|
const tablePatch = patch[key];
|
|
488
|
-
fields.forEach(field => {
|
|
489
|
-
const { fk: { tableName }, name } = field;
|
|
490
|
-
tablePatch.forEach(entity => {
|
|
492
|
+
fields.forEach((field) => {
|
|
493
|
+
const { fk: { tableName }, name, } = field;
|
|
494
|
+
tablePatch.forEach((entity) => {
|
|
491
495
|
const actualTableName = (typeof tableName == 'function' ? tableName(entity) : tableName);
|
|
492
496
|
const dbEntity = table.byId(table.getId(entity));
|
|
493
497
|
const parentEntity = tables[actualTableName].byId(dbEntity[name]);
|
|
@@ -505,7 +509,7 @@ function getEntityParentDependencies(entity, entityName, tables) {
|
|
|
505
509
|
let patch = { [entityName]: [entity] };
|
|
506
510
|
const resultPatches = [];
|
|
507
511
|
while (true) {
|
|
508
|
-
|
|
512
|
+
const parents = getParentEntities(patch, tables);
|
|
509
513
|
if (isPatchBlank(parents)) {
|
|
510
514
|
break;
|
|
511
515
|
}
|
|
@@ -555,7 +559,7 @@ class TempIdMap {
|
|
|
555
559
|
for (let n = 0; n < keys.length; n++) {
|
|
556
560
|
const key = keys[n];
|
|
557
561
|
let condition = filter[key];
|
|
558
|
-
if (condition != null && typeof condition ===
|
|
562
|
+
if (condition != null && typeof condition === 'object') {
|
|
559
563
|
condition = Object.assign({}, condition);
|
|
560
564
|
if ('in' in condition && Array.isArray(condition.in) && condition.in.length) {
|
|
561
565
|
condition.in = condition.in.map(clientToServer);
|
|
@@ -571,28 +575,28 @@ class TempIdMap {
|
|
|
571
575
|
}
|
|
572
576
|
copyPatch(patch) {
|
|
573
577
|
const newPatch = Object.assign({}, patch);
|
|
574
|
-
objectKeys(patch).forEach(tableName => {
|
|
575
|
-
|
|
578
|
+
objectKeys(patch).forEach((tableName) => {
|
|
579
|
+
const tablePatch = patch[tableName].map((entityPatch) => (Object.assign({}, entityPatch)));
|
|
576
580
|
newPatch[tableName] = tablePatch;
|
|
577
581
|
});
|
|
578
582
|
return newPatch;
|
|
579
583
|
}
|
|
580
584
|
// Iterate thru every field in every patch for every table, matching certain field criteria. The patch is mutated!
|
|
581
585
|
mapFields(patch, filter, callback) {
|
|
582
|
-
objectKeys(patch).forEach(tableName => {
|
|
586
|
+
objectKeys(patch).forEach((tableName) => {
|
|
583
587
|
const schema = this.db.tables[tableName].schema;
|
|
584
588
|
const fields = objectKeys(schema.fields || [])
|
|
585
|
-
.map(fieldName => {
|
|
589
|
+
.map((fieldName) => {
|
|
586
590
|
const fieldSchema = schema.fields[fieldName];
|
|
587
591
|
if (filter(fieldSchema, fieldName)) {
|
|
588
592
|
return { name: fieldName, schema: fieldSchema };
|
|
589
593
|
}
|
|
590
594
|
})
|
|
591
|
-
.filter(f => !!f);
|
|
595
|
+
.filter((f) => !!f);
|
|
592
596
|
if (!fields.length) {
|
|
593
597
|
return;
|
|
594
598
|
}
|
|
595
|
-
patch[tableName].forEach(entityPatch => {
|
|
599
|
+
patch[tableName].forEach((entityPatch) => {
|
|
596
600
|
for (let n = 0; n < fields.length; n++) {
|
|
597
601
|
const field = fields[n];
|
|
598
602
|
const fieldValue = entityPatch[field.name];
|
|
@@ -615,7 +619,7 @@ class TempIdMap {
|
|
|
615
619
|
serverToClientPatch(patch) {
|
|
616
620
|
patch = this.copyPatch(patch);
|
|
617
621
|
// We map PK in a separate pass, as we need to remap all PKs before re-mapping FKs
|
|
618
|
-
this.mapFields(patch, f => f.isGenerated, (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
622
|
+
this.mapFields(patch, (f) => f.isGenerated, (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
619
623
|
let clientId = this.getServerToClientMap(tableName).get(fieldValue);
|
|
620
624
|
if (!clientId) {
|
|
621
625
|
clientId = getTempId();
|
|
@@ -624,8 +628,8 @@ class TempIdMap {
|
|
|
624
628
|
}
|
|
625
629
|
entityPatch[fieldName] = clientId;
|
|
626
630
|
});
|
|
627
|
-
this.mapFields(patch, f => !!(f.fk ||
|
|
628
|
-
let isUndefined = typeof
|
|
631
|
+
this.mapFields(patch, (f) => !!(f.fk || f.default != null || f.toClient), (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
632
|
+
let isUndefined = typeof fieldValue === 'undefined';
|
|
629
633
|
if (fieldSchema.default != null && fieldValue == null) {
|
|
630
634
|
fieldValue = fieldSchema.default;
|
|
631
635
|
isUndefined = false;
|
|
@@ -651,7 +655,7 @@ class TempIdMap {
|
|
|
651
655
|
}
|
|
652
656
|
clientToServerPatch(patch) {
|
|
653
657
|
patch = this.copyPatch(patch);
|
|
654
|
-
this.mapFields(patch, f => f.isGenerated || !!f.fk, (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
658
|
+
this.mapFields(patch, (f) => f.isGenerated || !!f.fk, (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
655
659
|
if (fieldValue != null) {
|
|
656
660
|
const existingId = this.clientToServerIds.get(fieldValue);
|
|
657
661
|
if (existingId) {
|
|
@@ -659,22 +663,22 @@ class TempIdMap {
|
|
|
659
663
|
}
|
|
660
664
|
}
|
|
661
665
|
});
|
|
662
|
-
this.mapFields(patch, f => !(f.isClientOnly || f.isReadOnly) && !!f.toServer, (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
666
|
+
this.mapFields(patch, (f) => !(f.isClientOnly || f.isReadOnly) && !!f.toServer, (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
663
667
|
entityPatch[fieldName] = fieldSchema.toServer(entityPatch[fieldName]);
|
|
664
668
|
});
|
|
665
|
-
this.mapFields(patch, meta => meta.isClientOnly || meta.isReadOnly, (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
669
|
+
this.mapFields(patch, (meta) => meta.isClientOnly || meta.isReadOnly, (fieldName, fieldSchema, fieldValue, entityPatch, tableName) => {
|
|
666
670
|
delete entityPatch[fieldName];
|
|
667
671
|
});
|
|
668
672
|
return patch;
|
|
669
673
|
}
|
|
670
674
|
appendServerMapping(response) {
|
|
671
|
-
objectKeys(response.submit).forEach(tableName => {
|
|
675
|
+
objectKeys(response.submit).forEach((tableName) => {
|
|
672
676
|
if (this.db.tables[tableName]) {
|
|
673
677
|
const tablePatch = response.submit[tableName];
|
|
674
678
|
if (tablePatch) {
|
|
675
679
|
const serverToClientIds = this.getServerToClientMap(tableName);
|
|
676
680
|
const table = this.db.tables[tableName];
|
|
677
|
-
tablePatch.forEach(patch => {
|
|
681
|
+
tablePatch.forEach((patch) => {
|
|
678
682
|
if (isTempId(patch.id)) {
|
|
679
683
|
const clientId = patch.id;
|
|
680
684
|
const serverId = table.getId(patch.payload);
|
|
@@ -741,7 +745,7 @@ class Loader {
|
|
|
741
745
|
if (this.options.clientToServerRequest) {
|
|
742
746
|
serverRequest = this.options.clientToServerRequest(serverRequest);
|
|
743
747
|
}
|
|
744
|
-
state.promise = this.options.api(serverRequest).then(result => {
|
|
748
|
+
state.promise = this.options.api(serverRequest).then((result) => {
|
|
745
749
|
this.loaded.append(state.missing, result);
|
|
746
750
|
this.loadedAndLoading.append(state.missing, result);
|
|
747
751
|
state.missing = null;
|
|
@@ -793,17 +797,21 @@ class ListLoadingTracker {
|
|
|
793
797
|
if (search) {
|
|
794
798
|
options.search = search;
|
|
795
799
|
}
|
|
796
|
-
|
|
800
|
+
const keyObject = Object.assign(Object.assign({}, options), unknownFields);
|
|
797
801
|
const key = JSON.stringify(keyObject);
|
|
798
802
|
let entry = this.cache.get(key);
|
|
799
803
|
if (!entry) {
|
|
800
|
-
entry = {
|
|
804
|
+
entry = {
|
|
805
|
+
options, count: 0, maxCount: null, isComplete: false,
|
|
806
|
+
};
|
|
801
807
|
this.cache.set(key, entry);
|
|
802
808
|
}
|
|
803
|
-
return {
|
|
809
|
+
return {
|
|
810
|
+
options, range, unknownFields, entry,
|
|
811
|
+
};
|
|
804
812
|
}
|
|
805
813
|
diff(request) {
|
|
806
|
-
const { options, range, unknownFields, entry } = this.prepare(request);
|
|
814
|
+
const { options, range, unknownFields, entry, } = this.prepare(request);
|
|
807
815
|
if (entry.isComplete) {
|
|
808
816
|
return null;
|
|
809
817
|
}
|
|
@@ -829,7 +837,7 @@ class ListLoadingTracker {
|
|
|
829
837
|
return { knownCount: Math.max(entry.count, entry.maxCount), exactCount: entry.maxCount };
|
|
830
838
|
}
|
|
831
839
|
append(request, response) {
|
|
832
|
-
const { options, range, unknownFields, entry } = this.prepare(request);
|
|
840
|
+
const { options, range, unknownFields, entry, } = this.prepare(request);
|
|
833
841
|
if (response) {
|
|
834
842
|
const list = this.extractList(response);
|
|
835
843
|
if (list.count) {
|
|
@@ -841,7 +849,7 @@ class ListLoadingTracker {
|
|
|
841
849
|
entry.isComplete = true;
|
|
842
850
|
}
|
|
843
851
|
else {
|
|
844
|
-
const from =
|
|
852
|
+
const from = list.from == null ? range.from : list.from;
|
|
845
853
|
if (list.items.length > 0) {
|
|
846
854
|
entry.count = Math.max(entry.count, from + list.items.length);
|
|
847
855
|
}
|
|
@@ -942,23 +950,29 @@ class DbRef {
|
|
|
942
950
|
}
|
|
943
951
|
beforeUpdate(patch, tables, prevTables) {
|
|
944
952
|
let patchAndDependencies = {};
|
|
945
|
-
objectKeys(tables)
|
|
953
|
+
objectKeys(tables)
|
|
954
|
+
.filter((entityName) => patch[entityName] && !tables[entityName].schema.beforeUpdate)
|
|
955
|
+
.forEach((entityName) => {
|
|
946
956
|
patchAndDependencies[entityName] = patch[entityName];
|
|
947
957
|
});
|
|
948
|
-
objectKeys(tables)
|
|
958
|
+
objectKeys(tables)
|
|
959
|
+
.filter((entityName) => patch[entityName] && tables[entityName].schema.beforeUpdate)
|
|
960
|
+
.forEach((entityName) => {
|
|
949
961
|
const schema = tables[entityName].schema;
|
|
950
962
|
const { beforeUpdate } = schema;
|
|
951
|
-
|
|
963
|
+
const context = {
|
|
952
964
|
clientIdsMap: this.tempIdMap,
|
|
953
965
|
schema,
|
|
954
966
|
tables,
|
|
955
967
|
prevTables,
|
|
956
968
|
};
|
|
957
|
-
const results = patch[entityName].map(e => beforeUpdate(e, context));
|
|
958
|
-
const updatedPatch = { [entityName]: results.map(result => result.entity) };
|
|
959
|
-
const dependentEntityPatchesForUpdate = unionPatches(results.filter(result => result.dependentEntities).map(result => result.dependentEntities));
|
|
969
|
+
const results = patch[entityName].map((e) => beforeUpdate(e, context));
|
|
970
|
+
const updatedPatch = { [entityName]: results.map((result) => result.entity) };
|
|
971
|
+
const dependentEntityPatchesForUpdate = unionPatches(results.filter((result) => result.dependentEntities).map((result) => result.dependentEntities));
|
|
960
972
|
const dependentEntityPatches = this.beforeUpdate(dependentEntityPatchesForUpdate, tables, prevTables);
|
|
961
|
-
patchAndDependencies = mergeEntityPatches(tables, unionPatches([
|
|
973
|
+
patchAndDependencies = mergeEntityPatches(tables, unionPatches([
|
|
974
|
+
patchAndDependencies, updatedPatch, dependentEntityPatches,
|
|
975
|
+
]));
|
|
962
976
|
});
|
|
963
977
|
return patchAndDependencies;
|
|
964
978
|
}
|
|
@@ -977,7 +991,7 @@ class DbRef {
|
|
|
977
991
|
makeCumulativePatch() {
|
|
978
992
|
const lastLogEntry = this.log.length;
|
|
979
993
|
const logEntriesToSave = this.log.slice(this.savedPoint, lastLogEntry);
|
|
980
|
-
let cumulativePatch = makeCumulativePatch(this.db, logEntriesToSave.map(t => t.patch), this.tempIdMap);
|
|
994
|
+
let cumulativePatch = makeCumulativePatch(this.db, logEntriesToSave.map((t) => t.patch), this.tempIdMap);
|
|
981
995
|
cumulativePatch = this.tempIdMap.clientToServerPatch(cumulativePatch);
|
|
982
996
|
return cumulativePatch;
|
|
983
997
|
}
|
|
@@ -1000,7 +1014,9 @@ class DbRef {
|
|
|
1000
1014
|
currentParams: null,
|
|
1001
1015
|
currentValue: null,
|
|
1002
1016
|
onUpdate,
|
|
1003
|
-
unsubscribe: () => {
|
|
1017
|
+
unsubscribe: () => {
|
|
1018
|
+
this.subscriptions.delete(id);
|
|
1019
|
+
},
|
|
1004
1020
|
};
|
|
1005
1021
|
subscription.update(params);
|
|
1006
1022
|
this.subscriptions.set(id, subscription);
|
|
@@ -1008,12 +1024,12 @@ class DbRef {
|
|
|
1008
1024
|
}
|
|
1009
1025
|
onUpdate(handler) {
|
|
1010
1026
|
this.subscribe({
|
|
1011
|
-
compute: db => db,
|
|
1027
|
+
compute: (db) => db,
|
|
1012
1028
|
compareResults: (a, b) => a === b,
|
|
1013
1029
|
}, null, handler);
|
|
1014
1030
|
}
|
|
1015
1031
|
update() {
|
|
1016
|
-
this.subscriptions.forEach(subscription => {
|
|
1032
|
+
this.subscriptions.forEach((subscription) => {
|
|
1017
1033
|
const previousValue = subscription.currentValue;
|
|
1018
1034
|
subscription.update(subscription.currentParams);
|
|
1019
1035
|
if (subscription.currentValue !== previousValue && subscription.onUpdate) {
|
|
@@ -1025,7 +1041,7 @@ class DbRef {
|
|
|
1025
1041
|
this.saveErrorHandlers.push(handler);
|
|
1026
1042
|
}
|
|
1027
1043
|
saveError(request, error) {
|
|
1028
|
-
this.saveErrorHandlers.forEach(handler => handler(request, error));
|
|
1044
|
+
this.saveErrorHandlers.forEach((handler) => handler(request, error));
|
|
1029
1045
|
}
|
|
1030
1046
|
makeLoader(options) {
|
|
1031
1047
|
const loader = new Loader(this, () => new SimpleLoadingTracker(), options);
|