polystore 0.11.1 → 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -7
- package/src/index.js +6 -196
- package/src/index.test.js +0 -631
- package/src/index.types.ts +0 -18
- package/src/test/customFull.js +0 -45
- package/src/test/customSimple.js +0 -27
- package/src/test/data.json +0 -1
- package/src/test/setup.js +0 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polystore",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"description": "A small compatibility layer for many popular KV stores like localStorage, Redis, FileSystem, etc.",
|
|
5
5
|
"homepage": "https://polystore.dev/",
|
|
6
6
|
"repository": "https://github.com/franciscop/polystore.git",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"size": "echo $(gzip -c src/index.js | wc -c) bytes",
|
|
18
18
|
"start": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch --coverage --detectOpenHandles",
|
|
19
|
-
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage --ci --watchAll=false --detectOpenHandles && check-dts
|
|
19
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage --ci --watchAll=false --detectOpenHandles && check-dts test/index.types.ts"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
22
|
"kv",
|
|
@@ -54,11 +54,8 @@
|
|
|
54
54
|
"jest": {
|
|
55
55
|
"testEnvironment": "jsdom",
|
|
56
56
|
"setupFiles": [
|
|
57
|
-
"./
|
|
57
|
+
"./test/setup.js"
|
|
58
58
|
],
|
|
59
|
-
"transform": {}
|
|
60
|
-
"modulePathIgnorePatterns": [
|
|
61
|
-
"src/test/"
|
|
62
|
-
]
|
|
59
|
+
"transform": {}
|
|
63
60
|
}
|
|
64
61
|
}
|
package/src/index.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A number, or a string containing a number.
|
|
3
|
-
* @typedef {(number|string|object|array)} Value
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
1
|
import clients from "./clients/index.js";
|
|
7
2
|
import { createId, isClass, parse } from "./utils.js";
|
|
8
3
|
|
|
9
|
-
// #region Store
|
|
10
4
|
class Store {
|
|
11
5
|
PREFIX = "";
|
|
12
6
|
|
|
@@ -21,7 +15,6 @@ class Store {
|
|
|
21
15
|
});
|
|
22
16
|
}
|
|
23
17
|
|
|
24
|
-
// #region #client()
|
|
25
18
|
#find(store) {
|
|
26
19
|
// Already a fully compliant KV store
|
|
27
20
|
if (store instanceof Store) return store.client;
|
|
@@ -41,7 +34,6 @@ class Store {
|
|
|
41
34
|
return store;
|
|
42
35
|
}
|
|
43
36
|
|
|
44
|
-
// #region #validate()
|
|
45
37
|
#validate(client) {
|
|
46
38
|
if (!client.set || !client.get || !client.iterate) {
|
|
47
39
|
throw new Error(
|
|
@@ -93,21 +85,6 @@ class Store {
|
|
|
93
85
|
return false;
|
|
94
86
|
}
|
|
95
87
|
|
|
96
|
-
// #region .add()
|
|
97
|
-
/**
|
|
98
|
-
* Save the data on an autogenerated key, can add expiration as well:
|
|
99
|
-
*
|
|
100
|
-
* ```js
|
|
101
|
-
* const key1 = await store.add("value1");
|
|
102
|
-
* const key2 = await store.add({ hello: "world" });
|
|
103
|
-
* const key3 = await store.add("value3", { expires: "1h" });
|
|
104
|
-
* ```
|
|
105
|
-
*
|
|
106
|
-
* **[→ Full .add() Docs](https://polystore.dev/documentation#add)**
|
|
107
|
-
* @param {Value} value
|
|
108
|
-
* @param {{ expires: string }} options
|
|
109
|
-
* @returns {Promise<string>}
|
|
110
|
-
*/
|
|
111
88
|
async add(value, options = {}) {
|
|
112
89
|
await this.promise;
|
|
113
90
|
const expires = parse(options.expire ?? options.expires);
|
|
@@ -130,22 +107,6 @@ class Store {
|
|
|
130
107
|
return id; // The plain one without the prefix
|
|
131
108
|
}
|
|
132
109
|
|
|
133
|
-
// #region .set()
|
|
134
|
-
/**
|
|
135
|
-
* Save the data on the given key, can add expiration as well:
|
|
136
|
-
*
|
|
137
|
-
* ```js
|
|
138
|
-
* const key = await store.set("key1", "value1");
|
|
139
|
-
* await store.set("key2", { hello: "world" });
|
|
140
|
-
* await store.set("key3", "value3", { expires: "1h" });
|
|
141
|
-
* ```
|
|
142
|
-
*
|
|
143
|
-
* **[→ Full .set() Docs](https://polystore.dev/documentation#set)**
|
|
144
|
-
* @param {string} key
|
|
145
|
-
* @param {Value} value
|
|
146
|
-
* @param {{ expires: string }} options
|
|
147
|
-
* @returns {Promise<string>}
|
|
148
|
-
*/
|
|
149
110
|
async set(key, value, options = {}) {
|
|
150
111
|
await this.promise;
|
|
151
112
|
const id = this.PREFIX + key;
|
|
@@ -168,23 +129,6 @@ class Store {
|
|
|
168
129
|
return key;
|
|
169
130
|
}
|
|
170
131
|
|
|
171
|
-
// #region .get()
|
|
172
|
-
/**
|
|
173
|
-
* Read a single value from the KV store:
|
|
174
|
-
*
|
|
175
|
-
* ```js
|
|
176
|
-
* const value1 = await store.get("key1");
|
|
177
|
-
* // null (doesn't exist or has expired)
|
|
178
|
-
* const value2 = await store.get("key2");
|
|
179
|
-
* // "value2"
|
|
180
|
-
* const value3 = await store.get("key3");
|
|
181
|
-
* // { hello: "world" }
|
|
182
|
-
* ```
|
|
183
|
-
*
|
|
184
|
-
* **[→ Full .get() Docs](https://polystore.dev/documentation#get)**
|
|
185
|
-
* @param {string} key
|
|
186
|
-
* @returns {Promise<Value>}
|
|
187
|
-
*/
|
|
188
132
|
async get(key) {
|
|
189
133
|
await this.promise;
|
|
190
134
|
const id = this.PREFIX + key;
|
|
@@ -202,26 +146,6 @@ class Store {
|
|
|
202
146
|
return data.value;
|
|
203
147
|
}
|
|
204
148
|
|
|
205
|
-
// #region .has()
|
|
206
|
-
/**
|
|
207
|
-
* Check whether a key exists or not:
|
|
208
|
-
*
|
|
209
|
-
* ```js
|
|
210
|
-
* if (await store.has("key1")) { ... }
|
|
211
|
-
* ```
|
|
212
|
-
*
|
|
213
|
-
* If you are going to use the value, it's better to just read it:
|
|
214
|
-
*
|
|
215
|
-
* ```js
|
|
216
|
-
* const val = await store.get("key1");
|
|
217
|
-
* if (val) { ... }
|
|
218
|
-
* ```
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* **[→ Full .has() Docs](https://polystore.dev/documentation#has)**
|
|
222
|
-
* @param {string} key
|
|
223
|
-
* @returns {Promise<boolean>}
|
|
224
|
-
*/
|
|
225
149
|
async has(key) {
|
|
226
150
|
await this.promise;
|
|
227
151
|
const id = this.PREFIX + key;
|
|
@@ -234,18 +158,6 @@ class Store {
|
|
|
234
158
|
return value !== null;
|
|
235
159
|
}
|
|
236
160
|
|
|
237
|
-
// #region .del()
|
|
238
|
-
/**
|
|
239
|
-
* Remove a single key and its value from the store:
|
|
240
|
-
*
|
|
241
|
-
* ```js
|
|
242
|
-
* const key = await store.del("key1");
|
|
243
|
-
* ```
|
|
244
|
-
*
|
|
245
|
-
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
246
|
-
* @param {string} key
|
|
247
|
-
* @returns {Promise<string>}
|
|
248
|
-
*/
|
|
249
161
|
async del(key) {
|
|
250
162
|
await this.promise;
|
|
251
163
|
const id = this.PREFIX + key;
|
|
@@ -272,33 +184,19 @@ class Store {
|
|
|
272
184
|
}
|
|
273
185
|
}
|
|
274
186
|
|
|
275
|
-
// #region .entries()
|
|
276
|
-
/**
|
|
277
|
-
* Return an array of the entries, in the [key, value] format:
|
|
278
|
-
*
|
|
279
|
-
* ```js
|
|
280
|
-
* const entries = await store.entries();
|
|
281
|
-
* // [["key1", "value1"], ["key2", { hello: "world" }], ...]
|
|
282
|
-
*
|
|
283
|
-
* // To limit it to a given prefix, use `.prefix()`:
|
|
284
|
-
* const sessions = await store.prefix("session:").entries();
|
|
285
|
-
* ```
|
|
286
|
-
*
|
|
287
|
-
* **[→ Full .entries() Docs](https://polystore.dev/documentation#entries)**
|
|
288
|
-
* @returns {Promise<[string, Value][]>}
|
|
289
|
-
*/
|
|
290
187
|
async entries() {
|
|
291
188
|
await this.promise;
|
|
292
189
|
|
|
190
|
+
// Cut the key to size
|
|
191
|
+
const trim = (key) => key.slice(this.PREFIX.length);
|
|
192
|
+
|
|
293
193
|
let list = [];
|
|
294
194
|
if (this.client.entries) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
value,
|
|
298
|
-
]);
|
|
195
|
+
const entries = await this.client.entries(this.PREFIX);
|
|
196
|
+
list = entries.map(([key, value]) => [trim(key), value]);
|
|
299
197
|
} else {
|
|
300
198
|
for await (const [key, value] of this.client.iterate(this.PREFIX)) {
|
|
301
|
-
list.push([key
|
|
199
|
+
list.push([trim(key), value]);
|
|
302
200
|
}
|
|
303
201
|
}
|
|
304
202
|
|
|
@@ -312,21 +210,6 @@ class Store {
|
|
|
312
210
|
.map(([key, data]) => [key, data.value]);
|
|
313
211
|
}
|
|
314
212
|
|
|
315
|
-
// #region .keys()
|
|
316
|
-
/**
|
|
317
|
-
* Return an array of the keys in the store:
|
|
318
|
-
*
|
|
319
|
-
* ```js
|
|
320
|
-
* const keys = await store.keys();
|
|
321
|
-
* // ["key1", "key2", ...]
|
|
322
|
-
*
|
|
323
|
-
* // To limit it to a given prefix, use `.prefix()`:
|
|
324
|
-
* const sessions = await store.prefix("session:").keys();
|
|
325
|
-
* ```
|
|
326
|
-
*
|
|
327
|
-
* **[→ Full .keys() Docs](https://polystore.dev/documentation#keys)**
|
|
328
|
-
* @returns {Promise<string[]>}
|
|
329
|
-
*/
|
|
330
213
|
async keys() {
|
|
331
214
|
await this.promise;
|
|
332
215
|
|
|
@@ -340,21 +223,6 @@ class Store {
|
|
|
340
223
|
return entries.map((e) => e[0]);
|
|
341
224
|
}
|
|
342
225
|
|
|
343
|
-
// #region .values()
|
|
344
|
-
/**
|
|
345
|
-
* Return an array of the values in the store:
|
|
346
|
-
*
|
|
347
|
-
* ```js
|
|
348
|
-
* const values = await store.values();
|
|
349
|
-
* // ["value1", { hello: "world" }, ...]
|
|
350
|
-
*
|
|
351
|
-
* // To limit it to a given prefix, use `.prefix()`:
|
|
352
|
-
* const sessions = await store.prefix("session:").values();
|
|
353
|
-
* ```
|
|
354
|
-
*
|
|
355
|
-
* **[→ Full .values() Docs](https://polystore.dev/documentation#values)**
|
|
356
|
-
* @returns {Promise<Value[]>}
|
|
357
|
-
*/
|
|
358
226
|
async values() {
|
|
359
227
|
await this.promise;
|
|
360
228
|
|
|
@@ -370,21 +238,6 @@ class Store {
|
|
|
370
238
|
return entries.map((e) => e[1]);
|
|
371
239
|
}
|
|
372
240
|
|
|
373
|
-
// #region .all()
|
|
374
|
-
/**
|
|
375
|
-
* Return an object with the keys:values in the store:
|
|
376
|
-
*
|
|
377
|
-
* ```js
|
|
378
|
-
* const obj = await store.all();
|
|
379
|
-
* // { key1: "value1", key2: { hello: "world" }, ... }
|
|
380
|
-
*
|
|
381
|
-
* // To limit it to a given prefix, use `.prefix()`:
|
|
382
|
-
* const sessions = await store.prefix("session:").all();
|
|
383
|
-
* ```
|
|
384
|
-
*
|
|
385
|
-
* **[→ Full .all() Docs](https://polystore.dev/documentation#all)**
|
|
386
|
-
* @returns {Promise<{ [key:string]: Value }>}
|
|
387
|
-
*/
|
|
388
241
|
async all() {
|
|
389
242
|
await this.promise;
|
|
390
243
|
|
|
@@ -402,19 +255,6 @@ class Store {
|
|
|
402
255
|
return Object.fromEntries(entries);
|
|
403
256
|
}
|
|
404
257
|
|
|
405
|
-
// #region .clear()
|
|
406
|
-
/**
|
|
407
|
-
* Delete all of the records of the store:
|
|
408
|
-
*
|
|
409
|
-
* ```js
|
|
410
|
-
* await store.clear();
|
|
411
|
-
* ```
|
|
412
|
-
*
|
|
413
|
-
* It's useful for cache invalidation, clearing the data, and testing.
|
|
414
|
-
*
|
|
415
|
-
* **[→ Full .clear() Docs](https://polystore.dev/documentation#clear)**
|
|
416
|
-
* @returns {Promise<null>}
|
|
417
|
-
*/
|
|
418
258
|
async clear() {
|
|
419
259
|
await this.promise;
|
|
420
260
|
|
|
@@ -427,23 +267,6 @@ class Store {
|
|
|
427
267
|
await Promise.all(keys.map((key) => this.del(key)));
|
|
428
268
|
}
|
|
429
269
|
|
|
430
|
-
// #region .prefix()
|
|
431
|
-
/**
|
|
432
|
-
* Create a substore where all the keys are stored with
|
|
433
|
-
* the given prefix:
|
|
434
|
-
*
|
|
435
|
-
* ```js
|
|
436
|
-
* const session = store.prefix("session:");
|
|
437
|
-
* await session.set("key1", "value1");
|
|
438
|
-
* console.log(await session.entries()); // session.
|
|
439
|
-
* // [["key1", "value1"]]
|
|
440
|
-
* console.log(await store.entries()); // store.
|
|
441
|
-
* // [["session:key1", "value1"]]
|
|
442
|
-
* ```
|
|
443
|
-
*
|
|
444
|
-
* **[→ Full .prefix() Docs](https://polystore.dev/documentation#prefix)**
|
|
445
|
-
* @returns {Store}
|
|
446
|
-
*/
|
|
447
270
|
prefix(prefix = "") {
|
|
448
271
|
const store = new Store(
|
|
449
272
|
Promise.resolve(this.promise).then((client) => client || this.client)
|
|
@@ -452,19 +275,6 @@ class Store {
|
|
|
452
275
|
return store;
|
|
453
276
|
}
|
|
454
277
|
|
|
455
|
-
// #region .close()
|
|
456
|
-
/**
|
|
457
|
-
* Stop the connection to the store, if any:
|
|
458
|
-
*
|
|
459
|
-
* ```js
|
|
460
|
-
* await session.set("key1", "value1");
|
|
461
|
-
* await store.close();
|
|
462
|
-
* await session.set("key2", "value2"); // error
|
|
463
|
-
* ```
|
|
464
|
-
*
|
|
465
|
-
* **[→ Full .close() Docs](https://polystore.dev/documentation#close)**
|
|
466
|
-
* @returns {Store}
|
|
467
|
-
*/
|
|
468
278
|
async close() {
|
|
469
279
|
await this.promise;
|
|
470
280
|
|
package/src/index.test.js
DELETED
|
@@ -1,631 +0,0 @@
|
|
|
1
|
-
import "dotenv/config";
|
|
2
|
-
|
|
3
|
-
import { jest } from "@jest/globals";
|
|
4
|
-
import { EdgeKVNamespace as KVNamespace } from "edge-mock";
|
|
5
|
-
import { Etcd3 } from "etcd3";
|
|
6
|
-
import { Level } from "level";
|
|
7
|
-
import localForage from "localforage";
|
|
8
|
-
import { createClient } from "redis";
|
|
9
|
-
|
|
10
|
-
import kv from "./index.js";
|
|
11
|
-
import customFull from "./test/customFull.js";
|
|
12
|
-
import customSimple from "./test/customSimple.js";
|
|
13
|
-
|
|
14
|
-
const stores = [];
|
|
15
|
-
stores.push(["kv()", kv()]);
|
|
16
|
-
stores.push(["kv(new Map())", kv(new Map())]);
|
|
17
|
-
stores.push(["kv(localStorage)", kv(localStorage)]);
|
|
18
|
-
stores.push(["kv(sessionStorage)", kv(sessionStorage)]);
|
|
19
|
-
stores.push(["kv(localForage)", kv(localForage)]);
|
|
20
|
-
const path = `file://${process.cwd()}/src/test/data.json`;
|
|
21
|
-
stores.push([`kv(new URL("${path}"))`, kv(new URL(path))]);
|
|
22
|
-
const path2 = `file://${process.cwd()}/src/test/data.json`;
|
|
23
|
-
stores.push([`kv("${path2}")`, kv(path2)]);
|
|
24
|
-
stores.push([`kv("cookie")`, kv("cookie")]);
|
|
25
|
-
stores.push(["kv(new KVNamespace())", kv(new KVNamespace())]);
|
|
26
|
-
stores.push([`kv(new Level("data"))`, kv(new Level("data"))]);
|
|
27
|
-
if (process.env.REDIS) {
|
|
28
|
-
stores.push(["kv(redis)", kv(createClient())]);
|
|
29
|
-
}
|
|
30
|
-
if (process.env.ETCD) {
|
|
31
|
-
// Note: need to add to .env "ETCD=true" and run `etcd` in the terminal
|
|
32
|
-
stores.push(["kv(new Etcd3())", kv(new Etcd3())]);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
stores.push(["kv(customSimple)", kv(customSimple)]);
|
|
36
|
-
stores.push(["kv(customFull)", kv(customFull)]);
|
|
37
|
-
|
|
38
|
-
const delay = (t) => new Promise((done) => setTimeout(done, t));
|
|
39
|
-
|
|
40
|
-
class Base {
|
|
41
|
-
get() {}
|
|
42
|
-
set() {}
|
|
43
|
-
*iterate() {}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
global.console = {
|
|
47
|
-
...console,
|
|
48
|
-
warn: jest.fn(),
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
describe("potato", () => {
|
|
52
|
-
it("a potato is not a valid store", async () => {
|
|
53
|
-
await expect(() => kv("potato").get("any")).rejects.toThrow();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("an empty object is not a valid store", async () => {
|
|
57
|
-
await expect(() => kv({}).get("any")).rejects.toThrow({
|
|
58
|
-
message: "A client should have at least a .get(), .set() and .iterate()",
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("cannot handle no EXPIRES + keys", async () => {
|
|
63
|
-
await expect(() =>
|
|
64
|
-
kv(
|
|
65
|
-
class extends Base {
|
|
66
|
-
has() {}
|
|
67
|
-
}
|
|
68
|
-
).get("any")
|
|
69
|
-
).rejects.toThrow({
|
|
70
|
-
message:
|
|
71
|
-
"You can only define client.has() when the client manages the expiration; otherwise please do NOT define .has() and let us manage it",
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("cannot handle no EXPIRES + keys", async () => {
|
|
76
|
-
await expect(() =>
|
|
77
|
-
kv(
|
|
78
|
-
class extends Base {
|
|
79
|
-
keys() {}
|
|
80
|
-
}
|
|
81
|
-
).get("any")
|
|
82
|
-
).rejects.toThrow({
|
|
83
|
-
message:
|
|
84
|
-
"You can only define client.keys() when the client manages the expiration; otherwise please do NOT define .keys() and let us manage them",
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("warns the user with no EXPIRES + .values()", async () => {
|
|
89
|
-
const warn = jest
|
|
90
|
-
.spyOn(console, "warn")
|
|
91
|
-
.mockImplementationOnce(() => "Hello");
|
|
92
|
-
await kv(
|
|
93
|
-
class extends Base {
|
|
94
|
-
values() {}
|
|
95
|
-
}
|
|
96
|
-
).get("any");
|
|
97
|
-
expect(warn).toHaveBeenCalled(); // But at least we warn them
|
|
98
|
-
warn.mockClear();
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
for (let [name, store] of stores) {
|
|
103
|
-
describe(name, () => {
|
|
104
|
-
beforeEach(async () => {
|
|
105
|
-
await store.clear();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
afterAll(async () => {
|
|
109
|
-
await store.clear();
|
|
110
|
-
await store.close();
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("can perform a CRUD", async () => {
|
|
114
|
-
expect(await store.get("a")).toBe(null);
|
|
115
|
-
expect(await store.has("a")).toBe(false);
|
|
116
|
-
expect(await store.set("a", "b")).toBe("a");
|
|
117
|
-
expect(await store.has("a")).toBe(true);
|
|
118
|
-
expect(await store.get("a")).toBe("b");
|
|
119
|
-
expect(await store.del("a")).toBe("a");
|
|
120
|
-
expect(await store.get("a")).toBe(null);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("is empty on the start", async () => {
|
|
124
|
-
expect(await store.get("a")).toBe(null);
|
|
125
|
-
expect(await store.has("a")).toBe(false);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it("can add() arbitrary values", async () => {
|
|
129
|
-
const key = await store.add("b");
|
|
130
|
-
expect(typeof key).toBe("string");
|
|
131
|
-
expect(await store.get(key)).toBe("b");
|
|
132
|
-
expect(await store.has(key)).toBe(true);
|
|
133
|
-
expect(key.length).toBe(24);
|
|
134
|
-
expect(key).toMatch(/^[a-zA-Z0-9]{24}$/);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it("can store values", async () => {
|
|
138
|
-
const key = await store.set("a", "b");
|
|
139
|
-
expect(await store.get("a")).toBe("b");
|
|
140
|
-
expect(await store.has("a")).toBe(true);
|
|
141
|
-
expect(key).toBe("a");
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it("can store values with a semicolon", async () => {
|
|
145
|
-
const key = await store.set("a", "b;c");
|
|
146
|
-
expect(await store.get("a")).toBe("b;c");
|
|
147
|
-
expect(await store.has("a")).toBe(true);
|
|
148
|
-
expect(key).toBe("a");
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("can store values with an equal", async () => {
|
|
152
|
-
const key = await store.set("a", "b=c");
|
|
153
|
-
expect(await store.get("a")).toBe("b=c");
|
|
154
|
-
expect(await store.has("a")).toBe(true);
|
|
155
|
-
expect(key).toBe("a");
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("can store values with a semicolon in the key", async () => {
|
|
159
|
-
const key = await store.set("a;b", "c");
|
|
160
|
-
expect(await store.get("a;b")).toBe("c");
|
|
161
|
-
expect(await store.has("a;b")).toBe(true);
|
|
162
|
-
expect(key).toBe("a;b");
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it("can store values with an equal in the key", async () => {
|
|
166
|
-
const key = await store.set("a=b", "c");
|
|
167
|
-
expect(await store.get("a=b")).toBe("c");
|
|
168
|
-
expect(await store.has("a=b")).toBe(true);
|
|
169
|
-
expect(key).toBe("a=b");
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("can store basic types", async () => {
|
|
173
|
-
await store.set("a", 10);
|
|
174
|
-
expect(await store.get("a")).toEqual(10);
|
|
175
|
-
await store.set("a", "b");
|
|
176
|
-
expect(await store.get("a")).toEqual("b");
|
|
177
|
-
await store.set("a", true);
|
|
178
|
-
expect(await store.get("a")).toEqual(true);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it("can store arrays of JSON values", async () => {
|
|
182
|
-
await store.set("a", ["b", "c"]);
|
|
183
|
-
expect(await store.get("a")).toEqual(["b", "c"]);
|
|
184
|
-
expect(await store.has("a")).toBe(true);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it("can store objects", async () => {
|
|
188
|
-
await store.set("a", { b: "c" });
|
|
189
|
-
expect(await store.get("a")).toEqual({ b: "c" });
|
|
190
|
-
expect(await store.has("a")).toBe(true);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it("can get the keys", async () => {
|
|
194
|
-
await store.set("a", "b");
|
|
195
|
-
await store.set("c", "d");
|
|
196
|
-
expect(await store.keys()).toEqual(["a", "c"]);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it("can get the values", async () => {
|
|
200
|
-
await store.set("a", "b");
|
|
201
|
-
await store.set("c", "d");
|
|
202
|
-
expect(await store.values()).toEqual(["b", "d"]);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it("can get the entries", async () => {
|
|
206
|
-
await store.set("a", "b");
|
|
207
|
-
await store.set("c", "d");
|
|
208
|
-
expect(await store.entries()).toEqual([
|
|
209
|
-
["a", "b"],
|
|
210
|
-
["c", "d"],
|
|
211
|
-
]);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it("can get the all object", async () => {
|
|
215
|
-
await store.set("a", "b");
|
|
216
|
-
await store.set("c", "d");
|
|
217
|
-
expect(await store.all()).toEqual({
|
|
218
|
-
a: "b",
|
|
219
|
-
c: "d",
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it("can get the keys with a colon prefix", async () => {
|
|
224
|
-
await store.set("a:0", "a0");
|
|
225
|
-
await store.set("a:1", "a1");
|
|
226
|
-
await store.set("b:0", "b0");
|
|
227
|
-
await store.set("a:2", "a2");
|
|
228
|
-
expect((await store.keys()).sort()).toEqual(["a:0", "a:1", "a:2", "b:0"]);
|
|
229
|
-
expect((await store.prefix("a:").keys()).sort()).toEqual(["0", "1", "2"]);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("can get the values with a colon prefix", async () => {
|
|
233
|
-
await store.set("a:0", "a0");
|
|
234
|
-
await store.set("a:1", "a1");
|
|
235
|
-
await store.set("b:0", "b0");
|
|
236
|
-
await store.set("a:2", "a2");
|
|
237
|
-
expect((await store.prefix("a:").values()).sort()).toEqual([
|
|
238
|
-
"a0",
|
|
239
|
-
"a1",
|
|
240
|
-
"a2",
|
|
241
|
-
]);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it("can get the entries with a colon prefix", async () => {
|
|
245
|
-
await store.set("a:0", "a0");
|
|
246
|
-
await store.set("a:1", "a1");
|
|
247
|
-
await store.set("b:0", "b0");
|
|
248
|
-
await store.set("a:2", "a2");
|
|
249
|
-
expect((await store.entries()).sort()).toEqual([
|
|
250
|
-
["a:0", "a0"],
|
|
251
|
-
["a:1", "a1"],
|
|
252
|
-
["a:2", "a2"],
|
|
253
|
-
["b:0", "b0"],
|
|
254
|
-
]);
|
|
255
|
-
expect((await store.prefix("a:").entries()).sort()).toEqual([
|
|
256
|
-
["0", "a0"],
|
|
257
|
-
["1", "a1"],
|
|
258
|
-
["2", "a2"],
|
|
259
|
-
]);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it("can get the all object with a colon prefix", async () => {
|
|
263
|
-
await store.set("a:0", "a0");
|
|
264
|
-
await store.set("a:1", "a1");
|
|
265
|
-
await store.set("b:0", "b0");
|
|
266
|
-
await store.set("a:2", "a2");
|
|
267
|
-
expect(await store.prefix("a:").all()).toEqual({
|
|
268
|
-
0: "a0",
|
|
269
|
-
1: "a1",
|
|
270
|
-
2: "a2",
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
it("can get the keys with a dash prefix", async () => {
|
|
275
|
-
await store.set("a-0", "a0");
|
|
276
|
-
await store.set("a-1", "a1");
|
|
277
|
-
await store.set("b-0", "b0");
|
|
278
|
-
await store.set("a-2", "a2");
|
|
279
|
-
expect((await store.keys()).sort()).toEqual(["a-0", "a-1", "a-2", "b-0"]);
|
|
280
|
-
expect((await store.prefix("a-").keys()).sort()).toEqual(["0", "1", "2"]);
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
it("can get the values with a dash prefix", async () => {
|
|
284
|
-
await store.set("a-0", "a0");
|
|
285
|
-
await store.set("a-1", "a1");
|
|
286
|
-
await store.set("b-0", "b0");
|
|
287
|
-
await store.set("a-2", "a2");
|
|
288
|
-
expect((await store.prefix("a-").values()).sort()).toEqual([
|
|
289
|
-
"a0",
|
|
290
|
-
"a1",
|
|
291
|
-
"a2",
|
|
292
|
-
]);
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
it("can get the entries with a dash prefix", async () => {
|
|
296
|
-
await store.set("a-0", "a0");
|
|
297
|
-
await store.set("a-1", "a1");
|
|
298
|
-
await store.set("b-0", "b0");
|
|
299
|
-
await store.set("a-2", "a2");
|
|
300
|
-
expect((await store.prefix("a-").entries()).sort()).toEqual([
|
|
301
|
-
["0", "a0"],
|
|
302
|
-
["1", "a1"],
|
|
303
|
-
["2", "a2"],
|
|
304
|
-
]);
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it("can get the all object with a dash prefix", async () => {
|
|
308
|
-
await store.set("a-0", "a0");
|
|
309
|
-
await store.set("a-1", "a1");
|
|
310
|
-
await store.set("b-0", "b0");
|
|
311
|
-
await store.set("a-2", "a2");
|
|
312
|
-
expect(await store.prefix("a-").all()).toEqual({
|
|
313
|
-
0: "a0",
|
|
314
|
-
1: "a1",
|
|
315
|
-
2: "a2",
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
it("can delete the data", async () => {
|
|
320
|
-
await store.set("a", "b");
|
|
321
|
-
expect(await store.get("a")).toBe("b");
|
|
322
|
-
await store.del("a");
|
|
323
|
-
expect(await store.get("a")).toBe(null);
|
|
324
|
-
expect(await store.keys()).toEqual([]);
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
it("can delete the data by setting it to null", async () => {
|
|
328
|
-
await store.set("a", "b");
|
|
329
|
-
expect(await store.get("a")).toBe("b");
|
|
330
|
-
await store.set("a", null);
|
|
331
|
-
expect(await store.get("a")).toBe(null);
|
|
332
|
-
expect(await store.keys()).toEqual([]);
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
it("can clear all the values", async () => {
|
|
336
|
-
await store.set("a", "b");
|
|
337
|
-
await store.set("c", "d");
|
|
338
|
-
expect(await store.get("a")).toBe("b");
|
|
339
|
-
await store.clear();
|
|
340
|
-
expect(await store.get("a")).toBe(null);
|
|
341
|
-
await store.set("a", "b");
|
|
342
|
-
expect(await store.get("a")).toBe("b");
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
describe("iteration", () => {
|
|
346
|
-
beforeEach(async () => {
|
|
347
|
-
await store.clear();
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
it("supports raw iteration", async () => {
|
|
351
|
-
await store.set("a", "b");
|
|
352
|
-
await store.set("c", "d");
|
|
353
|
-
|
|
354
|
-
const entries = [];
|
|
355
|
-
for await (const entry of store) {
|
|
356
|
-
entries.push(entry);
|
|
357
|
-
}
|
|
358
|
-
expect(entries).toEqual([
|
|
359
|
-
["a", "b"],
|
|
360
|
-
["c", "d"],
|
|
361
|
-
]);
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
it("supports raw prefix iteration", async () => {
|
|
365
|
-
await store.set("a:a", "b");
|
|
366
|
-
await store.set("b:a", "d");
|
|
367
|
-
await store.set("a:c", "d");
|
|
368
|
-
await store.set("b:c", "d");
|
|
369
|
-
|
|
370
|
-
const entries = [];
|
|
371
|
-
for await (const entry of store.prefix("a:")) {
|
|
372
|
-
entries.push(entry);
|
|
373
|
-
}
|
|
374
|
-
expect(entries.sort()).toEqual([
|
|
375
|
-
["a", "b"],
|
|
376
|
-
["c", "d"],
|
|
377
|
-
]);
|
|
378
|
-
});
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
describe("expires", () => {
|
|
382
|
-
// The mock implementation does NOT support expiration 😪
|
|
383
|
-
if (name === "kv(new KVNamespace())") return;
|
|
384
|
-
|
|
385
|
-
afterEach(() => {
|
|
386
|
-
jest.restoreAllMocks();
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
it("expires = 0 means immediately", async () => {
|
|
390
|
-
await store.set("a", "b", { expires: 0 });
|
|
391
|
-
expect(await store.get("a")).toBe(null);
|
|
392
|
-
expect(await store.has("a")).toBe(false);
|
|
393
|
-
expect(await store.keys()).toEqual([]);
|
|
394
|
-
expect(await store.values()).toEqual([]);
|
|
395
|
-
expect(await store.entries()).toEqual([]);
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
it("expires = potato means undefined = forever", async () => {
|
|
399
|
-
await store.set("a", "b", { expires: "potato" });
|
|
400
|
-
expect(await store.get("a")).toBe("b");
|
|
401
|
-
await delay(100);
|
|
402
|
-
expect(await store.get("a")).toBe("b");
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
it("expires = 5potato means undefined = forever", async () => {
|
|
406
|
-
await store.set("a", "b", { expires: "5potato" });
|
|
407
|
-
expect(await store.get("a")).toBe("b");
|
|
408
|
-
await delay(100);
|
|
409
|
-
expect(await store.get("a")).toBe("b");
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
it("expires = null means never to expire it", async () => {
|
|
413
|
-
await store.set("a", "b", { expires: null });
|
|
414
|
-
expect(await store.get("a")).toBe("b");
|
|
415
|
-
await delay(100);
|
|
416
|
-
expect(await store.get("a")).toBe("b");
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
it("expires = undefined means never to expire it", async () => {
|
|
420
|
-
await store.set("a", "b");
|
|
421
|
-
expect(await store.get("a")).toBe("b");
|
|
422
|
-
await delay(100);
|
|
423
|
-
expect(await store.get("a")).toBe("b");
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
if (
|
|
427
|
-
name !== `kv("cookie")` &&
|
|
428
|
-
name !== `kv(redis)` &&
|
|
429
|
-
name !== `kv(new Etcd3())`
|
|
430
|
-
) {
|
|
431
|
-
it("can use 0.01 expire", async () => {
|
|
432
|
-
// 10ms
|
|
433
|
-
await store.set("a", "b", { expires: 0.01 });
|
|
434
|
-
expect(await store.keys()).toEqual(["a"]);
|
|
435
|
-
expect(await store.values()).toEqual(["b"]);
|
|
436
|
-
expect(await store.get("a")).toBe("b");
|
|
437
|
-
await delay(100);
|
|
438
|
-
expect(await store.keys()).toEqual([]);
|
|
439
|
-
expect(await store.values()).toEqual([]);
|
|
440
|
-
expect(await store.get("a")).toBe(null);
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
it("can use 0.01s expire", async () => {
|
|
444
|
-
await store.set("a", "b", { expires: "0.01s" });
|
|
445
|
-
expect(await store.keys()).toEqual(["a"]);
|
|
446
|
-
expect(await store.values()).toEqual(["b"]);
|
|
447
|
-
expect(await store.get("a")).toBe("b");
|
|
448
|
-
await delay(100);
|
|
449
|
-
expect(await store.keys()).toEqual([]);
|
|
450
|
-
expect(await store.values()).toEqual([]);
|
|
451
|
-
expect(await store.get("a")).toBe(null);
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
it("can use 0.01seconds expire", async () => {
|
|
455
|
-
await store.set("a", "b", { expires: "0.01seconds" });
|
|
456
|
-
expect(await store.keys()).toEqual(["a"]);
|
|
457
|
-
expect(await store.values()).toEqual(["b"]);
|
|
458
|
-
expect(await store.get("a")).toBe("b");
|
|
459
|
-
await delay(100);
|
|
460
|
-
expect(await store.keys()).toEqual([]);
|
|
461
|
-
expect(await store.values()).toEqual([]);
|
|
462
|
-
expect(await store.get("a")).toBe(null);
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
it("can use 10ms expire", async () => {
|
|
466
|
-
await store.set("a", "b", { expires: "10ms" });
|
|
467
|
-
expect(await store.keys()).toEqual(["a"]);
|
|
468
|
-
expect(await store.values()).toEqual(["b"]);
|
|
469
|
-
expect(await store.get("a")).toBe("b");
|
|
470
|
-
await delay(100);
|
|
471
|
-
expect(await store.keys()).toEqual([]);
|
|
472
|
-
expect(await store.values()).toEqual([]);
|
|
473
|
-
expect(await store.get("a")).toBe(null);
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
it("removes the expired key with .get()", async () => {
|
|
477
|
-
await store.set("a", "b", { expires: "10ms" });
|
|
478
|
-
const spy = jest.spyOn(store, "del");
|
|
479
|
-
expect(spy).not.toHaveBeenCalled();
|
|
480
|
-
await delay(100);
|
|
481
|
-
expect(spy).not.toHaveBeenCalled(); // Nothing we can do 😪
|
|
482
|
-
expect(await store.get("a")).toBe(null);
|
|
483
|
-
expect(spy).toHaveBeenCalled();
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
it("removes the expired key with .keys()", async () => {
|
|
487
|
-
await store.set("a", "b", { expires: "10ms" });
|
|
488
|
-
const spy = jest.spyOn(store, "del");
|
|
489
|
-
expect(spy).not.toHaveBeenCalled();
|
|
490
|
-
await delay(100);
|
|
491
|
-
expect(spy).not.toHaveBeenCalled(); // Nothing we can do 😪
|
|
492
|
-
expect(await store.keys()).toEqual([]);
|
|
493
|
-
expect(spy).toHaveBeenCalled();
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
it("CANNOT remove the expired key with .values()", async () => {
|
|
497
|
-
await store.set("a", "b", { expires: "10ms" });
|
|
498
|
-
const spy = jest.spyOn(store, "del");
|
|
499
|
-
expect(spy).not.toHaveBeenCalled();
|
|
500
|
-
await delay(100);
|
|
501
|
-
expect(spy).not.toHaveBeenCalled(); // Nothing we can do 😪
|
|
502
|
-
expect(await store.values()).toEqual([]);
|
|
503
|
-
if (!store.client.EXPIRES && store.client.values) {
|
|
504
|
-
expect(spy).not.toHaveBeenCalled(); // Nothing we can do 😪😪
|
|
505
|
-
} else {
|
|
506
|
-
expect(spy).toHaveBeenCalled();
|
|
507
|
-
}
|
|
508
|
-
});
|
|
509
|
-
} else {
|
|
510
|
-
it("can use 1 (second) expire", async () => {
|
|
511
|
-
await store.set("a", "b", { expires: 1 });
|
|
512
|
-
expect(await store.keys()).toEqual(["a"]);
|
|
513
|
-
expect(await store.values()).toEqual(["b"]);
|
|
514
|
-
expect(await store.get("a")).toBe("b");
|
|
515
|
-
await delay(2000);
|
|
516
|
-
expect(await store.keys()).toEqual([]);
|
|
517
|
-
expect(await store.values()).toEqual([]);
|
|
518
|
-
expect(await store.get("a")).toBe(null);
|
|
519
|
-
});
|
|
520
|
-
it("can use 1s expire", async () => {
|
|
521
|
-
await store.set("a", "b", { expires: "1s" });
|
|
522
|
-
expect(await store.keys()).toEqual(["a"]);
|
|
523
|
-
expect(await store.values()).toEqual(["b"]);
|
|
524
|
-
expect(await store.get("a")).toBe("b");
|
|
525
|
-
await delay(2000);
|
|
526
|
-
expect(await store.keys()).toEqual([]);
|
|
527
|
-
expect(await store.values()).toEqual([]);
|
|
528
|
-
expect(await store.get("a")).toBe(null);
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
describe(".prefix()", () => {
|
|
534
|
-
let session;
|
|
535
|
-
beforeAll(() => {
|
|
536
|
-
session = store.prefix("session:");
|
|
537
|
-
});
|
|
538
|
-
|
|
539
|
-
it("has the same methods", () => {
|
|
540
|
-
expect(Object.keys(store)).toEqual(Object.keys(session));
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
it("can write/read one", async () => {
|
|
544
|
-
const id = await session.set("a", "b");
|
|
545
|
-
expect(id).toBe("a");
|
|
546
|
-
expect(await session.get("a")).toBe("b");
|
|
547
|
-
expect(await store.get("session:a")).toBe("b");
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
it("checks the has properly", async () => {
|
|
551
|
-
expect(await session.has("a")).toBe(false);
|
|
552
|
-
await session.set("a", "b");
|
|
553
|
-
expect(await session.has("a")).toBe(true);
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
it("can add with the prefix", async () => {
|
|
557
|
-
const id = await session.add("b");
|
|
558
|
-
expect(id.length).toBe(24);
|
|
559
|
-
expect(id).not.toMatch(/^session\:/);
|
|
560
|
-
|
|
561
|
-
const keys = await store.keys();
|
|
562
|
-
expect(keys[0]).toMatch(/^session\:/);
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
it("the group operations return the proper values", async () => {
|
|
566
|
-
await session.set("a", "b");
|
|
567
|
-
|
|
568
|
-
expect(await session.keys()).toEqual(["a"]);
|
|
569
|
-
expect(await session.values()).toEqual(["b"]);
|
|
570
|
-
expect(await session.entries()).toEqual([["a", "b"]]);
|
|
571
|
-
|
|
572
|
-
expect(await store.keys()).toEqual(["session:a"]);
|
|
573
|
-
expect(await store.values()).toEqual(["b"]);
|
|
574
|
-
expect(await store.entries()).toEqual([["session:a", "b"]]);
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
it("clears only the substore", async () => {
|
|
578
|
-
await store.set("a", "b");
|
|
579
|
-
await session.set("c", "d");
|
|
580
|
-
|
|
581
|
-
expect((await store.keys()).sort()).toEqual(["a", "session:c"]);
|
|
582
|
-
await session.clear();
|
|
583
|
-
expect(await store.keys()).toEqual(["a"]);
|
|
584
|
-
});
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
describe(".prefix().prefix()", () => {
|
|
588
|
-
let auth;
|
|
589
|
-
beforeAll(() => {
|
|
590
|
-
auth = store.prefix("session:").prefix("auth:");
|
|
591
|
-
});
|
|
592
|
-
|
|
593
|
-
it("can write/read one", async () => {
|
|
594
|
-
const id = await auth.set("a", "b");
|
|
595
|
-
expect(id).toBe("a");
|
|
596
|
-
expect(await auth.get("a")).toBe("b");
|
|
597
|
-
expect(await store.get("session:auth:a")).toBe("b");
|
|
598
|
-
});
|
|
599
|
-
|
|
600
|
-
it("can add with the prefix", async () => {
|
|
601
|
-
const id = await auth.add("b");
|
|
602
|
-
expect(id.length).toBe(24);
|
|
603
|
-
expect(id).not.toMatch(/^session\:/);
|
|
604
|
-
|
|
605
|
-
const keys = await store.keys();
|
|
606
|
-
expect(keys[0]).toMatch(/^session\:auth\:/);
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
it("the group operations return the proper values", async () => {
|
|
610
|
-
await auth.set("a", "b");
|
|
611
|
-
|
|
612
|
-
expect(await auth.keys()).toEqual(["a"]);
|
|
613
|
-
expect(await auth.values()).toEqual(["b"]);
|
|
614
|
-
expect(await auth.entries()).toEqual([["a", "b"]]);
|
|
615
|
-
|
|
616
|
-
expect(await store.keys()).toEqual(["session:auth:a"]);
|
|
617
|
-
expect(await store.values()).toEqual(["b"]);
|
|
618
|
-
expect(await store.entries()).toEqual([["session:auth:a", "b"]]);
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
it("clears only the substore", async () => {
|
|
622
|
-
await store.set("a", "b");
|
|
623
|
-
await auth.set("c", "d");
|
|
624
|
-
|
|
625
|
-
expect((await store.keys()).sort()).toEqual(["a", "session:auth:c"]);
|
|
626
|
-
await auth.clear();
|
|
627
|
-
expect(await store.keys()).toEqual(["a"]);
|
|
628
|
-
});
|
|
629
|
-
});
|
|
630
|
-
});
|
|
631
|
-
}
|
package/src/index.types.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import kv from "..";
|
|
2
|
-
|
|
3
|
-
const store = kv();
|
|
4
|
-
|
|
5
|
-
(async () => {
|
|
6
|
-
await store.get("key");
|
|
7
|
-
await store.set("key", "value");
|
|
8
|
-
await store.set("key", "value", {});
|
|
9
|
-
await store.set("key", "value", { expires: 100 });
|
|
10
|
-
await store.set("key", "value", { expires: "100s" });
|
|
11
|
-
await store.prefix("a:").prefix("b:").get("hello");
|
|
12
|
-
const key1: string = await store.add("value");
|
|
13
|
-
const key2: string = await store.add("value", { expires: 100 });
|
|
14
|
-
const key3: string = await store.add("value", { expires: "100s" });
|
|
15
|
-
console.log(key1, key2, key3);
|
|
16
|
-
if (await store.has("key")) {
|
|
17
|
-
}
|
|
18
|
-
})();
|
package/src/test/customFull.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
const dataSource = {};
|
|
2
|
-
|
|
3
|
-
export default class MyClient {
|
|
4
|
-
get(key) {
|
|
5
|
-
return dataSource[key];
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
set(key, value) {
|
|
9
|
-
dataSource[key] = value;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
add(prefix, value) {
|
|
13
|
-
const id = Math.random().toString(16).slice(2).padStart(24, "0");
|
|
14
|
-
this.set(prefix + id, value);
|
|
15
|
-
return id;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
del(key) {
|
|
19
|
-
delete dataSource[key];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
*iterate(prefix) {
|
|
23
|
-
const entries = this.entries(prefix);
|
|
24
|
-
for (const entry of entries) {
|
|
25
|
-
yield entry;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Filter them by the prefix, note that `prefix` will always be a string
|
|
30
|
-
entries(prefix) {
|
|
31
|
-
const entries = Object.entries(dataSource);
|
|
32
|
-
if (!prefix) return entries;
|
|
33
|
-
return entries.filter(([key]) => key.startsWith(prefix));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
values(prefix) {
|
|
37
|
-
const list = this.entries(prefix);
|
|
38
|
-
return list.map((e) => e[1]);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Cannot have a keys() if it's an unamanaged store
|
|
42
|
-
// keys(prefix) {
|
|
43
|
-
// // This should throw
|
|
44
|
-
// }
|
|
45
|
-
}
|
package/src/test/customSimple.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const dataSource = {};
|
|
2
|
-
|
|
3
|
-
export default class MyClient {
|
|
4
|
-
get(key) {
|
|
5
|
-
return dataSource[key];
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// No need to stringify it or anything for a plain object storage
|
|
9
|
-
set(key, value) {
|
|
10
|
-
if (value === null) {
|
|
11
|
-
delete dataSource[key];
|
|
12
|
-
} else {
|
|
13
|
-
dataSource[key] = value;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Filter them by the prefix, note that `prefix` will always be a string
|
|
18
|
-
*iterate(prefix) {
|
|
19
|
-
const raw = Object.entries(dataSource);
|
|
20
|
-
const entries = prefix
|
|
21
|
-
? raw.filter(([key, value]) => key.startsWith(prefix))
|
|
22
|
-
: raw;
|
|
23
|
-
for (const entry of entries) {
|
|
24
|
-
yield entry;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
package/src/test/data.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
package/src/test/setup.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as util from "util";
|
|
2
|
-
|
|
3
|
-
// ref: https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
|
|
4
|
-
// ref: https://github.com/jsdom/jsdom/issues/2524
|
|
5
|
-
if (typeof TextEncoder === "undefined") {
|
|
6
|
-
Object.defineProperty(window, "TextEncoder", {
|
|
7
|
-
writable: true,
|
|
8
|
-
value: util.TextEncoder,
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
if (typeof TextDecoder === "undefined") {
|
|
12
|
-
Object.defineProperty(window, "TextDecoder", {
|
|
13
|
-
writable: true,
|
|
14
|
-
value: util.TextDecoder,
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (typeof setImmediate === "undefined") {
|
|
19
|
-
Object.defineProperty(window, "setImmediate", {
|
|
20
|
-
writable: true,
|
|
21
|
-
value: (cb) => setTimeout(cb, 0),
|
|
22
|
-
});
|
|
23
|
-
}
|