From 6020f4bdb43a7ce7e19ca31ace8a4588ef65eb8b Mon Sep 17 00:00:00 2001 From: rishtigupta Date: Tue, 16 Apr 2024 12:17:10 -0700 Subject: [PATCH] feat: add incr api --- src/momento-redis-adapter.ts | 16 +++++++++ test/increment.test.ts | 70 ++++++++++++++++++++++++++++++++++++ test/integration-setup.ts | 5 +++ 3 files changed, 91 insertions(+) create mode 100644 test/increment.test.ts diff --git a/src/momento-redis-adapter.ts b/src/momento-redis-adapter.ts index 94831c6..671ebdd 100644 --- a/src/momento-redis-adapter.ts +++ b/src/momento-redis-adapter.ts @@ -9,6 +9,7 @@ import { CacheDictionarySetFields, CacheFlush, CacheGet, + CacheIncrement, CacheItemGetTtl, CacheSet, CacheSetIfAbsent, @@ -91,6 +92,8 @@ export interface MomentoIORedis { nx: 'NX' ): Promise<'OK' | null>; + incr(key: RedisKey): Promise; + ttl(key: RedisKey): Promise; pttl(key: RedisKey): Promise; @@ -395,6 +398,19 @@ export class MomentoRedisAdapter return null; } + async incr(key: RedisKey): Promise { + const rsp = await this.momentoClient.increment(this.cacheName, key); + if (rsp instanceof CacheIncrement.Success) { + return rsp.value(); + } else if (rsp instanceof CacheIncrement.Error) { + this.emitError('incr', rsp.message(), rsp.errorCode()); + return rsp.message(); + } else { + this.emitError('incr', `unexpected-response ${rsp.toString()}`); + return rsp.toString(); + } + } + async hset( ...args: [ RedisKey, diff --git a/test/increment.test.ts b/test/increment.test.ts new file mode 100644 index 0000000..60f5c22 --- /dev/null +++ b/test/increment.test.ts @@ -0,0 +1,70 @@ +import {SetupIntegrationTest} from './integration-setup'; +import {v4} from 'uuid'; + +const {client} = SetupIntegrationTest(); + +describe('increment', () => { + it('should increment the value of the key by 1 if the key exists', async () => { + const key = v4(); + const value = 5; + + // Set initial key value + await client.set(key, value); + + // Increment the value of the key + const incrResp = await client.incr(key); + expect(incrResp).toBe(value + 1); + }); + + it('should increment the value of the key to 1 if the key does not exists', async () => { + const key = v4(); + + // Increment the value of the key that is not set + const incrResp = await client.incr(key); + expect(incrResp).toBe(1); + }); + + it('should error out if the key contains a value of wrong type or contains a string that can be represented as integer', async () => { + const key = v4(); + const value = 'monkey'; + + // Set initial key value + await client.set(key, value); + + // Increment the value of the key that is not set + try { + await client.incr(key); + } catch (error) { + if (process.env.MOMENTO_ENABLED === 'true') { + const momentoError = error as { + code: string; + context: {code: string; msg: string; op: string; platform: string}; + }; + expect(momentoError.code).toBe('ERR_UNHANDLED_ERROR'); + expect(momentoError.context.code).toBe('FAILED_PRECONDITION_ERROR'); + expect(momentoError.context.msg).toBe( + "System is not in a state required for the operation's execution: 9 FAILED_PRECONDITION: failed to parse value into long" + ); + expect(momentoError.context.op).toBe('incr'); + expect(momentoError.context.platform).toBe('momento'); + } else { + expect(error).toBeInstanceOf(Error); + expect((error as Error).message).toBe( + 'ERR value is not an integer or out of range' + ); + } + } + }); + + it('should increment the value of key that contains a string that can be represented as integer', async () => { + const key = v4(); + const value = '10'; + + // Set initial key value + await client.set(key, value); + + // Increment the value of the key that is not set + const incrResp = await client.incr(key); + expect(incrResp).toBe(11); + }); +}); diff --git a/test/integration-setup.ts b/test/integration-setup.ts index fd941c3..32cf0a7 100644 --- a/test/integration-setup.ts +++ b/test/integration-setup.ts @@ -86,6 +86,11 @@ function setupIntegrationTestWithMomento() { } ); + // If using Momento with Redis backend, close the Redis connection + afterAll(async () => { + await momentoNodeRedisClient.quit(); + }); + return {client: momentoNodeRedisClient}; }