polystore 0.15.4 → 0.15.6

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.15.4",
3
+ "version": "0.15.6",
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",
@@ -32,13 +32,13 @@ export default class File {
32
32
  // Internal
33
33
  #read = async () => {
34
34
  const fsp = await this.promise;
35
- const data = await fsp.readFile(this.file, "utf8");
36
- return JSON.parse(data || "{}");
35
+ const text = await fsp.readFile(this.file, "utf8");
36
+ return text ? JSON.parse(text) : {};
37
37
  };
38
38
 
39
39
  #write = async (data) => {
40
40
  const fsp = await this.promise;
41
- fsp.writeFile(this.file, JSON.stringify(data, null, 2));
41
+ return fsp.writeFile(this.file, JSON.stringify(data, null, 2));
42
42
  };
43
43
 
44
44
  get = async (key) => {
@@ -54,7 +54,6 @@ export default class File {
54
54
  data[key] = value;
55
55
  }
56
56
  await this.#write(data);
57
- return key;
58
57
  };
59
58
 
60
59
  async *iterate(prefix = "") {
@@ -1,67 +1,56 @@
1
- const noFileOk = (error) => {
2
- if (error.code === "ENOENT") return null;
3
- throw error;
4
- };
1
+ const json = (data) => JSON.stringify(data, null, 2);
5
2
 
6
3
  // A client that uses a single file (JSON) as a store
7
4
  export default class Folder {
8
5
  // Check if this is the right class for the given client
9
6
  static test(client) {
10
- if (
7
+ if (client instanceof URL) client = client.href;
8
+ return (
11
9
  typeof client === "string" &&
12
- client.startsWith("file:") &&
10
+ client.startsWith("file://") &&
13
11
  client.endsWith("/")
14
- )
15
- return true;
16
- return (
17
- client instanceof URL &&
18
- client.protocol === "file:" &&
19
- client.pathname.endsWith("/")
20
12
  );
21
13
  }
22
14
 
23
15
  constructor(folder) {
24
- this.folder =
25
- typeof folder === "string"
26
- ? folder.slice("file://".length).replace(/\/$/, "") + "/"
27
- : folder.pathname.replace(/\/$/, "") + "/";
16
+ if (folder instanceof URL) folder = folder.href;
17
+ folder = folder.replace(/^file:\/\//, "");
28
18
 
29
19
  // Run this once on launch; import the FS module and reset the file
30
- this.promise = (async () => {
31
- const fsp = await import("node:fs/promises");
32
-
20
+ const prom = import("node:fs/promises").then((fsp) => {
33
21
  // Make sure the folder already exists, so attempt to create it
34
22
  // It fails if it already exists, hence the catch case
35
- await fsp.mkdir(this.folder, { recursive: true }).catch(() => {});
36
- return fsp;
37
- })();
23
+ return fsp.mkdir(folder, { recursive: true }).then(
24
+ () => fsp,
25
+ () => {},
26
+ );
27
+ });
28
+
29
+ const getter = (_, name) => {
30
+ return async (key, ...props) => {
31
+ const file = folder + (key ? key + ".json" : "");
32
+ const method = (await prom)[name];
33
+ return method(file, ...props).catch((error) => {
34
+ if (error.code === "ENOENT") return null;
35
+ throw error;
36
+ });
37
+ };
38
+ };
39
+
40
+ this.fs = new Proxy({}, { get: getter });
38
41
  }
39
42
 
40
- async get(key) {
41
- const fsp = await this.promise;
42
- const file = this.folder + key + ".json";
43
- const text = await fsp.readFile(file, "utf8").catch(noFileOk);
44
- if (!text) return null;
45
- return JSON.parse(text);
46
- }
43
+ get = async (key) => {
44
+ const text = await this.fs.readFile(key, "utf8");
45
+ return text ? JSON.parse(text) : null;
46
+ };
47
47
 
48
- async set(key, value) {
49
- const fsp = await this.promise;
50
- const file = this.folder + key + ".json";
51
- await fsp.writeFile(file, JSON.stringify(value, null, 2), "utf8");
52
- return file;
53
- }
48
+ set = (key, value) => this.fs.writeFile(key, json(value), "utf8");
54
49
 
55
- async del(key) {
56
- const file = this.folder + key + ".json";
57
- const fsp = await this.promise;
58
- await fsp.unlink(file).catch(noFileOk);
59
- return file;
60
- }
50
+ del = (key) => this.fs.unlink(key);
61
51
 
62
52
  async *iterate(prefix = "") {
63
- const fsp = await this.promise;
64
- const all = await fsp.readdir(this.folder);
53
+ const all = await this.fs.readdir();
65
54
  const keys = all
66
55
  .filter((f) => f.startsWith(prefix) && f.endsWith(".json"))
67
56
  .map((name) => name.slice(0, -".json".length));
@@ -70,14 +59,4 @@ export default class Folder {
70
59
  yield [key, data];
71
60
  }
72
61
  }
73
-
74
- // async clear(prefix = "") {
75
- // const data = await this.#read();
76
- // for (let key in data) {
77
- // if (key.startsWith(prefix)) {
78
- // delete data[key];
79
- // }
80
- // }
81
- // await this.#write(data);
82
- // }
83
62
  }
@@ -4,37 +4,25 @@ export default class Redis {
4
4
  EXPIRES = true;
5
5
 
6
6
  // Check if this is the right class for the given client
7
- static test(client) {
8
- return client && client.pSubscribe && client.sSubscribe;
9
- }
7
+ static test = (client) => client && client.pSubscribe && client.sSubscribe;
10
8
 
11
9
  constructor(client) {
12
10
  this.client = client;
13
11
  }
14
12
 
15
- async get(key) {
16
- const value = await this.client.get(key);
17
- if (!value) return null;
18
- return JSON.parse(value);
19
- }
13
+ get = async (key) => {
14
+ const text = await this.client.get(key);
15
+ return text ? JSON.parse(text) : null;
16
+ };
20
17
 
21
- async set(key, value, { expires } = {}) {
18
+ set = async (key, value, { expires } = {}) => {
22
19
  const EX = expires ? Math.round(expires) : undefined;
23
20
  return this.client.set(key, JSON.stringify(value), { EX });
24
- }
21
+ };
25
22
 
26
- async del(key) {
27
- return this.client.del(key);
28
- }
29
-
30
- async has(key) {
31
- return Boolean(await this.client.exists(key));
32
- }
23
+ del = (key) => this.client.del(key);
33
24
 
34
- // Group methods
35
- async keys(prefix = "") {
36
- return this.client.keys(prefix + "*");
37
- }
25
+ has = async (key) => Boolean(await this.client.exists(key));
38
26
 
39
27
  // Go through each of the [key, value] in the set
40
28
  async *iterate(prefix = "") {
@@ -47,32 +35,30 @@ export default class Redis {
47
35
  }
48
36
  }
49
37
 
50
- // Optimizing the retrieval of them all in bulk by loading the values
51
- // in parallel
52
- async entries(prefix = "") {
53
- const keys = await this.keys(prefix);
54
- const values = await Promise.all(keys.map((k) => this.get(k)));
55
- return keys.map((k, i) => [k, values[i]]);
56
- }
57
-
58
38
  // Optimizing the retrieval of them by not getting their values
59
- async keys(prefix = "") {
39
+ keys = async (prefix = "") => {
60
40
  const MATCH = prefix + "*";
61
41
  const keys = [];
62
42
  for await (const key of this.client.scanIterator({ MATCH })) {
63
43
  keys.push(key);
64
44
  }
65
45
  return keys;
66
- }
46
+ };
67
47
 
68
- async clear(prefix = "") {
48
+ // Optimizing the retrieval of them all in bulk by loading the values
49
+ // in parallel
50
+ entries = async (prefix = "") => {
51
+ const keys = await this.keys(prefix);
52
+ const values = await Promise.all(keys.map((k) => this.get(k)));
53
+ return keys.map((k, i) => [k, values[i]]);
54
+ };
55
+
56
+ clear = async (prefix = "") => {
69
57
  if (!prefix) return this.client.flushAll();
70
58
 
71
59
  const list = await this.keys(prefix);
72
60
  return Promise.all(list.map((k) => this.client.del(k)));
73
- }
61
+ };
74
62
 
75
- async close() {
76
- return this.client.quit();
77
- }
63
+ close = () => this.client.quit();
78
64
  }