polystore 0.14.0 → 0.14.1
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 +150 -5
- package/src/clients/folder.js +6 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polystore",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
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
|
@@ -462,13 +462,23 @@ console.log(await store.get("key1"));
|
|
|
462
462
|
|
|
463
463
|
<details>
|
|
464
464
|
<summary>Why use polystore with <code>new Map()</code>?</summary>
|
|
465
|
-
<p>
|
|
465
|
+
<p>These benefits are for wrapping Map() with polystore:</p>
|
|
466
466
|
<ul>
|
|
467
467
|
<li><strong>Expiration</strong>: you can now set lifetime to your values so that they are automatically evicted when the time passes. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
468
468
|
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
469
469
|
</ul>
|
|
470
470
|
</details>
|
|
471
471
|
|
|
472
|
+
```js
|
|
473
|
+
// GOOD - with polystore
|
|
474
|
+
await store.set("key1", { name: "Francisco" }, { expires: "2days" });
|
|
475
|
+
|
|
476
|
+
// COMPLEX - With sessionStorage
|
|
477
|
+
const data = new Map();
|
|
478
|
+
data.set("key1", { name: "Francisco" });
|
|
479
|
+
// Expiration not supported
|
|
480
|
+
```
|
|
481
|
+
|
|
472
482
|
### Local Storage
|
|
473
483
|
|
|
474
484
|
The traditional localStorage that we all know and love, this time with a unified API, and promises:
|
|
@@ -485,6 +495,26 @@ console.log(await store.get("key1"));
|
|
|
485
495
|
|
|
486
496
|
Same limitations as always apply to localStorage, if you think you are going to use too much storage try instead our integration with [Local Forage](#local-forage)!
|
|
487
497
|
|
|
498
|
+
<details>
|
|
499
|
+
<summary>Why use polystore with <code>localStorage</code>?</summary>
|
|
500
|
+
<p>These benefits are for wrapping localStorage with polystore:</p>
|
|
501
|
+
<ul>
|
|
502
|
+
<li><strong>Data structures</strong>: with Polystore you can pass more complex data structures and we'll handle the serialization/deserialization.</li>
|
|
503
|
+
<li><strong>Expiration</strong>: you can now set lifetime to your values so that they are automatically evicted when the time passes. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
504
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
505
|
+
</ul>
|
|
506
|
+
</details>
|
|
507
|
+
|
|
508
|
+
```js
|
|
509
|
+
// GOOD - with polystore
|
|
510
|
+
await store.set("key1", { name: "Francisco" }, { expires: "2days" });
|
|
511
|
+
|
|
512
|
+
// COMPLEX - With localStorage
|
|
513
|
+
const serialValue = JSON.stringify({ name: "Francisco" });
|
|
514
|
+
localStorage.set("key1", serialValue);
|
|
515
|
+
// Expiration not supported
|
|
516
|
+
```
|
|
517
|
+
|
|
488
518
|
### Session Storage
|
|
489
519
|
|
|
490
520
|
Same as localStorage, but now for the session only:
|
|
@@ -499,6 +529,26 @@ console.log(await store.get("key1"));
|
|
|
499
529
|
// "Hello world"
|
|
500
530
|
```
|
|
501
531
|
|
|
532
|
+
<details>
|
|
533
|
+
<summary>Why use polystore with <code>sessionStorage</code>?</summary>
|
|
534
|
+
<p>These benefits are for wrapping sessionStorage with polystore:</p>
|
|
535
|
+
<ul>
|
|
536
|
+
<li><strong>Data structures</strong>: with Polystore you can pass more complex data structures and we'll handle the serialization/deserialization.</li>
|
|
537
|
+
<li><strong>Expiration</strong>: you can now set lifetime to your values so that they are automatically evicted when the time passes. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
538
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
539
|
+
</ul>
|
|
540
|
+
</details>
|
|
541
|
+
|
|
542
|
+
```js
|
|
543
|
+
// GOOD - with polystore
|
|
544
|
+
await store.set("key1", { name: "Francisco" }, { expires: "2days" });
|
|
545
|
+
|
|
546
|
+
// COMPLEX - With sessionStorage
|
|
547
|
+
const serialValue = JSON.stringify({ name: "Francisco" });
|
|
548
|
+
sessionStorage.set("key1", serialValue);
|
|
549
|
+
// Expiration not supported
|
|
550
|
+
```
|
|
551
|
+
|
|
502
552
|
### Cookies
|
|
503
553
|
|
|
504
554
|
Supports native browser cookies, including setting the expire time:
|
|
@@ -517,6 +567,16 @@ It is fairly limited for how powerful cookies are, but in exchange it has the sa
|
|
|
517
567
|
|
|
518
568
|
> Note: the cookie expire resolution is in the seconds, so times shorter than 1 second like `expires: 0.02` (20 ms) don't make sense for this storage method and won't properly save them.
|
|
519
569
|
|
|
570
|
+
<details>
|
|
571
|
+
<summary>Why use polystore with <code>cookies</code>?</summary>
|
|
572
|
+
<p>These benefits are for wrapping cookies with polystore:</p>
|
|
573
|
+
<ul>
|
|
574
|
+
<li><strong>Data structures</strong>: with Polystore you can pass more complex data structures and we'll handle the serialization/deserialization.</li>
|
|
575
|
+
<li><strong>Intuitive expirations</strong>: use plain English to specify the expiration time like <code>10min</code>. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
576
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
577
|
+
</ul>
|
|
578
|
+
</details>
|
|
579
|
+
|
|
520
580
|
### Local Forage
|
|
521
581
|
|
|
522
582
|
Supports localForage (with any driver it uses) so that you have a unified API. It also _adds_ the `expires` option to the setters!
|
|
@@ -532,6 +592,15 @@ console.log(await store.get("key1"));
|
|
|
532
592
|
// "Hello world"
|
|
533
593
|
```
|
|
534
594
|
|
|
595
|
+
<details>
|
|
596
|
+
<summary>Why use polystore with <code>localStorage</code>?</summary>
|
|
597
|
+
<p>These benefits are for wrapping localStorage with polystore:</p>
|
|
598
|
+
<ul>
|
|
599
|
+
<li><strong>Intuitive expirations</strong>: use plain English to specify the expiration time like <code>10min</code>. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
600
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
601
|
+
</ul>
|
|
602
|
+
</details>
|
|
603
|
+
|
|
535
604
|
### Redis Client
|
|
536
605
|
|
|
537
606
|
Supports the official Node Redis Client. You can pass either the client or the promise:
|
|
@@ -551,6 +620,15 @@ You don't need to `await` for the connect or similar, this will process it prope
|
|
|
551
620
|
|
|
552
621
|
> Note: the Redis client expire resolution is in the seconds, so times shorter than 1 second like `expires: 0.02` (20 ms) don't make sense for this storage method and won't properly save them.
|
|
553
622
|
|
|
623
|
+
<details>
|
|
624
|
+
<summary>Why use polystore with <code>Redis</code>?</summary>
|
|
625
|
+
<p>These benefits are for wrapping Redis with polystore:</p>
|
|
626
|
+
<ul>
|
|
627
|
+
<li><strong>Intuitive expirations</strong>: use plain English to specify the expiration time like <code>10min</code>. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
628
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
629
|
+
</ul>
|
|
630
|
+
</details>
|
|
631
|
+
|
|
554
632
|
### File
|
|
555
633
|
|
|
556
634
|
Treat a JSON file in your filesystem as the source for the KV store:
|
|
@@ -576,6 +654,30 @@ const store1 = kv(new URL(`file://${process.cwd()}/cache.json`));
|
|
|
576
654
|
const store2 = kv(new URL(`file://${import.meta.dirname}/data.json`));
|
|
577
655
|
```
|
|
578
656
|
|
|
657
|
+
<details>
|
|
658
|
+
<summary>Why use polystore with a file?</summary>
|
|
659
|
+
<p>These benefits are for wrapping a file with polystore:</p>
|
|
660
|
+
<ul>
|
|
661
|
+
<li><strong>Data structures</strong>: with Polystore you can pass more complex data structures and we'll handle the serialization/deserialization.</li>
|
|
662
|
+
<li><strong>Expiration</strong>: you can now set lifetime to your values so that they are automatically evicted when the time passes. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
663
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
664
|
+
</ul>
|
|
665
|
+
</details>
|
|
666
|
+
|
|
667
|
+
```js
|
|
668
|
+
// GOOD - with polystore
|
|
669
|
+
await store.set("key1", { name: "Francisco" }, { expires: "2days" });
|
|
670
|
+
|
|
671
|
+
// COMPLEX - With native file managing
|
|
672
|
+
const file = './data/users.json';
|
|
673
|
+
const str = await fsp.readFile(file, "utf-8");
|
|
674
|
+
const data = JSON.parse(str);
|
|
675
|
+
data["key1"] = { name: "Francisco" };
|
|
676
|
+
const serialValue = JSON.stringify(data);
|
|
677
|
+
await fsp.writeFile(file, serialValue);
|
|
678
|
+
// Expiration not supported (and error handling not shown)
|
|
679
|
+
```
|
|
680
|
+
|
|
579
681
|
### Folder
|
|
580
682
|
|
|
581
683
|
Treat a single folder in your filesystem as the source for the KV store, with each key being within a file:
|
|
@@ -601,6 +703,27 @@ const store1 = kv(new URL(`file://${process.cwd()}/cache/`));
|
|
|
601
703
|
const store2 = kv(new URL(`file://${import.meta.dirname}/data/`));
|
|
602
704
|
```
|
|
603
705
|
|
|
706
|
+
<details>
|
|
707
|
+
<summary>Why use polystore with a folder?</summary>
|
|
708
|
+
<p>These benefits are for wrapping a folder with polystore:</p>
|
|
709
|
+
<ul>
|
|
710
|
+
<li><strong>Data structures</strong>: with Polystore you can pass more complex data structures and we'll handle the serialization/deserialization.</li>
|
|
711
|
+
<li><strong>Expiration</strong>: you can now set lifetime to your values so that they are automatically evicted when the time passes. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
712
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
713
|
+
</ul>
|
|
714
|
+
</details>
|
|
715
|
+
|
|
716
|
+
```js
|
|
717
|
+
// GOOD - with polystore
|
|
718
|
+
await store.set("key1", { name: "Francisco" }, { expires: "2days" });
|
|
719
|
+
|
|
720
|
+
// COMPLEX - With native folder
|
|
721
|
+
const file = './data/user/key1.json';
|
|
722
|
+
const serialValue = JSON.stringify({ name: "Francisco" });
|
|
723
|
+
await fsp.writeFile(file, serialValue);
|
|
724
|
+
// Expiration not supported (and error handling not shown)
|
|
725
|
+
```
|
|
726
|
+
|
|
604
727
|
### Cloudflare KV
|
|
605
728
|
|
|
606
729
|
Supports the official Cloudflare's KV stores. Follow [the official guide](https://developers.cloudflare.com/kv/get-started/), then load it like this:
|
|
@@ -621,7 +744,15 @@ export default {
|
|
|
621
744
|
};
|
|
622
745
|
```
|
|
623
746
|
|
|
624
|
-
|
|
747
|
+
<details>
|
|
748
|
+
<summary>Why use polystore with Cloudflare's KV?</summary>
|
|
749
|
+
<p>These benefits are for wrapping Cloudflare's KV with polystore:</p>
|
|
750
|
+
<ul>
|
|
751
|
+
<li><strong>Data structures</strong>: with Polystore you can pass more complex data structures and we'll handle the serialization/deserialization.</li>
|
|
752
|
+
<li><strong>Intuitive expirations</strong>: use plain English to specify the expiration time like <code>10min</code>. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
753
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
754
|
+
</ul>
|
|
755
|
+
</details>
|
|
625
756
|
|
|
626
757
|
```js
|
|
627
758
|
// GOOD - with polystore
|
|
@@ -650,7 +781,13 @@ console.log(await store.get("key1"));
|
|
|
650
781
|
// "Hello world"
|
|
651
782
|
```
|
|
652
783
|
|
|
653
|
-
|
|
784
|
+
<details>
|
|
785
|
+
<summary>Why use polystore with Level?</summary>
|
|
786
|
+
<p>These benefits are for wrapping Level with polystore:</p>
|
|
787
|
+
<ul>
|
|
788
|
+
<li><strong>Intuitive expirations</strong>: use plain English to specify the expiration time like <code>10min</code>. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
789
|
+
</ul>
|
|
790
|
+
</details>
|
|
654
791
|
|
|
655
792
|
```js
|
|
656
793
|
// GOOD - with polystore
|
|
@@ -675,6 +812,15 @@ console.log(await store.get("key1"));
|
|
|
675
812
|
// "Hello world"
|
|
676
813
|
```
|
|
677
814
|
|
|
815
|
+
<details>
|
|
816
|
+
<summary>Why use polystore with Etcd?</summary>
|
|
817
|
+
<p>These benefits are for wrapping Etcd with polystore:</p>
|
|
818
|
+
<ul>
|
|
819
|
+
<li><strong>Intuitive expirations</strong>: use plain English to specify the expiration time like <code>10min</code>. <a href="#expiration-explained">Expiration explained</a>.</li>
|
|
820
|
+
<li><strong>Substores</strong>: you can also create substores and manage partial data with ease. <a href="#prefix">Details about substores</a>.</li>
|
|
821
|
+
</ul>
|
|
822
|
+
</details>
|
|
823
|
+
|
|
678
824
|
### Custom store
|
|
679
825
|
|
|
680
826
|
Please see the [creating a store](#creating-a-store) section for all the details!
|
|
@@ -782,8 +928,7 @@ const value = await store.get("a");
|
|
|
782
928
|
// client.get("hello:world:a");
|
|
783
929
|
|
|
784
930
|
// User calls this, then the client is called with that:
|
|
785
|
-
for await (const
|
|
786
|
-
}
|
|
931
|
+
for await (const [key, value] of store) {}
|
|
787
932
|
// client.iterate("hello:world:");
|
|
788
933
|
```
|
|
789
934
|
|
package/src/clients/folder.js
CHANGED
|
@@ -23,7 +23,7 @@ export default class Folder {
|
|
|
23
23
|
constructor(folder) {
|
|
24
24
|
this.folder =
|
|
25
25
|
typeof folder === "string"
|
|
26
|
-
? folder.slice("
|
|
26
|
+
? folder.slice("file://".length).replace(/\/$/, "") + "/"
|
|
27
27
|
: folder.pathname.replace(/\/$/, "") + "/";
|
|
28
28
|
|
|
29
29
|
// Run this once on launch; import the FS module and reset the file
|
|
@@ -48,7 +48,7 @@ export default class Folder {
|
|
|
48
48
|
async set(key, value) {
|
|
49
49
|
const fsp = await this.promise;
|
|
50
50
|
const file = this.folder + key + ".json";
|
|
51
|
-
await fsp.writeFile(file, JSON.stringify(value), "utf8");
|
|
51
|
+
await fsp.writeFile(file, JSON.stringify(value, null, 2), "utf8");
|
|
52
52
|
return file;
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -61,15 +61,10 @@ export default class Folder {
|
|
|
61
61
|
|
|
62
62
|
async *iterate(prefix = "") {
|
|
63
63
|
const fsp = await this.promise;
|
|
64
|
-
const all = await fsp.readdir(this.folder
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
.map((
|
|
68
|
-
(file.path.replace(/\/$/, "") + "/" + file.name)
|
|
69
|
-
.replace(this.folder, "")
|
|
70
|
-
.replace(".json", ""),
|
|
71
|
-
)
|
|
72
|
-
.filter((k) => k.startsWith(prefix));
|
|
64
|
+
const all = await fsp.readdir(this.folder);
|
|
65
|
+
const keys = all
|
|
66
|
+
.filter((f) => f.startsWith(prefix) && f.endsWith(".json"))
|
|
67
|
+
.map((name) => name.slice(0, -".json".length));
|
|
73
68
|
for (const key of keys) {
|
|
74
69
|
const data = await this.get(key);
|
|
75
70
|
yield [key, data];
|