From 8a1563401bab5ae854e7611c833ea64fff20a50d Mon Sep 17 00:00:00 2001 From: Patrick Corbett Date: Fri, 26 Mar 2021 12:36:30 +0000 Subject: [PATCH] Allow unserialised data to be written to store This PR: https://github.com/apollographql/apollo-cache-persist/pull/388 stops the cache being written as anything other than a string. The CachePersistor accepts an option "serialize: boolean" that can allow for data to be written to the store without being serialised to a string first. However with the .toString() coercion, when serialize is true, all that gets written to the store is [object object], rather than the object. This change makes sense, to bring the api inline with the web storage api. However, it means all data must be stored as JSON, which, when there is a large data set, is very expensive in memory and cpu. So this resolves the issue by putting the generic back in, removing the coercion, and assigning the appropriate generic to each of the storage wrappers (I think everything is string apart from localForage, but perhaps other wrappers can support non-string values) --- src/Storage.ts | 4 ++-- src/__tests__/Storage.ts | 18 ++++++++++++++++++ src/storageWrappers/AsyncStorageWrapper.ts | 2 +- src/storageWrappers/IonicStorageWrapper.ts | 2 +- src/storageWrappers/LocalForageWrapper.ts | 2 +- src/storageWrappers/LocalStorageWrapper.ts | 2 +- src/storageWrappers/MMKVStorageWrapper.ts | 2 +- src/storageWrappers/SessionStorageWrapper.ts | 2 +- src/types/index.ts | 10 +++++----- 9 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/Storage.ts b/src/Storage.ts index 42094847..c458fdab 100644 --- a/src/Storage.ts +++ b/src/Storage.ts @@ -5,7 +5,7 @@ import { } from './types'; export default class Storage { - storage: PersistentStorage; + storage: PersistentStorage>; key: string; constructor(options: ApolloPersistOptions) { @@ -20,7 +20,7 @@ export default class Storage { } async write(data: PersistedData): Promise { - await this.storage.setItem(this.key, data.toString()); + await this.storage.setItem(this.key, data); } async purge(): Promise { diff --git a/src/__tests__/Storage.ts b/src/__tests__/Storage.ts index 16770fce..fa41ab00 100644 --- a/src/__tests__/Storage.ts +++ b/src/__tests__/Storage.ts @@ -12,4 +12,22 @@ describe('Storage', () => { await storage.purge(); await expect(storage.read()).resolves.toBe(undefined); }); + + describe('when data is an object', () => { + it ('writes an object to persistent storage', async () => { + const obj = { + yo: 'yo yo' + } + + await expect(storage.write(obj)).resolves.toBe(undefined); + await expect(storage.read()).resolves.toBe(obj); + }) + }) + + describe('when data is a string', () => { + it ('writes a string to persistent storage', async () => { + await expect(storage.write('yo yo yo')).resolves.toBe(undefined); + await expect(storage.read()).resolves.toBe('yo yo yo'); + }) + }) }); diff --git a/src/storageWrappers/AsyncStorageWrapper.ts b/src/storageWrappers/AsyncStorageWrapper.ts index 5d423aeb..3eeb4da9 100644 --- a/src/storageWrappers/AsyncStorageWrapper.ts +++ b/src/storageWrappers/AsyncStorageWrapper.ts @@ -12,7 +12,7 @@ import { PersistentStorage } from '../types'; * }); * */ -export class AsyncStorageWrapper implements PersistentStorage { +export class AsyncStorageWrapper implements PersistentStorage { // Actual type definition: https://github.com/react-native-async-storage/async-storage/blob/master/types/index.d.ts private storage; diff --git a/src/storageWrappers/IonicStorageWrapper.ts b/src/storageWrappers/IonicStorageWrapper.ts index e6ed0ba6..27ed0244 100644 --- a/src/storageWrappers/IonicStorageWrapper.ts +++ b/src/storageWrappers/IonicStorageWrapper.ts @@ -1,6 +1,6 @@ import { PersistentStorage } from '../types'; -export class IonicStorageWrapper implements PersistentStorage { +export class IonicStorageWrapper implements PersistentStorage { // Actual type definition: https://github.com/ionic-team/ionic-storage/blob/main/src/storage.ts#L102 private storage; diff --git a/src/storageWrappers/LocalForageWrapper.ts b/src/storageWrappers/LocalForageWrapper.ts index 3372773d..19e988ab 100644 --- a/src/storageWrappers/LocalForageWrapper.ts +++ b/src/storageWrappers/LocalForageWrapper.ts @@ -1,6 +1,6 @@ import { PersistentStorage } from '../types'; -export class LocalForageWrapper implements PersistentStorage { +export class LocalForageWrapper implements PersistentStorage { // Actual type definition: https://github.com/localForage/localForage/blob/master/typings/localforage.d.ts#L17 private storage; diff --git a/src/storageWrappers/LocalStorageWrapper.ts b/src/storageWrappers/LocalStorageWrapper.ts index a1aead42..5fb8ea8e 100644 --- a/src/storageWrappers/LocalStorageWrapper.ts +++ b/src/storageWrappers/LocalStorageWrapper.ts @@ -1,6 +1,6 @@ import { PersistentStorage } from '../types'; -export class LocalStorageWrapper implements PersistentStorage { +export class LocalStorageWrapper implements PersistentStorage { // Actual type definition: https://github.com/microsoft/TypeScript/blob/master/lib/lib.dom.d.ts#L15286 private storage; diff --git a/src/storageWrappers/MMKVStorageWrapper.ts b/src/storageWrappers/MMKVStorageWrapper.ts index 15140b54..ef983b04 100644 --- a/src/storageWrappers/MMKVStorageWrapper.ts +++ b/src/storageWrappers/MMKVStorageWrapper.ts @@ -11,7 +11,7 @@ import { PersistentStorage } from '../types'; * }); * */ -export class MMKVStorageWrapper implements PersistentStorage { +export class MMKVStorageWrapper implements PersistentStorage { // Actual type definition: https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/index.d.ts#L27 private storage; diff --git a/src/storageWrappers/SessionStorageWrapper.ts b/src/storageWrappers/SessionStorageWrapper.ts index 40429b5d..2b5ebf0d 100644 --- a/src/storageWrappers/SessionStorageWrapper.ts +++ b/src/storageWrappers/SessionStorageWrapper.ts @@ -1,6 +1,6 @@ import { PersistentStorage } from '../types'; -export class SessionStorageWrapper implements PersistentStorage { +export class SessionStorageWrapper implements PersistentStorage { // Actual type definition: https://github.com/microsoft/TypeScript/blob/master/lib/lib.dom.d.ts#L15286 private storage; diff --git a/src/types/index.ts b/src/types/index.ts index cb054f67..3fb0f207 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -10,15 +10,15 @@ export type TriggerFunction = (persist: () => void) => TriggerUninstallFunction; export type PersistedData = T | string | null; -export interface PersistentStorage { - getItem: (key: string) => string | null | Promise; - setItem: (key: string, value: string) => void | Promise; - removeItem: (key: string) => void | Promise; +export interface PersistentStorage { + getItem: (key: string) => Promise | T | null; + setItem: (key: string, value: T) => Promise | Promise | void | T; + removeItem: (key: string) => Promise | Promise | void; } export interface ApolloPersistOptions { cache: ApolloCache; - storage: PersistentStorage; + storage: PersistentStorage>; trigger?: 'write' | 'background' | TriggerFunction | false; debounce?: number; key?: string;