Skip to content

Instantly share code, notes, and snippets.

@hyrsky
Last active November 18, 2019 23:28
Show Gist options
  • Save hyrsky/b11c7327fda6f84b327b48ca5593958d to your computer and use it in GitHub Desktop.
Save hyrsky/b11c7327fda6f84b327b48ca5593958d to your computer and use it in GitHub Desktop.
/** GraphQL type name for union of all known paragraph types. */
const PARAGRAPH_UNON_NAME = 'paragraph_types_union'
/** GraphQL type name for union of all known media types. */
const MEDIA_UNON_NAME = 'media_types_union'
/** Construct field schema with type overrides. */
function createCustomFields(fields) {
return fields.reduce((schema, { type, name: fieldName }) => {
const resolveById = (parent, args, context) => {
const ids = parent[`${fieldName}___NODE`]
return context.nodeModel.getNodesByIds({
ids: Array.isArray(ids) ? ids : [ids]
})
}
switch (type) {
case 'paragraphs':
schema[fieldName] = {
type: `[${PARAGRAPH_UNON_NAME}]`,
// Resolve correct paragraph nodes.
resolve: resolveById
}
break
case 'media':
schema[fieldName] = {
type: `[${MEDIA_UNON_NAME}]`,
// Resolve correct media nodes.
resolve: resolveById
}
break
}
return schema
}, {})
}
/**
* gatsby-source-drupal does not handle GraphQL type unions well if not relationship data is present.
*
* For example instead of infering a separate type for each paragraph field it
* would be easier to reuse code if we had a global paragrah type that
* would include all paragraph types.
*
* This schema customization overrides media and paragraph field types to do
* just that.
*/
exports.createSchemaCustomization = ({ actions, schema, getNodesByType }) => {
/** Fix union types for these types and their fields. */
const FixTypes = [
{ type: 'node__landing_page', fields: [{ type: 'paragraphs', name: 'field_landing_paragraphs' }] },
{ type: 'paragraph__hero_form', fields: [{ type: 'media', name: 'field_media_any' }] },
{ type: 'paragraph__media', fields: [{ type: 'media', name: 'field_media_any' }] }
]
const getAllDrupalTypes = drupalType =>
getNodesByType(drupalType)
.flatMap(node => Object.keys(node.relationships))
.map(type => type.replace('___NODE', ''))
/** Get GraphQL relationship field type name for given type. */
const relationshipName = type => `${type}__relationship`
// Get all media types.
const mediaTypes = getAllDrupalTypes('media_type__media_type')
// Get all paragrah types (related to any node in any language).
const paragraphTypes = getAllDrupalTypes('paragraphs_type__paragraphs_type')
if (process.env.NODE_ENV === 'development') {
console.log(`Found ${mediaTypes.length} media types:`, mediaTypes)
console.log(`Found ${paragraphTypes.length} paragraph types:`, paragraphTypes)
}
const { createTypes } = actions
createTypes([
// Create GraphQL union type that includes all found paragraph types.
schema.buildUnionType({
name: PARAGRAPH_UNON_NAME,
types: paragraphTypes
}),
// Create GraphQL union type that includes all media types.
schema.buildUnionType({
name: MEDIA_UNON_NAME,
types: mediaTypes
}),
// Override relationship field type for specified content types.
...FixTypes.map(
({ type }) => `
type ${type} implements Node @infer {
relationships: ${relationshipName(type)}
}
`
),
// Change relationship field type to include all found paragraphs types.
...FixTypes.map(({ type, fields }) =>
schema.buildObjectType({
name: relationshipName(type),
interfaces: ['Node'],
fields: createCustomFields(fields)
})
)
])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment