@expo/entity 0.16.0 → 0.20.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/EnforcingEntityLoader.js +2 -2
- package/build/EnforcingEntityLoader.js.map +1 -1
- package/build/Entity.js +8 -2
- package/build/Entity.js.map +1 -1
- package/build/EntityAssociationLoader.js +3 -3
- package/build/EntityAssociationLoader.js.map +1 -1
- package/build/EntityCompanion.d.ts +5 -0
- package/build/EntityCompanion.js +8 -1
- package/build/EntityCompanion.js.map +1 -1
- package/build/EntityCompanionProvider.d.ts +1 -1
- package/build/EntityCompanionProvider.js +5 -5
- package/build/EntityCompanionProvider.js.map +1 -1
- package/build/EntityConfiguration.d.ts +1 -1
- package/build/EntityConfiguration.js +3 -3
- package/build/EntityConfiguration.js.map +1 -1
- package/build/EntityDatabaseAdapter.d.ts +4 -4
- package/build/EntityDatabaseAdapter.js +13 -13
- package/build/EntityDatabaseAdapter.js.map +1 -1
- package/build/EntityFieldDefinition.d.ts +77 -0
- package/build/EntityFieldDefinition.js +53 -0
- package/build/EntityFieldDefinition.js.map +1 -0
- package/build/EntityFields.d.ts +5 -78
- package/build/EntityFields.js +19 -61
- package/build/EntityFields.js.map +1 -1
- package/build/EntityLoader.d.ts +3 -1
- package/build/EntityLoader.js +19 -15
- package/build/EntityLoader.js.map +1 -1
- package/build/EntityLoaderFactory.d.ts +3 -1
- package/build/EntityLoaderFactory.js +3 -2
- package/build/EntityLoaderFactory.js.map +1 -1
- package/build/EntityMutationInfo.d.ts +26 -0
- package/build/EntityMutationInfo.js +10 -0
- package/build/EntityMutationInfo.js.map +1 -0
- package/build/EntityMutationTriggerConfiguration.d.ts +4 -4
- package/build/EntityMutationValidator.d.ts +3 -3
- package/build/EntityMutationValidator.js.map +1 -1
- package/build/EntityMutator.d.ts +5 -16
- package/build/EntityMutator.js +62 -58
- package/build/EntityMutator.js.map +1 -1
- package/build/EntityPrivacyPolicy.d.ts +5 -4
- package/build/EntityPrivacyPolicy.js +60 -12
- package/build/EntityPrivacyPolicy.js.map +1 -1
- package/build/EntityQueryContext.d.ts +13 -0
- package/build/EntityQueryContext.js +18 -0
- package/build/EntityQueryContext.js.map +1 -1
- package/build/EntitySecondaryCacheLoader.js +2 -2
- package/build/EntitySecondaryCacheLoader.js.map +1 -1
- package/build/ReadonlyEntity.js +3 -4
- package/build/ReadonlyEntity.js.map +1 -1
- package/build/ViewerScopedEntityCompanion.d.ts +5 -0
- package/build/ViewerScopedEntityCompanion.js +6 -0
- package/build/ViewerScopedEntityCompanion.js.map +1 -1
- package/build/__tests__/EnforcingEntityLoader-test.js +82 -82
- package/build/__tests__/EnforcingEntityLoader-test.js.map +1 -1
- package/build/__tests__/Entity-test.js +6 -6
- package/build/__tests__/Entity-test.js.map +1 -1
- package/build/__tests__/EntityAssociationLoader-test.js +40 -40
- package/build/__tests__/EntityAssociationLoader-test.js.map +1 -1
- package/build/__tests__/EntityCommonUseCases-test.js +11 -11
- package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
- package/build/__tests__/EntityCompanion-test.js +3 -3
- package/build/__tests__/EntityCompanion-test.js.map +1 -1
- package/build/__tests__/EntityCompanionProvider-test.js +1 -1
- package/build/__tests__/EntityCompanionProvider-test.js.map +1 -1
- package/build/__tests__/EntityDatabaseAdapter-test.js +12 -12
- package/build/__tests__/EntityDatabaseAdapter-test.js.map +1 -1
- package/build/__tests__/EntityEdges-test.js +103 -6
- package/build/__tests__/EntityEdges-test.js.map +1 -1
- package/build/__tests__/EntityFields-test.js +18 -26
- package/build/__tests__/EntityFields-test.js.map +1 -1
- package/build/__tests__/EntityLoader-constructor-test.d.ts +22 -0
- package/build/__tests__/EntityLoader-constructor-test.js +111 -0
- package/build/__tests__/EntityLoader-constructor-test.js.map +1 -0
- package/build/__tests__/EntityLoader-test.js +81 -73
- package/build/__tests__/EntityLoader-test.js.map +1 -1
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.d.ts +1 -0
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js +81 -0
- package/build/__tests__/EntityMutator-MutationCacheConsistency-test.js.map +1 -0
- package/build/__tests__/EntityMutator-test.js +138 -136
- package/build/__tests__/EntityMutator-test.js.map +1 -1
- package/build/__tests__/EntityPrivacyPolicy-test.js +143 -67
- package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
- package/build/__tests__/EntitySecondaryCacheLoader-test.js +15 -15
- package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
- package/build/__tests__/EntitySelfReferentialEdges-test.js +13 -12
- package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
- package/build/__tests__/ReadonlyEntity-test.js +12 -12
- package/build/__tests__/ReadonlyEntity-test.js.map +1 -1
- package/build/__tests__/ViewerContext-test.js +2 -2
- package/build/__tests__/ViewerContext-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityCompanion-test.js +2 -2
- package/build/__tests__/ViewerScopedEntityCompanion-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js +2 -2
- package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js +5 -5
- package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js +5 -5
- package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js +5 -5
- package/build/__tests__/cases/TwoEntitySameTableDisjointRows-test.js.map +1 -1
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js +2 -2
- package/build/__tests__/cases/TwoEntitySameTableOverlappingRows-test.js.map +1 -1
- package/build/__tests__/entityUtils-test.js +21 -21
- package/build/__tests__/entityUtils-test.js.map +1 -1
- package/build/index.d.ts +3 -0
- package/build/index.js +5 -1
- package/build/index.js.map +1 -1
- package/build/internal/EntityDataManager.js +8 -7
- package/build/internal/EntityDataManager.js.map +1 -1
- package/build/internal/EntityFieldTransformationUtils.js +2 -2
- package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
- package/build/internal/ReadThroughEntityCache.js +4 -4
- package/build/internal/ReadThroughEntityCache.js.map +1 -1
- package/build/internal/__tests__/EntityDataManager-test.js +21 -21
- package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
- package/build/internal/__tests__/EntityFieldTransformationUtils-test.js +8 -8
- package/build/internal/__tests__/EntityFieldTransformationUtils-test.js.map +1 -1
- package/build/internal/__tests__/ReadThroughEntityCache-test.js +48 -48
- package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
- package/build/metrics/EntityMetricsUtils.js +1 -1
- package/build/metrics/EntityMetricsUtils.js.map +1 -1
- package/build/metrics/IEntityMetricsAdapter.d.ts +16 -0
- package/build/metrics/IEntityMetricsAdapter.js +6 -1
- package/build/metrics/IEntityMetricsAdapter.js.map +1 -1
- package/build/metrics/NoOpEntityMetricsAdapter.d.ts +2 -1
- package/build/metrics/NoOpEntityMetricsAdapter.js +1 -0
- package/build/metrics/NoOpEntityMetricsAdapter.js.map +1 -1
- package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js +4 -4
- package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
- package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js +4 -4
- package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
- package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js +4 -4
- package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
- package/build/testfixtures/DateIDTestEntity.js.map +1 -1
- package/build/testfixtures/SimpleTestEntity.js.map +1 -1
- package/build/testfixtures/TestEntity.d.ts +6 -6
- package/build/testfixtures/TestEntity.js +4 -4
- package/build/testfixtures/TestEntity.js.map +1 -1
- package/build/testfixtures/TestEntity2.d.ts +5 -5
- package/build/testfixtures/TestEntity2.js.map +1 -1
- package/build/testfixtures/TestEntityNumberKey.js +1 -1
- package/build/testfixtures/TestEntityNumberKey.js.map +1 -1
- package/build/utils/collections/__tests__/maps-test.js +13 -13
- package/build/utils/collections/__tests__/maps-test.js.map +1 -1
- package/build/utils/collections/maps.js +1 -1
- package/build/utils/collections/maps.js.map +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +6 -6
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
- package/build/utils/testing/StubCacheAdapter.js +1 -1
- package/build/utils/testing/StubCacheAdapter.js.map +1 -1
- package/build/utils/testing/StubDatabaseAdapter.js +7 -7
- package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
- package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js +26 -26
- package/build/utils/testing/__tests__/StubDatabaseAdapter-test.js.map +1 -1
- package/build/utils/testing/describeFieldTestCase.d.ts +2 -0
- package/build/utils/testing/describeFieldTestCase.js +18 -0
- package/build/utils/testing/describeFieldTestCase.js.map +1 -0
- package/package.json +2 -1
- package/src/Entity.ts +10 -2
- package/src/EntityAssociationLoader.ts +1 -1
- package/src/EntityCompanion.ts +10 -2
- package/src/EntityCompanionProvider.ts +5 -9
- package/src/EntityConfiguration.ts +1 -1
- package/src/EntityDatabaseAdapter.ts +10 -8
- package/src/EntityFieldDefinition.ts +124 -0
- package/src/EntityFields.ts +11 -126
- package/src/EntityLoader.ts +12 -4
- package/src/EntityLoaderFactory.ts +5 -2
- package/src/EntityMutationInfo.ts +47 -0
- package/src/EntityMutationTriggerConfiguration.ts +5 -5
- package/src/EntityMutationValidator.ts +10 -4
- package/src/EntityMutator.ts +98 -76
- package/src/EntityPrivacyPolicy.ts +77 -19
- package/src/EntityQueryContext.ts +20 -0
- package/src/ReadonlyEntity.ts +3 -2
- package/src/ViewerScopedEntityCompanion.ts +8 -0
- package/src/__tests__/Entity-test.ts +8 -8
- package/src/__tests__/EntityCommonUseCases-test.ts +4 -4
- package/src/__tests__/EntityEdges-test.ts +169 -14
- package/src/__tests__/EntityFields-test.ts +6 -23
- package/src/__tests__/EntityLoader-constructor-test.ts +177 -0
- package/src/__tests__/EntityLoader-test.ts +48 -20
- package/src/__tests__/EntityMutator-MutationCacheConsistency-test.ts +105 -0
- package/src/__tests__/EntityMutator-test.ts +153 -146
- package/src/__tests__/EntityPrivacyPolicy-test.ts +215 -78
- package/src/__tests__/EntitySecondaryCacheLoader-test.ts +7 -9
- package/src/__tests__/EntitySelfReferentialEdges-test.ts +6 -5
- package/src/__tests__/ReadonlyEntity-test.ts +1 -1
- package/src/__tests__/ViewerContext-test.ts +7 -6
- package/src/__tests__/ViewerScopedEntityCompanion-test.ts +11 -10
- package/src/__tests__/ViewerScopedEntityMutatorFactory-test.ts +4 -3
- package/src/__tests__/cases/TwoEntitySameTableDisjointRows-test.ts +6 -6
- package/src/__tests__/cases/TwoEntitySameTableOverlappingRows-test.ts +4 -4
- package/src/index.ts +3 -0
- package/src/internal/EntityDataManager.ts +2 -1
- package/src/internal/__tests__/EntityDataManager-test.ts +6 -6
- package/src/internal/__tests__/ReadThroughEntityCache-test.ts +15 -13
- package/src/metrics/EntityMetricsUtils.ts +56 -50
- package/src/metrics/IEntityMetricsAdapter.ts +23 -0
- package/src/metrics/NoOpEntityMetricsAdapter.ts +2 -0
- package/src/testfixtures/DateIDTestEntity.ts +4 -4
- package/src/testfixtures/SimpleTestEntity.ts +4 -4
- package/src/testfixtures/TestEntity.ts +8 -8
- package/src/testfixtures/TestEntity2.ts +4 -4
- package/src/testfixtures/TestEntityNumberKey.ts +6 -6
- package/src/utils/testing/StubDatabaseAdapter.ts +4 -4
- package/src/utils/testing/__tests__/StubDatabaseAdapter-test.ts +18 -18
- package/src/utils/testing/describeFieldTestCase.ts +21 -0
- package/CHANGELOG.md +0 -241
package/src/EntityMutator.ts
CHANGED
|
@@ -5,8 +5,14 @@ import Entity, { IEntityClass } from './Entity';
|
|
|
5
5
|
import { EntityCompanionDefinition } from './EntityCompanionProvider';
|
|
6
6
|
import EntityConfiguration from './EntityConfiguration';
|
|
7
7
|
import EntityDatabaseAdapter from './EntityDatabaseAdapter';
|
|
8
|
-
import { EntityEdgeDeletionBehavior } from './
|
|
8
|
+
import { EntityEdgeDeletionBehavior } from './EntityFieldDefinition';
|
|
9
9
|
import EntityLoaderFactory from './EntityLoaderFactory';
|
|
10
|
+
import {
|
|
11
|
+
EntityValidatorMutationInfo,
|
|
12
|
+
EntityMutationType,
|
|
13
|
+
EntityTriggerMutationInfo,
|
|
14
|
+
EntityMutationTriggerDeleteCascadeInfo,
|
|
15
|
+
} from './EntityMutationInfo';
|
|
10
16
|
import EntityMutationTriggerConfiguration, {
|
|
11
17
|
EntityMutationTrigger,
|
|
12
18
|
EntityNonTransactionalMutationTrigger,
|
|
@@ -21,30 +27,6 @@ import { timeAndLogMutationEventAsync } from './metrics/EntityMetricsUtils';
|
|
|
21
27
|
import IEntityMetricsAdapter, { EntityMetricsMutationType } from './metrics/IEntityMetricsAdapter';
|
|
22
28
|
import { mapMapAsync } from './utils/collections/maps';
|
|
23
29
|
|
|
24
|
-
export enum EntityMutationType {
|
|
25
|
-
CREATE,
|
|
26
|
-
UPDATE,
|
|
27
|
-
DELETE,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export type EntityMutationInfo<
|
|
31
|
-
TFields,
|
|
32
|
-
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
33
|
-
TViewerContext extends ViewerContext,
|
|
34
|
-
TEntity extends Entity<TFields, TID, TViewerContext, TSelectedFields>,
|
|
35
|
-
TSelectedFields extends keyof TFields = keyof TFields
|
|
36
|
-
> =
|
|
37
|
-
| {
|
|
38
|
-
type: EntityMutationType.CREATE;
|
|
39
|
-
}
|
|
40
|
-
| {
|
|
41
|
-
type: EntityMutationType.UPDATE;
|
|
42
|
-
previousValue: TEntity;
|
|
43
|
-
}
|
|
44
|
-
| {
|
|
45
|
-
type: EntityMutationType.DELETE;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
30
|
abstract class BaseMutator<
|
|
49
31
|
TFields,
|
|
50
32
|
TID extends NonNullable<TFields[TSelectedFields]>,
|
|
@@ -110,26 +92,44 @@ abstract class BaseMutator<
|
|
|
110
92
|
}
|
|
111
93
|
}
|
|
112
94
|
|
|
113
|
-
protected async
|
|
114
|
-
|
|
95
|
+
protected async executeMutationValidatorsAsync(
|
|
96
|
+
validators: EntityMutationValidator<TFields, TID, TViewerContext, TEntity, TSelectedFields>[],
|
|
97
|
+
queryContext: EntityTransactionalQueryContext,
|
|
98
|
+
entity: TEntity,
|
|
99
|
+
mutationInfo: EntityValidatorMutationInfo<
|
|
100
|
+
TFields,
|
|
101
|
+
TID,
|
|
102
|
+
TViewerContext,
|
|
103
|
+
TEntity,
|
|
104
|
+
TSelectedFields
|
|
105
|
+
>
|
|
106
|
+
): Promise<void> {
|
|
107
|
+
await Promise.all(
|
|
108
|
+
validators.map((validator) =>
|
|
109
|
+
validator.executeAsync(this.viewerContext, queryContext, entity, mutationInfo)
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
protected async executeMutationTriggersAsync(
|
|
115
|
+
triggers:
|
|
115
116
|
| EntityMutationTrigger<TFields, TID, TViewerContext, TEntity, TSelectedFields>[]
|
|
116
|
-
| EntityMutationValidator<TFields, TID, TViewerContext, TEntity, TSelectedFields>[]
|
|
117
117
|
| undefined,
|
|
118
|
-
queryContext:
|
|
118
|
+
queryContext: EntityTransactionalQueryContext,
|
|
119
119
|
entity: TEntity,
|
|
120
|
-
mutationInfo:
|
|
120
|
+
mutationInfo: EntityTriggerMutationInfo<TFields, TID, TViewerContext, TEntity, TSelectedFields>
|
|
121
121
|
): Promise<void> {
|
|
122
|
-
if (!
|
|
122
|
+
if (!triggers) {
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
await Promise.all(
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
triggers.map((trigger) =>
|
|
127
|
+
trigger.executeAsync(this.viewerContext, queryContext, entity, mutationInfo)
|
|
128
128
|
)
|
|
129
129
|
);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
protected async
|
|
132
|
+
protected async executeNonTransactionalMutationTriggersAsync(
|
|
133
133
|
triggers:
|
|
134
134
|
| EntityNonTransactionalMutationTrigger<
|
|
135
135
|
TFields,
|
|
@@ -140,7 +140,7 @@ abstract class BaseMutator<
|
|
|
140
140
|
>[]
|
|
141
141
|
| undefined,
|
|
142
142
|
entity: TEntity,
|
|
143
|
-
mutationInfo:
|
|
143
|
+
mutationInfo: EntityTriggerMutationInfo<TFields, TID, TViewerContext, TEntity, TSelectedFields>
|
|
144
144
|
): Promise<void> {
|
|
145
145
|
if (!triggers) {
|
|
146
146
|
return;
|
|
@@ -211,35 +211,36 @@ export class CreateMutator<
|
|
|
211
211
|
): Promise<Result<TEntity>> {
|
|
212
212
|
this.validateFields(this.fieldsForEntity);
|
|
213
213
|
|
|
214
|
-
const temporaryEntityForPrivacyCheck = new this.entityClass(this.viewerContext,
|
|
214
|
+
const temporaryEntityForPrivacyCheck = new this.entityClass(this.viewerContext, {
|
|
215
215
|
[this.entityConfiguration.idField]: '00000000-0000-0000-0000-000000000000', // zero UUID
|
|
216
216
|
...this.fieldsForEntity,
|
|
217
|
-
} as unknown
|
|
217
|
+
} as unknown as TFields);
|
|
218
218
|
|
|
219
219
|
const authorizeCreateResult = await asyncResult(
|
|
220
220
|
this.privacyPolicy.authorizeCreateAsync(
|
|
221
221
|
this.viewerContext,
|
|
222
222
|
queryContext,
|
|
223
|
-
temporaryEntityForPrivacyCheck
|
|
223
|
+
temporaryEntityForPrivacyCheck,
|
|
224
|
+
this.metricsAdapter
|
|
224
225
|
)
|
|
225
226
|
);
|
|
226
227
|
if (!authorizeCreateResult.ok) {
|
|
227
228
|
return authorizeCreateResult;
|
|
228
229
|
}
|
|
229
230
|
|
|
230
|
-
await this.
|
|
231
|
+
await this.executeMutationValidatorsAsync(
|
|
231
232
|
this.mutationValidators,
|
|
232
233
|
queryContext,
|
|
233
234
|
temporaryEntityForPrivacyCheck,
|
|
234
235
|
{ type: EntityMutationType.CREATE }
|
|
235
236
|
);
|
|
236
|
-
await this.
|
|
237
|
+
await this.executeMutationTriggersAsync(
|
|
237
238
|
this.mutationTriggers.beforeAll,
|
|
238
239
|
queryContext,
|
|
239
240
|
temporaryEntityForPrivacyCheck,
|
|
240
241
|
{ type: EntityMutationType.CREATE }
|
|
241
242
|
);
|
|
242
|
-
await this.
|
|
243
|
+
await this.executeMutationTriggersAsync(
|
|
243
244
|
this.mutationTriggers.beforeCreate,
|
|
244
245
|
queryContext,
|
|
245
246
|
temporaryEntityForPrivacyCheck,
|
|
@@ -249,7 +250,7 @@ export class CreateMutator<
|
|
|
249
250
|
const insertResult = await this.databaseAdapter.insertAsync(queryContext, this.fieldsForEntity);
|
|
250
251
|
|
|
251
252
|
const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext);
|
|
252
|
-
queryContext.
|
|
253
|
+
queryContext.appendPostCommitInvalidationCallback(
|
|
253
254
|
entityLoader.invalidateFieldsAsync.bind(entityLoader, insertResult)
|
|
254
255
|
);
|
|
255
256
|
|
|
@@ -258,13 +259,13 @@ export class CreateMutator<
|
|
|
258
259
|
.enforcing()
|
|
259
260
|
.loadByIDAsync(unauthorizedEntityAfterInsert.getID());
|
|
260
261
|
|
|
261
|
-
await this.
|
|
262
|
+
await this.executeMutationTriggersAsync(
|
|
262
263
|
this.mutationTriggers.afterCreate,
|
|
263
264
|
queryContext,
|
|
264
265
|
newEntity,
|
|
265
266
|
{ type: EntityMutationType.CREATE }
|
|
266
267
|
);
|
|
267
|
-
await this.
|
|
268
|
+
await this.executeMutationTriggersAsync(
|
|
268
269
|
this.mutationTriggers.afterAll,
|
|
269
270
|
queryContext,
|
|
270
271
|
newEntity,
|
|
@@ -272,7 +273,7 @@ export class CreateMutator<
|
|
|
272
273
|
);
|
|
273
274
|
|
|
274
275
|
queryContext.appendPostCommitCallback(
|
|
275
|
-
this.
|
|
276
|
+
this.executeNonTransactionalMutationTriggersAsync.bind(
|
|
276
277
|
this,
|
|
277
278
|
this.mutationTriggers.afterCommit,
|
|
278
279
|
newEntity,
|
|
@@ -408,26 +409,27 @@ export class UpdateMutator<
|
|
|
408
409
|
this.privacyPolicy.authorizeUpdateAsync(
|
|
409
410
|
this.viewerContext,
|
|
410
411
|
queryContext,
|
|
411
|
-
entityAboutToBeUpdated
|
|
412
|
+
entityAboutToBeUpdated,
|
|
413
|
+
this.metricsAdapter
|
|
412
414
|
)
|
|
413
415
|
);
|
|
414
416
|
if (!authorizeUpdateResult.ok) {
|
|
415
417
|
return authorizeUpdateResult;
|
|
416
418
|
}
|
|
417
419
|
|
|
418
|
-
await this.
|
|
420
|
+
await this.executeMutationValidatorsAsync(
|
|
419
421
|
this.mutationValidators,
|
|
420
422
|
queryContext,
|
|
421
423
|
entityAboutToBeUpdated,
|
|
422
424
|
{ type: EntityMutationType.UPDATE, previousValue: this.originalEntity }
|
|
423
425
|
);
|
|
424
|
-
await this.
|
|
426
|
+
await this.executeMutationTriggersAsync(
|
|
425
427
|
this.mutationTriggers.beforeAll,
|
|
426
428
|
queryContext,
|
|
427
429
|
entityAboutToBeUpdated,
|
|
428
430
|
{ type: EntityMutationType.UPDATE, previousValue: this.originalEntity }
|
|
429
431
|
);
|
|
430
|
-
await this.
|
|
432
|
+
await this.executeMutationTriggersAsync(
|
|
431
433
|
this.mutationTriggers.beforeUpdate,
|
|
432
434
|
queryContext,
|
|
433
435
|
entityAboutToBeUpdated,
|
|
@@ -443,13 +445,13 @@ export class UpdateMutator<
|
|
|
443
445
|
|
|
444
446
|
const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext);
|
|
445
447
|
|
|
446
|
-
queryContext.
|
|
448
|
+
queryContext.appendPostCommitInvalidationCallback(
|
|
447
449
|
entityLoader.invalidateFieldsAsync.bind(
|
|
448
450
|
entityLoader,
|
|
449
451
|
this.originalEntity.getAllDatabaseFields()
|
|
450
452
|
)
|
|
451
453
|
);
|
|
452
|
-
queryContext.
|
|
454
|
+
queryContext.appendPostCommitInvalidationCallback(
|
|
453
455
|
entityLoader.invalidateFieldsAsync.bind(entityLoader, this.fieldsForEntity)
|
|
454
456
|
);
|
|
455
457
|
|
|
@@ -458,13 +460,13 @@ export class UpdateMutator<
|
|
|
458
460
|
.enforcing()
|
|
459
461
|
.loadByIDAsync(unauthorizedEntityAfterUpdate.getID());
|
|
460
462
|
|
|
461
|
-
await this.
|
|
463
|
+
await this.executeMutationTriggersAsync(
|
|
462
464
|
this.mutationTriggers.afterUpdate,
|
|
463
465
|
queryContext,
|
|
464
466
|
updatedEntity,
|
|
465
467
|
{ type: EntityMutationType.UPDATE, previousValue: this.originalEntity }
|
|
466
468
|
);
|
|
467
|
-
await this.
|
|
469
|
+
await this.executeMutationTriggersAsync(
|
|
468
470
|
this.mutationTriggers.afterAll,
|
|
469
471
|
queryContext,
|
|
470
472
|
updatedEntity,
|
|
@@ -472,7 +474,7 @@ export class UpdateMutator<
|
|
|
472
474
|
);
|
|
473
475
|
|
|
474
476
|
queryContext.appendPostCommitCallback(
|
|
475
|
-
this.
|
|
477
|
+
this.executeNonTransactionalMutationTriggersAsync.bind(
|
|
476
478
|
this,
|
|
477
479
|
this.mutationTriggers.afterCommit,
|
|
478
480
|
updatedEntity,
|
|
@@ -563,7 +565,7 @@ export class DeleteMutator<
|
|
|
563
565
|
this.metricsAdapter,
|
|
564
566
|
EntityMetricsMutationType.DELETE,
|
|
565
567
|
this.entityClass.name
|
|
566
|
-
)(this.deleteInTransactionAsync());
|
|
568
|
+
)(this.deleteInTransactionAsync(new Set(), false, null));
|
|
567
569
|
}
|
|
568
570
|
|
|
569
571
|
/**
|
|
@@ -574,14 +576,16 @@ export class DeleteMutator<
|
|
|
574
576
|
}
|
|
575
577
|
|
|
576
578
|
private async deleteInTransactionAsync(
|
|
577
|
-
processedEntityIdentifiersFromTransitiveDeletions: Set<string
|
|
578
|
-
skipDatabaseDeletion: boolean
|
|
579
|
+
processedEntityIdentifiersFromTransitiveDeletions: Set<string>,
|
|
580
|
+
skipDatabaseDeletion: boolean,
|
|
581
|
+
cascadingDeleteCause: EntityMutationTriggerDeleteCascadeInfo | null
|
|
579
582
|
): Promise<Result<void>> {
|
|
580
583
|
return await this.queryContext.runInTransactionIfNotInTransactionAsync((innerQueryContext) =>
|
|
581
584
|
this.deleteInternalAsync(
|
|
582
585
|
innerQueryContext,
|
|
583
586
|
processedEntityIdentifiersFromTransitiveDeletions,
|
|
584
|
-
skipDatabaseDeletion
|
|
587
|
+
skipDatabaseDeletion,
|
|
588
|
+
cascadingDeleteCause
|
|
585
589
|
)
|
|
586
590
|
);
|
|
587
591
|
}
|
|
@@ -589,10 +593,16 @@ export class DeleteMutator<
|
|
|
589
593
|
private async deleteInternalAsync(
|
|
590
594
|
queryContext: EntityTransactionalQueryContext,
|
|
591
595
|
processedEntityIdentifiersFromTransitiveDeletions: Set<string>,
|
|
592
|
-
skipDatabaseDeletion: boolean
|
|
596
|
+
skipDatabaseDeletion: boolean,
|
|
597
|
+
cascadingDeleteCause: EntityMutationTriggerDeleteCascadeInfo | null
|
|
593
598
|
): Promise<Result<void>> {
|
|
594
599
|
const authorizeDeleteResult = await asyncResult(
|
|
595
|
-
this.privacyPolicy.authorizeDeleteAsync(
|
|
600
|
+
this.privacyPolicy.authorizeDeleteAsync(
|
|
601
|
+
this.viewerContext,
|
|
602
|
+
queryContext,
|
|
603
|
+
this.entity,
|
|
604
|
+
this.metricsAdapter
|
|
605
|
+
)
|
|
596
606
|
);
|
|
597
607
|
if (!authorizeDeleteResult.ok) {
|
|
598
608
|
return authorizeDeleteResult;
|
|
@@ -601,20 +611,21 @@ export class DeleteMutator<
|
|
|
601
611
|
await this.processEntityDeletionForInboundEdgesAsync(
|
|
602
612
|
this.entity,
|
|
603
613
|
queryContext,
|
|
604
|
-
processedEntityIdentifiersFromTransitiveDeletions
|
|
614
|
+
processedEntityIdentifiersFromTransitiveDeletions,
|
|
615
|
+
cascadingDeleteCause
|
|
605
616
|
);
|
|
606
617
|
|
|
607
|
-
await this.
|
|
618
|
+
await this.executeMutationTriggersAsync(
|
|
608
619
|
this.mutationTriggers.beforeAll,
|
|
609
620
|
queryContext,
|
|
610
621
|
this.entity,
|
|
611
|
-
{ type: EntityMutationType.DELETE }
|
|
622
|
+
{ type: EntityMutationType.DELETE, cascadingDeleteCause }
|
|
612
623
|
);
|
|
613
|
-
await this.
|
|
624
|
+
await this.executeMutationTriggersAsync(
|
|
614
625
|
this.mutationTriggers.beforeDelete,
|
|
615
626
|
queryContext,
|
|
616
627
|
this.entity,
|
|
617
|
-
{ type: EntityMutationType.DELETE }
|
|
628
|
+
{ type: EntityMutationType.DELETE, cascadingDeleteCause }
|
|
618
629
|
);
|
|
619
630
|
|
|
620
631
|
if (!skipDatabaseDeletion) {
|
|
@@ -626,29 +637,29 @@ export class DeleteMutator<
|
|
|
626
637
|
}
|
|
627
638
|
|
|
628
639
|
const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext);
|
|
629
|
-
queryContext.
|
|
640
|
+
queryContext.appendPostCommitInvalidationCallback(
|
|
630
641
|
entityLoader.invalidateFieldsAsync.bind(entityLoader, this.entity.getAllDatabaseFields())
|
|
631
642
|
);
|
|
632
643
|
|
|
633
|
-
await this.
|
|
644
|
+
await this.executeMutationTriggersAsync(
|
|
634
645
|
this.mutationTriggers.afterDelete,
|
|
635
646
|
queryContext,
|
|
636
647
|
this.entity,
|
|
637
|
-
{ type: EntityMutationType.DELETE }
|
|
648
|
+
{ type: EntityMutationType.DELETE, cascadingDeleteCause }
|
|
638
649
|
);
|
|
639
|
-
await this.
|
|
650
|
+
await this.executeMutationTriggersAsync(
|
|
640
651
|
this.mutationTriggers.afterAll,
|
|
641
652
|
queryContext,
|
|
642
653
|
this.entity,
|
|
643
|
-
{ type: EntityMutationType.DELETE }
|
|
654
|
+
{ type: EntityMutationType.DELETE, cascadingDeleteCause }
|
|
644
655
|
);
|
|
645
656
|
|
|
646
657
|
queryContext.appendPostCommitCallback(
|
|
647
|
-
this.
|
|
658
|
+
this.executeNonTransactionalMutationTriggersAsync.bind(
|
|
648
659
|
this,
|
|
649
660
|
this.mutationTriggers.afterCommit,
|
|
650
661
|
this.entity,
|
|
651
|
-
{ type: EntityMutationType.DELETE }
|
|
662
|
+
{ type: EntityMutationType.DELETE, cascadingDeleteCause }
|
|
652
663
|
)
|
|
653
664
|
);
|
|
654
665
|
|
|
@@ -672,7 +683,8 @@ export class DeleteMutator<
|
|
|
672
683
|
private async processEntityDeletionForInboundEdgesAsync(
|
|
673
684
|
entity: TEntity,
|
|
674
685
|
queryContext: EntityTransactionalQueryContext,
|
|
675
|
-
processedEntityIdentifiers: Set<string
|
|
686
|
+
processedEntityIdentifiers: Set<string>,
|
|
687
|
+
cascadingDeleteCause: EntityMutationTriggerDeleteCascadeInfo | null
|
|
676
688
|
): Promise<void> {
|
|
677
689
|
// prevent infinite reference cycles by keeping track of entities already processed
|
|
678
690
|
if (processedEntityIdentifiers.has(entity.getUniqueIdentifier())) {
|
|
@@ -680,7 +692,9 @@ export class DeleteMutator<
|
|
|
680
692
|
}
|
|
681
693
|
processedEntityIdentifiers.add(entity.getUniqueIdentifier());
|
|
682
694
|
|
|
683
|
-
const companionDefinition = (
|
|
695
|
+
const companionDefinition = (
|
|
696
|
+
entity.constructor as any
|
|
697
|
+
).getCompanionDefinition() as EntityCompanionDefinition<
|
|
684
698
|
TFields,
|
|
685
699
|
TID,
|
|
686
700
|
TViewerContext,
|
|
@@ -743,7 +757,11 @@ export class DeleteMutator<
|
|
|
743
757
|
.forDelete(inboundReferenceEntity, queryContext)
|
|
744
758
|
.deleteInTransactionAsync(
|
|
745
759
|
processedEntityIdentifiers,
|
|
746
|
-
/* skipDatabaseDeletion */ true // deletion is handled by DB
|
|
760
|
+
/* skipDatabaseDeletion */ true, // deletion is handled by DB
|
|
761
|
+
{
|
|
762
|
+
entity,
|
|
763
|
+
cascadingDeleteCause,
|
|
764
|
+
}
|
|
747
765
|
)
|
|
748
766
|
)
|
|
749
767
|
);
|
|
@@ -767,7 +785,11 @@ export class DeleteMutator<
|
|
|
767
785
|
.forDelete(inboundReferenceEntity, queryContext)
|
|
768
786
|
.deleteInTransactionAsync(
|
|
769
787
|
processedEntityIdentifiers,
|
|
770
|
-
/* skipDatabaseDeletion */ false
|
|
788
|
+
/* skipDatabaseDeletion */ false,
|
|
789
|
+
{
|
|
790
|
+
entity,
|
|
791
|
+
cascadingDeleteCause,
|
|
792
|
+
}
|
|
771
793
|
)
|
|
772
794
|
)
|
|
773
795
|
);
|
|
@@ -2,6 +2,9 @@ import { EntityQueryContext } from './EntityQueryContext';
|
|
|
2
2
|
import ReadonlyEntity from './ReadonlyEntity';
|
|
3
3
|
import ViewerContext from './ViewerContext';
|
|
4
4
|
import EntityNotAuthorizedError from './errors/EntityNotAuthorizedError';
|
|
5
|
+
import IEntityMetricsAdapter, {
|
|
6
|
+
EntityMetricsAuthorizationResult,
|
|
7
|
+
} from './metrics/IEntityMetricsAdapter';
|
|
5
8
|
import PrivacyPolicyRule, { RuleEvaluationResult } from './rules/PrivacyPolicyRule';
|
|
6
9
|
|
|
7
10
|
export enum EntityPrivacyPolicyEvaluationMode {
|
|
@@ -124,14 +127,16 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
124
127
|
async authorizeCreateAsync(
|
|
125
128
|
viewerContext: TViewerContext,
|
|
126
129
|
queryContext: EntityQueryContext,
|
|
127
|
-
entity: TEntity
|
|
130
|
+
entity: TEntity,
|
|
131
|
+
metricsAdapter: IEntityMetricsAdapter
|
|
128
132
|
): Promise<TEntity> {
|
|
129
133
|
return await this.authorizeForRulesetAsync(
|
|
130
134
|
this.createRules,
|
|
131
135
|
viewerContext,
|
|
132
136
|
queryContext,
|
|
133
137
|
entity,
|
|
134
|
-
EntityAuthorizationAction.CREATE
|
|
138
|
+
EntityAuthorizationAction.CREATE,
|
|
139
|
+
metricsAdapter
|
|
135
140
|
);
|
|
136
141
|
}
|
|
137
142
|
|
|
@@ -146,14 +151,16 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
146
151
|
async authorizeReadAsync(
|
|
147
152
|
viewerContext: TViewerContext,
|
|
148
153
|
queryContext: EntityQueryContext,
|
|
149
|
-
entity: TEntity
|
|
154
|
+
entity: TEntity,
|
|
155
|
+
metricsAdapter: IEntityMetricsAdapter
|
|
150
156
|
): Promise<TEntity> {
|
|
151
157
|
return await this.authorizeForRulesetAsync(
|
|
152
158
|
this.readRules,
|
|
153
159
|
viewerContext,
|
|
154
160
|
queryContext,
|
|
155
161
|
entity,
|
|
156
|
-
EntityAuthorizationAction.READ
|
|
162
|
+
EntityAuthorizationAction.READ,
|
|
163
|
+
metricsAdapter
|
|
157
164
|
);
|
|
158
165
|
}
|
|
159
166
|
|
|
@@ -168,14 +175,16 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
168
175
|
async authorizeUpdateAsync(
|
|
169
176
|
viewerContext: TViewerContext,
|
|
170
177
|
queryContext: EntityQueryContext,
|
|
171
|
-
entity: TEntity
|
|
178
|
+
entity: TEntity,
|
|
179
|
+
metricsAdapter: IEntityMetricsAdapter
|
|
172
180
|
): Promise<TEntity> {
|
|
173
181
|
return await this.authorizeForRulesetAsync(
|
|
174
182
|
this.updateRules,
|
|
175
183
|
viewerContext,
|
|
176
184
|
queryContext,
|
|
177
185
|
entity,
|
|
178
|
-
EntityAuthorizationAction.UPDATE
|
|
186
|
+
EntityAuthorizationAction.UPDATE,
|
|
187
|
+
metricsAdapter
|
|
179
188
|
);
|
|
180
189
|
}
|
|
181
190
|
|
|
@@ -190,14 +199,16 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
190
199
|
async authorizeDeleteAsync(
|
|
191
200
|
viewerContext: TViewerContext,
|
|
192
201
|
queryContext: EntityQueryContext,
|
|
193
|
-
entity: TEntity
|
|
202
|
+
entity: TEntity,
|
|
203
|
+
metricsAdapter: IEntityMetricsAdapter
|
|
194
204
|
): Promise<TEntity> {
|
|
195
205
|
return await this.authorizeForRulesetAsync(
|
|
196
206
|
this.deleteRules,
|
|
197
207
|
viewerContext,
|
|
198
208
|
queryContext,
|
|
199
209
|
entity,
|
|
200
|
-
EntityAuthorizationAction.DELETE
|
|
210
|
+
EntityAuthorizationAction.DELETE,
|
|
211
|
+
metricsAdapter
|
|
201
212
|
);
|
|
202
213
|
}
|
|
203
214
|
|
|
@@ -206,48 +217,95 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
206
217
|
viewerContext: TViewerContext,
|
|
207
218
|
queryContext: EntityQueryContext,
|
|
208
219
|
entity: TEntity,
|
|
209
|
-
action: EntityAuthorizationAction
|
|
220
|
+
action: EntityAuthorizationAction,
|
|
221
|
+
metricsAdapter: IEntityMetricsAdapter
|
|
210
222
|
): Promise<TEntity> {
|
|
211
223
|
const privacyPolicyEvaluator = this.getPrivacyPolicyEvaluator(viewerContext);
|
|
212
224
|
switch (privacyPolicyEvaluator.mode) {
|
|
213
225
|
case EntityPrivacyPolicyEvaluationMode.ENFORCE:
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
226
|
+
try {
|
|
227
|
+
const result = await this.authorizeForRulesetInnerAsync(
|
|
228
|
+
ruleset,
|
|
229
|
+
viewerContext,
|
|
230
|
+
queryContext,
|
|
231
|
+
entity,
|
|
232
|
+
action
|
|
233
|
+
);
|
|
234
|
+
metricsAdapter.logAuthorizationEvent({
|
|
235
|
+
entityClassName: entity.constructor.name,
|
|
236
|
+
action,
|
|
237
|
+
evaluationResult: EntityMetricsAuthorizationResult.ALLOW,
|
|
238
|
+
privacyPolicyEvaluationMode: privacyPolicyEvaluator.mode,
|
|
239
|
+
});
|
|
240
|
+
return result;
|
|
241
|
+
} catch (e) {
|
|
242
|
+
if (!(e instanceof EntityNotAuthorizedError)) {
|
|
243
|
+
throw e;
|
|
244
|
+
}
|
|
245
|
+
metricsAdapter.logAuthorizationEvent({
|
|
246
|
+
entityClassName: entity.constructor.name,
|
|
247
|
+
action,
|
|
248
|
+
evaluationResult: EntityMetricsAuthorizationResult.DENY,
|
|
249
|
+
privacyPolicyEvaluationMode: privacyPolicyEvaluator.mode,
|
|
250
|
+
});
|
|
251
|
+
throw e;
|
|
252
|
+
}
|
|
221
253
|
case EntityPrivacyPolicyEvaluationMode.ENFORCE_AND_LOG:
|
|
222
254
|
try {
|
|
223
|
-
|
|
255
|
+
const result = await this.authorizeForRulesetInnerAsync(
|
|
224
256
|
ruleset,
|
|
225
257
|
viewerContext,
|
|
226
258
|
queryContext,
|
|
227
259
|
entity,
|
|
228
260
|
action
|
|
229
261
|
);
|
|
262
|
+
metricsAdapter.logAuthorizationEvent({
|
|
263
|
+
entityClassName: entity.constructor.name,
|
|
264
|
+
action,
|
|
265
|
+
evaluationResult: EntityMetricsAuthorizationResult.ALLOW,
|
|
266
|
+
privacyPolicyEvaluationMode: privacyPolicyEvaluator.mode,
|
|
267
|
+
});
|
|
268
|
+
return result;
|
|
230
269
|
} catch (e) {
|
|
231
270
|
if (!(e instanceof EntityNotAuthorizedError)) {
|
|
232
271
|
throw e;
|
|
233
272
|
}
|
|
234
273
|
privacyPolicyEvaluator.denyHandler(e);
|
|
274
|
+
metricsAdapter.logAuthorizationEvent({
|
|
275
|
+
entityClassName: entity.constructor.name,
|
|
276
|
+
action,
|
|
277
|
+
evaluationResult: EntityMetricsAuthorizationResult.DENY,
|
|
278
|
+
privacyPolicyEvaluationMode: privacyPolicyEvaluator.mode,
|
|
279
|
+
});
|
|
235
280
|
throw e;
|
|
236
281
|
}
|
|
237
282
|
case EntityPrivacyPolicyEvaluationMode.DRY_RUN:
|
|
238
283
|
try {
|
|
239
|
-
|
|
284
|
+
const result = await this.authorizeForRulesetInnerAsync(
|
|
240
285
|
ruleset,
|
|
241
286
|
viewerContext,
|
|
242
287
|
queryContext,
|
|
243
288
|
entity,
|
|
244
289
|
action
|
|
245
290
|
);
|
|
291
|
+
metricsAdapter.logAuthorizationEvent({
|
|
292
|
+
entityClassName: entity.constructor.name,
|
|
293
|
+
action,
|
|
294
|
+
evaluationResult: EntityMetricsAuthorizationResult.ALLOW,
|
|
295
|
+
privacyPolicyEvaluationMode: privacyPolicyEvaluator.mode,
|
|
296
|
+
});
|
|
297
|
+
return result;
|
|
246
298
|
} catch (e) {
|
|
247
299
|
if (!(e instanceof EntityNotAuthorizedError)) {
|
|
248
300
|
throw e;
|
|
249
301
|
}
|
|
250
302
|
privacyPolicyEvaluator.denyHandler(e);
|
|
303
|
+
metricsAdapter.logAuthorizationEvent({
|
|
304
|
+
entityClassName: entity.constructor.name,
|
|
305
|
+
action,
|
|
306
|
+
evaluationResult: EntityMetricsAuthorizationResult.DENY,
|
|
307
|
+
privacyPolicyEvaluationMode: privacyPolicyEvaluator.mode,
|
|
308
|
+
});
|
|
251
309
|
return entity;
|
|
252
310
|
}
|
|
253
311
|
}
|
|
@@ -261,7 +319,7 @@ export default abstract class EntityPrivacyPolicy<
|
|
|
261
319
|
action: EntityAuthorizationAction
|
|
262
320
|
): Promise<TEntity> {
|
|
263
321
|
for (let i = 0; i < ruleset.length; i++) {
|
|
264
|
-
const rule = ruleset[i]
|
|
322
|
+
const rule = ruleset[i]!;
|
|
265
323
|
const ruleEvaluationResult = await rule.evaluateAsync(viewerContext, queryContext, entity);
|
|
266
324
|
switch (ruleEvaluationResult) {
|
|
267
325
|
case RuleEvaluationResult.DENY:
|
|
@@ -43,13 +43,33 @@ export class EntityNonTransactionalQueryContext extends EntityQueryContext {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export class EntityTransactionalQueryContext extends EntityQueryContext {
|
|
46
|
+
private readonly postCommitInvalidationCallbacks: PostCommitCallback[] = [];
|
|
46
47
|
private readonly postCommitCallbacks: PostCommitCallback[] = [];
|
|
47
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Schedule a post-commit cache invalidation callback. These are run before normal
|
|
51
|
+
* post-commit callbacks in order to have cache consistency in normal post-commit callbacks.
|
|
52
|
+
*
|
|
53
|
+
* @param callback - callback to schedule
|
|
54
|
+
*/
|
|
55
|
+
public appendPostCommitInvalidationCallback(callback: PostCommitCallback): void {
|
|
56
|
+
this.postCommitInvalidationCallbacks.push(callback);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Schedule a post-commit callback. These will be run after the transaction has
|
|
61
|
+
* been committed.
|
|
62
|
+
* @param callback - callback to schedule
|
|
63
|
+
*/
|
|
48
64
|
public appendPostCommitCallback(callback: PostCommitCallback): void {
|
|
49
65
|
this.postCommitCallbacks.push(callback);
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
public async runPostCommitCallbacksAsync(): Promise<void> {
|
|
69
|
+
const invalidationCallbacks = [...this.postCommitInvalidationCallbacks];
|
|
70
|
+
this.postCommitInvalidationCallbacks.length = 0;
|
|
71
|
+
await Promise.all(invalidationCallbacks.map((callback) => callback()));
|
|
72
|
+
|
|
53
73
|
const callbacks = [...this.postCommitCallbacks];
|
|
54
74
|
this.postCommitCallbacks.length = 0;
|
|
55
75
|
await Promise.all(callbacks.map((callback) => callback()));
|
package/src/ReadonlyEntity.ts
CHANGED
|
@@ -37,8 +37,9 @@ export default abstract class ReadonlyEntity<
|
|
|
37
37
|
private readonly viewerContext: TViewerContext,
|
|
38
38
|
private readonly databaseFields: Readonly<TFields>
|
|
39
39
|
) {
|
|
40
|
-
const companionDefinition = (
|
|
41
|
-
.constructor as any
|
|
40
|
+
const companionDefinition = (
|
|
41
|
+
this.constructor as any
|
|
42
|
+
).getCompanionDefinition() as EntityCompanionDefinition<
|
|
42
43
|
TFields,
|
|
43
44
|
TID,
|
|
44
45
|
TViewerContext,
|
|
@@ -5,6 +5,7 @@ import ReadonlyEntity from './ReadonlyEntity';
|
|
|
5
5
|
import ViewerContext from './ViewerContext';
|
|
6
6
|
import ViewerScopedEntityLoaderFactory from './ViewerScopedEntityLoaderFactory';
|
|
7
7
|
import ViewerScopedEntityMutatorFactory from './ViewerScopedEntityMutatorFactory';
|
|
8
|
+
import IEntityMetricsAdapter from './metrics/IEntityMetricsAdapter';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Provides a simpler API for loading and mutating entities by injecting the {@link ViewerContext}
|
|
@@ -76,4 +77,11 @@ export default class ViewerScopedEntityCompanion<
|
|
|
76
77
|
getQueryContextProvider(): EntityQueryContextProvider {
|
|
77
78
|
return this.entityCompanion.getQueryContextProvider();
|
|
78
79
|
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get the {@link IEntityMetricsAdapter} for this companion.
|
|
83
|
+
*/
|
|
84
|
+
getMetricsAdapter(): IEntityMetricsAdapter {
|
|
85
|
+
return this.entityCompanion.getMetricsAdapter();
|
|
86
|
+
}
|
|
79
87
|
}
|