Skip to content

Commit

Permalink
fix: improve context handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Diizzayy committed Oct 17, 2022
1 parent 82666c0 commit b5d3ae2
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 28 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"build": "nuxt-module-build",
"dev": "nuxi dev playground",
"dev:build": "nuxi build playground",
"test": "vitest run --coverage",
"test": "vitest run --coverage --watch false",
"lint": "eslint --ext .js,.ts,.vue .",
"lint:fix": "eslint --fix --ext .js,.ts,.vue .",
"prepare": "nuxt-module-build --stub && nuxi prepare playground"
Expand Down
16 changes: 4 additions & 12 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ export function prepareContext (ctx: GqlContext, prefix: string) {
const fnExp = (fn: string, typed = false) => {
const name = fnName(fn)

if (!typed) {
const client = ctx?.clients.find(c => ctx?.clientOps?.[c]?.includes(fn))

return `export const ${name} = (...params) => GqlInstance().handle(${client ? `'${client}'` : ''})['${fn}'](...params)`
}
if (!typed) { return `export const ${name} = (...params) => useGql()('${fn}', ...params)` }

return ` export const ${name}: (...params: Parameters<GqlSdkFuncs['${fn}']>) => ReturnType<GqlSdkFuncs['${fn}']>`
}
Expand All @@ -40,14 +36,8 @@ export function prepareContext (ctx: GqlContext, prefix: string) {
'import { useGql } from \'#imports\'',
...ctx.clients.map(client => `import { getSdk as ${client}GqlSdk } from '#gql/${client}'`),
'export const GqlSdks = {',
` default: ${ctx.clients.find(c => c === 'default') || ctx.clients[0]}GqlSdk,`,
...ctx.clients.map(client => ` ${client}: ${client}GqlSdk,`),
'}',
'const ctx = { instance: null }',
'export const GqlInstance = () => {',
' if (!ctx?.instance) {ctx.instance = useGql()}',
' return ctx.instance',
'}',
`export const GqlOperations = ${JSON.stringify(ctx.clientOps)}`,
...ctx.fns.map(f => fnExp(f))
].join('\n')
Expand All @@ -58,7 +48,9 @@ export function prepareContext (ctx: GqlContext, prefix: string) {
'declare module \'#gql\' {',
` type GqlClients = '${ctx.clients.join("' | '") || 'default'}'`,
' const GqlOperations = {}',
' type GqlSdkValues<T extends GqlClients> = ReturnType<typeof GqlSdks[T]>',
' const GqlSdks = {',
...ctx.clients.map(client => ` ${client}: ${client}GqlSdk,`),
' }',
...ctx.fns.map(f => fnExp(f, true)),
` type GqlSdkFuncs = ${ctx.clients.map(c => `ReturnType<typeof ${c}GqlSdk>`).join(' & ')}`,
'}'
Expand Down
32 changes: 21 additions & 11 deletions src/runtime/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type { GqlState, GqlConfig, GqlError, OnGqlError } from '../../types'
import { deepmerge } from '../utils'
// @ts-ignore
// eslint-disable-next-line import/named
import { GqlSdks, GqlInstance, GqlOperations } from '#gql'
import type { GqlClients, GqlSdkValues, GqlSdkFuncs } from '#gql'
import { GqlSdks, GqlOperations } from '#gql'
import type { GqlClients, GqlSdkFuncs } from '#gql'
import { useState, useNuxtApp, useAsyncData, useRuntimeConfig } from '#imports'

const useGqlState = (): Ref<GqlState> => {
Expand Down Expand Up @@ -204,12 +204,25 @@ export const useGqlCors = (cors: GqlCors) => {
setGqlState({ client, patch: { mode, credentials } })
}

export const useGql = () => {
export const useGql = (): (<
T extends keyof GqlSdkFuncs,
R extends ReturnType<GqlSdkFuncs[T]>,
P extends Parameters<GqlSdkFuncs[T]>['0'],
> (args: { operation: T, variables?: P }) => R) &
(<
T extends keyof GqlSdkFuncs,
R extends ReturnType<GqlSdkFuncs[T]>,
P extends Parameters<GqlSdkFuncs[T]>['0'],
> (operation: T, variables?: P) => R) => {
const state = useGqlState()
const errState = useGqlErrorState()

const handle = <T extends GqlClients> (client?: T) => {
client = client || 'default' as T
return (...args: any[]) => {
const operation = (typeof args?.[0] !== 'string' && 'operation' in args?.[0] ? args[0].operation : args[0]) ?? undefined
const variables = (typeof args?.[0] !== 'string' && 'variables' in args?.[0] ? args[0].variables : args[1]) ?? undefined

const client = Object.keys(GqlOperations).find(k => GqlOperations[k].includes(operation)) ?? 'default'

const { instance } = state.value?.[client]

return GqlSdks[client](instance, async (action, operationName, operationType): Promise<any> => {
Expand All @@ -230,10 +243,8 @@ export const useGql = () => {

throw errState.value
}
}) as GqlSdkValues<T>
})[operation](variables)
}

return { handle }
}

/**
Expand Down Expand Up @@ -294,7 +305,6 @@ export function useAsyncGql (...args: any[]) {
const operation = (typeof args?.[0] !== 'string' && 'operation' in args?.[0] ? args[0].operation : args[0]) ?? undefined
const variables = (typeof args?.[0] !== 'string' && 'variables' in args?.[0] ? args[0].variables : args[1]) ?? undefined
const options = (typeof args?.[0] !== 'string' && 'options' in args?.[0] ? args[0].options : args[2]) ?? undefined
const client = Object.keys(GqlOperations).find(k => GqlOperations[k].includes(operation)) ?? 'default'
const key = hash({ operation, client, variables })
return useAsyncData(key, () => GqlInstance().handle(client as GqlClients)[operation](variables), options)
const key = hash({ operation, variables })
return useAsyncData(key, () => useGql()(operation, variables), options)
}
16 changes: 16 additions & 0 deletions test/fixtures/multi-client/pages/rmorty/chain.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<div>
<p>First Episode: {{ data.episode.name || 'Unknown' }}</p>
<p>Name: {{ data?.character?.name || 'John Doe' }}</p>
</div>
</template>

<script lang="ts" setup>
const GqlInstance = useGql()
const { data } = await useAsyncData(async () => {
const { episode } = await GqlInstance('first_episode')
const { character } = await GqlInstance('character')
return { episode, character }
})
</script>
2 changes: 1 addition & 1 deletion test/fixtures/multi-client/pages/spacex/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
</template>

<script lang="ts" setup>
const { data } = await useAsyncGql('launches')
const { data } = await useAsyncData(() => GqlLaunches())
</script>
4 changes: 3 additions & 1 deletion test/fixtures/multi-client/pages/spacex/mission.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
</template>

<script lang="ts" setup>
const { data } = await useAsyncGql('mission')
const GqlInstance = useGql()
const { data } = await useAsyncData(() => GqlInstance('mission'))
</script>
10 changes: 8 additions & 2 deletions test/multi-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ describe('test multiple clients', () => {
it('renders the character morty', async () => {
const result = await $fetch('/rmorty')
expect(result).toContain('<p>Name: Morty Smith</p>')
}, 15000)
})

it('fetches the name of the first rick and morty episode', async () => {
const result = await $fetch('/rmorty/first-ep')
expect(result).toContain('<p>First Episode: Pilot</p>')
}, 15000)
})

it('fetches the name of the first rick and morty episode', async () => {
const result = await $fetch('/rmorty/chain')
expect(result).toContain('<p>First Episode: Pilot</p>')
expect(result).toContain('<p>Name: Morty Smith</p>')
})
})

0 comments on commit b5d3ae2

Please sign in to comment.