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: support base in useStorage(base?: string) and improve docs #1012

Merged
merged 4 commits into from
Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 66 additions & 17 deletions docs/content/1.guide/1.introduction/4.storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,27 @@

Nitro provides a built-in storage layer that can abstract filesystem or database or any other data source.

See [unjs/unstorage](https://github.com/unjs/unstorage) for more usage information.
`useStorage()` is an instance of [createStorage](https://unstorage.unjs.io/usage) using the [memory driver](https://unstorage.unjs.io/drivers/memory).

**Example:** Simple (in memory) operations

```js
await useStorage().setItem('test:foo', { hello: 'world' })
await useStorage().getItem('test:foo')
```

## Defining Mountpoints
// Could can also specific the base in useStorage(base)
await useStorage('test').setItem('foo', { hello: 'world' })
await useStorage('test').getItem('foo')
```

By default storage is in-memory with mounted `cache:` prefix only for development.
See [Unstorage](https://unstorage.unjs.io/usage) for detailed usage.

```js
await useStorage().setItem('cache:foo', { hello: 'world' })
await useStorage().getItem('cache:foo')
```
## Mountpoints

You can mount other storage drivers through the Nitro config using the `storage` option:
You can mount storage drivers using the `storage` option:

```js
// nitro.config.ts
::code-group
```ts [nitro.config.ts]
import { defineNitroConfig } from 'nitropack'

export default defineNitroConfig({
Expand All @@ -39,35 +38,85 @@ export default defineNitroConfig({
}
})
```
```ts [nuxt.config.ts]
export default defineNuxtConfig({
nitro: {
storage: {
redis: {
driver: 'redis',
/* redis connector options */
},
db: {
driver: 'fs',
base: './data/db'
pi0 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
})
```
::

Usage:

```js
await useStorage('redis').setItem('foo', { hello: 'world' })
await useStorage('redis').getItem('foo')
// or
await useStorage().setItem('redis:foo', { hello: 'world' })
await useStorage().getItem('redis:foo')
```

You can find the list of drivers [on the unstorage repository](https://github.com/unjs/unstorage#drivers).
You can find the list of drivers on [unstorage documentation](https://unstorage.unjs.io/).

## DevStorage

You can use the `devStorage` key to overwrite the storage configuration during development.
In development, Nitro adds the `cache` mountpoint using the [FS driver](https://unstorage.unjs.io/drivers/fs) writting to `.nitro/cache` or `.nuxt/cache` if using [Nuxt](https://nuxt.com).

```js
await useStorage('cache').setItem('foo', { hello: 'world' })
await useStorage('cache').getItem('foo')
```


## Development storage

You can use the `devStorage` key to overwrite the storage configuration during development, very useful when you use a database in production and want to use the filesystem in development.

::code-group
```ts [nitro.config.ts]
export default defineNitroConfig({
// Production
storage: {
'db': {
db: {
driver: 'redis',
/* redis connector options */
}
}
// Development
devStorage: {
'db': {
db: {
driver: 'fs',
base: './data/db'
}
}
})
```
```ts [nuxt.config.ts]
export default defineNuxtConfig({
nitro: {
// Production
storage: {
db: {
driver: 'redis',
/* redis connector options */
}
}
// Development
devStorage: {
db: {
driver: 'fs',
base: './data/db'
}
}
}
})
```
::
10 changes: 8 additions & 2 deletions src/rollup/plugins/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,20 @@ for (const base of bundledStorage) {
return virtual(
{
"#internal/nitro/virtual/storage": `
import { createStorage } from 'unstorage'
import { createStorage, prefixStorage } from 'unstorage'
import { assets } from '#internal/nitro/virtual/server-assets'

${driverImports.map((i) => genImport(i, genSafeVariableName(i))).join("\n")}

const storage = createStorage({})

export const useStorage = () => storage
export const useStorage = (base = '') => {
if (base) {
return prefixStorage(storage, base)
}

return storage
}

storage.mount('/assets', assets)

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/virtual/storage.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import type { Storage } from "unstorage";

export declare const useStorage: () => Storage;
export declare const useStorage: (base?: string) => Storage;
11 changes: 11 additions & 0 deletions test/fixture/api/storage/[...base].get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default eventHandler(async (event) => {
const { key } = getQuery(event)
const base = event.context.params.base as string
const storage = useStorage(`cache:${base}`)
if (!key) {
return await storage.getKeys()
}

const value = await storage.getItem(key as string)
return { key, value }
})
9 changes: 9 additions & 0 deletions test/fixture/api/storage/[...base].put.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default eventHandler(async (event) => {
const { key, value } = await readBody(event)
const base = event.context.params.base as string
const storage = useStorage(`cache:${base}`)

await storage.setItem(key, value)

return { key, value }
})
13 changes: 13 additions & 0 deletions test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,19 @@ export function testNitro(
});
});

it("supports useStorage(base)", async () => {
const { data } = await callHandler({ url: "/api/storage/test" });
expect(data).toMatchObject([]);
const { data: res } = await callHandler({
url: '/api/storage/test',
method: 'PUT',
body: { key: 'hello', value: 'world' }
});
expect(res.key).toBe('hello');
const { data: keys } = await callHandler({ url: "/api/storage/test" });
expect(data).toMatchObject(['hello']);
});

if (additionalTests) {
additionalTests(ctx, callHandler);
}
Expand Down