sqlocal
Version:
SQLocal makes it easy to run SQLite3 in the browser, backed by the origin private file system.
68 lines (59 loc) • 1.64 kB
text/typescript
import {
computed,
isRef,
readonly,
shallowRef,
watchEffect,
type DeepReadonly,
type Ref,
} from 'vue';
import type { SQLocal } from '../client.js';
import type { ReactiveQueryStatus, StatementInput } from '../types.js';
/**
* A composable for using reactive SQL queries in Vue components.
* @see {@link https://sqlocal.dev/api/reactivequery#vue}
*/
export function useReactiveQuery<Result extends Record<string, any>>(
db: SQLocal | Ref<SQLocal>,
query: StatementInput<Result> | Ref<StatementInput<Result>>
): {
data: Readonly<Ref<DeepReadonly<Result[]>>>;
error: Readonly<Ref<Error | undefined>>;
status: Readonly<Ref<ReactiveQueryStatus>>;
} {
const data = shallowRef<Result[]>([]);
const error = shallowRef<Error | undefined>(undefined);
const pending = shallowRef<boolean>(true);
const dbValue = computed(() => (isRef(db) ? db.value : db));
const queryValue = computed(() => (isRef(query) ? query.value : query));
watchEffect((onCleanup) => {
const db = dbValue.value;
const query = queryValue.value;
pending.value = true;
const subscription = db.reactiveQuery(query).subscribe(
(results) => {
data.value = results;
error.value = undefined;
pending.value = false;
},
(err) => {
error.value = err;
}
);
onCleanup(() => {
subscription.unsubscribe();
});
});
const status = computed<ReactiveQueryStatus>(() => {
const hasError = !!error.value;
const isPending = pending.value;
if (hasError) return 'error';
if (isPending) return 'pending';
return 'ok';
});
return {
data: readonly(data),
error: readonly(error),
status: readonly(status),
};
}