Skip to content

Commit

Permalink
Merge branch '11554-fix-unbound-method-error-on-observablequery-metho…
Browse files Browse the repository at this point in the history
…ds' of github.com:apollographql/apollo-client into 11554-fix-unbound-method-error-on-observablequery-methods
  • Loading branch information
alessbell committed Feb 5, 2024
2 parents 556b085 + 9acdd5b commit 7804373
Show file tree
Hide file tree
Showing 14 changed files with 410 additions and 142 deletions.
2 changes: 2 additions & 0 deletions .api-reports/api-report-react.md
Original file line number Diff line number Diff line change
Expand Up @@ -2212,6 +2212,8 @@ export function useFragment<TData = any, TVars = OperationVariables>(options: Us

// @public (undocumented)
export interface UseFragmentOptions<TData, TVars> extends Omit<Cache_2.DiffOptions<NoInfer<TData>, NoInfer<TVars>>, "id" | "query" | "optimistic" | "previousResult" | "returnPartialData">, Omit<Cache_2.ReadFragmentOptions<TData, TVars>, "id" | "variables" | "returnPartialData"> {
// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@apollo/client" does not have an export "ApolloClient"
client?: ApolloClient<any>;
// (undocumented)
from: StoreObject | Reference | string;
// (undocumented)
Expand Down
2 changes: 2 additions & 0 deletions .api-reports/api-report-react_hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -2048,6 +2048,8 @@ export function useFragment<TData = any, TVars = OperationVariables>(options: Us

// @public (undocumented)
export interface UseFragmentOptions<TData, TVars> extends Omit<Cache_2.DiffOptions<NoInfer<TData>, NoInfer<TVars>>, "id" | "query" | "optimistic" | "previousResult" | "returnPartialData">, Omit<Cache_2.ReadFragmentOptions<TData, TVars>, "id" | "variables" | "returnPartialData"> {
// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@apollo/client" does not have an export "ApolloClient"
client?: ApolloClient<any>;
// (undocumented)
from: StoreObject | Reference | string;
// (undocumented)
Expand Down
1 change: 1 addition & 0 deletions .api-reports/api-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -2865,6 +2865,7 @@ export function useFragment<TData = any, TVars = OperationVariables>(options: Us

// @public (undocumented)
export interface UseFragmentOptions<TData, TVars> extends Omit<Cache_2.DiffOptions<NoInfer<TData>, NoInfer<TVars>>, "id" | "query" | "optimistic" | "previousResult" | "returnPartialData">, Omit<Cache_2.ReadFragmentOptions<TData, TVars>, "id" | "variables" | "returnPartialData"> {
client?: ApolloClient<any>;
// (undocumented)
from: StoreObject | Reference | string;
// (undocumented)
Expand Down
5 changes: 5 additions & 0 deletions .changeset/brave-cougars-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": patch
---

Allows passing in client via options to useFragment
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ jobs:
externalPackage:
type: string
docker:
- image: cimg/node:20.6.1
- image: cimg/node:21.6.1
steps:
- checkout
- attach_workspace:
Expand Down
2 changes: 1 addition & 1 deletion .size-limits.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"dist/apollo-client.min.cjs": 39061,
"dist/apollo-client.min.cjs": 39052,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32559
}
2 changes: 1 addition & 1 deletion netlify.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

[context.deploy-preview.build]
base = "docs"
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF"
ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ../src"
command = """\
npm i
npm run docmodel
Expand Down
408 changes: 285 additions & 123 deletions package-lock.json

Large diffs are not rendered by default.

24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"hoist-non-react-statics": "^3.3.2",
"optimism": "^0.18.0",
"prop-types": "^15.7.2",
"rehackt": "0.0.3",
"rehackt": "0.0.4",
"response-iterator": "^0.2.6",
"symbol-observable": "^4.0.0",
"ts-invariant": "^0.10.3",
Expand All @@ -116,28 +116,28 @@
"@rollup/plugin-node-resolve": "11.2.1",
"@size-limit/esbuild-why": "11.0.2",
"@size-limit/preset-small-lib": "11.0.2",
"@testing-library/jest-dom": "6.3.0",
"@testing-library/react": "14.1.2",
"@testing-library/jest-dom": "6.4.2",
"@testing-library/react": "14.2.1",
"@testing-library/react-12": "npm:@testing-library/react@^12",
"@testing-library/user-event": "14.5.2",
"@tsconfig/node20": "20.1.2",
"@types/bytes": "3.1.4",
"@types/fetch-mock": "7.3.8",
"@types/glob": "8.1.0",
"@types/hoist-non-react-statics": "3.3.5",
"@types/jest": "29.5.11",
"@types/jest": "29.5.12",
"@types/lodash": "4.14.202",
"@types/node": "20.11.10",
"@types/node": "20.11.16",
"@types/node-fetch": "2.6.11",
"@types/react": "18.2.48",
"@types/react": "18.2.54",
"@types/react-dom": "18.2.18",
"@types/relay-runtime": "14.1.14",
"@types/relay-runtime": "14.1.23",
"@types/use-sync-external-store": "0.0.6",
"@typescript-eslint/eslint-plugin": "6.19.1",
"@typescript-eslint/parser": "6.19.1",
"@typescript-eslint/rule-tester": "6.19.1",
"@typescript-eslint/types": "6.19.1",
"@typescript-eslint/utils": "6.19.1",
"@typescript-eslint/eslint-plugin": "6.20.0",
"@typescript-eslint/parser": "6.20.0",
"@typescript-eslint/rule-tester": "6.20.0",
"@typescript-eslint/types": "6.20.0",
"@typescript-eslint/utils": "6.20.0",
"acorn": "8.11.3",
"blob-polyfill": "7.0.20220408",
"bytes": "3.1.2",
Expand Down
37 changes: 36 additions & 1 deletion src/__tests__/mutationResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { cloneDeep } from "lodash";
import gql from "graphql-tag";
import { GraphQLError } from "graphql";

import { ApolloClient } from "../core";
import { ApolloClient, FetchResult } from "../core";
import { InMemoryCache } from "../cache";
import { ApolloLink } from "../link/core";
import {
Expand Down Expand Up @@ -1819,5 +1819,40 @@ describe("mutation results", () => {
}, reject);
}
);

itAsync(
"data might be undefined in case of failure with errorPolicy = ignore",
async (resolve, reject) => {
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new ApolloLink(
() =>
new Observable<FetchResult<{ foo: string }>>((observer) => {
observer.next({
errors: [new GraphQLError("Oops")],
});
observer.complete();
})
).setOnError(reject),
});

const ignoreErrorsResult = await client.mutate({
mutation: gql`
mutation Foo {
foo
}
`,
fetchPolicy: "no-cache",
errorPolicy: "ignore",
});

expect(ignoreErrorsResult).toEqual({
data: undefined,
errors: undefined,
});

resolve();
}
);
});
});
3 changes: 2 additions & 1 deletion src/core/ApolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,8 @@ export class ApolloClient<TCacheShape> implements DataProxy {
/**
* This resolves a single mutation according to the options specified and returns a
* Promise which is either resolved with the resulting data or rejected with an
* error.
* error. In some cases both `data` and `errors` might be undefined, for example
* when `errorPolicy` is set to `'ignore'`.
*
* It takes options as an object with the following keys and values:
*/
Expand Down
1 change: 1 addition & 0 deletions src/link/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export interface SingleExecutionResult<
TContext = DefaultContext,
TExtensions = Record<string, any>,
> extends ExecutionResult<TData, TExtensions> {
// data might be undefined if errorPolicy was set to 'ignore'
data?: TData | null;
context?: TContext;
}
Expand Down
50 changes: 50 additions & 0 deletions src/react/hooks/__tests__/useFragment.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,55 @@ describe("useFragment", () => {
screen.getByText(/Item #1/);
});

it("allows the client to be overriden", () => {
const ItemFragment: TypedDocumentNode<Item> = gql`
fragment ItemFragment on Item {
id
text
}
`;
const cache = new InMemoryCache();
const item = { __typename: "Item", id: 1, text: "Item #1" };
cache.writeFragment({
fragment: ItemFragment,
data: item,
});
const client = new ApolloClient({
cache,
});
function Component() {
const { data } = useFragment({
fragment: ItemFragment,
from: { __typename: "Item", id: 1 },
client,
});
return <>{data.text}</>;
}

// Without a MockedProvider supplying the client via context,
// the client must be passed directly to the hook or an error is thrown
expect(() => render(<Component />)).not.toThrow(/pass an ApolloClient/);

// Item #1 is rendered
screen.getByText(/Item #1/);
});

it("throws if no client is provided", () => {
function Component() {
const { data } = useFragment({
fragment: ItemFragment,
from: { __typename: "Item", id: 1 },
});
return <>{data.text}</>;
}

// silence the console error
{
using _spy = spyOnConsole("error");
expect(() => render(<Component />)).toThrow(/pass an ApolloClient/);
}
});

it.each<TypedDocumentNode<{ list: Item[] }>>([
// This query uses a basic field-level @nonreactive directive.
gql`
Expand Down Expand Up @@ -1721,6 +1770,7 @@ describe.skip("Type Tests", () => {
optimistic?: boolean;
variables?: TVars;
canonizeResults?: boolean;
client?: ApolloClient<any>;
}>();
});
});
13 changes: 11 additions & 2 deletions src/react/hooks/useFragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {

import { useApolloClient } from "./useApolloClient.js";
import { useSyncExternalStore } from "./useSyncExternalStore.js";
import type { OperationVariables } from "../../core/index.js";
import type { ApolloClient, OperationVariables } from "../../core/index.js";
import type { NoInfer } from "../types/types.js";
import { useDeepMemo, useLazyRef } from "./internal/index.js";

Expand All @@ -28,6 +28,15 @@ export interface UseFragmentOptions<TData, TVars>
from: StoreObject | Reference | string;
// Override this field to make it optional (default: true).
optimistic?: boolean;
/**
* The instance of {@link ApolloClient} to use to look up the fragment.
*
* By default, the instance that's passed down via context is used, but you
* can provide a different instance here.
*
* @docGroup 1. Operation options
*/
client?: ApolloClient<any>;
}

export type UseFragmentResult<TData> =
Expand All @@ -45,7 +54,7 @@ export type UseFragmentResult<TData> =
export function useFragment<TData = any, TVars = OperationVariables>(
options: UseFragmentOptions<TData, TVars>
): UseFragmentResult<TData> {
const { cache } = useApolloClient();
const { cache } = useApolloClient(options.client);

const diffOptions = useDeepMemo<Cache.DiffOptions<TData, TVars>>(() => {
const {
Expand Down

0 comments on commit 7804373

Please sign in to comment.