diff --git a/playground/components/TodosDemo.vue b/playground/components/TodosDemo.vue index 5ecc38ab..acaf6c24 100644 --- a/playground/components/TodosDemo.vue +++ b/playground/components/TodosDemo.vue @@ -35,7 +35,8 @@ const gqlTodos = gql`query todo { todos { id text } }` const gqlCreateTodo = gql`mutation createTodo($todo: TodoInput!) { createTodo(todo: $todo) { id } }` const gqlTodoAdded = gql`subscription todoAdded { todoAdded { id text } }` -const { data, refresh } = await useAsyncQuery(gqlTodos, 'todos') +type TodoEntry = { id: string, text: string } +const { data, refresh } = await useAsyncQuery(gqlTodos, null, 'todos') const { mutate: todoMutation } = useMutation(gqlCreateTodo, { clientId: 'todos' }) diff --git a/src/runtime/composables.ts b/src/runtime/composables.ts index cf6182b5..734f88e5 100644 --- a/src/runtime/composables.ts +++ b/src/runtime/composables.ts @@ -1,56 +1,108 @@ import { hash } from 'ohash' import { print } from 'graphql' import type { OperationVariables, QueryOptions, DefaultContext } from '@apollo/client' -import type { AsyncData } from 'nuxt/dist/app/composables' +import type { AsyncData, NuxtError } from 'nuxt/app' import type { NuxtAppApollo } from '../types' import { ref, useCookie, useNuxtApp, useAsyncData } from '#imports' import NuxtApollo from '#build/apollo' +type PickFrom> = T extends Array ? T : T extends Record ? keyof T extends K[number] ? T : K[number] extends never ? T : Pick : T +type KeysOf = Array + type TQuery = QueryOptions['query'] -type TVariables = QueryOptions['variables'] +type TVariables = QueryOptions['variables'] | null type TAsyncQuery = { - cache?: boolean, - context?: DefaultContext, - clientId?: string, - key?: string, - query: TQuery, - variables?: TVariables, + key?: string + query: TQuery + variables?: TVariables + clientId?: string + context?: DefaultContext + cache?: boolean } -export function useAsyncQuery (opts: TAsyncQuery): AsyncData -export function useAsyncQuery (query: TQuery, clientId?: string): AsyncData -export function useAsyncQuery (query: TQuery, variables?: TVariables, clientId?: string, context?: DefaultContext): AsyncData - -export function useAsyncQuery (...args: any) { - const { key, fn } = prep(...args) +export function useAsyncQuery < + T, + DataT = T, + PickKeys extends KeysOf = KeysOf, + DefaultT = null, + NuxtErrorDataT = unknown +> (opts: TAsyncQuery): AsyncData | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError) | null> + +export function useAsyncQuery < + T, + DataT = T, + PickKeys extends KeysOf = KeysOf, + DefaultT = null, + NuxtErrorDataT = unknown +> (query: TQuery, variables?: TVariables, clientId?: string, context?: DefaultContext): AsyncData | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError) | null> + +export function useAsyncQuery (...args: any[]) { + const { key, fn } = prep(...args) return useAsyncData(key, fn) } -export function useLazyAsyncQuery (opts: TAsyncQuery): AsyncData -export function useLazyAsyncQuery (query: TQuery, clientId?: string): AsyncData -export function useLazyAsyncQuery (query: TQuery, variables?: TVariables, clientId?: string, context?: DefaultContext): AsyncData +export function useLazyAsyncQuery < + T, + DataT = T, + PickKeys extends KeysOf = KeysOf, + DefaultT = null, + NuxtErrorDataT = unknown +> (opts: TAsyncQuery): AsyncData | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError) | null> + +export function useLazyAsyncQuery < + T, + DataT = T, + PickKeys extends KeysOf = KeysOf, + DefaultT = null, + NuxtErrorDataT = unknown +> (query: TQuery, variables?: TVariables, clientId?: string, context?: DefaultContext): AsyncData | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError) | null> export function useLazyAsyncQuery (...args: any) { - const { key, fn } = prep(...args) + const { key, fn } = prep(...args) return useAsyncData(key, fn, { lazy: true }) } -const prep = (...args: any) => { +const prep = (...args: any[]) => { const { clients } = useApollo() - const query = args?.[0]?.query || args?.[0] - const cache = args?.[0]?.cache ?? true - const variables = args?.[0]?.variables || (typeof args?.[1] !== 'string' && args?.[1]) || undefined - const context = args?.[0]?.context || (typeof args?.[1] === 'string' && args?.[3]) || undefined - let clientId = args?.[0]?.clientId || (typeof args?.[1] === 'string' && args?.[2]) || undefined + let query: TQuery + let variables: TVariables + + let cache: boolean = true + let clientId: string | undefined + let context: DefaultContext + + if ((typeof args?.[0] === 'object' && 'query' in args[0])) { + query = args?.[0]?.query + variables = args?.[0]?.variables + + cache = args?.[0]?.cache ?? true + context = args?.[0]?.context + clientId = args?.[0]?.clientId + } else { + query = args?.[0] + variables = args?.[1] + + clientId = args?.[2] + context = args?.[3] + } + + if (!query) { throw new Error('@nuxtjs/apollo: no query provided') } if (!clientId || !clients?.[clientId]) { - clientId = clients?.default ? 'default' : Object.keys(clients!)[0] + clientId = clients?.default ? 'default' : Object.keys(clients!)?.[0] + + if (!clientId) { throw new Error('@nuxtjs/apollo: no client found') } } const key = args?.[0]?.key || hash({ query: print(query), variables, clientId }) - const fn = () => clients![clientId]?.query({ query, variables, fetchPolicy: cache ? 'cache-first' : 'no-cache', context }).then(r => r.data) + const fn = () => clients![clientId!]?.query({ + query, + variables: variables || undefined, + fetchPolicy: cache ? 'cache-first' : 'no-cache', + context + }).then(r => r.data) return { key, query, clientId, variables, fn } } @@ -83,6 +135,7 @@ export const useApollo = () => { if (conf?.tokenStorage === 'cookie') { const cookieOpts = (client && conf?.cookieAttributes) || NuxtApollo?.cookieAttributes + // @ts-ignore const cookie = useCookie(tokenName, cookieOpts) if (!cookie.value && mode === 'logout') { return }