Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.

(core) - Add built-in gql tag function (#1187)

* Add built-in gql function

* Add inner document source to DocumentNodes from gql

* Update tests to use new gql helper

* Protect against invalid inputs in gql

* Fix up execute tests

* Fix linting issues in gql.ts

* Add basic tests for gql tag

* Shave some bytes off of cacheExchange

* Simplify composeExchanges helper

* Replace all usages of graphql-tag

* Update entries in docs

* Add changeset

* Revert changes / Update snapshot

* Fix linting issues in populate and core

* Add core / gql section to Queries page

+9
.changeset/fair-flies-grab.md
···
+
---
+
'@urql/core': minor
+
'@urql/preact': patch
+
'urql': patch
+
'@urql/svelte': patch
+
'@urql/vue': patch
+
---
+
+
Add a built-in `gql` tag function helper to `@urql/core`. This behaves similarly to `graphql-tag` but only warns about _locally_ duplicated fragment names rather than globally. It also primes `@urql/core`'s key cache with the parsed `DocumentNode`.
+30
docs/api/core.md
···
## Utilities
+
### gql
+
+
This is a `gql` tagged template literal function, similar to the one that's also commonly known from
+
`graphql-tag`. It can be used to write GraphQL documents in a tagged template literal and returns a
+
parsed `DocumentNode` that's primed against the `createRequest`'s cache for `key`s.
+
+
```js
+
import { gql } from '@urql/core';
+
+
const SharedFragment = gql`
+
fragment UserFrag on User {
+
id
+
name
+
}
+
`;
+
+
gql`
+
query {
+
user
+
...UserFrag
+
}
+
+
${SharedFragment}
+
`;
+
```
+
+
Unlike `graphql-tag`, this function outputs a warning in development when names of fragments in the
+
document are duplicated. It does not output warnings when fragment names were duplicated globally
+
however.
+
### stringifyVariables
This function is a variation of `JSON.stringify` that sorts any object's keys that is being
+3 -3
docs/api/graphcache.md
···
data. If any data is uncached and missing it'll return `null`.
```js
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
cache.readFragment(
gql`
···
If any fields on the fragment require variables, you can pass them as the third argument like so:
```js
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
cache.readFragment(
gql`
···
an entity key from the given data, but also the fields that will be written:
```js
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
cache.writeFragment(
gql`
+84
docs/basics/queries.md
···
it.](../api/vue.md#usequery)
[On the next page we'll learn about "Mutations" rather than Queries.](./mutations.md#vue)
+
+
## Core
+
+
All framework bindings — meaning `urql`, `@urql/preact`, `@urql/svelte`, and `@urql/vue` — reexport
+
all exports of our `@urql/core` core library. This package contains the
+
[`Client`](../api/core.md#client), built-in exchanges, and other utilities that are shared between
+
all bindings.
+
+
### gql
+
+
A notable utility function is the `gql` tagged template literal function, which is a drop-in
+
replacement for `graphql-tag`, if you're coming from other GraphQL clients.
+
+
Wherever `urql` accepts a query document, you may either pass a string or a `DocumentNode`. `gql` is
+
a utility that allows a `DocumentNode` to be created directly, and others to be interpolated into
+
it, which is useful for fragments for instance. This function will often also mark GraphQL documents
+
for syntax highlighting in most code editors.
+
+
In most examples we may have passed a string to define a query document, like so:
+
+
```js
+
const TodosQuery = `
+
query {
+
todos {
+
id
+
title
+
}
+
}
+
`;
+
```
+
+
We may also use the `gql` tag function to create a `DocumentNode` directly:
+
+
```js
+
import { gql } from '@urql/core';
+
+
const TodosQuery = gql`
+
query {
+
todos {
+
id
+
title
+
}
+
}
+
`;
+
```
+
+
Since all framework bindings also re-export `@urql/core`, we may also import `gql` from `'urql'`,
+
`'@urql/svelte'` and other bindings directly.
+
+
We can also start interpolating other documents into the tag function. This is useful to compose
+
fragment documents into a larger query, since it's common to define fragments across components of
+
an app to spread out data dependencies. If we accidentally use a duplicate fragment name in a
+
document, `gql` will log a warning, since GraphQL APIs won't accept duplicate names.
+
+
```js
+
import { gql } from '@urql/core';
+
+
const TodoFragment = gql`
+
fragment SmallTodo on Todo {
+
id
+
title
+
}
+
`;
+
+
const TodosQuery = gql`
+
query {
+
todos {
+
...TodoFragment
+
}
+
}
+
+
${TodoFragment}
+
`;
+
```
+
+
### Reading on
+
+
There are some more utilities that `@urql/core` exports. [All of them are listed in the API docs for
+
it.](../api/core.md)
+
+
[Read more about the `@urql/core` library on the "Core Package"
+
page.](https://formidable.com/open-source/urql/docs/concepts/core-package/)
+
+
+2 -2
docs/graphcache/computed-queries.md
···
accepts a `fragment` and an `id`. This looks like the following.
```js
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
const data = cache.readFragment(
gql`
···
```
> **Note:** In the above example, we've used
-
> [graphql-tag](https://github.com/apollographql/graphql-tag) because `writeFragment` only accepts
+
> [the `gql` tag function](../api/core.md#gql) because `readFragment` only accepts
> GraphQL `DocumentNode`s as inputs, and not strings.
This way we'll get the Todo with id 1 and the relevant data we are asking for in the
+3 -3
docs/graphcache/custom-updates.md
···
contain `id` or another field if the type has a custom `keys` configuration.
```js
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
cache.writeFragment(
gql`
···
```
> **Note:** In the above example, we've used
-
> [graphql-tag](https://github.com/apollographql/graphql-tag) because `writeFragment` only accepts
+
> [the `gql` tag function](../api/core.md#gql) because `writeFragment` only accepts
> GraphQL `DocumentNode`s as inputs, and not strings.
This can be useful for instance if we have a mutation that doesn't return the type that the GraphQL
···
manually:
```js
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
const cache = cacheExchange({
updates: {
+1 -2
exchanges/auth/package.json
···
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
},
"devDependencies": {
-
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1"
+
"graphql": "^15.4.0"
},
"publishConfig": {
"access": "public"
+1 -2
exchanges/execute/package.json
···
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
},
"devDependencies": {
-
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1"
+
"graphql": "^15.4.0"
},
"publishConfig": {
"access": "public"
+15 -7
exchanges/execute/src/execute.test.ts
···
-
jest.mock('graphql');
+
jest.mock('graphql', () => {
+
const graphql = jest.requireActual('graphql');
+
+
return {
+
__esModule: true,
+
...graphql,
+
print: jest.fn(a => a as any),
+
execute: jest.fn(() => ({ key: 'value' })),
+
};
+
});
import { fetchExchange } from 'urql';
import { executeExchange } from './execute';
···
const expectedOperationName = getOperationName(queryOperation.query);
const fetchMock = (global as any).fetch as jest.Mock;
-
afterEach(() => {
-
fetchMock.mockClear();
-
});
-
const mockHttpResponseData = { key: 'value' };
-
-
beforeEach(jest.clearAllMocks);
beforeEach(() => {
+
jest.clearAllMocks();
mocked(print).mockImplementation(a => a as any);
mocked(execute).mockResolvedValue({ data: mockHttpResponseData });
+
});
+
+
afterEach(() => {
+
fetchMock.mockClear();
});
describe('on operation', () => {
+1 -2
exchanges/graphcache/package.json
···
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
},
"devDependencies": {
-
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1"
+
"graphql": "^15.4.0"
},
"publishConfig": {
"access": "public"
+1 -1
exchanges/graphcache/src/ast/traversal.test.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { getSelectionSet } from './node';
import { getMainOperation, shouldInclude } from './traversal';
+1 -1
exchanges/graphcache/src/ast/variables.test.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { getMainOperation } from './traversal';
import { normalizeVariables, filterVariables } from './variables';
+1 -2
exchanges/graphcache/src/cacheExchange.test.ts
···
-
import gql from 'graphql-tag';
-
import {
+
gql,
createClient,
ExchangeIO,
Operation,
+1 -1
exchanges/graphcache/src/extras/relayPagination.test.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';
import { relayPagination } from './relayPagination';
+1 -1
exchanges/graphcache/src/extras/simplePagination.test.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';
import { simplePagination } from './simplePagination';
+1 -1
exchanges/graphcache/src/offlineExchange.test.ts
···
import {
+
gql,
createClient,
ExchangeIO,
Operation,
···
formatDocument,
} from '@urql/core';
-
import gql from 'graphql-tag';
import { pipe, map, makeSubject, tap, publish } from 'wonka';
import { offlineExchange } from './offlineExchange';
+1 -1
exchanges/graphcache/src/operations/query.test.ts
···
/* eslint-disable @typescript-eslint/no-var-requires */
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { minifyIntrospectionQuery } from '@urql/introspection';
import { Store } from '../store';
+1 -1
exchanges/graphcache/src/operations/write.test.ts
···
/* eslint-disable @typescript-eslint/no-var-requires */
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { minifyIntrospectionQuery } from '@urql/introspection';
import { write } from './write';
+1 -2
exchanges/graphcache/src/store/store.test.ts
···
/* eslint-disable @typescript-eslint/no-var-requires */
-
import gql from 'graphql-tag';
import { minifyIntrospectionQuery } from '@urql/introspection';
-
import { maskTypename } from '@urql/core';
+
import { gql, maskTypename } from '@urql/core';
import { mocked } from 'ts-jest/utils';
import { Data, StorageAdapter } from '../types';
+1 -1
exchanges/graphcache/src/test-utils/examples-1.test.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { query, write, writeOptimistic } from '../operations';
import * as InMemoryData from '../store/data';
import { Store } from '../store';
+1 -1
exchanges/graphcache/src/test-utils/examples-2.test.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';
+1 -1
exchanges/graphcache/src/test-utils/examples-3.test.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';
+1 -1
exchanges/graphcache/src/test-utils/suite.test.ts
···
import { DocumentNode } from 'graphql';
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';
+1 -2
exchanges/multipart-fetch/package.json
···
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
},
"devDependencies": {
-
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1"
+
"graphql": "^15.4.0"
},
"publishConfig": {
"access": "public"
+179
exchanges/multipart-fetch/src/__snapshots__/multipartFetchExchange.test.ts.snap
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "mutation",
"operationName": "mutation",
"query": Object {
+
"__key": 3781860981,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "uploadProfilePicture",
},
"operation": "mutation",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "picture",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "picture",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "uploadProfilePicture",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "location",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "File",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "picture",
},
},
···
"kind": "Document",
"loc": Object {
"end": 134,
+
"source": Source {
+
"body": "
+
mutation uploadProfilePicture($picture: File) {
+
uploadProfilePicture(picture: $picture) {
+
location
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "mutation",
"operationName": "mutation",
"query": Object {
+
"__key": 1193185401,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "uploadProfilePictures",
},
"operation": "mutation",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "pictures",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "pictures",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "uploadProfilePicture",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "location",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "ListType",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "File",
},
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "pictures",
},
},
···
"kind": "Document",
"loc": Object {
"end": 140,
+
"source": Source {
+
"body": "
+
mutation uploadProfilePictures($pictures: [File]) {
+
uploadProfilePicture(pictures: $pictures) {
+
location
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
+1 -1
exchanges/multipart-fetch/src/test-utils.ts
···
import {
+
gql,
GraphQLRequest,
OperationContext,
Operation,
makeOperation,
} from '@urql/core';
-
import gql from 'graphql-tag';
const context: OperationContext = {
fetchOptions: {
+1 -2
exchanges/persisted-fetch/package.json
···
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
},
"devDependencies": {
-
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1"
+
"graphql": "^15.4.0"
},
"publishConfig": {
"access": "public"
+1 -1
exchanges/persisted-fetch/src/test-utils.ts
···
import {
+
gql,
GraphQLRequest,
OperationContext,
Operation,
makeOperation,
} from '@urql/core';
-
import gql from 'graphql-tag';
const context: OperationContext = {
fetchOptions: {
+1 -2
exchanges/populate/package.json
···
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
},
"devDependencies": {
-
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1"
+
"graphql": "^15.4.0"
},
"publishConfig": {
"access": "public"
+7 -2
exchanges/populate/src/populateExchange.test.ts
···
ASTKindToNode,
} from 'graphql';
-
import gql from 'graphql-tag';
import { fromValue, pipe, fromArray, toArray } from 'wonka';
-
import { Client, Operation, OperationContext, makeOperation } from '@urql/core';
+
import {
+
gql,
+
Client,
+
Operation,
+
OperationContext,
+
makeOperation,
+
} from '@urql/core';
import { populateExchange } from './populateExchange';
+2 -2
exchanges/refocus/src/refocusExchange.test.ts
···
-
import gql from 'graphql-tag';
-
import { pipe, map, makeSubject, publish, tap } from 'wonka';
import {
+
gql,
createClient,
Operation,
OperationResult,
ExchangeIO,
} from '@urql/core';
+
import { refocusExchange } from './refocusExchange';
const dispatchDebug = jest.fn();
+2 -2
exchanges/request-policy/src/requestPolicyExchange.test.ts
···
-
import gql from 'graphql-tag';
-
import { pipe, map, makeSubject, publish, tap } from 'wonka';
import {
+
gql,
createClient,
Operation,
OperationResult,
ExchangeIO,
} from '@urql/core';
+
import { requestPolicyExchange } from './requestPolicyExchange';
const dispatchDebug = jest.fn();
+2 -2
exchanges/retry/src/retryExchange.test.ts
···
-
import gql from 'graphql-tag';
-
import { pipe, map, makeSubject, publish, tap } from 'wonka';
import {
+
gql,
createClient,
Operation,
OperationResult,
ExchangeIO,
} from '@urql/core';
+
import { retryExchange } from './retryExchange';
const dispatchDebug = jest.fn();
-1
package.json
···
"execa": "^4.1.0",
"glob": "^7.1.6",
"graphql": "^15.4.0",
-
"graphql-tag": "^2.11.0",
"husky": "^4.3.0",
"invariant": "^2.2.4",
"jest": "^26.6.3",
+1 -2
packages/core/package.json
···
"preset": "../../scripts/jest/preset"
},
"devDependencies": {
-
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1"
+
"graphql": "^15.4.0"
},
"peerDependencies": {
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
+1 -1
packages/core/src/client.test.ts
···
import { print } from 'graphql';
-
import gql from 'graphql-tag';
/** NOTE: Testing in this file is designed to test both the client and its interaction with default Exchanges */
import { Source, map, pipe, subscribe, filter, toArray, tap } from 'wonka';
+
import { gql } from './gql';
import { Exchange, Operation, OperationResult } from './types';
import { createClient } from './client';
import { queryOperation } from './test-utils';
+114
packages/core/src/exchanges/__snapshots__/fetch.test.ts.snap
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
+32
packages/core/src/exchanges/__snapshots__/subscription.test.ts.snap
···
"kind": "subscription",
"operationName": "subscription",
"query": Object {
+
"__key": 2616620656,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "subscribeToUser",
},
"operation": "subscription",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
},
···
"kind": "Document",
"loc": Object {
"end": 106,
+
"source": Source {
+
"body": "
+
subscription subscribeToUser($user: String) {
+
user(user: $user) {
+
name
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
+1 -58
packages/core/src/exchanges/cache.test.ts
···
undefinedQueryResponse,
} from '../test-utils';
import { Operation, OperationResult, ExchangeInput } from '../types';
-
import { afterMutation, cacheExchange } from './cache';
+
import { cacheExchange } from './cache';
const reexecuteOperation = jest.fn();
const dispatchDebug = jest.fn();
···
complete();
expect(forwardedOperations.length).toBe(2);
expect(reexecuteOperation).not.toBeCalled();
-
});
-
-
it('retriggers query operation', () => {
-
const typename = 'ExampleType';
-
const resultCache = new Map([[123, queryResponse]]);
-
const operationCache = { [typename]: new Set([123]) };
-
-
afterMutation(
-
resultCache,
-
operationCache,
-
exchangeArgs.client,
-
dispatchDebug
-
)({
-
...mutationResponse,
-
data: {
-
todos: [
-
{
-
id: 1,
-
__typename: typename,
-
},
-
],
-
},
-
});
-
-
expect(reexecuteOperation).toBeCalledTimes(1);
-
});
-
-
it('retriggers query operation with additionalTypenames', () => {
-
const typename = 'ExampleType';
-
const resultCache = new Map([[123, queryResponse]]);
-
const operationCache = { [`${typename}-2`]: new Set([123]) };
-
-
afterMutation(
-
resultCache,
-
operationCache,
-
exchangeArgs.client,
-
dispatchDebug
-
)({
-
...mutationResponse,
-
operation: {
-
...mutationResponse.operation,
-
context: {
-
...mutationResponse.operation.context,
-
additionalTypenames: [`${typename}-2`],
-
},
-
},
-
data: {
-
todos: [
-
{
-
id: 1,
-
__typename: typename,
-
},
-
],
-
},
-
});
-
-
expect(reexecuteOperation).toBeCalledTimes(1);
});
});
+47 -78
packages/core/src/exchanges/cache.ts
···
import { filter, map, merge, pipe, share, tap } from 'wonka';
import { Client } from '../client';
-
import { Exchange, Operation, OperationResult, ExchangeInput } from '../types';
+
import { Exchange, Operation, OperationResult } from '../types';
import {
makeOperation,
···
formattedOperation.query = formatDocument(operation.query);
return formattedOperation;
};
-
-
const handleAfterMutation = afterMutation(
-
resultCache,
-
operationCache,
-
client,
-
dispatchDebug
-
);
-
-
const handleAfterQuery = afterQuery(resultCache, operationCache);
const isOperationCached = (operation: Operation) => {
const {
···
),
forward,
tap(response => {
-
if (response.operation && response.operation.kind === 'mutation') {
-
handleAfterMutation(response);
-
} else if (response.operation && response.operation.kind === 'query') {
-
handleAfterQuery(response);
+
let { operation } = response;
+
if (!operation) return;
+
+
const typenames = collectTypesFromResponse(response.data).concat(
+
operation.context.additionalTypenames || []
+
);
+
+
// Invalidates the cache given a mutation's response
+
if (response.operation.kind === 'mutation') {
+
const pendingOperations = new Set<number>();
+
+
dispatchDebug({
+
type: 'cacheInvalidation',
+
message: `The following typenames have been invalidated: ${typenames}`,
+
operation,
+
data: { typenames, response },
+
});
+
+
for (let i = 0; i < typenames.length; i++) {
+
const typeName = typenames[i];
+
const operations =
+
operationCache[typeName] ||
+
(operationCache[typeName] = new Set());
+
operations.forEach(key => {
+
pendingOperations.add(key);
+
});
+
operations.clear();
+
}
+
+
pendingOperations.forEach(key => {
+
if (resultCache.has(key)) {
+
operation = (resultCache.get(key) as OperationResult).operation;
+
resultCache.delete(key);
+
reexecuteOperation(client, operation);
+
}
+
});
+
// Mark typenames on typenameInvalidate for early invalidation
+
} else if (operation.kind === 'query' && response.data) {
+
resultCache.set(operation.key, response);
+
for (let i = 0; i < typenames.length; i++) {
+
const typeName = typenames[i];
+
const operations =
+
operationCache[typeName] ||
+
(operationCache[typeName] = new Set());
+
operations.add(operation.key);
+
}
}
})
);
···
})
);
};
-
-
// Invalidates the cache given a mutation's response
-
export const afterMutation = (
-
resultCache: ResultCache,
-
operationCache: OperationCache,
-
client: Client,
-
dispatchDebug: ExchangeInput['dispatchDebug']
-
) => (response: OperationResult) => {
-
const pendingOperations = new Set<number>();
-
const { additionalTypenames } = response.operation.context;
-
-
const typenames = [
-
...collectTypesFromResponse(response.data),
-
...(additionalTypenames || []),
-
];
-
-
dispatchDebug({
-
type: 'cacheInvalidation',
-
message: `The following typenames have been invalidated: ${typenames}`,
-
operation: response.operation,
-
data: { typenames, response },
-
});
-
-
typenames.forEach(typeName => {
-
const operations =
-
operationCache[typeName] || (operationCache[typeName] = new Set());
-
operations.forEach(key => {
-
pendingOperations.add(key);
-
});
-
operations.clear();
-
});
-
-
pendingOperations.forEach(key => {
-
if (resultCache.has(key)) {
-
const operation = (resultCache.get(key) as OperationResult).operation;
-
resultCache.delete(key);
-
reexecuteOperation(client, operation);
-
}
-
});
-
};
-
-
// Mark typenames on typenameInvalidate for early invalidation
-
const afterQuery = (
-
resultCache: ResultCache,
-
operationCache: OperationCache
-
) => (response: OperationResult) => {
-
const { operation, data, error } = response;
-
const { additionalTypenames } = operation.context;
-
-
if (data === undefined || data === null) {
-
return;
-
}
-
-
resultCache.set(operation.key, { operation, data, error });
-
-
[
-
...collectTypesFromResponse(response.data),
-
...(additionalTypenames || []),
-
].forEach(typeName => {
-
const operations =
-
operationCache[typeName] || (operationCache[typeName] = new Set());
-
operations.add(operation.key);
-
});
-
};
+60
packages/core/src/gql.test.ts
···
+
import { Source, parse, print } from 'graphql';
+
import { gql } from './gql';
+
import { keyDocument } from './utils';
+
+
it('parses GraphQL Documents', () => {
+
expect(gql('{ test }').definitions).toEqual(
+
parse('{ test }', { noLocation: true }).definitions
+
);
+
expect(gql('{ test }')).toBe(keyDocument('{ test }'));
+
+
expect(gql('{ test }').loc).toEqual({
+
start: 0,
+
end: 8,
+
source: new Source('{ test }', 'gql'),
+
});
+
});
+
+
it('interpolates nested GraphQL Documents', () => {
+
expect(
+
print(
+
gql`
+
query {
+
...Query
+
}
+
+
${gql`
+
fragment Query on Query {
+
field
+
}
+
`}
+
`
+
)
+
).toMatchInlineSnapshot(`
+
"{
+
...Query
+
}
+
+
fragment Query on Query {
+
field
+
}
+
"
+
`);
+
});
+
+
it('interpolates strings', () => {
+
expect(
+
print(
+
gql`
+
query {
+
${'field'}
+
}
+
`
+
)
+
).toMatchInlineSnapshot(`
+
"{
+
field
+
}
+
"
+
`);
+
});
+64
packages/core/src/gql.ts
···
+
/* eslint-disable prefer-rest-params */
+
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
+
import { Source, Location, DocumentNode, Kind, print } from 'graphql';
+
import { keyDocument } from './utils';
+
+
type WritableDocumentNode = {
+
-readonly [K in keyof DocumentNode]: DocumentNode[K];
+
};
+
+
function gql<Data = any, Variables = object>(
+
strings: TemplateStringsArray,
+
...interpolations: Array<TypedDocumentNode | DocumentNode | string>
+
): TypedDocumentNode<Data, Variables>;
+
+
function gql<Data = any, Variables = object>(
+
string: string
+
): TypedDocumentNode<Data, Variables>;
+
+
function gql(/* arguments */) {
+
let body: string = Array.isArray(arguments[0])
+
? arguments[0][0]
+
: arguments[0] || '';
+
for (let i = 1; i < arguments.length; i++) {
+
const value = arguments[i];
+
body +=
+
value && value.kind === Kind.DOCUMENT
+
? value.loc
+
? value.loc.source.body
+
: print(value)
+
: value;
+
body += arguments[0][i];
+
}
+
+
const doc = keyDocument(body);
+
if (process.env.NODE_ENV !== 'production') {
+
const fragmentNames = new Set();
+
for (let i = 0; i < doc.definitions.length; i++) {
+
const definition = doc.definitions[i];
+
if (definition.kind === Kind.FRAGMENT_DEFINITION) {
+
const name = definition.name.value;
+
if (fragmentNames.has(name)) {
+
console.warn(
+
'[WARNING: Duplicate Fragment] A fragment with name `' +
+
name +
+
'` already exists in this document.\n' +
+
'While fragment names may not be unique across your source, each name must be unique per document.'
+
);
+
} else {
+
fragmentNames.add(name);
+
}
+
}
+
}
+
}
+
+
(doc as WritableDocumentNode).loc = {
+
start: 0,
+
end: body.length,
+
source: new Source(body, 'gql'),
+
} as Location;
+
+
return doc;
+
}
+
+
export { gql };
+1
packages/core/src/index.ts
···
export { TypedDocumentNode } from '@graphql-typed-document-node/core';
+
export { gql } from './gql';
export * from './client';
export * from './exchanges';
+190
packages/core/src/internal/__snapshots__/fetchSource.test.ts.snap
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
···
"kind": "query",
"operationName": "query",
"query": Object {
+
"__key": 3044551916,
"definitions": Array [
Object {
"directives": Array [],
"kind": "OperationDefinition",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "getUser",
},
"operation": "query",
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [
Object {
"kind": "Argument",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
"value": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "user",
},
"selectionSet": Object {
"kind": "SelectionSet",
+
"loc": undefined,
"selections": Array [
Object {
"alias": undefined,
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "id",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "firstName",
},
"selectionSet": undefined,
···
"arguments": Array [],
"directives": Array [],
"kind": "Field",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "lastName",
},
"selectionSet": undefined,
···
"defaultValue": undefined,
"directives": Array [],
"kind": "VariableDefinition",
+
"loc": undefined,
"type": Object {
"kind": "NamedType",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "String",
},
},
"variable": Object {
"kind": "Variable",
+
"loc": undefined,
"name": Object {
"kind": "Name",
+
"loc": undefined,
"value": "name",
},
},
···
"kind": "Document",
"loc": Object {
"end": 124,
+
"source": Source {
+
"body": "
+
query getUser($name: String) {
+
user(name: $name) {
+
id
+
firstName
+
lastName
+
}
+
}
+
",
+
"locationOffset": Object {
+
"column": 1,
+
"line": 1,
+
},
+
"name": "gql",
+
},
"start": 0,
},
},
+1 -1
packages/core/src/test-utils/samples.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '../gql';
import {
ExecutionResult,
+1 -1
packages/core/src/utils/request.test.ts
···
import { parse, print } from 'graphql';
-
import gql from 'graphql-tag';
+
import { gql } from '../gql';
import { createRequest } from './request';
it('should hash identical queries identically', () => {
+1 -2
packages/introspection/package.json
···
"preset": "../../scripts/jest/preset"
},
"devDependencies": {
-
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1"
+
"graphql": "^15.4.0"
},
"peerDependencies": {
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0"
-1
packages/next-urql/package.json
···
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.3",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-is": "^17.0.1"
-1
packages/preact-urql/package.json
···
"devDependencies": {
"@testing-library/preact": "^2.0.0",
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1",
"preact": "^10.5.5"
},
"peerDependencies": {
+2 -2
packages/preact-urql/src/hooks/useMutation.test.tsx
···
import { FunctionalComponent as FC, h } from 'preact';
import { render, cleanup, act } from '@testing-library/preact';
import { print } from 'graphql';
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { useMutation } from './useMutation';
import { fromValue, delay, pipe } from 'wonka';
import { Provider } from '../context';
···
const call = client.executeMutation.mock.calls[0][0];
expect(state).toHaveProperty('fetching', true);
expect(client.executeMutation).toBeCalledTimes(1);
-
expect(print(call.query)).toBe(print(gql([props.query])));
+
expect(print(call.query)).toBe(print(gql(props.query)));
expect(call).toHaveProperty('variables', vars);
});
-1
packages/react-urql/package.json
···
"@types/react": "^16.9.56",
"@types/react-test-renderer": "^16.9.3",
"graphql": "^15.4.0",
-
"graphql-tag": "^2.10.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-is": "^17.0.1",
+2 -2
packages/react-urql/src/hooks/useMutation.test.tsx
···
});
import { print } from 'graphql';
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import React, { FC } from 'react';
import renderer, { act } from 'react-test-renderer';
···
});
const call = client.executeMutation.mock.calls[0][0];
-
expect(print(call.query)).toBe(print(gql([props.query])));
+
expect(print(call.query)).toBe(print(gql(props.query)));
});
it('calls executeMutation with variables', () => {
+1 -1
packages/react-urql/src/hooks/useRequest.test.ts
···
-
import gql from 'graphql-tag';
+
import { gql } from '@urql/core';
import { renderHook } from '@testing-library/react-hooks';
import { useRequest } from './useRequest';
+1 -1
packages/react-urql/src/test-utils/ssr.test.tsx
···
import React from 'react';
-
import gql from 'graphql-tag';
import prepass from 'react-ssr-prepass';
import { never, publish, filter, delay, pipe, map } from 'wonka';
import {
+
gql,
createClient,
Exchange,
dedupExchange,
+1 -6
yarn.lock
···
"@typescript-eslint/types" "4.6.1"
eslint-visitor-keys "^2.0.0"
-
"@urql/devtools@^2.0.2":
+
"@urql/devtools@>=2.0.0":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@urql/devtools/-/devtools-2.0.2.tgz#0991bc3bb09444b162ef56518b76f64f286954fc"
integrity sha512-f3gIx4NDOuWdXC54m4VQlLKNtYHl6PITSEqexH6xiktzvH7QcwS5hNPg0Fkki8cas/DZtkmDpwxNV1uRZ5xlvA==
···
version "1.0.4"
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
-
-
graphql-tag@^2.10.1, graphql-tag@^2.10.3, graphql-tag@^2.11.0:
-
version "2.11.0"
-
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.11.0.tgz#1deb53a01c46a7eb401d6cb59dec86fa1cccbffd"
-
integrity sha512-VmsD5pJqWJnQZMUeRwrDhfgoyqcfwEkvtpANqcoUG8/tOLkwNgU9mzub/Mc78OJMhHjx7gfAMTxzdG43VGg3bA==
graphql@^15.1.0, graphql@^15.4.0:
version "15.4.0"