types: strict tsconfig and @apollo/client v3 docs (#1062)
This commit is contained in:
@@ -23,7 +23,7 @@ A clear and concise description of what you expected to happen.
|
||||
**Versions**
|
||||
vue:
|
||||
vue-apollo:
|
||||
apollo-client:
|
||||
@apollo/client:
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
@@ -137,9 +137,7 @@ Here is an example:
|
||||
// apollo.js
|
||||
|
||||
import Vue from 'vue'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core'
|
||||
import VueApollo from '@vue/apollo-option'
|
||||
|
||||
// Install the vue plugin
|
||||
|
||||
@@ -55,10 +55,10 @@ export default {
|
||||
|
||||
## Network Errors
|
||||
|
||||
When using Apollo Link, the ability to handle network errors is way more powerful. The best way to do this is to use the `apollo-link-error` to catch and handle server errors, network errors, and GraphQL errors. If you would like to combine with other links, see [composing links](https://www.apollographql.com/docs/link/composition).
|
||||
When using Apollo Link, the ability to handle network errors is way more powerful. The best way to do this is to use the `@apollo/client/link/error` to catch and handle server errors, network errors, and GraphQL errors. If you would like to combine with other links, see [composing links](https://www.apollographql.com/docs/link/composition).
|
||||
|
||||
```js
|
||||
import { onError } from 'apollo-link-error'
|
||||
import { onError } from '@apollo/client/link/error'
|
||||
|
||||
const link = onError(({ graphQLErrors, networkError }) => {
|
||||
if (graphQLErrors)
|
||||
@@ -75,7 +75,7 @@ const link = onError(({ graphQLErrors, networkError }) => {
|
||||
You can also use the `logErrorMessages` function from the `@vue/apollo-util` package to format the error in the browser console:
|
||||
|
||||
```js
|
||||
import { onError } from 'apollo-link-error'
|
||||
import { onError } from '@apollo/client/link/error'
|
||||
import { logErrorMessages } from '@vue/apollo-util'
|
||||
|
||||
const link = onError(error => {
|
||||
@@ -90,7 +90,7 @@ Example error:
|
||||
If you are using Webpack or Vue CLI, it's a good idea to only use it in development:
|
||||
|
||||
```js
|
||||
import { onError } from 'apollo-link-error'
|
||||
import { onError } from '@apollo/client/link/error'
|
||||
import { logErrorMessages } from '@vue/apollo-util'
|
||||
|
||||
const link = onError(error => {
|
||||
@@ -121,4 +121,4 @@ onError(({ response, operation }) => {
|
||||
response.errors = null
|
||||
}
|
||||
})
|
||||
```
|
||||
```
|
||||
|
||||
@@ -203,105 +203,27 @@ query {
|
||||
}
|
||||
```
|
||||
|
||||
In the query above, `allPeople` returns a result of type `Character[]`. Both `Jedi` and `Droid` are possible concrete types of `Character`, but on the client there is no way to know that without having some information about the schema. By default, Apollo Client's cache will use a heuristic fragment matcher, which assumes that a fragment matched if the result included all the fields in its selection set, and didn't match when any field was missing. This works in most cases, but it also means that Apollo Client cannot check the server response for you, and it cannot tell you when you're manually writing invalid data into the store using `update`, `updateQuery`, `writeQuery`, etc. Also, the heuristic fragment matcher will not work accurately when using fragments with unions or interfaces. Apollo Client will let you know this with a console warning (in development), if it attempts to use the default heuristic fragment matcher with unions/interfaces. The `IntrospectionFragmentMatcher` is the solution for working with unions/interfaces, and is explained in more detail below.
|
||||
In the query above, `allPeople` returns a result of type `Character[]`. Both `Jedi` and `Droid` are possible concrete types of `Character`, but on the client there is no way to know that without having some information about the schema. By default, Apollo Client's cache will use a heuristic fragment matcher, which assumes that a fragment matched if the result included all the fields in its selection set, and didn't match when any field was missing. This works in most cases, but it also means that Apollo Client cannot check the server response for you, and it cannot tell you when you're manually writing invalid data into the store using `update`, `updateQuery`, `writeQuery`, etc. To inform the cache store about these polymorphic relationships, you need to pass `possibleTypes` option to `InMemoryCache` below.
|
||||
|
||||
The section below explains how to pass the necessary schema knowledge to the Apollo Client cache so unions and interfaces can be accurately matched and results validated before writing them into the store.
|
||||
|
||||
To support result validation and accurate fragment matching on unions and interfaces, a special fragment matcher called the `IntrospectionFragmentMatcher` can be used. If there are any changes related to union or interface types in your schema, you will have to update the fragment matcher accordingly.
|
||||
|
||||
We recommend setting up a build step that extracts the necessary information from the schema into a JSON file, where it can be imported from when constructing the fragment matcher. To set it up, follow the three steps below:
|
||||
We recommend setting up a build step that extracts the necessary information from the schema into a JSON file, where it can be imported from when constructing the cache. To set it up, follow the steps below:
|
||||
|
||||
1. Query your server / schema to obtain the necessary information about unions and interfaces and write it to a file.
|
||||
|
||||
You can automate this or set this as a script to run at build time.
|
||||
Read the documentation about how to [extract possibleTypes automatically](https://www.apollographql.com/docs/react/data/fragments/#generating-possibletypes-automatically) using an introspection query. Or use the plugin [fragment-matcher](https://graphql-code-generator.com/docs/plugins/fragment-matcher) for graphql-codegen and configure it for [apollo client 3](https://graphql-code-generator.com/docs/plugins/fragment-matcher#usage-with-apollo-client-3).
|
||||
|
||||
If you want to auto-generate the introspection result, there's a tool called [GraphQL Code Generator](https://graphql-code-generator.com) that does it. Define where your GraphQL Schema is available and where to write the file:
|
||||
|
||||
```yaml
|
||||
# codegen.yml
|
||||
schema: YOUR_API
|
||||
overwrite: true
|
||||
generates:
|
||||
./fragmentTypes.json:
|
||||
plugins:
|
||||
- fragment-matcher
|
||||
```
|
||||
|
||||
With all of that, you simply run:
|
||||
|
||||
```shell
|
||||
gql-gen
|
||||
```
|
||||
|
||||
> To learn more, you can read the ["Fragment Matcher" chapter](https://graphql-code-generator.com/docs/plugins/fragment-matcher).
|
||||
|
||||
In order to introspect the server manually, set this as a script to run at build time.
|
||||
2. Use `possibleTypes.json` to configure your cache during construction. Then, you pass your newly configured cache to `ApolloClient` to complete the process.
|
||||
|
||||
```js
|
||||
const fetch = require('node-fetch')
|
||||
const fs = require('fs')
|
||||
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client/core'
|
||||
import possibleTypes from './possibleTypes.json'
|
||||
|
||||
fetch(`${YOUR_API_HOST}/graphql`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
variables: {},
|
||||
query: `
|
||||
{
|
||||
__schema {
|
||||
types {
|
||||
kind
|
||||
name
|
||||
possibleTypes {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
}),
|
||||
})
|
||||
.then(result => result.json())
|
||||
.then(result => {
|
||||
// here we're filtering out any type information unrelated to unions or interfaces
|
||||
const filteredData = result.data.__schema.types.filter(
|
||||
type => type.possibleTypes !== null,
|
||||
)
|
||||
result.data.__schema.types = filteredData
|
||||
fs.writeFile('./fragmentTypes.json', JSON.stringify(result.data), err => {
|
||||
if (err) {
|
||||
console.error('Error writing fragmentTypes file', err)
|
||||
} else {
|
||||
console.log('Fragment types successfully extracted!')
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
2. Create a new IntrospectionFragment matcher by passing in the `fragmentTypes.json` file you just created. You'll want to do this in the same file where you initialize the cache for Apollo Client.
|
||||
|
||||
```js
|
||||
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'
|
||||
import introspectionQueryResultData from './fragmentTypes.json'
|
||||
|
||||
const fragmentMatcher = new IntrospectionFragmentMatcher({
|
||||
introspectionQueryResultData
|
||||
})
|
||||
```
|
||||
|
||||
3. Pass in the newly created `IntrospectionFragmentMatcher` to configure your cache during construction. Then, you pass your newly configured cache to `ApolloClient` to complete the process.
|
||||
|
||||
```js
|
||||
import ApolloClient from 'apollo-client'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
|
||||
// add fragmentMatcher code from step 2 here
|
||||
|
||||
const cache = new InMemoryCache({ fragmentMatcher })
|
||||
const cache = new InMemoryCache({ possibleTypes })
|
||||
const httpLink = createHttpLink({ uri });
|
||||
|
||||
const client = new ApolloClient({
|
||||
cache,
|
||||
link: new HttpLink(),
|
||||
link: httpLink,
|
||||
})
|
||||
```
|
||||
|
||||
@@ -53,26 +53,14 @@ A future version of Apollo or GraphQL might include support for live queries, wh
|
||||
|
||||
## Client setup
|
||||
|
||||
The most popular transport for GraphQL subscriptions today is [`subscriptions-transport-ws`](https://github.com/apollographql/subscriptions-transport-ws). This package is maintained by the Apollo community, but can be used with any client or server GraphQL implementation. In this article, we'll explain how to set it up on the client, but you'll also need a server implementation. You can [read about how to use subscriptions with a JavaScript server](https://www.apollographql.com/docs/graphql-subscriptions/setup), or enjoy subscriptions set up out of the box if you are using a GraphQL backend as a service like [Graphcool](https://www.graph.cool/docs/tutorials/worldchat-subscriptions-example-ui0eizishe/).
|
||||
In this article, we'll explain how to set it up on the client, but you'll also need a server implementation. You can [read about how to use subscriptions with a JavaScript server](https://www.apollographql.com/docs/graphql-subscriptions/setup), or enjoy subscriptions set up out of the box if you are using a GraphQL backend as a service like [Graphcool](https://www.graph.cool/docs/tutorials/worldchat-subscriptions-example-ui0eizishe/).
|
||||
|
||||
Let's look at how to add support for this transport to Apollo Client.
|
||||
|
||||
First, install the WebSocket Apollo Link (`apollo-link-ws`) from npm:
|
||||
|
||||
```shell
|
||||
npm install --save apollo-link-ws subscriptions-transport-ws
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```shell
|
||||
yarn add apollo-link-ws subscriptions-transport-ws
|
||||
```
|
||||
|
||||
Then, initialize a GraphQL subscriptions transport link:
|
||||
First, initialize a GraphQL web socket link:
|
||||
|
||||
```js
|
||||
import { WebSocketLink } from "apollo-link-ws";
|
||||
import { WebSocketLink } from "@apollo/client/link/ws";
|
||||
|
||||
const wsLink = new WebSocketLink({
|
||||
uri: `ws://localhost:5000/`,
|
||||
@@ -85,10 +73,9 @@ const wsLink = new WebSocketLink({
|
||||
We need to either use the `WebSocketLink` or the `HttpLink` depending on the operation type:
|
||||
|
||||
```js
|
||||
import { split } from "apollo-link";
|
||||
import { HttpLink } from "apollo-link-http";
|
||||
import { WebSocketLink } from "apollo-link-ws";
|
||||
import { getMainDefinition } from "apollo-utilities";
|
||||
import { HttpLink, split } from "@apollo/client/core";
|
||||
import { WebSocketLink } from "@apollo/client/link/ws";
|
||||
import { getMainDefinition } from "@apollo/client/utilities";
|
||||
|
||||
// Create an http link:
|
||||
const httpLink = new HttpLink({
|
||||
@@ -569,7 +556,7 @@ subscribeToMore(() => ({
|
||||
In many cases it is necessary to authenticate clients before allowing them to receive subscription results. To do this, the `SubscriptionClient` constructor accepts a `connectionParams` field, which passes a custom object that the server can use to validate the connection before setting up any subscriptions.
|
||||
|
||||
```js
|
||||
import { WebSocketLink } from 'apollo-link-ws';
|
||||
import { WebSocketLink } from "@apollo/client/link/ws";
|
||||
|
||||
const wsLink = new WebSocketLink({
|
||||
uri: `ws://localhost:5000/`,
|
||||
|
||||
@@ -4,21 +4,11 @@
|
||||
|
||||
*For the server implementation, you can take a look at [this simple example](https://github.com/Akryum/apollo-server-example).*
|
||||
|
||||
To enable the websocket-based subscription, a bit of additional setup is required:
|
||||
|
||||
```
|
||||
npm install --save apollo-link-ws apollo-utilities
|
||||
```
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
// New Imports
|
||||
import { split } from 'apollo-link'
|
||||
import { WebSocketLink } from 'apollo-link-ws'
|
||||
import { getMainDefinition } from 'apollo-utilities'
|
||||
import { ApolloClient, HttpLink, InMemoryCache, split } from '@apollo/client/core'
|
||||
import { WebSocketLink } from '@apollo/client/link/ws'
|
||||
import { getMainDefinition } from '@apollo/client/utilities'
|
||||
|
||||
import VueApollo from '@vue/apollo-option'
|
||||
|
||||
|
||||
@@ -16,55 +16,20 @@ Then you can skip to next section: [Basic Usage](./apollo/).
|
||||
|
||||
## Manual installation
|
||||
|
||||
You can either use [Apollo Boost](#apollo-boost) or [Apollo Client directly](#apollo-client-full-configuration) (more configuration work).
|
||||
|
||||
### Apollo Boost
|
||||
|
||||
Apollo Boost is a zero-config way to start using Apollo Client. It includes some sensible defaults, such as our recommended `InMemoryCache` and `HttpLink`, which come configured for you with our recommended settings and it's perfect for starting to develop fast.
|
||||
|
||||
Install it alongside `vue-apollo` and `graphql`:
|
||||
|
||||
```shell
|
||||
npm install --save graphql apollo-boost
|
||||
npm install --save graphql graphql-tag @apollo/client
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```shell
|
||||
yarn add graphql apollo-boost
|
||||
yarn add graphql graphql-tag @apollo/client
|
||||
```
|
||||
|
||||
In your app, create an `ApolloClient` instance:
|
||||
|
||||
```js
|
||||
import ApolloClient from 'apollo-boost'
|
||||
|
||||
const apolloClient = new ApolloClient({
|
||||
// You should use an absolute URL here
|
||||
uri: 'https://api.graphcms.com/simple/v1/awesomeTalksClone'
|
||||
})
|
||||
```
|
||||
|
||||
### Apollo client full configuration
|
||||
|
||||
If you want some more fine grained control install these packages instead of apollo-boost:
|
||||
|
||||
```shell
|
||||
npm install --save graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```shell
|
||||
yarn add graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
|
||||
```
|
||||
|
||||
In your app, create an `ApolloClient` instance:
|
||||
|
||||
```js
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { createHttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client/core'
|
||||
|
||||
// HTTP connection to the API
|
||||
const httpLink = createHttpLink({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# From vue-apollo 2 and Apollo 1
|
||||
# From vue-apollo 3
|
||||
|
||||
The main changes are related to the apollo client setup. Your components code shouldn't be affected. Apollo now uses a more flexible [apollo-link](https://github.com/apollographql/apollo-link) system that allows compositing multiple links together to add more features (like batching, offline support and more).
|
||||
|
||||
@@ -9,13 +9,13 @@ The main changes are related to the apollo client setup. Your components code sh
|
||||
Before:
|
||||
|
||||
```
|
||||
npm install --save vue-apollo apollo-client
|
||||
npm install --save vue-apollo@next graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
npm install --save vue-apollo@next graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
|
||||
npm install --save vue-apollo@next @apollo/client
|
||||
```
|
||||
|
||||
### Imports
|
||||
@@ -24,7 +24,9 @@ Before:
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import { ApolloClient, createBatchingNetworkInterface } from 'apollo-client'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import VueApollo from '@vue/apollo-option'
|
||||
```
|
||||
|
||||
@@ -32,9 +34,7 @@ After:
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core'
|
||||
import VueApollo from '@vue/apollo-option'
|
||||
```
|
||||
|
||||
@@ -168,29 +168,31 @@ Query reducers have been removed. Use the `update` API to update the cache now.
|
||||
Before:
|
||||
|
||||
```
|
||||
npm install --save subscriptions-transport-ws
|
||||
npm install --save apollo-link-ws apollo-utilities
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
npm install --save apollo-link-ws apollo-utilities
|
||||
npm install --save @apollo/client
|
||||
```
|
||||
|
||||
### Imports
|
||||
|
||||
Before:
|
||||
|
||||
```js
|
||||
import { SubscriptionClient, addGraphQLSubscriptions } from 'subscriptions-transport-ws'
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```js
|
||||
import { split } from 'apollo-link'
|
||||
import { WebSocketLink } from 'apollo-link-ws'
|
||||
import { getMainDefinition } from 'apollo-utilities'
|
||||
```
|
||||
|
||||
Learn more at the [official apollo documentation](https://www.apollographql.com/docs/react/2.0-migration.html).
|
||||
After:
|
||||
|
||||
```js
|
||||
import { split } from '@apollo/client/core'
|
||||
import { WebSocketLink } from '@apollo/client/link/ws'
|
||||
import { getMainDefinition } from '@apollo/client/utilities'
|
||||
```
|
||||
|
||||
Learn more at the [official apollo documentation](https://www.apollographql.com/docs/react/2.0-migration.html).
|
||||
|
||||
@@ -4,21 +4,11 @@
|
||||
|
||||
*关于服务端实现,你可以看看 [这个简单的示例](https://github.com/Akryum/apollo-server-example)。*
|
||||
|
||||
要启用基于 websocket 的订阅,需要做一些额外的设置:
|
||||
|
||||
```
|
||||
npm install --save apollo-link-ws apollo-utilities
|
||||
```
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
// 新的引入文件
|
||||
import { split } from 'apollo-link'
|
||||
import { WebSocketLink } from 'apollo-link-ws'
|
||||
import { getMainDefinition } from 'apollo-utilities'
|
||||
import { ApolloClient, HttpLink, InMemoryCache, split } from '@apollo/client/core'
|
||||
import { WebSocketLink } from '@apollo/client/link/ws'
|
||||
import { getMainDefinition } from '@apollo/client/utilities'
|
||||
|
||||
import VueApollo from '@vue/apollo-option'
|
||||
|
||||
|
||||
@@ -18,55 +18,20 @@ vue add apollo
|
||||
|
||||
### 1. Apollo Client
|
||||
|
||||
你可以使用 [Apollo Boost](#apollo-boost) 或 [直接使用 Apollo Client](#apollo-client-full-configuration)(需要更多配置工作)。
|
||||
|
||||
#### Apollo Boost
|
||||
|
||||
Apollo Boost 是一种零配置开始使用 Apollo Client 的方式。它包含一些实用的默认值,例如我们推荐的 `InMemoryCache` 和 `HttpLink`,它非常适合用于快速启动开发。
|
||||
|
||||
将它与 `vue-apollo` 和 `graphql` 一起安装:
|
||||
|
||||
```
|
||||
npm install --save vue-apollo graphql apollo-boost
|
||||
npm install --save graphql graphql-tag @apollo/client
|
||||
```
|
||||
|
||||
或:
|
||||
|
||||
```
|
||||
yarn add vue-apollo graphql apollo-boost
|
||||
yarn add graphql graphql-tag @apollo/client
|
||||
```
|
||||
|
||||
在你的应用中创建一个 `ApolloClient` 实例:
|
||||
|
||||
```js
|
||||
import ApolloClient from 'apollo-boost'
|
||||
|
||||
const apolloClient = new ApolloClient({
|
||||
// 你需要在这里使用绝对路径
|
||||
uri: 'https://api.graphcms.com/simple/v1/awesomeTalksClone'
|
||||
})
|
||||
```
|
||||
|
||||
#### Apollo 客户端完整配置
|
||||
|
||||
如果你想要更细粒度的控制,安装这些包来代替 `apollo-boost`:
|
||||
|
||||
```
|
||||
npm install --save vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
|
||||
```
|
||||
|
||||
或:
|
||||
|
||||
```
|
||||
yarn add vue-apollo graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
|
||||
```
|
||||
|
||||
在你的应用中创建一个 `ApolloClient` 实例:
|
||||
|
||||
```js
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { createHttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client/core'
|
||||
|
||||
// 与 API 的 HTTP 连接
|
||||
const httpLink = createHttpLink({
|
||||
|
||||
@@ -125,9 +125,7 @@ export default {
|
||||
// apollo.js
|
||||
|
||||
import Vue from 'vue'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core'
|
||||
import VueApollo from '@vue/apollo-option'
|
||||
|
||||
// 安装 vue 插件
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
之前:
|
||||
|
||||
```
|
||||
npm install --save vue-apollo apollo-client
|
||||
npm install --save vue-apollo@next graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
|
||||
```
|
||||
|
||||
之后:
|
||||
|
||||
```
|
||||
npm install --save vue-apollo@next graphql apollo-client apollo-link apollo-link-http apollo-cache-inmemory graphql-tag
|
||||
npm install --save vue-apollo@next @apollo/client
|
||||
```
|
||||
|
||||
### 导入
|
||||
@@ -24,7 +24,9 @@ npm install --save vue-apollo@next graphql apollo-client apollo-link apollo-link
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import { ApolloClient, createBatchingNetworkInterface } from 'apollo-client'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import VueApollo from '@vue/apollo-option'
|
||||
```
|
||||
|
||||
@@ -32,9 +34,7 @@ import VueApollo from '@vue/apollo-option'
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { HttpLink } from 'apollo-link-http'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core'
|
||||
import VueApollo from '@vue/apollo-option'
|
||||
```
|
||||
|
||||
@@ -111,7 +111,7 @@ const apolloClient = new ApolloClient({
|
||||
```js
|
||||
// 创建 apollo 客户端
|
||||
const apolloClient = new ApolloClient({
|
||||
networkInterface: createBatchingNetworkInterface({
|
||||
link: createHttpLink({
|
||||
uri: 'http://localhost:3020/graphql',
|
||||
}),
|
||||
connectToDevTools: true,
|
||||
@@ -174,23 +174,25 @@ npm install --save subscriptions-transport-ws
|
||||
之后:
|
||||
|
||||
```
|
||||
npm install --save apollo-link-ws apollo-utilities
|
||||
npm install --save @apollo/client
|
||||
```
|
||||
|
||||
### 导入
|
||||
|
||||
之前:
|
||||
|
||||
```js
|
||||
import { SubscriptionClient, addGraphQLSubscriptions } from 'subscriptions-transport-ws'
|
||||
```
|
||||
|
||||
之后:
|
||||
|
||||
```js
|
||||
import { split } from 'apollo-link'
|
||||
import { WebSocketLink } from 'apollo-link-ws'
|
||||
import { getMainDefinition } from 'apollo-utilities'
|
||||
```
|
||||
|
||||
了解更多请查看 [apollo 官方文档](https://www.apollographql.com/docs/react/2.0-migration.html)。
|
||||
之后:
|
||||
|
||||
```js
|
||||
import { split } from '@apollo/client/core'
|
||||
import { WebSocketLink } from '@apollo/client/link/ws'
|
||||
import { getMainDefinition } from '@apollo/client/utilities'
|
||||
```
|
||||
|
||||
了解更多请查看 [apollo 官方文档](https://www.apollographql.com/docs/react/2.0-migration.html)。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createApolloClient, restartWebsockets } from 'vue-cli-plugin-apollo/graphql-client'
|
||||
import { logErrorMessages } from '@vue/apollo-util'
|
||||
// import { print } from 'graphql'
|
||||
import { onError } from 'apollo-link-error'
|
||||
import { onError } from '@apollo/client/link/error'
|
||||
|
||||
// Name of the localStorage item
|
||||
const AUTH_TOKEN = 'apollo-token'
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"vue": "^2.6.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apollo/client": "^3.0.0",
|
||||
"@types/throttle-debounce": "^2.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.4.1",
|
||||
"@typescript-eslint/parser": "^4.4.1",
|
||||
|
||||
@@ -15,14 +15,14 @@ export interface UseApolloClientReturn<TCacheShape> {
|
||||
readonly client: ApolloClient<TCacheShape>
|
||||
}
|
||||
|
||||
function resolveDefaultClient<T> (providedApolloClients: ClientDict<T>, providedApolloClient: ApolloClient<T>): NullableApolloClient<T> {
|
||||
function resolveDefaultClient<T> (providedApolloClients: ClientDict<T> | null, providedApolloClient: ApolloClient<T> | null): NullableApolloClient<T> {
|
||||
const resolvedClient = providedApolloClients
|
||||
? providedApolloClients.default
|
||||
: providedApolloClient
|
||||
: (providedApolloClient ?? undefined)
|
||||
return resolvedClient
|
||||
}
|
||||
|
||||
function resolveClientWithId<T> (providedApolloClients: ClientDict<T>, clientId: ClientId): NullableApolloClient<T> {
|
||||
function resolveClientWithId<T> (providedApolloClients: ClientDict<T> | null, clientId: ClientId): NullableApolloClient<T> {
|
||||
if (!providedApolloClients) {
|
||||
throw new Error(`No apolloClients injection found, tried to resolve '${clientId}' clientId`)
|
||||
}
|
||||
@@ -35,10 +35,10 @@ export function useApolloClient<TCacheShape = any> (clientId?: ClientId): UseApo
|
||||
if (!getCurrentInstance()) {
|
||||
resolveImpl = () => currentApolloClient
|
||||
} else {
|
||||
const providedApolloClients: ClientDict<TCacheShape> = inject(ApolloClients, null)
|
||||
const providedApolloClient: ApolloClient<TCacheShape> = inject(DefaultApolloClient, null)
|
||||
const providedApolloClients: ClientDict<TCacheShape> | null = inject(ApolloClients, null)
|
||||
const providedApolloClient: ApolloClient<TCacheShape> | null = inject(DefaultApolloClient, null)
|
||||
|
||||
resolveImpl = (id: ClientId) => {
|
||||
resolveImpl = (id?: ClientId) => {
|
||||
if (currentApolloClient) {
|
||||
return currentApolloClient
|
||||
} else if (id) {
|
||||
@@ -48,10 +48,10 @@ export function useApolloClient<TCacheShape = any> (clientId?: ClientId): UseApo
|
||||
}
|
||||
}
|
||||
|
||||
function resolveClient (id: ClientId = clientId) {
|
||||
function resolveClient (id: ClientId | undefined = clientId) {
|
||||
const client = resolveImpl(id)
|
||||
if (!client) {
|
||||
throw new Error(`Apollo client with id ${id || 'default'} not found. Use provideApolloClient() if you are outside of a component setup.`)
|
||||
throw new Error(`Apollo client with id ${id ?? 'default'} not found. Use provideApolloClient() if you are outside of a component setup.`)
|
||||
}
|
||||
return client
|
||||
}
|
||||
@@ -70,7 +70,7 @@ export function provideApolloClient<TCacheShape = any> (client: ApolloClient<TCa
|
||||
currentApolloClient = client
|
||||
return function <TFnResult = any> (fn: () => TFnResult) {
|
||||
const result = fn()
|
||||
currentApolloClient = null
|
||||
currentApolloClient = undefined
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export function useLazyQuery<
|
||||
TResult = any,
|
||||
TVariables = any,
|
||||
> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
variables?: VariablesParameter<TVariables>,
|
||||
options?: OptionsParameter<TResult, TVariables>,
|
||||
) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DocumentNode } from 'graphql'
|
||||
import { MutationOptions, OperationVariables, FetchResult } from '@apollo/client/core'
|
||||
import { MutationOptions, OperationVariables, FetchResult, TypedDocumentNode } from '@apollo/client/core'
|
||||
import { ref, onBeforeUnmount, isRef, Ref } from 'vue-demi'
|
||||
import { useApolloClient } from './useApolloClient'
|
||||
import { ReactiveFunction } from './util/ReactiveFunction'
|
||||
@@ -16,17 +16,17 @@ export interface UseMutationOptions<
|
||||
clientId?: string
|
||||
}
|
||||
|
||||
type DocumentParameter = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode>
|
||||
type DocumentParameter<TResult, TVariables> = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode> | TypedDocumentNode<TResult, TVariables> | Ref<TypedDocumentNode<TResult, TVariables>> | ReactiveFunction<TypedDocumentNode<TResult, TVariables>>
|
||||
type OptionsParameter<TResult, TVariables> = UseMutationOptions<TResult, TVariables> | Ref<UseMutationOptions<TResult, TVariables>> | ReactiveFunction<UseMutationOptions<TResult, TVariables>>
|
||||
|
||||
export type MutateOverrideOptions = Pick<UseMutationOptions<any, OperationVariables>, 'update' | 'optimisticResponse' | 'context' | 'updateQueries' | 'refetchQueries' | 'awaitRefetchQueries' | 'errorPolicy' | 'fetchPolicy' | 'clientId'>
|
||||
export type MutateResult<TResult> = Promise<FetchResult<TResult, Record<string, any>, Record<string, any>>>
|
||||
export type MutateFunction<TResult, TVariables> = (variables?: TVariables, overrideOptions?: MutateOverrideOptions) => MutateResult<TResult>
|
||||
export type MutateFunction<TResult, TVariables> = (variables?: TVariables | null, overrideOptions?: MutateOverrideOptions) => MutateResult<TResult>
|
||||
|
||||
export interface UseMutationReturn<TResult, TVariables> {
|
||||
mutate: MutateFunction<TResult, TVariables>
|
||||
loading: Ref<boolean>
|
||||
error: Ref<Error>
|
||||
error: Ref<Error | null>
|
||||
called: Ref<boolean>
|
||||
onDone: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>) => void) => {
|
||||
off: () => void
|
||||
@@ -40,14 +40,12 @@ export function useMutation<
|
||||
TResult = any,
|
||||
TVariables extends OperationVariables = OperationVariables
|
||||
> (
|
||||
document: DocumentParameter,
|
||||
options?: OptionsParameter<TResult, TVariables>,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
options: OptionsParameter<TResult, TVariables> = {},
|
||||
): UseMutationReturn<TResult, TVariables> {
|
||||
if (!options) options = {}
|
||||
|
||||
const loading = ref<boolean>(false)
|
||||
trackMutation(loading)
|
||||
const error = ref<Error>(null)
|
||||
const error = ref<Error | null>(null)
|
||||
const called = ref<boolean>(false)
|
||||
|
||||
const doneEvent = useEventHook<FetchResult<TResult, Record<string, any>, Record<string, any>>>()
|
||||
@@ -56,7 +54,7 @@ export function useMutation<
|
||||
// Apollo Client
|
||||
const { resolveClient } = useApolloClient()
|
||||
|
||||
async function mutate (variables?: TVariables, overrideOptions: Omit<UseMutationOptions<TResult, TVariables>, 'variables'> = {}) {
|
||||
async function mutate (variables?: TVariables | null, overrideOptions: Omit<UseMutationOptions<TResult, TVariables>, 'variables'> = {}) {
|
||||
let currentDocument: DocumentNode
|
||||
if (typeof document === 'function') {
|
||||
currentDocument = document()
|
||||
@@ -79,14 +77,16 @@ export function useMutation<
|
||||
loading.value = true
|
||||
called.value = true
|
||||
try {
|
||||
const result = await client.mutate<TResult>({
|
||||
const result = await client.mutate<TResult, TVariables>({
|
||||
mutation: currentDocument,
|
||||
...currentOptions,
|
||||
...overrideOptions,
|
||||
variables: {
|
||||
...currentOptions.variables || {},
|
||||
...variables || {},
|
||||
},
|
||||
variables: (variables ?? currentOptions.variables)
|
||||
? {
|
||||
...(currentOptions.variables as TVariables),
|
||||
...(variables as TVariables),
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
loading.value = false
|
||||
doneEvent.trigger(result)
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
FetchMoreQueryOptions,
|
||||
FetchMoreOptions,
|
||||
ObservableSubscription,
|
||||
TypedDocumentNode,
|
||||
} from '@apollo/client/core'
|
||||
import { throttle, debounce } from 'throttle-debounce'
|
||||
import { useApolloClient } from './useApolloClient'
|
||||
@@ -29,6 +30,8 @@ import { paramToReactive } from './util/paramToReactive'
|
||||
import { useEventHook } from './util/useEventHook'
|
||||
import { trackQuery } from './util/loadingTracking'
|
||||
|
||||
import type { CurrentInstance } from './util/types'
|
||||
|
||||
export interface UseQueryOptions<
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
TResult = any,
|
||||
@@ -47,26 +50,26 @@ interface SubscribeToMoreItem {
|
||||
}
|
||||
|
||||
// Parameters
|
||||
export type DocumentParameter = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode>
|
||||
export type DocumentParameter<TResult, TVariables = undefined> = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode> | TypedDocumentNode<TResult, TVariables> | Ref<TypedDocumentNode<TResult, TVariables>> | ReactiveFunction<TypedDocumentNode<TResult, TVariables>>
|
||||
export type VariablesParameter<TVariables> = TVariables | Ref<TVariables> | ReactiveFunction<TVariables>
|
||||
export type OptionsParameter<TResult, TVariables> = UseQueryOptions<TResult, TVariables> | Ref<UseQueryOptions<TResult, TVariables>> | ReactiveFunction<UseQueryOptions<TResult, TVariables>>
|
||||
|
||||
// Return
|
||||
export interface UseQueryReturn<TResult, TVariables> {
|
||||
result: Ref<TResult>
|
||||
result: Ref<TResult | undefined>
|
||||
loading: Ref<boolean>
|
||||
networkStatus: Ref<number>
|
||||
error: Ref<Error>
|
||||
networkStatus: Ref<number | undefined>
|
||||
error: Ref<Error | null>
|
||||
start: () => void
|
||||
stop: () => void
|
||||
restart: () => void
|
||||
forceDisabled: Ref<boolean>
|
||||
document: Ref<DocumentNode>
|
||||
variables: Ref<TVariables>
|
||||
variables: Ref<TVariables | undefined>
|
||||
options: UseQueryOptions<TResult, TVariables> | Ref<UseQueryOptions<TResult, TVariables>>
|
||||
query: Ref<ObservableQuery<TResult, TVariables>>
|
||||
refetch: (variables?: TVariables) => Promise<ApolloQueryResult<TResult>>
|
||||
fetchMore: <K extends keyof TVariables>(options: FetchMoreQueryOptions<TVariables, K> & FetchMoreOptions<TResult, TVariables>) => Promise<ApolloQueryResult<TResult>>
|
||||
query: Ref<ObservableQuery<TResult, TVariables> | null | undefined>
|
||||
refetch: (variables?: TVariables) => Promise<ApolloQueryResult<TResult>> | undefined
|
||||
fetchMore: <K extends keyof TVariables>(options: FetchMoreQueryOptions<TVariables, K> & FetchMoreOptions<TResult, TVariables>) => Promise<ApolloQueryResult<TResult>> | undefined
|
||||
subscribeToMore: <TSubscriptionVariables = OperationVariables, TSubscriptionData = TResult>(options: SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData> | Ref<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>> | ReactiveFunction<SubscribeToMoreOptions<TResult, TSubscriptionVariables, TSubscriptionData>>) => void
|
||||
onResult: (fn: (param: ApolloQueryResult<TResult>) => void) => {
|
||||
off: () => void
|
||||
@@ -80,21 +83,21 @@ export interface UseQueryReturn<TResult, TVariables> {
|
||||
* Use a query that does not require variables or options.
|
||||
* */
|
||||
export function useQuery<TResult = any> (
|
||||
document: DocumentParameter
|
||||
document: DocumentParameter<TResult, undefined>
|
||||
): UseQueryReturn<TResult, undefined>
|
||||
|
||||
/**
|
||||
* Use a query that has optional variables but not options
|
||||
*/
|
||||
export function useQuery<TResult = any, TVariables extends OperationVariables = OperationVariables> (
|
||||
document: DocumentParameter
|
||||
document: DocumentParameter<TResult, TVariables>
|
||||
): UseQueryReturn<TResult, TVariables>
|
||||
|
||||
/**
|
||||
* Use a query that has required variables but not options
|
||||
*/
|
||||
export function useQuery<TResult = any, TVariables extends OperationVariables = OperationVariables> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
variables: VariablesParameter<TVariables>
|
||||
): UseQueryReturn<TResult, TVariables>
|
||||
|
||||
@@ -102,7 +105,7 @@ export function useQuery<TResult = any, TVariables extends OperationVariables =
|
||||
* Use a query that requires options but not variables.
|
||||
*/
|
||||
export function useQuery<TResult = any> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, undefined>,
|
||||
variables: undefined | null,
|
||||
options: OptionsParameter<TResult, null>,
|
||||
): UseQueryReturn<TResult, null>
|
||||
@@ -111,7 +114,7 @@ export function useQuery<TResult = any> (
|
||||
* Use a query that requires variables and options.
|
||||
*/
|
||||
export function useQuery<TResult = any, TVariables extends OperationVariables = OperationVariables> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
variables: VariablesParameter<TVariables>,
|
||||
options: OptionsParameter<TResult, TVariables>,
|
||||
): UseQueryReturn<TResult, TVariables>
|
||||
@@ -120,7 +123,7 @@ export function useQuery<
|
||||
TResult,
|
||||
TVariables extends OperationVariables
|
||||
> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
variables?: VariablesParameter<TVariables>,
|
||||
options?: OptionsParameter<TResult, TVariables>,
|
||||
): UseQueryReturn<TResult, TVariables> {
|
||||
@@ -131,17 +134,15 @@ export function useQueryImpl<
|
||||
TResult,
|
||||
TVariables extends OperationVariables
|
||||
> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
variables?: VariablesParameter<TVariables>,
|
||||
options?: OptionsParameter<TResult, TVariables>,
|
||||
options: OptionsParameter<TResult, TVariables> = {},
|
||||
lazy: boolean = false,
|
||||
): UseQueryReturn<TResult, TVariables> {
|
||||
// Is on server?
|
||||
const vm: any = getCurrentInstance()
|
||||
const isServer = vm?.$isServer
|
||||
const vm = getCurrentInstance() as CurrentInstance | null
|
||||
const isServer = vm?.$isServer ?? false
|
||||
|
||||
if (variables == null) variables = ref()
|
||||
if (options == null) options = {}
|
||||
const documentRef = paramToRef(document)
|
||||
const variablesRef = paramToRef(variables)
|
||||
const optionsRef = paramToReactive(options)
|
||||
@@ -150,9 +151,9 @@ export function useQueryImpl<
|
||||
/**
|
||||
* Result from the query
|
||||
*/
|
||||
const result = ref<TResult>()
|
||||
const result = ref<TResult | undefined>()
|
||||
const resultEvent = useEventHook<ApolloQueryResult<TResult>>()
|
||||
const error = ref<Error>(null)
|
||||
const error = ref<Error | null>(null)
|
||||
const errorEvent = useEventHook<Error>()
|
||||
|
||||
// Loading
|
||||
@@ -168,7 +169,7 @@ export function useQueryImpl<
|
||||
let firstResolve: Function | undefined
|
||||
let firstReject: Function | undefined
|
||||
onServerPrefetch?.(() => {
|
||||
if (!isEnabled.value || (isServer && currentOptions.value.prefetch === false)) return
|
||||
if (!isEnabled.value || (isServer && currentOptions.value?.prefetch === false)) return
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
firstResolve = () => {
|
||||
@@ -189,8 +190,8 @@ export function useQueryImpl<
|
||||
|
||||
// Query
|
||||
|
||||
const query: Ref<ObservableQuery<TResult, TVariables>> = ref()
|
||||
let observer: ObservableSubscription
|
||||
const query: Ref<ObservableQuery<TResult, TVariables> | null | undefined> = ref()
|
||||
let observer: ObservableSubscription | undefined
|
||||
let started = false
|
||||
|
||||
/**
|
||||
@@ -199,7 +200,7 @@ export function useQueryImpl<
|
||||
function start () {
|
||||
if (
|
||||
started || !isEnabled.value ||
|
||||
(isServer && currentOptions.value.prefetch === false)
|
||||
(isServer && currentOptions.value?.prefetch === false)
|
||||
) {
|
||||
if (firstResolve) firstResolve()
|
||||
return
|
||||
@@ -208,7 +209,7 @@ export function useQueryImpl<
|
||||
started = true
|
||||
loading.value = true
|
||||
|
||||
const client = resolveClient(currentOptions.value.clientId)
|
||||
const client = resolveClient(currentOptions.value?.clientId)
|
||||
|
||||
query.value = client.watchQuery<TResult, TVariables>({
|
||||
query: currentDocument,
|
||||
@@ -221,10 +222,10 @@ export function useQueryImpl<
|
||||
|
||||
startQuerySubscription()
|
||||
|
||||
if (!isServer && (currentOptions.value.fetchPolicy !== 'no-cache' || currentOptions.value.notifyOnNetworkStatusChange)) {
|
||||
if (!isServer && (currentOptions.value?.fetchPolicy !== 'no-cache' || currentOptions.value.notifyOnNetworkStatusChange)) {
|
||||
const currentResult = query.value.getCurrentResult()
|
||||
|
||||
if (!currentResult.loading || currentOptions.value.notifyOnNetworkStatusChange) {
|
||||
if (!currentResult.loading || currentOptions.value?.notifyOnNetworkStatusChange) {
|
||||
onNextResult(currentResult)
|
||||
}
|
||||
}
|
||||
@@ -268,14 +269,14 @@ export function useQueryImpl<
|
||||
}
|
||||
|
||||
function processNextResult (queryResult: ApolloQueryResult<TResult>) {
|
||||
result.value = queryResult.data && Object.keys(queryResult.data).length === 0 ? null : queryResult.data
|
||||
result.value = queryResult.data && Object.keys(queryResult.data).length === 0 ? undefined : queryResult.data
|
||||
loading.value = queryResult.loading
|
||||
networkStatus.value = queryResult.networkStatus
|
||||
resultEvent.trigger(queryResult)
|
||||
}
|
||||
|
||||
function onError (queryError: any) {
|
||||
processNextResult(query.value.getCurrentResult())
|
||||
processNextResult((query.value as ObservableQuery<TResult, TVariables>).getCurrentResult())
|
||||
processError(queryError)
|
||||
if (firstReject) {
|
||||
firstReject(queryError)
|
||||
@@ -322,7 +323,7 @@ export function useQueryImpl<
|
||||
|
||||
if (observer) {
|
||||
observer.unsubscribe()
|
||||
observer = null
|
||||
observer = undefined
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,9 +353,9 @@ export function useQueryImpl<
|
||||
if (!currentOptions) {
|
||||
debouncedRestart = baseRestart
|
||||
} else {
|
||||
if (currentOptions.value.throttle) {
|
||||
if (currentOptions.value?.throttle) {
|
||||
debouncedRestart = throttle(currentOptions.value.throttle, baseRestart)
|
||||
} else if (currentOptions.value.debounce) {
|
||||
} else if (currentOptions.value?.debounce) {
|
||||
debouncedRestart = debounce(currentOptions.value.debounce, baseRestart)
|
||||
} else {
|
||||
debouncedRestart = baseRestart
|
||||
@@ -378,7 +379,7 @@ export function useQueryImpl<
|
||||
})
|
||||
|
||||
// Applying variables
|
||||
let currentVariables: TVariables
|
||||
let currentVariables: TVariables | undefined
|
||||
let currentVariablesSerialized: string
|
||||
watch(variablesRef, (value, oldValue) => {
|
||||
const serialized = JSON.stringify(value)
|
||||
@@ -410,7 +411,7 @@ export function useQueryImpl<
|
||||
|
||||
// Fefetch
|
||||
|
||||
function refetch (variables: TVariables = null) {
|
||||
function refetch (variables: TVariables | undefined = undefined) {
|
||||
if (query.value) {
|
||||
if (variables) {
|
||||
currentVariables = variables
|
||||
@@ -465,6 +466,9 @@ export function useQueryImpl<
|
||||
|
||||
function addSubscribeToMore (item: SubscribeToMoreItem) {
|
||||
if (!started) return
|
||||
if (!query.value) {
|
||||
throw new Error('Query is not defined')
|
||||
}
|
||||
const unsubscribe = query.value.subscribeToMore(item.options)
|
||||
onStopHandlers.push(unsubscribe)
|
||||
item.unsubscribeFns.push(unsubscribe)
|
||||
|
||||
@@ -16,9 +16,9 @@ export type UseResultReturn<T> = Readonly<Ref<Readonly<T>>>
|
||||
* @param {Ref<TResult>} result A `result` returned from `useQuery` to resolve.
|
||||
* @returns Readonly ref with `undefined` or the resolved `result`.
|
||||
*/
|
||||
export function useResult<TResult, TResultKey extends keyof TResult = keyof TResult> (
|
||||
export function useResult<TResult, TResultKey extends keyof NonNullable<TResult> = keyof NonNullable<TResult>> (
|
||||
result: Ref<TResult>
|
||||
): UseResultReturn<undefined | ExtractSingleKey<TResult, TResultKey>>
|
||||
): UseResultReturn<undefined | ExtractSingleKey<NonNullable<TResult>, TResultKey>>
|
||||
|
||||
/**
|
||||
* Resolve a `result`, returning either the first key of the `result` if there
|
||||
@@ -34,10 +34,10 @@ export function useResult<TResult, TResultKey extends keyof TResult = keyof TRes
|
||||
* @param {TDefaultValue} defaultValue The default return value before `result` is resolved.
|
||||
* @returns Readonly ref with the `defaultValue` or the resolved `result`.
|
||||
*/
|
||||
export function useResult<TResult, TDefaultValue, TResultKey extends keyof TResult = keyof TResult> (
|
||||
export function useResult<TResult, TDefaultValue, TResultKey extends keyof NonNullable<TResult> = keyof NonNullable<TResult>> (
|
||||
result: Ref<TResult>,
|
||||
defaultValue: TDefaultValue
|
||||
): UseResultReturn<TDefaultValue | ExtractSingleKey<TResult, TResultKey>>
|
||||
): UseResultReturn<TDefaultValue | ExtractSingleKey<NonNullable<TResult>, TResultKey>>
|
||||
|
||||
/**
|
||||
* Resolve a `result`, returning the `result` mapped with the `pick` function.
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
FetchResult,
|
||||
Observable,
|
||||
ObservableSubscription,
|
||||
TypedDocumentNode,
|
||||
} from '@apollo/client/core'
|
||||
import { throttle, debounce } from 'throttle-debounce'
|
||||
import { ReactiveFunction } from './util/ReactiveFunction'
|
||||
@@ -24,6 +25,8 @@ import { useApolloClient } from './useApolloClient'
|
||||
import { useEventHook } from './util/useEventHook'
|
||||
import { trackSubscription } from './util/loadingTracking'
|
||||
|
||||
import type { CurrentInstance } from './util/types'
|
||||
|
||||
export interface UseSubscriptionOptions <
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
TResult = any,
|
||||
@@ -35,21 +38,21 @@ export interface UseSubscriptionOptions <
|
||||
debounce?: number
|
||||
}
|
||||
|
||||
type DocumentParameter = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode>
|
||||
type DocumentParameter<TResult, TVariables> = DocumentNode | Ref<DocumentNode> | ReactiveFunction<DocumentNode> | TypedDocumentNode<TResult, TVariables> | Ref<TypedDocumentNode<TResult, TVariables>> | ReactiveFunction<TypedDocumentNode<TResult, TVariables>>
|
||||
type VariablesParameter<TVariables> = TVariables | Ref<TVariables> | ReactiveFunction<TVariables>
|
||||
type OptionsParameter<TResult, TVariables> = UseSubscriptionOptions<TResult, TVariables> | Ref<UseSubscriptionOptions<TResult, TVariables>> | ReactiveFunction<UseSubscriptionOptions<TResult, TVariables>>
|
||||
|
||||
export interface UseSubscriptionReturn<TResult, TVariables> {
|
||||
result: Ref<TResult>
|
||||
result: Ref<TResult | null | undefined>
|
||||
loading: Ref<boolean>
|
||||
error: Ref<Error>
|
||||
error: Ref<Error | null>
|
||||
start: () => void
|
||||
stop: () => void
|
||||
restart: () => void
|
||||
document: Ref<DocumentNode>
|
||||
variables: Ref<TVariables>
|
||||
variables: Ref<TVariables | undefined>
|
||||
options: UseSubscriptionOptions<TResult, TVariables> | Ref<UseSubscriptionOptions<TResult, TVariables>>
|
||||
subscription: Ref<Observable<FetchResult<TResult, Record<string, any>, Record<string, any>>>>
|
||||
subscription: Ref<Observable<FetchResult<TResult, Record<string, any>, Record<string, any>>> | null>
|
||||
onResult: (fn: (param: FetchResult<TResult, Record<string, any>, Record<string, any>>) => void) => {
|
||||
off: () => void
|
||||
}
|
||||
@@ -62,14 +65,14 @@ export interface UseSubscriptionReturn<TResult, TVariables> {
|
||||
* Use a subscription that does not require variables or options.
|
||||
* */
|
||||
export function useSubscription<TResult = any> (
|
||||
document: DocumentParameter
|
||||
document: DocumentParameter<TResult, undefined>
|
||||
): UseSubscriptionReturn<TResult, undefined>
|
||||
|
||||
/**
|
||||
* Use a subscription that requires options but not variables.
|
||||
*/
|
||||
export function useSubscription<TResult = any> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, undefined>,
|
||||
variables: undefined | null,
|
||||
options: OptionsParameter<TResult, null>
|
||||
): UseSubscriptionReturn<TResult, null>
|
||||
@@ -78,7 +81,7 @@ export function useSubscription<TResult = any> (
|
||||
* Use a subscription that requires variables.
|
||||
*/
|
||||
export function useSubscription<TResult = any, TVariables extends OperationVariables = OperationVariables> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
variables: VariablesParameter<TVariables>
|
||||
): UseSubscriptionReturn<TResult, TVariables>
|
||||
|
||||
@@ -86,14 +89,14 @@ export function useSubscription<TResult = any, TVariables extends OperationVaria
|
||||
* Use a subscription that has optional variables.
|
||||
*/
|
||||
export function useSubscription<TResult = any, TVariables extends OperationVariables = OperationVariables> (
|
||||
document: DocumentParameter
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
): UseSubscriptionReturn<TResult, TVariables>
|
||||
|
||||
/**
|
||||
* Use a subscription that requires variables and options.
|
||||
*/
|
||||
export function useSubscription<TResult = any, TVariables extends OperationVariables = OperationVariables> (
|
||||
document: DocumentParameter,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
variables: VariablesParameter<TVariables>,
|
||||
options: OptionsParameter<TResult, TVariables>
|
||||
): UseSubscriptionReturn<TResult, TVariables>
|
||||
@@ -102,23 +105,21 @@ export function useSubscription <
|
||||
TResult,
|
||||
TVariables
|
||||
> (
|
||||
document: DocumentParameter,
|
||||
variables: VariablesParameter<TVariables> = null,
|
||||
options: OptionsParameter<TResult, TVariables> = null,
|
||||
document: DocumentParameter<TResult, TVariables>,
|
||||
variables: VariablesParameter<TVariables> | undefined = undefined,
|
||||
options: OptionsParameter<TResult, TVariables> = {},
|
||||
): UseSubscriptionReturn<TResult, TVariables> {
|
||||
// Is on server?
|
||||
const vm: any = getCurrentInstance()
|
||||
const isServer = vm?.$isServer
|
||||
const vm = getCurrentInstance() as CurrentInstance | null
|
||||
const isServer = vm?.$isServer ?? false
|
||||
|
||||
if (variables == null) variables = ref()
|
||||
if (!options) options = {}
|
||||
const documentRef = paramToRef(document)
|
||||
const variablesRef = paramToRef(variables)
|
||||
const optionsRef = paramToReactive(options)
|
||||
|
||||
const result = ref<TResult>()
|
||||
const result = ref<TResult | null | undefined>()
|
||||
const resultEvent = useEventHook<FetchResult<TResult>>()
|
||||
const error = ref<Error>(null)
|
||||
const error = ref<Error | null>(null)
|
||||
const errorEvent = useEventHook<Error>()
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -127,8 +128,8 @@ export function useSubscription <
|
||||
// Apollo Client
|
||||
const { resolveClient } = useApolloClient()
|
||||
|
||||
const subscription: Ref<Observable<FetchResult<TResult>>> = ref()
|
||||
let observer: ObservableSubscription
|
||||
const subscription: Ref<Observable<FetchResult<TResult>> | null> = ref(null)
|
||||
let observer: ObservableSubscription | null = null
|
||||
let started = false
|
||||
|
||||
function start () {
|
||||
@@ -136,7 +137,7 @@ export function useSubscription <
|
||||
started = true
|
||||
loading.value = true
|
||||
|
||||
const client = resolveClient(currentOptions.value.clientId)
|
||||
const client = resolveClient(currentOptions.value?.clientId)
|
||||
|
||||
subscription.value = client.subscribe<TResult, TVariables>({
|
||||
query: currentDocument,
|
||||
@@ -197,9 +198,9 @@ export function useSubscription <
|
||||
|
||||
let debouncedRestart: Function
|
||||
function updateRestartFn () {
|
||||
if (currentOptions.value.throttle) {
|
||||
if (currentOptions.value?.throttle) {
|
||||
debouncedRestart = throttle(currentOptions.value.throttle, baseRestart)
|
||||
} else if (currentOptions.value.debounce) {
|
||||
} else if (currentOptions.value?.debounce) {
|
||||
debouncedRestart = debounce(currentOptions.value.debounce, baseRestart)
|
||||
} else {
|
||||
debouncedRestart = baseRestart
|
||||
@@ -237,7 +238,7 @@ export function useSubscription <
|
||||
})
|
||||
|
||||
// Applying variables
|
||||
let currentVariables: TVariables
|
||||
let currentVariables: TVariables | undefined
|
||||
let currentVariablesSerialized: string
|
||||
watch(variablesRef, (value, oldValue) => {
|
||||
const serialized = JSON.stringify(value)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Ref, watch, onUnmounted, ref, getCurrentInstance, onBeforeUnmount } from 'vue-demi'
|
||||
import type { CurrentInstance } from './types'
|
||||
|
||||
export interface LoadingTracking {
|
||||
queries: Ref<number>
|
||||
@@ -11,8 +12,12 @@ export interface AppLoadingTracking extends LoadingTracking {
|
||||
}
|
||||
|
||||
export function getAppTracking () {
|
||||
const vm: any = getCurrentInstance()
|
||||
const root: any = vm.$root || vm.root
|
||||
const vm = getCurrentInstance() as CurrentInstance | null
|
||||
const root = vm?.$root ?? vm?.root
|
||||
if (!root) {
|
||||
throw new Error('Instance $root not found')
|
||||
}
|
||||
|
||||
let appTracking: AppLoadingTracking
|
||||
|
||||
if (!root._apolloAppTracking) {
|
||||
@@ -54,7 +59,7 @@ export function getCurrentTracking () {
|
||||
appTracking.components.delete(vm)
|
||||
})
|
||||
} else {
|
||||
tracking = appTracking.components.get(vm)
|
||||
tracking = appTracking.components.get(vm) as LoadingTracking
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { ComponentInternalInstance } from 'vue-demi'
|
||||
import type { AppLoadingTracking } from './loadingTracking'
|
||||
|
||||
export interface CurrentInstance extends Omit<ComponentInternalInstance, 'root' | '$root'> {
|
||||
_apolloAppTracking?: AppLoadingTracking
|
||||
$root?: CurrentInstance
|
||||
root?: CurrentInstance
|
||||
$isServer?: boolean
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import gql from 'graphql-tag'
|
||||
import { TypedDocumentNode } from '@apollo/client/core'
|
||||
|
||||
export type ID = string
|
||||
|
||||
@@ -83,3 +84,9 @@ export interface MultiKeyExampleQuery {
|
||||
__typename?: 'OtherExample'
|
||||
}
|
||||
}
|
||||
|
||||
export const ExampleTypedQueryDocument: TypedDocumentNode<ExampleQuery, ExampleQueryVariables> = ExampleDocument
|
||||
|
||||
export const ExampleTypedMutationDocument: TypedDocumentNode<ExampleUpdateMutation, ExampleUpdateMutationVariables> = ExampleDocument
|
||||
|
||||
export const ExampleTypedSubscriptionDocument: TypedDocumentNode<ExampleUpdatedSubscription, ExampleUpdatedSubscriptionVariables> = ExampleDocument
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
"module": "commonjs",
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true
|
||||
// "strict": true // TODO: this should be enabled, but src is broken with strict
|
||||
"skipLibCheck": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": [
|
||||
"*.test.ts"
|
||||
|
||||
@@ -7,7 +7,7 @@ import { assertExactType } from './assertions'
|
||||
// =============================================================================
|
||||
{
|
||||
const noClientId = useApolloClient()
|
||||
noClientId.client.extract(true).storeType.is.any
|
||||
noClientId.client?.extract(true).storeType.is.any
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -16,7 +16,7 @@ import { assertExactType } from './assertions'
|
||||
// =============================================================================
|
||||
{
|
||||
const withClientId = useApolloClient('88K2tP')
|
||||
withClientId.client.extract(true).storeType.is.any
|
||||
withClientId.client?.extract(true).storeType.is.any
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -25,8 +25,8 @@ import { assertExactType } from './assertions'
|
||||
// =============================================================================
|
||||
{
|
||||
const withType = useApolloClient<'cacheShape'>('38pX2d')
|
||||
const store = withType.client.extract(true)
|
||||
const store = withType.client?.extract(true)
|
||||
|
||||
assertExactType<typeof withType, UseApolloClientReturn<'cacheShape'>>(withType)
|
||||
assertExactType<typeof store, 'cacheShape'>(store)
|
||||
assertExactType<typeof store, 'cacheShape' | undefined>(store)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
ExampleUpdateMutation,
|
||||
ExampleUpdateMutationVariables,
|
||||
ExampleUpdatePayload,
|
||||
ExampleTypedMutationDocument,
|
||||
} from '../fixtures/graphql-example-types'
|
||||
import { assertExactType } from './assertions'
|
||||
|
||||
@@ -85,8 +86,11 @@ import { assertExactType } from './assertions'
|
||||
|
||||
useMutationOnlyMutationType.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<typeof param.data.exampleUpdate, ExampleUpdatePayload>(
|
||||
param.data.exampleUpdate,
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -108,8 +112,11 @@ import { assertExactType } from './assertions'
|
||||
|
||||
useMutationOnlyMutationTypeWithOptions.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<typeof param.data.exampleUpdate, ExampleUpdatePayload>(
|
||||
param.data.exampleUpdate,
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -131,8 +138,11 @@ import { assertExactType } from './assertions'
|
||||
|
||||
useMutationAllTyped.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<typeof param.data.exampleUpdate, ExampleUpdatePayload>(
|
||||
param.data.exampleUpdate,
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -149,8 +159,11 @@ import { assertExactType } from './assertions'
|
||||
|
||||
useMutationAllTyped.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<typeof param.data.exampleUpdate, ExampleUpdatePayload>(
|
||||
param.data.exampleUpdate,
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -162,8 +175,11 @@ import { assertExactType } from './assertions'
|
||||
|
||||
useMutationAllTyped.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<typeof param.data.exampleUpdate, ExampleUpdatePayload>(
|
||||
param.data.exampleUpdate,
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -207,8 +223,11 @@ import { assertExactType } from './assertions'
|
||||
|
||||
withVariablesInOptions.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<typeof param.data.exampleUpdate, ExampleUpdatePayload>(
|
||||
param.data.exampleUpdate,
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -230,8 +249,11 @@ import { assertExactType } from './assertions'
|
||||
|
||||
withNoOptions.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<typeof param.data.exampleUpdate, ExampleUpdatePayload>(
|
||||
param.data.exampleUpdate,
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -273,8 +295,35 @@ import { assertExactType } from './assertions'
|
||||
|
||||
withNoVariablesInOptions.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<typeof param.data.exampleUpdate, ExampleUpdatePayload>(
|
||||
param.data.exampleUpdate,
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// With a TypedQueryDocument:
|
||||
// - TResult should be the mutation type
|
||||
// - TVariables should be the variables type
|
||||
// =============================================================================
|
||||
{
|
||||
const useMutationAllTyped = useMutation(
|
||||
ExampleTypedMutationDocument,
|
||||
{ variables: { id: '1', example: { name: 'new' } } },
|
||||
)
|
||||
|
||||
useMutationAllTyped.mutate({ id: '2', example: { name: 'remix' } }, {})
|
||||
|
||||
useMutationAllTyped.onDone(param => {
|
||||
assertExactType<typeof param, FetchResult<ExampleUpdateMutation> | undefined>(param)
|
||||
assertExactType<
|
||||
NonNullable<NonNullable<typeof param>['data']>['exampleUpdate'],
|
||||
ExampleUpdatePayload | null | undefined
|
||||
>(
|
||||
param?.data?.exampleUpdate,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
ExampleDocument,
|
||||
ExampleQuery,
|
||||
ExampleQueryVariables,
|
||||
ExampleTypedQueryDocument,
|
||||
} from '../fixtures/graphql-example-types'
|
||||
import { assertExactType } from './assertions'
|
||||
|
||||
@@ -31,7 +32,7 @@ import { assertExactType } from './assertions'
|
||||
const useQueryOnlyQueryType = useQuery<ExampleQuery>(ExampleDocument)
|
||||
|
||||
const useQueryOnlyQueryTypeResult = useQueryOnlyQueryType.result.value
|
||||
assertExactType<typeof useQueryOnlyQueryTypeResult, ExampleQuery>(useQueryOnlyQueryTypeResult)
|
||||
assertExactType<typeof useQueryOnlyQueryTypeResult, ExampleQuery | null | undefined>(useQueryOnlyQueryTypeResult)
|
||||
|
||||
const useQueryOnlyQueryTypeVariables = useQueryOnlyQueryType.variables.value
|
||||
assertExactType<typeof useQueryOnlyQueryTypeVariables, undefined>(useQueryOnlyQueryTypeVariables)
|
||||
@@ -46,10 +47,10 @@ import { assertExactType } from './assertions'
|
||||
const useQueryWithVars = useQuery<ExampleQuery>(ExampleDocument, { id: 'asdf' })
|
||||
|
||||
const useQueryWithVarsResult = useQueryWithVars.result.value
|
||||
assertExactType<typeof useQueryWithVarsResult, ExampleQuery>(useQueryWithVarsResult)
|
||||
assertExactType<typeof useQueryWithVarsResult, ExampleQuery | null | undefined>(useQueryWithVarsResult)
|
||||
|
||||
const useQueryWithVarsVariables = useQueryWithVars.variables.value
|
||||
assertExactType<typeof useQueryWithVarsVariables, OperationVariables>(useQueryWithVarsVariables)
|
||||
assertExactType<typeof useQueryWithVarsVariables, OperationVariables | undefined>(useQueryWithVarsVariables)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -63,10 +64,10 @@ import { assertExactType } from './assertions'
|
||||
})
|
||||
|
||||
const useQueryAllTypedResult = useQueryAllTyped.result.value
|
||||
assertExactType<typeof useQueryAllTypedResult, ExampleQuery>(useQueryAllTypedResult)
|
||||
assertExactType<typeof useQueryAllTypedResult, ExampleQuery | null | undefined>(useQueryAllTypedResult)
|
||||
|
||||
const useQueryAllTypedVariables = useQueryAllTyped.variables.value
|
||||
assertExactType<typeof useQueryAllTypedVariables, ExampleQueryVariables>(
|
||||
assertExactType<typeof useQueryAllTypedVariables, ExampleQueryVariables | undefined>(
|
||||
useQueryAllTypedVariables,
|
||||
)
|
||||
}
|
||||
@@ -80,10 +81,10 @@ import { assertExactType } from './assertions'
|
||||
const useQueryAllTyped = useQuery<ExampleQuery, ExampleQueryVariables>(ExampleDocument)
|
||||
|
||||
const useQueryAllTypedResult = useQueryAllTyped.result.value
|
||||
assertExactType<typeof useQueryAllTypedResult, ExampleQuery>(useQueryAllTypedResult)
|
||||
assertExactType<typeof useQueryAllTypedResult, ExampleQuery | null | undefined>(useQueryAllTypedResult)
|
||||
|
||||
const useQueryAllTypedVariables = useQueryAllTyped.variables.value
|
||||
assertExactType<typeof useQueryAllTypedVariables, ExampleQueryVariables>(
|
||||
assertExactType<typeof useQueryAllTypedVariables, ExampleQueryVariables | undefined>(
|
||||
useQueryAllTypedVariables,
|
||||
)
|
||||
}
|
||||
@@ -104,13 +105,13 @@ import { assertExactType } from './assertions'
|
||||
|
||||
const useQueryOnlyQueryTypeNoVarsWithOptionsResult =
|
||||
useQueryOnlyQueryTypeNoVarsWithOptions.result.value
|
||||
assertExactType<typeof useQueryOnlyQueryTypeNoVarsWithOptionsResult, ExampleQuery>(
|
||||
assertExactType<typeof useQueryOnlyQueryTypeNoVarsWithOptionsResult, ExampleQuery | null | undefined>(
|
||||
useQueryOnlyQueryTypeNoVarsWithOptionsResult,
|
||||
)
|
||||
|
||||
const useQueryOnlyQueryTypeNoVarsWithOptionsVariables =
|
||||
useQueryOnlyQueryTypeNoVarsWithOptions.variables.value
|
||||
assertExactType<typeof useQueryOnlyQueryTypeNoVarsWithOptionsVariables, null>(
|
||||
assertExactType<typeof useQueryOnlyQueryTypeNoVarsWithOptionsVariables, null | undefined>(
|
||||
useQueryOnlyQueryTypeNoVarsWithOptionsVariables,
|
||||
)
|
||||
}
|
||||
@@ -125,13 +126,13 @@ import { assertExactType } from './assertions'
|
||||
|
||||
const useQueryOnlyQueryTypeNoVarsWithOptionsResult =
|
||||
useQueryOnlyQueryTypeNoVarsWithOptions.result.value
|
||||
assertExactType<typeof useQueryOnlyQueryTypeNoVarsWithOptionsResult, ExampleQuery>(
|
||||
assertExactType<typeof useQueryOnlyQueryTypeNoVarsWithOptionsResult, ExampleQuery | undefined>(
|
||||
useQueryOnlyQueryTypeNoVarsWithOptionsResult,
|
||||
)
|
||||
|
||||
const useQueryOnlyQueryTypeNoVarsWithOptionsVariables =
|
||||
useQueryOnlyQueryTypeNoVarsWithOptions.variables.value
|
||||
assertExactType<typeof useQueryOnlyQueryTypeNoVarsWithOptionsVariables, null>(
|
||||
assertExactType<typeof useQueryOnlyQueryTypeNoVarsWithOptionsVariables, null | undefined>(
|
||||
useQueryOnlyQueryTypeNoVarsWithOptionsVariables,
|
||||
)
|
||||
}
|
||||
@@ -161,14 +162,33 @@ import { assertExactType } from './assertions'
|
||||
)
|
||||
|
||||
const useQueryWithOptionsResult = useQueryWithOptions.result.value
|
||||
assertExactType<typeof useQueryWithOptionsResult, ExampleQuery>(useQueryWithOptionsResult)
|
||||
assertExactType<typeof useQueryWithOptionsResult, ExampleQuery | null | undefined>(useQueryWithOptionsResult)
|
||||
|
||||
const useQueryWithOptionsVariables = useQueryWithOptions.variables.value
|
||||
assertExactType<typeof useQueryWithOptionsVariables, ExampleQueryVariables>(
|
||||
assertExactType<typeof useQueryWithOptionsVariables, ExampleQueryVariables | undefined>(
|
||||
useQueryWithOptionsVariables,
|
||||
)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// With a TypedQueryDocument:
|
||||
// - TResult should be the query type
|
||||
// - TVariables should be OperationVariables
|
||||
// =============================================================================
|
||||
{
|
||||
const useQueryAllTyped = useQuery(ExampleTypedQueryDocument, {
|
||||
id: 'k3x47b',
|
||||
})
|
||||
|
||||
const useQueryAllTypedResult = useQueryAllTyped.result.value
|
||||
assertExactType<typeof useQueryAllTypedResult, ExampleQuery | null | undefined>(useQueryAllTypedResult)
|
||||
|
||||
const useQueryAllTypedVariables = useQueryAllTyped.variables.value
|
||||
assertExactType<typeof useQueryAllTypedVariables, ExampleQueryVariables | undefined>(
|
||||
useQueryAllTypedVariables,
|
||||
)
|
||||
}
|
||||
|
||||
// ====== Expected failures, uncomment to test ======
|
||||
|
||||
// // @ts-expect-error - should require variables to be OperationType
|
||||
|
||||
@@ -94,8 +94,8 @@ const { result: multiKeyResult } = multiKeyQuery
|
||||
assertExactType<typeof result, 'secret'>(result)
|
||||
useResult_WithDefaultValue_MultiKey.value
|
||||
} else {
|
||||
useResult_WithDefaultValue_MultiKey.value.example?.__typename
|
||||
useResult_WithDefaultValue_MultiKey.value.otherExample?.__typename
|
||||
useResult_WithDefaultValue_MultiKey.value?.example?.__typename
|
||||
useResult_WithDefaultValue_MultiKey.value?.otherExample?.__typename
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ const { result: multiKeyResult } = multiKeyQuery
|
||||
const useResult_WithPickFunction = useResult(
|
||||
multiKeyResult,
|
||||
[] as const,
|
||||
data => data.otherExample?.__typename,
|
||||
data => data?.otherExample?.__typename,
|
||||
)
|
||||
|
||||
assertExactType<
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
ExampleDocument,
|
||||
ExampleUpdatedSubscription,
|
||||
ExampleUpdatedSubscriptionVariables,
|
||||
ExampleTypedSubscriptionDocument,
|
||||
} from '../fixtures/graphql-example-types'
|
||||
import { assertExactType } from './assertions'
|
||||
|
||||
@@ -42,7 +43,7 @@ import { assertExactType } from './assertions'
|
||||
// Result type should match the passed in subscription type
|
||||
const useSubscription_OnlySubscriptionTypeResult =
|
||||
useSubscription_OnlySubscriptionType.result.value
|
||||
assertExactType<typeof useSubscription_OnlySubscriptionTypeResult, ExampleUpdatedSubscription>(
|
||||
assertExactType<typeof useSubscription_OnlySubscriptionTypeResult, ExampleUpdatedSubscription | null | undefined>(
|
||||
useSubscription_OnlySubscriptionTypeResult,
|
||||
)
|
||||
|
||||
@@ -69,13 +70,13 @@ import { assertExactType } from './assertions'
|
||||
|
||||
// Result type should match the passed in subscription type
|
||||
const useSubscription_WithVarsResult = useSubscription_WithVars.result.value
|
||||
assertExactType<typeof useSubscription_WithVarsResult, ExampleUpdatedSubscription>(
|
||||
assertExactType<typeof useSubscription_WithVarsResult, ExampleUpdatedSubscription | null | undefined>(
|
||||
useSubscription_WithVarsResult,
|
||||
)
|
||||
|
||||
// Variables type should match the passed in variables type
|
||||
const useSubscription_WithVarsVariables = useSubscription_WithVars.variables.value
|
||||
assertExactType<typeof useSubscription_WithVarsVariables, OperationVariables>(
|
||||
assertExactType<typeof useSubscription_WithVarsVariables, OperationVariables | undefined>(
|
||||
useSubscription_WithVarsVariables,
|
||||
)
|
||||
|
||||
@@ -96,13 +97,13 @@ import { assertExactType } from './assertions'
|
||||
|
||||
// Result type should match the passed in subscription type
|
||||
const useSubscription_AllTypedResult = useSubscription_AllTyped.result.value
|
||||
assertExactType<typeof useSubscription_AllTypedResult, ExampleUpdatedSubscription>(
|
||||
assertExactType<typeof useSubscription_AllTypedResult, ExampleUpdatedSubscription | null | undefined>(
|
||||
useSubscription_AllTypedResult,
|
||||
)
|
||||
|
||||
// Variables type should match the passed in variables type
|
||||
const useSubscription_AllTypedVariables = useSubscription_AllTyped.variables.value
|
||||
assertExactType<typeof useSubscription_AllTypedVariables, ExampleUpdatedSubscriptionVariables>(
|
||||
assertExactType<typeof useSubscription_AllTypedVariables, ExampleUpdatedSubscriptionVariables | undefined>(
|
||||
useSubscription_AllTypedVariables,
|
||||
)
|
||||
|
||||
@@ -123,13 +124,13 @@ import { assertExactType } from './assertions'
|
||||
|
||||
// Result type should match the passed in subscription type
|
||||
const useSubscription_AllTypedResult = useSubscription_AllTyped.result.value
|
||||
assertExactType<typeof useSubscription_AllTypedResult, ExampleUpdatedSubscription>(
|
||||
assertExactType<typeof useSubscription_AllTypedResult, ExampleUpdatedSubscription | null | undefined>(
|
||||
useSubscription_AllTypedResult,
|
||||
)
|
||||
|
||||
// Variables type should match the passed in variables type
|
||||
const useSubscription_AllTypedVariables = useSubscription_AllTyped.variables.value
|
||||
assertExactType<typeof useSubscription_AllTypedVariables, ExampleUpdatedSubscriptionVariables>(
|
||||
assertExactType<typeof useSubscription_AllTypedVariables, ExampleUpdatedSubscriptionVariables | undefined>(
|
||||
useSubscription_AllTypedVariables,
|
||||
)
|
||||
|
||||
@@ -154,7 +155,7 @@ import { assertExactType } from './assertions'
|
||||
useSubscription_OnlySubscriptionType_NoVarsWithOptions.result.value
|
||||
assertExactType<
|
||||
typeof useSubscription_OnlySubscriptionType_NoVarsWithOptionsResult,
|
||||
ExampleUpdatedSubscription
|
||||
ExampleUpdatedSubscription | null | undefined
|
||||
>(useSubscription_OnlySubscriptionType_NoVarsWithOptionsResult)
|
||||
|
||||
// Variables type should be `undefined`
|
||||
@@ -162,7 +163,7 @@ import { assertExactType } from './assertions'
|
||||
useSubscription_OnlySubscriptionType_NoVarsWithOptions.variables.value
|
||||
assertExactType<
|
||||
typeof useSubscription_OnlySubscriptionType_NoVarsWithOptionsVariables,
|
||||
null
|
||||
null | undefined
|
||||
>(useSubscription_OnlySubscriptionType_NoVarsWithOptionsVariables)
|
||||
|
||||
// Result data type should be the passed in result
|
||||
@@ -193,12 +194,12 @@ import { assertExactType } from './assertions'
|
||||
)
|
||||
|
||||
const useSubscription_WithOptionsResult = useSubscription_WithOptions.result.value
|
||||
assertExactType<typeof useSubscription_WithOptionsResult, ExampleUpdatedSubscription>(
|
||||
assertExactType<typeof useSubscription_WithOptionsResult, ExampleUpdatedSubscription | null | undefined>(
|
||||
useSubscription_WithOptionsResult,
|
||||
)
|
||||
|
||||
const useSubscription_WithOptionsVariables = useSubscription_WithOptions.variables.value
|
||||
assertExactType<typeof useSubscription_WithOptionsVariables, ExampleUpdatedSubscriptionVariables>(
|
||||
assertExactType<typeof useSubscription_WithOptionsVariables, ExampleUpdatedSubscriptionVariables | undefined>(
|
||||
useSubscription_WithOptionsVariables,
|
||||
)
|
||||
|
||||
@@ -206,6 +207,30 @@ import { assertExactType } from './assertions'
|
||||
useSubscription_WithOptions.onResult(result => result?.data?.exampleUpdated.name)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// With a TypedQueryDocument:
|
||||
// - TResult should be the subscription type
|
||||
// - TVariables should be the variables type
|
||||
// =============================================================================
|
||||
{
|
||||
const useSubscription_AllTyped = useSubscription(ExampleTypedSubscriptionDocument, { id: 'k3x47b' })
|
||||
|
||||
// Result type should match the passed in subscription type
|
||||
const useSubscription_AllTypedResult = useSubscription_AllTyped.result.value
|
||||
assertExactType<typeof useSubscription_AllTypedResult, ExampleUpdatedSubscription | null | undefined>(
|
||||
useSubscription_AllTypedResult,
|
||||
)
|
||||
|
||||
// Variables type should match the passed in variables type
|
||||
const useSubscription_AllTypedVariables = useSubscription_AllTyped.variables.value
|
||||
assertExactType<typeof useSubscription_AllTypedVariables, ExampleUpdatedSubscriptionVariables | undefined>(
|
||||
useSubscription_AllTypedVariables,
|
||||
)
|
||||
|
||||
// Result data type should be the passed in result
|
||||
useSubscription_AllTyped.onResult(result => result?.data?.exampleUpdated.name)
|
||||
}
|
||||
|
||||
// // ====== Expected failures, uncomment to test ======
|
||||
|
||||
// // @ts-expect-error - should require variables to be OperationType
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
"target": "es5",
|
||||
"module": "amd",
|
||||
"sourceMap": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node",
|
||||
"lib": [
|
||||
@@ -12,9 +12,10 @@
|
||||
"ES2015",
|
||||
"ES2020.Symbol.WellKnown"
|
||||
],
|
||||
"declaration": true
|
||||
"declaration": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
],
|
||||
}
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,8 +9,8 @@ import {
|
||||
SubscriptionOptions,
|
||||
OperationVariables,
|
||||
FetchResult,
|
||||
Observable
|
||||
} from '@apollo/client/core'
|
||||
import { Observable } from '@apollo/client/utilities/observables/Observable'
|
||||
import { ApolloProvider } from './apollo-provider'
|
||||
import {
|
||||
VueApolloQueryDefinition,
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"serialize-javascript": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/serialize-javascript": "^4.0.0",
|
||||
"typescript": "^4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export function getStates (apolloClients: ApolloClients, options: GetStatesOptio
|
||||
const finalOptions = Object.assign({}, {
|
||||
exportNamespace: '',
|
||||
}, options)
|
||||
const states = {}
|
||||
const states: Record<string, any> = {}
|
||||
for (const key in apolloClients) {
|
||||
const client = apolloClients[key]
|
||||
const state = client.cache.extract()
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"sourceMap": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
],
|
||||
}
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { print } from 'graphql/language/printer'
|
||||
import { ApolloError } from '@apollo/client/core'
|
||||
import { ErrorResponse } from '@apollo/client/link/error'
|
||||
|
||||
export function getErrorMessages (error) {
|
||||
export function getErrorMessages (error: ErrorResponse | ApolloError) {
|
||||
const messages: string[] = []
|
||||
const { graphQLErrors, networkError, operation, stack } = error
|
||||
let printedQuery
|
||||
const { graphQLErrors, networkError } = error
|
||||
const operation = 'operation' in error ? error.operation : undefined;
|
||||
const stack = 'stack' in error ? error.stack : undefined;
|
||||
let printedQuery: string;
|
||||
|
||||
if (operation) {
|
||||
printedQuery = print(operation.query)
|
||||
@@ -20,7 +24,7 @@ export function getErrorMessages (error) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if (networkError) messages.push(`[Network error] ${networkError}`)
|
||||
|
||||
if (stack) messages.push(stack)
|
||||
@@ -28,7 +32,7 @@ export function getErrorMessages (error) {
|
||||
return messages
|
||||
}
|
||||
|
||||
export function logErrorMessages (error, printStack = true) {
|
||||
export function logErrorMessages (error: ApolloError | ErrorResponse, printStack = true) {
|
||||
getErrorMessages(error).map(message => {
|
||||
const result = /\[([\w ]*)](.*)/.exec(message)
|
||||
if (result) {
|
||||
@@ -41,6 +45,8 @@ export function logErrorMessages (error, printStack = true) {
|
||||
|
||||
if (printStack) {
|
||||
let stack = new Error().stack
|
||||
if (stack == null) return
|
||||
|
||||
const newLineIndex = stack.indexOf('\n')
|
||||
stack = stack.substr(stack.indexOf('\n', newLineIndex + 1))
|
||||
console.log(`%c${stack}`, 'color:grey;')
|
||||
@@ -52,21 +58,25 @@ interface ErrorLocation {
|
||||
column: number
|
||||
}
|
||||
|
||||
function logOperation (printedQuery: string, locations: ErrorLocation[]) {
|
||||
function logOperation (printedQuery: string, locations: readonly ErrorLocation[] | undefined) {
|
||||
const lines = printedQuery.split('\n')
|
||||
const l = lines.length
|
||||
const result = lines.slice()
|
||||
const lineMap = {}
|
||||
const lineMap: Record<number, number> = {}
|
||||
for (let i = 0; i < l; i++) {
|
||||
lineMap[i] = i
|
||||
}
|
||||
for (const { line, column } of locations) {
|
||||
const index = lineMap[line]
|
||||
result.splice(index, 0, '▲'.padStart(column, ' '))
|
||||
// Offset remaining lines
|
||||
for (let i = index + 1; i < l; i++) {
|
||||
lineMap[i]++
|
||||
|
||||
if (locations) {
|
||||
for (const { line, column } of locations) {
|
||||
const index = lineMap[line]
|
||||
result.splice(index, 0, '▲'.padStart(column, ' '))
|
||||
// Offset remaining lines
|
||||
for (let i = index + 1; i < l; i++) {
|
||||
lineMap[i]++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.join('\n')
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
],
|
||||
}
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user