@expo/entity 0.23.0 → 0.25.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 +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/EntityFieldDefinition.d.ts +8 -0
- package/build/EntityFieldDefinition.js +5 -0
- package/build/EntityFieldDefinition.js.map +1 -1
- package/build/EntityFields.d.ts +38 -0
- package/build/EntityFields.js +38 -0
- package/build/EntityFields.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/GenericSecondaryEntityCache.d.ts +19 -0
- package/build/GenericSecondaryEntityCache.js +74 -0
- package/build/GenericSecondaryEntityCache.js.map +1 -0
- package/build/IEntityGenericCacher.d.ts +11 -0
- package/build/IEntityGenericCacher.js +3 -0
- package/build/IEntityGenericCacher.js.map +1 -0
- 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 +4 -0
- package/build/index.js +7 -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/EntityFieldDefinition.ts +8 -0
- package/src/EntityFields.ts +45 -0
- 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/GenericSecondaryEntityCache.ts +98 -0
- package/src/IEntityGenericCacher.ts +15 -0
- 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 +4 -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 AlwaysAllowPrivacyPolicyRule_1 = __importDefault(require("../AlwaysAllowPr
|
|
|
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":"AlwaysAllowPrivacyPolicyRule-test.js","sourceRoot":"","sources":["../../../src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts"],"names":[],"mappings":";;;;;AAAA,2CAAsD;
|
|
1
|
+
{"version":3,"file":"AlwaysAllowPrivacyPolicyRule-test.js","sourceRoot":"","sources":["../../../src/rules/__tests__/AlwaysAllowPrivacyPolicyRule-test.ts"],"names":[],"mappings":";;;;;AAAA,2CAAsD;AAGtD,iEAA8D;AAC9D,wEAAgD;AAChD,+FAA2F;AAC3F,mGAA2E;AAE3E,IAAA,sDAAyB,EAAC,IAAI,sCAA4B,EAAE,EAAE;IAC5D,UAAU,EAAE;QACV;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 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
|
|
@@ -28,6 +28,9 @@ export enum EntityEdgeDeletionBehavior {
|
|
|
28
28
|
SET_NULL,
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Defines an association between entities. An association is primarily used to define cascading deletion behavior.
|
|
33
|
+
*/
|
|
31
34
|
export interface EntityAssociationDefinition<
|
|
32
35
|
TViewerContext extends ViewerContext,
|
|
33
36
|
TAssociatedFields,
|
|
@@ -83,6 +86,10 @@ export interface EntityAssociationDefinition<
|
|
|
83
86
|
edgeDeletionBehavior?: EntityEdgeDeletionBehavior;
|
|
84
87
|
}
|
|
85
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Definition for a field referencing a column in the underlying database. Specifies things like
|
|
91
|
+
* cache behavior and associations, and handles input validation.
|
|
92
|
+
*/
|
|
86
93
|
export abstract class EntityFieldDefinition<T> {
|
|
87
94
|
readonly columnName: string;
|
|
88
95
|
readonly cache: boolean;
|
|
@@ -93,6 +100,7 @@ export abstract class EntityFieldDefinition<T> {
|
|
|
93
100
|
* @param cache - Whether or not to cache loaded instances of the entity by this field. The column name is
|
|
94
101
|
* used to derive a cache key for the cache entry. If true, this column must be able uniquely
|
|
95
102
|
* identify the entity.
|
|
103
|
+
* @param association - Defines the association behavior for an entity that this column references.
|
|
96
104
|
*/
|
|
97
105
|
constructor({
|
|
98
106
|
columnName,
|
package/src/EntityFields.ts
CHANGED
|
@@ -2,59 +2,104 @@ import { validate as validateUUID } from 'uuid';
|
|
|
2
2
|
|
|
3
3
|
import { EntityFieldDefinition } from './EntityFieldDefinition';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* {@link EntityFieldDefinition} for a column with a JS string type.
|
|
7
|
+
*/
|
|
5
8
|
export class StringField extends EntityFieldDefinition<string> {
|
|
6
9
|
protected validateInputValueInternal(value: string): boolean {
|
|
7
10
|
return typeof value === 'string';
|
|
8
11
|
}
|
|
9
12
|
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* {@link EntityFieldDefinition} for a column with a JS string type.
|
|
16
|
+
* Enforces that the string is a valid UUID.
|
|
17
|
+
*/
|
|
10
18
|
export class UUIDField extends StringField {
|
|
11
19
|
protected override validateInputValueInternal(value: string): boolean {
|
|
12
20
|
return validateUUID(value);
|
|
13
21
|
}
|
|
14
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* {@link EntityFieldDefinition} for a column with a JS Date type.
|
|
26
|
+
*/
|
|
15
27
|
export class DateField extends EntityFieldDefinition<Date> {
|
|
16
28
|
protected validateInputValueInternal(value: Date): boolean {
|
|
17
29
|
return value instanceof Date;
|
|
18
30
|
}
|
|
19
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* {@link EntityFieldDefinition} for a column with a JS boolean type.
|
|
35
|
+
*/
|
|
20
36
|
export class BooleanField extends EntityFieldDefinition<boolean> {
|
|
21
37
|
protected validateInputValueInternal(value: boolean): boolean {
|
|
22
38
|
return typeof value === 'boolean';
|
|
23
39
|
}
|
|
24
40
|
}
|
|
25
41
|
|
|
42
|
+
/**
|
|
43
|
+
* {@link EntityFieldDefinition} for a column with a JS number type.
|
|
44
|
+
* Enforces that the number is an integer.
|
|
45
|
+
*/
|
|
26
46
|
export class IntField extends EntityFieldDefinition<number> {
|
|
27
47
|
protected validateInputValueInternal(value: number): boolean {
|
|
28
48
|
return typeof value === 'number' && Number.isInteger(value);
|
|
29
49
|
}
|
|
30
50
|
}
|
|
31
51
|
|
|
52
|
+
/**
|
|
53
|
+
* {@link EntityFieldDefinition} for a column with a JS number type.
|
|
54
|
+
* Enforces that the number is a float (which includes integers in JS).
|
|
55
|
+
*/
|
|
32
56
|
export class FloatField extends EntityFieldDefinition<number> {
|
|
33
57
|
protected validateInputValueInternal(value: number): boolean {
|
|
34
58
|
return typeof value === 'number';
|
|
35
59
|
}
|
|
36
60
|
}
|
|
37
61
|
|
|
62
|
+
/**
|
|
63
|
+
* {@link EntityFieldDefinition} for a column with a JS string array type.
|
|
64
|
+
* Enforces that every member of the string array is a string.
|
|
65
|
+
*/
|
|
38
66
|
export class StringArrayField extends EntityFieldDefinition<string[]> {
|
|
39
67
|
protected validateInputValueInternal(value: string[]): boolean {
|
|
40
68
|
return Array.isArray(value) && value.every((subValue) => typeof subValue === 'string');
|
|
41
69
|
}
|
|
42
70
|
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* {@link EntityFieldDefinition} for a column with a JS JSON object type.
|
|
74
|
+
*/
|
|
43
75
|
export class JSONObjectField extends EntityFieldDefinition<object> {
|
|
44
76
|
protected validateInputValueInternal(value: object): boolean {
|
|
45
77
|
return typeof value === 'object' && !Array.isArray(value);
|
|
46
78
|
}
|
|
47
79
|
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* {@link EntityFieldDefinition} for a enum column with a JS string or number type.
|
|
83
|
+
*/
|
|
48
84
|
export class EnumField extends EntityFieldDefinition<string | number> {
|
|
49
85
|
protected validateInputValueInternal(value: string | number): boolean {
|
|
50
86
|
return typeof value === 'number' || typeof value === 'string';
|
|
51
87
|
}
|
|
52
88
|
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* {@link EntityFieldDefinition} for a column with a JS JSON array type.
|
|
92
|
+
*/
|
|
53
93
|
export class JSONArrayField extends EntityFieldDefinition<any[]> {
|
|
54
94
|
protected validateInputValueInternal(value: any[]): boolean {
|
|
55
95
|
return Array.isArray(value);
|
|
56
96
|
}
|
|
57
97
|
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* {@link EntityFieldDefinition} for a column that may be a JS JSON array type.
|
|
101
|
+
* Does not do any validation.
|
|
102
|
+
*/
|
|
58
103
|
export class MaybeJSONArrayField extends EntityFieldDefinition<any | any[]> {
|
|
59
104
|
protected validateInputValueInternal(_value: any): boolean {
|
|
60
105
|
return true;
|
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
|
};
|