Skip to content

Commit

Permalink
Merge pull request #7015 from apollographql/release-3.3
Browse files Browse the repository at this point in the history
Release 3.3.0
  • Loading branch information
benjamn committed Nov 24, 2020
2 parents 62c81ff + 0b66021 commit 29d41eb
Show file tree
Hide file tree
Showing 64 changed files with 4,281 additions and 942 deletions.
89 changes: 89 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,92 @@
## Apollo Client 3.3.0

## Bug Fixes

- Update `@wry/equality` to consider undefined properties equivalent to missing properties. <br/>
[@benjamn](https://github.com/benjamn) in [#7108](https://github.com/apollographql/apollo-client/pull/7108)

- Prevent memory leaks involving unused `onBroadcast` function closure created in `ApolloClient` constructor. <br/>
[@kamilkisiela](https://github.com/kamilkisiela) in [#7161](https://github.com/apollographql/apollo-client/pull/7161)

- Provide default empty cache object for root IDs like `ROOT_QUERY`, to avoid differences in behavior before/after `ROOT_QUERY` data has been written into `InMemoryCache`. <br/>
[@benjamn](https://github.com/benjamn) in [#7100](https://github.com/apollographql/apollo-client/pull/7100)

- Cancel `queryInfo.notifyTimeout` in `QueryInfo#markResult` to prevent unnecessary network requests when using a `FetchPolicy` of `cache-and-network` or `network-only` in a React component with multiple `useQuery` calls. <br/>
[@benjamn](https://github.com/benjamn) in [#7347](https://github.com/apollographql/apollo-client/pull/7347)

## Potentially breaking changes

- Ensure `cache.readQuery` and `cache.readFragment` always return `TData | null`, instead of throwing `MissingFieldError` exceptions when missing fields are encountered. <br/>
[@benjamn](https://github.com/benjamn) in [#7098](https://github.com/apollographql/apollo-client/pull/7098)
> Since this change converts prior exceptions to `null` returns, and since `null` was already a possible return value according to the `TData | null` return type, we are confident this change will be backwards compatible (as long as `null` was properly handled before).
- `HttpLink` will now automatically strip any unused `variables` before sending queries to the GraphQL server, since those queries are very likely to fail validation, according to the [All Variables Used](https://spec.graphql.org/draft/#sec-All-Variables-Used) rule in the GraphQL specification. If you depend on the preservation of unused variables, you can restore the previous behavior by passing `includeUnusedVariables: true` to the `HttpLink` constructor (which is typically passed as `options.link` to the `ApolloClient` constructor). <br/>
[@benjamn](https://github.com/benjamn) in [#7127](https://github.com/apollographql/apollo-client/pull/7127)

- Ensure `MockLink` (used by `MockedProvider`) returns mock configuration errors (e.g. `No more mocked responses for the query ...`) through the Link's `Observable`, instead of throwing them. These errors are now available through the `error` property of a result. <br/>
[@hwillson](https://github.com/hwillson) in [#7110](https://github.com/apollographql/apollo-client/pull/7110)
> Returning mock configuration errors through the Link's `Observable` was the default behavior in Apollo Client 2.x. We changed it for 3, but the change has been problematic for those looking to migrate from 2.x to 3. We've decided to change this back with the understanding that not many people want or are relying on `MockLink`'s throwing exception approach. If you want to change this functionality, you can define custom error handling through `MockLink.setOnError`.
- Unsubscribing the last observer from an `ObservableQuery` will once again unsubscribe from the underlying network `Observable` in all cases, as in Apollo Client 2.x, allowing network requests to be cancelled by unsubscribing. <br/>
[@javier-garcia-meteologica](https://github.com/javier-garcia-meteologica) in [#7165](https://github.com/apollographql/apollo-client/pull/7165) and [#7170](https://github.com/apollographql/apollo-client/pull/7170).

- The independent `QueryBaseOptions` and `ModifiableWatchQueryOptions` interface supertypes have been eliminated, and their fields are now defined by `QueryOptions`. <br/>
[@DCtheTall](https://github.com/DCtheTall) in [#7136](https://github.com/apollographql/apollo-client/pull/7136)

- Internally, Apollo Client now avoids nested imports from the `graphql` package, importing everything from the top-level package instead. For example,
```ts
import { visit } from "graphql/language/visitor"
```
is now just
```ts
import { visit } from "graphql"
```
Since the `graphql` package uses `.mjs` modules, your bundler may need to be configured to recognize `.mjs` files as ECMAScript modules rather than CommonJS modules. <br/>
[@benjamn](https://github.com/benjamn) in [#7185](https://github.com/apollographql/apollo-client/pull/7185)

## Improvements

- Support inheritance of type and field policies, according to `possibleTypes`. <br/>
[@benjamn](https://github.com/benjamn) in [#7065](https://github.com/apollographql/apollo-client/pull/7065)

- Allow configuring custom `merge` functions, including the `merge: true` and `merge: false` shorthands, in type policies as well as field policies. <br/>
[@benjamn](https://github.com/benjamn) in [#7070](https://github.com/apollographql/apollo-client/pull/7070)

- The verbosity of Apollo Client console messages can be globally adjusted using the `setLogVerbosity` function:
```ts
import { setLogVerbosity } from "@apollo/client";
setLogVerbosity("log"); // display all messages
setLogVerbosity("warn"); // display only warnings and errors (default)
setLogVerbosity("error"); // display only errors
setLogVerbosity("silent"); // hide all console messages
```
Remember that all logs, warnings, and errors are hidden in production. <br/>
[@benjamn](https://github.com/benjamn) in [#7226](https://github.com/apollographql/apollo-client/pull/7226)

- Modifying `InMemoryCache` fields that have `keyArgs` configured will now invalidate only the field value with matching key arguments, rather than invalidating all field values that share the same field name. If `keyArgs` has not been configured, the cache must err on the side of invalidating by field name, as before. <br/>
[@benjamn](https://github.com/benjamn) in [#7351](https://github.com/apollographql/apollo-client/pull/7351)

- Shallow-merge `options.variables` when combining existing or default options with newly-provided options, so new variables do not completely overwrite existing variables. <br/>
[@amannn](https://github.com/amannn) in [#6927](https://github.com/apollographql/apollo-client/pull/6927)

- Avoid displaying `Cache data may be lost...` warnings for scalar field values that happen to be objects, such as JSON data. <br/>
[@benjamn](https://github.com/benjamn) in [#7075](https://github.com/apollographql/apollo-client/pull/7075)

- In addition to the `result.data` property, `useQuery` and `useLazyQuery` will now provide a `result.previousData` property, which can be useful when a network request is pending and `result.data` is undefined, since `result.previousData` can be rendered instead of rendering an empty/loading state. <br/>
[@hwillson](https://github.com/hwillson) in [#7082](https://github.com/apollographql/apollo-client/pull/7082)

- Passing `validate: true` to the `SchemaLink` constructor will enable validation of incoming queries against the local schema before execution, returning validation errors in `result.errors`, just like a non-local GraphQL endpoint typically would. <br/>
[@amannn](https://github.com/amannn) in [#7094](https://github.com/apollographql/apollo-client/pull/7094)

- Allow optional arguments in `keyArgs: [...]` arrays for `InMemoryCache` field policies. <br/>
[@benjamn](https://github.com/benjamn) in [#7109](https://github.com/apollographql/apollo-client/pull/7109)

- Avoid registering `QueryPromise` when `skip` is `true` during server-side rendering. <br/>
[@izumin5210](https://github.com/izumin5210) in [#7310](https://github.com/apollographql/apollo-client/pull/7310)

- `ApolloCache` objects (including `InMemoryCache`) may now be associated with or disassociated from individual reactive variables by calling `reactiveVar.attachCache(cache)` and/or `reactiveVar.forgetCache(cache)`. <br/>
[@benjamn](https://github.com/benjamn) in [#7350](https://github.com/apollographql/apollo-client/pull/7350)

## Apollo Client 3.2.8

## Bug Fixes
Expand Down
5 changes: 3 additions & 2 deletions docs/shared/query-result.mdx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
| Property | Type | Description |
| - | - | - |
| `data` | TData | An object containing the result of your GraphQL query. Defaults to `undefined`. |
| `previousData` | TData | An object containing the previous result of your GraphQL query (the last result before a new `data` value was set). Defaults to `undefined`. |
| `loading` | boolean | A boolean that indicates whether the request is in flight |
| `error` | ApolloError | A runtime error with `graphQLErrors` and `networkError` properties |
| `variables` | { [key: string]: any } | An object containing the variables the query was called with |
| `networkStatus` | NetworkStatus | A number from 1-8 (1 = `loading`, 2 = `setVariables`, 3 = `fetchMore`, 4 = `refetch`, 6 = `poll`, 7 = `ready`, 8 = `error`) corresponding to the detailed state of your network request. Includes information about refetching and polling status. Used in conjunction with the `notifyOnNetworkStatusChange` prop. |
| `refetch` | (variables?: Partial&lt;TVariables&gt;) => Promise&lt;ApolloQueryResult&gt; | A function that allows you to refetch the query and optionally pass in new variables |
| `fetchMore` | ({ query?: DocumentNode, variables?: TVariables, updateQuery: Function}) => Promise&lt;ApolloQueryResult&gt; | A function that enables [pagination](/features/pagination/) for your query |
| `fetchMore` | ({ query?: DocumentNode, variables?: TVariables, updateQuery: Function}) => Promise&lt;ApolloQueryResult&gt; | A function that enables [pagination](../../pagination/overview) for your query |
| `startPolling` | (interval: number) => void | This function sets up an interval in ms and fetches the query each time the specified interval passes. |
| `stopPolling` | () => void | This function stops the query from polling. |
| `subscribeToMore` | (options: { document: DocumentNode, variables?: TVariables, updateQuery?: Function, onError?: Function}) => () => void | A function that sets up a [subscription](/data/subscriptions/). `subscribeToMore` returns a function that you can use to unsubscribe. |
| `subscribeToMore` | (options: { document: DocumentNode, variables?: TVariables, updateQuery?: Function, onError?: Function}) => () => void | A function that sets up a [subscription](../../data/subscriptions/). `subscribeToMore` returns a function that you can use to unsubscribe. |
| `updateQuery` | (previousResult: TData, options: { variables: TVariables }) => TData | A function that allows you to update the query's result in the cache outside the context of a fetch, mutation, or subscription |
| `client` | ApolloClient | Your `ApolloClient` instance. Useful for manually firing queries or writing data to the cache. |
| `called` | boolean | A boolean indicating if the query function has been called, used by `useLazyQuery` (not set for `useQuery` / `Query`). |
27 changes: 27 additions & 0 deletions docs/source/caching/cache-field-behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,33 @@ const cache = new InMemoryCache({

In summary, the `Book.author` policy above allows the cache to safely merge the `author` objects of any two `Book` objects that have the same identity.

#### Configuring `merge` functions for types rather than fields

Beginning with Apollo Client 3.3, you can avoid having to configure `merge` functions for lots of different fields that might hold an `Author` object, and instead put the `merge` configuration in the `Author` type policy:

```ts{13}
const cache = new InMemoryCache({
typePolicies: {
Book: {
fields: {
// No longer necessary!
// author: {
// merge: true,
// },
},
},
Author: {
merge: true,
},
},
});
```

These configurations have the same behavior, but putting the `merge: true` in the `Author` type policy is shorter and easier to maintain, especially when `Author` objects could appear in lots of different fields besides `Book.author`.

Remember that mergeable objects will only be merged with existing objects occupying the same field of the same parent object, and only when the `__typename` of the objects is the same. If you really need to work around these rules, you can write a custom `merge` function to do whatever you want, but `merge: true` follows these rules.

### Merging arrays of non-normalized objects

Once you're comfortable with the ideas and recommendations from the previous section, consider what happens when a `Book` can have multiple authors:
Expand Down
13 changes: 6 additions & 7 deletions docs/source/caching/cache-interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ All code samples below assume that you have initialized an instance of `ApolloC

The `readQuery` method enables you to run a GraphQL query directly on your cache.

* If your cache contains all of the data necessary to fulfill a specified query, `readQuery` returns a data object in the shape of that query, just like a GraphQL server does.
* If your cache contains all of the data necessary to fulfill the specified query, `readQuery` returns a data object in the shape of that query, just like a GraphQL server does.

* If your cache _doesn't_ contain all of the data necessary to fulfill a specified query, `readQuery` throws an error. It _never_ attempts to fetch data from a remote server.
* If your cache does not contain all of the data necessary to fulfill the specified query, `readQuery` returns `null`, without attempting to fetch data from a remote server.

> Prior to Apollo Client 3.3, `readQuery` would throw `MissingFieldError` exceptions to report missing fields. Beginning with Apollo Client 3.3, `readQuery` always returns `null` to indicate fields were missing.
Pass `readQuery` a GraphQL query string like so:

Expand Down Expand Up @@ -81,12 +83,9 @@ const todo = client.readFragment({

The first argument, `id`, is the value of the unique identifier for the object you want to read from the cache. By default, this is the value of the object's `id` field, but you can [customize this behavior](./cache-configuration/#generating-unique-identifiers).

In the example above:
In the example above, `readFragment` returns `null` if no `Todo` object with an `id` of `5` exists in the cache, or if the object exists but is missing the `text` or `completed` fields.

* If a `Todo` object with an `id` of `5` is _not_ in the cache,
`readFragment` returns `null`.
* If the `Todo` object _is_ in the cache but it's
missing either a `text` or `completed` field, `readFragment` throws an error.
> Prior to Apollo Client 3.3, `readFragment` would throw `MissingFieldError` exceptions to report missing fields, and return `null` only when reading a fragment from a nonexistent ID. Beginning with Apollo Client 3.3, `readFragment` always returns `null` to indicate insufficient data (missing ID or missing fields), instead of throwing a `MissingFieldError`.
## `writeQuery` and `writeFragment`

Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apollo/client",
"version": "3.2.8",
"version": "3.3.0",
"description": "A fully-featured caching GraphQL client.",
"private": true,
"keywords": [
Expand Down Expand Up @@ -48,13 +48,13 @@
"coverage": "jest --config ./config/jest.config.js --verbose --coverage",
"bundlesize": "npm run build && bundlesize",
"predeploy": "npm run build",
"deploy": "cd dist && npm publish"
"deploy": "cd dist && npm publish --tag next"
},
"bundlesize": [
{
"name": "apollo-client",
"path": "./dist/apollo-client.cjs.min.js",
"maxSize": "24.75 kB"
"maxSize": "25.5 kB"
}
],
"peerDependencies": {
Expand All @@ -74,14 +74,14 @@
"@graphql-typed-document-node/core": "^3.0.0",
"@types/zen-observable": "^0.8.0",
"@wry/context": "^0.5.2",
"@wry/equality": "^0.2.0",
"@wry/equality": "^0.3.0",
"fast-json-stable-stringify": "^2.0.0",
"graphql-tag": "^2.11.0",
"hoist-non-react-statics": "^3.3.2",
"optimism": "^0.13.0",
"optimism": "^0.13.1",
"prop-types": "^15.7.2",
"symbol-observable": "^2.0.0",
"ts-invariant": "^0.5.0",
"ts-invariant": "^0.5.1",
"tslib": "^1.10.0",
"zen-observable": "^0.8.14"
},
Expand Down
23 changes: 23 additions & 0 deletions src/__tests__/ApolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,9 @@ describe('ApolloClient', () => {
});

expect((client.cache as InMemoryCache).extract()).toEqual({
__META: {
extraRootIds: ['foo'],
},
foo: {
__typename: 'Foo',
'field({"literal":true,"value":42})': 1,
Expand Down Expand Up @@ -2287,6 +2290,26 @@ describe('ApolloClient', () => {

client.stop();
});

it('should be able to set all default query options', () => {
new ApolloClient({
link: ApolloLink.empty(),
cache: new InMemoryCache(),
defaultOptions: {
query: {
query: {kind: 'Document', definitions: []},
variables: {foo: 'bar'},
errorPolicy: 'none',
context: null,
fetchPolicy: 'cache-first',
pollInterval: 100,
notifyOnNetworkStatusChange: true,
returnPartialData: true,
partialRefetch: true,
},
},
});
});
});

describe('clearStore', () => {
Expand Down

0 comments on commit 29d41eb

Please sign in to comment.