import { ViewerContext } from '@expo/entity' ; import { enforceAsyncResult } from '@expo/results' ; import Redis from 'ioredis' ; import { URL } from 'url' ; import { v4 as uuidv4 } from 'uuid' ; import RedisCacheAdapter , { RedisCacheAdapterContext } from '../RedisCacheAdapter' ; import RedisTestEntity from '../testfixtures/RedisTestEntity' ; import { createRedisIntegrationTestEntityCompanionProvider } from '../testfixtures/createRedisIntegrationTestEntityCompanionProvider' ; class TestViewerContext extends ViewerContext { } describe ( RedisCacheAdapter , ( ) => { let redisCacheAdapterContext ; beforeAll ( ( ) => { redisCacheAdapterContext = { redisClient : new Redis ( new URL ( process . env [ 'REDIS_URL' ] ! ) . toString ( ) ) , makeKeyFn ( ... parts ) { const delimiter = ':' ; const escapedParts = parts . map ( ( part ) => part . replace ( '\\' , '\\\\' ) . replace ( delimiter , `\\${ delimiter }` ) ) ; return escapedParts . join ( delimiter ) ; } , cacheKeyPrefix : 'test-' , cacheKeyVersion : 1 , ttlSecondsPositive : 86400 , ttlSecondsNegative : 600 , } ; } ) ; beforeEach ( async ( ) => { await redisCacheAdapterContext . redisClient . flushdb ( ) ; } ) ; afterAll ( async ( ) => { redisCacheAdapterContext . redisClient . disconnect ( ) ; } ) ; it ( 'has correct caching behavior' , async ( ) => { const viewerContext = new TestViewerContext ( createRedisIntegrationTestEntityCompanionProvider ( redisCacheAdapterContext ) ) ; const cacheAdapter = viewerContext . entityCompanionProvider . getCompanionForEntity ( RedisTestEntity , RedisTestEntity . getCompanionDefinition ( ) ) [ 'tableDataCoordinator' ] [ 'cacheAdapter' ] ; const cacheKeyMaker = cacheAdapter [ 'makeCacheKey' ] . bind ( cacheAdapter ) ; const entity1Created = await RedisTestEntity . creator ( viewerContext ) . setField ( 'name' , 'blah' ) . enforceCreateAsync ( ) ; const entity1 = await RedisTestEntity . loader ( viewerContext ) . enforcing ( ) . loadByIDAsync ( entity1Created . getID ( ) ) ; const cachedJSON = await redisCacheAdapterContext . redisClient . get ( cacheKeyMaker ( 'id' , entity1 . getID ( ) ) ) ; const cachedValue = JSON . parse ( cachedJSON ! ) ; expect ( cachedValue ) . toMatchObject ( { id : entity1 . getID ( ) , name : 'blah' , } ) ; const nonExistentId = uuidv4 ( ) ; const entityNonExistentResult = await RedisTestEntity . loader ( viewerContext ) . loadByIDAsync ( nonExistentId ) ; expect ( entityNonExistentResult . ok ) . toBe ( false ) ; const nonExistentCachedValue = await redisCacheAdapterContext . redisClient . get ( cacheKeyMaker ( 'id' , nonExistentId ) ) ; expect ( nonExistentCachedValue ) . toEqual ( '' ) ; const entityNonExistentResult2 = await RedisTestEntity . loader ( viewerContext ) . loadByIDAsync ( nonExistentId ) ; expect ( entityNonExistentResult2 . ok ) . toBe ( false ) ; await RedisTestEntity . loader ( viewerContext ) . invalidateFieldsAsync ( entity1 . getAllFields ( ) ) ; const cachedValueNull = await redisCacheAdapterContext . redisClient . get ( cacheKeyMaker ( 'id' , entity1 . getID ( ) ) ) ; expect ( cachedValueNull ) . toBe ( null ) ; } ) ; it ( 'caches and restores date fields' , async ( ) => { const viewerContext = new TestViewerContext ( createRedisIntegrationTestEntityCompanionProvider ( redisCacheAdapterContext ) ) ; const date = new Date ( ) ; const entity1 = await enforceAsyncResult ( RedisTestEntity . creator ( viewerContext ) . setField ( 'dateField' , date ) . createAsync ( ) ) ; expect ( entity1 . getField ( 'dateField' ) ) . toEqual ( date ) ; const entity2 = await RedisTestEntity . loader ( viewerContext ) . enforcing ( ) . loadByIDAsync ( entity1 . getID ( ) ) ; expect ( entity2 . getField ( 'dateField' ) ) . toEqual ( date ) ; const vc2 = new TestViewerContext ( createRedisIntegrationTestEntityCompanionProvider ( redisCacheAdapterContext ) ) ; const entity3 = await RedisTestEntity . loader ( vc2 ) . enforcing ( ) . loadByIDAsync ( entity1 . getID ( ) ) ; expect ( entity3 . getField ( 'dateField' ) ) . toEqual ( date ) ; } ) ; it ( 'caches and restores empty string field keys' , async ( ) => { const viewerContext = new TestViewerContext ( createRedisIntegrationTestEntityCompanionProvider ( redisCacheAdapterContext ) ) ; const entity1 = await enforceAsyncResult ( RedisTestEntity . creator ( viewerContext ) . setField ( 'name' , '' ) . createAsync ( ) ) ; const entity2 = await RedisTestEntity . loader ( viewerContext ) . enforcing ( ) . loadByFieldEqualingAsync ( 'name' , '' ) ; expect ( entity2 ?. getID ( ) ) . toEqual ( entity1 . getID ( ) ) ; const vc2 = new TestViewerContext ( createRedisIntegrationTestEntityCompanionProvider ( redisCacheAdapterContext ) ) ; const entity3 = await RedisTestEntity . loader ( vc2 ) . enforcing ( ) . loadByFieldEqualingAsync ( 'name' , '' ) ; expect ( entity3 ?. getID ( ) ) . toEqual ( entity1 . getID ( ) ) ; } ) ; } ) ;