Skip to content

Commit

Permalink
(core) - Add built-in gql tag function (#1187)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
kitten authored Dec 3, 2020
1 parent 564ed1b commit 64668b3
Show file tree
Hide file tree
Showing 55 changed files with 880 additions and 211 deletions.
9 changes: 9 additions & 0 deletions .changeset/fair-flies-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@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 changes: 30 additions & 0 deletions docs/api/core.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,36 @@ errorExchange({

## 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
Expand Down
6 changes: 3 additions & 3 deletions docs/api/graphcache.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ The method will then attempt to read the entity according to the fragment entire
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`
Expand All @@ -303,7 +303,7 @@ present on the fragment itself.
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`
Expand Down Expand Up @@ -355,7 +355,7 @@ however the second argument, `data`, should not only contain properties that are
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`
Expand Down
84 changes: 84 additions & 0 deletions docs/basics/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -815,3 +815,87 @@ There are some more tricks we can use with `useQuery`. [Read more about its API
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/)


4 changes: 2 additions & 2 deletions docs/graphcache/computed-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ The store allows the user to also read a fragment for a certain entity, this fun
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`
Expand All @@ -157,7 +157,7 @@ const data = cache.readFragment(
```

> **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
Expand Down
6 changes: 3 additions & 3 deletions docs/graphcache/custom-updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ fragment. The second argument is the data that should be written to the cache. T
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`
Expand All @@ -121,7 +121,7 @@ cache.writeFragment(
```

> **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
Expand All @@ -130,7 +130,7 @@ to access the updated `Todo`. In such a case `cache.writeFragment` allows us to
manually:

```js
import gql from 'graphql-tag';
import { gql } from '@urql/core';

const cache = cacheExchange({
updates: {
Expand Down
3 changes: 1 addition & 2 deletions exchanges/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@
"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"
Expand Down
3 changes: 1 addition & 2 deletions exchanges/execute/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@
"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"
Expand Down
22 changes: 15 additions & 7 deletions exchanges/execute/src/execute.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
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';
Expand Down Expand Up @@ -31,19 +40,18 @@ const exchangeArgs = {
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', () => {
it('calls execute with args', async () => {
const context = 'USER_ID=123';
Expand Down
3 changes: 1 addition & 2 deletions exchanges/graphcache/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,7 @@
"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"
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/ast/traversal.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import gql from 'graphql-tag';
import { gql } from '@urql/core';
import { getSelectionSet } from './node';

import { getMainOperation, shouldInclude } from './traversal';
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/ast/variables.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import gql from 'graphql-tag';
import { gql } from '@urql/core';
import { getMainOperation } from './traversal';
import { normalizeVariables, filterVariables } from './variables';

Expand Down
3 changes: 1 addition & 2 deletions exchanges/graphcache/src/cacheExchange.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import gql from 'graphql-tag';

import {
gql,
createClient,
ExchangeIO,
Operation,
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/extras/relayPagination.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import gql from 'graphql-tag';
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';
import { relayPagination } from './relayPagination';
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/extras/simplePagination.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import gql from 'graphql-tag';
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';
import { simplePagination } from './simplePagination';
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/offlineExchange.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
gql,
createClient,
ExchangeIO,
Operation,
OperationResult,
formatDocument,
} from '@urql/core';

import gql from 'graphql-tag';
import { pipe, map, makeSubject, tap, publish } from 'wonka';
import { offlineExchange } from './offlineExchange';

Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/operations/query.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* 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';
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/operations/write.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* 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';
Expand Down
3 changes: 1 addition & 2 deletions exchanges/graphcache/src/store/store.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/* 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';
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/test-utils/examples-1.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
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';
Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/test-utils/examples-2.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import gql from 'graphql-tag';
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';

Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/test-utils/examples-3.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import gql from 'graphql-tag';
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';

Expand Down
2 changes: 1 addition & 1 deletion exchanges/graphcache/src/test-utils/suite.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DocumentNode } from 'graphql';
import gql from 'graphql-tag';
import { gql } from '@urql/core';
import { query, write } from '../operations';
import { Store } from '../store';

Expand Down
3 changes: 1 addition & 2 deletions exchanges/multipart-fetch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@
"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"
Expand Down
Loading

0 comments on commit 64668b3

Please sign in to comment.