Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add incr api #28

Merged
merged 5 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
20 changes: 20 additions & 0 deletions src/momento-redis-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
CacheDictionarySetFields,
CacheFlush,
CacheGet,
CacheIncrement,
CacheItemGetTtl,
CacheSet,
CacheSetIfAbsent,
Expand Down Expand Up @@ -91,6 +92,8 @@ export interface MomentoIORedis {
nx: 'NX'
): Promise<'OK' | null>;

incr(key: RedisKey): Promise<number | null>;

ttl(key: RedisKey): Promise<number | null>;

pttl(key: RedisKey): Promise<number | null>;
Expand Down Expand Up @@ -395,6 +398,23 @@ export class MomentoRedisAdapter
return null;
}

async incr(key: RedisKey): Promise<number | null> {
if (this.useCompression) {
this.emitError('incr', 'compression-not-supported');
rishtigupta marked this conversation as resolved.
Show resolved Hide resolved
return null;
}

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());
} else {
this.emitError('incr', `unexpected-response ${rsp.toString()}`);
}
return null;
}

async hset(
...args: [
RedisKey,
Expand Down
28 changes: 28 additions & 0 deletions test/increment-compression.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {v4} from 'uuid';

import {SetupIntegrationTest} from './integration-setup';

const {client} = SetupIntegrationTest();

describe('increment, with compression client', () => {
it('should return error saying compression not supported', async () => {
const key = v4();
const value = 5;

// Set initial key value
await client.set(key, value);

// Increment the value of the key
try {
await client.incr(key);
} catch (error) {
const momentoError = error as {
code: string;
context: {code: string; msg: string; op: string; platform: string};
};
expect(momentoError.context.op).toBe('incr');
expect(momentoError.context.platform).toBe('momento');
expect(momentoError.context.msg).toBe('compression-not-supported');
}
});
});
70 changes: 70 additions & 0 deletions test/increment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {SetupIntegrationTest} from './integration-setup';
import {v4} from 'uuid';

const {client} = SetupIntegrationTest(false);

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);
});
});
12 changes: 4 additions & 8 deletions test/integration-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ export function testCacheName(): string {
return name + v4();
}

function useCompression(): boolean {
return process.env.COMPRESSION === 'true';
}
rishtigupta marked this conversation as resolved.
Show resolved Hide resolved

const deleteCacheIfExists = async (momento: CacheClient, cacheName: string) => {
const deleteResponse = await momento.deleteCache(cacheName);
if (deleteResponse instanceof DeleteCache.Error) {
Expand All @@ -45,17 +41,17 @@ export function isRedisBackedTest() {
return process.env.MOMENTO_ENABLED !== 'true';
}

export function SetupIntegrationTest(): {
export function SetupIntegrationTest(useCompression = true): {
client: MomentoIORedis;
} {
if (isRedisBackedTest()) {
return setupIntegrationTestWithRedis();
} else {
return setupIntegrationTestWithMomento();
return setupIntegrationTestWithMomento(useCompression);
}
}

function setupIntegrationTestWithMomento() {
function setupIntegrationTestWithMomento(useCompression = true) {
const cacheName = testCacheName();

beforeAll(async () => {
Expand All @@ -82,7 +78,7 @@ function setupIntegrationTestWithMomento() {
momentoClient,
cacheName,
{
useCompression: useCompression(),
useCompression: useCompression,
}
);

Expand Down
Loading