feat: add updateQuery to useQuery (#1552)

This commit is contained in:
Leonardo Santos
2024-08-14 11:12:58 -03:00
committed by GitHub
parent f2360701ba
commit d1098bee4f
4 changed files with 185 additions and 0 deletions
@@ -0,0 +1,141 @@
<script lang="ts" setup>
import { useMutation, useQuery } from '@vue/apollo-composable'
import gql from 'graphql-tag'
import { computed, ref } from 'vue'
import MessageItem from './MessageItem.vue'
interface Channel {
id: string
label: string
}
const channelsQuery = useQuery<{ channels: Channel[] }>(gql`
query channels {
channels {
id
label
}
}
`)
const channels = computed(() => channelsQuery.result.value?.channels ?? [])
const selectedChannelId = ref<string | null>(null)
const selectedChannelQuery = useQuery(gql`
query channel ($id: ID!) {
channel (id: $id) {
id
label
messages {
id
text
}
}
}
`, () => ({
id: selectedChannelId.value,
}), () => ({
enabled: !!selectedChannelId.value,
}))
const addMessageMutation = useMutation(gql`
mutation sendMessage ($input: AddMessageInput!) {
message: addMessage (input: $input) {
id
text
}
}
`)
const selectedChannel = computed(() => selectedChannelQuery.result.value?.channel)
const newMessageText = ref('')
async function sendMessage () {
if (!newMessageText.value.length) return
const result = await addMessageMutation.mutate({
input: {
channelId: selectedChannelId.value,
text: newMessageText.value,
},
})
newMessageText.value = ''
selectedChannelQuery.updateQuery(previousResult => ({
...previousResult,
channel: {
...previousResult.channel,
messages: [
...previousResult.channel.messages,
result?.data.message,
],
},
}))
}
</script>
<template>
<div class="h-full flex flex-col">
<div class="flex h-full">
<div class="flex flex-col">
<button
v-for="channel of channels"
:key="channel.id"
class="channel-btn p-4"
:class="{
'bg-green-200': selectedChannelId === channel.id,
}"
@click="selectedChannelId = channel.id"
>
{{ channel.label }}
</button>
</div>
<div
v-if="selectedChannel"
class="the-channel flex flex-col w-full h-full overflow-auto"
>
<div class="flex-none p-6 border-b border-gray-200 bg-white">
# {{ selectedChannel.label }}
</div>
<div class="flex-1 overflow-y-auto">
<MessageItem
v-for="message of selectedChannel.messages"
:key="message.id"
:message="message"
class="m-2"
/>
</div>
<div class="flex gap-x-2 p-4">
<div class="border border-gray-200 rounded-lg bg-white flex-1">
<input
v-model="newMessageText"
type="text"
class="message-input w-full h-full bg-transparent px-3"
placeholder="Type a message..."
>
</div>
<button
class="send-message-btn bg-green-200 py-3 px-4 rounded-lg"
@click="sendMessage"
>
Send
</button>
</div>
</div>
<div
v-else
class="no-data"
>
No data
</div>
</div>
</div>
</template>
@@ -93,5 +93,9 @@ export const router = createRouter({
layout: 'blank',
},
},
{
path: '/update-query',
component: () => import('./components/UpdateQuery.vue'),
},
],
})
@@ -0,0 +1,30 @@
describe('updateQuery', () => {
beforeEach(() => {
cy.task('db:reset')
cy.visit('/update-query')
})
it('should add new message to cache using updateQuery', () => {
cy.get('.channel-btn').eq(0).click()
cy.get('.message-input').type('hello 1')
cy.get('.message').should('have.lengthOf', 0)
cy.get('.send-message-btn').click()
cy.get('.message').should('have.lengthOf', 1)
cy.get('.message-input').type('hello 2')
cy.get('.send-message-btn').click()
cy.get('.message').should('have.lengthOf', 2)
cy.contains('.message', 'hello 1')
cy.contains('.message', 'hello 2')
cy.get('.channel-btn').eq(1).click()
cy.get('.message-input').type('hello 3')
cy.get('.message').should('have.lengthOf', 0)
cy.get('.send-message-btn').click()
cy.get('.message').should('have.lengthOf', 1)
cy.get('.message-input').type('hello 4')
cy.get('.send-message-btn').click()
cy.get('.message').should('have.lengthOf', 2)
cy.contains('.message', 'hello 3')
cy.contains('.message', 'hello 4')
})
})
@@ -81,6 +81,7 @@ export interface UseQueryReturn<TResult, TVariables extends OperationVariables>
query: Ref<ObservableQuery<TResult, TVariables> | null | undefined>
refetch: (variables?: TVariables) => Promise<ApolloQueryResult<TResult>> | undefined
fetchMore: (options: FetchMoreQueryOptions<TVariables, TResult> & FetchMoreOptions<TResult, TVariables>) => Promise<ApolloQueryResult<TResult>> | undefined
updateQuery: (mapFn: (previousQueryResult: TResult, options: Pick<WatchQueryOptions<TVariables, TResult>, 'variables'>) => TResult) => void
subscribeToMore: <TSubscriptionVariables = OperationVariables, TSubscriptionData = TResult>(options: SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData> | Ref<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>> | ReactiveFunction<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>>) => void
onResult: (fn: (param: ApolloQueryResult<TResult>, context: OnResultContext) => void) => {
off: () => void
@@ -534,6 +535,14 @@ export function useQueryImpl<
}
}
// Update Query
function updateQuery (mapFn: (previousQueryResult: TResult, options: Pick<WatchQueryOptions<TVariables, TResult>, 'variables'>) => TResult) {
if (query.value) {
query.value.updateQuery(mapFn)
}
}
// Fetch more
function fetchMore (options: FetchMoreQueryOptions<TVariables, TResult> & FetchMoreOptions<TResult, TVariables>) {
@@ -637,6 +646,7 @@ export function useQueryImpl<
refetch,
fetchMore,
subscribeToMore,
updateQuery,
onResult: resultEvent.on,
onError: errorEvent.on,
}