Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(schema): Inference controls and improvements #13028

Merged
merged 35 commits into from
May 16, 2019
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ff596b9
WIP inference changes
freiksenet Mar 29, 2019
a88165c
Fixed all inferrence issues
freiksenet Apr 2, 2019
494f2e5
Reorder adding fields so field name resolving happens first
freiksenet Apr 2, 2019
b1fff33
Warnings and addResolver directives
freiksenet Apr 2, 2019
0ded10d
Kitchen sink tests
freiksenet Apr 3, 2019
354f11e
More fixes
freiksenet Apr 4, 2019
774ada4
Mapping via extensions
freiksenet Apr 4, 2019
ffa3960
Remove unused code
freiksenet Apr 4, 2019
fd57bb5
Fix comment
freiksenet Apr 4, 2019
5a6320f
Simplify some code, make some other code very complicated
freiksenet Apr 5, 2019
d065cb6
v2.4.0-alpha.1
freiksenet Apr 5, 2019
978e22e
Fix review comments
freiksenet Apr 5, 2019
1c2a501
[schema] Simplify type merging (#13557)
stefanprobst Apr 23, 2019
ce07eb1
Merge remote-tracking branch 'origin/master' into infer-fixing
freiksenet Apr 23, 2019
9ca160e
v2.4.0-alpha.2
freiksenet Apr 23, 2019
17d7857
More consistent naming
freiksenet Apr 24, 2019
c18d1e9
Ensure link() default arg (#13591)
stefanprobst Apr 24, 2019
9b2be71
[schema] Clarify warning message (#13693)
stefanprobst Apr 29, 2019
e40f6d2
Allow registering field extensions (#13623)
stefanprobst Apr 30, 2019
0a53e22
Revert "Allow registering field extensions (#13623)" (#13735)
stefanprobst Apr 30, 2019
9bad5a4
v2.4.0-alpha.3
freiksenet Apr 29, 2019
06b612a
Add blog post
freiksenet May 2, 2019
446c60a
Update docs
freiksenet May 2, 2019
2bcdc40
Fix link
freiksenet May 2, 2019
f2e1986
Improve docs
freiksenet May 2, 2019
5bf9bb8
[schema] Allow registering custom field extensions (#13738)
stefanprobst May 14, 2019
b8b96f9
Merge remote-tracking branch 'origin/master' into infer-fixing
freiksenet May 14, 2019
aee5186
Fix all addResolver uses
freiksenet May 15, 2019
daa2af3
v2.5.0-rc.1
freiksenet May 15, 2019
65e7504
Fix blog post
freiksenet May 15, 2019
b6c61e5
Apply suggestions from code review
freiksenet May 15, 2019
e76784c
Update packages/gatsby/src/redux/actions.js
stefanprobst May 15, 2019
69f179a
Update packages/gatsby/src/redux/actions.js
stefanprobst May 15, 2019
f338bdd
More blog post improvements
freiksenet May 15, 2019
1af8600
Merge branch 'master' into infer-fixing
freiksenet May 16, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions docs/blog/2019-05-17-improvements-to-schema-customization/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: Improvements to Schema Customization API - Available in Gatsby 2.4.0
freiksenet marked this conversation as resolved.
Show resolved Hide resolved
date: 2019-05-17
author: Mikhail Novikov
tags:
- schema
- graphql
---

Today we are releasing further improvements to the schema customization that [we've released in version 2.2.0](/blog/2019-03-18-releasing-new-schema-customization). You can use them with Gatsby 2.4.0.

It is now possible to indicate to Gatsby, that you want to add a resolver to an explicitly defined fields. Use extensions like `@link` and `@dateformat` to add default arguments or/and resolvers to fields. In addition, when `@dontInfer` is set, Gatsby will no longer run inference for marked type, allowing one to improve performance for large data sets.

## Summary

After about a month of testing schema customization both here and in pre-release we determined a couple of issues. We set up to do this because we wanted to remove uncertainty in people's schemas, when the data changes. However, the original design allowed some uncertainties anyway. In addition, we have made inferrence a more heavy process, trading performance for consistency and didn't really provide a way to opt out of it completely. To summarize:
freiksenet marked this conversation as resolved.
Show resolved Hide resolved

- Resolvers and arguments of fields like Date and File was determined by inferred data
- There was no easy way to use arguments/resolvers to override the above
- Inferrence was run even when `@dontInfer` flag was on
- There was no way to control inference outside of SDL, eg in Type Builders

Therefore we have some changes to the way we do inferrence. In addition, we are deprecating some of the features introduced is 2.2.0 and will remove them in Gatsby 3.
freiksenet marked this conversation as resolved.
Show resolved Hide resolved

m-allanson marked this conversation as resolved.
Show resolved Hide resolved
## noDefaultResolvers and inferrence modes

First of all, we are deprecating `noDefaultResolvers`. It was an argument of `infer` and `dontInfer`. We feel it was confusing and in some cases it didn't even actually add resolvers :). We will support `noDefaultResolvers` until version 3, after which `@infer` behaviour (see below) will become a default and `noDefaultResolvers` will be removed.
m-allanson marked this conversation as resolved.
Show resolved Hide resolved

We didn't want to break things, so we keep old default behaviour, even though we think it's not optimal. Add explicit `@infer` and resolver extensions (like `@link`) to fields to be future proof.

### Default (deprecated, removed in v3)

Applies with no `@infer` and no `@dontInfer` on a type. Equals to `@infer(noDefaultResolvers: false)`.

Type gets all inferred fields added. If type has defined fields of types `Date`, `File` and any other node, and we inferred that they should have resolver options, resolver options will be added to type with a warning.

### Strict inference (future default in v3)

Applies with `@infer` or `@infer(noDefaultResolvers: true)`.

Type gets all inferred fields added. Existing fields won't automatically get resolvers (use resolver extensions).

### No inferrence

Applies with `@dontInfer` or `@dontInfer(noDefaultResolvers: true)`.

Inferrence won't run at all. Existing fields won't automatically get resolvers (use resolver extensions).

### No new fields with default resolvers (deprecated, removed in v3)

Applies with `@dontInfer(noDefaultResolvers: false)`

Inferrence will run, but fields won't be added. If type has defined fields of types `Date`, `File` and any other node, and we inferred that they should have resolvers/args, resolvers/args will be added to type with a warning.

## Resolver extensions

Add resolver and resolver options (such as arguments) to the given field. There are currently 3 extensions available.

- `@dateformat` - add date formatting arguments. Accepts `formatString` and
`locale` options that sets the defaults for this field
- `@link` - connect to a different Node. Arguments `by` and `from`, which
define which field to compare to on a remote node and which field to use on
the source node
- `@fileByRelativePath` - connect to a File node. Same arguments. The
difference from link is that this normalizes the relative path to be
relative from the path where source node is found.

```graphql
type MyType @infer {
date: Date @dateformat(formatString: "DD MMM", locale: "fi")
image: File @fileByRelativePath
authorByEmail: Author @link(by: "email")
}
```

### Type Builders and extensions

You can now apply configuration to type builder types through extension property on them.

```js
schema.createObjectType({
name: MyType,
extensions: {
infer: true,
},
fields: {
date: {
type: "Date",
extensions: {
dateformat: {
formatString: "DD MMM",
locale: "fi",
},
},
},
},
})
```

## Conclusions

With these improvements we hope we'll solve most of the issues that people are having with new schema customization. We are working on further improvements, like allowing users and plugins to define their own extensions (see [PR #13738](https://github.com/gatsbyjs/gatsby/pull/13738)).

m-allanson marked this conversation as resolved.
Show resolved Hide resolved
Useful links:

- [createTypes Documentation](https://www.gatsbyjs.org/docs/actions/#createTypes)
- [Umbrella issue for schema customization bug reports](https://github.com/gatsbyjs/gatsby/issues/12272)
4 changes: 2 additions & 2 deletions packages/gatsby/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "gatsby",
"description": "Blazing fast modern site generator for React",
"version": "2.4.4",
"version": "2.5.0-rc.1",
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"bin": {
"gatsby": "./dist/bin/gatsby.js"
Expand Down Expand Up @@ -73,7 +73,7 @@
"glob": "^7.1.1",
"got": "8.0.0",
"graphql": "^14.1.1",
"graphql-compose": "6.0.3",
"graphql-compose": "^6.3.2",
"graphql-playground-middleware-express": "^1.7.10",
"hash-mod": "^0.0.5",
"invariant": "^2.2.4",
Expand Down
73 changes: 62 additions & 11 deletions packages/gatsby/src/redux/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1265,8 +1265,28 @@ import type GatsbyGraphQLType from "../schema/types/type-builders"
* with inferred field types, and default field resolvers for `Date` (which
* adds formatting options) and `File` (which resolves the field value as
* a `relativePath` foreign-key field) are added. This behavior can be
* customised with `@infer` and `@dontInfer` directives, and their
* `noDefaultResolvers` argument.
* customised with `@infer`, `@dontInfer` directives or extensions. Fields
* may be assigned resolver (and other option like args) with additional
* directives. Currently `@dateformat`, `@link` and `@fileByRelativePath` are
* available.
*
*
* Schema customization controls:
* * `@infer` - run inference on the type and add fields that don't exist on the
* defined type to it.
* * `@dontInfer` - don't run any inference on the type
*
* Extensions to add resolver options:
* * `@dateformat` - add date formatting arguments. Accepts `formatString` and
* `locale` options that sets the defaults for this field
* * `@link` - connect to a different Node. Arguments `by` and `from`, which
* define which field to compare to on a remote node and which field to use on
* the source node
* * `@fileByRelativePath` - connect to a File node. Same arguments. The
* difference from link is that this normalizes the relative path to be
* relative from the path where source node is found.
*
*
*
* @example
* exports.sourceNodes = ({ actions }) => {
Expand All @@ -1275,17 +1295,17 @@ import type GatsbyGraphQLType from "../schema/types/type-builders"
* """
* Markdown Node
* """
* type MarkdownRemark implements Node {
* type MarkdownRemark implements Node @infer {
* frontmatter: Frontmatter!
* }
*
* """
* Markdown Frontmatter
* """
* type Frontmatter {
* type Frontmatter @infer {
* title: String!
* author: AuthorJson!
* date: Date!
* author: AuthorJson! @link
* date: Date! @dateformat
* published: Boolean!
* tags: [String!]!
* }
Expand All @@ -1294,9 +1314,9 @@ import type GatsbyGraphQLType from "../schema/types/type-builders"
* Author information
* """
* # Does not include automatically inferred fields
* type AuthorJson implements Node @dontInfer(noFieldResolvers: true) {
* type AuthorJson implements Node @dontInfer {
* name: String!
* birthday: Date! # no default resolvers for Date formatting added
* birthday: Date! @date(locale: "ru")
stefanprobst marked this conversation as resolved.
Show resolved Hide resolved
* }
* `
* createTypes(typeDefs)
Expand All @@ -1312,6 +1332,9 @@ import type GatsbyGraphQLType from "../schema/types/type-builders"
* frontmatter: 'Frontmatter!'
* },
* interfaces: ['Node'],
* extensions: {
* infer: true,
* },
* }),
* schema.buildObjectType({
* name: 'Frontmatter',
Expand All @@ -1322,12 +1345,40 @@ import type GatsbyGraphQLType from "../schema/types/type-builders"
* return parent.title || '(Untitled)'
* }
* },
* author: 'AuthorJson!',
* date: 'Date!',
* author: {
* type: 'AuthorJson'
* extensions: {
* link: {},
* },
* }
* date: {
* type: 'Date!'
* extensions: {
* dateformat: {},
* },
* },
* published: 'Boolean!',
* tags: '[String!]!',
* }
* })
* }),
* schema.buildObjectType({
* name: 'AuthorJson',
* fields: {
* name: 'String!'
* birthday: {
* type: 'Date!'
* extensions: {
* date: {
stefanprobst marked this conversation as resolved.
Show resolved Hide resolved
* locale: 'ru',
* },
* },
* },
* },
* interfaces: ['Node'],
* extensions: {
* infer: false,
* },
* }),
* ]
* createTypes(typeDefs)
* }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Kichen sink schema test passes kitchen sink query 1`] = `
exports[`Kitchen sink schema test passes kitchen sink query 1`] = `
Object {
"data": Object {
"addResolvers": Array [
"createResolvers": Array [
Object {
"code": "BdiU-TTFP4h",
"id": "1685001452849004065",
Expand Down Expand Up @@ -43,6 +43,7 @@ Object {
"_3invalidKey": null,
"code": "BShF_8qhtEv",
"comment": 0,
"defaultTime": "05 huhtikuu",
"id": "1486495736706552111",
"idWithDecoration": "decoration-1486495736706552111",
"image": Object {
Expand All @@ -51,6 +52,8 @@ Object {
},
},
"likes": 8,
"localeFormat": "05 huhtikuu 2017",
"localeString": "05 апреля",
"time": "05.04.2017",
},
},
Expand All @@ -59,6 +62,7 @@ Object {
"_3invalidKey": null,
"code": "BY6B8z5lR1F",
"comment": 0,
"defaultTime": "11 syyskuu",
"id": "1601601194425654597",
"idWithDecoration": "decoration-1601601194425654597",
"image": Object {
Expand All @@ -67,6 +71,8 @@ Object {
},
},
"likes": 9,
"localeFormat": "11 syyskuu 2017",
"localeString": "11 сентября",
"time": "11.09.2017",
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,7 @@
"nodeAPIs": [
"createPages",
"sourceNodes",
"addResolvers"
"createResolvers"
],
"browserAPIs": [
"shouldUpdateScroll",
Expand Down
Loading