-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSplitStorage.ts
140 lines (117 loc) · 4.44 KB
/
SplitStorage.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* Durable object to use as Split Storage
*/
export class SplitStorage {
// https://developers.cloudflare.com/workers/runtime-apis/durable-objects#transactional-storage-api
storage: DurableObjectStorage;
constructor(state: DurableObjectState) {
this.storage = state.storage!;
}
// Handle HTTP requests from clients.
async fetch(request: Request) {
let url = new URL(request.url);
let reqBody, result;
let param = url.searchParams.get("param");
switch (url.pathname) {
/** Key-Value operations */
case "/get":
// Setting allowConcurrency to improve performance. By default, the system will prevent concurrent events from executing while awaiting a read operation
result =
(await this.storage.get<string>(param!, {
allowConcurrency: true
})) || null;
break;
case "/set":
reqBody = await request.json<string>();
// There is no need to await write operations. Any series of write operations with no intervening await will automatically be submitted atomically
this.storage.put(param!, reqBody);
break;
case "/getAndSet":
// Using default allowConcurrency (false), to guarantee atomic operation.
// A series of reads followed by a series of writes are automatically atomic and behave like a transaction
const getResult = this.storage.get<string>(param!);
reqBody = await request.json<string>();
this.storage.put(param!, reqBody);
result = (await getResult) || null;
break;
case "/del":
this.storage.delete(param!);
break;
case "/getKeysByPrefix":
result = await this.storage.list<string>({
prefix: param!,
allowConcurrency: true
});
result = Array.from(result.keys());
break;
case "/getMany":
const keys = param!.split(",");
const map = await this.storage.get<string>(keys, {
allowConcurrency: true
});
result = keys.map(key => map.get(key) || null);
break;
case "/incr":
reqBody = await request.json<number>();
result = await this.storage.get<number>(param!); // allowConcurrency false
result = result ? result + reqBody : reqBody;
this.storage.put(param!, result);
break;
case "/decr":
reqBody = await request.json<number>();
result = await this.storage.get<number>(param!); // allowConcurrency false
result = result ? result - reqBody : -reqBody;
this.storage.put(param!, result);
break;
/** Set operations */
case "/itemContains":
reqBody = await request.json<string>();
result = await this.storage.get<Set<string>>(param!, {
allowConcurrency: true
});
result = result && result.has(reqBody) ? true : false;
break;
case "/addItems":
reqBody = await request.json<string[]>();
result =
(await this.storage.get<Set<string>>(param!)) || new Set<string>(); // allowConcurrency false
for (let i = 0; i < reqBody.length; i++) result.add(reqBody[i]);
this.storage.put(param!, result);
break;
case "/removeItems":
reqBody = await request.json<string[]>();
result = await this.storage.get<Set<string>>(param!); // allowConcurrency false
if (result) {
for (let i = 0; i < reqBody.length; i++) result.delete(reqBody[i]);
this.storage.put(param!, result);
}
break;
case "/getItems":
result = await this.storage.get<Set<string>>(param!, {
allowConcurrency: true
});
result = Array.from(result || new Set<string>());
break;
/** Queue operations */
// Since SDK must run in partial consumer mode, events and impressions are
// not tracked and so there is no need to implement Queue operations
case "/pushItems":
break;
case "/popItems":
result = new Array<string>();
break;
case "/getItemsCount":
result = 0;
break;
// Extra endpoint to clear the storage, for testing or fixing issues when migrating the durable object instance
case "/deleteAll":
await this.storage.deleteAll();
break;
default:
return new Response("Not found", { status: 404 });
}
return new Response(
result !== undefined ? JSON.stringify(result) : undefined
);
}
}