Skip to content

Commit

Permalink
Create exposed API for connection updates
Browse files Browse the repository at this point in the history
  • Loading branch information
bloodyowl committed Apr 6, 2024
1 parent f8e91d7 commit a0d4e1b
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 21 deletions.
28 changes: 28 additions & 0 deletions docs/docs/use-mutation.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ sidebar_label: useMutation
### Params

- `mutation`: your mutation document node
- `config`:
- `connectionUpdates`: configuration to prepend/append/remove edges from connections on mutation

### Returns

Expand Down Expand Up @@ -74,3 +76,29 @@ const UserPage = ({ userId }: Props) => {
);
};
```

## Handling connections

```ts
useMutation(BlockUser, {
connectionUpdates: [
({ data, append }) =>
Option.fromNullable(data.blockUser).map(({ user }) =>
append(blockedUsers, [user]),
),
({ data, prepend }) =>
Option.fromNullable(data.blockUser).map(({ user }) =>
prepend(lastBlockedUsers, [user]),
),
],
});

useMutation(Unfriend, {
connectionUpdates: [
({ variables, remove }) =>
Option.fromNullable(data.unfriend).map(() =>
remove(friends, [variables.id]),
),
],
});
```
78 changes: 61 additions & 17 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,50 @@ const defaultMakeRequest: MakeRequest = ({
);
};

type RequestOptions = { optimize?: boolean };
type ConnectionUpdate<Node> = [
Connection<Node>,
{ prepend: Edge<Node>[] } | { append: Edge<Node>[] } | { remove: string[] },
];

const prepend = <A>(
connection: Connection<A>,
edges: Edge<A>[],
): ConnectionUpdate<A> => {
return [connection, { prepend: edges }];
};

const append = <A>(
connection: Connection<A>,
edges: Edge<A>[],
): ConnectionUpdate<A> => {
return [connection, { append: edges }];
};

const remove = <A>(
connection: Connection<A>,
ids: string[],
): ConnectionUpdate<A> => {
return [connection, { remove: ids }];
};

export type GetConnectionUpdate<Data, Variables> = (config: {
data: Data;
variables: Variables;
prepend: <A>(
connection: Connection<A>,
edges: Edge<A>[],
) => ConnectionUpdate<A>;
append: <A>(
connection: Connection<A>,
edges: Edge<A>[],
) => ConnectionUpdate<A>;
remove: <A>(connection: Connection<A>, ids: string[]) => ConnectionUpdate<A>;
}) => Option<ConnectionUpdate<unknown>>;

type RequestOptions<Data, Variables> = {
optimize?: boolean;
connectionUpdates?: GetConnectionUpdate<Data, Variables>[] | undefined;
};

export class Client {
url: string;
Expand Down Expand Up @@ -122,7 +165,10 @@ export class Client {
request<Data, Variables>(
document: TypedDocumentNode<Data, Variables>,
variables: Variables,
{ optimize = false }: RequestOptions = {},
{
optimize = false,
connectionUpdates,
}: RequestOptions<Data, Variables> = {},
): Future<Result<Data, ClientError>> {
const transformedDocument = this.getTransformedDocument(document);
const transformedDocumentsForRequest =
Expand Down Expand Up @@ -170,6 +216,17 @@ export class Client {
variablesAsRecord,
);
})
.tapOk((data) => {
if (connectionUpdates !== undefined) {
connectionUpdates.forEach((getUpdate) => {
getUpdate({ data, variables, prepend, append, remove }).map(
([connection, update]) => {
this.cache.updateConnection(connection, update);
},
);
});
}
})
.tap((result) => {
this.cache.setOperationInCache(
transformedDocument,
Expand Down Expand Up @@ -205,29 +262,16 @@ export class Client {
query<Data, Variables>(
document: TypedDocumentNode<Data, Variables>,
variables: Variables,
requestOptions?: RequestOptions,
requestOptions?: RequestOptions<Data, Variables>,
) {
return this.request(document, variables, requestOptions);
}

commitMutation<Data, Variables>(
document: TypedDocumentNode<Data, Variables>,
variables: Variables,
requestOptions?: RequestOptions,
requestOptions?: RequestOptions<Data, Variables>,
) {
return this.request(document, variables, requestOptions);
}

updateConnection<A>(
connection: Connection<A>,
config:
| { prepend: Edge<A>[] }
| { append: Edge<A>[] }
| { remove: string[] },
) {
this.cache.updateConnection(connection, config);
this.subscribers.forEach((func) => {
func();
});
}
}
15 changes: 13 additions & 2 deletions src/react/useMutation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AsyncData, Future, Result } from "@swan-io/boxed";
import { useCallback, useContext, useState } from "react";
import { useCallback, useContext, useRef, useState } from "react";
import { GetConnectionUpdate } from "../client";
import { ClientError } from "../errors";
import { TypedDocumentNode } from "../types";
import { ClientContext } from "./ClientContext";
Expand All @@ -9,11 +10,19 @@ export type Mutation<Data, Variables> = readonly [
AsyncData<Result<Data, ClientError>>,
];

export type MutationConfig<Data, Variables> = {
connectionUpdates?: GetConnectionUpdate<Data, Variables>[] | undefined;
};

export const useMutation = <Data, Variables>(
mutation: TypedDocumentNode<Data, Variables>,
config: MutationConfig<Data, Variables> = {},
): Mutation<Data, Variables> => {
const client = useContext(ClientContext);

const connectionUpdatesRef = useRef(config?.connectionUpdates);
connectionUpdatesRef.current = config?.connectionUpdates;

const [stableMutation] =
useState<TypedDocumentNode<Data, Variables>>(mutation);

Expand All @@ -25,7 +34,9 @@ export const useMutation = <Data, Variables>(
(variables: Variables) => {
setData(AsyncData.Loading());
return client
.commitMutation(stableMutation, variables)
.commitMutation(stableMutation, variables, {
connectionUpdates: connectionUpdatesRef.current,
})
.tap((result) => setData(AsyncData.Done(result)));
},
[client, stableMutation],
Expand Down
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ export interface TypedDocumentNode<
DocumentTypeDecoration<TResult, TVariables> {}

export type Edge<T> = {
__typename?: string;
cursor?: string | null;
__typename?: string | null | undefined;
cursor?: string | null | undefined;
node?: T | null | undefined;
};

Expand Down

0 comments on commit a0d4e1b

Please sign in to comment.