Skip to content

Commit ccddaba

Browse files
committed
- Added RESTORE functionality
1 parent a7d5bc7 commit ccddaba

File tree

3 files changed

+167
-0
lines changed

3 files changed

+167
-0
lines changed

packages/client/lib/cluster/commands.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ import * as PTTL from '../commands/PTTL';
110110
import * as PUBLISH from '../commands/PUBLISH';
111111
import * as RENAME from '../commands/RENAME';
112112
import * as RENAMENX from '../commands/RENAMENX';
113+
import * as RESTORE from '../commands/RESTORE';
113114
import * as RPOP_COUNT from '../commands/RPOP_COUNT';
114115
import * as RPOP from '../commands/RPOP';
115116
import * as RPOPLPUSH from '../commands/RPOPLPUSH';
@@ -434,6 +435,8 @@ export default {
434435
rename: RENAME,
435436
RENAMENX,
436437
renameNX: RENAMENX,
438+
RESTORE,
439+
restore: RESTORE,
437440
RPOP_COUNT,
438441
rPopCount: RPOP_COUNT,
439442
RPOP,
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { strict as assert } from 'assert';
2+
import testUtils, { GLOBAL } from '../test-utils';
3+
import { transformArguments } from './RESTORE';
4+
5+
describe('RESTORE', () => {
6+
describe('transformArguments', () => {
7+
it('parses ttl and value', () => {
8+
assert.deepEqual(
9+
transformArguments('KeyName', 0, '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"'),
10+
['RESTORE', 'KeyName', '0', '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"']
11+
);
12+
});
13+
14+
it('parses REPLACE', () => {
15+
assert.deepEqual(
16+
transformArguments('KeyName', 0, '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', {
17+
REPLACE: true
18+
}),
19+
['RESTORE', 'KeyName', '0', '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', 'REPLACE']
20+
);
21+
});
22+
23+
it('parses ABSTTL', () => {
24+
assert.deepEqual(
25+
transformArguments('KeyName', 2693098555000, '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', {
26+
ABSTTL: true
27+
}),
28+
['RESTORE', 'KeyName', '2693098555000', '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', 'ABSTTL']
29+
);
30+
});
31+
32+
it('parses IDLETIME', () => {
33+
assert.deepEqual(
34+
transformArguments('KeyName', 0, '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', {
35+
IDLETIME: 5
36+
}),
37+
['RESTORE', 'KeyName', '0', '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', 'IDLETIME', '5']
38+
);
39+
});
40+
41+
it('parses FREQ', () => {
42+
assert.deepEqual(
43+
transformArguments('KeyName', 0, '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', {
44+
FREQ: 5
45+
}),
46+
['RESTORE', 'KeyName', '0', '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', 'FREQ', '5']
47+
);
48+
});
49+
50+
it('parses REPLACE and ABSTTL', () => {
51+
assert.deepEqual(
52+
transformArguments('KeyName', 2693098555000, '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', {
53+
REPLACE: true,
54+
ABSTTL: true
55+
}),
56+
['RESTORE', 'KeyName', '2693098555000', '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', 'REPLACE', 'ABSTTL']
57+
);
58+
});
59+
60+
it('parses REPLACE and IDLETIME', () => {
61+
assert.deepEqual(
62+
transformArguments('KeyName', 0, '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', {
63+
REPLACE: true,
64+
IDLETIME: 5
65+
}),
66+
['RESTORE', 'KeyName', '0', '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', 'REPLACE', 'IDLETIME', '5']
67+
);
68+
});
69+
70+
it('parses REPLACE, ABSTTL, IDLETIME and FREQ', () => {
71+
assert.deepEqual(
72+
transformArguments('KeyName', 2693098555000, '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', {
73+
REPLACE: true,
74+
ABSTTL: true,
75+
IDLETIME: 5,
76+
FREQ: 50
77+
}),
78+
['RESTORE', 'KeyName', '2693098555000', '"\x00\x0bStringValue\n\x00\b\xebpW1H\x0c,"', 'REPLACE', 'ABSTTL', 'IDLETIME', '5', 'FREQ', '50']
79+
);
80+
});
81+
});
82+
83+
describe('client.restore', () => {
84+
testUtils.testWithClient('new key', async client => {
85+
await client.set('oldKey', 'oldValue')
86+
const dumpValue = await client.dump('oldKey');
87+
assert.equal(
88+
await client.restore('newKey', 0, dumpValue),
89+
'OK'
90+
);
91+
assert.equal(
92+
await client.get('newKey'),
93+
'oldValue'
94+
)
95+
}, GLOBAL.SERVERS.OPEN);
96+
97+
98+
testUtils.testWithClient('crash on RESTORE for existing key', async client => {
99+
await client.set('oldKey', 'oldValue')
100+
await client.set('newKey', 'newValue')
101+
const dumpValue = await client.dump('oldKey');
102+
assert.rejects(
103+
client.restore('newKey', 0, dumpValue),
104+
{
105+
name: 'ErrorReply',
106+
message: 'BUSYKEY Target key name already exists.'
107+
}
108+
)
109+
}, GLOBAL.SERVERS.OPEN);
110+
111+
testUtils.testWithClient('replace existing key', async client => {
112+
await client.set('oldKey', 'oldValue')
113+
await client.set('newKey', 'newValue')
114+
const dumpValue = await client.dump('oldKey');
115+
assert.equal(
116+
await client.restore('newKey', 0, dumpValue, {
117+
REPLACE: true
118+
}),
119+
'OK'
120+
);
121+
assert.equal(
122+
await client.get('newKey'),
123+
'oldValue'
124+
)
125+
}, GLOBAL.SERVERS.OPEN);
126+
})
127+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { RedisCommandArgument, RedisCommandArguments } from '.';
2+
3+
interface RestoreOptions {
4+
REPLACE?: true;
5+
ABSTTL?: true;
6+
IDLETIME?: number;
7+
FREQ?: number;
8+
}
9+
10+
export function transformArguments(
11+
key: RedisCommandArgument,
12+
ttl: number,
13+
serializedValue: RedisCommandArgument,
14+
options?: RestoreOptions
15+
): RedisCommandArguments {
16+
const args = ['RESTORE', key, ttl.toString(), serializedValue];
17+
18+
if (options?.REPLACE) {
19+
args.push('REPLACE');
20+
}
21+
22+
if (options?.ABSTTL) {
23+
args.push('ABSTTL');
24+
}
25+
26+
if (options?.IDLETIME) {
27+
args.push('IDLETIME', options.IDLETIME.toString());
28+
}
29+
30+
if (options?.FREQ) {
31+
args.push('FREQ', options.FREQ.toString());
32+
}
33+
34+
return args;
35+
}
36+
37+
export declare function transformReply(): 'OK';

0 commit comments

Comments
 (0)