Skip to content

Commit d261d4c

Browse files
authored
fix(kitsu-core): prevent relationship mutation during multi-circular deserialisation (#722)
* test(kitsu-core): add test for multi-circular deserialisation specifically if Article1 and Article2 are deserialized in primary data, but also references directly by a relationship of Article1, such as Author1 This makes Article1 deserialize first, then its relationship Author1 is deserialised, along with its relationships Article1 and Article 2 Once the entire chain is complete in Article1, Article2 is deserialised in the main data, but due to being mutated by the prior deserialisation, it has no items in its relationships key * fix(kitsu-core): fix cyclic deserialisation of primary data use object assigns to ensure `delete` calls do not modify objects in future iterations of the deserialiseArray loop
1 parent 68616c4 commit d261d4c

2 files changed

Lines changed: 150 additions & 1 deletion

File tree

packages/kitsu-core/src/deserialise/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ function deserialiseArray (array) {
1212
const previouslyLinked = {}
1313
const relationshipCache = {}
1414
for (let value of array.data) {
15-
value = linkRelationships(value, [ ...array.data, ...(array.included || []) ], previouslyLinked, relationshipCache)
15+
const included = [
16+
...array.data.map(item => ({ ...item, relationships: { ...item.relationships } })),
17+
...(array.included || [])
18+
]
19+
value = linkRelationships(value, included, previouslyLinked, relationshipCache)
1620
if (value.attributes) value = deattribute(value)
1721
array.data[array.data.indexOf(value)] = value
1822
}

packages/kitsu-core/src/deserialise/index.spec.js

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,4 +1102,149 @@ describe('kitsu-core', () => {
11021102
expect(input).toEqual(output)
11031103
})
11041104
})
1105+
1106+
it('Deserializes first level resources after being serialized as a relationship', () => {
1107+
expect.assertions(1)
1108+
1109+
const input = JSON.parse(stringify(deserialise({
1110+
data: [
1111+
{
1112+
id: '5',
1113+
type: 'articles',
1114+
attributes: { title: 'asd0' },
1115+
relationships: {
1116+
author: {
1117+
data: {
1118+
id: '11',
1119+
type: 'authors'
1120+
},
1121+
links: { self: 'http://kitsu.example.com/authors' },
1122+
meta: { authors: 'articles#5' }
1123+
}
1124+
}
1125+
},
1126+
{
1127+
id: '6',
1128+
type: 'articles',
1129+
attributes: { title: 'asd1' },
1130+
relationships: {
1131+
author: {
1132+
data: {
1133+
id: '11',
1134+
type: 'authors'
1135+
},
1136+
links: { self: 'http://kitsu.example.com/authors' },
1137+
meta: { authors: 'articles#6' }
1138+
}
1139+
}
1140+
}
1141+
],
1142+
included: [
1143+
{
1144+
id: '11',
1145+
type: 'authors',
1146+
attributes: { first_name: 'Egon', last_name: 'Egonsen' },
1147+
relationships: {
1148+
articles: {
1149+
data: [
1150+
{
1151+
id: '5',
1152+
type: 'articles'
1153+
},
1154+
{
1155+
id: '6',
1156+
type: 'articles'
1157+
}
1158+
]
1159+
}
1160+
}
1161+
}
1162+
]
1163+
})))
1164+
1165+
const output = {
1166+
data: [
1167+
{
1168+
id: '5',
1169+
type: 'articles',
1170+
title: 'asd0',
1171+
author: {
1172+
links: { self: 'http://kitsu.example.com/authors' },
1173+
meta: { authors: 'articles#5' },
1174+
data: {
1175+
id: '11',
1176+
type: 'authors',
1177+
first_name: 'Egon',
1178+
last_name: 'Egonsen',
1179+
articles: {
1180+
data: [
1181+
{
1182+
id: '5',
1183+
type: 'articles',
1184+
title: 'asd0',
1185+
author: {
1186+
data: '[Circular ~.data.0.author.data]',
1187+
links: { self: 'http://kitsu.example.com/authors' },
1188+
meta: { authors: 'articles#5' }
1189+
}
1190+
},
1191+
{
1192+
id: '6',
1193+
type: 'articles',
1194+
title: 'asd1',
1195+
author: {
1196+
data: '[Circular ~.data.0.author.data]',
1197+
links: { self: 'http://kitsu.example.com/authors' },
1198+
meta: { authors: 'articles#6' }
1199+
}
1200+
}
1201+
]
1202+
}
1203+
}
1204+
}
1205+
},
1206+
{
1207+
id: '6',
1208+
type: 'articles',
1209+
title: 'asd1',
1210+
author: {
1211+
links: { self: 'http://kitsu.example.com/authors' },
1212+
meta: { authors: 'articles#6' },
1213+
data: {
1214+
id: '11',
1215+
type: 'authors',
1216+
first_name: 'Egon',
1217+
last_name: 'Egonsen',
1218+
articles: {
1219+
data: [
1220+
{
1221+
id: '5',
1222+
type: 'articles',
1223+
title: 'asd0',
1224+
author: {
1225+
data: '[Circular ~.data.1.author.data]',
1226+
links: { self: 'http://kitsu.example.com/authors' },
1227+
meta: { authors: 'articles#5' }
1228+
}
1229+
},
1230+
{
1231+
id: '6',
1232+
type: 'articles',
1233+
title: 'asd1',
1234+
author: {
1235+
data: '[Circular ~.data.1.author.data]',
1236+
links: { self: 'http://kitsu.example.com/authors' },
1237+
meta: { authors: 'articles#6' }
1238+
}
1239+
}
1240+
]
1241+
}
1242+
}
1243+
}
1244+
}
1245+
]
1246+
}
1247+
1248+
expect(input).toEqual(output)
1249+
})
11051250
})

0 commit comments

Comments
 (0)