Skip to content

Commit 911759e

Browse files
committed
support for multiple delegated stores
1 parent 856c739 commit 911759e

File tree

19 files changed

+218
-115
lines changed

19 files changed

+218
-115
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
uses: actions/checkout@v4
2121

2222
- name: Install Deno
23-
uses: denoland/setup-deno@v1
23+
uses: denoland/setup-deno@v2
2424

2525
- name: Verify formatting
2626
run: deno fmt --check
@@ -29,7 +29,7 @@ jobs:
2929
run: deno task lint
3030

3131
- name: Run TypeScript checking
32-
run: deno task check
32+
run: deno check
3333

3434
- name: Run tests
3535
run: deno task test

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
uses: actions/checkout@v4
2222

2323
- name: Install Deno
24-
uses: denoland/setup-deno@v1
24+
uses: denoland/setup-deno@v2
2525

2626
- name: Publish package
2727
run: deno publish

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to
77
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

9+
## [0.5.0]
10+
11+
### Added
12+
13+
- [store] support for multiple delegated storage modules, based on the key
14+
prefix
15+
16+
### Changed
17+
18+
- update to Deno 2+
19+
920
## [0.4.0]
1021

1122
### Changed

deno.json

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@
44
],
55
"tasks": {
66
"test": "deno test --allow-env --allow-read --allow-write --allow-net --allow-sys",
7-
"reload": "deno cache --reload **/*.ts jsr:@check/deps",
8-
"check": "deno check **/*.ts",
97
"lint": "deno lint && deno doc --lint **/*.ts",
10-
"ok": "deno fmt && deno task lint && deno task check && deno task test && deno publish --dry-run --allow-dirty",
11-
"outdated": "deno run --allow-read=. --allow-net=jsr.io,registry.npmjs.org jsr:@check/deps",
12-
"lock": "rm -f deno.lock && deno task check"
8+
"ok": "deno fmt && deno task lint && deno check && deno task test && deno publish --dry-run --allow-dirty",
9+
"lock": "rm -f deno.lock && deno install --reload && deno check"
1310
},
1411
"compilerOptions": {
1512
"noUncheckedIndexedAccess": true,
@@ -26,16 +23,15 @@
2623
"./store"
2724
],
2825
"imports": {
29-
"@jollytoad/store": "jsr:@jollytoad/store@^0.4.0",
30-
"@jollytoad/store-common": "jsr:@jollytoad/store-common@^0.4.0",
31-
"@jollytoad/store-deno-fs": "jsr:@jollytoad/store-deno-fs@^0.4.0",
32-
"@jollytoad/store-deno-kv": "jsr:@jollytoad/store-deno-kv@^0.4.0",
33-
"@jollytoad/store-deno-kv-fs": "jsr:@jollytoad/store-deno-kv-fs@^0.4.0",
34-
"@jollytoad/store-no-op": "jsr:@jollytoad/store-no-op@^0.4.0",
35-
"@jollytoad/store-web-storage": "jsr:@jollytoad/store-web-storage@^0.4.0",
36-
"@std/assert": "jsr:@std/assert@^1.0.0",
37-
"@std/fs": "jsr:@std/fs@^1.0.0-rc.4",
38-
"@std/path": "jsr:@std/path@^1.0.0-rc.4",
39-
"@types/node": "npm:@types/node@^20.14.10"
26+
"@jollytoad/store": "jsr:@jollytoad/store@^0.5.0",
27+
"@jollytoad/store-common": "jsr:@jollytoad/store-common@^0.5.0",
28+
"@jollytoad/store-deno-fs": "jsr:@jollytoad/store-deno-fs@^0.5.0",
29+
"@jollytoad/store-deno-kv": "jsr:@jollytoad/store-deno-kv@^0.5.0",
30+
"@jollytoad/store-deno-kv-fs": "jsr:@jollytoad/store-deno-kv-fs@^0.5.0",
31+
"@jollytoad/store-no-op": "jsr:@jollytoad/store-no-op@^0.5.0",
32+
"@jollytoad/store-web-storage": "jsr:@jollytoad/store-web-storage@^0.5.0",
33+
"@std/assert": "jsr:@std/assert@^1.0.14",
34+
"@std/fs": "jsr:@std/fs@^1.0.19",
35+
"@std/path": "jsr:@std/path@^1.1.2"
4036
}
4137
}

deno.lock

Lines changed: 51 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

store-common/deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jollytoad/store-common",
3-
"version": "0.4.0",
3+
"version": "0.5.0",
44
"exports": {
55
"./key-utils": "./key-utils.ts",
66
"./test-storage-module": "./test-storage-module.ts",

store-common/test-storage-module.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
assertEquals,
55
assertStringIncludes,
66
} from "@std/assert";
7-
import type { StorageModule } from "./types.ts";
7+
import type { DelegatedStore, StorageModule } from "./types.ts";
88

99
/**
1010
* Test the url() function of the given storage module.
@@ -21,17 +21,40 @@ export async function testUrl(
2121
});
2222
}
2323

24+
/**
25+
* Test the url() function of the given delegated storage module with a key prefix.
26+
*/
27+
export async function testUrlForPrefix(
28+
t: Deno.TestContext,
29+
{ url }: DelegatedStore,
30+
includes: string,
31+
prefix: string,
32+
) {
33+
await t.step(
34+
`url contains "${includes}" for keys prefixed with "${prefix}"`,
35+
async () => {
36+
const actualUrl = await url(prefix);
37+
console.log("StorageModule URL:", actualUrl);
38+
assertStringIncludes(actualUrl, includes);
39+
},
40+
);
41+
}
42+
2443
/**
2544
* Test the isWriteable() function of the given storage module.
2645
*/
2746
export async function testIsWriteable(
2847
t: Deno.TestContext,
2948
{ isWritable }: StorageModule,
3049
expected = true,
50+
prefix?: string,
3151
) {
32-
await t.step(`isWriteable() to be ${expected}`, async () => {
33-
assertEquals(await isWritable(), expected);
34-
});
52+
await t.step(
53+
`isWriteable(${prefix ? `["${prefix}"]` : ""}) to be ${expected}`,
54+
async () => {
55+
assertEquals(await isWritable(prefix ? [prefix] : undefined), expected);
56+
},
57+
);
3558
}
3659

3760
/**

store-common/types.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,33 @@ export interface StorageModule<T = unknown> {
6565
}
6666

6767
/**
68-
* Additional functions for a store that delegates to another store
68+
* Additional functions for a store that delegates to one or more other stores
6969
*/
7070
export interface DelegatedStore {
7171
/**
7272
* Set the storage module to which all function calls are delegated
7373
*
7474
* @param storageModule may be the store, promise of the store, or undefined to remove any delegate store
75+
* @param prefix delegate only for StorageKeys starting with this prefix
7576
*/
76-
setStore(storageModule?: StorageModule | Promise<StorageModule>): void;
77+
setStore(
78+
storageModule?: StorageModule | Promise<StorageModule>,
79+
prefix?: string,
80+
): void;
7781

7882
/**
7983
* Get the delegate store previously set via `setStore` or obtained via another mechanism (eg. env vars)
8084
*
85+
* @param key get the store specific to this key or prefix
8186
* @returns the promise of the store to which all operations are delegated
8287
* @throws if no store has been set or can be loaded
8388
*/
84-
getStore(): Promise<StorageModule>;
89+
getStore(key?: StorageKey | string): Promise<StorageModule>;
90+
91+
/**
92+
* Returns the `import.meta.url` of the module.
93+
*
94+
* @param key get the store specific to this key or prefix
95+
*/
96+
url(key?: StorageKey | string): Promise<string>;
8597
}

store-deno-fs/deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jollytoad/store-deno-fs",
3-
"version": "0.4.0",
3+
"version": "0.5.0",
44
"exports": {
55
".": "./mod.ts"
66
}

store-deno-fs/mod.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export async function getItem<T>(key: StorageKey): Promise<T | undefined> {
5656
try {
5757
return JSON.parse(await Deno.readTextFile(filepath(key)));
5858
} catch (e) {
59-
if (e.code === "ENOENT") {
59+
if (isNotFound(e)) {
6060
return undefined;
6161
} else {
6262
throw e;
@@ -118,7 +118,7 @@ export async function* listItems<T>(
118118
}
119119
}
120120
} catch (e) {
121-
if (e.code === "ENOENT") {
121+
if (isNotFound(e)) {
122122
return;
123123
} else {
124124
throw e;
@@ -134,7 +134,7 @@ export async function clearItems(keyPrefix: StorageKey): Promise<void> {
134134
try {
135135
await Deno.remove(dirpath(keyPrefix), { recursive: true });
136136
} catch (e) {
137-
if (e.code === "ENOENT") {
137+
if (isNotFound(e)) {
138138
return;
139139
} else {
140140
throw e;
@@ -158,3 +158,8 @@ function dirpath(key: StorageKey = []) {
158158
const root = Deno.env.get("STORE_FS_ROOT") ?? ".store";
159159
return resolve(root, ...toStrKey(key));
160160
}
161+
162+
// deno-lint-ignore no-explicit-any
163+
function isNotFound(e: any) {
164+
return e && "code" in e && e.code === "ENOENT";
165+
}

0 commit comments

Comments
 (0)