-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathkvs.ts
80 lines (80 loc) · 2.46 KB
/
kvs.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import { v4 as uuidv4 } from 'uuid';
export type ValueType = string | number | boolean | Array<unknown>;
export default class KeyValueStore {
data: Map<
string,
{
modificationMetadata: {
id: string;
/** @type {number} Unix timestamp in ms when key will be deleted */
deletionTime?: number;
};
value: ValueType;
}
>;
constructor() {
this.data = new Map();
}
// Parameters may be declared in a variety of syntactic forms
/**
* @param {number?} timeout The time before the key is deleted in MS
*/
public set(key: string, value: ValueType, timeout?: number): void {
const modificationId = uuidv4();
if (timeout) {
this.data.set(key, {
value,
modificationMetadata: {
id: modificationId,
deletionTime: Date.now() + timeout,
},
});
setInterval(() => {
const gotKey = this.data.get(key);
if (gotKey && gotKey.modificationMetadata.id === modificationId)
this.delete(key);
}, timeout);
} else
this.data.set(key, {
value,
modificationMetadata: { id: modificationId },
});
}
public timeLeft(key: string): number | undefined {
const gotKey = this.data.get(key);
if (gotKey && gotKey.modificationMetadata.deletionTime)
return gotKey.modificationMetadata.deletionTime - Date.now();
}
public add(key: string, amount: number): void {
const gotKey = this.data.get(key);
if (!gotKey || typeof gotKey.value !== 'number') {
throw new Error('Key is not a number');
}
this.data.set(key, {
value: gotKey.value + amount,
modificationMetadata: gotKey.modificationMetadata,
});
}
/**
* @param {number?} timeout The time before the key is deleted in MS, if a new key is created
*/
public addOrCreate(key: string, amount: number, timeout?: number): void {
const gotKey = this.data.get(key);
if (!gotKey) this.set(key, amount, timeout);
else this.add(key, amount);
}
public get(key: string): ValueType | null {
return this.data.get(key)?.value || null;
}
public getOrSet(key: string, ifNotExists: ValueType): ValueType {
const origKey = this.data.get(key);
if (origKey) return origKey.value;
this.set(key, ifNotExists);
const newKey = this.data.get(key);
if (newKey) return newKey?.value;
else throw new Error('Failed to set');
}
public delete(key: string): boolean {
return this.data.delete(key);
}
}