From 24a9e4394b1bdef7b753a120b88aeb6b58f512ae Mon Sep 17 00:00:00 2001 From: estrada9166 Date: Thu, 9 May 2019 11:21:42 -0500 Subject: [PATCH 1/4] Add partialRefetch as an option --- src/useQuery.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/useQuery.ts b/src/useQuery.ts index 17a7c47..2fe122a 100644 --- a/src/useQuery.ts +++ b/src/useQuery.ts @@ -42,6 +42,7 @@ export interface QueryHookOptions ssr?: boolean; skip?: boolean; suspend?: boolean; + partialRefetch?: boolean; } export interface QueryHookResult @@ -67,6 +68,7 @@ export function useQuery< ssr = true, skip = false, suspend = false, + partialRefetch = false, // Watch options pollInterval, @@ -163,6 +165,20 @@ export function useQuery< }; } + if ( + partialRefetch && + Object.keys(result.data).length === 0 && + result.partial && + fetchPolicy !== 'cache-only' + ) { + Object.assign(result.data, helpers, { + loading: true, + networkStatus: NetworkStatus.loading, + }); + helpers.refetch(); + return result.data; + } + return { ...helpers, data, From 449d9b652c3f1f453de34f309339302b9328d2ff Mon Sep 17 00:00:00 2001 From: estrada9166 Date: Thu, 9 May 2019 11:25:14 -0500 Subject: [PATCH 2/4] Add comment ref solution --- src/useQuery.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/useQuery.ts b/src/useQuery.ts index 2fe122a..3017a04 100644 --- a/src/useQuery.ts +++ b/src/useQuery.ts @@ -165,6 +165,7 @@ export function useQuery< }; } + // Taken from https://github.com/apollographql/react-apollo/blob/22f8ebf52b26b348d6be905d5b7fbbfea51c1541/src/Query.tsx#L455-L472 if ( partialRefetch && Object.keys(result.data).length === 0 && From 1fbd21b849ef8b2f48a0513baa614dec51e006d4 Mon Sep 17 00:00:00 2001 From: estrada9166 Date: Thu, 9 May 2019 11:27:32 -0500 Subject: [PATCH 3/4] Fix ci --- src/useQuery.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/useQuery.ts b/src/useQuery.ts index 3017a04..e7cb944 100644 --- a/src/useQuery.ts +++ b/src/useQuery.ts @@ -172,12 +172,14 @@ export function useQuery< result.partial && fetchPolicy !== 'cache-only' ) { - Object.assign(result.data, helpers, { + const partialRefetchResult = { + ...result.data, + ...helpers, loading: true, networkStatus: NetworkStatus.loading, - }); + }; helpers.refetch(); - return result.data; + return partialRefetchResult; } return { From 01afc8e8bdc37486cec7978e335d877964f59967 Mon Sep 17 00:00:00 2001 From: estrada9166 Date: Thu, 16 May 2019 20:38:24 -0500 Subject: [PATCH 4/4] Handle data to return last result, add UT --- src/__tests__/useMutation-test.tsx | 225 +++++++++++++++++++++++++++++ src/useQuery.ts | 9 +- 2 files changed, 232 insertions(+), 2 deletions(-) diff --git a/src/__tests__/useMutation-test.tsx b/src/__tests__/useMutation-test.tsx index 0f99ce8..1ea7996 100644 --- a/src/__tests__/useMutation-test.tsx +++ b/src/__tests__/useMutation-test.tsx @@ -84,6 +84,31 @@ const TASKS_MOCKS = [ }, }, }, + + { + request: { + query: gql` + mutation AddTaskMissingFieldMutation($input: AddTaskMutationInput!) { + addTask(input: $input) { + id + text + __typename + } + } + `, + variables: { input: { text: 'Learn Jest' } }, + }, + result: { + data: { + __typename: 'Mutation', + addTask: { + __typename: 'Task', + id: '4', + text: 'Learn Jest', + }, + }, + }, + }, ]; const TASKS_QUERY = gql` @@ -115,6 +140,15 @@ const ADD_TASK_MUTATION = gql` } `; +const ADD_TASK_MISSING_FIELD_MUTATION = gql` + mutation AddTaskMissingFieldMutation($input: AddTaskMutationInput!) { + addTask(input: $input) { + id + text + } + } +`; + interface TaskFragment { id: number; text: string; @@ -254,3 +288,194 @@ it('should allow to pass options forwarded to the mutation', async () => { expect(container.querySelectorAll('li')).toHaveLength(4); expect(container.querySelectorAll('li')[3].textContent).toBe('Learn Jest'); }); + +it('should have an error if the mutation has a field missings', async () => { + // Added 1 more time the query mock for TASKS_QUERY, because of this comment + // https://github.com/apollographql/react-apollo/issues/617#issuecomment-29310361 + TASKS_MOCKS.push({ + request: { + query: gql` + query TasksQuery { + tasks { + id + text + completed + __typename + } + } + `, + variables: {}, + }, + result: { + data: { + __typename: 'Query', + tasks: [ + ...SAMPLE_TASKS, + { + __typename: 'Task', + id: 4, + text: 'Learn Jest', + } as any, + ], + }, + }, + }); + + let tasks; + function TasksWithMutation() { + const { data, error, loading } = useQuery(TASKS_QUERY); + const addTask = useMutation }>( + ADD_TASK_MISSING_FIELD_MUTATION, + { + update: (proxy, mutationResult) => { + const previousData = proxy.readQuery<{ tasks: TaskFragment[] }>({ + query: TASKS_QUERY, + }); + previousData!.tasks.push(mutationResult!.data!.addTask); + proxy.writeQuery({ data: previousData, query: TASKS_QUERY }); + }, + variables: { + input: { + text: 'Learn Jest', + }, + }, + } + ); + + tasks = data.tasks; + if (error) { + throw error; + } + + if (loading) { + return <>Loading; + } + + return ( + <> +
    + {data && + data.tasks && + data.tasks.map((task: TaskFragment) => ( +
  • {task.text}
  • + ))} +
+ + + ); + } + + const client = createClient({ mocks: TASKS_MOCKS }); + const { container, getByTestId } = render( + + + + ); + + await wait(); + + const addTaskButton = getByTestId('add-task-button'); + fireEvent.click(addTaskButton); + await wait(); + + expect(container.querySelectorAll('li')).toHaveLength(0); + expect(tasks).toBe(undefined); +}); + +it('should work if the mutation has a field missings and the partialRefetch is true', async () => { + // Added 1 more time the query mock for TASKS_QUERY, because of this comment + // https://github.com/apollographql/react-apollo/issues/617#issuecomment-29310361 + TASKS_MOCKS.push({ + request: { + query: gql` + query TasksQuery { + tasks { + id + text + completed + __typename + } + } + `, + variables: {}, + }, + result: { + data: { + __typename: 'Query', + tasks: [ + ...SAMPLE_TASKS, + { + __typename: 'Task', + id: 4, + text: 'Learn Jest', + } as any, + ], + }, + }, + }); + + let tasks; + function TasksWithMutation() { + const { data, error, loading } = useQuery(TASKS_QUERY, { + partialRefetch: true, + }); + const addTask = useMutation }>( + ADD_TASK_MISSING_FIELD_MUTATION, + { + update: (proxy, mutationResult) => { + const previousData = proxy.readQuery<{ tasks: TaskFragment[] }>({ + query: TASKS_QUERY, + }); + previousData!.tasks.push(mutationResult!.data!.addTask); + proxy.writeQuery({ data: previousData, query: TASKS_QUERY }); + }, + variables: { + input: { + text: 'Learn Jest', + }, + }, + } + ); + + tasks = data.tasks; + if (error) { + throw error; + } + + if (loading) { + return <>Loading; + } + + return ( + <> +
    + {data && + data.tasks && + data.tasks.map((task: TaskFragment) => ( +
  • {task.text}
  • + ))} +
+ + + ); + } + + const client = createClient({ mocks: TASKS_MOCKS }); + const { getByTestId } = render( + + + + ); + + await wait(); + + const addTaskButton = getByTestId('add-task-button'); + fireEvent.click(addTaskButton); + await wait(); + + expect(tasks).toHaveLength(4); +}); diff --git a/src/useQuery.ts b/src/useQuery.ts index e7cb944..57e73dd 100644 --- a/src/useQuery.ts +++ b/src/useQuery.ts @@ -172,13 +172,18 @@ export function useQuery< result.partial && fetchPolicy !== 'cache-only' ) { - const partialRefetchResult = { + data = { ...result.data, + ...(observableQuery.getLastResult() || {}).data, + }; + + const partialRefetchResult = { ...helpers, + data, loading: true, networkStatus: NetworkStatus.loading, }; - helpers.refetch(); + partialRefetchResult.refetch(); return partialRefetchResult; }