feat: add updateQuery to useQuery (#1552)
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user