import type { ConnectionState, CustomMutatorDefs, DefaultContext, DefaultSchema, Falsy, PullRow, QueryOrQueryRequest, ReadonlyJSONValue, Schema, ZeroOptions, } from '@rocicorp/zero' import type { DeepReadonly, MaybeRefOrGetter, Ref, ShallowRef } from 'vue' import type { MaybeQueryResult, QueryResult, UseQueryOptions } from './query' import { Zero } from '@rocicorp/zero' import { getCurrentInstance, onUnmounted, readonly, ref, shallowRef, toValue, watch } from 'vue' import { useQuery as _useQuery } from './query' export interface ZeroComposables< TSchema extends Schema, MD extends CustomMutatorDefs | undefined, TContext, > { useZero: () => ShallowRef> useQuery: { < TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TReturn = PullRow, >( query: MaybeRefOrGetter>, options?: MaybeRefOrGetter, ): QueryResult < TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TReturn = PullRow, >( query: MaybeRefOrGetter | Falsy>, options?: MaybeRefOrGetter, ): MaybeQueryResult } useConnectionState: () => DeepReadonly> } export function createZeroComposables< TSchema extends Schema = DefaultSchema, MD extends CustomMutatorDefs | undefined = undefined, TContext = DefaultContext, >( optsOrZero: MaybeRefOrGetter | { zero: Zero }>, ): ZeroComposables { let z: ShallowRef> let connectionState: Ref let unsubscribe: () => void function useZero(): ShallowRef> { if (!z) { z = shallowRef() as ShallowRef> } if (z.value) { return z } watch(() => toValue(optsOrZero), (opts) => { if (z.value && !z.value.closed) { void z.value.close() } z.value = 'zero' in opts ? opts.zero : new Zero(opts) }, { deep: 1, immediate: true, }) return z } function useQuery< TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TReturn = PullRow, >( query: MaybeRefOrGetter>, options?: MaybeRefOrGetter, ): QueryResult function useQuery< TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TReturn = PullRow, >( query: MaybeRefOrGetter | Falsy>, options?: MaybeRefOrGetter, ): MaybeQueryResult function useQuery< TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TReturn = PullRow, >( query: MaybeRefOrGetter | Falsy>, options?: MaybeRefOrGetter, ): QueryResult | MaybeQueryResult { const zero = useZero() return _useQuery(zero, query, options) } function useConnectionState(): DeepReadonly> { if (!connectionState) { useZero() connectionState = ref() as Ref watch(z, (zero) => { if (!zero) { return } connectionState.value = zero.connection.state.current unsubscribe = zero.connection.state.subscribe((state) => { connectionState.value = state }) }, { immediate: true }) } return readonly(connectionState) } function cleanup() { unsubscribe?.() } if (getCurrentInstance()) { onUnmounted(cleanup) } return { useZero, useQuery, useConnectionState, } }