Skip to content

Commit

Permalink
Allow user to set TVariables and TContext types
Browse files Browse the repository at this point in the history
  • Loading branch information
Jenn Creighton committed Apr 1, 2021
1 parent 38dd67c commit 90a9131
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 100 deletions.
15 changes: 8 additions & 7 deletions src/core/ApolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import {
LocalState,
FragmentMatcher,
} from './LocalState';
import { Context } from 'vm';

export interface DefaultOptions {
watchQuery?: Partial<WatchQueryOptions<any, any>>;
query?: Partial<QueryOptions<any, any>>;
mutate?: Partial<MutationOptions<any, any>>;
mutate?: Partial<MutationOptions<any, any, any>>;
}

let hasSuggestedDevtools = false;
Expand All @@ -56,13 +57,13 @@ export type ApolloClientOptions<TCacheShape> = {
version?: string;
};

type OptionsUnion<TData, TVariables> =
type OptionsUnion<TData, TVariables, TContext> =
| WatchQueryOptions<TVariables, TData>
| QueryOptions<TVariables, TData>
| MutationOptions<TData, TVariables>;
| MutationOptions<TData, TVariables, TContext>;

export function mergeOptions<
TOptions extends OptionsUnion<any, any>
TOptions extends OptionsUnion<any, any, any>
>(
defaults: Partial<TOptions>,
options: TOptions,
Expand Down Expand Up @@ -347,13 +348,13 @@ export class ApolloClient<TCacheShape> implements DataProxy {
*
* It takes options as an object with the following keys and values:
*/
public mutate<T = any, TVariables = OperationVariables>(
options: MutationOptions<T, TVariables>,
public mutate<T = any, TVariables = OperationVariables, TContext = Context>(
options: MutationOptions<T, TVariables, TContext>,
): Promise<FetchResult<T>> {
if (this.defaultOptions.mutate) {
options = mergeOptions(this.defaultOptions.mutate, options);
}
return this.queryManager.mutate<T>(options);
return this.queryManager.mutate<T, TVariables, TContext>(options);
}

/**
Expand Down
55 changes: 22 additions & 33 deletions src/core/QueryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { NetworkStatus, isNetworkRequestInFlight } from './networkStatus';
import {
ApolloQueryResult,
OperationVariables,
MutationUpdaterFunction,
} from './types';
import { LocalState } from './LocalState';

Expand All @@ -48,11 +49,7 @@ interface MutationStoreValue {
error: Error | null;
}

type MutationResult<TData> = Omit<FetchResult<TData>, 'context'>;
interface MutationResultOptions {
context?: Record<string, any>,
variables?: OperationVariables,
}
type UpdateQueries<TData> = MutationOptions<TData, any, any>["updateQueries"];

export class QueryManager<TStore> {
public cache: ApolloCache<TStore>;
Expand Down Expand Up @@ -127,7 +124,7 @@ export class QueryManager<TStore> {
this.fetchCancelFns.clear();
}

public async mutate<T>({
public async mutate<T, TVariables, TContext>({
mutation,
variables,
optimisticResponse,
Expand All @@ -138,7 +135,7 @@ export class QueryManager<TStore> {
errorPolicy = 'none',
fetchPolicy,
context,
}: MutationOptions): Promise<FetchResult<T>> {
}: MutationOptions<T, TVariables, TContext>): Promise<FetchResult<T>> {
invariant(
mutation,
'mutation option is required. You must specify your GraphQL document in the mutation option.',
Expand All @@ -152,10 +149,10 @@ export class QueryManager<TStore> {
const mutationId = this.generateMutationId();
mutation = this.transform(mutation).document;

variables = this.getVariables(mutation, variables);
variables = this.getVariables(mutation, variables) as TVariables;

if (this.transform(mutation).hasClientExports) {
variables = await this.localState.addExportedVariables(mutation, variables, context);
variables = await this.localState.addExportedVariables(mutation, variables, context) as TVariables;
}

const mutationStoreValue =
Expand All @@ -168,7 +165,7 @@ export class QueryManager<TStore> {
} as MutationStoreValue);

if (optimisticResponse) {
this.markMutationOptimistic<T>(optimisticResponse, {
this.markMutationOptimistic<T, TVariables, TContext>(optimisticResponse, {
mutationId,
document: mutation,
variables,
Expand Down Expand Up @@ -211,7 +208,7 @@ export class QueryManager<TStore> {

if (fetchPolicy !== 'no-cache') {
try {
self.markMutationResult<T>({
self.markMutationResult<T, TVariables, TContext>({
mutationId,
result,
document: mutation,
Expand Down Expand Up @@ -319,20 +316,16 @@ export class QueryManager<TStore> {
});
}

public markMutationResult<TData>(
public markMutationResult<TData, TVariables, TContext>(
mutation: {
mutationId: string;
result: FetchResult<TData>;
document: DocumentNode;
variables?: OperationVariables;
variables?: TVariables;
errorPolicy: ErrorPolicy;
context: Record<string, any>;
updateQueries: MutationOptions<TData>["updateQueries"],
update?: (
cache: ApolloCache<TStore>,
result: MutationResult<TData>,
options: MutationResultOptions,
) => void;
context?: TContext;
updateQueries: UpdateQueries<TData>,
update?: MutationUpdaterFunction<TData, TVariables, TContext>,
},
cache = this.cache,
) {
Expand Down Expand Up @@ -391,7 +384,7 @@ export class QueryManager<TStore> {
// write action.
const { update } = mutation;
if (update) {
update(c, mutation.result, {
update(c as any, mutation.result, {
context: mutation.context,
variables: mutation.variables,
});
Expand All @@ -400,20 +393,16 @@ export class QueryManager<TStore> {
}
}

public markMutationOptimistic<TData>(
public markMutationOptimistic<TData, TVariables, TContext>(
optimisticResponse: any,
mutation: {
mutationId: string;
document: DocumentNode;
variables?: OperationVariables;
variables?: TVariables;
errorPolicy: ErrorPolicy;
context: Record<string, any>;
updateQueries: MutationOptions<TData>["updateQueries"],
update?: (
cache: ApolloCache<TStore>,
result: MutationResult<TData>,
options: MutationResultOptions,
) => void;
context?: TContext;
updateQueries: UpdateQueries<TData>,
update?: MutationUpdaterFunction<TData, TVariables, TContext>;
},
) {
const data = typeof optimisticResponse === "function"
Expand All @@ -422,7 +411,7 @@ export class QueryManager<TStore> {

return this.cache.recordOptimisticTransaction(cache => {
try {
this.markMutationResult<TData>({
this.markMutationResult<TData, TVariables, TContext>({
...mutation,
result: { data },
}, cache);
Expand Down Expand Up @@ -518,9 +507,9 @@ export class QueryManager<TStore> {
return transformCache.get(document)!;
}

private getVariables(
private getVariables<TVariables>(
document: DocumentNode,
variables?: OperationVariables,
variables?: TVariables,
): OperationVariables {
return {
...this.transform(document).defaultVars,
Expand Down
1 change: 0 additions & 1 deletion src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export {
ErrorPolicy,
FetchMoreQueryOptions,
SubscribeToMoreOptions,
MutationUpdaterFn,
} from './watchQueryOptions';
export { NetworkStatus } from './networkStatus';
export * from './types';
Expand Down
11 changes: 11 additions & 0 deletions src/core/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DocumentNode, GraphQLError } from 'graphql';

import { ApolloCache } from '../cache';
import { FetchResult } from '../link/core';
import { ApolloError } from '../errors';
import { QueryInfo } from './QueryInfo';
Expand All @@ -8,6 +9,8 @@ import { Resolver } from './LocalState';

export { TypedDocumentNode } from '@graphql-typed-document-node/core';

export type Context = Record<string, any>;

export type QueryListener = (queryInfo: QueryInfo) => void;

export type OperationVariables = Record<string, any>;
Expand Down Expand Up @@ -44,6 +47,14 @@ export type MutationQueryReducersMap<T = { [key: string]: any }> = {
[queryName: string]: MutationQueryReducer<T>;
};

export type MutationUpdaterFunction<T extends Record<string, any>, TVariables, TContext> = (
cache: ApolloCache<T>,
result: Omit<FetchResult<T>, 'context'>,
options: {
context?: TContext,
variables?: TVariables,
},
) => void;
export interface Resolvers {
[key: string]: {
[ field: string ]: Resolver;
Expand Down
33 changes: 16 additions & 17 deletions src/core/watchQueryOptions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { DocumentNode } from 'graphql';
import { TypedDocumentNode } from '@graphql-typed-document-node/core';

import { ApolloCache } from '../cache';
import { FetchResult } from '../link/core';
import { MutationQueryReducersMap } from './types';
import { PureQueryOptions, OperationVariables } from './types';
import {
Context,
MutationQueryReducersMap,
PureQueryOptions,
OperationVariables,
MutationUpdaterFunction,
} from './types';

/**
* fetchPolicy determines where the client may return a result from. The options are:
Expand Down Expand Up @@ -170,8 +174,9 @@ export interface SubscriptionOptions<TVariables = OperationVariables, TData = an
export type RefetchQueryDescription = Array<string | PureQueryOptions>;

export interface MutationBaseOptions<
T = { [key: string]: any },
TVariables = OperationVariables
T,
TVariables,
TContext,
> {
/**
* An object that represents the result of this mutation that will be
Expand Down Expand Up @@ -230,7 +235,7 @@ export interface MutationBaseOptions<
* and you don't need to update the store, use the Promise returned from
* `client.mutate` instead.
*/
update?: MutationUpdaterFn<T>;
update?: MutationUpdaterFunction<T, TVariables, TContext>;

/**
* Specifies the {@link ErrorPolicy} to be used for this operation
Expand All @@ -245,9 +250,10 @@ export interface MutationBaseOptions<
}

export interface MutationOptions<
T = { [key: string]: any },
TVariables = OperationVariables
> extends MutationBaseOptions<T, TVariables> {
T,
TVariables extends OperationVariables,
TContext extends Context,
> extends MutationBaseOptions<T, TVariables, TContext> {
/**
* A GraphQL document, often created with `gql` from the `graphql-tag`
* package, that contains a single mutation inside of it.
Expand All @@ -264,7 +270,7 @@ export interface MutationOptions<
* [`query` `context` option](https://www.apollographql.com/docs/react/api/apollo-client#ApolloClient.query))
* when the query is first initialized/run.
*/
context?: any;
context?: TContext;

/**
* Specifies the {@link FetchPolicy} to be used for this query. Mutations only
Expand All @@ -274,10 +280,3 @@ export interface MutationOptions<
*/
fetchPolicy?: Extract<FetchPolicy, 'no-cache'>;
}

// Add a level of indirection for `typedoc`.
export type MutationUpdaterFn<T = { [key: string]: any }> = (
cache: ApolloCache<T>,
mutationResult: FetchResult<T>,
options?: any,
) => void;
24 changes: 13 additions & 11 deletions src/react/data/MutationData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import {
MutationResult,
} from '../types/types';
import { OperationData } from './OperationData';
import { OperationVariables, MutationOptions, mergeOptions } from '../../core';
import { MutationOptions, mergeOptions } from '../../core';
import { FetchResult } from '../../link/core';

type MutationResultWithoutClient<TData = any> = Omit<MutationResult<TData>, 'client'>;

export class MutationData<
TData = any,
TVariables = OperationVariables
> extends OperationData<MutationDataOptions<TData, TVariables>> {
TData,
TVariables,
TContext,
> extends OperationData<MutationDataOptions<TData, TVariables, TContext>> {
private mostRecentMutationId: number;
private result: MutationResultWithoutClient<TData>;
private previousResult?: MutationResultWithoutClient<TData>;
Expand All @@ -29,7 +30,7 @@ export class MutationData<
result,
setResult
}: {
options: MutationDataOptions<TData, TVariables>;
options: MutationDataOptions<TData, TVariables, TContext>;
context: any;
result: MutationResultWithoutClient<TData>;
setResult: (result: MutationResultWithoutClient<TData>) => any;
Expand All @@ -41,13 +42,13 @@ export class MutationData<
this.mostRecentMutationId = 0;
}

public execute(result: MutationResultWithoutClient<TData>): MutationTuple<TData, TVariables> {
public execute(result: MutationResultWithoutClient<TData>): MutationTuple<TData, TVariables, TContext> {
this.isMounted = true;
this.verifyDocumentType(this.getOptions().mutation, DocumentType.Mutation);
return [
this.runMutation,
{ ...result, client: this.refreshClient().client }
] as MutationTuple<TData, TVariables>;
] as MutationTuple<TData, TVariables, TContext>;
}

public afterExecute() {
Expand All @@ -62,8 +63,9 @@ export class MutationData<
private runMutation = (
mutationFunctionOptions: MutationFunctionOptions<
TData,
TVariables
> = {} as MutationFunctionOptions<TData, TVariables>
TVariables,
TContext
> = {} as MutationFunctionOptions<TData, TVariables, TContext>
) => {
this.onMutationStart();
const mutationId = this.generateNewMutationId();
Expand All @@ -80,12 +82,12 @@ export class MutationData<
};

private mutate(
options: MutationFunctionOptions<TData, TVariables>
options: MutationFunctionOptions<TData, TVariables, TContext>
) {
return this.refreshClient().client.mutate(
mergeOptions(
this.getOptions(),
options as MutationOptions<TData, TVariables>,
options as MutationOptions<TData, TVariables, TContext>,
),
);
}
Expand Down

0 comments on commit 90a9131

Please sign in to comment.