Skip to content

Commit

Permalink
BREAKING CHANGE: make using non-enforcing entity loader explicit (#238)
Browse files Browse the repository at this point in the history
  • Loading branch information
wschurman authored Jun 12, 2024
1 parent 6569486 commit 2edc7af
Show file tree
Hide file tree
Showing 18 changed files with 841 additions and 559 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ describe(GenericLocalMemoryCacher, () => {
// simulate non existent db fetch, should write negative result ('') to cache
const nonExistentId = uuidv4();

const entityNonExistentResult =
await LocalMemoryTestEntity.loader(viewerContext).loadByIDAsync(nonExistentId);
const entityNonExistentResult = await LocalMemoryTestEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(nonExistentId);
expect(entityNonExistentResult.ok).toBe(false);

const nonExistentCachedResult = await entitySpecificGenericCacher.loadManyAsync([
Expand All @@ -75,12 +76,15 @@ describe(GenericLocalMemoryCacher, () => {
});

// load again through entities framework to ensure it reads negative result
const entityNonExistentResult2 =
await LocalMemoryTestEntity.loader(viewerContext).loadByIDAsync(nonExistentId);
const entityNonExistentResult2 = await LocalMemoryTestEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(nonExistentId);
expect(entityNonExistentResult2.ok).toBe(false);

// invalidate from cache to ensure it invalidates correctly
await LocalMemoryTestEntity.loader(viewerContext).invalidateFieldsAsync(entity1.getAllFields());
await LocalMemoryTestEntity.loader(viewerContext)
.withAuthorizationResults()
.invalidateFieldsAsync(entity1.getAllFields());
const cachedResultMiss = await entitySpecificGenericCacher.loadManyAsync([
cacheKeyMaker('id', entity1.getID()),
]);
Expand Down Expand Up @@ -131,8 +135,9 @@ describe(GenericLocalMemoryCacher, () => {
// a non existent db fetch should try to write negative result ('') but it's a noop cache, so it should be a miss
const nonExistentId = uuidv4();

const entityNonExistentResult =
await LocalMemoryTestEntity.loader(viewerContext).loadByIDAsync(nonExistentId);
const entityNonExistentResult = await LocalMemoryTestEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(nonExistentId);
expect(entityNonExistentResult.ok).toBe(false);

const nonExistentCachedResult = await entitySpecificGenericCacher.loadManyAsync([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,23 @@ describe(GenericRedisCacher, () => {

// simulate non existent db fetch, should write negative result ('') to cache
const nonExistentId = uuidv4();
const entityNonExistentResult =
await RedisTestEntity.loader(viewerContext).loadByIDAsync(nonExistentId);
const entityNonExistentResult = await RedisTestEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(nonExistentId);
expect(entityNonExistentResult.ok).toBe(false);
const cacheKeyNonExistent = cacheKeyMaker('id', nonExistentId);
const nonExistentCachedValue = await redis.get(cacheKeyNonExistent);
expect(nonExistentCachedValue).toEqual('');
// load again through entities framework to ensure it reads negative result
const entityNonExistentResult2 =
await RedisTestEntity.loader(viewerContext).loadByIDAsync(nonExistentId);
const entityNonExistentResult2 = await RedisTestEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(nonExistentId);
expect(entityNonExistentResult2.ok).toBe(false);

// invalidate from cache to ensure it invalidates correctly in both caches
await RedisTestEntity.loader(viewerContext).invalidateFieldsAsync(entity1.getAllFields());
await RedisTestEntity.loader(viewerContext)
.withAuthorizationResults()
.invalidateFieldsAsync(entity1.getAllFields());
await expect(redis.get(cacheKeyEntity1)).resolves.toBeNull();
await expect(redis.get(cacheKeyEntity1NameField)).resolves.toBeNull();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ describe(GenericRedisCacher, () => {
// simulate non existent db fetch, should write negative result ('') to cache
const nonExistentId = uuidv4();

const entityNonExistentResult =
await RedisTestEntity.loader(viewerContext).loadByIDAsync(nonExistentId);
const entityNonExistentResult = await RedisTestEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(nonExistentId);
expect(entityNonExistentResult.ok).toBe(false);

const nonExistentCachedValue = await (genericRedisCacheContext.redisClient as Redis).get(
Expand All @@ -77,12 +78,15 @@ describe(GenericRedisCacher, () => {
expect(nonExistentCachedValue).toEqual('');

// load again through entities framework to ensure it reads negative result
const entityNonExistentResult2 =
await RedisTestEntity.loader(viewerContext).loadByIDAsync(nonExistentId);
const entityNonExistentResult2 = await RedisTestEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(nonExistentId);
expect(entityNonExistentResult2.ok).toBe(false);

// invalidate from cache to ensure it invalidates correctly
await RedisTestEntity.loader(viewerContext).invalidateFieldsAsync(entity1.getAllFields());
await RedisTestEntity.loader(viewerContext)
.withAuthorizationResults()
.invalidateFieldsAsync(entity1.getAllFields());
const cachedValueNull = await (genericRedisCacheContext.redisClient as Redis).get(
cacheKeyMaker('id', entity1.getID()),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
OrderByOrdering,
createUnitTestEntityCompanionProvider,
enforceResultsAsync,
ViewerContext,
TransactionIsolationLevel,
} from '@expo/entity';
Expand Down Expand Up @@ -92,7 +91,7 @@ describe('postgres entity integration', () => {
PostgresTestEntity.creator(vc1).setField('name', 'hello').createAsync(),
);

await enforceAsyncResult(PostgresTestEntity.loader(vc1).loadByIDAsync(firstEntity.getID()));
await PostgresTestEntity.loader(vc1).enforcing().loadByIDAsync(firstEntity.getID());

const errorToThrow = new Error('Intentional error');

Expand All @@ -111,9 +110,9 @@ describe('postgres entity integration', () => {
),
).rejects.toEqual(errorToThrow);

const entities = await enforceResultsAsync(
PostgresTestEntity.loader(vc1).loadManyByFieldEqualingAsync('name', 'hello'),
);
const entities = await PostgresTestEntity.loader(vc1)
.enforcing()
.loadManyByFieldEqualingAsync('name', 'hello');
expect(entities).toHaveLength(1);
});

Expand Down
12 changes: 9 additions & 3 deletions packages/entity-example/src/routers/notesRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ router.get('/', async (ctx) => {

router.get('/:id', async (ctx) => {
const viewerContext = ctx.state.viewerContext;
const noteResult = await NoteEntity.loader(viewerContext).loadByIDAsync(ctx.params['id']!);
const noteResult = await NoteEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(ctx.params['id']!);
if (!noteResult.ok) {
ctx.throw(403, noteResult.reason);
return;
Expand Down Expand Up @@ -72,7 +74,9 @@ router.put('/:id', async (ctx) => {
const viewerContext = ctx.state.viewerContext;
const { title, body } = ctx.request.body as any;

const noteLoadResult = await NoteEntity.loader(viewerContext).loadByIDAsync(ctx.params['id']!);
const noteLoadResult = await NoteEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(ctx.params['id']!);
if (!noteLoadResult.ok) {
ctx.throw(403, noteLoadResult.reason);
return;
Expand All @@ -95,7 +99,9 @@ router.put('/:id', async (ctx) => {
router.delete('/:id', async (ctx) => {
const viewerContext = ctx.state.viewerContext;

const noteLoadResult = await NoteEntity.loader(viewerContext).loadByIDAsync(ctx.params['id']!);
const noteLoadResult = await NoteEntity.loader(viewerContext)
.withAuthorizationResults()
.loadByIDAsync(ctx.params['id']!);
if (!noteLoadResult.ok) {
ctx.throw(403, noteLoadResult.reason);
return;
Expand Down
Loading

0 comments on commit 2edc7af

Please sign in to comment.