Gatsby: Creating mappings automatically within a plugin

Created on 1 Apr 2019  路  4Comments  路  Source: gatsbyjs/gatsby

I'm building a custom plugin that works with a CMS that supports relational data (specifically, one-to-one and one-to-many relationships).

Is there a good way to implement these relations within the generated schema such that they feel as if they were created with gatsby-config's mapping option, but entirely within the plugin itself?

More concretely, suppose our plugin's user has two collections in their CMS, BlogPost and Author:

{
  type: 'BlogPost',
  id: 'blog-post-42',
  // Each `BlogPost` can have 0 or more `Authors`
  authors: ['author-123', 'author-456'],
  ...
}
{
  type: 'Author',
  id: 'author-123',
  ...
}

If they were to _manually_ configure the mapping between BlogPost -> Author it would look like this:

module.exports = {
  plugins: [...],
  mapping: {
    'BlogPost.authors': `Author`
  }
}

To automate this behavior within the plugin, I imagine I could make use of createTypes and/or createResolvers, but given how ergonomic it is to use mapping, I was hoping plugin authors could somehow harness that interface.

  • Are there any plans to support something like this, or is it already possible?
  • Are there any existing DB/CMS plugins that support automatic relation mapping in this fashion?

    • I've discovered that gatsby-source-pg does support relation mapping, but it implements this by using Postgraphile combined with gatsby-source-graphql - Clever!

Thank you 馃檱

Relevant Links

question or discussion

Most helpful comment

In the above example, I imagine inference would fail if the name of the field were something other than authors and there weren't any Author nodes created yet, but this _wouldn't_ be a problem if inference occurs _after_ every createNode call as there _would_ be some Author nodes to infer against.

Graphql schema is created after all plugins created their nodes. This means you can reference nodes that weren't yet created when using ___NODE. (This is needed to create any cross refences). I.e:

// create node that references not yet existing node
createNode({
  id: 'foo',
  parent: null,
  children: []
  internal: { type: 'BlogPost', contentDigest: 'contentDigest' },

  authors___NODE: [`not-yet-existing-author`],

  // your normal data
})

// and create node that was missing:
createNode({
  id: 'not-yet-existing-author',
  parent: null,
  children: []
  internal: { type: 'Author', contentDigest: 'contentDigest' },

  // back reference to foo
  foo___NODE: [`foo`],

  // your normal data
})

Is completely fine, as we won't create schema yet.

All 4 comments

For mapping in plugin you'd need to use Foreign Key reference in your data. In your example it would be:

{
  type: 'BlogPost',
  id: 'blog-post-42',
  // Each `BlogPost` can have 0 or more `Authors`
- authors: ['author-123', 'author-456'],
+ // ___NODE suffix instruct gatsby to create node link field
+ authors___NODE: ['author-123', 'author-456'],
  ...
}
{
  type: 'Author',
  id: 'author-123',
  ...
}

___NODE suffix can be used for single "foreign node" id or array of ids (like in this example)

Thank you @pieh! 馃檱 I read that section but incorrectly assumed it only worked for single IDs (e.g. author: 'abc123'), but it _should_ work in this case.

My next question is (anticipating edge cases 馃槄): When does inferFromFieldName (or GQL type inference in general) occur?

In the above example, I imagine inference would fail if the name of the field were something other than authors and there weren't any Author nodes created yet, but this _wouldn't_ be a problem if inference occurs _after_ every createNode call as there _would_ be some Author nodes to infer against.

In the above example, I imagine inference would fail if the name of the field were something other than authors and there weren't any Author nodes created yet, but this _wouldn't_ be a problem if inference occurs _after_ every createNode call as there _would_ be some Author nodes to infer against.

Graphql schema is created after all plugins created their nodes. This means you can reference nodes that weren't yet created when using ___NODE. (This is needed to create any cross refences). I.e:

// create node that references not yet existing node
createNode({
  id: 'foo',
  parent: null,
  children: []
  internal: { type: 'BlogPost', contentDigest: 'contentDigest' },

  authors___NODE: [`not-yet-existing-author`],

  // your normal data
})

// and create node that was missing:
createNode({
  id: 'not-yet-existing-author',
  parent: null,
  children: []
  internal: { type: 'Author', contentDigest: 'contentDigest' },

  // back reference to foo
  foo___NODE: [`foo`],

  // your normal data
})

Is completely fine, as we won't create schema yet.

Fantastic - thank you for the detailed explanation @pieh! I suppose this means Gatsby waits until after all createNode calls before the schema is resolved - makes a lot of sense :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ferMartz picture ferMartz  路  3Comments

theduke picture theduke  路  3Comments

totsteps picture totsteps  路  3Comments

benstr picture benstr  路  3Comments

brandonmp picture brandonmp  路  3Comments