Skip to content

Commit 5160012

Browse files
committed
feat(@kvs/node-localstorage): add node implementation
1 parent ceebe34 commit 5160012

File tree

17 files changed

+326
-42
lines changed

17 files changed

+326
-42
lines changed

packages/common-test-case/src/common-test-case.ts

+9-11
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,20 @@ import { KVS, KVSOptions } from "@kvs/types";
44
export type KVSTestCaseOptions = {
55
setTestDataList: { name: string; value: any; type?: "object" }[];
66
};
7+
export type KVSTestCaseRef = {
8+
current: KVS<any, any> | null;
9+
updateRef(ref: KVS<any, any>): void;
10+
};
711
// version always be defined
812
export const createKVSTestCase = (
913
kvsStorageConstructor: (options: Partial<KVSOptions<any, any>> & { version: number }) => Promise<KVS<any, any>>,
1014
options: KVSTestCaseOptions
1115
) => {
12-
const ref: { current: KVS<any, any> | null } = {
13-
current: null
16+
const ref: KVSTestCaseRef = {
17+
current: null,
18+
updateRef(target: KVS<any, any>) {
19+
ref.current = target;
20+
}
1421
};
1522
let kvs: KVS<any, any>;
1623
return {
@@ -71,15 +78,6 @@ export const createKVSTestCase = (
7178
await kvs.delete("key");
7279
assert.ok((await kvs.has("key1")) === false);
7380
});
74-
it("set empty value and has return true", async () => {
75-
kvs = ref.current = await kvsStorageConstructor({
76-
version: 1
77-
});
78-
await kvs.set("key", "value");
79-
assert.ok(await kvs.get("key"));
80-
await kvs.set("key", undefined);
81-
assert.ok(await kvs.has("key"), "should have key that is undefined");
82-
});
8381
it("clear all data", async () => {
8482
kvs = ref.current = await kvsStorageConstructor({
8583
version: 1

packages/common-test-case/tsconfig.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"esModuleInterop": true,
77
"newLine": "LF",
88
"outDir": "./lib/",
9-
"target": "es5",
9+
"target": "ES2015",
1010
"sourceMap": true,
1111
"declaration": true,
1212
"jsx": "preserve",
@@ -33,4 +33,4 @@
3333
".git",
3434
"node_modules"
3535
]
36-
}
36+
}

packages/indexeddb/src/index.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,18 @@ const hasItem = async <K extends IndexedDBKey>(database: IDBDatabase, tableName:
123123
};
124124
});
125125
};
126-
const setItem = <K extends IndexedDBKey, V>(
126+
const setItem = async <K extends IndexedDBKey, V>(
127127
database: IDBDatabase,
128128
tableName: string,
129129
key: K,
130130
value: V
131131
): Promise<void> => {
132+
// If the value is undefined, delete the key
133+
// This behavior aim to align localStorage implementation
134+
if (value === undefined) {
135+
await deleteItem(database, tableName, key);
136+
return;
137+
}
132138
return new Promise((resolve, reject) => {
133139
const transaction = database.transaction(tableName, "readwrite");
134140
const objectStore = transaction.objectStore(tableName);

packages/localstorage/test/index.test.ts

+1-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { kvsLocalStorage } from "../src";
22
import { createKVSTestCase } from "@kvs/common-test-case";
3+
import assert from "assert";
34

45
const databaseName = "kvs-test";
56
const kvsTestCase = createKVSTestCase(
@@ -23,25 +24,13 @@ const kvsTestCase = createKVSTestCase(
2324
name: "boolean",
2425
value: false
2526
},
26-
{
27-
name: "date",
28-
value: new Date(),
29-
type: "object"
30-
},
3127
{
3228
name: "object",
3329
value: {
3430
prop: "propValue"
3531
},
3632
type: "object"
3733
}
38-
// Edge, old-Safari does not support Blob
39-
// https://github.com/jakearchibald/idb/issues/58
40-
// {
41-
// name: "blob",
42-
// value: new Blob(["Hello, world!"], { type: "text/plain" }),
43-
// type: "object"
44-
// }
4534
]
4635
}
4736
);

packages/localstorage/tsconfig.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"esModuleInterop": true,
77
"newLine": "LF",
88
"outDir": "./lib/",
9-
"target": "es5",
9+
"target": "ES2015",
1010
"sourceMap": true,
1111
"declaration": true,
1212
"jsx": "preserve",
@@ -33,4 +33,4 @@
3333
".git",
3434
"node_modules"
3535
]
36-
}
36+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"require": [
3+
"ts-node-test-register"
4+
]
5+
}

packages/node-localstorage/LICENSE

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2020 azu
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19+
SOFTWARE.

packages/node-localstorage/README.md

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# @kvs/node-localstorage
2+
3+
Node.js localstorage for KVS.
4+
5+
## Dependencies
6+
7+
- [lmaccherone/node-localstorage: A drop-in substitute for the browser native localStorage API that runs on node.js.](https://github.com/lmaccherone/node-localstorage)
8+
9+
## Install
10+
11+
Install with [npm](https://www.npmjs.com/):
12+
13+
npm install @kvs/node-localstorage
14+
15+
## Usage
16+
17+
- [ ] Write usage instructions
18+
19+
## Changelog
20+
21+
See [Releases page](https://github.com/azu/kvs/releases).
22+
23+
## Running tests
24+
25+
Install devDependencies and Run `npm test`:
26+
27+
npm test
28+
29+
## Contributing
30+
31+
Pull requests and stars are always welcome.
32+
33+
For bugs and feature requests, [please create an issue](https://github.com/azu/kvs/issues).
34+
35+
1. Fork it!
36+
2. Create your feature branch: `git checkout -b my-new-feature`
37+
3. Commit your changes: `git commit -am 'Add some feature'`
38+
4. Push to the branch: `git push origin my-new-feature`
39+
5. Submit a pull request :D
40+
41+
## Author
42+
43+
- [github/azu](https://github.com/azu)
44+
- [twitter/azu_re](https://twitter.com/azu_re)
45+
46+
## License
47+
48+
MIT © azu
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"name": "@kvs/node-localstorage",
3+
"version": "1.0.0",
4+
"description": "Node.js localstorage for KVS.",
5+
"keywords": [
6+
"kvs",
7+
"browser",
8+
"localstorage"
9+
],
10+
"homepage": "https://github.com/azu/kvs/tree/master/packages/node-localstorage/",
11+
"bugs": {
12+
"url": "https://github.com/azu/kvs/issues"
13+
},
14+
"repository": {
15+
"type": "git",
16+
"url": "https://github.com/azu/kvs.git"
17+
},
18+
"license": "MIT",
19+
"author": "azu",
20+
"sideEffects": false,
21+
"main": "lib/index.js",
22+
"module": "module/index.js",
23+
"types": "lib/index.d.ts",
24+
"directories": {
25+
"lib": "lib",
26+
"test": "test"
27+
},
28+
"files": [
29+
"bin/",
30+
"lib/",
31+
"module"
32+
],
33+
"scripts": {
34+
"build": "tsc -p . && tsc --project ./tsconfig.module.json",
35+
"clean": "rimraf lib/ module/",
36+
"prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"",
37+
"prepublish": "npm run clean && npm run build",
38+
"test": "mocha \"test/**/*.ts\"",
39+
"watch": "tsc -p . --watch"
40+
},
41+
"prettier": {
42+
"printWidth": 120,
43+
"singleQuote": false,
44+
"tabWidth": 4,
45+
"trailingComma": "none"
46+
},
47+
"dependencies": {
48+
"node-localstorage": "^2.1.6",
49+
"@kvs/storage": "^1.0.0",
50+
"app-root-path": "^3.0.0",
51+
"mkdirp": "^1.0.4"
52+
},
53+
"devDependencies": {
54+
"@jsdevtools/karma-config": "^3.1.7",
55+
"@kvs/common-test-case": "^1.0.0",
56+
"@types/mocha": "^8.0.1",
57+
"@types/node": "^14.0.27",
58+
"lerna": "^3.22.1",
59+
"mocha": "^8.1.1",
60+
"prettier": "^2.0.5",
61+
"rimraf": "^3.0.2",
62+
"ts-loader": "^8.0.2",
63+
"typescript": "^3.9.7"
64+
},
65+
"publishConfig": {
66+
"access": "public"
67+
}
68+
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import path from "path";
2+
import { JsonValue, KvsStorage, kvsStorage, KVSStorageKey } from "@kvs/storage";
3+
import { KVS, KVSOptions } from "@kvs/types";
4+
// @ts-ignore
5+
import { LocalStorage } from "node-localstorage";
6+
// @ts-ignore
7+
import appRoot from "app-root-path";
8+
// @ts-ignore
9+
import mkdirp from "mkdirp";
10+
11+
export type KvsLocalStorage<K extends KVSStorageKey, V extends JsonValue> = KVS<K, V>;
12+
export type KvsLocalStorageOptions<K extends KVSStorageKey, V extends JsonValue> = KVSOptions<K, V> & {
13+
kvsVersionKey?: string;
14+
storeFilePath?: string;
15+
};
16+
export const kvsLocalStorage = async <K extends KVSStorageKey, V extends JsonValue>(
17+
options: KvsLocalStorageOptions<K, V>
18+
): Promise<KvsStorage<K, V>> => {
19+
const defaultCacheDir = path.join(appRoot.toString(), ".cache");
20+
if (!options.storeFilePath) {
21+
await mkdirp(defaultCacheDir);
22+
}
23+
const saveFilePath = options.storeFilePath
24+
? options.storeFilePath
25+
: path.join(defaultCacheDir, "kvs-node-localstorage");
26+
return kvsStorage({
27+
...options,
28+
storage: new LocalStorage(saveFilePath)
29+
});
30+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { kvsLocalStorage } from "../src";
2+
import { createKVSTestCase } from "@kvs/common-test-case";
3+
4+
const databaseName = "kvs-test";
5+
const kvsTestCase = createKVSTestCase(
6+
(options) =>
7+
kvsLocalStorage({
8+
...options,
9+
name: databaseName,
10+
debug: true
11+
}),
12+
{
13+
setTestDataList: [
14+
{
15+
name: "string",
16+
value: "str"
17+
},
18+
{
19+
name: "number",
20+
value: 42
21+
},
22+
{
23+
name: "boolean",
24+
value: false
25+
},
26+
{
27+
name: "object",
28+
value: {
29+
prop: "propValue"
30+
},
31+
type: "object"
32+
}
33+
// Edge, old-Safari does not support Blob
34+
// https://github.com/jakearchibald/idb/issues/58
35+
// {
36+
// name: "blob",
37+
// value: new Blob(["Hello, world!"], { type: "text/plain" }),
38+
// type: "object"
39+
// }
40+
]
41+
}
42+
);
43+
const deleteAllDB = async () => {
44+
if (!kvsTestCase.ref.current) {
45+
return;
46+
}
47+
try {
48+
await kvsTestCase.ref.current.clear();
49+
// await kvs.dropInstance();
50+
} catch (error) {
51+
console.error("deleteAllDB", error);
52+
}
53+
};
54+
describe("@kvs/node-localstorage", () => {
55+
before(deleteAllDB);
56+
afterEach(deleteAllDB);
57+
kvsTestCase.run();
58+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "../tsconfig.json",
3+
"compilerOptions": {
4+
"declaration": false,
5+
"noEmit": true
6+
},
7+
"include": [
8+
"../src/**/*",
9+
"./**/*"
10+
]
11+
}

0 commit comments

Comments
 (0)