polystore 0.11.3 → 0.11.5
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 +1 -1
- package/readme.md +14 -3
- package/src/clients/cloudflare.js +3 -5
- package/src/clients/cookie.js +6 -9
- package/src/clients/etcd.js +9 -10
- package/src/clients/forage.js +5 -6
- package/src/clients/memory.js +6 -12
- package/src/clients/redis.js +8 -7
- package/src/clients/storage.js +13 -18
- package/src/index.d.ts +25 -10
- package/src/index.js +6 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polystore",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.5",
|
|
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",
|
package/readme.md
CHANGED
|
@@ -249,18 +249,29 @@ You can iterate over the whole store with an async iterator:
|
|
|
249
249
|
|
|
250
250
|
```js
|
|
251
251
|
for await (const [key, value] of store) {
|
|
252
|
-
|
|
252
|
+
console.log(key, value);
|
|
253
253
|
}
|
|
254
254
|
```
|
|
255
255
|
|
|
256
|
-
This is very useful for performance resons.
|
|
256
|
+
This is very useful for performance resons since it will retrieve the data sequentially, avoiding blocking the client while retrieving it all at once. The main disadvantage is if you keep writing data while the async iterator is running.
|
|
257
|
+
|
|
258
|
+
You can also iterate on a subset of the entries with `.prefix()` (the prefix is stripped from the key here, see [.`prefix()`](#prefix)):
|
|
257
259
|
|
|
258
260
|
```js
|
|
261
|
+
const session = store.prefix("session:");
|
|
262
|
+
for await (const [key, value] of session) {
|
|
263
|
+
console.log(key, value);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Same as this (both have the prefix stripped):
|
|
267
|
+
|
|
259
268
|
for await (const [key, value] of store.prefix("session:")) {
|
|
260
|
-
|
|
269
|
+
console.log(key, value);
|
|
261
270
|
}
|
|
262
271
|
```
|
|
263
272
|
|
|
273
|
+
There are also methods to retrieve all of the keys, values, or entries at once below, but those [have worse performance](#performance).
|
|
274
|
+
|
|
264
275
|
### .keys()
|
|
265
276
|
|
|
266
277
|
Get all of the keys in the store, optionally filtered by a prefix:
|
|
@@ -23,8 +23,7 @@ export default class Cloudflare {
|
|
|
23
23
|
|
|
24
24
|
async set(key, value, { expires } = {}) {
|
|
25
25
|
const expirationTtl = expires ? Math.round(expires) : undefined;
|
|
26
|
-
this.client.put(key, JSON.stringify(value), { expirationTtl });
|
|
27
|
-
return key;
|
|
26
|
+
return this.client.put(key, JSON.stringify(value), { expirationTtl });
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
async del(key) {
|
|
@@ -40,8 +39,7 @@ export default class Cloudflare {
|
|
|
40
39
|
const keys = raw.keys.map((k) => k.name);
|
|
41
40
|
for (let key of keys) {
|
|
42
41
|
const value = await this.get(key);
|
|
43
|
-
// By the time this specific value is read, it could
|
|
44
|
-
// already be gone!
|
|
42
|
+
// By the time this specific value is read, it could be gone!
|
|
45
43
|
if (!value) continue;
|
|
46
44
|
yield [key, value];
|
|
47
45
|
}
|
|
@@ -63,7 +61,7 @@ export default class Cloudflare {
|
|
|
63
61
|
async entries(prefix = "") {
|
|
64
62
|
const keys = await this.keys(prefix);
|
|
65
63
|
const values = await Promise.all(keys.map((k) => this.get(k)));
|
|
66
|
-
return keys.map((
|
|
64
|
+
return keys.map((k, i) => [k, values[i]]);
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
async clear(prefix = "") {
|
package/src/clients/cookie.js
CHANGED
|
@@ -31,22 +31,19 @@ export default class Cookie {
|
|
|
31
31
|
|
|
32
32
|
set(key, data = null, { expires } = {}) {
|
|
33
33
|
// Setting it to null deletes it
|
|
34
|
-
if (data === null) {
|
|
35
|
-
data = "";
|
|
36
|
-
expires = -100;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
34
|
let expireStr = "";
|
|
40
35
|
// NOTE: 0 is already considered here!
|
|
41
36
|
if (expires !== null) {
|
|
42
|
-
const
|
|
43
|
-
const time = new Date(now + expires * 1000).toUTCString();
|
|
37
|
+
const time = new Date(Date.now() + expires * 1000).toUTCString();
|
|
44
38
|
expireStr = `; expires=${time}`;
|
|
45
39
|
}
|
|
46
40
|
|
|
47
|
-
const value = encodeURIComponent(JSON.stringify(data));
|
|
41
|
+
const value = encodeURIComponent(JSON.stringify(data || ""));
|
|
48
42
|
document.cookie = encodeURIComponent(key) + "=" + value + expireStr;
|
|
49
|
-
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
del(key) {
|
|
46
|
+
this.set(key, "", { expires: -100 });
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
async *iterate(prefix = "") {
|
package/src/clients/etcd.js
CHANGED
|
@@ -14,11 +14,11 @@ export default class Etcd {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async set(key, value) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
17
|
+
return this.client.put(key).value(JSON.stringify(value));
|
|
18
|
+
}
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
async del(key) {
|
|
21
|
+
return this.client.delete().key(key).exec();
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
async *iterate(prefix = "") {
|
|
@@ -28,19 +28,18 @@ export default class Etcd {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
async keys(prefix = "") {
|
|
32
|
+
return this.client.getAll().prefix(prefix).keys();
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
async entries(prefix = "") {
|
|
32
|
-
const keys = await this.
|
|
36
|
+
const keys = await this.keys(prefix);
|
|
33
37
|
const values = await Promise.all(keys.map((k) => this.get(k)));
|
|
34
38
|
return keys.map((k, i) => [k, values[i]]);
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
async clear(prefix = "") {
|
|
38
42
|
if (!prefix) return this.client.delete().all();
|
|
39
|
-
|
|
40
43
|
return this.client.delete().prefix(prefix);
|
|
41
44
|
}
|
|
42
|
-
|
|
43
|
-
async close() {
|
|
44
|
-
// return this.client.close();
|
|
45
|
-
}
|
|
46
45
|
}
|
package/src/clients/forage.js
CHANGED
|
@@ -14,12 +14,11 @@ export default class Forage {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async set(key, value) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return key;
|
|
17
|
+
return this.client.setItem(key, value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async del(key) {
|
|
21
|
+
return this.client.removeItem(key);
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
async *iterate(prefix = "") {
|
package/src/clients/memory.js
CHANGED
|
@@ -14,33 +14,27 @@ export default class Memory {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
set(key, data) {
|
|
17
|
-
this.client.set(key, data);
|
|
17
|
+
return this.client.set(key, data);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
del(key) {
|
|
21
|
-
this.client.delete(key);
|
|
21
|
+
return this.client.delete(key);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
*iterate(prefix = "") {
|
|
25
|
-
const
|
|
26
|
-
for (const entry of entries) {
|
|
25
|
+
for (const entry of this.client.entries()) {
|
|
27
26
|
if (!entry[0].startsWith(prefix)) continue;
|
|
28
27
|
yield entry;
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
// Group methods
|
|
33
|
-
entries(prefix = "") {
|
|
34
|
-
const entries = [...this.client.entries()];
|
|
35
|
-
return entries.filter((p) => p[0].startsWith(prefix));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
31
|
clear(prefix = "") {
|
|
39
32
|
// Delete the whole dataset
|
|
40
33
|
if (!prefix) return this.client.clear();
|
|
41
34
|
|
|
42
35
|
// Delete them in a map
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
return [...this.client.keys()]
|
|
37
|
+
.filter((k) => k.startsWith(prefix))
|
|
38
|
+
.map((k) => this.del(k));
|
|
45
39
|
}
|
|
46
40
|
}
|
package/src/clients/redis.js
CHANGED
|
@@ -19,13 +19,12 @@ export default class Redis {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
async set(key, value, { expires } = {}) {
|
|
22
|
-
if (value === null || expires === 0) {
|
|
23
|
-
return this.client.del(key);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
22
|
const EX = expires ? Math.round(expires) : undefined;
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
return this.client.set(key, JSON.stringify(value), { EX });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async del(key) {
|
|
27
|
+
return this.client.del(key);
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
async has(key) {
|
|
@@ -42,6 +41,8 @@ export default class Redis {
|
|
|
42
41
|
const MATCH = prefix + "*";
|
|
43
42
|
for await (const key of this.client.scanIterator({ MATCH })) {
|
|
44
43
|
const value = await this.get(key);
|
|
44
|
+
// By the time this specific value is read, it could be gone!
|
|
45
|
+
if (!value) continue;
|
|
45
46
|
yield [key, value];
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -68,7 +69,7 @@ export default class Redis {
|
|
|
68
69
|
if (!prefix) return this.client.flushAll();
|
|
69
70
|
|
|
70
71
|
const list = await this.keys(prefix);
|
|
71
|
-
return Promise.all(list.map((k) => this.
|
|
72
|
+
return Promise.all(list.map((k) => this.client.del(k)));
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
async close() {
|
package/src/clients/storage.js
CHANGED
|
@@ -17,27 +17,20 @@ export default class WebStorage {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
set(key, data) {
|
|
20
|
-
|
|
21
|
-
this.client.removeItem(key);
|
|
22
|
-
} else {
|
|
23
|
-
this.client.setItem(key, JSON.stringify(data));
|
|
24
|
-
}
|
|
25
|
-
return key;
|
|
20
|
+
return this.client.setItem(key, JSON.stringify(data));
|
|
26
21
|
}
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
for (const entry of entries) {
|
|
31
|
-
yield entry;
|
|
32
|
-
}
|
|
23
|
+
del(key) {
|
|
24
|
+
return this.client.removeItem(key);
|
|
33
25
|
}
|
|
34
26
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
27
|
+
*iterate(prefix = "") {
|
|
28
|
+
for (const key of Object.keys(this.client)) {
|
|
29
|
+
if (!key.startsWith(prefix)) continue;
|
|
30
|
+
const value = this.get(key);
|
|
31
|
+
if (!value) continue;
|
|
32
|
+
yield [key, value];
|
|
33
|
+
}
|
|
41
34
|
}
|
|
42
35
|
|
|
43
36
|
clear(prefix = "") {
|
|
@@ -45,6 +38,8 @@ export default class WebStorage {
|
|
|
45
38
|
if (!prefix) return this.client.clear();
|
|
46
39
|
|
|
47
40
|
// Delete them in a map
|
|
48
|
-
return
|
|
41
|
+
return Object.keys(this.client)
|
|
42
|
+
.filter((k) => k.startsWith(prefix))
|
|
43
|
+
.map((k) => this.del(k));
|
|
49
44
|
}
|
|
50
45
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
type Options = { expires?: number | string | null };
|
|
2
|
-
type Value =
|
|
1
|
+
export type Options = { expires?: number | string | null };
|
|
2
|
+
export type Value = string | { [key: string]: Value } | Value[];
|
|
3
3
|
|
|
4
|
-
interface Store {
|
|
4
|
+
export interface Store {
|
|
5
5
|
/**
|
|
6
6
|
* Save the data on an autogenerated key, can add expiration as well:
|
|
7
7
|
*
|
|
@@ -13,7 +13,7 @@ interface Store {
|
|
|
13
13
|
*
|
|
14
14
|
* **[→ Full .add() Docs](https://polystore.dev/documentation#add)**
|
|
15
15
|
*/
|
|
16
|
-
add: (value:
|
|
16
|
+
add: <T = Value>(value: T, options?: Options) => Promise<string>;
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Save the data on the given key, can add expiration as well:
|
|
@@ -26,7 +26,7 @@ interface Store {
|
|
|
26
26
|
*
|
|
27
27
|
* **[→ Full .set() Docs](https://polystore.dev/documentation#set)**
|
|
28
28
|
*/
|
|
29
|
-
set: (key: string, value:
|
|
29
|
+
set: <T = Value>(key: string, value: T, options?: Options) => Promise<string>;
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Read a single value from the KV store:
|
|
@@ -42,7 +42,7 @@ interface Store {
|
|
|
42
42
|
*
|
|
43
43
|
* **[→ Full .get() Docs](https://polystore.dev/documentation#get)**
|
|
44
44
|
*/
|
|
45
|
-
get: (key: string) => Promise<
|
|
45
|
+
get: <T = Value>(key: string) => Promise<T | null>;
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Check whether a key exists or not:
|
|
@@ -72,7 +72,7 @@ interface Store {
|
|
|
72
72
|
*
|
|
73
73
|
* **[→ Full .del() Docs](https://polystore.dev/documentation#del)**
|
|
74
74
|
*/
|
|
75
|
-
del: (key: string) => Promise<
|
|
75
|
+
del: (key: string) => Promise<string>;
|
|
76
76
|
|
|
77
77
|
/**
|
|
78
78
|
* Return an array of the entries, in the [key, value] format:
|
|
@@ -87,7 +87,7 @@ interface Store {
|
|
|
87
87
|
*
|
|
88
88
|
* **[→ Full .entries() Docs](https://polystore.dev/documentation#entries)**
|
|
89
89
|
*/
|
|
90
|
-
entries: () => Promise<[key: string, value:
|
|
90
|
+
entries: <T = Value>() => Promise<[key: string, value: T][]>;
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
93
|
* Return an array of the keys in the store:
|
|
@@ -117,7 +117,7 @@ interface Store {
|
|
|
117
117
|
*
|
|
118
118
|
* **[→ Full .values() Docs](https://polystore.dev/documentation#values)**
|
|
119
119
|
*/
|
|
120
|
-
values: () => Promise<
|
|
120
|
+
values: <T = Value>() => Promise<T[]>;
|
|
121
121
|
|
|
122
122
|
/**
|
|
123
123
|
* Return an object with the keys:values in the store:
|
|
@@ -132,7 +132,7 @@ interface Store {
|
|
|
132
132
|
*
|
|
133
133
|
* **[→ Full .all() Docs](https://polystore.dev/documentation#all)**
|
|
134
134
|
*/
|
|
135
|
-
all: () => Promise<{ [key: string]:
|
|
135
|
+
all: <T = Value>() => Promise<{ [key: string]: T }>;
|
|
136
136
|
|
|
137
137
|
/**
|
|
138
138
|
* Delete all of the records of the store:
|
|
@@ -176,6 +176,21 @@ interface Store {
|
|
|
176
176
|
* **[→ Full .close() Docs](https://polystore.dev/documentation#close)**
|
|
177
177
|
*/
|
|
178
178
|
close?: () => Promise<null>;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* An iterator that goes through all of the key:value pairs in the client
|
|
182
|
+
*
|
|
183
|
+
* ```js
|
|
184
|
+
* for await (const [key, value] of store) {
|
|
185
|
+
* console.log(key, value);
|
|
186
|
+
* }
|
|
187
|
+
* ```
|
|
188
|
+
*
|
|
189
|
+
* **[→ Full Iterator Docs](https://polystore.dev/documentation#iterator)**
|
|
190
|
+
*/
|
|
191
|
+
[Symbol.asyncIterator]: () => {
|
|
192
|
+
next: () => Promise<{ value: [string, Value] }>;
|
|
193
|
+
};
|
|
179
194
|
}
|
|
180
195
|
|
|
181
196
|
export default function (store?: any): Store;
|
package/src/index.js
CHANGED
|
@@ -6,8 +6,6 @@ class Store {
|
|
|
6
6
|
|
|
7
7
|
constructor(clientPromise = new Map()) {
|
|
8
8
|
this.promise = Promise.resolve(clientPromise).then(async (client) => {
|
|
9
|
-
if (client?.open) await client.open();
|
|
10
|
-
if (client?.connect) await client.connect();
|
|
11
9
|
this.client = this.#find(client);
|
|
12
10
|
this.#validate(this.client);
|
|
13
11
|
this.promise = null;
|
|
@@ -42,20 +40,12 @@ class Store {
|
|
|
42
40
|
}
|
|
43
41
|
|
|
44
42
|
if (!client.EXPIRES) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
throw new Error(
|
|
52
|
-
`You can only define client.keys() when the client manages the expiration; otherwise please do NOT define .keys() and let us manage them`
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
if (client.values) {
|
|
56
|
-
console.warn(
|
|
57
|
-
`Since this KV client does not manage expiration, it's better not to define client.values() since it doesn't allow us to evict expired keys`
|
|
58
|
-
);
|
|
43
|
+
for (let method of ["has", "keys", "values"]) {
|
|
44
|
+
if (client[method]) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`You can only define client.${method}() when the client manages the expiration; otherwise please do NOT define .${method}() and let us manage it`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
59
49
|
}
|
|
60
50
|
}
|
|
61
51
|
}
|