@expo/entity 0.43.0 → 0.45.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/build/AuthorizationResultBasedEntityLoader.js +5 -1
- package/build/AuthorizationResultBasedEntityLoader.js.map +1 -1
- package/build/AuthorizationResultBasedEntityMutator.d.ts +87 -2
- package/build/AuthorizationResultBasedEntityMutator.js +122 -8
- package/build/AuthorizationResultBasedEntityMutator.js.map +1 -1
- package/build/EntityLoaderUtils.d.ts +15 -3
- package/build/EntityLoaderUtils.js +25 -10
- package/build/EntityLoaderUtils.js.map +1 -1
- package/build/EntityQueryContext.d.ts +53 -7
- package/build/EntityQueryContext.js +65 -10
- package/build/EntityQueryContext.js.map +1 -1
- package/build/EntityQueryContextProvider.d.ts +5 -1
- package/build/EntityQueryContextProvider.js +11 -4
- package/build/EntityQueryContextProvider.js.map +1 -1
- package/build/IEntityGenericCacher.d.ts +2 -2
- package/build/errors/EntityNotFoundError.d.ts +8 -1
- package/build/errors/EntityNotFoundError.js +7 -2
- package/build/errors/EntityNotFoundError.js.map +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/internal/CompositeFieldHolder.d.ts +13 -0
- package/build/internal/CompositeFieldHolder.js +7 -0
- package/build/internal/CompositeFieldHolder.js.map +1 -1
- package/build/internal/CompositeFieldValueMap.d.ts +3 -0
- package/build/internal/CompositeFieldValueMap.js +3 -0
- package/build/internal/CompositeFieldValueMap.js.map +1 -1
- package/build/internal/EntityDataManager.d.ts +22 -3
- package/build/internal/EntityDataManager.js +99 -11
- package/build/internal/EntityDataManager.js.map +1 -1
- package/build/internal/EntityFieldTransformationUtils.d.ts +20 -0
- package/build/internal/EntityFieldTransformationUtils.js +15 -0
- package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
- package/build/internal/EntityLoadInterfaces.d.ts +8 -0
- package/build/internal/EntityLoadInterfaces.js +2 -0
- package/build/internal/EntityLoadInterfaces.js.map +1 -1
- package/build/internal/EntityTableDataCoordinator.d.ts +2 -0
- package/build/internal/EntityTableDataCoordinator.js +2 -0
- package/build/internal/EntityTableDataCoordinator.js.map +1 -1
- package/build/internal/ReadThroughEntityCache.d.ts +8 -0
- package/build/internal/ReadThroughEntityCache.js +5 -0
- package/build/internal/ReadThroughEntityCache.js.map +1 -1
- package/build/internal/SingleFieldHolder.d.ts +7 -0
- package/build/internal/SingleFieldHolder.js +7 -0
- package/build/internal/SingleFieldHolder.js.map +1 -1
- package/build/metrics/EntityMetricsUtils.d.ts +4 -3
- package/build/metrics/EntityMetricsUtils.js +6 -3
- package/build/metrics/EntityMetricsUtils.js.map +1 -1
- package/build/metrics/IEntityMetricsAdapter.d.ts +21 -0
- package/build/metrics/IEntityMetricsAdapter.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/build/utils/EntityCreationUtils.d.ts +14 -0
- package/build/utils/EntityCreationUtils.js +57 -0
- package/build/utils/EntityCreationUtils.js.map +1 -0
- package/package.json +13 -13
- package/src/AuthorizationResultBasedEntityLoader.ts +7 -1
- package/src/AuthorizationResultBasedEntityMutator.ts +133 -15
- package/src/EntityLoaderUtils.ts +43 -12
- package/src/EntityQueryContext.ts +68 -13
- package/src/EntityQueryContextProvider.ts +20 -3
- package/src/IEntityGenericCacher.ts +2 -2
- package/src/__tests__/AuthorizationResultBasedEntityLoader-test.ts +98 -0
- package/src/__tests__/EntityQueryContext-test.ts +141 -26
- package/src/errors/EntityNotFoundError.ts +51 -4
- package/src/errors/__tests__/EntityDatabaseAdapterError-test.ts +26 -0
- package/src/index.ts +1 -0
- package/src/internal/CompositeFieldHolder.ts +15 -0
- package/src/internal/CompositeFieldValueMap.ts +3 -0
- package/src/internal/EntityDataManager.ts +170 -10
- package/src/internal/EntityFieldTransformationUtils.ts +20 -0
- package/src/internal/EntityLoadInterfaces.ts +8 -0
- package/src/internal/EntityTableDataCoordinator.ts +2 -0
- package/src/internal/ReadThroughEntityCache.ts +8 -0
- package/src/internal/SingleFieldHolder.ts +7 -0
- package/src/internal/__tests__/EntityDataManager-test.ts +708 -186
- package/src/metrics/EntityMetricsUtils.ts +7 -0
- package/src/metrics/IEntityMetricsAdapter.ts +27 -0
- package/src/utils/EntityCreationUtils.ts +143 -0
- package/src/utils/__testfixtures__/StubDatabaseAdapter.ts +13 -1
- package/src/utils/__tests__/EntityCreationUtils-test.ts +354 -0
|
@@ -14,6 +14,10 @@ import {
|
|
|
14
14
|
} from '../internal/EntityLoadInterfaces';
|
|
15
15
|
|
|
16
16
|
declare const CompositeFieldHolderSerializedBrand: unique symbol;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
17
21
|
export type SerializedCompositeFieldHolder = string & {
|
|
18
22
|
readonly [CompositeFieldHolderSerializedBrand]: true;
|
|
19
23
|
};
|
|
@@ -21,6 +25,8 @@ export type SerializedCompositeFieldHolder = string & {
|
|
|
21
25
|
/**
|
|
22
26
|
* A load key that represents a composite field (set of fieldName) on an entity.
|
|
23
27
|
* Must be defined in the entity configuration composite field definition.
|
|
28
|
+
*
|
|
29
|
+
* @internal
|
|
24
30
|
*/
|
|
25
31
|
export class CompositeFieldHolder<
|
|
26
32
|
TFields extends Record<string, any>,
|
|
@@ -151,12 +157,18 @@ export class CompositeFieldHolder<
|
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
declare const CompositeFieldValueHolderSerializedBrand: unique symbol;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @internal
|
|
163
|
+
*/
|
|
154
164
|
export type SerializedCompositeFieldValueHolder = string & {
|
|
155
165
|
readonly [CompositeFieldValueHolderSerializedBrand]: true;
|
|
156
166
|
};
|
|
157
167
|
|
|
158
168
|
/**
|
|
159
169
|
* A load value for a CompositeFieldHolder.
|
|
170
|
+
*
|
|
171
|
+
* @internal
|
|
160
172
|
*/
|
|
161
173
|
export class CompositeFieldValueHolder<
|
|
162
174
|
TFields extends Record<string, any>,
|
|
@@ -201,6 +213,9 @@ export class CompositeFieldValueHolder<
|
|
|
201
213
|
}
|
|
202
214
|
}
|
|
203
215
|
|
|
216
|
+
/**
|
|
217
|
+
* @internal
|
|
218
|
+
*/
|
|
204
219
|
export class CompositeFieldValueHolderMap<
|
|
205
220
|
TFields extends Record<string, any>,
|
|
206
221
|
N extends EntityCompositeField<TFields>,
|
|
@@ -7,7 +7,11 @@ import EntityDatabaseAdapter, {
|
|
|
7
7
|
QuerySelectionModifiers,
|
|
8
8
|
QuerySelectionModifiersWithOrderByRaw,
|
|
9
9
|
} from '../EntityDatabaseAdapter';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
EntityQueryContext,
|
|
12
|
+
EntityTransactionalQueryContext,
|
|
13
|
+
TransactionalDataLoaderMode,
|
|
14
|
+
} from '../EntityQueryContext';
|
|
11
15
|
import EntityQueryContextProvider from '../EntityQueryContextProvider';
|
|
12
16
|
import { partitionErrors } from '../entityUtils';
|
|
13
17
|
import { IEntityLoadKey, IEntityLoadValue, LoadPair } from './EntityLoadInterfaces';
|
|
@@ -21,18 +25,28 @@ import IEntityMetricsAdapter, {
|
|
|
21
25
|
} from '../metrics/IEntityMetricsAdapter';
|
|
22
26
|
import { computeIfAbsent } from '../utils/collections/maps';
|
|
23
27
|
|
|
28
|
+
type DataLoaderMap<TFields extends Record<string, any>> = Map<
|
|
29
|
+
string,
|
|
30
|
+
DataLoader<unknown, readonly Readonly<TFields>[]>
|
|
31
|
+
>;
|
|
32
|
+
|
|
24
33
|
/**
|
|
25
34
|
* A data manager is responsible for orchestrating multiple sources of entity
|
|
26
35
|
* data including local caches, EntityCacheAdapter, and EntityDatabaseAdapter.
|
|
27
36
|
*
|
|
28
37
|
* It is also responsible for invalidating all sources of data when mutated using EntityMutator.
|
|
38
|
+
*
|
|
39
|
+
* @internal
|
|
29
40
|
*/
|
|
30
41
|
export default class EntityDataManager<
|
|
31
42
|
TFields extends Record<string, any>,
|
|
32
43
|
TIDField extends keyof TFields,
|
|
33
44
|
> {
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
// map from (load method type + data manager data loader key) to dataloader
|
|
46
|
+
private readonly dataLoaders: DataLoaderMap<TFields> = new Map();
|
|
47
|
+
|
|
48
|
+
// map from transaction id to dataloader map
|
|
49
|
+
private readonly transactionalDataLoaders: Map<string, DataLoaderMap<TFields>> = new Map();
|
|
36
50
|
|
|
37
51
|
constructor(
|
|
38
52
|
private readonly databaseAdapter: EntityDatabaseAdapter<TFields, TIDField>,
|
|
@@ -48,7 +62,7 @@ export default class EntityDataManager<
|
|
|
48
62
|
TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
|
|
49
63
|
>(key: TLoadKey): DataLoader<TSerializedLoadValue, readonly Readonly<TFields>[]> {
|
|
50
64
|
return computeIfAbsent(
|
|
51
|
-
this.
|
|
65
|
+
this.dataLoaders,
|
|
52
66
|
key.getLoadMethodType() + key.getDataManagerDataLoaderKey(),
|
|
53
67
|
() => {
|
|
54
68
|
return new DataLoader(
|
|
@@ -58,7 +72,7 @@ export default class EntityDataManager<
|
|
|
58
72
|
const values = serializedLoadValues.map((serializedLoadValue) =>
|
|
59
73
|
key.deserializeLoadValue(serializedLoadValue),
|
|
60
74
|
);
|
|
61
|
-
const objectMap = await this.
|
|
75
|
+
const objectMap = await this.loadManyForNonTransactionalDataLoaderAsync(key, values);
|
|
62
76
|
return values.map((value) => objectMap.get(value) ?? []);
|
|
63
77
|
},
|
|
64
78
|
);
|
|
@@ -66,7 +80,7 @@ export default class EntityDataManager<
|
|
|
66
80
|
);
|
|
67
81
|
}
|
|
68
82
|
|
|
69
|
-
private async
|
|
83
|
+
private async loadManyForNonTransactionalDataLoaderAsync<
|
|
70
84
|
TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
|
|
71
85
|
TSerializedLoadValue,
|
|
72
86
|
TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
|
|
@@ -76,6 +90,7 @@ export default class EntityDataManager<
|
|
|
76
90
|
): Promise<ReadonlyMap<TLoadValue, readonly Readonly<TFields>[]>> {
|
|
77
91
|
this.metricsAdapter.incrementDataManagerLoadCount({
|
|
78
92
|
type: IncrementLoadCountEventType.CACHE,
|
|
93
|
+
isInTransaction: false,
|
|
79
94
|
fieldValueCount: values.length,
|
|
80
95
|
entityClassName: this.entityClassName,
|
|
81
96
|
loadType: key.getLoadMethodType(),
|
|
@@ -84,6 +99,7 @@ export default class EntityDataManager<
|
|
|
84
99
|
return await this.entityCache.readManyThroughAsync(key, values, async (fetcherValues) => {
|
|
85
100
|
this.metricsAdapter.incrementDataManagerLoadCount({
|
|
86
101
|
type: IncrementLoadCountEventType.DATABASE,
|
|
102
|
+
isInTransaction: false,
|
|
87
103
|
fieldValueCount: fetcherValues.length,
|
|
88
104
|
entityClassName: this.entityClassName,
|
|
89
105
|
loadType: key.getLoadMethodType(),
|
|
@@ -96,6 +112,65 @@ export default class EntityDataManager<
|
|
|
96
112
|
});
|
|
97
113
|
}
|
|
98
114
|
|
|
115
|
+
private getTransactionalDataLoaderForLoadKey<
|
|
116
|
+
TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
|
|
117
|
+
TSerializedLoadValue,
|
|
118
|
+
TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
|
|
119
|
+
>(
|
|
120
|
+
queryContext: EntityTransactionalQueryContext,
|
|
121
|
+
key: TLoadKey,
|
|
122
|
+
): DataLoader<TSerializedLoadValue, readonly Readonly<TFields>[]> {
|
|
123
|
+
const dataLoaderMapForTransaction = computeIfAbsent(
|
|
124
|
+
this.transactionalDataLoaders,
|
|
125
|
+
queryContext.transactionId,
|
|
126
|
+
() => new Map(),
|
|
127
|
+
);
|
|
128
|
+
return computeIfAbsent(
|
|
129
|
+
dataLoaderMapForTransaction,
|
|
130
|
+
key.getLoadMethodType() + key.getDataManagerDataLoaderKey(),
|
|
131
|
+
() => {
|
|
132
|
+
return new DataLoader(
|
|
133
|
+
async (
|
|
134
|
+
serializedLoadValues: readonly TSerializedLoadValue[],
|
|
135
|
+
): Promise<readonly (readonly TFields[])[]> => {
|
|
136
|
+
const values = serializedLoadValues.map((serializedLoadValue) =>
|
|
137
|
+
key.deserializeLoadValue(serializedLoadValue),
|
|
138
|
+
);
|
|
139
|
+
const objectMap = await this.loadManyForTransactionalDataLoaderAsync(
|
|
140
|
+
queryContext,
|
|
141
|
+
key,
|
|
142
|
+
values,
|
|
143
|
+
);
|
|
144
|
+
return values.map((value) => objectMap.get(value) ?? []);
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
// only cache if transactional dataloader caching is enabled for the transactional query context
|
|
148
|
+
cache: queryContext.transactionalDataLoaderMode === TransactionalDataLoaderMode.ENABLED,
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private async loadManyForTransactionalDataLoaderAsync<
|
|
156
|
+
TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
|
|
157
|
+
TSerializedLoadValue,
|
|
158
|
+
TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
|
|
159
|
+
>(
|
|
160
|
+
queryContext: EntityTransactionalQueryContext,
|
|
161
|
+
key: TLoadKey,
|
|
162
|
+
values: readonly TLoadValue[],
|
|
163
|
+
): Promise<ReadonlyMap<TLoadValue, readonly Readonly<TFields>[]>> {
|
|
164
|
+
this.metricsAdapter.incrementDataManagerLoadCount({
|
|
165
|
+
type: IncrementLoadCountEventType.DATABASE,
|
|
166
|
+
isInTransaction: true,
|
|
167
|
+
fieldValueCount: values.length,
|
|
168
|
+
entityClassName: this.entityClassName,
|
|
169
|
+
loadType: key.getLoadMethodType(),
|
|
170
|
+
});
|
|
171
|
+
return await this.databaseAdapter.fetchManyWhereAsync(queryContext, key, values);
|
|
172
|
+
}
|
|
173
|
+
|
|
99
174
|
/**
|
|
100
175
|
* Load many objects through read-through dataloader (batcher) and cache (optional).
|
|
101
176
|
*
|
|
@@ -117,6 +192,7 @@ export default class EntityDataManager<
|
|
|
117
192
|
this.metricsAdapter,
|
|
118
193
|
EntityMetricsLoadType.LOAD_MANY,
|
|
119
194
|
this.entityClassName,
|
|
195
|
+
queryContext,
|
|
120
196
|
)(this.loadManyEqualingInternalAsync(queryContext, key, values));
|
|
121
197
|
}
|
|
122
198
|
|
|
@@ -131,18 +207,30 @@ export default class EntityDataManager<
|
|
|
131
207
|
): Promise<ReadonlyMap<TLoadValue, readonly Readonly<TFields>[]>> {
|
|
132
208
|
key.validateRuntimeLoadValuesForDataManagerDataLoader(values, this.entityClassName);
|
|
133
209
|
|
|
134
|
-
|
|
135
|
-
|
|
210
|
+
if (
|
|
211
|
+
queryContext.isInTransaction() &&
|
|
212
|
+
queryContext.transactionalDataLoaderMode === TransactionalDataLoaderMode.DISABLED
|
|
213
|
+
) {
|
|
214
|
+
this.metricsAdapter.incrementDataManagerLoadCount({
|
|
215
|
+
type: IncrementLoadCountEventType.DATABASE,
|
|
216
|
+
isInTransaction: true,
|
|
217
|
+
fieldValueCount: values.length,
|
|
218
|
+
entityClassName: this.entityClassName,
|
|
219
|
+
loadType: key.getLoadMethodType(),
|
|
220
|
+
});
|
|
136
221
|
return await this.databaseAdapter.fetchManyWhereAsync(queryContext, key, values);
|
|
137
222
|
}
|
|
138
223
|
|
|
139
224
|
this.metricsAdapter.incrementDataManagerLoadCount({
|
|
140
225
|
type: IncrementLoadCountEventType.DATALOADER,
|
|
226
|
+
isInTransaction: queryContext.isInTransaction(),
|
|
141
227
|
fieldValueCount: values.length,
|
|
142
228
|
entityClassName: this.entityClassName,
|
|
143
229
|
loadType: key.getLoadMethodType(),
|
|
144
230
|
});
|
|
145
|
-
const dataLoader =
|
|
231
|
+
const dataLoader = queryContext.isInTransaction()
|
|
232
|
+
? this.getTransactionalDataLoaderForLoadKey(queryContext, key)
|
|
233
|
+
: this.getDataLoaderForLoadKey(key);
|
|
146
234
|
const results = await dataLoader.loadMany(values.map((v) => key.serializeLoadValue(v)));
|
|
147
235
|
const [successfulValues, errors] = partitionErrors(results);
|
|
148
236
|
if (errors.length > 0) {
|
|
@@ -179,6 +267,7 @@ export default class EntityDataManager<
|
|
|
179
267
|
this.metricsAdapter,
|
|
180
268
|
EntityMetricsLoadType.LOAD_MANY_EQUALITY_CONJUNCTION,
|
|
181
269
|
this.entityClassName,
|
|
270
|
+
queryContext,
|
|
182
271
|
)(
|
|
183
272
|
this.databaseAdapter.fetchManyByFieldEqualityConjunctionAsync(
|
|
184
273
|
queryContext,
|
|
@@ -207,6 +296,7 @@ export default class EntityDataManager<
|
|
|
207
296
|
this.metricsAdapter,
|
|
208
297
|
EntityMetricsLoadType.LOAD_MANY_RAW,
|
|
209
298
|
this.entityClassName,
|
|
299
|
+
queryContext,
|
|
210
300
|
)(
|
|
211
301
|
this.databaseAdapter.fetchManyByRawWhereClauseAsync(
|
|
212
302
|
queryContext,
|
|
@@ -226,6 +316,16 @@ export default class EntityDataManager<
|
|
|
226
316
|
this.getDataLoaderForLoadKey(key).clear(key.serializeLoadValue(value));
|
|
227
317
|
}
|
|
228
318
|
|
|
319
|
+
private invalidateOneForTransaction<
|
|
320
|
+
TLoadKey extends IEntityLoadKey<TFields, TIDField, TSerializedLoadValue, TLoadValue>,
|
|
321
|
+
TSerializedLoadValue,
|
|
322
|
+
TLoadValue extends IEntityLoadValue<TSerializedLoadValue>,
|
|
323
|
+
>(queryContext: EntityTransactionalQueryContext, key: TLoadKey, value: TLoadValue): void {
|
|
324
|
+
this.getTransactionalDataLoaderForLoadKey(queryContext, key).clear(
|
|
325
|
+
key.serializeLoadValue(value),
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
229
329
|
/**
|
|
230
330
|
* Invalidate all caches, in-memory or otherwise, for sets of key-value pairs.
|
|
231
331
|
* @param pairs - key-value pairs to invalidate
|
|
@@ -233,7 +333,67 @@ export default class EntityDataManager<
|
|
|
233
333
|
public async invalidateKeyValuePairsAsync(
|
|
234
334
|
pairs: readonly LoadPair<TFields, TIDField, any, any, any>[],
|
|
235
335
|
): Promise<void> {
|
|
236
|
-
// TODO(wschurman): check for races with load
|
|
237
336
|
await Promise.all(pairs.map(([key, value]) => this.invalidateOneAsync(key, value)));
|
|
238
337
|
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Invalidate all in-memory caches for sets of key-value pairs for all transactions and parent transactions.
|
|
341
|
+
* @param pairs - key-value pairs to invalidate
|
|
342
|
+
*/
|
|
343
|
+
public invalidateKeyValuePairsForTransaction(
|
|
344
|
+
queryContext: EntityTransactionalQueryContext,
|
|
345
|
+
pairs: readonly LoadPair<TFields, TIDField, any, any, any>[],
|
|
346
|
+
): void {
|
|
347
|
+
if (queryContext.transactionalDataLoaderMode === TransactionalDataLoaderMode.DISABLED) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// invalidate all query contexts in transaction tree
|
|
352
|
+
const outermostTransactionalQueryContext =
|
|
353
|
+
EntityDataManager.getOutermostTransactionalQueryContextIfInNestedTransaction(queryContext);
|
|
354
|
+
const allQueryContextsToInvalidate = [
|
|
355
|
+
outermostTransactionalQueryContext,
|
|
356
|
+
...EntityDataManager.getAllDescendantTransactionalQueryContexts(
|
|
357
|
+
outermostTransactionalQueryContext,
|
|
358
|
+
),
|
|
359
|
+
];
|
|
360
|
+
for (const currentQueryContext of allQueryContextsToInvalidate) {
|
|
361
|
+
for (const [key, value] of pairs) {
|
|
362
|
+
this.invalidateOneForTransaction(currentQueryContext, key, value);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Traverse to root of transactional query context tree.
|
|
369
|
+
*/
|
|
370
|
+
private static getOutermostTransactionalQueryContextIfInNestedTransaction(
|
|
371
|
+
queryContext: EntityTransactionalQueryContext,
|
|
372
|
+
): EntityTransactionalQueryContext {
|
|
373
|
+
if (queryContext.isInNestedTransaction()) {
|
|
374
|
+
return EntityDataManager.getOutermostTransactionalQueryContextIfInNestedTransaction(
|
|
375
|
+
queryContext.parentQueryContext,
|
|
376
|
+
);
|
|
377
|
+
} else {
|
|
378
|
+
return queryContext;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Get a list of all child query contexts recursively for a given query context.
|
|
384
|
+
*/
|
|
385
|
+
private static getAllDescendantTransactionalQueryContexts(
|
|
386
|
+
queryContext: EntityTransactionalQueryContext,
|
|
387
|
+
): readonly EntityTransactionalQueryContext[] {
|
|
388
|
+
if (queryContext.childQueryContexts.length === 0) {
|
|
389
|
+
return [];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return queryContext.childQueryContexts.flatMap((childQueryContext) => {
|
|
393
|
+
return [
|
|
394
|
+
childQueryContext,
|
|
395
|
+
...EntityDataManager.getAllDescendantTransactionalQueryContexts(childQueryContext),
|
|
396
|
+
];
|
|
397
|
+
});
|
|
398
|
+
}
|
|
239
399
|
}
|
|
@@ -3,6 +3,9 @@ import nullthrows from 'nullthrows';
|
|
|
3
3
|
|
|
4
4
|
import EntityConfiguration from '../EntityConfiguration';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
6
9
|
export interface FieldTransformer<T> {
|
|
7
10
|
/**
|
|
8
11
|
* Transformation to apply when a value is read from an adapter.
|
|
@@ -17,9 +20,14 @@ export interface FieldTransformer<T> {
|
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* Map from concrete EntityFieldDefinition implementation class name to field transformer.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
20
25
|
*/
|
|
21
26
|
export type FieldTransformerMap = Map<string, FieldTransformer<any>>;
|
|
22
27
|
|
|
28
|
+
/**
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
23
31
|
export const getDatabaseFieldForEntityField = <
|
|
24
32
|
TFields extends Record<string, any>,
|
|
25
33
|
TIDField extends keyof TFields,
|
|
@@ -32,6 +40,9 @@ export const getDatabaseFieldForEntityField = <
|
|
|
32
40
|
return databaseField;
|
|
33
41
|
};
|
|
34
42
|
|
|
43
|
+
/**
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
35
46
|
export const transformDatabaseObjectToFields = <
|
|
36
47
|
TFields extends Record<string, any>,
|
|
37
48
|
TIDField extends keyof TFields,
|
|
@@ -56,6 +67,9 @@ export const transformDatabaseObjectToFields = <
|
|
|
56
67
|
return fields;
|
|
57
68
|
};
|
|
58
69
|
|
|
70
|
+
/**
|
|
71
|
+
* @internal
|
|
72
|
+
*/
|
|
59
73
|
export const transformFieldsToDatabaseObject = <
|
|
60
74
|
TFields extends Record<string, any>,
|
|
61
75
|
TIDField extends keyof TFields,
|
|
@@ -79,6 +93,9 @@ export const transformFieldsToDatabaseObject = <
|
|
|
79
93
|
return databaseObject;
|
|
80
94
|
};
|
|
81
95
|
|
|
96
|
+
/**
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
82
99
|
export const transformCacheObjectToFields = <
|
|
83
100
|
TFields extends Record<string, any>,
|
|
84
101
|
TIDField extends keyof TFields,
|
|
@@ -100,6 +117,9 @@ export const transformCacheObjectToFields = <
|
|
|
100
117
|
return fields;
|
|
101
118
|
};
|
|
102
119
|
|
|
120
|
+
/**
|
|
121
|
+
* @internal
|
|
122
|
+
*/
|
|
103
123
|
export const transformFieldsToCacheObject = <
|
|
104
124
|
TFields extends Record<string, any>,
|
|
105
125
|
TIDField extends keyof TFields,
|
|
@@ -19,6 +19,8 @@ export enum EntityLoadMethodType {
|
|
|
19
19
|
/**
|
|
20
20
|
* Interface responsible for defining how the key and corresponding load values behave in the data manager, cache adapter,
|
|
21
21
|
* and database adapter during entity field loading.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
22
24
|
*/
|
|
23
25
|
export interface IEntityLoadKey<
|
|
24
26
|
TFields extends Record<string, any>,
|
|
@@ -117,6 +119,8 @@ export interface IEntityLoadKey<
|
|
|
117
119
|
|
|
118
120
|
/**
|
|
119
121
|
* Interface for a load value corresponding to a load key.
|
|
122
|
+
*
|
|
123
|
+
* @internal
|
|
120
124
|
*/
|
|
121
125
|
export interface IEntityLoadValue<TSerialized> extends ISerializable<TSerialized> {
|
|
122
126
|
toString(): string;
|
|
@@ -124,6 +128,8 @@ export interface IEntityLoadValue<TSerialized> extends ISerializable<TSerialized
|
|
|
124
128
|
|
|
125
129
|
/**
|
|
126
130
|
* Map from load value interface to value.
|
|
131
|
+
*
|
|
132
|
+
* @internal
|
|
127
133
|
*/
|
|
128
134
|
export abstract class LoadValueMap<
|
|
129
135
|
TSerialized,
|
|
@@ -133,6 +139,8 @@ export abstract class LoadValueMap<
|
|
|
133
139
|
|
|
134
140
|
/**
|
|
135
141
|
* Load pair type for a load key and load value.
|
|
142
|
+
*
|
|
143
|
+
* @internal
|
|
136
144
|
*/
|
|
137
145
|
export type LoadPair<
|
|
138
146
|
TFields extends Record<string, any>,
|
|
@@ -12,6 +12,8 @@ import IEntityMetricsAdapter from '../metrics/IEntityMetricsAdapter';
|
|
|
12
12
|
* Responsible for orchestrating fetching and caching of entity data from a
|
|
13
13
|
* table. Note that one instance is shared amongst all entities that read from
|
|
14
14
|
* the table to ensure cross-entity data consistency.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
15
17
|
*/
|
|
16
18
|
export default class EntityTableDataCoordinator<
|
|
17
19
|
TFields extends Record<string, any>,
|
|
@@ -5,12 +5,18 @@ import IEntityCacheAdapter from '../IEntityCacheAdapter';
|
|
|
5
5
|
import { IEntityLoadKey, IEntityLoadValue } from './EntityLoadInterfaces';
|
|
6
6
|
import { filterMap } from '../utils/collections/maps';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
8
11
|
export enum CacheStatus {
|
|
9
12
|
HIT,
|
|
10
13
|
MISS,
|
|
11
14
|
NEGATIVE,
|
|
12
15
|
}
|
|
13
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
14
20
|
export type CacheLoadResult<TFields extends Record<string, any>> =
|
|
15
21
|
| {
|
|
16
22
|
status: CacheStatus.HIT;
|
|
@@ -26,6 +32,8 @@ export type CacheLoadResult<TFields extends Record<string, any>> =
|
|
|
26
32
|
/**
|
|
27
33
|
* A read-through entity cache is responsible for coordinating EntityDatabaseAdapter and
|
|
28
34
|
* EntityCacheAdapter within the EntityDataManager.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
29
37
|
*/
|
|
30
38
|
export default class ReadThroughEntityCache<
|
|
31
39
|
TFields extends Record<string, any>,
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* A load key that represents a single field (fieldName) on an entity.
|
|
14
|
+
*
|
|
15
|
+
* @internal
|
|
14
16
|
*/
|
|
15
17
|
export class SingleFieldHolder<
|
|
16
18
|
TFields extends Record<string, any>,
|
|
@@ -97,6 +99,8 @@ export class SingleFieldHolder<
|
|
|
97
99
|
|
|
98
100
|
/**
|
|
99
101
|
* A load value for a SingleFieldHolder.
|
|
102
|
+
*
|
|
103
|
+
* @internal
|
|
100
104
|
*/
|
|
101
105
|
export class SingleFieldValueHolder<TFields extends Record<string, any>, N extends keyof TFields>
|
|
102
106
|
implements IEntityLoadValue<NonNullable<TFields[N]>>
|
|
@@ -118,6 +122,9 @@ export class SingleFieldValueHolder<TFields extends Record<string, any>, N exten
|
|
|
118
122
|
}
|
|
119
123
|
}
|
|
120
124
|
|
|
125
|
+
/**
|
|
126
|
+
* @internal
|
|
127
|
+
*/
|
|
121
128
|
export class SingleFieldValueHolderMap<
|
|
122
129
|
TFields extends Record<string, any>,
|
|
123
130
|
N extends keyof TFields,
|