Skip to content

Commit cdeff78

Browse files
GatsbyJS BotKyleAMathews
GatsbyJS Bot
andauthored
fix(gatsby-source-drupal): Ensure all new nodes are created before creating relationships (#33864) (#33926)
Co-authored-by: Kyle Mathews <[email protected]>
1 parent 62a5612 commit cdeff78

File tree

5 files changed

+214
-0
lines changed

5 files changed

+214
-0
lines changed

packages/gatsby-source-drupal/src/__tests__/fixtures/1593545806.json

+63
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,69 @@
9898
}
9999
}
100100
}
101+
},
102+
{
103+
"jsonapi": {
104+
"version": "1.0",
105+
"meta": {
106+
"links": {
107+
"self": {
108+
"href": "http://jsonapi.org/format/1.0/"
109+
}
110+
}
111+
}
112+
},
113+
"data": {
114+
"type": "node--article",
115+
"id": "article-10",
116+
"attributes": {
117+
"id": 100,
118+
"uuid": "article-10",
119+
"title": "Article #10",
120+
"body": "Aliquam non varius libero, sit amet consequat ex. Aenean porta turpis quis vulputate blandit. Suspendisse in porta erat. Sed sit amet scelerisque turpis, at rutrum mauris. Sed tempor eleifend lobortis. Proin maximus, massa sed dignissim sollicitudin, quam risus mattis justo, sit amet aliquam odio ligula quis urna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut mollis leo nisi, at interdum urna fermentum ut. Fusce id suscipit neque, eu fermentum lacus. Donec egestas laoreet felis ac luctus. Vestibulum molestie mattis ante, a vulputate nunc ullamcorper at. Ut hendrerit ipsum eget gravida ultricies."
121+
},
122+
"relationships": {
123+
"field_tags": {
124+
"data": [
125+
{
126+
"type": "taxonomy_term--tags",
127+
"id": "tag-10"
128+
}
129+
]
130+
}
131+
}
132+
}
133+
},
134+
{
135+
"jsonapi": {
136+
"version": "1.0",
137+
"meta": {
138+
"links": {
139+
"self": {
140+
"href": "http://jsonapi.org/format/1.0/"
141+
}
142+
}
143+
}
144+
},
145+
"data": {
146+
"type": "taxonomy_term--tags",
147+
"id": "tag-10",
148+
"attributes": {
149+
"id": 110,
150+
"uuid": "tag-10",
151+
"langcode": "en",
152+
"name": "Tag #10",
153+
"description": null,
154+
"weight": 0,
155+
"changed": 1523031646,
156+
"default_langcode": true,
157+
"path": {
158+
"alias": null,
159+
"pid": null,
160+
"langcode": "en"
161+
}
162+
}
163+
}
101164
}
102165
]
103166
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"action": "update",
3+
"data": [
4+
{
5+
"type": "node--article",
6+
"id": "article-10",
7+
"attributes": {
8+
"id": 100,
9+
"uuid": "article-10",
10+
"title": "Article #10",
11+
"body": "Aliquam non varius libero, sit amet consequat ex. Aenean porta turpis quis vulputate blandit. Suspendisse in porta erat. Sed sit amet scelerisque turpis, at rutrum mauris. Sed tempor eleifend lobortis. Proin maximus, massa sed dignissim sollicitudin, quam risus mattis justo, sit amet aliquam odio ligula quis urna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut mollis leo nisi, at interdum urna fermentum ut. Fusce id suscipit neque, eu fermentum lacus. Donec egestas laoreet felis ac luctus. Vestibulum molestie mattis ante, a vulputate nunc ullamcorper at. Ut hendrerit ipsum eget gravida ultricies."
12+
},
13+
"relationships": {
14+
"field_tags": {
15+
"data": [
16+
{
17+
"type": "taxonomy_term--tags",
18+
"id": "tag-10"
19+
}
20+
]
21+
}
22+
}
23+
},
24+
{
25+
"type": "taxonomy_term--tags",
26+
"id": "tag-10",
27+
"attributes": {
28+
"id": 110,
29+
"uuid": "tag-10",
30+
"langcode": "en",
31+
"name": "Tag #10",
32+
"description": null,
33+
"weight": 0,
34+
"changed": 1523031646,
35+
"default_langcode": true,
36+
"path": {
37+
"alias": null,
38+
"pid": null,
39+
"langcode": "en"
40+
}
41+
}
42+
}
43+
]
44+
}
45+

packages/gatsby-source-drupal/src/__tests__/index.js

+24
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,26 @@ describe(`gatsby-source-drupal`, () => {
355355
})
356356
})
357357
})
358+
describe(`multiple entities in webhook body`, () => {
359+
let resp
360+
beforeAll(async () => {
361+
const webhookBody = require(`./fixtures/webhook-body-multiple-nodes.json`)
362+
await sourceNodes(
363+
{
364+
...args,
365+
webhookBody,
366+
},
367+
{ baseUrl }
368+
)
369+
})
370+
371+
it(`Relationships`, async () => {
372+
expect(
373+
nodes[createNodeId(`und.article-10`)].relationships.field_tags___NODE
374+
.length
375+
).toBe(1)
376+
})
377+
})
358378

359379
describe(`Insert content`, () => {
360380
it(`Node doesn't exist before webhook`, () => {
@@ -567,6 +587,10 @@ describe(`gatsby-source-drupal`, () => {
567587
nodes[createNodeId(`und.article-2`)].relationships
568588
.field_tertiary_image___NODE_image___NODE
569589
).toBe(undefined)
590+
expect(
591+
nodes[createNodeId(`und.article-10`)].relationships.field_tags___NODE
592+
.length
593+
).toBe(1)
570594
})
571595

572596
it(`Back references`, () => {

packages/gatsby-source-drupal/src/gatsby-node.js

+37
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
storeRefsLookups,
1717
handleReferences,
1818
handleWebhookUpdate,
19+
createNodeIfItDoesNotExist,
1920
handleDeletedNode,
2021
} = require(`./utils`)
2122

@@ -234,6 +235,17 @@ ${JSON.stringify(webhookBody, null, 4)}`
234235
nodesToUpdate = [data]
235236
}
236237

238+
for (const nodeToUpdate of nodesToUpdate) {
239+
await createNodeIfItDoesNotExist({
240+
nodeToUpdate,
241+
actions,
242+
createNodeId,
243+
createContentDigest,
244+
getNode,
245+
reporter,
246+
})
247+
}
248+
237249
for (const nodeToUpdate of nodesToUpdate) {
238250
await handleWebhookUpdate(
239251
{
@@ -345,6 +357,31 @@ ${JSON.stringify(webhookBody, null, 4)}`
345357

346358
// Process sync data from Drupal.
347359
const nodesToSync = res.body.entities
360+
361+
// First create all nodes that we haven't seen before. That
362+
// way we can create relationships correctly next as the nodes
363+
// will exist in Gatsby.
364+
for (const nodeSyncData of nodesToSync) {
365+
if (nodeSyncData.action === `delete`) {
366+
continue
367+
}
368+
369+
let nodesToUpdate = nodeSyncData.data
370+
if (!Array.isArray(nodeSyncData.data)) {
371+
nodesToUpdate = [nodeSyncData.data]
372+
}
373+
for (const nodeToUpdate of nodesToUpdate) {
374+
createNodeIfItDoesNotExist({
375+
nodeToUpdate,
376+
actions,
377+
createNodeId,
378+
createContentDigest,
379+
getNode,
380+
reporter,
381+
})
382+
}
383+
}
384+
348385
for (const nodeSyncData of nodesToSync) {
349386
if (nodeSyncData.action === `delete`) {
350387
handleDeletedNode({

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

+45
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,50 @@ const handleDeletedNode = async ({
240240
return deletedNode
241241
}
242242

243+
function createNodeIfItDoesNotExist({
244+
nodeToUpdate,
245+
actions,
246+
createNodeId,
247+
createContentDigest,
248+
getNode,
249+
reporter,
250+
}) {
251+
if (!nodeToUpdate) {
252+
reporter.warn(
253+
`The updated node was empty. The fact you're seeing this warning means there's probably a bug in how we're creating and processing updates from Drupal.
254+
255+
${JSON.stringify(nodeToUpdate, null, 4)}
256+
`
257+
)
258+
259+
return
260+
}
261+
262+
const { createNode } = actions
263+
const newNodeId = createNodeId(
264+
createNodeIdWithVersion(
265+
nodeToUpdate.id,
266+
nodeToUpdate.type,
267+
getOptions().languageConfig ? nodeToUpdate.langcode : `und`,
268+
nodeToUpdate.meta?.target_version,
269+
getOptions().entityReferenceRevisions
270+
)
271+
)
272+
273+
const oldNode = getNode(newNodeId)
274+
// Node doesn't yet exist so we'll create it now.
275+
if (!oldNode) {
276+
const newNode = nodeFromData(
277+
nodeToUpdate,
278+
createNodeId,
279+
getOptions().entityReferenceRevisions
280+
)
281+
282+
newNode.internal.contentDigest = createContentDigest(newNode)
283+
createNode(newNode)
284+
}
285+
}
286+
243287
const handleWebhookUpdate = async (
244288
{
245289
nodeToUpdate,
@@ -371,3 +415,4 @@ ${JSON.stringify(nodeToUpdate, null, 4)}
371415

372416
exports.handleWebhookUpdate = handleWebhookUpdate
373417
exports.handleDeletedNode = handleDeletedNode
418+
exports.createNodeIfItDoesNotExist = createNodeIfItDoesNotExist

0 commit comments

Comments
 (0)