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

Log type conflics when inferring graphql types #3905

Merged
merged 15 commits into from
Apr 14, 2018

Conversation

pieh
Copy link
Contributor

@pieh pieh commented Feb 8, 2018

This adds logging discarded/omitted fields that have conflicting types.

Example of output:

success update schema — 0.152 s
warning There are conflicting field types in your data. GraphQL schema will omit those fields.
SitePage.context.previous:
 - boolean: false
 - object: { fields: [Object], frontmatter: [Object] }
SitePage.context.next:
 - boolean: false
 - object: { fields: [Object], frontmatter: [Object] }
MarkdownRemark.frontmatter.scalarTest:
 - boolean: true (File "src\pages\my-second-post\index.md")
 - number: 5 (File "src\pages\hi-folks\index.md")
 - string: 'string' (File "src\pages\hello-world\index.md")
MarkdownRemark.frontmatter.scalarObjectTest:
 - object: { prop: true, a3: true } (File "src\pages\hello-world\index.md")
 - string: 'string' (File "src\pages\my-second-post\index.md")
MarkdownRemark.frontmatter.objectArrayTest:
 - array<number>: [ 5 ] (File "src\pages\hello-world\index.md")
 - object: { prop: true } (File "src\pages\hi-folks\index.md")
MarkdownRemark.frontmatter.mixedArrayInSingleNodeTest:
 - array<number|string>: [ 5, ..., 'string', ... ] (File "src\pages\hello-world\index.md")
MarkdownRemark.frontmatter.mixedArrayInDifferentNodesTest:
 - array<number>: [ 5 ] (File "src\pages\hello-world\index.md")
 - array<string>: [ 'string' ] (File "src\pages\hi-folks\index.md")
MarkdownRemark.frontmatter.objectsInArray[].scalarTest:
 - boolean: true (File "src\pages\hello-world\index.md")
 - string: 'test' (File "src\pages\my-second-post\index.md")
success extract queries from components — 0.080 s

Above was generated using this demo - https://github.com/pieh/gatsby-conflicting-types-demo with prepared conflicts in frontmatter:

page 1 (hello-world - https://github.com/pieh/gatsby-conflicting-types-demo/blob/master/src/pages/hello-world/index.md ):

scalarTest: 'string'
scalarObjectTest:
  prop: true
  a3: true
objectArrayTest:
  - 5
mixedArrayInSingleNodeTest:
  - 5
  - 8
  - 9
  - 'string'
  - 'anotherString'
mixedArrayInDifferentNodesTest:
  - 5
objectsInArray:
  - scalarTest: true
    correct: true

page 2 (hi-folks - https://github.com/pieh/gatsby-conflicting-types-demo/blob/master/src/pages/hi-folks/index.md ):

scalarTest: 5
scalarObjectTest:
  prop: true
  a2: true
objectArrayTest:
  prop: true
mixedArrayInDifferentNodesTest:
  - 'string'

page 3 (my second post - https://github.com/pieh/gatsby-conflicting-types-demo/blob/master/src/pages/my-second-post/index.md ):

scalarTest: true
scalarObjectTest: 'string'
objectsInArray:
  - scalarTest: "test"
    correct: true

Closes #3856

Btw: funny side gain for finding conflicts in gatsby-starter-blog in passed context ( if anyone would ever want to query that :) ). Would need to use null instead of false here - https://github.com/gatsbyjs/gatsby-starter-blog/blob/master/gatsby-node.js#L39-L40

@ghost ghost assigned pieh Feb 8, 2018
@ghost ghost added the review label Feb 8, 2018
@gatsbybot
Copy link
Collaborator

gatsbybot commented Feb 8, 2018

Deploy preview for gatsbygram ready!

Built with commit 97a9953

https://deploy-preview-3905--gatsbygram.netlify.com

@pieh
Copy link
Contributor Author

pieh commented Feb 8, 2018

Will check those failing tests tomorrow

@KyleAMathews
Copy link
Contributor

Woah nice!!

A couple of thoughts which you've probably thought of already but I'll throw out to document them:

  • it'd be cool to print out the actual conflicting data
  • When possible, print out the source of the data e.g. frontmatter on a markdown file — print out the file path to the file with the conflicting data. Or in case of remote data — this is harder (we might want to establish conventions for source plugins to create error strings e.g. IDs of a node) but we could say e.g. for Contentful that the data came from an object of ID X and in Space Y.
@pieh
Copy link
Contributor Author

pieh commented Feb 8, 2018

it'd be cool to print out the actual conflicting data

Had that in my initial version, just removed it thinking it would be too spammy with array values (in long arrays scenario). If I would reduce arrays to single items of given type then it would be more readable but probably also somewhat confusing

When possible, print out the source of the data e.g. frontmatter on a markdown file — print out the file path to the file with the conflicting data. Or in case of remote data — this is harder (we might want to establish conventions for source plugins to create error strings e.g. IDs of a node) but we could say e.g. for Contentful that the data came from an object of ID X and in Space Y.

I'd rather avoid adding special cases in core to show local markdown file even if it would be straight forward to do (getting parent File node and showing path to it). I would think that in general this would try finding nearest ancestor node (or self) that have origin (in whatever manner it is decided to be set).

I will experiment with some conventions tomorrow and hopefully plugin authors will voice their opinion on this topic. It doesn't need to be implemented in this PR - this can be done in follow up IMO.

Another topic - what's Your opinion about adding links in console output - I could add paragraph about type conflicts here https://www.gatsbyjs.org/docs/querying-with-graphql/#where-does-gatsbys-graphql-schema-come-from and add link to it in warning message but then we'd need to be sure this link will always be correct. We do this in couple of places (f.e. debugging html builds or queries not run in non page-or-layout components), but I don't know if that's the right way to add more context to warnings/errors.

@KyleAMathews
Copy link
Contributor

what's your opinion about adding links in console output

I added the other links so I'm a big fan :-)

Ideally we link to a single page and chose the title wisely so the link is stable. If it's a single page, we can easily add / tweak content over time.

@KyleAMathews
Copy link
Contributor

KyleAMathews commented Feb 9, 2018

Deploy preview for using-glamor failed.

Built with commit f3902676bc664d93d2372bda5f3ef1b7e475959e

https://app.netlify.com/sites/using-glamor/deploys/5a7d091e0b79b765d683cd48

@pieh
Copy link
Contributor Author

pieh commented Feb 10, 2018

Just note - I added data origin logging but it's bugged currently (it reports wrong sources). I will check if this is something I can fix with my current approach or will have to change it to something else.

@pieh pieh force-pushed the infer_conflict_type_log branch 3 times, most recently from 620721a to eab0355 Compare February 15, 2018 19:55
@pieh
Copy link
Contributor Author

pieh commented Feb 15, 2018

I ended up rewriting extractFieldExamples completely as this was just very painful and hacky to get original value to display (instead of merged value) and track selector path.

It now will analyze values and report conflicts before doing any actual merging. It does have some performance hit (using freeCodeCamp guides website - it was consistently about +20% in 5 tests I run):

nodes count
 - SitePage - 2769
 - SitePlugin - 16
 - Site - 1
 - Directory - 2761
 - File - 2767
 - MarkdownRemark - 2764
current: 267.151ms
dev: 315.725ms

but it is offseted by fact that it now stores example value and extraction in not run 4 times for same nodes (for fields, for input fields, for sort field enums and for group enums). I will recheck that with example provided in #4055 later.

Examples will fail to build because I added origin field in node.internal and as it wasn't published it won't work ( 300961e ) and I still consider this RFC. For now I'm not worried much about it. I'd like to discuss what's actually good way to pass that information from plugin first.

@pieh pieh force-pushed the infer_conflict_type_log branch 2 times, most recently from ee447d2 to 8045728 Compare February 20, 2018 10:53
@gatsbybot
Copy link
Collaborator

gatsbybot commented Apr 5, 2018

Deploy preview for using-drupal ready!

Built with commit 97a9953

https://deploy-preview-3905--using-drupal.netlify.com

@pieh
Copy link
Contributor Author

pieh commented Apr 5, 2018

Rebased this PR so it's mergable again

I've run gatsby build on master and this PR 5 times for gatsbyjs.org and it does decrease time spent on building schema (average times):

master this PR
building schema 1.591s 0.726s
update schema 1.408s 0.527s
total 2.999s 1.253s
…or fields, for input fields, for sort field enums and for group enums)

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
… it to findRootNodeAncestor

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
…t type conflicts when creating graphql schema

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
…h and detect type conflicts early (to not merge values if there is conflict)

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
@pieh
Copy link
Contributor Author

pieh commented Apr 10, 2018

Anyone care to review?

Copy link
Contributor

@KyleAMathews KyleAMathews left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

I didn't see any tests for the conflicts? Or perhaps I just missed them.

Also does the output look similar still to your original PR comment? I think that could be clearer still.

@@ -505,6 +505,10 @@ const typeOwners = {}
* @param {string} node.internal.contentDigest the digest for the content
* of this node. Helps Gatsby avoid doing extra work on data that hasn't
* changed.
* @param {string} node.internal.nodeDescription An optional field. Human
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just name the field description? node is already implied.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will change that soon

return { type, nodes }
}

const getExampleValue = arg => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this isn't named getExampleValues?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change that, but we get single value (object) from array of nodes, so I though single value would be more accurate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think of the object as a bag of values 🤷‍♂️

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is all that's left for this to get in?

@pieh
Copy link
Contributor Author

pieh commented Apr 11, 2018

Yes, tests for this functionality is missing right now, will add them

@pieh
Copy link
Contributor Author

pieh commented Apr 11, 2018

Output in PR description is what currently looks like - i feel this a little bit more readible in actual terminal:

t1

Just did testing with more spaced out information:

t2

might be worth adding some more colouring to seprate things, but I worry this would cause problems with readability in custom styled terminals people seems to like to use

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
@KyleAMathews
Copy link
Contributor

Cool yeah — and generally people will only have one conflicting type so it should be less overwhelming for folks.

We should double-check the official starters don't have any conflicting types before this gets merged too :-)

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
@pieh
Copy link
Contributor Author

pieh commented Apr 11, 2018

I will run this through official starters, but what about gatsbyjs.org: 😄

hah

I was just thinking now how to handle possible conflicts in SitePlugin nodes - not sure if anyone is using those in graphql, but pluginOptions could generate some conflicts if plugins will have options with same names and different types - should we silence SitePlugin conflicts?

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
@pieh
Copy link
Contributor Author

pieh commented Apr 12, 2018

Updating starters right now and as I suspected - this might be problematic with SitePlugin:

warning There are conflicting field types in your data. GraphQL schema will omit those fields.
SitePlugin.packageJson.author:
 - type: object
   value: { name: 'Kyle Mathews', email: 'mathews.kyle@gmail.com' }
 - type: string
   value: 'Kyle Mathews <mathews.kyle@gmail.com>'

I think silencing SitePlugin conflicts seems reasonable

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
…rently examples are not stored because type is not set - this is just future proofing

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
@pieh pieh changed the title [rfc] Log type conflics when inferring graphql types Apr 14, 2018
@KyleAMathews KyleAMathews merged commit 5b1dc1c into gatsbyjs:master Apr 14, 2018
@KyleAMathews
Copy link
Contributor

Sweeet! Let's publish this!

@pieh
Copy link
Contributor Author

pieh commented Apr 15, 2018

We should also merge this ( gatsby-starter-blog small adjustments to prevent same conflict as in this screenshot - #3905 (comment) ) - gatsbyjs/gatsby-starter-blog#97 not sure why travis fail at git checkout there

@rdela
Copy link
Contributor

rdela commented Aug 28, 2018

Would need to use null instead of false here - gatsbyjs/gatsby-starter-blog:gatsby-node.js@master#L39-L40

man thank heavens for this comment @pieh that was driving me crazy til I found this!
rdela/rdela.com@9914f7f#diff-fda05457e393bada716f508859bfc604L74

mwfrost pushed a commit to mwfrost/gatsby that referenced this pull request Apr 20, 2023
* add nodeDescription field to node internal object

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* store extracted example value to not run it 4 times for same nodes (for fields, for input fields, for sort field enums and for group enums)

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* introduce TypeConflictReporter utility class that will store and print type conflicts when creating graphql schema

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* enhance findRootNode function to accept predicate function and rename it to findRootNodeAncestor

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* rewrite extractFieldExamples to be able to keep track of selector path and detect type conflicts early (to not merge values if there is conflict)

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* use type conflict reporter when extracting example value

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* add nested arrays in array of objects to tests

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* rename nodeDescription to description

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* add tests for conflict reporting

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* space out conflict info to be more readable

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* add description for possible conflicts in page context

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* fix schema type conflict in gatsbyjs.org

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* Silence SitePlugin type conflicts

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* just in case clear type examples store in data-tree-utils tests - currently examples are not stored because type is not set - this is just future proofing

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>

* rename getExampleValue to getExampleValues

Signed-off-by: Michal Piechowiak <misiek.piechowiak@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
5 participants