tinybase 1.0.2 → 1.1.0-beta.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/lib/checkpoints.d.ts +945 -0
- package/lib/checkpoints.js +1 -0
- package/lib/checkpoints.js.gz +0 -0
- package/lib/common.d.ts +115 -0
- package/lib/common.js +1 -0
- package/lib/common.js.gz +0 -0
- package/lib/debug/checkpoints.d.ts +66 -0
- package/lib/debug/checkpoints.js +332 -0
- package/lib/debug/common.js +3 -0
- package/lib/debug/indexes.d.ts +167 -6
- package/lib/debug/indexes.js +431 -0
- package/lib/debug/metrics.d.ts +72 -0
- package/lib/debug/metrics.js +401 -0
- package/lib/debug/persisters.js +191 -0
- package/lib/debug/relationships.d.ts +86 -1
- package/lib/debug/relationships.js +434 -0
- package/lib/debug/store.d.ts +187 -5
- package/lib/debug/store.js +783 -0
- package/lib/debug/tinybase.js +144 -39
- package/lib/indexes.d.ts +939 -0
- package/lib/indexes.js +1 -0
- package/lib/indexes.js.gz +0 -0
- package/lib/metrics.d.ts +829 -0
- package/lib/metrics.js +1 -0
- package/lib/metrics.js.gz +0 -0
- package/lib/persisters.d.ts +711 -0
- package/lib/persisters.js +1 -0
- package/lib/persisters.js.gz +0 -0
- package/lib/relationships.d.ts +1201 -0
- package/lib/relationships.js +1 -0
- package/lib/relationships.js.gz +0 -0
- package/lib/store.d.ts +2688 -0
- package/lib/store.js +1 -0
- package/lib/store.js.gz +0 -0
- package/lib/tinybase.d.ts +13 -0
- package/lib/tinybase.js +1 -0
- package/lib/tinybase.js.gz +0 -0
- package/lib/ui-react.d.ts +7185 -0
- package/lib/ui-react.js +1 -0
- package/lib/ui-react.js.gz +0 -0
- package/lib/umd/checkpoints.js +1 -0
- package/lib/umd/checkpoints.js.gz +0 -0
- package/lib/umd/common.js +1 -0
- package/lib/umd/common.js.gz +0 -0
- package/lib/umd/indexes.js +1 -0
- package/lib/umd/indexes.js.gz +0 -0
- package/lib/umd/metrics.js +1 -0
- package/lib/umd/metrics.js.gz +0 -0
- package/lib/umd/persisters.js +1 -0
- package/lib/umd/persisters.js.gz +0 -0
- package/lib/umd/relationships.js +1 -0
- package/lib/umd/relationships.js.gz +0 -0
- package/lib/umd/store.js +1 -0
- package/lib/umd/store.js.gz +0 -0
- package/lib/umd/tinybase.js +1 -0
- package/lib/umd/tinybase.js.gz +0 -0
- package/lib/umd/ui-react.js +1 -0
- package/lib/umd/ui-react.js.gz +0 -0
- package/package.json +14 -14
- package/readme.md +2 -2
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @module relationships
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {GetCell, Store} from './store.d';
|
|
14
|
+
import {GetCell, RowCallback, Store} from './store.d';
|
|
15
15
|
import {Id, IdOrNull, Ids} from './common.d';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -39,6 +39,25 @@ export type Relationship = {
|
|
|
39
39
|
linkedRowIds: {[firstRowId: Id]: Ids};
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* The RelationshipCallback type describes a function that takes a
|
|
44
|
+
* Relationship's Id and a callback to loop over each local Row within it.
|
|
45
|
+
*
|
|
46
|
+
* A RelationshipCallback is provided when using the forEachRelationship method,
|
|
47
|
+
* so that you can do something based on every Relationship in the Relationships
|
|
48
|
+
* object. See that method for specific examples.
|
|
49
|
+
*
|
|
50
|
+
* @param relationshipId The Id of the Relationship that the callback can
|
|
51
|
+
* operate on.
|
|
52
|
+
* @param forEachRow A function that will let you iterate over the local Row
|
|
53
|
+
* objects in this Relationship.
|
|
54
|
+
* @category Callback
|
|
55
|
+
*/
|
|
56
|
+
export type RelationshipCallback = (
|
|
57
|
+
relationshipId: Id,
|
|
58
|
+
forEachRow: (rowCallback: RowCallback) => void,
|
|
59
|
+
) => void;
|
|
60
|
+
|
|
42
61
|
/**
|
|
43
62
|
* The RemoteRowIdListener type describes a function that is used to listen to
|
|
44
63
|
* changes to the remote Row Id end of a Relationship.
|
|
@@ -405,6 +424,72 @@ export interface Relationships {
|
|
|
405
424
|
*/
|
|
406
425
|
getRelationshipIds(): Ids;
|
|
407
426
|
|
|
427
|
+
/**
|
|
428
|
+
* The forEachRelationship method takes a function that it will then call for
|
|
429
|
+
* each Relationship in a specified Relationships object.
|
|
430
|
+
*
|
|
431
|
+
* This method is useful for iterating over the structure of the Relationships
|
|
432
|
+
* object in a functional style. The `relationshipCallback` parameter is a
|
|
433
|
+
* RelationshipCallback function that will be called with the Id of each
|
|
434
|
+
* Relationship, and with a function that can then be used to iterate over
|
|
435
|
+
* each local Row involved in the Relationship.
|
|
436
|
+
*
|
|
437
|
+
* @param relationshipCallback The function that should be called for every
|
|
438
|
+
* Relationship.
|
|
439
|
+
* @example
|
|
440
|
+
* This example iterates over each Relationship in a Relationships object, and
|
|
441
|
+
* lists each Row Id within them.
|
|
442
|
+
*
|
|
443
|
+
* ```js
|
|
444
|
+
* const store = createStore().setTable('pets', {
|
|
445
|
+
* fido: {species: 'dog', next: 'felix'},
|
|
446
|
+
* felix: {species: 'cat', next: 'cujo'},
|
|
447
|
+
* cujo: {species: 'dog'},
|
|
448
|
+
* });
|
|
449
|
+
* const relationships = createRelationships(store)
|
|
450
|
+
* .setRelationshipDefinition('petSpecies', 'pets', 'species', 'species')
|
|
451
|
+
* .setRelationshipDefinition('petSequence', 'pets', 'pets', 'next');
|
|
452
|
+
*
|
|
453
|
+
* relationships.forEachRelationship((relationshipId, forEachRow) => {
|
|
454
|
+
* console.log(relationshipId);
|
|
455
|
+
* forEachRow((rowId) => console.log(`- ${rowId}`));
|
|
456
|
+
* });
|
|
457
|
+
* // -> 'petSpecies'
|
|
458
|
+
* // -> '- fido'
|
|
459
|
+
* // -> '- felix'
|
|
460
|
+
* // -> '- cujo'
|
|
461
|
+
* // -> 'petSequence'
|
|
462
|
+
* // -> '- fido'
|
|
463
|
+
* // -> '- felix'
|
|
464
|
+
* // -> '- cujo'
|
|
465
|
+
* ```
|
|
466
|
+
* @category Iterator
|
|
467
|
+
*/
|
|
468
|
+
forEachRelationship(relationshipCallback: RelationshipCallback): void;
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* The hasRelationship method returns a boolean indicating whether a given
|
|
472
|
+
* Relationship exists in the Relationships object.
|
|
473
|
+
*
|
|
474
|
+
* @param relationshipId The Id of a possible Relationship in the
|
|
475
|
+
* Relationships object.
|
|
476
|
+
* @returns Whether a Relationship with that Id exists.
|
|
477
|
+
* @example
|
|
478
|
+
* This example shows two simple Relationship existence checks.
|
|
479
|
+
*
|
|
480
|
+
* ```js
|
|
481
|
+
* const relationships = createRelationships(
|
|
482
|
+
* createStore(),
|
|
483
|
+
* ).setRelationshipDefinition('petSpecies', 'pets', 'species', 'species');
|
|
484
|
+
* console.log(relationships.hasRelationship('petSpecies'));
|
|
485
|
+
* // -> true
|
|
486
|
+
* console.log(relationships.hasRelationship('petColor'));
|
|
487
|
+
* // -> false
|
|
488
|
+
* ```
|
|
489
|
+
* @category Getter
|
|
490
|
+
*/
|
|
491
|
+
hasRelationship(indexId: Id): boolean;
|
|
492
|
+
|
|
408
493
|
/**
|
|
409
494
|
* The getLocalTableId method returns the Id of the underlying local Table
|
|
410
495
|
* that is used in the Relationship.
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
const getTypeOf = (thing) => typeof thing;
|
|
2
|
+
const EMPTY_STRING = '';
|
|
3
|
+
const STRING = getTypeOf(EMPTY_STRING);
|
|
4
|
+
|
|
5
|
+
const arrayForEach = (array, cb) => array.forEach(cb);
|
|
6
|
+
const arrayLength = (array) => array.length;
|
|
7
|
+
const arrayIsEmpty = (array) => arrayLength(array) == 0;
|
|
8
|
+
const arrayReduce = (array, cb, initial) => array.reduce(cb, initial);
|
|
9
|
+
const arrayFromSecond = (ids) => ids.slice(1);
|
|
10
|
+
const arrayPush = (array, value) => array.push(value);
|
|
11
|
+
const arrayPop = (array) => array.pop();
|
|
12
|
+
|
|
13
|
+
const isUndefined = (thing) => thing == void 0;
|
|
14
|
+
const ifNotUndefined = (value, then, otherwise) =>
|
|
15
|
+
isUndefined(value) ? otherwise?.() : then(value);
|
|
16
|
+
const isString = (thing) => getTypeOf(thing) == STRING;
|
|
17
|
+
|
|
18
|
+
const collSizeN = (collSizer) => (coll) =>
|
|
19
|
+
arrayReduce(collValues(coll), (total, coll2) => total + collSizer(coll2), 0);
|
|
20
|
+
const collSize = (coll) => coll.size;
|
|
21
|
+
const collSize2 = collSizeN(collSize);
|
|
22
|
+
const collSize3 = collSizeN(collSize2);
|
|
23
|
+
const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
|
|
24
|
+
const collIsEmpty = (coll) => isUndefined(coll) || collSize(coll) == 0;
|
|
25
|
+
const collValues = (coll) => [...(coll?.values() ?? [])];
|
|
26
|
+
const collClear = (coll) => coll.clear();
|
|
27
|
+
const collForEach = (coll, cb) => coll?.forEach(cb);
|
|
28
|
+
const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
|
|
29
|
+
|
|
30
|
+
const mapNew = (entries) => new Map(entries);
|
|
31
|
+
const mapKeys = (map) => [...(map?.keys() ?? [])];
|
|
32
|
+
const mapGet = (map, key) => map?.get(key);
|
|
33
|
+
const mapForEach = (map, cb) =>
|
|
34
|
+
collForEach(map, (value, key) => cb(key, value));
|
|
35
|
+
const mapSet = (map, key, value) =>
|
|
36
|
+
isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
|
|
37
|
+
const mapEnsure = (map, key, defaultValue, onWillAdd) => {
|
|
38
|
+
if (!collHas(map, key)) {
|
|
39
|
+
onWillAdd?.(defaultValue);
|
|
40
|
+
map.set(key, defaultValue);
|
|
41
|
+
}
|
|
42
|
+
return mapGet(map, key);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const setNew = (entries) => new Set(entries);
|
|
46
|
+
const setAdd = (set, value) => set?.add(value);
|
|
47
|
+
|
|
48
|
+
const getDefinableFunctions = (store, getDefaultThing, validateRowValue) => {
|
|
49
|
+
const hasRow = store.hasRow;
|
|
50
|
+
const tableIds = mapNew();
|
|
51
|
+
const things = mapNew();
|
|
52
|
+
const allRowValues = mapNew();
|
|
53
|
+
const allSortKeys = mapNew();
|
|
54
|
+
const storeListenerIds = mapNew();
|
|
55
|
+
const getStore = () => store;
|
|
56
|
+
const getThingIds = () => mapKeys(tableIds);
|
|
57
|
+
const forEachThing = (cb) => mapForEach(things, cb);
|
|
58
|
+
const hasThing = (id) => collHas(things, id);
|
|
59
|
+
const getTableId = (id) => mapGet(tableIds, id);
|
|
60
|
+
const getThing = (id) => mapGet(things, id);
|
|
61
|
+
const setThing = (id, thing) => mapSet(things, id, thing);
|
|
62
|
+
const removeStoreListeners = (id) =>
|
|
63
|
+
ifNotUndefined(mapGet(storeListenerIds, id), (listenerIds) => {
|
|
64
|
+
collForEach(listenerIds, store.delListener);
|
|
65
|
+
mapSet(storeListenerIds, id);
|
|
66
|
+
});
|
|
67
|
+
const setDefinition = (id, tableId, onChanged, getRowValue, getSortKey) => {
|
|
68
|
+
const changedRowValues = mapNew();
|
|
69
|
+
const changedSortKeys = mapNew();
|
|
70
|
+
mapSet(tableIds, id, tableId);
|
|
71
|
+
if (!collHas(things, id)) {
|
|
72
|
+
mapSet(things, id, getDefaultThing());
|
|
73
|
+
mapSet(allRowValues, id, mapNew());
|
|
74
|
+
mapSet(allSortKeys, id, mapNew());
|
|
75
|
+
}
|
|
76
|
+
const rowValues = mapGet(allRowValues, id);
|
|
77
|
+
const sortKeys = mapGet(allSortKeys, id);
|
|
78
|
+
const processRow = (rowId) => {
|
|
79
|
+
const getCell = (cellId) => store.getCell(tableId, rowId, cellId);
|
|
80
|
+
const oldRowValue = mapGet(rowValues, rowId);
|
|
81
|
+
const newRowValue = hasRow(tableId, rowId)
|
|
82
|
+
? validateRowValue(getRowValue(getCell, rowId))
|
|
83
|
+
: void 0;
|
|
84
|
+
if (oldRowValue != newRowValue) {
|
|
85
|
+
mapSet(changedRowValues, rowId, [oldRowValue, newRowValue]);
|
|
86
|
+
}
|
|
87
|
+
if (!isUndefined(getSortKey)) {
|
|
88
|
+
const oldSortKey = mapGet(sortKeys, rowId);
|
|
89
|
+
const newSortKey = hasRow(tableId, rowId)
|
|
90
|
+
? getSortKey(getCell, rowId)
|
|
91
|
+
: void 0;
|
|
92
|
+
if (oldSortKey != newSortKey) {
|
|
93
|
+
mapSet(changedSortKeys, rowId, newSortKey);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const processTable = (force) => {
|
|
98
|
+
onChanged(
|
|
99
|
+
() => {
|
|
100
|
+
collForEach(changedRowValues, ([, newRowValue], rowId) =>
|
|
101
|
+
mapSet(rowValues, rowId, newRowValue),
|
|
102
|
+
);
|
|
103
|
+
collForEach(changedSortKeys, (newSortKey, rowId) =>
|
|
104
|
+
mapSet(sortKeys, rowId, newSortKey),
|
|
105
|
+
);
|
|
106
|
+
},
|
|
107
|
+
changedRowValues,
|
|
108
|
+
changedSortKeys,
|
|
109
|
+
rowValues,
|
|
110
|
+
sortKeys,
|
|
111
|
+
force,
|
|
112
|
+
);
|
|
113
|
+
collClear(changedRowValues);
|
|
114
|
+
collClear(changedSortKeys);
|
|
115
|
+
};
|
|
116
|
+
mapForEach(rowValues, processRow);
|
|
117
|
+
if (store.hasTable(tableId)) {
|
|
118
|
+
arrayForEach(store.getRowIds(tableId), (rowId) => {
|
|
119
|
+
if (!collHas(rowValues, rowId)) {
|
|
120
|
+
processRow(rowId);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
processTable(true);
|
|
125
|
+
removeStoreListeners(id);
|
|
126
|
+
mapSet(
|
|
127
|
+
storeListenerIds,
|
|
128
|
+
id,
|
|
129
|
+
setNew([
|
|
130
|
+
store.addRowListener(tableId, null, (_store, _tableId, rowId) =>
|
|
131
|
+
processRow(rowId),
|
|
132
|
+
),
|
|
133
|
+
store.addTableListener(tableId, () => processTable()),
|
|
134
|
+
]),
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
const delDefinition = (id) => {
|
|
138
|
+
mapSet(tableIds, id);
|
|
139
|
+
mapSet(things, id);
|
|
140
|
+
mapSet(allRowValues, id);
|
|
141
|
+
mapSet(allSortKeys, id);
|
|
142
|
+
removeStoreListeners(id);
|
|
143
|
+
};
|
|
144
|
+
const destroy = () => mapForEach(storeListenerIds, delDefinition);
|
|
145
|
+
return [
|
|
146
|
+
getStore,
|
|
147
|
+
getThingIds,
|
|
148
|
+
forEachThing,
|
|
149
|
+
hasThing,
|
|
150
|
+
getTableId,
|
|
151
|
+
getThing,
|
|
152
|
+
setThing,
|
|
153
|
+
setDefinition,
|
|
154
|
+
delDefinition,
|
|
155
|
+
destroy,
|
|
156
|
+
];
|
|
157
|
+
};
|
|
158
|
+
const getRowCellFunction = (getRowCell, defaultCellValue) =>
|
|
159
|
+
isString(getRowCell)
|
|
160
|
+
? (getCell) => getCell(getRowCell)
|
|
161
|
+
: getRowCell ?? (() => defaultCellValue ?? EMPTY_STRING);
|
|
162
|
+
const getCreateFunction = (getFunction) => {
|
|
163
|
+
const getFunctionsByStore = /* @__PURE__ */ new WeakMap();
|
|
164
|
+
return (store) => {
|
|
165
|
+
if (!getFunctionsByStore.has(store)) {
|
|
166
|
+
getFunctionsByStore.set(store, getFunction(store));
|
|
167
|
+
}
|
|
168
|
+
return getFunctionsByStore.get(store);
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const addDeepSet = (deepSet, value, ids) =>
|
|
173
|
+
arrayLength(ids) < 2
|
|
174
|
+
? setAdd(
|
|
175
|
+
arrayIsEmpty(ids) ? deepSet : mapEnsure(deepSet, ids[0], setNew()),
|
|
176
|
+
value,
|
|
177
|
+
)
|
|
178
|
+
: addDeepSet(
|
|
179
|
+
mapEnsure(deepSet, ids[0], mapNew()),
|
|
180
|
+
value,
|
|
181
|
+
arrayFromSecond(ids),
|
|
182
|
+
);
|
|
183
|
+
const forDeepSet = (valueDo) => {
|
|
184
|
+
const deep = (deepIdSet, arg, ...ids) =>
|
|
185
|
+
ifNotUndefined(deepIdSet, (deepIdSet2) =>
|
|
186
|
+
arrayIsEmpty(ids)
|
|
187
|
+
? valueDo(deepIdSet2, arg)
|
|
188
|
+
: arrayForEach([ids[0], null], (id) =>
|
|
189
|
+
deep(mapGet(deepIdSet2, id), arg, ...arrayFromSecond(ids)),
|
|
190
|
+
),
|
|
191
|
+
);
|
|
192
|
+
return deep;
|
|
193
|
+
};
|
|
194
|
+
const getListenerFunctions = (getThing) => {
|
|
195
|
+
let thing;
|
|
196
|
+
let nextId = 0;
|
|
197
|
+
const listenerPool = [];
|
|
198
|
+
const allListeners = mapNew();
|
|
199
|
+
const addListener = (listener, deepSet, idOrNulls = []) => {
|
|
200
|
+
thing ??= getThing();
|
|
201
|
+
const id = arrayPop(listenerPool) ?? '' + nextId++;
|
|
202
|
+
mapSet(allListeners, id, [listener, deepSet, idOrNulls]);
|
|
203
|
+
addDeepSet(deepSet, id, idOrNulls);
|
|
204
|
+
return id;
|
|
205
|
+
};
|
|
206
|
+
const callListeners = (deepSet, ids = [], ...extraArgs) =>
|
|
207
|
+
forDeepSet(collForEach)(
|
|
208
|
+
deepSet,
|
|
209
|
+
(id) =>
|
|
210
|
+
ifNotUndefined(mapGet(allListeners, id), ([listener]) =>
|
|
211
|
+
listener(thing, ...ids, ...extraArgs),
|
|
212
|
+
),
|
|
213
|
+
...ids,
|
|
214
|
+
);
|
|
215
|
+
const delListener = (id) =>
|
|
216
|
+
ifNotUndefined(
|
|
217
|
+
mapGet(allListeners, id),
|
|
218
|
+
([, deepSet, idOrNulls]) => {
|
|
219
|
+
forDeepSet(collDel)(deepSet, id, ...idOrNulls);
|
|
220
|
+
mapSet(allListeners, id);
|
|
221
|
+
if (arrayLength(listenerPool) < 1e3) {
|
|
222
|
+
arrayPush(listenerPool, id);
|
|
223
|
+
}
|
|
224
|
+
return idOrNulls;
|
|
225
|
+
},
|
|
226
|
+
() => [],
|
|
227
|
+
);
|
|
228
|
+
const callListener = (id, idNullGetters, extraArgsGetter) =>
|
|
229
|
+
ifNotUndefined(mapGet(allListeners, id), ([listener, , idOrNulls]) => {
|
|
230
|
+
const callWithIds = (...ids) => {
|
|
231
|
+
const index = arrayLength(ids);
|
|
232
|
+
index == arrayLength(idOrNulls)
|
|
233
|
+
? listener(thing, ...ids, ...extraArgsGetter(ids))
|
|
234
|
+
: isUndefined(idOrNulls[index])
|
|
235
|
+
? arrayForEach(idNullGetters[index](...ids), (id2) =>
|
|
236
|
+
callWithIds(...ids, id2),
|
|
237
|
+
)
|
|
238
|
+
: callWithIds(...ids, idOrNulls[index]);
|
|
239
|
+
};
|
|
240
|
+
callWithIds();
|
|
241
|
+
});
|
|
242
|
+
return [addListener, callListeners, delListener, callListener];
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
const object = Object;
|
|
246
|
+
const objFreeze = object.freeze;
|
|
247
|
+
|
|
248
|
+
const createRelationships = getCreateFunction((store) => {
|
|
249
|
+
const remoteTableIds = mapNew();
|
|
250
|
+
const remoteRowIdListeners = mapNew();
|
|
251
|
+
const localRowIdsListeners = mapNew();
|
|
252
|
+
const linkedRowIdsListeners = mapNew();
|
|
253
|
+
const [
|
|
254
|
+
getStore,
|
|
255
|
+
getRelationshipIds,
|
|
256
|
+
forEachRelationshipImpl,
|
|
257
|
+
hasRelationship,
|
|
258
|
+
getLocalTableId,
|
|
259
|
+
getRelationship,
|
|
260
|
+
_setRelationship,
|
|
261
|
+
setDefinition,
|
|
262
|
+
delDefinition,
|
|
263
|
+
destroy,
|
|
264
|
+
] = getDefinableFunctions(
|
|
265
|
+
store,
|
|
266
|
+
() => [mapNew(), mapNew(), mapNew(), mapNew()],
|
|
267
|
+
(value) => (isUndefined(value) ? void 0 : value + EMPTY_STRING),
|
|
268
|
+
);
|
|
269
|
+
const [addListener, callListeners, delListenerImpl] = getListenerFunctions(
|
|
270
|
+
() => relationships,
|
|
271
|
+
);
|
|
272
|
+
const getLinkedRowIdsCache = (relationshipId, firstRowId, skipCache) =>
|
|
273
|
+
ifNotUndefined(
|
|
274
|
+
getRelationship(relationshipId),
|
|
275
|
+
([remoteRows, , linkedRowsCache]) => {
|
|
276
|
+
if (!collHas(linkedRowsCache, firstRowId)) {
|
|
277
|
+
const linkedRows = setNew();
|
|
278
|
+
if (
|
|
279
|
+
getLocalTableId(relationshipId) != getRemoteTableId(relationshipId)
|
|
280
|
+
) {
|
|
281
|
+
setAdd(linkedRows, firstRowId);
|
|
282
|
+
} else {
|
|
283
|
+
let rowId = firstRowId;
|
|
284
|
+
while (!isUndefined(rowId) && !collHas(linkedRows, rowId)) {
|
|
285
|
+
setAdd(linkedRows, rowId);
|
|
286
|
+
rowId = mapGet(remoteRows, rowId);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (skipCache) {
|
|
290
|
+
return linkedRows;
|
|
291
|
+
}
|
|
292
|
+
mapSet(linkedRowsCache, firstRowId, linkedRows);
|
|
293
|
+
}
|
|
294
|
+
return mapGet(linkedRowsCache, firstRowId);
|
|
295
|
+
},
|
|
296
|
+
);
|
|
297
|
+
const delLinkedRowIdsCache = (relationshipId, firstRowId) =>
|
|
298
|
+
ifNotUndefined(getRelationship(relationshipId), ([, , linkedRowsCache]) =>
|
|
299
|
+
mapSet(linkedRowsCache, firstRowId),
|
|
300
|
+
);
|
|
301
|
+
const setRelationshipDefinition = (
|
|
302
|
+
relationshipId,
|
|
303
|
+
localTableId,
|
|
304
|
+
remoteTableId,
|
|
305
|
+
getRemoteRowId2,
|
|
306
|
+
) => {
|
|
307
|
+
mapSet(remoteTableIds, relationshipId, remoteTableId);
|
|
308
|
+
setDefinition(
|
|
309
|
+
relationshipId,
|
|
310
|
+
localTableId,
|
|
311
|
+
(change, changedRemoteRowIds) => {
|
|
312
|
+
const changedLocalRows = setNew();
|
|
313
|
+
const changedRemoteRows = setNew();
|
|
314
|
+
const changedLinkedRows = setNew();
|
|
315
|
+
const [localRows, remoteRows] = getRelationship(relationshipId);
|
|
316
|
+
collForEach(
|
|
317
|
+
changedRemoteRowIds,
|
|
318
|
+
([oldRemoteRowId, newRemoteRowId], localRowId) => {
|
|
319
|
+
if (!isUndefined(oldRemoteRowId)) {
|
|
320
|
+
setAdd(changedRemoteRows, oldRemoteRowId);
|
|
321
|
+
ifNotUndefined(
|
|
322
|
+
mapGet(remoteRows, oldRemoteRowId),
|
|
323
|
+
(oldRemoteRow) => {
|
|
324
|
+
collDel(oldRemoteRow, localRowId);
|
|
325
|
+
if (collIsEmpty(oldRemoteRow)) {
|
|
326
|
+
mapSet(remoteRows, oldRemoteRowId);
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
if (!isUndefined(newRemoteRowId)) {
|
|
332
|
+
setAdd(changedRemoteRows, newRemoteRowId);
|
|
333
|
+
if (!collHas(remoteRows, newRemoteRowId)) {
|
|
334
|
+
mapSet(remoteRows, newRemoteRowId, setNew());
|
|
335
|
+
}
|
|
336
|
+
setAdd(mapGet(remoteRows, newRemoteRowId), localRowId);
|
|
337
|
+
}
|
|
338
|
+
setAdd(changedLocalRows, localRowId);
|
|
339
|
+
mapSet(localRows, localRowId, newRemoteRowId);
|
|
340
|
+
mapForEach(
|
|
341
|
+
mapGet(linkedRowIdsListeners, relationshipId),
|
|
342
|
+
(firstRowId) => {
|
|
343
|
+
if (
|
|
344
|
+
collHas(
|
|
345
|
+
getLinkedRowIdsCache(relationshipId, firstRowId),
|
|
346
|
+
localRowId,
|
|
347
|
+
)
|
|
348
|
+
) {
|
|
349
|
+
setAdd(changedLinkedRows, firstRowId);
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
);
|
|
353
|
+
},
|
|
354
|
+
);
|
|
355
|
+
change();
|
|
356
|
+
collForEach(changedLocalRows, (localRowId) =>
|
|
357
|
+
callListeners(remoteRowIdListeners, [relationshipId, localRowId]),
|
|
358
|
+
);
|
|
359
|
+
collForEach(changedRemoteRows, (remoteRowId) =>
|
|
360
|
+
callListeners(localRowIdsListeners, [relationshipId, remoteRowId]),
|
|
361
|
+
);
|
|
362
|
+
collForEach(changedLinkedRows, (firstRowId) => {
|
|
363
|
+
delLinkedRowIdsCache(relationshipId, firstRowId);
|
|
364
|
+
callListeners(linkedRowIdsListeners, [relationshipId, firstRowId]);
|
|
365
|
+
});
|
|
366
|
+
},
|
|
367
|
+
getRowCellFunction(getRemoteRowId2),
|
|
368
|
+
);
|
|
369
|
+
return relationships;
|
|
370
|
+
};
|
|
371
|
+
const forEachRelationship = (relationshipCallback) =>
|
|
372
|
+
forEachRelationshipImpl((relationshipId) =>
|
|
373
|
+
relationshipCallback(relationshipId, (rowCallback) =>
|
|
374
|
+
store.forEachRow(getLocalTableId(relationshipId), rowCallback),
|
|
375
|
+
),
|
|
376
|
+
);
|
|
377
|
+
const delRelationshipDefinition = (relationshipId) => {
|
|
378
|
+
mapSet(remoteTableIds, relationshipId);
|
|
379
|
+
delDefinition(relationshipId);
|
|
380
|
+
return relationships;
|
|
381
|
+
};
|
|
382
|
+
const getRemoteTableId = (relationshipId) =>
|
|
383
|
+
mapGet(remoteTableIds, relationshipId);
|
|
384
|
+
const getRemoteRowId = (relationshipId, localRowId) =>
|
|
385
|
+
mapGet(getRelationship(relationshipId)?.[0], localRowId);
|
|
386
|
+
const getLocalRowIds = (relationshipId, remoteRowId) =>
|
|
387
|
+
collValues(mapGet(getRelationship(relationshipId)?.[1], remoteRowId));
|
|
388
|
+
const getLinkedRowIds = (relationshipId, firstRowId) =>
|
|
389
|
+
isUndefined(getRelationship(relationshipId))
|
|
390
|
+
? [firstRowId]
|
|
391
|
+
: collValues(getLinkedRowIdsCache(relationshipId, firstRowId, true));
|
|
392
|
+
const addRemoteRowIdListener = (relationshipId, localRowId, listener) =>
|
|
393
|
+
addListener(listener, remoteRowIdListeners, [relationshipId, localRowId]);
|
|
394
|
+
const addLocalRowIdsListener = (relationshipId, remoteRowId, listener) =>
|
|
395
|
+
addListener(listener, localRowIdsListeners, [relationshipId, remoteRowId]);
|
|
396
|
+
const addLinkedRowIdsListener = (relationshipId, firstRowId, listener) => {
|
|
397
|
+
getLinkedRowIdsCache(relationshipId, firstRowId);
|
|
398
|
+
return addListener(listener, linkedRowIdsListeners, [
|
|
399
|
+
relationshipId,
|
|
400
|
+
firstRowId,
|
|
401
|
+
]);
|
|
402
|
+
};
|
|
403
|
+
const delListener = (listenerId) => {
|
|
404
|
+
delLinkedRowIdsCache(...delListenerImpl(listenerId));
|
|
405
|
+
return relationships;
|
|
406
|
+
};
|
|
407
|
+
const getListenerStats = () => ({
|
|
408
|
+
remoteRowId: collSize3(remoteRowIdListeners),
|
|
409
|
+
localRowIds: collSize3(localRowIdsListeners),
|
|
410
|
+
linkedRowIds: collSize3(linkedRowIdsListeners),
|
|
411
|
+
});
|
|
412
|
+
const relationships = {
|
|
413
|
+
setRelationshipDefinition,
|
|
414
|
+
delRelationshipDefinition,
|
|
415
|
+
getStore,
|
|
416
|
+
getRelationshipIds,
|
|
417
|
+
forEachRelationship,
|
|
418
|
+
hasRelationship,
|
|
419
|
+
getLocalTableId,
|
|
420
|
+
getRemoteTableId,
|
|
421
|
+
getRemoteRowId,
|
|
422
|
+
getLocalRowIds,
|
|
423
|
+
getLinkedRowIds,
|
|
424
|
+
addRemoteRowIdListener,
|
|
425
|
+
addLocalRowIdsListener,
|
|
426
|
+
addLinkedRowIdsListener,
|
|
427
|
+
delListener,
|
|
428
|
+
destroy,
|
|
429
|
+
getListenerStats,
|
|
430
|
+
};
|
|
431
|
+
return objFreeze(relationships);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
export {createRelationships};
|