From 0468b6462507ea05ff47df960186fed8789c79d9 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Tue, 27 Jul 2021 17:06:14 +0100 Subject: [PATCH] refactor: update e2e test schema WIP - first try to use union for reference field with validations fix multi reference fields shorten union names support multiple reference fields for a single content type fix: type name generation remove comment introduce validation for single reference fields --- e2e-tests/contentful/schema.gql | 48 +++++++++---- .../contentful/src/pages/content-reference.js | 17 +++-- e2e-tests/contentful/src/pages/rich-text.js | 12 ++-- .../src/generate-schema.js | 69 +++++++++++++++++-- .../gatsby-source-contentful/src/normalize.js | 3 +- 5 files changed, 119 insertions(+), 30 deletions(-) diff --git a/e2e-tests/contentful/schema.gql b/e2e-tests/contentful/schema.gql index 5f4ef8d58f623..899619b3983b2 100644 --- a/e2e-tests/contentful/schema.gql +++ b/e2e-tests/contentful/schema.gql @@ -124,7 +124,7 @@ type SiteBuildMetadata implements Node @dontInfer { interface ContentfulReference implements Node { id: ID! - sys: ContentfulSys + sys: ContentfulSys! } type ContentfulSys { @@ -145,13 +145,23 @@ type ContentfulContentType implements Node @dontInfer { description: String! } -interface ContentfulEntry implements Node { +interface ContentfulEntry implements ContentfulReference & Node { id: ID! - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! +} + +type ContentfulMetadata @dontInfer { + tags: [ContentfulTag]! @link(by: "id", from: "tags___NODE") +} + +type ContentfulTag implements Node @dontInfer { + name: String! + contentful_id: String! } type ContentfulAsset implements ContentfulReference & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! title: String description: String contentType: String @@ -203,7 +213,8 @@ type ContentfulText implements Node @dontInfer { } type ContentfulContentTypeNumber implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String integer: Int integerLocalized: Int @@ -212,7 +223,8 @@ type ContentfulContentTypeNumber implements ContentfulReference & ContentfulEntr } type ContentfulContentTypeText implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String short: String shortLocalized: String @@ -224,7 +236,8 @@ type ContentfulContentTypeText implements ContentfulReference & ContentfulEntry } type ContentfulContentTypeMediaReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String one: ContentfulAsset @link(by: "id", from: "one___NODE") oneLocalized: ContentfulAsset @link(by: "id", from: "oneLocalized___NODE") @@ -233,14 +246,16 @@ type ContentfulContentTypeMediaReference implements ContentfulReference & Conten } type ContentfulContentTypeBoolean implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String boolean: Boolean booleanLocalized: Boolean } type ContentfulContentTypeDate implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String date: Date @dateformat dateTime: Date @dateformat @@ -249,21 +264,24 @@ type ContentfulContentTypeDate implements ContentfulReference & ContentfulEntry } type ContentfulContentTypeLocation implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String location: ContentfulLocation locationLocalized: ContentfulLocation } type ContentfulContentTypeJson implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String json: JSON jsonLocalized: JSON } type ContentfulContentTypeRichText implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String richText: ContentfulRichText richTextLocalized: ContentfulRichText @@ -271,7 +289,8 @@ type ContentfulContentTypeRichText implements ContentfulReference & ContentfulEn } type ContentfulContentTypeContentReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String one: ContentfulEntry @link(by: "id", from: "one___NODE") oneLocalized: ContentfulEntry @link(by: "id", from: "oneLocalized___NODE") @@ -280,7 +299,8 @@ type ContentfulContentTypeContentReference implements ContentfulReference & Cont } type ContentfulContentTypeValidatedContentReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String oneItemSingleType: ContentfulEntry @link(by: "id", from: "oneItemSingleType___NODE") oneItemManyTypes: ContentfulEntry @link(by: "id", from: "oneItemManyTypes___NODE") diff --git a/e2e-tests/contentful/src/pages/content-reference.js b/e2e-tests/contentful/src/pages/content-reference.js index af6400da98f3b..d31fdb8f8b14b 100644 --- a/e2e-tests/contentful/src/pages/content-reference.js +++ b/e2e-tests/contentful/src/pages/content-reference.js @@ -109,8 +109,10 @@ export const pageQuery = graphql` } one { __typename - sys { - id + ... on ContentfulEntry { + sys { + id + } } ... on ContentfulContentTypeText { title @@ -152,8 +154,10 @@ export const pageQuery = graphql` } many { __typename - sys { - id + ... on ContentfulEntry { + sys { + id + } } ... on ContentfulContentTypeText { title @@ -165,6 +169,11 @@ export const pageQuery = graphql` } ... on ContentfulContentTypeContentReference { title + ... on ContentfulEntry { + sys { + id + } + } one { ... on ContentfulContentTypeText { title diff --git a/e2e-tests/contentful/src/pages/rich-text.js b/e2e-tests/contentful/src/pages/rich-text.js index c3488ad37f63a..84bf8c2909b19 100644 --- a/e2e-tests/contentful/src/pages/rich-text.js +++ b/e2e-tests/contentful/src/pages/rich-text.js @@ -156,8 +156,10 @@ export const pageQuery = graphql` title one { __typename - sys { - id + ... on ContentfulEntry { + sys { + id + } } ... on ContentfulContentTypeText { title @@ -179,8 +181,10 @@ export const pageQuery = graphql` } many { __typename - sys { - id + ... on ContentfulEntry { + sys { + id + } } ... on ContentfulContentTypeText { title diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 24c0317047198..3a60c62e656d1 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -70,7 +70,64 @@ const ContentfulDataTypes = new Map([ ], ]) -const getLinkFieldType = (linkType, field) => { +const unionsNameSet = new Set() + +const getLinkFieldType = (linkType, field, schema, createTypes) => { + // Check for validations + const validations = + field.type === `Array` ? field.items?.validations : field?.validations + + if (validations) { + // We only handle content type validations + const linkContentTypeValidation = validations.find( + ({ linkContentType }) => !!linkContentType + ) + if (linkContentTypeValidation) { + const { linkContentType } = linkContentTypeValidation + const contentTypes = Array.isArray(linkContentType) + ? linkContentType + : [linkContentType] + + // Full type names for union members, shorter variant for the union type name + const translatedTypeNames = contentTypes.map(typeName => + makeTypeName(typeName) + ) + const shortTypeNames = contentTypes.map(typeName => + makeTypeName(typeName, ``) + ) + + // Single content type + if (translatedTypeNames.length === 1) { + return { + type: translatedTypeNames.shift(), + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } + } + + // Multiple content types + const unionName = [`UnionContentful`, ...shortTypeNames].join(``) + + if (!unionsNameSet.has(unionName)) { + unionsNameSet.add(unionName) + createTypes( + schema.buildUnionType({ + name: unionName, + types: translatedTypeNames, + }) + ) + } + + return { + type: unionName, + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } + } + } + return { type: `Contentful${linkType}`, extensions: { @@ -79,19 +136,19 @@ const getLinkFieldType = (linkType, field) => { } } -const translateFieldType = field => { +const translateFieldType = (field, schema, createTypes) => { let fieldType if (field.type === `Array`) { // Arrays of Contentful Links or primitive types const fieldData = field.items.type === `Link` - ? getLinkFieldType(field.items.linkType, field) - : translateFieldType(field.items) + ? getLinkFieldType(field.items.linkType, field, schema, createTypes) + : translateFieldType(field.items, schema, createTypes) fieldType = { ...fieldData, type: `[${fieldData.type}]` } } else if (field.type === `Link`) { // Contentful Link (reference) field types - fieldType = getLinkFieldType(field.linkType, field) + fieldType = getLinkFieldType(field.linkType, field, schema, createTypes) } else { // Primitive field types fieldType = ContentfulDataTypes.get(field.type)(field) @@ -371,7 +428,7 @@ export function generateSchema({ if (field.disabled || field.omitted) { return } - fields[field.id] = translateFieldType(field) + fields[field.id] = translateFieldType(field, schema, createTypes) }) const type = pluginConfig.get(`useNameForId`) diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 122fef70b0601..318c3987c5de0 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -1,8 +1,7 @@ // @ts-check import _ from "lodash" -const typePrefix = `ContentfulContentType` -export const makeTypeName = type => +export const makeTypeName = (type, typePrefix = `ContentfulContentType`) => _.upperFirst(_.camelCase(`${typePrefix} ${type}`)) export const getLocalizedField = ({ field, locale, localesFallback }) => {