Skip to content

Commit b6ce030

Browse files
authored
feat(all): atomic get and set (#14)
* atomic get and set * remove import * types * update retun value * types
1 parent a96284d commit b6ce030

File tree

3 files changed

+40
-5
lines changed

3 files changed

+40
-5
lines changed

src/redis.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import {
33
RedisClientType,
44
RedisDefaultModules,
55
RedisFunctions,
6-
RedisModules, RedisScripts
6+
RedisModules,
7+
RedisScripts
78
} from 'redis';
89
import {Milliseconds, RedisStore, TConfig, TMset} from './types';
910
import {ScanReply} from '@redis/client/dist/lib/commands/SCAN';
11+
import {RedisCommandRawReply} from "@redis/client/dist/lib/commands";
1012

1113
export const redisStore = async (config?: TConfig): Promise<RedisStore> => {
1214
const redisCache: RedisClientType<RedisDefaultModules & RedisModules, RedisFunctions, RedisScripts> = createClient(config);
@@ -110,6 +112,16 @@ class buildRedisStoreWithConfig implements RedisStore {
110112
return await this.redisCache.scan(cursor, { MATCH: pattern, COUNT: count });
111113
}
112114

115+
public async atomicGetAndSet(key: string, updateFunction: (val: any) => any): Promise<RedisCommandRawReply> {
116+
await this.redisCache.watch(key);
117+
const val = await this.get(key);
118+
return await this.redisCache.multi().set(key, updateFunction(val)).get(key).exec();
119+
}
120+
121+
public async flushAll() {
122+
await this.redisCache.flushAll();
123+
}
124+
113125
public getClient(): RedisClientType<RedisDefaultModules & RedisModules, RedisFunctions, RedisScripts> {
114126
return this.redisCache;
115127
}

src/types/RedisStore.interface.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,9 @@ export interface RedisStore extends Store {
88
getClient(): RedisClientType<RedisDefaultModules & RedisModules, RedisFunctions, RedisScripts>;
99

1010
scan(pattern: string, cursor? :number, count?: number): Promise<ScanReply>;
11+
12+
atomicGetAndSet(key: string, updateFunction: (val: any) => any): Promise<any>;
13+
14+
flushAll(): Promise<void>
15+
1116
}

test/redis.test.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import {redisStore} from '../src';
2-
import {RedisStore} from "../src/types";
3-
import {describe, beforeEach, it, expect} from "vitest";
1+
import { redisStore } from '../src';
2+
import { RedisStore } from "../src/types";
3+
import { describe, beforeEach, it, expect, afterEach } from "vitest";
44

55
let redisClient: RedisStore
66
const config = {
@@ -12,10 +12,16 @@ const config = {
1212
db: 0,
1313
ttl: 1000 * 60,
1414
};
15+
1516
beforeEach(async () => {
1617
redisClient = await redisStore(config);
1718
await redisClient.reset();
1819
});
20+
21+
afterEach(async () => {
22+
await redisClient.flushAll()
23+
});
24+
1925
describe('Redis Store', () => {
2026

2127
it('should set and get a value', async () => {
@@ -80,7 +86,7 @@ describe('Redis Store', () => {
8086
expect(retrievedTtl).toBeLessThanOrEqual(ttl / 1000); // Redis returns TTL in seconds
8187
});
8288

83-
it(`should return scan result by pattern`, async () => {
89+
it('should return scan result by pattern', async () => {
8490
const key1 = 'ttl:a:b';
8591
const key2 = 'ttl1:a:b';
8692
const key3 = 'ttl:a:b1';
@@ -106,4 +112,16 @@ describe('Redis Store', () => {
106112
expect(thirdScanWithCount.keys).toEqual([]);
107113
expect(thirdScanWithCount.cursor).equal(0);
108114
});
115+
116+
it('should inc value by one', async () => {
117+
await redisClient.set('test', { a: 1 });
118+
const res = await redisClient.atomicGetAndSet('test', (obj) => {
119+
const parsedVal = obj;
120+
parsedVal.a = parsedVal.a + 1;
121+
return JSON.stringify(parsedVal);
122+
});
123+
expect(JSON.parse(res[1])).to.deep.equal({ a: 2 });
124+
expect(res[0]).to.deep.equal("OK");
125+
})
126+
109127
});

0 commit comments

Comments
 (0)