Skip to content

Commit

Permalink
fix(gatsby-source-drupal): delete relationships to now deleted nodes (#…
Browse files Browse the repository at this point in the history
…32971)

* fix(gatsby-source-drupal): delete relationships to now deleted nodes

* Cleanup back/reference weakmaps

* Fix lint error

* Update packages/gatsby-source-drupal/src/utils.js

Co-authored-by: Ward Peeters <ward@coding-tech.com>

* Actually recreate updated nodes

* referenced nodes doesn't always exist

Co-authored-by: Ward Peeters <ward@coding-tech.com>
Co-authored-by: gatsbybot <mathews.kyle+gatsbybot@gmail.com>
  • Loading branch information
3 people authored Sep 2, 2021
1 parent 2b7296b commit c720767
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"timestamp": 1593545807,
"entities": [
{
"action": "delete",
"id": "file-4",
"type": "file--file"
},
{
"jsonapi": {
"version": "1.0",
Expand Down
26 changes: 26 additions & 0 deletions packages/gatsby-source-drupal/src/__tests__/fixtures/article.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,32 @@
"id": "file-1"
}
},
"field_secondary_image": {
"data": [
{
"type": "file--file",
"id": "file-4"
}
]
},
"field_secondary_multiple_image": {
"data": [
{
"type": "file--file",
"id": "file-3"
},
{
"type": "file--file",
"id": "file-4"
}
]
},
"field_tertiary_image": {
"data": {
"type": "file--file",
"id": "file-4"
}
},
"field_tags": {
"data": null
}
Expand Down
23 changes: 23 additions & 0 deletions packages/gatsby-source-drupal/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe(`gatsby-source-drupal`, () => {
const { objectContaining } = expect
const actions = {
createNode: jest.fn(node => (nodes[node.id] = node)),
deleteNode: jest.fn(node => delete nodes[node.id]),
setPluginStatus: jest.fn(),
touchNode: jest.fn(),
}
Expand Down Expand Up @@ -433,15 +434,22 @@ describe(`gatsby-source-drupal`, () => {
const fastBuilds = true
await sourceNodes(args, { baseUrl, fastBuilds })
})

it(`Attributes`, () => {
expect(nodes[createNodeId(`und.article-3`)].title).toBe(`Article #3`)
})

it(`Relationships`, () => {
expect(nodes[createNodeId(`und.article-3`)].relationships).toEqual({
field_main_image___NODE: createNodeId(`und.file-1`),
field_tags___NODE: [createNodeId(`und.tag-1`)],
})
expect(
nodes[createNodeId(`und.article-2`)].relationships
.field_secondary_image___NODE
).toEqual([createNodeId(`und.file-4`)])
})

it(`Back references`, () => {
expect(
nodes[createNodeId(`und.file-1`)].relationships[
Expand Down Expand Up @@ -473,17 +481,32 @@ describe(`gatsby-source-drupal`, () => {
})
await sourceNodes(args, { baseUrl, fastBuilds })
})

it(`Attributes`, () => {
expect(nodes[createNodeId(`und.article-3`)].title).toBe(
`Article #3 - Synced`
)
})

it(`Relationships`, () => {
// removed `field_main_image`, changed `field_tags`
expect(nodes[createNodeId(`und.article-3`)].relationships).toEqual({
field_tags___NODE: [createNodeId(`und.tag-2`)],
})
expect(
nodes[createNodeId(`und.article-2`)].relationships
.field_secondary_image___NODE
).toBe(undefined)
expect(
nodes[createNodeId(`und.article-2`)].relationships
.field_secondary_multiple_image___NODE.length
).toBe(1)
expect(
nodes[createNodeId(`und.article-2`)].relationships
.field_tertiary_image___NODE_image___NODE
).toBe(undefined)
})

it(`Back references`, () => {
// removed `field_main_image`, `file-1` no longer has back reference to `article-3`
expect(
Expand Down
51 changes: 22 additions & 29 deletions packages/gatsby-source-drupal/src/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ const {
isFileNode,
createNodeIdWithVersion,
} = require(`./normalize`)
const { handleReferences, handleWebhookUpdate } = require(`./utils`)
const {
handleReferences,
handleWebhookUpdate,
handleDeletedNode,
} = require(`./utils`)

const agent = {
http: new HttpAgent(),
Expand Down Expand Up @@ -149,19 +153,15 @@ exports.sourceNodes = async (
}

for (const nodeToDelete of nodesToDelete) {
const nodeIdToDelete = createNodeId(
createNodeIdWithVersion(
nodeToDelete.id,
nodeToDelete.type,
getOptions().languageConfig
? nodeToDelete.attributes?.langcode
: `und`,
nodeToDelete.attributes?.drupal_internal__revision_id,
entityReferenceRevisions
)
)
actions.deleteNode(getNode(nodeIdToDelete))
reporter.log(`Deleted node: ${nodeIdToDelete}`)
const deletedNode = await handleDeletedNode({
actions,
getNode,
node: nodeToDelete,
createNodeId,
createContentDigest,
entityReferenceRevisions,
})
reporter.log(`Deleted node: ${deletedNode.id}`)
}

changesActivity.end()
Expand Down Expand Up @@ -248,21 +248,14 @@ exports.sourceNodes = async (
const nodesToSync = res.body.entities
for (const nodeSyncData of nodesToSync) {
if (nodeSyncData.action === `delete`) {
actions.deleteNode(
getNode(
createNodeId(
createNodeIdWithVersion(
nodeSyncData.id,
nodeSyncData.type,
getOptions().languageConfig
? nodeSyncData.attributes.langcode
: `und`,
nodeSyncData.attributes?.drupal_internal__revision_id,
entityReferenceRevisions
)
)
)
)
handleDeletedNode({
actions,
getNode,
node: nodeSyncData,
createNodeId,
createContentDigest,
entityReferenceRevisions,
})
} else {
// The data could be a single Drupal entity or an array of Drupal
// entities to update.
Expand Down
73 changes: 73 additions & 0 deletions packages/gatsby-source-drupal/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,78 @@ const handleReferences = (

exports.handleReferences = handleReferences

const handleDeletedNode = async ({
actions,
node,
getNode,
createNodeId,
createContentDigest,
entityReferenceRevisions,
}) => {
const deletedNode = getNode(
createNodeId(
createNodeIdWithVersion(
node.id,
node.type,
getOptions().languageConfig ? node.attributes.langcode : `und`,
node.attributes?.drupal_internal__revision_id,
entityReferenceRevisions
)
)
)

// Remove the deleted node from backRefsNamesLookup
backRefsNamesLookup.delete(deletedNode)

// Remove relationships from other nodes and re-create them.
Object.keys(deletedNode.relationships).forEach(key => {
let ids = deletedNode.relationships[key]
ids = [].concat(ids)
ids.forEach(id => {
const node = getNode(id)
let referencedNodes = referencedNodesLookup.get(node)
if (referencedNodes?.includes(deletedNode.id)) {
// Loop over relationships and cleanup references.
Object.entries(node.relationships).forEach(([key, value]) => {
// If a string ref matches, delete it.
if (_.isString(value) && value === deletedNode.id) {
delete node.relationships[key]
}

// If it's an array, filter, then check if the array is empty and then delete
// if so
if (_.isArray(value)) {
value = value.filter(v => v !== deletedNode.id)

if (value.length === 0) {
delete node.relationships[key]
} else {
node.relationships[key] = value
}
}
})

// Remove deleted node from array of referencedNodes
referencedNodes = referencedNodes.filter(nId => nId !== deletedNode.id)
referencedNodesLookup.set(node, referencedNodes)
}
// Recreate the referenced node with its now cleaned-up relationships.
if (node.internal.owner) {
delete node.internal.owner
}
if (node.fields) {
delete node.fields
}
node.internal.contentDigest = createContentDigest(node)
actions.createNode(node)
})
})

actions.deleteNode(deletedNode)

return deletedNode
}

const handleWebhookUpdate = async (
{
nodeToUpdate,
Expand Down Expand Up @@ -216,3 +288,4 @@ const handleWebhookUpdate = async (
}

exports.handleWebhookUpdate = handleWebhookUpdate
exports.handleDeletedNode = handleDeletedNode

0 comments on commit c720767

Please sign in to comment.