// based on https://github.com/rocicorp/mono/tree/main/packages/zero-solid import type { CustomMutatorDefs, DefaultContext, DefaultSchema, Falsy, HumanReadable, PullRow, QueryOrQueryRequest, ReadonlyJSONValue, Schema, TTL, Zero, } from '@rocicorp/zero' import type { ComputedRef, MaybeRefOrGetter } from 'vue' import type { QueryError, QueryStatus, VueView } from './view' import { addContextToQuery, asQueryInternals, DEFAULT_TTL_MS } from '@rocicorp/zero/bindings' import { computed, getCurrentInstance, onUnmounted, shallowRef, toValue, watch, } from 'vue' import { vueViewFactory } from './view' export interface UseQueryOptions { ttl?: TTL | undefined } export interface QueryResult { data: ComputedRef> status: ComputedRef error: ComputedRef void } | undefined> } export interface MaybeQueryResult { data: ComputedRef | undefined> status: ComputedRef error: ComputedRef void } | undefined> } // Overload 1: Query export function useQuery< TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TSchema extends Schema = DefaultSchema, TReturn = PullRow, TContext = DefaultContext, MD extends CustomMutatorDefs | undefined = undefined, >( z: MaybeRefOrGetter>, query: MaybeRefOrGetter>, options?: MaybeRefOrGetter, ): QueryResult // Overload 2: Maybe query export function useQuery< TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TSchema extends Schema = DefaultSchema, TReturn = PullRow, TContext = DefaultContext, MD extends CustomMutatorDefs | undefined = undefined, >( z: MaybeRefOrGetter>, query: MaybeRefOrGetter | Falsy>, options?: MaybeRefOrGetter, ): MaybeQueryResult // Implementation export function useQuery< TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TSchema extends Schema = DefaultSchema, TReturn = PullRow, TContext = DefaultContext, MD extends CustomMutatorDefs | undefined = undefined, >( z: MaybeRefOrGetter>, query: MaybeRefOrGetter | Falsy>, options?: MaybeRefOrGetter, ): QueryResult | MaybeQueryResult { const ttl = computed(() => toValue(options)?.ttl ?? DEFAULT_TTL_MS) const view = shallowRef(null) const refetchKey = shallowRef(0) const q = shallowRef() watch( [ () => toValue(query), () => toValue(z), ], ([query, z]) => { q.value = query ? addContextToQuery(toValue(query), toValue(z).context) : undefined }, { immediate: true }, ) const qi = computed(() => q.value ? asQueryInternals(q.value) : undefined) const hash = computed(() => qi.value ? qi.value.hash() + JSON.stringify(qi.value.format) : undefined) watch( [ () => toValue(z), hash, refetchKey, ], ([z]) => { view.value?.destroy() if (!hash.value) { view.value = null } else { view.value = z.materialize(toValue(q), vueViewFactory, { ttl: toValue(ttl) }) } }, { immediate: true }, ) watch(ttl, (ttl) => { toValue(view)?.updateTTL(ttl) }) if (getCurrentInstance()) { onUnmounted(() => view.value?.destroy()) } return { data: computed(() => view.value?.data as HumanReadable), status: computed(() => view.value?.status ?? 'disabled'), error: computed(() => view.value?.error ? { retry: () => { refetchKey.value++ }, ...view.value.error, } : undefined, ), } }