Skip to content

Commit

Permalink
feat(gatsby-source-wordpress): MediaItem.excludeFieldNames / auto exc…
Browse files Browse the repository at this point in the history
…lude interface types that have no fields (#37062)

* allow MediaItem type to use excludeFieldNames option

* make sure cached media item nodes always return the MediaItem node, not File nodes if those are cached

* use get type settings helper instead of accessing settings on options

* auto exclude interface types that have no fields due to an implementing type excluding all of it's fields

* this should've been excluded before! Fixed now

* update comment

* use Map for caching instead of object properties

* exclude MediaItem.template field in tests

* remove debug code
  • Loading branch information
TylerBarnes authored Nov 21, 2022
1 parent 7544045 commit 0501ed3
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1493,7 +1493,6 @@ Array [
Object {
"fields": Array [
"avatar",
"databaseId",
"id",
"name",
"url",
Expand Down Expand Up @@ -1544,7 +1543,6 @@ Array [
"modifiedGmt",
"slug",
"status",
"template",
"uri",
"nodeType",
"parent",
Expand Down Expand Up @@ -5783,7 +5781,6 @@ Array [
"sourceUrl",
"srcSet",
"status",
"template",
"title",
"uri",
"nodeType",
Expand Down Expand Up @@ -6301,12 +6298,6 @@ Array [
],
"name": "WpNodeWithRevisionsToContentNodeConnectionEdge",
},
Object {
"fields": Array [
"template",
],
"name": "WpNodeWithTemplate",
},
Object {
"fields": Array [
"title",
Expand Down
1 change: 1 addition & 0 deletions integration-tests/gatsby-source-wordpress/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ require(`dotenv`).config({
console.log(`Sourcing data from ` + process.env.WPGRAPHQL_URL)

const mediaItemTypeSettings = {
excludeFieldNames: [`template`],
localFile: {
excludeByMimeTypes: ["video/mp4"],
/**
Expand Down
21 changes: 21 additions & 0 deletions packages/gatsby-source-wordpress/docs/plugin-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
- [type.\_\_all.beforeChangeNode](#type__allbeforechangenode)
- [type.RootQuery](#typerootquery)
- [type.MediaItem](#typemediaitem)
- [type.MediaItem.excludeFieldNames](#typemediaitemexcludefieldnames)
- [type.MediaItem.placeholderSizeName](#typemediaitemplaceholdersizename)
- [type.MediaItem.createFileNodes](#typemediaitemcreatefilenodes)
- [type.MediaItem.lazyNodes](#typemediaitemlazynodes)
Expand Down Expand Up @@ -1230,6 +1231,26 @@ A special type which is applied to any non-node root fields that are ingested an

**Field type**: `Object`

#### type.MediaItem.excludeFieldNames

Excludes fields on the MediaItem type by field name.

**Field type**: `Array`

```js
{
resolve: `gatsby-source-wordpress`,
options: {
type: {
MediaItem: {
excludeFieldNames: [`dateGmt`, `parent`],
},
},
},
}

```

#### type.MediaItem.placeholderSizeName

This option allows you to choose the placeholder size used in the new Gatsby image service (currently in ALPHA/BETA) for the small placeholder image. Please make this image size very small for better performance. 20px or smaller width is recommended. To use, create a new image size in WP and name it "gatsby-image-placeholder" (or the name that you pass to this option) and that new size will be used automatically for placeholder images in the Gatsby build.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
fieldOfTypeWasFetched,
getTypeSettingsByType,
filterTypeDefinition,
getTypesThatImplementInterfaceType,
} from "./helpers"

const unionType = typeBuilderApi => {
Expand Down Expand Up @@ -47,38 +48,24 @@ const unionType = typeBuilderApi => {
}

const interfaceType = typeBuilderApi => {
const { type, schema, gatsbyNodeTypes, fieldAliases, fieldBlacklist } =
typeBuilderApi
const { type, schema } = typeBuilderApi

const state = store.getState()
const { ingestibles, typeMap } = state.remoteSchema
const { ingestibles } = state.remoteSchema
const { nodeInterfaceTypes } = ingestibles

const allTypes = typeMap.values()

const implementingTypes = Array.from(allTypes)
.filter(
({ interfaces }) =>
interfaces &&
// find types that implement this interface type
interfaces.find(singleInterface => singleInterface.name === type.name)
)
.map(type => typeMap.get(type.name))
.filter(
type =>
type.kind !== `UNION` ||
// if this is a union type, make sure the union type has one or more member types, otherwise schema customization will throw an error
(!!type.possibleTypes && !!type.possibleTypes.length)
)
const implementingTypes = getTypesThatImplementInterfaceType(type)

const transformedFields = transformFields({
parentInterfacesImplementingTypes: implementingTypes,
parentType: type,
fields: type.fields,
gatsbyNodeTypes,
fieldAliases,
fieldBlacklist,
})

if (!transformedFields) {
return null
}

let typeDef = {
name: buildTypeName(type.name),
fields: transformedFields,
Expand Down Expand Up @@ -144,7 +131,11 @@ const objectType = typeBuilderApi => {
.filter(interfaceType => {
const interfaceTypeSettings = getTypeSettingsByType(interfaceType)

return !interfaceTypeSettings.exclude && fieldOfTypeWasFetched(type)
return (
!interfaceTypeSettings.exclude &&
fieldOfTypeWasFetched(type) &&
fieldOfTypeWasFetched(interfaceType)
)
})
.map(({ name }) => buildTypeName(name))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,38 @@ export const fieldOfTypeWasFetched = type => {
return typeWasFetched
}

const implementingTypeCache = new Map()

export const getTypesThatImplementInterfaceType = type => {
if (implementingTypeCache.has(type.name)) {
return implementingTypeCache.get(type.name)
}

const state = store.getState()
const { typeMap } = state.remoteSchema

const allTypes = typeMap.values()

const implementingTypes = Array.from(allTypes)
.filter(
({ interfaces }) =>
interfaces &&
// find types that implement this interface type
interfaces.find(singleInterface => singleInterface.name === type.name)
)
.map(type => typeMap.get(type.name))
.filter(
type =>
type.kind !== `UNION` ||
// if this is a union type, make sure the union type has one or more member types, otherwise schema customization will throw an error
(!!type.possibleTypes && !!type.possibleTypes.length)
)

implementingTypeCache.set(type.name, implementingTypes)

return implementingTypes
}

const supportedScalars = [
`Int`,
`Float`,
Expand All @@ -84,7 +116,7 @@ export const typeIsASupportedScalar = type => {
return supportedScalars.includes(findTypeName(type))
}

const typeSettingCache = {}
const typeSettingCache = new Map()

// retrieves plugin settings for the provided type
export const getTypeSettingsByType = type => {
Expand All @@ -94,7 +126,11 @@ export const getTypeSettingsByType = type => {

const typeName = findTypeName(type)

const cachedTypeSettings = typeSettingCache[typeName]
if (!typeName) {
return {}
}

const cachedTypeSettings = typeSettingCache.get(typeName)

if (cachedTypeSettings) {
return cachedTypeSettings
Expand All @@ -116,12 +152,12 @@ export const getTypeSettingsByType = type => {
if (typeSettings) {
const mergedSettings = merge(__allTypeSetting, typeSettings)

typeSettingCache[typeName] = mergedSettings
typeSettingCache.set(typeName, mergedSettings)

return mergedSettings
}

typeSettingCache[typeName] = __allTypeSetting
typeSettingCache.set(typeName, __allTypeSetting)

return __allTypeSetting
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ const customizeSchema = async ({ actions, schema, store: gatsbyStore }) => {
break
case `SCALAR`:
/**
* custom scalar types aren't imlemented currently.
* @todo make this hookable so sub-plugins or plugin options can add custom scalar support.
* custom scalar types aren't supported.
*/
break
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { fieldTransformers } from "./field-transformers"
import { getGatsbyNodeTypeNames } from "../../source-nodes/fetch-nodes/fetch-nodes"
import store from "~/store"

import {
Expand Down Expand Up @@ -88,19 +89,19 @@ const excludeField = ({
* with proper node linking and type namespacing
* also filters out unusable fields and types
*/

export const transformFields = ({
fields,
fieldAliases,
fieldBlacklist,
parentType,
parentInterfacesImplementingTypes,
gatsbyNodeTypes,
}) => {
if (!fields || !fields.length) {
return null
}

const gatsbyNodeTypes = getGatsbyNodeTypeNames()

const { fieldAliases, fieldBlacklist } = store.getState().remoteSchema

const parentTypeSettings = getTypeSettingsByType(parentType)

const parentInterfacesImplementingTypeSettings =
Expand Down Expand Up @@ -197,5 +198,9 @@ export const transformFields = ({
return fieldsObject
}, {})

if (!Object.keys(transformedFields).length) {
return null
}

return transformedFields
}
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,20 @@ When using this option, be sure to gitignore the wordpress-cache directory in th
`),
}),
MediaItem: Joi.object({
excludeFieldNames: Joi.array()
.items(Joi.string())
.allow(null)
.allow(false)
.description(`Excludes fields on the MediaItem type by field name.`)
.meta({
example: wrapOptions(`
type: {
MediaItem: {
excludeFieldNames: [\`dateGmt\`, \`parent\`],
},
},
`),
}),
placeholderSizeName: Joi.string()
.default(`gatsby-image-placeholder`)
.description(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,11 +542,8 @@ const transformFields = ({
?.filter(
field =>
!fieldIsExcludedOnParentType({
pluginOptions,
field,
parentType,
mainType,
parentField,
}) &&
!fieldIsExcludedOnAll({
pluginOptions,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import store from "~/store"
import { typeIsExcluded } from "~/steps/ingest-remote-schema/is-excluded"
import { typeIsABuiltInScalar } from "../create-schema-customization/helpers"
import { findTypeName } from "~/steps/create-schema-customization/helpers"
import {
findTypeName,
getTypesThatImplementInterfaceType,
} from "~/steps/create-schema-customization/helpers"
import { transformFields } from "~/steps/create-schema-customization/transform-fields"
import { getPersistentCache } from "~/utils/cache"

const identifyAndStoreIngestableFieldsAndTypes = async () => {
Expand Down Expand Up @@ -46,6 +50,23 @@ const identifyAndStoreIngestableFieldsAndTypes = async () => {
continue
}

if (!interfaceType.fields) {
continue
}

const typesThatImplementInterface =
getTypesThatImplementInterfaceType(interfaceType)

const shouldSkipInterfaceType = !transformFields({
fields: interfaceType.fields,
parentType: interfaceType,
parentInterfacesImplementingTypes: typesThatImplementInterface,
})

if (shouldSkipInterfaceType && interfaceType.name !== `Node`) {
continue
}

store.dispatch.remoteSchema.addFetchedType(interfaceType)

if (interfaceType.fields) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import store from "~/store"
import { findTypeName } from "~/steps/create-schema-customization/helpers"
import {
findTypeName,
getTypeSettingsByType,
} from "~/steps/create-schema-customization/helpers"

const typeIsExcluded = ({ pluginOptions, typeName }) =>
pluginOptions &&
Expand All @@ -15,9 +18,7 @@ const fieldIsExcludedOnAll = ({ pluginOptions, field }) => {
return !!allFieldSettings?.excludeFieldNames?.includes(field?.name)
}

const fieldIsExcludedOnParentType = ({ pluginOptions, field, parentType }) => {
const allTypeSettings = pluginOptions.type

const fieldIsExcludedOnParentType = ({ field, parentType }) => {
const state = store.getState()
const { typeMap } = state.remoteSchema

Expand All @@ -27,15 +28,16 @@ const fieldIsExcludedOnParentType = ({ pluginOptions, field, parentType }) => {
field => field.name === `nodes`
)

const parentTypeNodesFieldTypeName = findTypeName(parentTypeNodesField?.type)
const parentTypeNameSettings = getTypeSettingsByType(parentType)
const parentTypeNodesFieldTypeNameSettings = getTypeSettingsByType(
parentTypeNodesField?.type
)

const fieldIsExcludedOnParentType =
// if this field is excluded on either the parent type
allTypeSettings[parentType?.name]?.excludeFieldNames?.includes(
field?.name
) ||
parentTypeNameSettings?.excludeFieldNames?.includes(field?.name) ||
// or the parent type has a "nodes" field and that type has this field excluded
allTypeSettings[parentTypeNodesFieldTypeName]?.excludeFieldNames?.includes(
parentTypeNodesFieldTypeNameSettings?.excludeFieldNames?.includes(
field?.name
)

Expand Down
Loading

0 comments on commit 0501ed3

Please sign in to comment.