Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {
AlwaysAllowPrivacyPolicyRule,
AuthorizationResultBasedEntityLoader,
Entity,
EntityCompanionDefinition,
EntityCompanionProvider,
EntityConfiguration,
EntityConstructionUtils,
EntityPrivacyPolicy,
EntitySecondaryCacheLoader,
IEntityMetricsAdapter,
Expand Down Expand Up @@ -161,6 +163,32 @@ class TestSecondaryLocalMemoryCacheLoader extends EntitySecondaryCacheLoader<
> {
public databaseLoadCount = 0;

constructor(
secondaryEntityCache: LocalMemorySecondaryEntityCache<
LocalMemoryTestEntityFields,
'id',
TestLoadParams
>,
constructionUtils: EntityConstructionUtils<
LocalMemoryTestEntityFields,
'id',
TestViewerContext,
LocalMemoryTestEntity,
LocalMemoryTestEntityPrivacyPolicy,
keyof LocalMemoryTestEntityFields
>,
private readonly entityLoader: AuthorizationResultBasedEntityLoader<
LocalMemoryTestEntityFields,
'id',
TestViewerContext,
LocalMemoryTestEntity,
LocalMemoryTestEntityPrivacyPolicy,
keyof LocalMemoryTestEntityFields
>,
) {
super(secondaryEntityCache, constructionUtils);
}

protected async fetchObjectsFromDatabaseAsync(
loadParamsArray: readonly Readonly<TestLoadParams>[],
): Promise<ReadonlyMap<Readonly<TestLoadParams>, Readonly<LocalMemoryTestEntityFields> | null>> {
Expand Down Expand Up @@ -193,6 +221,10 @@ describe(LocalMemorySecondaryEntityCache, () => {
localMemoryTestEntityConfiguration,
createTTLCache<LocalMemoryTestEntityFields>(),
),
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(
LocalMemoryTestEntity,
viewerContext,
),
LocalMemoryTestEntity.loaderWithAuthorizationResults(viewerContext),
);

Expand Down Expand Up @@ -229,6 +261,10 @@ describe(LocalMemorySecondaryEntityCache, () => {
localMemoryTestEntityConfiguration,
createTTLCache<LocalMemoryTestEntityFields>(),
),
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(
LocalMemoryTestEntity,
viewerContext,
),
LocalMemoryTestEntity.loaderWithAuthorizationResults(viewerContext),
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { EntitySecondaryCacheLoader, mapMapAsync, ViewerContext } from '@expo/entity';
import {
AuthorizationResultBasedEntityLoader,
EntityConstructionUtils,
EntitySecondaryCacheLoader,
mapMapAsync,
ViewerContext,
} from '@expo/entity';
import {
GenericRedisCacheContext,
RedisCacheInvalidationStrategy,
Expand Down Expand Up @@ -33,6 +39,28 @@ class TestSecondaryRedisCacheLoader extends EntitySecondaryCacheLoader<
> {
public databaseLoadCount = 0;

constructor(
secondaryEntityCache: RedisSecondaryEntityCache<RedisTestEntityFields, 'id', TestLoadParams>,
constructionUtils: EntityConstructionUtils<
RedisTestEntityFields,
'id',
TestViewerContext,
RedisTestEntity,
RedisTestEntityPrivacyPolicy,
keyof RedisTestEntityFields
>,
private readonly entityLoader: AuthorizationResultBasedEntityLoader<
RedisTestEntityFields,
'id',
TestViewerContext,
RedisTestEntity,
RedisTestEntityPrivacyPolicy,
keyof RedisTestEntityFields
>,
) {
super(secondaryEntityCache, constructionUtils);
}

protected async fetchObjectsFromDatabaseAsync(
loadParamsArray: readonly Readonly<TestLoadParams>[],
): Promise<ReadonlyMap<Readonly<TestLoadParams>, Readonly<RedisTestEntityFields> | null>> {
Expand Down Expand Up @@ -93,6 +121,7 @@ describe(RedisSecondaryEntityCache, () => {
genericRedisCacheContext,
(loadParams) => `test-key-${loadParams.id}`,
),
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(RedisTestEntity, viewerContext),
RedisTestEntity.loaderWithAuthorizationResults(viewerContext),
);

Expand Down Expand Up @@ -132,6 +161,7 @@ describe(RedisSecondaryEntityCache, () => {
genericRedisCacheContext,
(loadParams) => `test-key-${loadParams.id}`,
),
EntitySecondaryCacheLoader.getConstructionUtilsForEntityClass(RedisTestEntity, viewerContext),
RedisTestEntity.loaderWithAuthorizationResults(viewerContext),
);

Expand Down
13 changes: 1 addition & 12 deletions packages/entity/src/AuthorizationResultBasedEntityLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
EntityConfiguration,
} from './EntityConfiguration';
import { EntityConstructionUtils } from './EntityConstructionUtils';
import { EntityInvalidationUtils } from './EntityInvalidationUtils';
import { EntityPrivacyPolicy } from './EntityPrivacyPolicy';
import { EntityQueryContext } from './EntityQueryContext';
import { ReadonlyEntity } from './ReadonlyEntity';
Expand All @@ -19,7 +18,6 @@ import { CompositeFieldHolder, CompositeFieldValueHolder } from './internal/Comp
import { CompositeFieldValueMap } from './internal/CompositeFieldValueMap';
import { EntityDataManager } from './internal/EntityDataManager';
import { SingleFieldHolder, SingleFieldValueHolder } from './internal/SingleFieldHolder';
import { IEntityMetricsAdapter } from './metrics/IEntityMetricsAdapter';
import { mapKeys, mapMap } from './utils/collections/maps';
import { areSetsEqual } from './utils/collections/sets';

Expand Down Expand Up @@ -55,16 +53,7 @@ export class AuthorizationResultBasedEntityLoader<
TSelectedFields
>,
private readonly dataManager: EntityDataManager<TFields, TIDField>,
protected readonly metricsAdapter: IEntityMetricsAdapter,
public readonly invalidationUtils: EntityInvalidationUtils<
TFields,
TIDField,
TViewerContext,
TEntity,
TPrivacyPolicy,
TSelectedFields
>,
public readonly constructionUtils: EntityConstructionUtils<
private readonly constructionUtils: EntityConstructionUtils<
TFields,
TIDField,
TViewerContext,
Expand Down
66 changes: 34 additions & 32 deletions packages/entity/src/AuthorizationResultBasedEntityMutator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,17 @@ export class AuthorizationResultBasedCreateMutator<
previousValue: null,
cascadingDeleteCause: null,
});
const invalidationUtils = this.entityLoaderFactory.invalidationUtils();
const constructionUtils = this.entityLoaderFactory.constructionUtils(
this.viewerContext,
queryContext,
{
previousValue: null,
cascadingDeleteCause: null,
},
);

const temporaryEntityForPrivacyCheck = entityLoader.constructionUtils.constructEntity({
const temporaryEntityForPrivacyCheck = constructionUtils.constructEntity({
[this.entityConfiguration.idField]: '00000000-0000-0000-0000-000000000000', // zero UUID
...this.fieldsForEntity,
} as unknown as TFields);
Expand Down Expand Up @@ -376,14 +385,13 @@ export class AuthorizationResultBasedCreateMutator<
// Invalidate all caches for the new entity so that any previously-negatively-cached loads
// are removed from the caches.
queryContext.appendPostCommitInvalidationCallback(async () => {
entityLoader.invalidationUtils.invalidateFieldsForTransaction(queryContext, insertResult);
await entityLoader.invalidationUtils.invalidateFieldsAsync(insertResult);
invalidationUtils.invalidateFieldsForTransaction(queryContext, insertResult);
await invalidationUtils.invalidateFieldsAsync(insertResult);
});

entityLoader.invalidationUtils.invalidateFieldsForTransaction(queryContext, insertResult);
invalidationUtils.invalidateFieldsForTransaction(queryContext, insertResult);

const unauthorizedEntityAfterInsert =
entityLoader.constructionUtils.constructEntity(insertResult);
const unauthorizedEntityAfterInsert = constructionUtils.constructEntity(insertResult);
const newEntity = await enforceAsyncResult(
entityLoader.loadByIDAsync(unauthorizedEntityAfterInsert.getID()),
);
Expand Down Expand Up @@ -542,10 +550,17 @@ export class AuthorizationResultBasedUpdateMutator<
previousValue: this.originalEntity,
cascadingDeleteCause: this.cascadingDeleteCause,
});

const entityAboutToBeUpdated = entityLoader.constructionUtils.constructEntity(
this.fieldsForEntity,
const invalidationUtils = this.entityLoaderFactory.invalidationUtils();
const constructionUtils = this.entityLoaderFactory.constructionUtils(
this.viewerContext,
queryContext,
{
previousValue: this.originalEntity,
cascadingDeleteCause: this.cascadingDeleteCause,
},
);

const entityAboutToBeUpdated = constructionUtils.constructEntity(this.fieldsForEntity);
const authorizeUpdateResult = await asyncResult(
this.privacyPolicy.authorizeUpdateAsync(
this.viewerContext,
Expand Down Expand Up @@ -609,30 +624,22 @@ export class AuthorizationResultBasedUpdateMutator<
// version of the entity.

queryContext.appendPostCommitInvalidationCallback(async () => {
entityLoader.invalidationUtils.invalidateFieldsForTransaction(
invalidationUtils.invalidateFieldsForTransaction(
queryContext,
this.originalEntity.getAllDatabaseFields(),
);
entityLoader.invalidationUtils.invalidateFieldsForTransaction(
queryContext,
this.fieldsForEntity,
);
invalidationUtils.invalidateFieldsForTransaction(queryContext, this.fieldsForEntity);
await Promise.all([
entityLoader.invalidationUtils.invalidateFieldsAsync(
this.originalEntity.getAllDatabaseFields(),
),
entityLoader.invalidationUtils.invalidateFieldsAsync(this.fieldsForEntity),
invalidationUtils.invalidateFieldsAsync(this.originalEntity.getAllDatabaseFields()),
invalidationUtils.invalidateFieldsAsync(this.fieldsForEntity),
]);
});

entityLoader.invalidationUtils.invalidateFieldsForTransaction(
invalidationUtils.invalidateFieldsForTransaction(
queryContext,
this.originalEntity.getAllDatabaseFields(),
);
entityLoader.invalidationUtils.invalidateFieldsForTransaction(
queryContext,
this.fieldsForEntity,
);
invalidationUtils.invalidateFieldsForTransaction(queryContext, this.fieldsForEntity);

const updatedEntity = await enforceAsyncResult(
entityLoader.loadByIDAsync(entityAboutToBeUpdated.getID()),
Expand Down Expand Up @@ -850,23 +857,18 @@ export class AuthorizationResultBasedDeleteMutator<
);
}

const entityLoader = this.entityLoaderFactory.forLoad(this.viewerContext, queryContext, {
previousValue: null,
cascadingDeleteCause: this.cascadingDeleteCause,
});
const invalidationUtils = this.entityLoaderFactory.invalidationUtils();

// Invalidate all caches for the entity so that any previously-cached loads
// are removed from the caches.
queryContext.appendPostCommitInvalidationCallback(async () => {
entityLoader.invalidationUtils.invalidateFieldsForTransaction(
invalidationUtils.invalidateFieldsForTransaction(
queryContext,
this.entity.getAllDatabaseFields(),
);
await entityLoader.invalidationUtils.invalidateFieldsAsync(
this.entity.getAllDatabaseFields(),
);
await invalidationUtils.invalidateFieldsAsync(this.entity.getAllDatabaseFields());
});
entityLoader.invalidationUtils.invalidateFieldsForTransaction(
invalidationUtils.invalidateFieldsForTransaction(
queryContext,
this.entity.getAllDatabaseFields(),
);
Expand Down
32 changes: 0 additions & 32 deletions packages/entity/src/EntityLoader.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { AuthorizationResultBasedEntityLoader } from './AuthorizationResultBasedEntityLoader';
import { EnforcingEntityLoader } from './EnforcingEntityLoader';
import { IEntityClass } from './Entity';
import { EntityConstructionUtils } from './EntityConstructionUtils';
import { EntityInvalidationUtils } from './EntityInvalidationUtils';
import { EntityPrivacyPolicy } from './EntityPrivacyPolicy';
import { EntityQueryContext } from './EntityQueryContext';
import { ReadonlyEntity } from './ReadonlyEntity';
Expand Down Expand Up @@ -74,34 +72,4 @@ export class EntityLoader<
.getLoaderFactory()
.forLoad(this.queryContext, { previousValue: null, cascadingDeleteCause: null });
}

/**
* Entity cache invalidation utilities.
* Calling into these should only be necessary in rare cases.
*/
public invalidationUtils(): EntityInvalidationUtils<
TFields,
TIDField,
TViewerContext,
TEntity,
TPrivacyPolicy,
TSelectedFields
> {
return this.withAuthorizationResults().invalidationUtils;
}

/**
* Entity construction and validation utilities.
* Calling into these should only be necessary in rare cases.
*/
public constructionUtils(): EntityConstructionUtils<
TFields,
TIDField,
TViewerContext,
TEntity,
TPrivacyPolicy,
TSelectedFields
> {
return this.withAuthorizationResults().constructionUtils;
}
}
Loading