From fc5455e4f9849660b48bb69d10f01e1746ef588d Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 13 Sep 2022 20:46:06 -0700 Subject: [PATCH] feat(7): replace FormData objects with k-v map in object-hash replacer --- README.md | 18 +++++++++ src/cachios.js | 22 ++++++++++- tests/getReplaced.spec.js | 79 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 tests/getReplaced.spec.js diff --git a/README.md b/README.md index 77a0b2a..c09713c 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,24 @@ cachios.getCacheIdentifier = function (config) { }; ``` +### Custom object-hash Replacer + +By default, Cachios uses an internal `defaultReplacer` function to add FormData support to [object-hash](https://github.com/puleos/object-hash). + +To override this, set the `getReplaced` property of your Cachios instance: + +```js +const cachios = require('cachios'); + +cachios.getReplaced = function (thing) { + if (thing === 'foo') { + return 'bar'; + } + + return thing; +}; +``` + ## License [MIT](LICENSE.md) diff --git a/src/cachios.js b/src/cachios.js index 773d3d1..5343e16 100644 --- a/src/cachios.js +++ b/src/cachios.js @@ -18,6 +18,23 @@ function defaultResponseCopier(response) { }; } +function defaultReplacer(thing) { + // object-hash doesn't handle FormData values, do it ourselves + // https://github.com/AlbinoDrought/cachios/issues/7 + if (typeof FormData !== 'undefined' && thing instanceof FormData) { + var formDataValues = {}; + var entriesIterator = thing.entries(); + for (var entry = entriesIterator.next(); !entry.done || typeof entry.value !== 'undefined'; entry = entriesIterator.next()) { + formDataValues[entry.value[0]] = defaultReplacer(entry.value[1]); + } + return formDataValues; + } + + // object-hash also doesn't support blobs, but I don't think we can read those synchronously + + return thing; +} + function Cachios(axiosInstance, nodeCacheConf) { this.axiosInstance = axiosInstance; this.cache = new NodeCache(nodeCacheConf || { @@ -29,10 +46,13 @@ function Cachios(axiosInstance, nodeCacheConf) { this.getCacheIdentifier = defaultCacheIdentifer; this.getResponseCopy = defaultResponseCopier; + this.getReplaced = defaultReplacer; } Cachios.prototype.getCacheKey = function (config) { - return hash(this.getCacheIdentifier(config)); + return hash(this.getCacheIdentifier(config), { + replacer: this.getReplaced, + }); }; Cachios.prototype.getCachedValue = function (cacheKey) { diff --git a/tests/getReplaced.spec.js b/tests/getReplaced.spec.js new file mode 100644 index 0000000..f8fa1e9 --- /dev/null +++ b/tests/getReplaced.spec.js @@ -0,0 +1,79 @@ +/** + * @jest-environment jsdom + */const cachios = require('./../src'); + +const axios = require('axios'); +const hash = require('object-hash'); + +describe('cachios.getReplaced', () => { + test('should be set by default', () => { + expect(cachios.getReplaced).toBeDefined(); + }); + + test('should not modify common values', () => { + [ + { foo: 'bar' }, + 1234, + 'Melon', + 1.234, + null, + undefined, + ].forEach((thing) => { + expect(cachios.getReplaced(thing)).toEqual(thing); + }); + }); + + test('should be used when creating cache keys', () => { + const instance = cachios.create(axios); + + instance.getReplaced = (thing) => { + console.log(thing); + if (thing === 'bar') { + return 'baz'; + } + return thing; + }; + + const expected = hash({ + method: 'GET', + url: '/something', + params: { + foo: 'baz', + }, + data: { + stuff: [ + { foo: 'baz' }, + ], + }, + }); + + const actual = instance.getCacheKey({ + method: 'GET', + url: '/something', + params: { + foo: 'bar', + }, + data: { + stuff: [ + { foo: 'bar' }, + ], + }, + }); + + expect(actual).toBe(expected); + }); + + test('should transform FormData to an object', () => { + const instance = cachios.create(axios); + + const fd = new FormData(); + fd.append('foo', 'bar'); + fd.append('transform', 'hello'); + + expect(instance.getReplaced(fd)).toEqual({ + foo: 'bar', + transform: 'hello', + }); + console.log(typeof cachios); + }); +});