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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polystore",
3
- "version": "0.11.3",
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. You can also iterate on a subset of the entries with .prefix:
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((key, i) => [key, values[i]]);
64
+ return keys.map((k, i) => [k, values[i]]);
67
65
  }
68
66
 
69
67
  async clear(prefix = "") {
@@ -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 now = new Date().getTime();
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
- return key;
43
+ }
44
+
45
+ del(key) {
46
+ this.set(key, "", { expires: -100 });
50
47
  }
51
48
 
52
49
  async *iterate(prefix = "") {
@@ -14,11 +14,11 @@ export default class Etcd {
14
14
  }
15
15
 
16
16
  async set(key, value) {
17
- if (value === null) {
18
- return this.client.delete().key(key).exec();
19
- }
17
+ return this.client.put(key).value(JSON.stringify(value));
18
+ }
20
19
 
21
- await this.client.put(key).value(JSON.stringify(value));
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.client.getAll().prefix(prefix).keys();
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
  }
@@ -14,12 +14,11 @@ export default class Forage {
14
14
  }
15
15
 
16
16
  async set(key, value) {
17
- if (value === null) {
18
- await this.client.removeItem(key);
19
- } else {
20
- await this.client.setItem(key, value);
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 = "") {
@@ -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 entries = this.entries();
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
- const list = this.entries(prefix);
44
- return Promise.all(list.map((e) => e[0]).map((k) => this.del(k)));
36
+ return [...this.client.keys()]
37
+ .filter((k) => k.startsWith(prefix))
38
+ .map((k) => this.del(k));
45
39
  }
46
40
  }
@@ -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
- await this.client.set(key, JSON.stringify(value), { EX });
28
- return key;
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.set(k, null)));
72
+ return Promise.all(list.map((k) => this.client.del(k)));
72
73
  }
73
74
 
74
75
  async close() {
@@ -17,27 +17,20 @@ export default class WebStorage {
17
17
  }
18
18
 
19
19
  set(key, data) {
20
- if (data === null) {
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
- *iterate(prefix = "") {
29
- const entries = this.entries(prefix);
30
- for (const entry of entries) {
31
- yield entry;
32
- }
23
+ del(key) {
24
+ return this.client.removeItem(key);
33
25
  }
34
26
 
35
- // Group methods
36
- entries(prefix = "") {
37
- const entries = Object.entries(this.client);
38
- return entries
39
- .map((p) => [p[0], p[1] ? JSON.parse(p[1]) : null])
40
- .filter((p) => p[0].startsWith(prefix));
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 this.entries(prefix).map((e) => this.set(e[0], null));
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 = null | string | { [key: string]: Value } | 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: Value, options?: Options) => Promise<string>;
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: Value, options?: Options) => Promise<string>;
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<Value>;
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<null>;
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: 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<Value[]>;
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]: Value }>;
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
- if (client.has) {
46
- throw new Error(
47
- `You can only define client.has() when the client manages the expiration; otherwise please do NOT define .has() and let us manage it`
48
- );
49
- }
50
- if (client.keys) {
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
  }