Skip to content

Commit

Permalink
fix(kitsu-core): Merge meta keys to preserve data (#853)
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
pedep and wopian authored Apr 26, 2023
1 parent be77507 commit 474d91b
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 3 deletions.
265 changes: 265 additions & 0 deletions packages/kitsu-core/src/deserialise/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,271 @@ describe('kitsu-core', () => {
expect(input).toEqual(output)
})

it('merges meta from relationship object and resource object', () => {
expect.assertions(1)

const input = JSON.parse(stringify(deserialise({
data: [
{
id: 1,
type: 'anime',
relationships: {
primary_category: {
meta: { qux: true },
data: { id: 1, type: 'category', meta: { foo: true } }
},
categories: {
meta: { qux: true },
data: [ { id: 1, type: 'category', meta: { foo: true } } ]
}
}
},
{
id: 2,
type: 'anime',
relationships: {
primary_category: {
meta: { quux: true },
data: { id: 1, type: 'category', meta: { bar: true } }
},
categories: {
meta: { quux: true },
data: [ { id: 1, type: 'category', meta: { bar: true } } ]
}
}
},
{
id: 3,
type: 'anime',
relationships: {
primary_category: {
meta: { corge: true },
data: { id: 1, type: 'category' }
},
categories: {
meta: { corge: true },
data: [ { id: 1, type: 'category' } ]
}
}
},
{
id: 4,
type: 'anime',
relationships: {
primary_category: {
meta: { grault: true },
data: { id: 1, type: 'category', meta: { baz: false } }
},
categories: {
meta: { grault: true },
data: [ { id: 1, type: 'category', meta: { baz: false } } ]
}
}
}
],
included: [ { id: 1, type: 'category', attributes: { title: 'foobar' }, meta: { baz: true } } ]
})))

const output = {
data: [
{
primary_category: {
meta: { qux: true },
data: {
id: 1,
type: 'category',
title: 'foobar',
meta: {
baz: true,
foo: true
}
}
},
categories: {
meta: { qux: true },
data: [
{
id: 1,
meta: {
baz: true,
foo: true
},
title: 'foobar',
type: 'category'
}
]
},
id: 1,
type: 'anime'
},
{
primary_category: {
meta: { quux: true },
data: {
id: 1,
type: 'category',
title: 'foobar',
meta: {
baz: true,
bar: true
}
}
},
categories: {
meta: { quux: true },
data: [
{
id: 1,
meta: {
baz: true,
bar: true
},
title: 'foobar',
type: 'category'
}
]
},
id: 2,
type: 'anime'
},
{
primary_category: {
meta: { corge: true },
data: {
id: 1,
type: 'category',
title: 'foobar',
meta: {
baz: true
}
}
},
categories: {
meta: { corge: true },
data: [
{
id: 1,
title: 'foobar',
type: 'category',
meta: {
baz: true
}
}
]
},
id: 3,
type: 'anime'
},
{
primary_category: {
meta: { grault: true },
data: {
id: 1,
type: 'category',
title: 'foobar',
meta: {
baz: false
}
}
},
categories: {
meta: { grault: true },
data: [
{
id: 1,
title: 'foobar',
type: 'category',
meta: {
baz: false
}
}
]
},
id: 4,
type: 'anime'
}
]
}

expect(input).toEqual(output)
})

it('preserves meta from included resource object', () => {
expect.assertions(1)

const input = JSON.parse(stringify(deserialise({
data: {
id: '1',
type: 'users',
relationships: {
followers: {
links: {
self: 'https://kitsu.example/users/1/relationships/followers',
related: 'https://kitsu.example/users/1/followers'
},
data: [ {
type: 'follows',
id: '1'
} ]
}
}
},
included: [
{
id: '1',
type: 'follows',
attributes: { a: 123 },
links: {
self: 'https://kitsu.example/follows/1'
},
meta: { value: 1 },
relationships: {
follower: {
links: {
self: 'https://kitsu.io/follows/1/relationships/follower',
related: 'https://kitsu.io/follows/1/follower'
}
}
}
}
]
})))

const output = {
data: {
id: '1',
type: 'users',
followers: {
links: {
self: 'https://kitsu.example/users/1/relationships/followers',
related: 'https://kitsu.example/users/1/followers'
},
data: [
{
id: '1',
type: 'follows',
a: 123,
links: {
self: 'https://kitsu.example/follows/1'
},
meta: {
value: 1
},
follower: {
links: {
self: 'https://kitsu.io/follows/1/relationships/follower',
related: 'https://kitsu.io/follows/1/follower'
}
}
}
]
}
}
}

expect(input).toEqual(output)
})

it('Deserializes nested single circular resource', () => {
expect.assertions(1)

Expand Down
7 changes: 4 additions & 3 deletions packages/kitsu-core/src/linkRelationships/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ function link ({ id, type, meta }, included, previouslyLinked, relationshipCache
if (filtered.relationships) {
linkRelationships(filtered, included, previouslyLinked, relationshipCache)
}
if (meta) filtered.meta = meta

return deattribute(filtered)
}
Expand All @@ -47,7 +46,7 @@ function linkArray (data, included, key, previouslyLinked, relationshipCache) {
for (const resource of data.relationships[key].data) {
const cache = previouslyLinked[`${resource.type}#${resource.id}`]
let relationship = cache || link(resource, included, previouslyLinked, relationshipCache)
if (resource.meta !== relationship.meta) relationship = { ...relationship, meta: resource.meta }
if (resource.meta || relationship.meta) { relationship = { ...relationship, meta: { ...relationship.meta, ...resource.meta } } }
data[key].data.push(relationship)
}

Expand Down Expand Up @@ -75,7 +74,7 @@ function linkObject (data, included, key, previouslyLinked, relationshipCache) {
if (!isDeepEqual(cache.meta, resource.meta)) {
resourceCache = {
...cache,
meta: resource.meta
meta: { ...cache.meta, ...resource.meta }
}
} else {
resourceCache = cache
Expand All @@ -86,6 +85,8 @@ function linkObject (data, included, key, previouslyLinked, relationshipCache) {
data[key].data = link(resource, included, previouslyLinked, relationshipCache)
}

if (resource.meta || data[key].data.meta) { data[key].data = { ...data[key].data, meta: { ...data[key].data.meta, ...resource.meta } } }

const cacheKey = `${data.type}#${data.id}#${key}`
const relationships = relationshipCache[cacheKey] || data.relationships[key]
if (!relationshipCache[cacheKey]) relationshipCache[cacheKey] = relationships
Expand Down

0 comments on commit 474d91b

Please sign in to comment.