Skip to content

Commit

Permalink
feat(#639): add cache controls to druxt vuex store
Browse files Browse the repository at this point in the history
  • Loading branch information
Decipher committed Jun 29, 2023
1 parent aacb500 commit 6af4377
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .changeset/few-pets-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"druxt": minor
---

feat(#639): added druxt/flushCollection and druxt/flushResource mutations
feat(#639): added bypassCache option to druxt/getCollection and druxt/getResource actions
95 changes: 88 additions & 7 deletions packages/druxt/src/stores/druxt.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,44 @@ const DruxtStore = ({ store }) => {

Vue.set(state.resources[type][id], prefix, resource)
},

/**
* @name flushCollection
* @mutator {object} flushCollection=collections Removes JSON:API collections from the Vuex state object.
* @param {flushCollectionContext} context
*
* @example @lang js
* // Flush all collections.
* this.$store.commit('druxt/flushCollection', {})
*
* // Flush target collection.
* this.$store.commit('druxt/flushCollection', { type, hash, prefix })
*/
flushCollection (state, { type, hash, prefix }) {
if (!type) Vue.set(state, 'collections', {})
else if (type && !hash && !prefix) Vue.set(state.collections, type, {})
else if (type && hash && !prefix) Vue.set(state.collections[type], hash, {})
else if (type && hash && prefix) Vue.set(state.collections[type][hash], prefix, {})
},

/**
* @name flushResource
* @mutator {object} flushResource=resources Removes JSON:API resources from the Vuex state object.
* @param {flushResourceContext} context
*
* @example @lang js
* // Flush all resources.
* this.$store.commit('druxt/flushResources', {})
*
* // Flush target resource.
* this.$store.commit('druxt/flushResources', { id, type, prefix, hash })
*/
flushResource (state, { type, id, prefix }) {
if (!type) Vue.set(state, 'resources', {})
else if (type && !id && !prefix) Vue.set(state.resources, type, {})
else if (type && id && !prefix) Vue.set(state.resources[type], id, {})
else if (type && id && prefix) Vue.set(state.resources[type][id], prefix, {})
}
},

/**
Expand All @@ -159,15 +197,16 @@ const DruxtStore = ({ store }) => {
* const resources = await this.$store.dispatch('druxt/getCollection', {
* type: 'node--article',
* query: new DrupalJsonApiParams().addFilter('status', '1'),
* bypassCache: false
* })
*/
async getCollection ({ commit, state }, { type, query, prefix }) {
async getCollection ({ commit, state }, { type, query, prefix, bypassCache = false }) {
// Generate a hash using query data excluding the 'fields' and 'include' data.
const queryObject = getDrupalJsonApiParams(query).getQueryObject()
const hash = query ? md5(JSON.stringify({ ...queryObject, fields: {}, include: [] })) : '_default'

// If collection hash exists, re-hydrate and return the data.
if (((state.collections[type] || {})[hash] || {})[prefix]) {
if (!bypassCache && ((state.collections[type] || {})[hash] || {})[prefix]) {
return {
...state.collections[type][hash][prefix],
// Hydrate resource data.
Expand Down Expand Up @@ -197,11 +236,15 @@ const DruxtStore = ({ store }) => {
* @return {object} The Drupal JSON:API resource.
*
* @example @lang js
* const resource = await this.$store.dispatch('druxt/getResource', { type: 'node--article', id })
* const resource = await this.$store.dispatch('druxt/getResource', {
* type: 'node--article',
* id,
* bypassCache: false
* })
*/
async getResource ({ commit, dispatch, state }, { type, id, query, prefix }) {
async getResource ({ commit, dispatch, state }, { type, id, query, prefix, bypassCache = false }) {
// Get the resource from the store if it's avaialble.
const storedResource = ((state.resources[type] || {})[id] || {})[prefix] ?
const storedResource = !bypassCache && ((state.resources[type] || {})[id] || {})[prefix] ?
{ ...state.resources[type][id][prefix] }
: null

Expand Down Expand Up @@ -351,6 +394,40 @@ export { DruxtStore }
* }
*/

/**
* Parameters for the `flushCollection` mutation.
*
* @typedef {object} flushCollectionContext
*
* @param {string} type - The JSON:API collection resource type.
* @param {string} hash - An md5 hash of the query string.
* @param {string} [prefix] - (Optional) The JSON:API endpoint prefix or langcode.
*
* @example @lang js
* {
* type: 'node--page',
* hash: '_default',
* prefix: 'en'
* }
*/

/**
* Parameters for the `flushResource` mutation.
*
* @typedef {object} flushResourceContext
*
* @param {string} [type] - The JSON:API Resource type.
* @param {string} [id] - The Drupal resource UUID.
* @param {string} [prefix] - (Optional) The JSON:API endpoint prefix or langcode.
*
* @example @lang js
* {
* type: 'node--page',
* id: 'd8dfd355-7f2f-4fc3-a149-288e4e293bdd',
* prefix: 'en'
* }
*/

/**
* Parameters for the `getCollection` action.
*
Expand All @@ -359,11 +436,13 @@ export { DruxtStore }
* @param {string} type - The JSON:API collection resource type.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
* @param {string} [prefix] - (Optional) The JSON:API endpoint prefix or langcode.
* @param {boolean} [bypassCache] - (Optional) Bypass the Vuex cached collection.
*
* @example @lang js
* {
* type: 'node--page',
* query: new DrupalJsonApiParams().addFilter('status', '1')
* query: new DrupalJsonApiParams().addFilter('status', '1'),
* bypassCache: false
* }
*/

Expand All @@ -376,12 +455,14 @@ export { DruxtStore }
* @param {string} id - The Drupal resource UUID.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
* @param {string} [prefix] - (Optional) The JSON:API endpoint prefix or langcode.
* @param {boolean} [bypassCache] - (Optional) Bypass the Vuex cached resource.
*
* @example @lang js
* {
* type: 'node--page',
* id: 'd8dfd355-7f2f-4fc3-a149-288e4e293bdd',
* prefix: 'en'
* prefix: 'en',
* bypassCache: false
* }
*/

Expand Down
47 changes: 47 additions & 0 deletions packages/druxt/test/stores/druxt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,51 @@ describe('DruxtStore', () => {
await store.dispatch('druxt/getCollection', { type: 'node--page', query: {} })
expect(mockAxios.get).toHaveBeenCalledTimes(2)
})

test('flushCollection', async () => {
const type = 'node--page'
const hash ='_default'
const prefix = 'en'

// Ensure that the results state is populated.
const collection = await getMockCollection(type)
store.commit('druxt/addCollection', { collection, type, prefix, hash })
expect(store.state.druxt.collections[type][hash][prefix]).toStrictEqual(collection)

store.commit('druxt/flushCollection', { type, hash, prefix })
expect(store.state.druxt.collections[type][hash][prefix]).toStrictEqual({})

store.commit('druxt/flushCollection', { type, hash })
expect(store.state.druxt.collections[type][hash]).toStrictEqual({})

store.commit('druxt/flushCollection', { type })
expect(store.state.druxt.collections[type]).toStrictEqual({})

store.commit('druxt/flushCollection', {})
expect(store.state.druxt.collections).toStrictEqual({})

})

test('flushResource', async () => {
const type = 'node--page'
const prefix = 'en'

// Ensure that the results state is populated.
const resource = await getMockResource(type)
const id = resource.data.id
store.commit('druxt/addResource', { prefix, resource })
expect(store.state.druxt.resources[type][id][prefix]).toStrictEqual(resource)

store.commit('druxt/flushResource', { type, id, prefix })
expect(store.state.druxt.resources[type][id][prefix]).toStrictEqual({})

store.commit('druxt/flushResource', { type, id })
expect(store.state.druxt.resources[type][id]).toStrictEqual({})

store.commit('druxt/flushResource', { type })
expect(store.state.druxt.resources[type]).toStrictEqual({})

store.commit('druxt/flushResource', {})
expect(store.state.druxt.resources).toStrictEqual({})
})
})

0 comments on commit 6af4377

Please sign in to comment.