@expo/entity 0.25.2 → 0.26.1
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/ComposedEntityCacheAdapter.d.ts +4 -2
- package/build/ComposedEntityCacheAdapter.js +39 -3
- package/build/ComposedEntityCacheAdapter.js.map +1 -1
- package/build/ComposedSecondaryEntityCache.d.ts +3 -2
- package/build/ComposedSecondaryEntityCache.js +3 -2
- package/build/ComposedSecondaryEntityCache.js.map +1 -1
- package/build/Entity.js +4 -4
- package/build/Entity.js.map +1 -1
- package/build/EntityAssociationLoader.d.ts +5 -0
- package/build/EntityAssociationLoader.js +5 -0
- package/build/EntityAssociationLoader.js.map +1 -1
- package/build/EntityFieldDefinition.d.ts +16 -8
- package/build/EntityFieldDefinition.js +12 -5
- package/build/EntityFieldDefinition.js.map +1 -1
- package/build/EntityLoader.js +2 -2
- package/build/EntityLoader.js.map +1 -1
- package/build/EntityMutationInfo.d.ts +2 -0
- package/build/EntityMutator.d.ts +6 -8
- package/build/EntityMutator.js +58 -46
- package/build/EntityMutator.js.map +1 -1
- package/build/EntityMutatorFactory.d.ts +4 -4
- package/build/EntityMutatorFactory.js +6 -6
- package/build/EntityMutatorFactory.js.map +1 -1
- package/build/EntityPrivacyPolicy.d.ts +13 -0
- package/build/EntityPrivacyPolicy.js +13 -0
- package/build/EntityPrivacyPolicy.js.map +1 -1
- package/build/EntityQueryContext.d.ts +11 -0
- package/build/EntityQueryContext.js +11 -0
- package/build/EntityQueryContext.js.map +1 -1
- package/build/ViewerScopedEntityMutatorFactory.d.ts +4 -4
- package/build/ViewerScopedEntityMutatorFactory.js +6 -6
- package/build/ViewerScopedEntityMutatorFactory.js.map +1 -1
- package/build/__tests__/ComposedCacheAdapter-test.js +37 -4
- package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -1
- package/build/__tests__/EntityCommonUseCases-test.js +5 -1
- package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
- package/build/__tests__/EntityCompanion-test.js +5 -1
- package/build/__tests__/EntityCompanion-test.js.map +1 -1
- package/build/__tests__/EntityCompanionProvider-test.js +5 -1
- package/build/__tests__/EntityCompanionProvider-test.js.map +1 -1
- package/build/__tests__/EntityEdges-test.js +199 -33
- package/build/__tests__/EntityEdges-test.js.map +1 -1
- package/build/__tests__/EntityLoader-test.js +5 -1
- package/build/__tests__/EntityLoader-test.js.map +1 -1
- package/build/__tests__/EntityMutator-test.js +38 -53
- package/build/__tests__/EntityMutator-test.js.map +1 -1
- package/build/__tests__/EntityPrivacyPolicy-test.js +5 -1
- package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
- package/build/__tests__/EntitySelfReferentialEdges-test.js +2 -2
- package/build/__tests__/EntitySelfReferentialEdges-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js +5 -1
- package/build/__tests__/ViewerScopedEntityCompanionProvider-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js +2 -3
- package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js.map +1 -1
- package/build/errors/EntityCacheAdapterError.js +5 -1
- package/build/errors/EntityCacheAdapterError.js.map +1 -1
- package/build/errors/EntityDatabaseAdapterError.js +5 -1
- package/build/errors/EntityDatabaseAdapterError.js.map +1 -1
- package/build/errors/EntityInvalidFieldValueError.js +6 -2
- package/build/errors/EntityInvalidFieldValueError.js.map +1 -1
- package/build/errors/EntityNotAuthorizedError.js +5 -1
- package/build/errors/EntityNotAuthorizedError.js.map +1 -1
- package/build/errors/EntityNotFoundError.js +6 -2
- package/build/errors/EntityNotFoundError.js.map +1 -1
- package/build/index.js +5 -1
- package/build/index.js.map +1 -1
- package/build/internal/EntityDataManager.js +7 -4
- package/build/internal/EntityDataManager.js.map +1 -1
- package/build/internal/EntityFieldTransformationUtils.js +1 -1
- package/build/internal/EntityFieldTransformationUtils.js.map +1 -1
- package/build/internal/ReadThroughEntityCache.js +1 -1
- package/build/internal/ReadThroughEntityCache.js.map +1 -1
- package/build/internal/__tests__/EntityDataManager-test.js +12 -7
- package/build/internal/__tests__/EntityDataManager-test.js.map +1 -1
- package/build/internal/__tests__/ReadThroughEntityCache-test.js +5 -1
- package/build/internal/__tests__/ReadThroughEntityCache-test.js.map +1 -1
- package/build/metrics/IEntityMetricsAdapter.d.ts +62 -17
- package/build/metrics/IEntityMetricsAdapter.js +17 -1
- package/build/metrics/IEntityMetricsAdapter.js.map +1 -1
- package/build/metrics/NoOpEntityMetricsAdapter.d.ts +1 -3
- package/build/metrics/NoOpEntityMetricsAdapter.js +1 -3
- package/build/metrics/NoOpEntityMetricsAdapter.js.map +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js +5 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js +5 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js +5 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
- package/build/utils/testing/StubDatabaseAdapter.js +6 -2
- package/build/utils/testing/StubDatabaseAdapter.js.map +1 -1
- package/package.json +1 -1
- package/src/ComposedEntityCacheAdapter.ts +44 -3
- package/src/ComposedSecondaryEntityCache.ts +3 -2
- package/src/Entity.ts +4 -4
- package/src/EntityAssociationLoader.ts +5 -0
- package/src/EntityFieldDefinition.ts +15 -6
- package/src/EntityLoader.ts +4 -2
- package/src/EntityMutationInfo.ts +2 -0
- package/src/EntityMutator.ts +98 -67
- package/src/EntityMutatorFactory.ts +4 -10
- package/src/EntityPrivacyPolicy.ts +15 -0
- package/src/EntityQueryContext.ts +11 -0
- package/src/ViewerScopedEntityMutatorFactory.ts +7 -22
- package/src/__tests__/ComposedCacheAdapter-test.ts +43 -4
- package/src/__tests__/EntityEdges-test.ts +287 -32
- package/src/__tests__/EntityMutator-test.ts +33 -54
- package/src/__tests__/EntitySelfReferentialEdges-test.ts +2 -2
- package/src/__tests__/ViewerScopedEntityMutatorFactory-test.ts +2 -6
- package/src/errors/EntityInvalidFieldValueError.ts +1 -1
- package/src/errors/EntityNotFoundError.ts +1 -1
- package/src/internal/EntityDataManager.ts +13 -5
- package/src/internal/EntityFieldTransformationUtils.ts +1 -1
- package/src/internal/ReadThroughEntityCache.ts +3 -1
- package/src/internal/__tests__/EntityDataManager-test.ts +11 -8
- package/src/metrics/IEntityMetricsAdapter.ts +72 -19
- package/src/metrics/NoOpEntityMetricsAdapter.ts +1 -5
- package/src/utils/testing/StubDatabaseAdapter.ts +4 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import invariant from 'invariant';
|
|
2
|
+
|
|
1
3
|
import Entity from '../Entity';
|
|
2
4
|
import { EntityCompanionDefinition } from '../EntityCompanionProvider';
|
|
3
5
|
import EntityConfiguration from '../EntityConfiguration';
|
|
@@ -33,9 +35,13 @@ interface GrandChildFields {
|
|
|
33
35
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
34
36
|
const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) => {
|
|
35
37
|
const triggerExecutionCounts = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
ParentEntityDeletion: 0,
|
|
39
|
+
ChildEntityDeletion: 0,
|
|
40
|
+
GrandChildEntityDeletion: 0,
|
|
41
|
+
|
|
42
|
+
ParentEntityUpdate: 0,
|
|
43
|
+
ChildEntityUpdate: 0,
|
|
44
|
+
GrandChildEntityUpdate: 0,
|
|
39
45
|
};
|
|
40
46
|
|
|
41
47
|
const privacyPolicyEvaluationRecords = {
|
|
@@ -107,7 +113,7 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
107
113
|
];
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
class
|
|
116
|
+
class ParentCheckInfoDeletionTrigger extends EntityMutationTrigger<
|
|
111
117
|
ParentFields,
|
|
112
118
|
string,
|
|
113
119
|
TestViewerContext,
|
|
@@ -119,19 +125,37 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
119
125
|
_entity: ParentEntity,
|
|
120
126
|
mutationInfo: EntityTriggerMutationInfo<ParentFields, string, TestViewerContext, ParentEntity>
|
|
121
127
|
): Promise<void> {
|
|
122
|
-
|
|
123
|
-
|
|
128
|
+
invariant(mutationInfo.type === EntityMutationType.DELETE, 'invalid EntityMutationType');
|
|
129
|
+
if (mutationInfo.cascadingDeleteCause !== null) {
|
|
130
|
+
throw new Error('Parent entity should not have casade delete cause');
|
|
124
131
|
}
|
|
125
132
|
|
|
133
|
+
triggerExecutionCounts.ParentEntityDeletion++;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
class ParentCheckInfoUpdateTrigger extends EntityMutationTrigger<
|
|
138
|
+
ParentFields,
|
|
139
|
+
string,
|
|
140
|
+
TestViewerContext,
|
|
141
|
+
ParentEntity
|
|
142
|
+
> {
|
|
143
|
+
async executeAsync(
|
|
144
|
+
_viewerContext: TestViewerContext,
|
|
145
|
+
_queryContext: EntityTransactionalQueryContext,
|
|
146
|
+
_entity: ParentEntity,
|
|
147
|
+
mutationInfo: EntityTriggerMutationInfo<ParentFields, string, TestViewerContext, ParentEntity>
|
|
148
|
+
): Promise<void> {
|
|
149
|
+
invariant(mutationInfo.type === EntityMutationType.UPDATE, 'invalid EntityMutationType');
|
|
126
150
|
if (mutationInfo.cascadingDeleteCause !== null) {
|
|
127
151
|
throw new Error('Parent entity should not have casade delete cause');
|
|
128
152
|
}
|
|
129
153
|
|
|
130
|
-
triggerExecutionCounts.
|
|
154
|
+
triggerExecutionCounts.ParentEntityUpdate++;
|
|
131
155
|
}
|
|
132
156
|
}
|
|
133
157
|
|
|
134
|
-
class
|
|
158
|
+
class ChildCheckInfoDeletionTrigger extends EntityMutationTrigger<
|
|
135
159
|
ChildFields,
|
|
136
160
|
string,
|
|
137
161
|
TestViewerContext,
|
|
@@ -143,10 +167,39 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
143
167
|
_entity: ChildEntity,
|
|
144
168
|
mutationInfo: EntityTriggerMutationInfo<ChildFields, string, TestViewerContext, ChildEntity>
|
|
145
169
|
): Promise<void> {
|
|
146
|
-
|
|
147
|
-
|
|
170
|
+
invariant(mutationInfo.type === EntityMutationType.DELETE, 'invalid EntityMutationType');
|
|
171
|
+
if (mutationInfo.cascadingDeleteCause === null) {
|
|
172
|
+
throw new Error('Child entity should have casade delete cause');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const cascadingDeleteCauseEntity = mutationInfo.cascadingDeleteCause.entity;
|
|
176
|
+
if (!(cascadingDeleteCauseEntity instanceof ParentEntity)) {
|
|
177
|
+
throw new Error('Child entity should have casade delete cause entity of type ParentEntity');
|
|
148
178
|
}
|
|
149
179
|
|
|
180
|
+
const secondLevelCascadingDeleteCause =
|
|
181
|
+
mutationInfo.cascadingDeleteCause.cascadingDeleteCause;
|
|
182
|
+
if (secondLevelCascadingDeleteCause) {
|
|
183
|
+
throw new Error('Child entity should not have two-level casade delete cause');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
triggerExecutionCounts.ChildEntityDeletion++;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
class ChildCheckInfoUpdateTrigger extends EntityMutationTrigger<
|
|
191
|
+
ChildFields,
|
|
192
|
+
string,
|
|
193
|
+
TestViewerContext,
|
|
194
|
+
ChildEntity
|
|
195
|
+
> {
|
|
196
|
+
async executeAsync(
|
|
197
|
+
_viewerContext: TestViewerContext,
|
|
198
|
+
_queryContext: EntityTransactionalQueryContext,
|
|
199
|
+
_entity: ChildEntity,
|
|
200
|
+
mutationInfo: EntityTriggerMutationInfo<ChildFields, string, TestViewerContext, ChildEntity>
|
|
201
|
+
): Promise<void> {
|
|
202
|
+
invariant(mutationInfo.type === EntityMutationType.UPDATE, 'invalid EntityMutationType');
|
|
150
203
|
if (mutationInfo.cascadingDeleteCause === null) {
|
|
151
204
|
throw new Error('Child entity should have casade delete cause');
|
|
152
205
|
}
|
|
@@ -162,11 +215,11 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
162
215
|
throw new Error('Child entity should not have two-level casade delete cause');
|
|
163
216
|
}
|
|
164
217
|
|
|
165
|
-
triggerExecutionCounts.
|
|
218
|
+
triggerExecutionCounts.ChildEntityUpdate++;
|
|
166
219
|
}
|
|
167
220
|
}
|
|
168
221
|
|
|
169
|
-
class
|
|
222
|
+
class GrandChildCheckInfoDeletionTrigger extends EntityMutationTrigger<
|
|
170
223
|
GrandChildFields,
|
|
171
224
|
string,
|
|
172
225
|
TestViewerContext,
|
|
@@ -183,10 +236,58 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
183
236
|
GrandChildEntity
|
|
184
237
|
>
|
|
185
238
|
): Promise<void> {
|
|
186
|
-
|
|
187
|
-
|
|
239
|
+
invariant(mutationInfo.type === EntityMutationType.DELETE, 'invalid EntityMutationType');
|
|
240
|
+
if (mutationInfo.cascadingDeleteCause === null) {
|
|
241
|
+
throw new Error('GrandChild entity should have cascade delete cause');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const cascadingDeleteCauseEntity = mutationInfo.cascadingDeleteCause.entity;
|
|
245
|
+
if (!(cascadingDeleteCauseEntity instanceof ChildEntity)) {
|
|
246
|
+
throw new Error(
|
|
247
|
+
'GrandChild entity should have cascade delete cause entity of type ChildEntity'
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const secondLevelCascadingDeleteCause =
|
|
252
|
+
mutationInfo.cascadingDeleteCause.cascadingDeleteCause;
|
|
253
|
+
if (!secondLevelCascadingDeleteCause) {
|
|
254
|
+
throw new Error('GrandChild entity should have two-level casade delete cause');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const secondLevelCascadingDeleteCauseEntity = secondLevelCascadingDeleteCause.entity;
|
|
258
|
+
if (!(secondLevelCascadingDeleteCauseEntity instanceof ParentEntity)) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
'GrandChild entity should have second level casade delete cause entity of type ParentEntity'
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const thirdLevelCascadingDeleteCause = secondLevelCascadingDeleteCause.cascadingDeleteCause;
|
|
265
|
+
if (thirdLevelCascadingDeleteCause) {
|
|
266
|
+
throw new Error('GrandChild entity should not have three-level casade delete cause');
|
|
188
267
|
}
|
|
189
268
|
|
|
269
|
+
triggerExecutionCounts.GrandChildEntityDeletion++;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
class GrandChildCheckInfoUpdateTrigger extends EntityMutationTrigger<
|
|
274
|
+
GrandChildFields,
|
|
275
|
+
string,
|
|
276
|
+
TestViewerContext,
|
|
277
|
+
GrandChildEntity
|
|
278
|
+
> {
|
|
279
|
+
async executeAsync(
|
|
280
|
+
_viewerContext: TestViewerContext,
|
|
281
|
+
_queryContext: EntityTransactionalQueryContext,
|
|
282
|
+
_entity: GrandChildEntity,
|
|
283
|
+
mutationInfo: EntityTriggerMutationInfo<
|
|
284
|
+
GrandChildFields,
|
|
285
|
+
string,
|
|
286
|
+
TestViewerContext,
|
|
287
|
+
GrandChildEntity
|
|
288
|
+
>
|
|
289
|
+
): Promise<void> {
|
|
290
|
+
invariant(mutationInfo.type === EntityMutationType.UPDATE, 'invalid EntityMutationType');
|
|
190
291
|
if (mutationInfo.cascadingDeleteCause === null) {
|
|
191
292
|
throw new Error('GrandChild entity should have cascade delete cause');
|
|
192
293
|
}
|
|
@@ -216,7 +317,7 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
216
317
|
throw new Error('GrandChild entity should not have three-level casade delete cause');
|
|
217
318
|
}
|
|
218
319
|
|
|
219
|
-
triggerExecutionCounts.
|
|
320
|
+
triggerExecutionCounts.GrandChildEntityUpdate++;
|
|
220
321
|
}
|
|
221
322
|
}
|
|
222
323
|
|
|
@@ -318,8 +419,11 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
318
419
|
entityConfiguration: parentEntityConfiguration,
|
|
319
420
|
privacyPolicyClass: TestEntityPrivacyPolicy,
|
|
320
421
|
mutationTriggers: () => ({
|
|
321
|
-
beforeDelete: [new
|
|
322
|
-
afterDelete: [new
|
|
422
|
+
beforeDelete: [new ParentCheckInfoDeletionTrigger()],
|
|
423
|
+
afterDelete: [new ParentCheckInfoDeletionTrigger()],
|
|
424
|
+
|
|
425
|
+
beforeUpdate: [new ParentCheckInfoUpdateTrigger()],
|
|
426
|
+
afterUpdate: [new ParentCheckInfoUpdateTrigger()],
|
|
323
427
|
}),
|
|
324
428
|
});
|
|
325
429
|
|
|
@@ -328,8 +432,11 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
328
432
|
entityConfiguration: childEntityConfiguration,
|
|
329
433
|
privacyPolicyClass: TestEntityPrivacyPolicy,
|
|
330
434
|
mutationTriggers: () => ({
|
|
331
|
-
beforeDelete: [new
|
|
332
|
-
afterDelete: [new
|
|
435
|
+
beforeDelete: [new ChildCheckInfoDeletionTrigger()],
|
|
436
|
+
afterDelete: [new ChildCheckInfoDeletionTrigger()],
|
|
437
|
+
|
|
438
|
+
beforeUpdate: [new ChildCheckInfoUpdateTrigger()],
|
|
439
|
+
afterUpdate: [new ChildCheckInfoUpdateTrigger()],
|
|
333
440
|
}),
|
|
334
441
|
});
|
|
335
442
|
|
|
@@ -338,8 +445,11 @@ const makeEntityClasses = (edgeDeletionBehavior: EntityEdgeDeletionBehavior) =>
|
|
|
338
445
|
entityConfiguration: grandChildEntityConfiguration,
|
|
339
446
|
privacyPolicyClass: TestEntityPrivacyPolicy,
|
|
340
447
|
mutationTriggers: () => ({
|
|
341
|
-
beforeDelete: [new
|
|
342
|
-
afterDelete: [new
|
|
448
|
+
beforeDelete: [new GrandChildCheckInfoDeletionTrigger()],
|
|
449
|
+
afterDelete: [new GrandChildCheckInfoDeletionTrigger()],
|
|
450
|
+
|
|
451
|
+
beforeUpdate: [new GrandChildCheckInfoUpdateTrigger()],
|
|
452
|
+
afterUpdate: [new GrandChildCheckInfoUpdateTrigger()],
|
|
343
453
|
}),
|
|
344
454
|
});
|
|
345
455
|
|
|
@@ -399,9 +509,13 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
|
|
|
399
509
|
|
|
400
510
|
// two calls for each trigger, one beforeDelete, one afterDelete
|
|
401
511
|
expect(triggerExecutionCounts).toMatchObject({
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
512
|
+
ParentEntityDeletion: 2,
|
|
513
|
+
ChildEntityDeletion: 2,
|
|
514
|
+
GrandChildEntityDeletion: 2,
|
|
515
|
+
|
|
516
|
+
ParentEntityUpdate: 0,
|
|
517
|
+
ChildEntityUpdate: 0,
|
|
518
|
+
GrandChildEntityUpdate: 0,
|
|
405
519
|
});
|
|
406
520
|
|
|
407
521
|
expect(privacyPolicyEvaluationRecords).toMatchObject({
|
|
@@ -518,9 +632,13 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
|
|
|
518
632
|
// two calls for only parent trigger, one beforeDelete, one afterDelete
|
|
519
633
|
// when using set null the descendants aren't deleted
|
|
520
634
|
expect(triggerExecutionCounts).toMatchObject({
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
635
|
+
ParentEntityDeletion: 2,
|
|
636
|
+
ChildEntityDeletion: 0,
|
|
637
|
+
GrandChildEntityDeletion: 0,
|
|
638
|
+
|
|
639
|
+
ParentEntityUpdate: 0,
|
|
640
|
+
ChildEntityUpdate: 2,
|
|
641
|
+
GrandChildEntityUpdate: 0,
|
|
524
642
|
});
|
|
525
643
|
|
|
526
644
|
expect(privacyPolicyEvaluationRecords).toMatchObject({
|
|
@@ -573,7 +691,7 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
|
|
|
573
691
|
});
|
|
574
692
|
});
|
|
575
693
|
|
|
576
|
-
describe('EntityEdgeDeletionBehavior.
|
|
694
|
+
describe('EntityEdgeDeletionBehavior.SET_NULL_INVALIDATE_CACHE_ONLY', () => {
|
|
577
695
|
it('invalidates the cache', async () => {
|
|
578
696
|
const {
|
|
579
697
|
ParentEntity,
|
|
@@ -581,7 +699,140 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
|
|
|
581
699
|
GrandChildEntity,
|
|
582
700
|
triggerExecutionCounts,
|
|
583
701
|
privacyPolicyEvaluationRecords,
|
|
584
|
-
} = makeEntityClasses(EntityEdgeDeletionBehavior.
|
|
702
|
+
} = makeEntityClasses(EntityEdgeDeletionBehavior.SET_NULL_INVALIDATE_CACHE_ONLY);
|
|
703
|
+
|
|
704
|
+
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
705
|
+
const viewerContext = new TestViewerContext(companionProvider);
|
|
706
|
+
|
|
707
|
+
const parent = await ParentEntity.creator(viewerContext).enforceCreateAsync();
|
|
708
|
+
const child = await ChildEntity.creator(viewerContext)
|
|
709
|
+
.setField('parent_id', parent.getID())
|
|
710
|
+
.enforceCreateAsync();
|
|
711
|
+
const grandchild = await GrandChildEntity.creator(viewerContext)
|
|
712
|
+
.setField('parent_id', child.getID())
|
|
713
|
+
.enforceCreateAsync();
|
|
714
|
+
|
|
715
|
+
await expect(
|
|
716
|
+
ParentEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(parent.getID())
|
|
717
|
+
).resolves.not.toBeNull();
|
|
718
|
+
await expect(
|
|
719
|
+
ChildEntity.loader(viewerContext)
|
|
720
|
+
.enforcing()
|
|
721
|
+
.loadByFieldEqualingAsync('parent_id', parent.getID())
|
|
722
|
+
).resolves.not.toBeNull();
|
|
723
|
+
await expect(
|
|
724
|
+
GrandChildEntity.loader(viewerContext)
|
|
725
|
+
.enforcing()
|
|
726
|
+
.loadByFieldEqualingAsync('parent_id', child.getID())
|
|
727
|
+
).resolves.not.toBeNull();
|
|
728
|
+
|
|
729
|
+
const childCacheAdapter = viewerContext.getViewerScopedEntityCompanionForClass(ChildEntity)[
|
|
730
|
+
'entityCompanion'
|
|
731
|
+
]['tableDataCoordinator']['cacheAdapter'] as InMemoryFullCacheStubCacheAdapter<ChildFields>;
|
|
732
|
+
const childCachedBefore = await childCacheAdapter.loadManyAsync('parent_id', [
|
|
733
|
+
parent.getID(),
|
|
734
|
+
]);
|
|
735
|
+
expect(childCachedBefore.get(parent.getID())?.status).toEqual(CacheStatus.HIT);
|
|
736
|
+
|
|
737
|
+
const grandChildCacheAdapter = viewerContext.getViewerScopedEntityCompanionForClass(
|
|
738
|
+
GrandChildEntity
|
|
739
|
+
)['entityCompanion']['tableDataCoordinator'][
|
|
740
|
+
'cacheAdapter'
|
|
741
|
+
] as InMemoryFullCacheStubCacheAdapter<ChildFields>;
|
|
742
|
+
const grandChildCachedBefore = await grandChildCacheAdapter.loadManyAsync('parent_id', [
|
|
743
|
+
child.getID(),
|
|
744
|
+
]);
|
|
745
|
+
expect(grandChildCachedBefore.get(child.getID())?.status).toEqual(CacheStatus.HIT);
|
|
746
|
+
|
|
747
|
+
privacyPolicyEvaluationRecords.shouldRecord = true;
|
|
748
|
+
await ParentEntity.enforceDeleteAsync(parent);
|
|
749
|
+
privacyPolicyEvaluationRecords.shouldRecord = false;
|
|
750
|
+
|
|
751
|
+
const childCachedAfter = await childCacheAdapter.loadManyAsync('parent_id', [parent.getID()]);
|
|
752
|
+
expect(childCachedAfter.get(parent.getID())?.status).toEqual(CacheStatus.MISS);
|
|
753
|
+
|
|
754
|
+
const grandChildCachedAfter = await grandChildCacheAdapter.loadManyAsync('parent_id', [
|
|
755
|
+
child.getID(),
|
|
756
|
+
]);
|
|
757
|
+
expect(grandChildCachedAfter.get(child.getID())?.status).toEqual(CacheStatus.HIT);
|
|
758
|
+
|
|
759
|
+
await expect(
|
|
760
|
+
ParentEntity.loader(viewerContext).enforcing().loadByIDNullableAsync(parent.getID())
|
|
761
|
+
).resolves.toBeNull();
|
|
762
|
+
|
|
763
|
+
const loadedChild = await ChildEntity.loader(viewerContext)
|
|
764
|
+
.enforcing()
|
|
765
|
+
.loadByIDAsync(child.getID());
|
|
766
|
+
expect(loadedChild).not.toBeNull();
|
|
767
|
+
|
|
768
|
+
const loadedGrandchild = await GrandChildEntity.loader(viewerContext)
|
|
769
|
+
.enforcing()
|
|
770
|
+
.loadByIDAsync(grandchild.getID());
|
|
771
|
+
expect(loadedGrandchild.getField('parent_id')).toEqual(loadedChild.getID());
|
|
772
|
+
|
|
773
|
+
// two calls for only parent trigger, one beforeDelete, one afterDelete
|
|
774
|
+
// when using set null the descendants aren't deleted
|
|
775
|
+
expect(triggerExecutionCounts).toMatchObject({
|
|
776
|
+
ParentEntityDeletion: 2,
|
|
777
|
+
ChildEntityDeletion: 0,
|
|
778
|
+
GrandChildEntityDeletion: 0,
|
|
779
|
+
|
|
780
|
+
ParentEntityUpdate: 0,
|
|
781
|
+
ChildEntityUpdate: 2,
|
|
782
|
+
GrandChildEntityUpdate: 0,
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
expect(privacyPolicyEvaluationRecords).toMatchObject({
|
|
786
|
+
ParentEntity: {
|
|
787
|
+
[EntityAuthorizationAction.CREATE]: [],
|
|
788
|
+
[EntityAuthorizationAction.READ]: [],
|
|
789
|
+
[EntityAuthorizationAction.UPDATE]: [],
|
|
790
|
+
// one DELETE auth action for parent (since it's being deleted)
|
|
791
|
+
[EntityAuthorizationAction.DELETE]: [{ cascadingDeleteCause: null }],
|
|
792
|
+
},
|
|
793
|
+
ChildEntity: {
|
|
794
|
+
[EntityAuthorizationAction.CREATE]: [],
|
|
795
|
+
|
|
796
|
+
// one READ auth action for child in order to update via cascade
|
|
797
|
+
// no other entities are read since it is not cascaded past first entity
|
|
798
|
+
[EntityAuthorizationAction.READ]: [
|
|
799
|
+
{
|
|
800
|
+
cascadingDeleteCause: {
|
|
801
|
+
entity: expect.any(ParentEntity),
|
|
802
|
+
cascadingDeleteCause: null,
|
|
803
|
+
},
|
|
804
|
+
},
|
|
805
|
+
],
|
|
806
|
+
// one UPDATE to set null
|
|
807
|
+
[EntityAuthorizationAction.UPDATE]: [
|
|
808
|
+
{
|
|
809
|
+
cascadingDeleteCause: {
|
|
810
|
+
entity: expect.any(ParentEntity),
|
|
811
|
+
cascadingDeleteCause: null,
|
|
812
|
+
},
|
|
813
|
+
},
|
|
814
|
+
],
|
|
815
|
+
[EntityAuthorizationAction.DELETE]: [],
|
|
816
|
+
},
|
|
817
|
+
GrandChildEntity: {
|
|
818
|
+
[EntityAuthorizationAction.CREATE]: [],
|
|
819
|
+
[EntityAuthorizationAction.READ]: [],
|
|
820
|
+
[EntityAuthorizationAction.UPDATE]: [],
|
|
821
|
+
[EntityAuthorizationAction.DELETE]: [],
|
|
822
|
+
},
|
|
823
|
+
});
|
|
824
|
+
});
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
describe('EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY', () => {
|
|
828
|
+
it('invalidates the cache', async () => {
|
|
829
|
+
const {
|
|
830
|
+
ParentEntity,
|
|
831
|
+
ChildEntity,
|
|
832
|
+
GrandChildEntity,
|
|
833
|
+
triggerExecutionCounts,
|
|
834
|
+
privacyPolicyEvaluationRecords,
|
|
835
|
+
} = makeEntityClasses(EntityEdgeDeletionBehavior.CASCADE_DELETE_INVALIDATE_CACHE_ONLY);
|
|
585
836
|
|
|
586
837
|
const companionProvider = createUnitTestEntityCompanionProvider();
|
|
587
838
|
const viewerContext = new TestViewerContext(companionProvider);
|
|
@@ -650,9 +901,13 @@ describe('EntityMutator.processEntityDeletionForInboundEdgesAsync', () => {
|
|
|
650
901
|
|
|
651
902
|
// two calls for each trigger, one beforeDelete, one afterDelete
|
|
652
903
|
expect(triggerExecutionCounts).toMatchObject({
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
904
|
+
ParentEntityDeletion: 2,
|
|
905
|
+
ChildEntityDeletion: 2,
|
|
906
|
+
GrandChildEntityDeletion: 2,
|
|
907
|
+
|
|
908
|
+
ParentEntityUpdate: 0,
|
|
909
|
+
ChildEntityUpdate: 0,
|
|
910
|
+
GrandChildEntityUpdate: 0,
|
|
656
911
|
});
|
|
657
912
|
|
|
658
913
|
expect(privacyPolicyEvaluationRecords).toMatchObject({
|