From 6eaabd543b6f017fa02da053f3d452475532a877 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Mon, 6 May 2024 13:41:13 -0700 Subject: [PATCH 1/3] feat: adds support for expire command --- src/momento-redis-adapter.ts | 44 +++--- test/{pexpire.test.ts => expire.test.ts} | 186 +++++++++++++++++++++++ 2 files changed, 209 insertions(+), 21 deletions(-) rename test/{pexpire.test.ts => expire.test.ts} (51%) diff --git a/src/momento-redis-adapter.ts b/src/momento-redis-adapter.ts index 61e184a..671794c 100644 --- a/src/momento-redis-adapter.ts +++ b/src/momento-redis-adapter.ts @@ -110,29 +110,23 @@ export interface MomentoIORedis { pexpire(key: RedisKey, milliseconds: number): Promise; - pexpire( - key: RedisKey, - milliseconds: number, - nx: 'NX' - ): Promise; + pexpire(key: RedisKey, milliseconds: number, nx: 'NX'): Promise; - pexpire( - key: RedisKey, - milliseconds: number, - xx: 'XX' - ): Promise; + pexpire(key: RedisKey, milliseconds: number, xx: 'XX'): Promise; - pexpire( - key: RedisKey, - milliseconds: number, - gt: 'GT' - ): Promise; + pexpire(key: RedisKey, milliseconds: number, gt: 'GT'): Promise; - pexpire( - key: RedisKey, - milliseconds: number, - lt: 'LT' - ): Promise; + pexpire(key: RedisKey, milliseconds: number, lt: 'LT'): Promise; + + expire(key: RedisKey, seconds: number): Promise; + + expire(key: RedisKey, seconds: number, nx: 'NX'): Promise; + + expire(key: RedisKey, seconds: number, xx: 'XX'): Promise; + + expire(key: RedisKey, seconds: number, gt: 'GT'): Promise; + + expire(key: RedisKey, seconds: number, lt: 'LT'): Promise; del(...args: [...keys: RedisKey[]]): Promise; @@ -785,7 +779,7 @@ export class MomentoRedisAdapter key: RedisKey, milliseconds: number, ttlFlagIdentifier?: 'NX' | 'XX' | 'GT' | 'LT' - ): Promise { + ): Promise { let shouldUpdateTtl = true; if (ttlFlagIdentifier === 'NX') { @@ -831,6 +825,14 @@ export class MomentoRedisAdapter return 0; } + async expire( + key: RedisKey, + seconds: number, + ttlFlagIdentifier?: 'NX' | 'XX' | 'GT' | 'LT' + ): Promise { + return await this.pexpire(key, seconds * 1000, ttlFlagIdentifier); + } + async unlink(...args: [...keys: RedisKey[]]): Promise { await this.del(...args); return args.length; diff --git a/test/pexpire.test.ts b/test/expire.test.ts similarity index 51% rename from test/pexpire.test.ts rename to test/expire.test.ts index aa8f2cb..3ee5288 100644 --- a/test/pexpire.test.ts +++ b/test/expire.test.ts @@ -188,3 +188,189 @@ describe('pexpire', () => { expect(pexpireRsp).toBe(0); }); }); + +describe('expire', () => { + it('should update ttl using expire when no flags are specified', async () => { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value); + + // Set ttl of key + const expireRsp = await client.expire(key, 5); + expect(expireRsp).toBe(1); + + // Get ttl of key + const ttlResp = await client.ttl(key); + expect(ttlResp).toBeGreaterThan(2); + }); + + it('should overwrite ttl using expire when no flags are specified', async () => { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 5); + + // Set ttl of key + const expireRsp = await client.expire(key, 1); + expect(expireRsp).toBe(1); + + // Get ttl of key + const ttlResp = await client.ttl(key); + expect(ttlResp).toBeGreaterThan(5); + }); + + it('should not update ttl using expire with nx flag when key exists when momento enabled', async () => { + if (process.env.MOMENTO_ENABLED === 'true') { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value); + + // Set ttl of key using nx flag + const expireRsp = await client.expire(key, 5, 'NX'); + expect(expireRsp).toBe(0); + } + }); + + it('should update ttl using expire with nx flag when key exists with no ttl when redis enabled', async () => { + if (process.env.REDIS_ENABLED === 'true') { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value); + + // Set ttl of key using nx flag + const expireRsp = await client.expire(key, 5, 'NX'); + expect(expireRsp).toBe(1); + } + }); + + it('should not update ttl using expire with nx flag when key exists and ttl on key exists', async () => { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 5); + + // Set ttl of key using nx flag + const expireRsp = await client.expire(key, 10, 'NX'); + expect(expireRsp).toBe(0); + }); + + it('should not update ttl when expire with nx flag when key does not exist', async () => { + const key = v4(); + const key1 = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 5); + + // Set ttl of key using nx flag + const expireRsp = await client.expire(key1, 10, 'NX'); + expect(expireRsp).toBe(0); + }); + + it('should update ttl using expire with xx flag is specified when key exists and ttl on key exits', async () => { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 5); + + // Set ttl of key using xx flag + const expireRsp = await client.expire(key, 10, 'XX'); + expect(expireRsp).toBe(1); + }); + + it('should not update ttl using expire with xx flag when key does not exist', async () => { + const key = v4(); + const key1 = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 5); + + // Set ttl of key using xx flag + const expireRsp = await client.expire(key1, 10, 'XX'); + expect(expireRsp).toBe(0); + }); + + it('should update ttl using expire with gt flag when key exists and new expiry is greater than current one', async () => { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 5); + + // Set ttl of key using gt flag + const expireRsp = await client.expire(key, 10, 'GT'); + expect(expireRsp).toBe(1); + }); + + it('should not update ttl using expire with gt flag when key exists and new expiry is less than the current one', async () => { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 10); + + // Set ttl of key using gt flag + const expireRsp = await client.expire(key, 5, 'GT'); + expect(expireRsp).toBe(0); + }); + + it('should not update ttl using expire with gt flag when key does not exist', async () => { + const key = v4(); + const key1 = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 10); + + // Set ttl of key using gt flag + const expireRsp = await client.expire(key1, 5, 'GT'); + expect(expireRsp).toBe(0); + }); + + it('should update ttl using expire with lt flag when key exists and new expiry is less than current one', async () => { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 10); + + // Set ttl of key using lt flag + const expireRsp = await client.expire(key, 5, 'LT'); + expect(expireRsp).toBe(1); + }); + + it('should not update ttl using expire with lt flag when key exists and new expiry is greater than current one', async () => { + const key = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 5); + + // Set ttl of key using lt flag + const expireRsp = await client.expire(key, 10, 'LT'); + expect(expireRsp).toBe(0); + }); + + it('should not update ttl using expire with lt flag when key does not exist', async () => { + const key = v4(); + const key1 = v4(); + const value = v4(); + + // Set initial key value + await client.set(key, value, 'EX', 5); + + // Set ttl of key using lt flag + const expireRsp = await client.expire(key1, 10, 'LT'); + expect(expireRsp).toBe(0); + }); +}); From 45e345901a7bf9d0deaec2e8c5df59176433ab09 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Mon, 6 May 2024 13:45:18 -0700 Subject: [PATCH 2/3] fix: broken test --- test/expire.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/expire.test.ts b/test/expire.test.ts index 3ee5288..d580c9f 100644 --- a/test/expire.test.ts +++ b/test/expire.test.ts @@ -214,7 +214,7 @@ describe('expire', () => { await client.set(key, value, 'EX', 5); // Set ttl of key - const expireRsp = await client.expire(key, 1); + const expireRsp = await client.expire(key, 10); expect(expireRsp).toBe(1); // Get ttl of key From 8b8472fda8d997f76f74f089ac3e172296092968 Mon Sep 17 00:00:00 2001 From: eaddingtonwhite <5491827+ellery44@users.noreply.github.com> Date: Mon, 6 May 2024 13:54:37 -0700 Subject: [PATCH 3/3] chore: add more explicit unit test --- test/expire.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/expire.test.ts b/test/expire.test.ts index d580c9f..76e9efd 100644 --- a/test/expire.test.ts +++ b/test/expire.test.ts @@ -187,6 +187,12 @@ describe('pexpire', () => { const pexpireRsp = await client.pexpire(key1, 10000, 'LT'); expect(pexpireRsp).toBe(0); }); + + it('should return 0 using pexpire when key does not exist', async () => { + // Set ttl of non-existent key + const pexpireRsp = await client.pexpire(v4(), 10000); + expect(pexpireRsp).toBe(0); + }); }); describe('expire', () => { @@ -373,4 +379,10 @@ describe('expire', () => { const expireRsp = await client.expire(key1, 10, 'LT'); expect(expireRsp).toBe(0); }); + + it('should return 0 using expire when key does not exist', async () => { + // Set ttl of non-existent key + const expireRsp = await client.expire(v4(), 10000); + expect(expireRsp).toBe(0); + }); });