Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(useIDBKeyval): new integration - Idb-keyval wrapper (#2335)
Co-authored-by: Jess Sachs <jess.sachs@pathai.com> closes #230
- Loading branch information
1 parent
2c4fdcd
commit acd1699
Showing
12 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// Supports polyfilling window, web workers, as well as node's global | ||
import 'fake-indexeddb/auto' | ||
|
||
export {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<script setup lang="ts"> | ||
import { stringify } from '@vueuse/docs-utils' | ||
import { useIDBKeyval } from '@vueuse/integrations' | ||
const KEY = 'vue-use-idb-keyval' | ||
const stateObject = useIDBKeyval(`${KEY}-object`, { | ||
name: 'Banana', | ||
color: 'Yellow', | ||
size: 'Medium', | ||
count: 0, | ||
}) | ||
const textObject = stringify(stateObject) | ||
const stateString = useIDBKeyval(`${KEY}-string`, 'foobar') | ||
const textString = stateString | ||
const stateArray = useIDBKeyval(`${KEY}-array`, ['foo', 'bar', 'baz']) | ||
const textArray = stringify(stateArray) | ||
</script> | ||
|
||
<template> | ||
<h5>Object</h5> | ||
<input v-model="stateObject.name" type="text"> | ||
<input v-model="stateObject.color" type="text"> | ||
<input v-model="stateObject.size" type="text"> | ||
<input v-model.number="stateObject.count" type="range" min="0" step="0.01" max="1000"> | ||
|
||
<pre lang="json">{{ textObject }}</pre> | ||
<br> | ||
|
||
<h5>String</h5> | ||
<input v-model="stateString" type="text"> | ||
<pre>{{ textString }}</pre> | ||
<br> | ||
|
||
<h5>Array</h5> | ||
<input v-model="stateArray[0]" type="text"> | ||
<input v-model="stateArray[1]" type="text"> | ||
<input v-model="stateArray[2]" type="text"> | ||
<pre lang="json">{{ textArray }}</pre> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--- | ||
category: '@Integrations' | ||
--- | ||
|
||
# useIDBKeyval | ||
|
||
Wrapper for [`idb-keyval`](https://www.npmjs.com/package/idb-keyval). | ||
|
||
|
||
## Install idb-keyval as a peer dependency | ||
|
||
```bash | ||
npm install idb-keyval | ||
``` | ||
|
||
## Usage | ||
|
||
```ts | ||
import { useIDBKeyval } from '@vueuse/integrations' | ||
|
||
// bind object | ||
const storedObject = useIDBKeyval('my-idb-keyval-store', { hello: 'hi', greeting: 'Hello' }) | ||
|
||
// update object | ||
storedObject.value.hello = 'hola' | ||
|
||
// bind boolean | ||
const flag = useIDBKeyval('my-flag', true) // returns Ref<boolean> | ||
|
||
// bind number | ||
const count = useIDBKeyval('my-count', 0) // returns Ref<number> | ||
|
||
// delete data from idb storage | ||
storedObject.value = null | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { nextTick } from 'vue-demi' | ||
import { del, get, set, update } from 'idb-keyval' | ||
import { useIDBKeyval } from '.' | ||
|
||
const KEY = 'vue-use-idb-keyval' | ||
|
||
const defaultState = { | ||
name: 'Banana', | ||
color: 'Yellow', | ||
size: 'Medium', | ||
count: 0, | ||
} | ||
|
||
beforeEach(() => { | ||
vi.unmock('idb-keyval') | ||
vi.mock('idb-keyval') | ||
}) | ||
|
||
describe('useIDBKeyval', () => { | ||
it('set/get', async () => { | ||
const state = useIDBKeyval(KEY, { ...defaultState }) | ||
await nextTick() | ||
expect(get).toHaveBeenCalled() | ||
expect(set).toHaveBeenCalled() | ||
expect(state.value).toEqual(defaultState) | ||
}) | ||
|
||
it('update', async () => { | ||
const state = useIDBKeyval(KEY, { ...defaultState }) | ||
state.value.name = 'Apple' | ||
state.value.color = 'Red' | ||
state.value.size = 'Giant' | ||
state.value.count += 1 | ||
|
||
await nextTick() | ||
expect(update).toHaveBeenCalled() | ||
expect(state.value.name).toBe('Apple') | ||
expect(state.value.color).toBe('Red') | ||
expect(state.value.size).toBe('Giant') | ||
expect(state.value.count).toBe(defaultState.count + 1) | ||
}) | ||
|
||
it('del', async () => { | ||
const state = useIDBKeyval(KEY, { ...defaultState }) | ||
state.value = null | ||
await nextTick() | ||
expect(del).toHaveBeenCalled() | ||
}) | ||
|
||
it('string', async () => { | ||
const state = useIDBKeyval(KEY, 'foo') | ||
await nextTick() | ||
expect(get).toHaveBeenCalled() | ||
expect(set).toHaveBeenCalled() | ||
expect(state.value).toEqual('foo') | ||
state.value = 'bar' | ||
await nextTick() | ||
expect(state.value).toEqual('bar') | ||
expect(update).toHaveBeenCalled() | ||
}) | ||
|
||
it('array', async () => { | ||
const defaultArray = ['foo', 'bar', 'baz'] | ||
const state = useIDBKeyval(KEY, [...defaultArray]) | ||
await nextTick() | ||
expect(get).toHaveBeenCalled() | ||
expect(set).toHaveBeenCalled() | ||
expect(state.value).toEqual(defaultArray) | ||
state.value[1] = 'boop' | ||
await nextTick() | ||
expect(state.value[1]).toEqual('boop') | ||
expect(update).toHaveBeenCalled() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import type { ConfigurableFlush, MaybeComputedRef, RemovableRef } from '@vueuse/shared' | ||
import { resolveUnref } from '@vueuse/shared' | ||
import type { Ref } from 'vue-demi' | ||
import { ref, shallowRef, watch } from 'vue-demi' | ||
import { del, get, set, update } from 'idb-keyval' | ||
|
||
export interface UseIDBOptions extends ConfigurableFlush { | ||
/** | ||
* Watch for deep changes | ||
* | ||
* @default true | ||
*/ | ||
deep?: boolean | ||
|
||
/** | ||
* On error callback | ||
* | ||
* Default log error to `console.error` | ||
*/ | ||
onError?: (error: unknown) => void | ||
|
||
/** | ||
* Use shallow ref as reference | ||
* | ||
* @default false | ||
*/ | ||
shallow?: boolean | ||
} | ||
|
||
/** | ||
* | ||
* @param key | ||
* @param initialValue | ||
* @param options | ||
*/ | ||
export function useIDBKeyval<T>( | ||
key: IDBValidKey, | ||
initialValue: MaybeComputedRef<T>, | ||
options: UseIDBOptions = {}, | ||
): RemovableRef<T> { | ||
const { | ||
flush = 'pre', | ||
deep = true, | ||
shallow, | ||
onError = (e) => { | ||
console.error(e) | ||
}, | ||
} = options | ||
|
||
const data = (shallow ? shallowRef : ref)(initialValue) as Ref<T> | ||
|
||
const rawInit: T = resolveUnref(initialValue) | ||
|
||
async function read() { | ||
try { | ||
const rawValue = await get<T>(key) | ||
if (rawValue === undefined) { | ||
if (rawInit) | ||
set(key, rawInit) | ||
} | ||
else { | ||
data.value = rawValue | ||
} | ||
} | ||
catch (e) { | ||
onError(e) | ||
} | ||
} | ||
|
||
read() | ||
|
||
async function write() { | ||
try { | ||
if (data.value == null) { | ||
await del(key) | ||
} | ||
else { | ||
// IndexedDB does not support saving proxies, convert from proxy before saving | ||
if (Array.isArray(data.value)) | ||
await update(key, () => (JSON.parse(JSON.stringify(data.value)))) | ||
else if (typeof data.value === 'object') | ||
await update(key, () => ({ ...data.value })) | ||
else | ||
await update(key, () => (data.value)) | ||
} | ||
} | ||
catch (e) { | ||
onError(e) | ||
} | ||
} | ||
|
||
watch(data, () => write(), { flush, deep }) | ||
|
||
return data as RemovableRef<T> | ||
} |
Oops, something went wrong.