@expo/entity 0.24.0 → 0.25.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/ComposedEntityCacheAdapter.d.ts +19 -0
- package/build/ComposedEntityCacheAdapter.js +66 -0
- package/build/ComposedEntityCacheAdapter.js.map +1 -0
- package/build/ComposedSecondaryEntityCache.d.ts +15 -0
- package/build/ComposedSecondaryEntityCache.js +37 -0
- package/build/ComposedSecondaryEntityCache.js.map +1 -0
- package/build/Entity.js +6 -6
- package/build/Entity.js.map +1 -1
- package/build/EntityAssociationLoader.js +4 -4
- package/build/EntityAssociationLoader.js.map +1 -1
- package/build/EntityLoader.d.ts +3 -2
- package/build/EntityLoader.js +5 -4
- package/build/EntityLoader.js.map +1 -1
- package/build/EntityLoaderFactory.d.ts +2 -2
- package/build/EntityLoaderFactory.js +2 -2
- package/build/EntityLoaderFactory.js.map +1 -1
- package/build/EntityMutationInfo.d.ts +12 -3
- package/build/EntityMutator.d.ts +5 -4
- package/build/EntityMutator.js +31 -24
- 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 +15 -4
- package/build/EntityPrivacyPolicy.js +14 -14
- package/build/EntityPrivacyPolicy.js.map +1 -1
- package/build/IEntityGenericCacher.d.ts +2 -2
- package/build/ReadonlyEntity.js +1 -1
- package/build/ReadonlyEntity.js.map +1 -1
- package/build/ViewerScopedEntityLoaderFactory.d.ts +2 -2
- package/build/ViewerScopedEntityLoaderFactory.js +2 -2
- package/build/ViewerScopedEntityLoaderFactory.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.d.ts +1 -0
- package/build/__tests__/ComposedCacheAdapter-test.js +198 -0
- package/build/__tests__/ComposedCacheAdapter-test.js.map +1 -0
- package/build/__tests__/ComposedSecondaryEntityCache-test.d.ts +1 -0
- package/build/__tests__/ComposedSecondaryEntityCache-test.js +65 -0
- package/build/__tests__/ComposedSecondaryEntityCache-test.js.map +1 -0
- package/build/__tests__/EntityCommonUseCases-test.js +1 -1
- package/build/__tests__/EntityCommonUseCases-test.js.map +1 -1
- package/build/__tests__/EntityEdges-test.js +260 -37
- package/build/__tests__/EntityEdges-test.js.map +1 -1
- package/build/__tests__/EntityLoader-constructor-test.js +2 -1
- package/build/__tests__/EntityLoader-constructor-test.js.map +1 -1
- package/build/__tests__/EntityLoader-test.js +19 -11
- package/build/__tests__/EntityLoader-test.js.map +1 -1
- package/build/__tests__/EntityMutator-test.js +96 -43
- package/build/__tests__/EntityMutator-test.js.map +1 -1
- package/build/__tests__/EntityPrivacyPolicy-test.js +23 -12
- package/build/__tests__/EntityPrivacyPolicy-test.js.map +1 -1
- package/build/__tests__/EntitySecondaryCacheLoader-test.js +1 -1
- package/build/__tests__/EntitySecondaryCacheLoader-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js +3 -2
- package/build/__tests__/ViewerScopedEntityLoaderFactory-test.js.map +1 -1
- package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js +3 -2
- package/build/__tests__/ViewerScopedEntityMutatorFactory-test.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.js +5 -1
- package/build/index.js.map +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.d.ts +2 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js +1 -1
- package/build/rules/AlwaysAllowPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.d.ts +2 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js +1 -1
- package/build/rules/AlwaysDenyPrivacyPolicyRule.js.map +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.d.ts +2 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js +1 -1
- package/build/rules/AlwaysSkipPrivacyPolicyRule.js.map +1 -1
- package/build/rules/PrivacyPolicyRule.d.ts +2 -1
- package/build/rules/PrivacyPolicyRule.js.map +1 -1
- package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js +1 -0
- package/build/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.js.map +1 -1
- package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js +1 -0
- package/build/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.js.map +1 -1
- package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js +1 -0
- package/build/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.js.map +1 -1
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.d.ts +2 -0
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js +6 -6
- package/build/utils/testing/PrivacyPolicyRuleTestUtils.js.map +1 -1
- package/package.json +1 -1
- package/src/ComposedEntityCacheAdapter.ts +86 -0
- package/src/ComposedSecondaryEntityCache.ts +63 -0
- package/src/Entity.ts +6 -4
- package/src/EntityAssociationLoader.ts +4 -4
- package/src/EntityLoader.ts +5 -1
- package/src/EntityLoaderFactory.ts +4 -2
- package/src/EntityMutationInfo.ts +13 -3
- package/src/EntityMutator.ts +44 -21
- package/src/EntityMutatorFactory.ts +10 -4
- package/src/EntityPrivacyPolicy.ts +31 -1
- package/src/IEntityGenericCacher.ts +2 -2
- package/src/ReadonlyEntity.ts +1 -1
- package/src/ViewerScopedEntityLoaderFactory.ts +8 -3
- package/src/ViewerScopedEntityMutatorFactory.ts +22 -7
- package/src/__tests__/ComposedCacheAdapter-test.ts +280 -0
- package/src/__tests__/ComposedSecondaryEntityCache-test.ts +101 -0
- package/src/__tests__/EntityCommonUseCases-test.ts +2 -1
- package/src/__tests__/EntityEdges-test.ts +286 -45
- package/src/__tests__/EntityLoader-constructor-test.ts +3 -1
- package/src/__tests__/EntityLoader-test.ts +26 -1
- package/src/__tests__/EntityMutator-test.ts +99 -37
- package/src/__tests__/EntityPrivacyPolicy-test.ts +66 -7
- package/src/__tests__/EntitySecondaryCacheLoader-test.ts +1 -0
- package/src/__tests__/ViewerScopedEntityLoaderFactory-test.ts +4 -2
- package/src/__tests__/ViewerScopedEntityMutatorFactory-test.ts +6 -2
- package/src/index.ts +2 -0
- package/src/rules/AlwaysAllowPrivacyPolicyRule.ts +2 -0
- package/src/rules/AlwaysDenyPrivacyPolicyRule.ts +2 -0
- package/src/rules/AlwaysSkipPrivacyPolicyRule.ts +2 -0
- package/src/rules/PrivacyPolicyRule.ts +2 -0
- package/src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts +2 -0
- package/src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts +2 -0
- package/src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts +2 -0
- package/src/utils/testing/PrivacyPolicyRuleTestUtils.ts +14 -6
|
@@ -13,6 +13,7 @@ const AlwaysDenyPrivacyPolicyRule_1 = __importDefault(require("../AlwaysDenyPriv
|
|
|
13
13
|
{
|
|
14
14
|
viewerContext: (0, ts_mockito_1.instance)((0, ts_mockito_1.mock)(ViewerContext_1.default)),
|
|
15
15
|
queryContext: (0, ts_mockito_1.instance)((0, ts_mockito_1.mock)(EntityQueryContext_1.EntityQueryContext)),
|
|
16
|
+
evaluationContext: (0, ts_mockito_1.instance)((0, ts_mockito_1.mock)()),
|
|
16
17
|
entity: (0, ts_mockito_1.anything)(),
|
|
17
18
|
},
|
|
18
19
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlwaysDenyPrivacyPolicyRule-test.js","sourceRoot":"","sources":["../../../src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts"],"names":[],"mappings":";;;;;AAAA,2CAAsD;
|
|
1
|
+
{"version":3,"file":"AlwaysDenyPrivacyPolicyRule-test.js","sourceRoot":"","sources":["../../../src/rules/__tests__/AlwaysDenyPrivacyPolicyRule-test.ts"],"names":[],"mappings":";;;;;AAAA,2CAAsD;AAGtD,iEAA8D;AAC9D,wEAAgD;AAChD,+FAA2F;AAC3F,iGAAyE;AAEzE,IAAA,sDAAyB,EAAC,IAAI,qCAA2B,EAAE,EAAE;IAC3D,SAAS,EAAE;QACT;YACE,aAAa,EAAE,IAAA,qBAAQ,EAAC,IAAA,iBAAI,EAAC,uBAAa,CAAC,CAAC;YAC5C,YAAY,EAAE,IAAA,qBAAQ,EAAC,IAAA,iBAAI,EAAC,uCAAkB,CAAC,CAAC;YAChD,iBAAiB,EAAE,IAAA,qBAAQ,EAAC,IAAA,iBAAI,GAAwC,CAAC;YACzE,MAAM,EAAE,IAAA,qBAAQ,GAAE;SACnB;KACF;CACF,CAAC,CAAC"}
|
|
@@ -13,6 +13,7 @@ const AlwaysSkipPrivacyPolicyRule_1 = __importDefault(require("../AlwaysSkipPriv
|
|
|
13
13
|
{
|
|
14
14
|
viewerContext: (0, ts_mockito_1.instance)((0, ts_mockito_1.mock)(ViewerContext_1.default)),
|
|
15
15
|
queryContext: (0, ts_mockito_1.instance)((0, ts_mockito_1.mock)(EntityQueryContext_1.EntityQueryContext)),
|
|
16
|
+
evaluationContext: (0, ts_mockito_1.instance)((0, ts_mockito_1.mock)()),
|
|
16
17
|
entity: (0, ts_mockito_1.anything)(),
|
|
17
18
|
},
|
|
18
19
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlwaysSkipPrivacyPolicyRule-test.js","sourceRoot":"","sources":["../../../src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts"],"names":[],"mappings":";;;;;AAAA,2CAAsD;
|
|
1
|
+
{"version":3,"file":"AlwaysSkipPrivacyPolicyRule-test.js","sourceRoot":"","sources":["../../../src/rules/__tests__/AlwaysSkipPrivacyPolicyRule-test.ts"],"names":[],"mappings":";;;;;AAAA,2CAAsD;AAGtD,iEAA8D;AAC9D,wEAAgD;AAChD,+FAA2F;AAC3F,iGAAyE;AAEzE,IAAA,sDAAyB,EAAC,IAAI,qCAA2B,EAAE,EAAE;IAC3D,SAAS,EAAE;QACT;YACE,aAAa,EAAE,IAAA,qBAAQ,EAAC,IAAA,iBAAI,EAAC,uBAAa,CAAC,CAAC;YAC5C,YAAY,EAAE,IAAA,qBAAQ,EAAC,IAAA,iBAAI,EAAC,uCAAkB,CAAC,CAAC;YAChD,iBAAiB,EAAE,IAAA,qBAAQ,EAAC,IAAA,iBAAI,GAAwC,CAAC;YACzE,MAAM,EAAE,IAAA,qBAAQ,GAAE;SACnB;KACF;CACF,CAAC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EntityPrivacyPolicyEvaluationContext } from '../../EntityPrivacyPolicy';
|
|
1
2
|
import { EntityQueryContext } from '../../EntityQueryContext';
|
|
2
3
|
import ReadonlyEntity from '../../ReadonlyEntity';
|
|
3
4
|
import ViewerContext from '../../ViewerContext';
|
|
@@ -5,6 +6,7 @@ import PrivacyPolicyRule from '../../rules/PrivacyPolicyRule';
|
|
|
5
6
|
export interface Case<TFields, TID extends NonNullable<TFields[TSelectedFields]>, TViewerContext extends ViewerContext, TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>, TSelectedFields extends keyof TFields> {
|
|
6
7
|
viewerContext: TViewerContext;
|
|
7
8
|
queryContext: EntityQueryContext;
|
|
9
|
+
evaluationContext: EntityPrivacyPolicyEvaluationContext;
|
|
8
10
|
entity: TEntity;
|
|
9
11
|
}
|
|
10
12
|
declare type CaseMap<TFields, TID extends NonNullable<TFields[TSelectedFields]>, TViewerContext extends ViewerContext, TEntity extends ReadonlyEntity<TFields, TID, TViewerContext, TSelectedFields>, TSelectedFields extends keyof TFields> = Map<string, () => Promise<Case<TFields, TID, TViewerContext, TEntity, TSelectedFields>>>;
|
|
@@ -10,24 +10,24 @@ const describePrivacyPolicyRuleWithAsyncTestCase = (privacyPolicyRule, { allowCa
|
|
|
10
10
|
if (allowCases && allowCases.size > 0) {
|
|
11
11
|
describe('allow cases', () => {
|
|
12
12
|
test.each(Array.from(allowCases.keys()))('%p', async (caseKey) => {
|
|
13
|
-
const { viewerContext, queryContext, entity } = await allowCases.get(caseKey)();
|
|
14
|
-
await expect(privacyPolicyRule.evaluateAsync(viewerContext, queryContext, entity)).resolves.toEqual(PrivacyPolicyRule_1.RuleEvaluationResult.ALLOW);
|
|
13
|
+
const { viewerContext, queryContext, evaluationContext, entity } = await allowCases.get(caseKey)();
|
|
14
|
+
await expect(privacyPolicyRule.evaluateAsync(viewerContext, queryContext, evaluationContext, entity)).resolves.toEqual(PrivacyPolicyRule_1.RuleEvaluationResult.ALLOW);
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
if (skipCases && skipCases.size > 0) {
|
|
19
19
|
describe('skip cases', () => {
|
|
20
20
|
test.each(Array.from(skipCases.keys()))('%p', async (caseKey) => {
|
|
21
|
-
const { viewerContext, queryContext, entity } = await skipCases.get(caseKey)();
|
|
22
|
-
await expect(privacyPolicyRule.evaluateAsync(viewerContext, queryContext, entity)).resolves.toEqual(PrivacyPolicyRule_1.RuleEvaluationResult.SKIP);
|
|
21
|
+
const { viewerContext, queryContext, evaluationContext, entity } = await skipCases.get(caseKey)();
|
|
22
|
+
await expect(privacyPolicyRule.evaluateAsync(viewerContext, queryContext, evaluationContext, entity)).resolves.toEqual(PrivacyPolicyRule_1.RuleEvaluationResult.SKIP);
|
|
23
23
|
});
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
if (denyCases && denyCases.size > 0) {
|
|
27
27
|
describe('deny cases', () => {
|
|
28
28
|
test.each(Array.from(denyCases.keys()))('%p', async (caseKey) => {
|
|
29
|
-
const { viewerContext, queryContext, entity } = await denyCases.get(caseKey)();
|
|
30
|
-
await expect(privacyPolicyRule.evaluateAsync(viewerContext, queryContext, entity)).resolves.toEqual(PrivacyPolicyRule_1.RuleEvaluationResult.DENY);
|
|
29
|
+
const { viewerContext, queryContext, evaluationContext, entity } = await denyCases.get(caseKey)();
|
|
30
|
+
await expect(privacyPolicyRule.evaluateAsync(viewerContext, queryContext, evaluationContext, entity)).resolves.toEqual(PrivacyPolicyRule_1.RuleEvaluationResult.DENY);
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PrivacyPolicyRuleTestUtils.js","sourceRoot":"","sources":["../../../src/utils/testing/PrivacyPolicyRuleTestUtils.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"PrivacyPolicyRuleTestUtils.js","sourceRoot":"","sources":["../../../src/utils/testing/PrivacyPolicyRuleTestUtils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import nullthrows from 'nullthrows';
|
|
2
|
+
|
|
3
|
+
import EntityCacheAdapter from './EntityCacheAdapter';
|
|
4
|
+
import EntityConfiguration from './EntityConfiguration';
|
|
5
|
+
import { CacheStatus, CacheLoadResult } from './internal/ReadThroughEntityCache';
|
|
6
|
+
|
|
7
|
+
export default class ComposedEntityCacheAdapter<TFields> extends EntityCacheAdapter<TFields> {
|
|
8
|
+
/**
|
|
9
|
+
* A {@link EntityCacheAdapter} that composes other {@link EntityCacheAdapter} instances.
|
|
10
|
+
*
|
|
11
|
+
* @param entityConfiguration - configuration for entity being loaded
|
|
12
|
+
* @param cacheAdapters - list of cache adapters to compose in order of precedence.
|
|
13
|
+
* Earlier cache adapters are read from first and written to (including invalidations) last.
|
|
14
|
+
* Typically, caches closer to the application should be ordered before caches closer to the database.
|
|
15
|
+
*/
|
|
16
|
+
constructor(
|
|
17
|
+
entityConfiguration: EntityConfiguration<TFields>,
|
|
18
|
+
private readonly cacheAdapters: EntityCacheAdapter<TFields>[]
|
|
19
|
+
) {
|
|
20
|
+
super(entityConfiguration);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public async loadManyAsync<N extends keyof TFields>(
|
|
24
|
+
fieldName: N,
|
|
25
|
+
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
26
|
+
): Promise<ReadonlyMap<NonNullable<TFields[N]>, CacheLoadResult<TFields>>> {
|
|
27
|
+
const retMap = new Map<NonNullable<TFields[N]>, CacheLoadResult<TFields>>();
|
|
28
|
+
|
|
29
|
+
let unfulfilledFieldValues = fieldValues;
|
|
30
|
+
for (const cacheAdapter of this.cacheAdapters) {
|
|
31
|
+
const cacheResultsFromAdapter = await cacheAdapter.loadManyAsync(
|
|
32
|
+
fieldName,
|
|
33
|
+
unfulfilledFieldValues
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const newUnfulfilledFieldValues = [];
|
|
37
|
+
for (const [fieldValue, cacheResult] of cacheResultsFromAdapter) {
|
|
38
|
+
if (cacheResult.status === CacheStatus.MISS) {
|
|
39
|
+
newUnfulfilledFieldValues.push(fieldValue);
|
|
40
|
+
} else {
|
|
41
|
+
retMap.set(fieldValue, cacheResult);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
unfulfilledFieldValues = newUnfulfilledFieldValues;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for (const fieldValue of unfulfilledFieldValues) {
|
|
48
|
+
retMap.set(fieldValue, { status: CacheStatus.MISS });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return retMap;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public async cacheManyAsync<N extends keyof TFields>(
|
|
55
|
+
fieldName: N,
|
|
56
|
+
objectMap: ReadonlyMap<NonNullable<TFields[N]>, Readonly<TFields>>
|
|
57
|
+
): Promise<void> {
|
|
58
|
+
// write to lower layers first
|
|
59
|
+
for (let i = this.cacheAdapters.length - 1; i >= 0; i--) {
|
|
60
|
+
const cacheAdapter = nullthrows(this.cacheAdapters[i]);
|
|
61
|
+
await cacheAdapter.cacheManyAsync(fieldName, objectMap);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async cacheDBMissesAsync<N extends keyof TFields>(
|
|
66
|
+
fieldName: N,
|
|
67
|
+
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
68
|
+
): Promise<void> {
|
|
69
|
+
// write to lower layers first
|
|
70
|
+
for (let i = this.cacheAdapters.length - 1; i >= 0; i--) {
|
|
71
|
+
const cacheAdapter = nullthrows(this.cacheAdapters[i]);
|
|
72
|
+
await cacheAdapter.cacheDBMissesAsync(fieldName, fieldValues);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public async invalidateManyAsync<N extends keyof TFields>(
|
|
77
|
+
fieldName: N,
|
|
78
|
+
fieldValues: readonly NonNullable<TFields[N]>[]
|
|
79
|
+
): Promise<void> {
|
|
80
|
+
// delete from lower layers first
|
|
81
|
+
for (let i = this.cacheAdapters.length - 1; i >= 0; i--) {
|
|
82
|
+
const cacheAdapter = nullthrows(this.cacheAdapters[i]);
|
|
83
|
+
await cacheAdapter.invalidateManyAsync(fieldName, fieldValues);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import nullthrows from 'nullthrows';
|
|
2
|
+
|
|
3
|
+
import { ISecondaryEntityCache } from './EntitySecondaryCacheLoader';
|
|
4
|
+
|
|
5
|
+
export default class ComposedSecondaryEntityCache<TLoadParams, TFields>
|
|
6
|
+
implements ISecondaryEntityCache<TFields, TLoadParams>
|
|
7
|
+
{
|
|
8
|
+
/**
|
|
9
|
+
* A {@link ISecondaryEntityCache} that composes other {@link ISecondaryEntityCache} instances.
|
|
10
|
+
*
|
|
11
|
+
* @param secondaryEntityCaches - list of caches to compose in order of precedence.
|
|
12
|
+
* Earlier caches are read from first and written to (including invalidations) last.
|
|
13
|
+
* Typically, caches closer to the application should be ordered before caches closer to the database.
|
|
14
|
+
*/
|
|
15
|
+
constructor(
|
|
16
|
+
private readonly secondaryEntityCaches: ISecondaryEntityCache<TFields, TLoadParams>[]
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
async loadManyThroughAsync(
|
|
20
|
+
loadParamsArray: readonly Readonly<TLoadParams>[],
|
|
21
|
+
fetcher: (
|
|
22
|
+
fetcherLoadParamsArray: readonly Readonly<TLoadParams>[]
|
|
23
|
+
) => Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null>>
|
|
24
|
+
): Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null>> {
|
|
25
|
+
return await ComposedSecondaryEntityCache.loadManyThroughRecursivelyAsync(
|
|
26
|
+
this.secondaryEntityCaches,
|
|
27
|
+
loadParamsArray,
|
|
28
|
+
fetcher
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private static async loadManyThroughRecursivelyAsync<TLoadParams, TFields>(
|
|
33
|
+
secondaryEntityCaches: ISecondaryEntityCache<TFields, TLoadParams>[],
|
|
34
|
+
loadParamsArray: readonly Readonly<TLoadParams>[],
|
|
35
|
+
fetcher: (
|
|
36
|
+
fetcherLoadParamsArray: readonly Readonly<TLoadParams>[]
|
|
37
|
+
) => Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null>>
|
|
38
|
+
): Promise<ReadonlyMap<Readonly<TLoadParams>, Readonly<TFields> | null>> {
|
|
39
|
+
if (secondaryEntityCaches.length === 0) {
|
|
40
|
+
return await fetcher(loadParamsArray);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const [firstCache, ...restCaches] = secondaryEntityCaches;
|
|
44
|
+
|
|
45
|
+
return await nullthrows(firstCache).loadManyThroughAsync(
|
|
46
|
+
loadParamsArray,
|
|
47
|
+
(fetcherLoadParamsArray) =>
|
|
48
|
+
ComposedSecondaryEntityCache.loadManyThroughRecursivelyAsync(
|
|
49
|
+
restCaches,
|
|
50
|
+
fetcherLoadParamsArray,
|
|
51
|
+
fetcher
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async invalidateManyAsync(loadParamsArray: readonly Readonly<TLoadParams>[]): Promise<void> {
|
|
57
|
+
// invalidate lower layers first
|
|
58
|
+
for (let i = this.secondaryEntityCaches.length - 1; i >= 0; i--) {
|
|
59
|
+
const secondaryEntityCache = nullthrows(this.secondaryEntityCaches[i]);
|
|
60
|
+
await secondaryEntityCache.invalidateManyAsync(loadParamsArray);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/Entity.ts
CHANGED
|
@@ -69,7 +69,7 @@ export default abstract class Entity<
|
|
|
69
69
|
return viewerContext
|
|
70
70
|
.getViewerScopedEntityCompanionForClass(this)
|
|
71
71
|
.getMutatorFactory()
|
|
72
|
-
.forCreate(queryContext);
|
|
72
|
+
.forCreate(queryContext, { cascadingDeleteCause: null });
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
@@ -111,7 +111,7 @@ export default abstract class Entity<
|
|
|
111
111
|
.getViewerContext()
|
|
112
112
|
.getViewerScopedEntityCompanionForClass(this)
|
|
113
113
|
.getMutatorFactory()
|
|
114
|
-
.forUpdate(existingEntity, queryContext);
|
|
114
|
+
.forUpdate(existingEntity, queryContext, { cascadingDeleteCause: null });
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
/**
|
|
@@ -152,7 +152,7 @@ export default abstract class Entity<
|
|
|
152
152
|
.getViewerContext()
|
|
153
153
|
.getViewerScopedEntityCompanionForClass(this)
|
|
154
154
|
.getMutatorFactory()
|
|
155
|
-
.forDelete(existingEntity, queryContext)
|
|
155
|
+
.forDelete(existingEntity, queryContext, { cascadingDeleteCause: null })
|
|
156
156
|
.deleteAsync();
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -194,7 +194,7 @@ export default abstract class Entity<
|
|
|
194
194
|
.getViewerContext()
|
|
195
195
|
.getViewerScopedEntityCompanionForClass(this)
|
|
196
196
|
.getMutatorFactory()
|
|
197
|
-
.forDelete(existingEntity, queryContext)
|
|
197
|
+
.forDelete(existingEntity, queryContext, { cascadingDeleteCause: null })
|
|
198
198
|
.enforceDeleteAsync();
|
|
199
199
|
}
|
|
200
200
|
|
|
@@ -251,6 +251,7 @@ export default abstract class Entity<
|
|
|
251
251
|
privacyPolicy.authorizeUpdateAsync(
|
|
252
252
|
existingEntity.getViewerContext(),
|
|
253
253
|
queryContext,
|
|
254
|
+
{ cascadingDeleteCause: null },
|
|
254
255
|
existingEntity,
|
|
255
256
|
companion.getMetricsAdapter()
|
|
256
257
|
)
|
|
@@ -304,6 +305,7 @@ export default abstract class Entity<
|
|
|
304
305
|
privacyPolicy.authorizeDeleteAsync(
|
|
305
306
|
existingEntity.getViewerContext(),
|
|
306
307
|
queryContext,
|
|
308
|
+
{ cascadingDeleteCause: null },
|
|
307
309
|
existingEntity,
|
|
308
310
|
companion.getMetricsAdapter()
|
|
309
311
|
)
|
|
@@ -69,7 +69,7 @@ export default class EntityAssociationLoader<
|
|
|
69
69
|
.getViewerContext()
|
|
70
70
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
71
71
|
.getLoaderFactory()
|
|
72
|
-
.forLoad(queryContext);
|
|
72
|
+
.forLoad(queryContext, { cascadingDeleteCause: null });
|
|
73
73
|
|
|
74
74
|
return (await loader.loadByIDAsync(associatedEntityID as unknown as TAssociatedID)) as Result<
|
|
75
75
|
null extends TFields[TIdentifyingField] ? TAssociatedEntity | null : TAssociatedEntity
|
|
@@ -123,7 +123,7 @@ export default class EntityAssociationLoader<
|
|
|
123
123
|
.getViewerContext()
|
|
124
124
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
125
125
|
.getLoaderFactory()
|
|
126
|
-
.forLoad(queryContext);
|
|
126
|
+
.forLoad(queryContext, { cascadingDeleteCause: null });
|
|
127
127
|
return await loader.loadManyByFieldEqualingAsync(
|
|
128
128
|
associatedEntityFieldContainingThisID,
|
|
129
129
|
thisID as any
|
|
@@ -180,7 +180,7 @@ export default class EntityAssociationLoader<
|
|
|
180
180
|
.getViewerContext()
|
|
181
181
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
182
182
|
.getLoaderFactory()
|
|
183
|
-
.forLoad(queryContext);
|
|
183
|
+
.forLoad(queryContext, { cascadingDeleteCause: null });
|
|
184
184
|
return await loader.loadByFieldEqualingAsync(
|
|
185
185
|
associatedEntityLookupByField,
|
|
186
186
|
associatedFieldValue as any
|
|
@@ -238,7 +238,7 @@ export default class EntityAssociationLoader<
|
|
|
238
238
|
.getViewerContext()
|
|
239
239
|
.getViewerScopedEntityCompanionForClass(associatedEntityClass)
|
|
240
240
|
.getLoaderFactory()
|
|
241
|
-
.forLoad(queryContext);
|
|
241
|
+
.forLoad(queryContext, { cascadingDeleteCause: null });
|
|
242
242
|
return await loader.loadManyByFieldEqualingAsync(
|
|
243
243
|
associatedEntityLookupByField,
|
|
244
244
|
associatedFieldValue as any
|
package/src/EntityLoader.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
QuerySelectionModifiers,
|
|
10
10
|
isSingleValueFieldEqualityCondition,
|
|
11
11
|
} from './EntityDatabaseAdapter';
|
|
12
|
-
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
12
|
+
import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './EntityPrivacyPolicy';
|
|
13
13
|
import { EntityQueryContext } from './EntityQueryContext';
|
|
14
14
|
import ReadonlyEntity from './ReadonlyEntity';
|
|
15
15
|
import ViewerContext from './ViewerContext';
|
|
@@ -40,6 +40,7 @@ export default class EntityLoader<
|
|
|
40
40
|
constructor(
|
|
41
41
|
private readonly viewerContext: TViewerContext,
|
|
42
42
|
private readonly queryContext: EntityQueryContext,
|
|
43
|
+
private readonly privacyPolicyEvaluationContext: EntityPrivacyPolicyEvaluationContext,
|
|
43
44
|
private readonly entityConfiguration: EntityConfiguration<TFields>,
|
|
44
45
|
private readonly entityClass: IEntityClass<
|
|
45
46
|
TFields,
|
|
@@ -218,6 +219,7 @@ export default class EntityLoader<
|
|
|
218
219
|
this.privacyPolicy.authorizeReadAsync(
|
|
219
220
|
this.viewerContext,
|
|
220
221
|
this.queryContext,
|
|
222
|
+
this.privacyPolicyEvaluationContext,
|
|
221
223
|
uncheckedEntityResult.value,
|
|
222
224
|
this.metricsAdapter
|
|
223
225
|
)
|
|
@@ -272,6 +274,7 @@ export default class EntityLoader<
|
|
|
272
274
|
this.privacyPolicy.authorizeReadAsync(
|
|
273
275
|
this.viewerContext,
|
|
274
276
|
this.queryContext,
|
|
277
|
+
this.privacyPolicyEvaluationContext,
|
|
275
278
|
uncheckedEntityResult.value,
|
|
276
279
|
this.metricsAdapter
|
|
277
280
|
)
|
|
@@ -332,6 +335,7 @@ export default class EntityLoader<
|
|
|
332
335
|
this.privacyPolicy.authorizeReadAsync(
|
|
333
336
|
this.viewerContext,
|
|
334
337
|
this.queryContext,
|
|
338
|
+
this.privacyPolicyEvaluationContext,
|
|
335
339
|
uncheckedEntityResult.value,
|
|
336
340
|
this.metricsAdapter
|
|
337
341
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IEntityClass } from './Entity';
|
|
2
2
|
import EntityConfiguration from './EntityConfiguration';
|
|
3
3
|
import EntityLoader from './EntityLoader';
|
|
4
|
-
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
4
|
+
import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './EntityPrivacyPolicy';
|
|
5
5
|
import { EntityQueryContext } from './EntityQueryContext';
|
|
6
6
|
import ReadonlyEntity from './ReadonlyEntity';
|
|
7
7
|
import ViewerContext from './ViewerContext';
|
|
@@ -47,11 +47,13 @@ export default class EntityLoaderFactory<
|
|
|
47
47
|
*/
|
|
48
48
|
forLoad(
|
|
49
49
|
viewerContext: TViewerContext,
|
|
50
|
-
queryContext: EntityQueryContext
|
|
50
|
+
queryContext: EntityQueryContext,
|
|
51
|
+
privacyPolicyEvaluationContext: EntityPrivacyPolicyEvaluationContext
|
|
51
52
|
): EntityLoader<TFields, TID, TViewerContext, TEntity, TPrivacyPolicy, TSelectedFields> {
|
|
52
53
|
return new EntityLoader(
|
|
53
54
|
viewerContext,
|
|
54
55
|
queryContext,
|
|
56
|
+
privacyPolicyEvaluationContext,
|
|
55
57
|
this.entityConfiguration,
|
|
56
58
|
this.entityClass,
|
|
57
59
|
this.privacyPolicyClass,
|
|
@@ -22,9 +22,19 @@ export type EntityValidatorMutationInfo<
|
|
|
22
22
|
previousValue: TEntity;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Information about a cascading deletion.
|
|
27
|
+
*/
|
|
28
|
+
export type EntityCascadingDeletionInfo = {
|
|
29
|
+
/**
|
|
30
|
+
* The entity that is being mutated at this step in the cascaded deletion.
|
|
31
|
+
*/
|
|
26
32
|
entity: Entity<any, any, any, any>;
|
|
27
|
-
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The cascade deletion that caused this mutation.
|
|
36
|
+
*/
|
|
37
|
+
cascadingDeleteCause: EntityCascadingDeletionInfo | null;
|
|
28
38
|
};
|
|
29
39
|
|
|
30
40
|
export type EntityTriggerMutationInfo<
|
|
@@ -43,5 +53,5 @@ export type EntityTriggerMutationInfo<
|
|
|
43
53
|
}
|
|
44
54
|
| {
|
|
45
55
|
type: EntityMutationType.DELETE;
|
|
46
|
-
cascadingDeleteCause:
|
|
56
|
+
cascadingDeleteCause: EntityCascadingDeletionInfo | null;
|
|
47
57
|
};
|
package/src/EntityMutator.ts
CHANGED
|
@@ -11,14 +11,14 @@ import {
|
|
|
11
11
|
EntityValidatorMutationInfo,
|
|
12
12
|
EntityMutationType,
|
|
13
13
|
EntityTriggerMutationInfo,
|
|
14
|
-
|
|
14
|
+
EntityCascadingDeletionInfo,
|
|
15
15
|
} from './EntityMutationInfo';
|
|
16
16
|
import EntityMutationTriggerConfiguration, {
|
|
17
17
|
EntityMutationTrigger,
|
|
18
18
|
EntityNonTransactionalMutationTrigger,
|
|
19
19
|
} from './EntityMutationTriggerConfiguration';
|
|
20
20
|
import EntityMutationValidator from './EntityMutationValidator';
|
|
21
|
-
import EntityPrivacyPolicy from './EntityPrivacyPolicy';
|
|
21
|
+
import EntityPrivacyPolicy, { EntityPrivacyPolicyEvaluationContext } from './EntityPrivacyPolicy';
|
|
22
22
|
import { EntityQueryContext, EntityTransactionalQueryContext } from './EntityQueryContext';
|
|
23
23
|
import ReadonlyEntity from './ReadonlyEntity';
|
|
24
24
|
import ViewerContext from './ViewerContext';
|
|
@@ -44,6 +44,7 @@ abstract class BaseMutator<
|
|
|
44
44
|
constructor(
|
|
45
45
|
protected readonly viewerContext: TViewerContext,
|
|
46
46
|
protected readonly queryContext: EntityQueryContext,
|
|
47
|
+
protected readonly privacyPolicyEvaluationContext: EntityPrivacyPolicyEvaluationContext,
|
|
47
48
|
protected readonly entityConfiguration: EntityConfiguration<TFields>,
|
|
48
49
|
protected readonly entityClass: IEntityClass<
|
|
49
50
|
TFields,
|
|
@@ -220,6 +221,7 @@ export class CreateMutator<
|
|
|
220
221
|
this.privacyPolicy.authorizeCreateAsync(
|
|
221
222
|
this.viewerContext,
|
|
222
223
|
queryContext,
|
|
224
|
+
this.privacyPolicyEvaluationContext,
|
|
223
225
|
temporaryEntityForPrivacyCheck,
|
|
224
226
|
this.metricsAdapter
|
|
225
227
|
)
|
|
@@ -249,7 +251,11 @@ export class CreateMutator<
|
|
|
249
251
|
|
|
250
252
|
const insertResult = await this.databaseAdapter.insertAsync(queryContext, this.fieldsForEntity);
|
|
251
253
|
|
|
252
|
-
const entityLoader = this.entityLoaderFactory.forLoad(
|
|
254
|
+
const entityLoader = this.entityLoaderFactory.forLoad(
|
|
255
|
+
this.viewerContext,
|
|
256
|
+
queryContext,
|
|
257
|
+
this.privacyPolicyEvaluationContext
|
|
258
|
+
);
|
|
253
259
|
queryContext.appendPostCommitInvalidationCallback(
|
|
254
260
|
entityLoader.invalidateFieldsAsync.bind(entityLoader, insertResult)
|
|
255
261
|
);
|
|
@@ -309,6 +315,7 @@ export class UpdateMutator<
|
|
|
309
315
|
constructor(
|
|
310
316
|
viewerContext: TViewerContext,
|
|
311
317
|
queryContext: EntityQueryContext,
|
|
318
|
+
privacyPolicyEvaluationContext: EntityPrivacyPolicyEvaluationContext,
|
|
312
319
|
entityConfiguration: EntityConfiguration<TFields>,
|
|
313
320
|
entityClass: IEntityClass<
|
|
314
321
|
TFields,
|
|
@@ -348,6 +355,7 @@ export class UpdateMutator<
|
|
|
348
355
|
super(
|
|
349
356
|
viewerContext,
|
|
350
357
|
queryContext,
|
|
358
|
+
privacyPolicyEvaluationContext,
|
|
351
359
|
entityConfiguration,
|
|
352
360
|
entityClass,
|
|
353
361
|
privacyPolicy,
|
|
@@ -409,6 +417,7 @@ export class UpdateMutator<
|
|
|
409
417
|
this.privacyPolicy.authorizeUpdateAsync(
|
|
410
418
|
this.viewerContext,
|
|
411
419
|
queryContext,
|
|
420
|
+
this.privacyPolicyEvaluationContext,
|
|
412
421
|
entityAboutToBeUpdated,
|
|
413
422
|
this.metricsAdapter
|
|
414
423
|
)
|
|
@@ -443,7 +452,11 @@ export class UpdateMutator<
|
|
|
443
452
|
this.updatedFields
|
|
444
453
|
);
|
|
445
454
|
|
|
446
|
-
const entityLoader = this.entityLoaderFactory.forLoad(
|
|
455
|
+
const entityLoader = this.entityLoaderFactory.forLoad(
|
|
456
|
+
this.viewerContext,
|
|
457
|
+
queryContext,
|
|
458
|
+
this.privacyPolicyEvaluationContext
|
|
459
|
+
);
|
|
447
460
|
|
|
448
461
|
queryContext.appendPostCommitInvalidationCallback(
|
|
449
462
|
entityLoader.invalidateFieldsAsync.bind(
|
|
@@ -506,6 +519,7 @@ export class DeleteMutator<
|
|
|
506
519
|
constructor(
|
|
507
520
|
viewerContext: TViewerContext,
|
|
508
521
|
queryContext: EntityQueryContext,
|
|
522
|
+
privacyPolicyEvaluationContext: EntityPrivacyPolicyEvaluationContext,
|
|
509
523
|
entityConfiguration: EntityConfiguration<TFields>,
|
|
510
524
|
entityClass: IEntityClass<
|
|
511
525
|
TFields,
|
|
@@ -545,6 +559,7 @@ export class DeleteMutator<
|
|
|
545
559
|
super(
|
|
546
560
|
viewerContext,
|
|
547
561
|
queryContext,
|
|
562
|
+
privacyPolicyEvaluationContext,
|
|
548
563
|
entityConfiguration,
|
|
549
564
|
entityClass,
|
|
550
565
|
privacyPolicy,
|
|
@@ -578,7 +593,7 @@ export class DeleteMutator<
|
|
|
578
593
|
private async deleteInTransactionAsync(
|
|
579
594
|
processedEntityIdentifiersFromTransitiveDeletions: Set<string>,
|
|
580
595
|
skipDatabaseDeletion: boolean,
|
|
581
|
-
cascadingDeleteCause:
|
|
596
|
+
cascadingDeleteCause: EntityCascadingDeletionInfo | null
|
|
582
597
|
): Promise<Result<void>> {
|
|
583
598
|
return await this.queryContext.runInTransactionIfNotInTransactionAsync((innerQueryContext) =>
|
|
584
599
|
this.deleteInternalAsync(
|
|
@@ -594,12 +609,13 @@ export class DeleteMutator<
|
|
|
594
609
|
queryContext: EntityTransactionalQueryContext,
|
|
595
610
|
processedEntityIdentifiersFromTransitiveDeletions: Set<string>,
|
|
596
611
|
skipDatabaseDeletion: boolean,
|
|
597
|
-
cascadingDeleteCause:
|
|
612
|
+
cascadingDeleteCause: EntityCascadingDeletionInfo | null
|
|
598
613
|
): Promise<Result<void>> {
|
|
599
614
|
const authorizeDeleteResult = await asyncResult(
|
|
600
615
|
this.privacyPolicy.authorizeDeleteAsync(
|
|
601
616
|
this.viewerContext,
|
|
602
617
|
queryContext,
|
|
618
|
+
{ cascadingDeleteCause },
|
|
603
619
|
this.entity,
|
|
604
620
|
this.metricsAdapter
|
|
605
621
|
)
|
|
@@ -636,7 +652,9 @@ export class DeleteMutator<
|
|
|
636
652
|
);
|
|
637
653
|
}
|
|
638
654
|
|
|
639
|
-
const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext
|
|
655
|
+
const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext, {
|
|
656
|
+
cascadingDeleteCause,
|
|
657
|
+
});
|
|
640
658
|
queryContext.appendPostCommitInvalidationCallback(
|
|
641
659
|
entityLoader.invalidateFieldsAsync.bind(entityLoader, this.entity.getAllDatabaseFields())
|
|
642
660
|
);
|
|
@@ -684,7 +702,7 @@ export class DeleteMutator<
|
|
|
684
702
|
entity: TEntity,
|
|
685
703
|
queryContext: EntityTransactionalQueryContext,
|
|
686
704
|
processedEntityIdentifiers: Set<string>,
|
|
687
|
-
cascadingDeleteCause:
|
|
705
|
+
cascadingDeleteCause: EntityCascadingDeletionInfo | null
|
|
688
706
|
): Promise<void> {
|
|
689
707
|
// prevent infinite reference cycles by keeping track of entities already processed
|
|
690
708
|
if (processedEntityIdentifiers.has(entity.getUniqueIdentifier())) {
|
|
@@ -732,10 +750,15 @@ export class DeleteMutator<
|
|
|
732
750
|
.getViewerScopedEntityCompanionForClass(entityClass)
|
|
733
751
|
.getMutatorFactory();
|
|
734
752
|
|
|
753
|
+
const newCascadingDeleteCause = {
|
|
754
|
+
entity,
|
|
755
|
+
cascadingDeleteCause,
|
|
756
|
+
};
|
|
757
|
+
|
|
735
758
|
let inboundReferenceEntities: readonly ReadonlyEntity<any, any, any, any>[];
|
|
736
759
|
if (associatedEntityLookupByField) {
|
|
737
760
|
inboundReferenceEntities = await loaderFactory
|
|
738
|
-
.forLoad(queryContext)
|
|
761
|
+
.forLoad(queryContext, { cascadingDeleteCause: newCascadingDeleteCause })
|
|
739
762
|
.enforcing()
|
|
740
763
|
.loadManyByFieldEqualingAsync(
|
|
741
764
|
fieldName,
|
|
@@ -743,7 +766,7 @@ export class DeleteMutator<
|
|
|
743
766
|
);
|
|
744
767
|
} else {
|
|
745
768
|
inboundReferenceEntities = await loaderFactory
|
|
746
|
-
.forLoad(queryContext)
|
|
769
|
+
.forLoad(queryContext, { cascadingDeleteCause: newCascadingDeleteCause })
|
|
747
770
|
.enforcing()
|
|
748
771
|
.loadManyByFieldEqualingAsync(fieldName, entity.getID());
|
|
749
772
|
}
|
|
@@ -754,14 +777,13 @@ export class DeleteMutator<
|
|
|
754
777
|
await Promise.all(
|
|
755
778
|
inboundReferenceEntities.map((inboundReferenceEntity) =>
|
|
756
779
|
mutatorFactory
|
|
757
|
-
.forDelete(inboundReferenceEntity, queryContext
|
|
780
|
+
.forDelete(inboundReferenceEntity, queryContext, {
|
|
781
|
+
cascadingDeleteCause: newCascadingDeleteCause,
|
|
782
|
+
})
|
|
758
783
|
.deleteInTransactionAsync(
|
|
759
784
|
processedEntityIdentifiers,
|
|
760
785
|
/* skipDatabaseDeletion */ true, // deletion is handled by DB
|
|
761
|
-
|
|
762
|
-
entity,
|
|
763
|
-
cascadingDeleteCause,
|
|
764
|
-
}
|
|
786
|
+
newCascadingDeleteCause
|
|
765
787
|
)
|
|
766
788
|
)
|
|
767
789
|
);
|
|
@@ -771,7 +793,9 @@ export class DeleteMutator<
|
|
|
771
793
|
await Promise.all(
|
|
772
794
|
inboundReferenceEntities.map((inboundReferenceEntity) =>
|
|
773
795
|
mutatorFactory
|
|
774
|
-
.forUpdate(inboundReferenceEntity, queryContext
|
|
796
|
+
.forUpdate(inboundReferenceEntity, queryContext, {
|
|
797
|
+
cascadingDeleteCause: newCascadingDeleteCause,
|
|
798
|
+
})
|
|
775
799
|
.setField(fieldName, null)
|
|
776
800
|
.enforceUpdateAsync()
|
|
777
801
|
)
|
|
@@ -782,14 +806,13 @@ export class DeleteMutator<
|
|
|
782
806
|
await Promise.all(
|
|
783
807
|
inboundReferenceEntities.map((inboundReferenceEntity) =>
|
|
784
808
|
mutatorFactory
|
|
785
|
-
.forDelete(inboundReferenceEntity, queryContext
|
|
809
|
+
.forDelete(inboundReferenceEntity, queryContext, {
|
|
810
|
+
cascadingDeleteCause: newCascadingDeleteCause,
|
|
811
|
+
})
|
|
786
812
|
.deleteInTransactionAsync(
|
|
787
813
|
processedEntityIdentifiers,
|
|
788
814
|
/* skipDatabaseDeletion */ false,
|
|
789
|
-
|
|
790
|
-
entity,
|
|
791
|
-
cascadingDeleteCause,
|
|
792
|
-
}
|
|
815
|
+
newCascadingDeleteCause
|
|
793
816
|
)
|
|
794
817
|
)
|
|
795
818
|
);
|