feat: add upstash driver (#500)

Co-authored-by: Matt Kane <m@mk.gg>
Co-authored-by: Pooya Parsa <pooya@pi0.io>
This commit is contained in:
Fahreddin Özcan 2024-12-06 15:55:58 +03:00 committed by GitHub
parent 88135c1d8c
commit 6caa7d6bb8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 136 additions and 0 deletions

2
.env.example Normal file
View File

@ -0,0 +1,2 @@
VITE_UPSTASH_REDIS_REST_URL=
VITE_UPSTASH_REDIS_REST_TOKEN=

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ __*
.vercel
.netlify
test/fs-storage/**
.env

49
docs/2.drivers/upstash.md Normal file
View File

@ -0,0 +1,49 @@
---
icon: simple-icons:upstash
---
# Upstash
> Store data in an Upstash Redis database.
## Usage
::read-more{to="https://upstash.com/"}
Learn more about Upstash.
::
::note
Unstorage uses [`@upstash/redis`](https://github.com/upstash/upstash-redis) internally to connect to Upstash Redis.
::
To use it, you will need to install `@upstash/redis` in your project:
:pm-install{name="@upstash/redis"}
Usage with Upstash Redis:
```js
import { createStorage } from "unstorage";
import upstashDriver from "unstorage/drivers/upstash";
const storage = createStorage({
driver: upstashDriver({
base: "unstorage",
// url: "", // or set UPSTASH_REDIS_REST_URL env
// token: "", // or set UPSTASH_REDIS_REST_TOKEN env
}),
});
```
**Options:**
- `base`: Optional prefix to use for all keys. Can be used for namespacing.
- `url`: The REST URL for your Upstash Redis database. Find it in [the Upstash Redis console](https://console.upstash.com/redis/). Driver uses `UPSTASH_REDIS_REST_URL` environment by default.
- `token`: The REST token for authentication with your Upstash Redis database. Find it in [the Upstash Redis console](https://console.upstash.com/redis/). Driver uses `UPSTASH_REDIS_REST_TOKEN` environment by default.
- `ttl`: Default TTL for all items in **seconds**.
See [@upstash/redis documentation](https://upstash.com/docs/redis/sdks/ts/overview) for all available options.
**Transaction options:**
- `ttl`: Supported for `setItem(key, value, { ttl: number /* seconds */ })`

69
src/drivers/upstash.ts Normal file
View File

@ -0,0 +1,69 @@
import { type RedisConfigNodejs, Redis } from "@upstash/redis";
import { defineDriver, normalizeKey, joinKeys } from "./utils";
export interface UpstashOptions extends Partial<RedisConfigNodejs> {
/**
* Optional prefix to use for all keys. Can be used for namespacing.
*/
base?: string;
/**
* Default TTL for all items in seconds.
*/
ttl?: number;
}
const DRIVER_NAME = "upstash";
export default defineDriver<UpstashOptions, Redis>(
(options: UpstashOptions = {}) => {
const base = normalizeKey(options?.base);
const r = (...keys: string[]) => joinKeys(base, ...keys);
let redisClient: Redis;
const getClient = () => {
if (redisClient) {
return redisClient;
}
const url =
options.url || globalThis.process?.env?.UPSTASH_REDIS_REST_URL;
const token =
options.token || globalThis.process?.env?.UPSTASH_REDIS_REST_TOKEN;
redisClient = new Redis({ url, token, ...options });
return redisClient;
};
return {
name: DRIVER_NAME,
getInstance: getClient,
hasItem(key) {
return getClient().exists(r(key)).then(Boolean);
},
getItem(key) {
return getClient().get(r(key));
},
setItem(key, value, tOptions) {
const ttl = tOptions?.ttl || options.ttl;
return getClient()
.set(r(key), value, ttl ? { ex: ttl } : undefined)
.then(() => {});
},
removeItem(key) {
return getClient()
.del(r(key))
.then(() => {});
},
getKeys(base) {
return getClient().keys(r(base, "*"));
},
async clear(base) {
const keys = await getClient().keys(r(base, "*"));
if (keys.length === 0) {
return;
}
return getClient()
.del(...keys)
.then(() => {});
},
};
}
);

View File

@ -27,6 +27,7 @@ export const builtinDrivers = {
planetscale: "unstorage/drivers/planetscale",
redis: "unstorage/drivers/redis",
sessionStorage: "unstorage/drivers/session-storage",
upstash: "unstorage/drivers/upstash",
vercelKV: "unstorage/drivers/vercel-kv",
/** @deprecated */

View File

@ -0,0 +1,14 @@
import { describe } from "vitest";
import { testDriver } from "./utils";
import driver from "../../src/drivers/upstash";
const url = process.env.VITE_UPSTASH_REDIS_REST_URL;
const token = process.env.VITE_UPSTASH_REDIS_REST_TOKEN;
describe.skipIf(!url || !token)("drivers: upstash", async () => {
process.env.UPSTASH_REDIS_REST_URL = url;
process.env.UPSTASH_REDIS_REST_TOKEN = token;
testDriver({
driver: driver({}),
});
});