Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lucky-moons-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'druxt': patch
---

fix(#781): re-hydrate included resources on getCollection cache hit
11 changes: 7 additions & 4 deletions packages/druxt/src/stores/druxt.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ const DruxtStore = ({ store }) => {
// Store and dehydrate collection resources.
collection.data = dehydrateResources({ commit: this.commit, prefix, queryObject, resources: collection.data })

// Extract and store included resources.
// Keep the dehydrated refs (don't delete) so a cache hit in
// getCollection can re-hydrate `included`, same as `data`.
if (collection.included) {
collection.included = dehydrateResources({ commit: this.commit, prefix, queryObject, resources: collection.included })
delete collection.included
}

// Recursively merge new collection data into stored collection.
Expand Down Expand Up @@ -207,10 +207,13 @@ const DruxtStore = ({ store }) => {

// If collection hash exists, re-hydrate and return the data.
if (!bypassCache && ((state.collections[type] || {})[hash] || {})[prefix]) {
const cached = state.collections[type][hash][prefix]
return {
...state.collections[type][hash][prefix],
...cached,
// Hydrate resource data.
data: state.collections[type][hash][prefix].data.map((o) => ((state.resources[o.type][o.id] || {})[prefix] || {}).data)
data: cached.data.map((o) => ((state.resources[o.type][o.id] || {})[prefix] || {}).data),
// Same for included - a cache hit must match a fresh fetch.
...(cached.included ? { included: cached.included.map((o) => ((state.resources[o.type][o.id] || {})[prefix] || {}).data) } : {}),
}
}

Expand Down
28 changes: 26 additions & 2 deletions packages/druxt/test/stores/druxt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,12 @@ describe('DruxtStore', () => {
expect.objectContaining({ id, type: 'node--page' })
)

// Expect the collection be stored without included data.
expect(store.state.druxt.collections['node--page']._default[undefined].included).toBeFalsy()
// Expect the collection be stored with dehydrated (not dropped)
// included resources, so a later cache hit can re-hydrate `included`
// the same way it re-hydrates `data`.
expect(store.state.druxt.collections['node--page']._default[undefined].included[0]).toStrictEqual(
expect.objectContaining({ id: included[0].id, type: 'node--article' })
)
})

test('addResource', async () => {
Expand Down Expand Up @@ -299,6 +303,26 @@ describe('DruxtStore', () => {
expect(mockAxios.get).toHaveBeenCalledTimes(2)
})

test('getCollection cache hit re-hydrates included data', async () => {
const mockCollectionPage = await getMockCollection('node--page')
const includedId = 'included-article-uuid'
store.commit('druxt/addCollection', {
collection: {
...mockCollectionPage,
included: [{ type: 'node--article', id: includedId, attributes: {} }],
},
type: 'node--page',
hash: '_default',
})

// A cache hit must return `included` the same way a fresh fetch would.
const cached = await store.dispatch('druxt/getCollection', { type: 'node--page' })
expect(cached.included).toHaveLength(1)
expect(cached.included[0]).toStrictEqual(
expect.objectContaining({ id: includedId, type: 'node--article' })
)
})

test('flushCollection', async () => {
const type = 'node--page'
const hash ='_default'
Expand Down
Loading