Skip to content

Commit

Permalink
refactor: allow storages not return promises
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurfiorette committed Jan 4, 2022
1 parent 16600b0 commit 567c1b2
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 10 deletions.
6 changes: 6 additions & 0 deletions src/cache/create.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { AxiosInstance } from 'axios';
import { isStorage } from '..';
import { defaultHeaderInterpreter } from '../header/interpreter';
import { CacheRequestInterceptor } from '../interceptors/request';
import { CacheResponseInterceptor } from '../interceptors/response';
Expand Down Expand Up @@ -62,6 +63,11 @@ export function setupCache(
const axiosCache = axios as AxiosCacheInstance;

axiosCache.storage = storage || buildMemoryStorage();

if (!isStorage(axiosCache.storage)) {
throw new Error('create an storage with buildStorage()');
}

axiosCache.generateKey = generateKey || defaultKeyGenerator;
axiosCache.waiting = waiting || {};
axiosCache.headerInterpreter = headerInterpreter || defaultHeaderInterpreter;
Expand Down
11 changes: 11 additions & 0 deletions src/storage/build.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { Header } from '../util/headers';
import type { AxiosStorage, StaleStorageValue } from './types';

const storage = Symbol();

/**
* Returns true if the provided object was created from {@link buildStorage} function.
*/
export const isStorage = (obj: any): obj is AxiosStorage => !!obj && !!obj[storage];

/**
* Builds a custom storage.
*
* **Note**: You can only create an custom storage with this function.
*
* @example
*
* ```js
Expand All @@ -22,6 +31,8 @@ export function buildStorage({
remove
}: Omit<AxiosStorage, 'get'>): AxiosStorage {
return {
//@ts-expect-error - we don't want to expose this
[storage]: 1,
set,
find,
remove,
Expand Down
6 changes: 3 additions & 3 deletions src/storage/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ import type { StorageValue } from './types';
export function buildMemoryStorage() {
const data: Record<string, StorageValue> = {};
const storage = buildStorage({
find: (key) => Promise.resolve(data[key]),
set: (key, value) => Promise.resolve(void (data[key] = value)),
remove: (key) => Promise.resolve(void delete data[key])
find: (key) => data[key],
set: (key, value) => void (data[key] = value),
remove: (key) => void delete data[key]
});
return { ...storage, data };
}
10 changes: 6 additions & 4 deletions src/storage/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export type EmptyStorageValue = {
state: 'empty';
};

type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;

/**
* A storage implementation that stores data in memory.
*
Expand All @@ -73,18 +75,18 @@ export type AxiosStorage = {
* Returns the value for the given key. This method does not have to make checks for
* cache invalidation or etc. It just return what was previous saved, if present.
*/
find: (key: string) => Promise<StorageValue | undefined>;
find: (key: string) => MaybePromise<StorageValue | undefined>;

/**
* Sets a new value for the given key
*
* Use CacheStorage.remove(key) to define a key to 'empty' state.
*/
set: (key: string, value: NotEmptyStorageValue) => Promise<void>;
set: (key: string, value: NotEmptyStorageValue) => MaybePromise<void>;

/** Removes the value for the given key */
remove: (key: string) => Promise<void>;
remove: (key: string) => MaybePromise<void>;

/** Returns the value for the given key. This method make checks for cache invalidation or etc. */
get: (key: string) => Promise<StorageValue>;
get: (key: string) => MaybePromise<StorageValue>;
};
6 changes: 3 additions & 3 deletions src/storage/web-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ export function buildWebStorage(storage: Storage, prefix = '') {
return buildStorage({
find: (key: string) => {
const json = storage.getItem(prefix + key);
return Promise.resolve(json ? JSON.parse(json) : undefined);
return json ? JSON.parse(json) : undefined;
},

set: (key: string, value: any) =>
Promise.resolve(void storage.setItem(prefix + key, JSON.stringify(value))),
void storage.setItem(prefix + key, JSON.stringify(value)),

remove: (key: string) => Promise.resolve(void storage.removeItem(prefix + key))
remove: (key: string) => void storage.removeItem(prefix + key)
});
}
25 changes: 25 additions & 0 deletions test/storage/is-storage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Axios } from 'axios';
import { buildMemoryStorage, isStorage } from '../../src';
import { mockAxios } from '../mocks/axios';

it('tests isStorage function', () => {
expect(isStorage(void 0)).toBe(false);
expect(isStorage(1)).toBe(false);
expect(isStorage('a')).toBe(false);
expect(isStorage({})).toBe(false);
expect(isStorage(Axios)).toBe(false);
expect(isStorage(() => 0)).toBe(false);
expect(isStorage(null)).toBe(false);
expect(isStorage(undefined)).toBe(false);
expect(isStorage({ a: 1, b: 'a' })).toBe(false);

expect(isStorage(buildMemoryStorage())).toBe(true);
});

it('tests setupCache without proper storage', () => {
expect(() =>
mockAxios({
storage: {} as any
})
).toThrowError();
});

0 comments on commit 567c1b2

Please sign in to comment.