Skip to content

Commit 28f3520

Browse files
committed
feat(useQuery): nullable query (auto disable)
1 parent 6a94797 commit 28f3520

File tree

4 files changed

+94
-4
lines changed

4 files changed

+94
-4
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<script lang="ts">
2+
import gql from 'graphql-tag'
3+
import { useQuery } from '@vue/apollo-composable'
4+
import { defineComponent, computed, ref } from 'vue'
5+
6+
export default defineComponent({
7+
setup () {
8+
const selectedId = ref<{ id: string } | null>(null)
9+
10+
const nullableQuery = () => selectedId.value ? gql`
11+
query channel ($id: ID!) {
12+
channel (id: $id) {
13+
id
14+
label
15+
messages {
16+
id
17+
}
18+
}
19+
}
20+
` : null
21+
22+
const { result, loading } = useQuery(nullableQuery, () => ({
23+
// Should not throw since it will not be called if the query is disabled
24+
id: selectedId.value!.id,
25+
}), () => ({
26+
fetchPolicy: 'no-cache',
27+
}))
28+
const channel = computed(() => result.value?.channel)
29+
30+
function load () {
31+
selectedId.value = { id: 'general' }
32+
}
33+
34+
return {
35+
load,
36+
loading,
37+
channel,
38+
}
39+
},
40+
})
41+
</script>
42+
43+
<template>
44+
<div class="m-6">
45+
<div>
46+
<button
47+
class="bg-green-200 rounded-lg p-4"
48+
@click="load()"
49+
>
50+
Load channel
51+
</button>
52+
</div>
53+
54+
<div
55+
v-if="loading"
56+
class="loading"
57+
>
58+
Loading...
59+
</div>
60+
61+
<div
62+
v-if="channel"
63+
data-test-id="data"
64+
>
65+
<div>Loaded channel: {{ channel.label }}</div>
66+
<div>Messages: {{ channel.messages.length }}</div>
67+
</div>
68+
</div>
69+
</template>

packages/test-e2e-composable-vue3/src/router.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,9 @@ export const router = createRouter({
4646
path: '/keep-previous-result',
4747
component: () => import('./components/KeepPreviousResult.vue'),
4848
},
49+
{
50+
path: '/null-query',
51+
component: () => import('./components/NullQuery.vue'),
52+
},
4953
],
5054
})
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/// <reference types="Cypress" />
2+
3+
describe('nullableQuery', () => {
4+
beforeEach(() => {
5+
cy.task('db:reset')
6+
cy.visit('/null-query')
7+
})
8+
9+
it('should enable useQuery only if query is non-null', () => {
10+
cy.get('button').should('exist')
11+
cy.wait(100)
12+
cy.get('[data-test-id="data"]').should('not.exist')
13+
cy.get('.loading').should('not.exist')
14+
cy.get('button').click()
15+
cy.get('[data-test-id="data"]').should('contain', 'Loaded channel: General')
16+
})
17+
})

packages/vue-apollo-composable/src/useQuery.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ interface SubscribeToMoreItem {
5353
}
5454

5555
// Parameters
56-
export type DocumentParameter<TResult, TVariables = undefined> = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode> | TypedDocumentNode<TResult, TVariables> | Ref<TypedDocumentNode<TResult, TVariables>> | ReactiveFunction<TypedDocumentNode<TResult, TVariables>>
56+
export type DocumentParameter<TResult, TVariables> = DocumentNode | Ref<DocumentNode | null | undefined> | ReactiveFunction<DocumentNode | null | undefined> | TypedDocumentNode<TResult, TVariables> | Ref<TypedDocumentNode<TResult, TVariables> | null | undefined> | ReactiveFunction<TypedDocumentNode<TResult, TVariables> | null | undefined>
5757
export type VariablesParameter<TVariables> = TVariables | Ref<TVariables> | ReactiveFunction<TVariables>
5858
export type OptionsParameter<TResult, TVariables extends OperationVariables> = UseQueryOptions<TResult, TVariables> | Ref<UseQueryOptions<TResult, TVariables>> | ReactiveFunction<UseQueryOptions<TResult, TVariables>>
5959

@@ -67,7 +67,7 @@ export interface UseQueryReturn<TResult, TVariables extends OperationVariables>
6767
stop: () => void
6868
restart: () => void
6969
forceDisabled: Ref<boolean>
70-
document: Ref<DocumentNode>
70+
document: Ref<DocumentNode | null | undefined>
7171
variables: Ref<TVariables | undefined>
7272
options: UseQueryOptions<TResult, TVariables> | Ref<UseQueryOptions<TResult, TVariables>>
7373
query: Ref<ObservableQuery<TResult, TVariables> | null | undefined>
@@ -437,13 +437,13 @@ export function useQueryImpl<
437437
}
438438

439439
// Applying document
440-
let currentDocument: DocumentNode = documentRef.value
440+
let currentDocument: DocumentNode | null | undefined = documentRef.value
441441

442442
// Enabled state
443443

444444
const forceDisabled = ref(lazy)
445445
const enabledOption = computed(() => !currentOptions.value || currentOptions.value.enabled == null || currentOptions.value.enabled)
446-
const isEnabled = computed(() => enabledOption.value && !forceDisabled.value)
446+
const isEnabled = computed(() => enabledOption.value && !forceDisabled.value && !!documentRef.value)
447447

448448
// Applying options first (in case it disables the query)
449449
watch(() => unref(optionsRef), value => {

0 commit comments

Comments
 (0)