Skip to content

Commit

Permalink
feat: namespaced storage (prefixStorage)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Sep 8, 2021
1 parent 197ff33 commit d58beaa
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 2 deletions.
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ Typically, we can choose our data storage based on use-case like a filesystem (N
✔️ State snapshot <br>
✔️ Driver agnostic watcher <br>
✔️ HTTP Storage server (cli and programmatic) <br>
✔️ Namespaced storage <br>
<br>
🚧 Overlay storage (usable for Copy-on-write for read-only storage) <br>
🚧 Namespaced storage <br>
🚧 Node FS API (for virtual fs) <br>
<br>

Expand All @@ -56,6 +56,7 @@ Typically, we can choose our data storage based on use-case like a filesystem (N
- [Utils](#utils)
- [`snapshot(storage, base?)`](#snapshotstorage-base)
- [`restoreSnapshot(storage, data, base?)`](#restoresnapshotstorage-data-base)
- [`prefixStorage(storage, data, base?)`](#prefixstoragestorage-data-base)
- [Storage Server](#storage-server)
- [Drivers](#drivers)
- [`fs` (node)](#fs-node)
Expand Down Expand Up @@ -247,6 +248,22 @@ Restore snapshot created by `snapshot()`.
await restoreSnapshot(storage, { 'foo:bar': 'baz' }, '/etc2')
```

### `prefixStorage(storage, data, base?)`

Create a namespaced instance of main storage.

All operations are virtually prefixed. Useful to create shorcuts and limit access.

```js
import { createStorage, prefixStorage } from 'unstorage'

const storage = createStorage()
const assetsStorage = prefixStorage(storage, 'assets')

// Same as storage.setItem('assets:x', 'hello!')
await assetsStorage.setItem('x', 'hello!')
```

## Storage Server

We can easily expose unstorage instance to an http server to allow remote connections.
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './storage'
export * from './types'
export * from './utils'
export { defineDriver } from './drivers/utils'
29 changes: 29 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { Storage } from './types'
import { normalizeBase } from './_utils'

const storageKeyProps: (keyof Storage)[] = [
'hasItem',
'getItem',
'setItem',
'removeItem',
'getMeta',
'setMeta',
'removeMeta',
'getKeys',
'clear',
'mount',
'unmount'
]

export function prefixStorage (storage: Storage, base: string): Storage {
base = normalizeBase(base)
if (!base) {
return storage
}
const nsStorage: Storage = { ...storage }
for (const prop of storageKeyProps) {
// @ts-ignore Better types?
nsStorage[prop] = (key: string, ...args) => storage[prop](base + key, ...args)
}
return nsStorage
}
11 changes: 10 additions & 1 deletion test/storage.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createStorage, snapshot, restoreSnapshot } from '../src'
import { createStorage, snapshot, restoreSnapshot, prefixStorage } from '../src'
import memory from '../src/drivers/memory'

const data = {
Expand Down Expand Up @@ -27,3 +27,12 @@ describe('storage', () => {
expect(onChange).toHaveBeenCalledWith('update', 'mnt:data:foo')
})
})

describe('utils', () => {
it('prefixStorage', async () => {
const storage = createStorage()
const pStorage = prefixStorage(storage, 'foo')
await pStorage.setItem('x', 'bar')
expect(await storage.getItem('foo:x')).toBe('bar')
})
})

0 comments on commit d58beaa

Please sign in to comment.