Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add indexedb driver #221

Merged
merged 11 commits into from
Aug 7, 2023
34 changes: 34 additions & 0 deletions docs/content/6.drivers/indexedb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
navigation.title: IndexedDB
---

# IndexedDB

Store data in [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) using [idb-keyval](https://github.com/jakearchibald/idb-keyval).

To use it, you will need to install `idb-keyval` in your project:

```bash
npm i idb-keyval
```

Usage:

```js
import { createStorage } from "unstorage";
import indexedDbDriver from "unstorage/drivers/indexeddb";

const storage = createStorage({
driver: indexedDbDriver({ base: "app:" }),
});
```

**Options:**

- `base`: Add `${base}:` to all keys to avoid collision
- `dbName`: Custom name for database. Defaults to `keyval-store`
- `storeName`: Custom name for store. Defaults to `keyval`

::alert{type="info"}
IndexedDB is a browser database. avoid using this preset on server environments.
::
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
"changelogen": "^0.5.4",
"eslint": "^8.46.0",
"eslint-config-unjs": "^0.2.1",
"fake-indexeddb": "^4.0.1",
"idb-keyval": "^6.2.1",
"ioredis-mock": "^8.8.1",
"jiti": "^1.19.1",
"jsdom": "^22.1.0",
Expand All @@ -99,6 +101,7 @@
"@azure/identity": "^3.2.3",
"@azure/keyvault-secrets": "^4.7.0",
"@azure/storage-blob": "^12.14.0",
"idb-keyval": "^6.2.1",
"@planetscale/database": "^1.8.0",
"@upstash/redis": "^1.22.0",
"@vercel/kv": "^0.2.2"
Expand Down Expand Up @@ -130,6 +133,9 @@
},
"@vercel/kv": {
"optional": true
},
"idb-keyval": {
"optional": true
}
},
"packageManager": "pnpm@8.6.7"
Expand Down
74 changes: 74 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions src/drivers/indexedb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { defineDriver } from "./utils";
import {
get,
set,
clear,
del,
keys,
createStore,
type UseStore,
} from "idb-keyval";

export interface IDBKeyvalOptions {
base?: string;
dbName?: string;
storeName?: string;
}

const DRIVER_NAME = "idb-keyval";

export default defineDriver((opts: IDBKeyvalOptions = {}) => {
const base = opts.base && opts.base.length > 0 ? `${opts.base}:` : "";
const makeKey = (key: string) => base + key;

let customStore: UseStore | undefined;
if (opts.dbName && opts.storeName) {
customStore = createStore(opts.dbName, opts.storeName);
}

return {
name: DRIVER_NAME,
options: opts,
async hasItem(key) {
const item = await get(makeKey(key), customStore);
return typeof item === "undefined" ? false : true;
},
async getItem(key) {
const item = await get(makeKey(key), customStore);
return item ?? null;
},
setItem(key, value) {
return set(makeKey(key), value, customStore);
},
removeItem(key) {
return del(makeKey(key), customStore);
},
getKeys() {
return keys(customStore);
},
clear() {
return clear(customStore);
},
};
});
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const builtinDrivers = {
fs: "unstorage/drivers/fs",
github: "unstorage/drivers/github",
http: "unstorage/drivers/http",
indexedb: "unstorage/drivers/indexedb",
localStorage: "unstorage/drivers/localstorage",
lruCache: "unstorage/drivers/lru-cache",
memory: "unstorage/drivers/memory",
Expand Down Expand Up @@ -61,6 +62,7 @@ export type BuiltinDriverOptions = {
fs: ExtractOpts<(typeof import("./drivers/fs"))["default"]>;
github: ExtractOpts<(typeof import("./drivers/github"))["default"]>;
http: ExtractOpts<(typeof import("./drivers/http"))["default"]>;
indexedb: ExtractOpts<(typeof import("./drivers/indexedb"))["default"]>;
localStorage: ExtractOpts<
(typeof import("./drivers/localstorage"))["default"]
>;
Expand Down
27 changes: 27 additions & 0 deletions test/drivers/indexedb.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { describe, expect, it } from "vitest";
import driver from "../../src/drivers/indexedb";
import { testDriver } from "./utils";
import "fake-indexeddb/auto";
import { createStorage } from "../../src";

describe("drivers: indexeddb", () => {
testDriver({ driver: driver({ dbName: "test-db" }) });

const customStorage = createStorage({
driver: driver({
dbName: "custom-db",
storeName: "custom-name",
base: "unstorage",
}),
});

it("can use a customStore", async () => {
await customStorage.setItem("first", "foo");
await customStorage.setItem("second", "bar");
expect(await customStorage.getItem("first")).toBe("foo");
await customStorage.removeItem("first");
expect(await customStorage.getKeys()).toMatchObject(["unstorage:second"]);
await customStorage.clear();
expect(await customStorage.hasItem("second")).toBe(false);
});
});