Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
at main 3.9 kB view raw
1import { pipe, map, scan, subscribe } from 'wonka'; 2import { derived, writable } from 'svelte/store'; 3 4import type { 5 AnyVariables, 6 GraphQLRequestParams, 7 Client, 8 OperationContext, 9} from '@urql/core'; 10import { createRequest } from '@urql/core'; 11 12import type { OperationResultState, OperationResultStore } from './common'; 13import { initialResult } from './common'; 14 15/** Input arguments for the {@link mutationStore} function. 16 * 17 * @param query - The GraphQL mutation that the `mutationStore` executes. 18 * @param variables - The variables for the GraphQL mutation that `mutationStore` executes. 19 */ 20export type MutationArgs< 21 Data = any, 22 Variables extends AnyVariables = AnyVariables, 23> = { 24 /** The {@link Client} using which the subscription will be started. 25 * 26 * @remarks 27 * If you’ve previously provided a {@link Client} on Svelte’s context 28 * this can be set to {@link getContextClient}’s return value. 29 */ 30 client: Client; 31 /** Updates the {@link OperationContext} for the GraphQL mutation operation. 32 * 33 * @remarks 34 * `context` may be passed to {@link mutationStore}, to update the 35 * {@link OperationContext} of a mutation operation. This may be used to update 36 * the `context` that exchanges will receive for a single hook. 37 * 38 * @example 39 * ```ts 40 * mutationStore({ 41 * query, 42 * context: { 43 * additionalTypenames: ['Item'], 44 * }, 45 * }); 46 * ``` 47 */ 48 context?: Partial<OperationContext>; 49} & GraphQLRequestParams<Data, Variables>; 50 51/** Function to create a `mutationStore` that runs a GraphQL mutation and updates with a GraphQL result. 52 * 53 * @param args - a {@link MutationArgs} object, to pass a `query`, `variables`, and options. 54 * @returns a {@link OperationResultStore} of the mutation’s result. 55 * 56 * @remarks 57 * `mutationStore` allows a GraphQL mutation to be defined as a Svelte store. 58 * Given {@link MutationArgs.query}, it executes the GraphQL mutation on the 59 * {@link MutationArgs.client}. 60 * 61 * The returned store updates with an {@link OperationResult} when 62 * the `Client` returns a result for the mutation. 63 * 64 * Hint: It’s often easier to use {@link Client.mutation} if you’re 65 * creating a mutation imperatively and don’t need a store. 66 * 67 * @see {@link https://urql.dev/goto/docs/basics/svelte#mutations} for 68 * `mutationStore` docs. 69 * 70 * @example 71 * ```ts 72 * import { mutationStore, gql, getContextClient } from '@urql/svelte'; 73 * 74 * const client = getContextClient(); 75 * 76 * let result; 77 * function updateTodo({ id, title }) { 78 * result = queryStore({ 79 * client, 80 * query: gql` 81 * mutation($id: ID!, $title: String!) { 82 * updateTodo(id: $id, title: $title) { id, title } 83 * } 84 * `, 85 * variables: { id, title }, 86 * }); 87 * } 88 * ``` 89 */ 90export function mutationStore< 91 Data = any, 92 Variables extends AnyVariables = AnyVariables, 93>(args: MutationArgs<Data, Variables>): OperationResultStore<Data, Variables> { 94 const request = createRequest(args.query, args.variables as Variables); 95 const operation = args.client.createRequestOperation( 96 'mutation', 97 request, 98 args.context 99 ); 100 const initialState: OperationResultState<Data, Variables> = { 101 ...initialResult, 102 operation, 103 fetching: true, 104 }; 105 const result$ = writable(initialState); 106 107 const subscription = pipe( 108 pipe( 109 args.client.executeRequestOperation(operation), 110 map(({ stale, data, error, extensions, operation, hasNext }) => ({ 111 fetching: false, 112 stale, 113 data, 114 error, 115 operation, 116 extensions, 117 hasNext, 118 })) 119 ), 120 scan( 121 (result: OperationResultState<Data, Variables>, partial) => ({ 122 ...result, 123 ...partial, 124 }), 125 initialState 126 ), 127 subscribe(result => { 128 result$.set(result); 129 }) 130 ); 131 132 return derived(result$, (result, set) => { 133 set(result); 134 return subscription.unsubscribe; 135 }); 136}