Skip to content

Commit 474d91b

Browse files
pedepwopian
andauthored
fix(kitsu-core): Merge meta keys to preserve data (#853)
Previously only the meta from the resource identifier object was preserved, while the resource object meta was discarded, resulting in some cases where meta would be set to undefined. The meta keys are now merged instead of picked between, preserving the largest amount of data possible. Co-authored-by: James Harris <[email protected]>
1 parent be77507 commit 474d91b

File tree

2 files changed

+269
-3
lines changed

2 files changed

+269
-3
lines changed

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

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,271 @@ describe('kitsu-core', () => {
815815
expect(input).toEqual(output)
816816
})
817817

818+
it('merges meta from relationship object and resource object', () => {
819+
expect.assertions(1)
820+
821+
const input = JSON.parse(stringify(deserialise({
822+
data: [
823+
{
824+
id: 1,
825+
type: 'anime',
826+
relationships: {
827+
primary_category: {
828+
meta: { qux: true },
829+
data: { id: 1, type: 'category', meta: { foo: true } }
830+
},
831+
categories: {
832+
meta: { qux: true },
833+
data: [ { id: 1, type: 'category', meta: { foo: true } } ]
834+
}
835+
}
836+
},
837+
{
838+
id: 2,
839+
type: 'anime',
840+
relationships: {
841+
primary_category: {
842+
meta: { quux: true },
843+
data: { id: 1, type: 'category', meta: { bar: true } }
844+
},
845+
categories: {
846+
meta: { quux: true },
847+
data: [ { id: 1, type: 'category', meta: { bar: true } } ]
848+
}
849+
}
850+
},
851+
{
852+
id: 3,
853+
type: 'anime',
854+
relationships: {
855+
primary_category: {
856+
meta: { corge: true },
857+
data: { id: 1, type: 'category' }
858+
},
859+
categories: {
860+
meta: { corge: true },
861+
data: [ { id: 1, type: 'category' } ]
862+
}
863+
}
864+
},
865+
{
866+
id: 4,
867+
type: 'anime',
868+
relationships: {
869+
primary_category: {
870+
meta: { grault: true },
871+
data: { id: 1, type: 'category', meta: { baz: false } }
872+
},
873+
categories: {
874+
meta: { grault: true },
875+
data: [ { id: 1, type: 'category', meta: { baz: false } } ]
876+
}
877+
}
878+
}
879+
],
880+
included: [ { id: 1, type: 'category', attributes: { title: 'foobar' }, meta: { baz: true } } ]
881+
})))
882+
883+
const output = {
884+
data: [
885+
{
886+
primary_category: {
887+
meta: { qux: true },
888+
data: {
889+
id: 1,
890+
type: 'category',
891+
title: 'foobar',
892+
meta: {
893+
baz: true,
894+
foo: true
895+
}
896+
}
897+
},
898+
categories: {
899+
meta: { qux: true },
900+
data: [
901+
{
902+
id: 1,
903+
meta: {
904+
baz: true,
905+
foo: true
906+
},
907+
title: 'foobar',
908+
type: 'category'
909+
}
910+
]
911+
},
912+
id: 1,
913+
type: 'anime'
914+
},
915+
{
916+
primary_category: {
917+
meta: { quux: true },
918+
data: {
919+
id: 1,
920+
type: 'category',
921+
title: 'foobar',
922+
meta: {
923+
baz: true,
924+
bar: true
925+
}
926+
}
927+
},
928+
categories: {
929+
meta: { quux: true },
930+
data: [
931+
{
932+
id: 1,
933+
meta: {
934+
baz: true,
935+
bar: true
936+
},
937+
title: 'foobar',
938+
type: 'category'
939+
}
940+
]
941+
},
942+
id: 2,
943+
type: 'anime'
944+
},
945+
{
946+
primary_category: {
947+
meta: { corge: true },
948+
data: {
949+
id: 1,
950+
type: 'category',
951+
title: 'foobar',
952+
meta: {
953+
baz: true
954+
}
955+
}
956+
},
957+
categories: {
958+
meta: { corge: true },
959+
data: [
960+
{
961+
id: 1,
962+
title: 'foobar',
963+
type: 'category',
964+
meta: {
965+
baz: true
966+
}
967+
}
968+
]
969+
},
970+
id: 3,
971+
type: 'anime'
972+
},
973+
{
974+
primary_category: {
975+
meta: { grault: true },
976+
data: {
977+
id: 1,
978+
type: 'category',
979+
title: 'foobar',
980+
meta: {
981+
baz: false
982+
}
983+
}
984+
},
985+
categories: {
986+
meta: { grault: true },
987+
data: [
988+
{
989+
id: 1,
990+
title: 'foobar',
991+
type: 'category',
992+
meta: {
993+
baz: false
994+
}
995+
}
996+
]
997+
},
998+
id: 4,
999+
type: 'anime'
1000+
}
1001+
]
1002+
}
1003+
1004+
expect(input).toEqual(output)
1005+
})
1006+
1007+
it('preserves meta from included resource object', () => {
1008+
expect.assertions(1)
1009+
1010+
const input = JSON.parse(stringify(deserialise({
1011+
data: {
1012+
id: '1',
1013+
type: 'users',
1014+
relationships: {
1015+
followers: {
1016+
links: {
1017+
self: 'https://kitsu.example/users/1/relationships/followers',
1018+
related: 'https://kitsu.example/users/1/followers'
1019+
},
1020+
data: [ {
1021+
type: 'follows',
1022+
id: '1'
1023+
} ]
1024+
}
1025+
}
1026+
},
1027+
included: [
1028+
{
1029+
id: '1',
1030+
type: 'follows',
1031+
attributes: { a: 123 },
1032+
links: {
1033+
self: 'https://kitsu.example/follows/1'
1034+
},
1035+
meta: { value: 1 },
1036+
relationships: {
1037+
follower: {
1038+
links: {
1039+
self: 'https://kitsu.io/follows/1/relationships/follower',
1040+
related: 'https://kitsu.io/follows/1/follower'
1041+
}
1042+
}
1043+
}
1044+
}
1045+
]
1046+
})))
1047+
1048+
const output = {
1049+
data: {
1050+
id: '1',
1051+
type: 'users',
1052+
followers: {
1053+
links: {
1054+
self: 'https://kitsu.example/users/1/relationships/followers',
1055+
related: 'https://kitsu.example/users/1/followers'
1056+
},
1057+
data: [
1058+
{
1059+
id: '1',
1060+
type: 'follows',
1061+
a: 123,
1062+
links: {
1063+
self: 'https://kitsu.example/follows/1'
1064+
},
1065+
meta: {
1066+
value: 1
1067+
},
1068+
follower: {
1069+
links: {
1070+
self: 'https://kitsu.io/follows/1/relationships/follower',
1071+
related: 'https://kitsu.io/follows/1/follower'
1072+
}
1073+
}
1074+
}
1075+
]
1076+
}
1077+
}
1078+
}
1079+
1080+
expect(input).toEqual(output)
1081+
})
1082+
8181083
it('Deserializes nested single circular resource', () => {
8191084
expect.assertions(1)
8201085

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ function link ({ id, type, meta }, included, previouslyLinked, relationshipCache
2121
if (filtered.relationships) {
2222
linkRelationships(filtered, included, previouslyLinked, relationshipCache)
2323
}
24-
if (meta) filtered.meta = meta
2524

2625
return deattribute(filtered)
2726
}
@@ -47,7 +46,7 @@ function linkArray (data, included, key, previouslyLinked, relationshipCache) {
4746
for (const resource of data.relationships[key].data) {
4847
const cache = previouslyLinked[`${resource.type}#${resource.id}`]
4948
let relationship = cache || link(resource, included, previouslyLinked, relationshipCache)
50-
if (resource.meta !== relationship.meta) relationship = { ...relationship, meta: resource.meta }
49+
if (resource.meta || relationship.meta) { relationship = { ...relationship, meta: { ...relationship.meta, ...resource.meta } } }
5150
data[key].data.push(relationship)
5251
}
5352

@@ -75,7 +74,7 @@ function linkObject (data, included, key, previouslyLinked, relationshipCache) {
7574
if (!isDeepEqual(cache.meta, resource.meta)) {
7675
resourceCache = {
7776
...cache,
78-
meta: resource.meta
77+
meta: { ...cache.meta, ...resource.meta }
7978
}
8079
} else {
8180
resourceCache = cache
@@ -86,6 +85,8 @@ function linkObject (data, included, key, previouslyLinked, relationshipCache) {
8685
data[key].data = link(resource, included, previouslyLinked, relationshipCache)
8786
}
8887

88+
if (resource.meta || data[key].data.meta) { data[key].data = { ...data[key].data, meta: { ...data[key].data.meta, ...resource.meta } } }
89+
8990
const cacheKey = `${data.type}#${data.id}#${key}`
9091
const relationships = relationshipCache[cacheKey] || data.relationships[key]
9192
if (!relationshipCache[cacheKey]) relationshipCache[cacheKey] = relationships

0 commit comments

Comments
 (0)