Skip to content

Commit 566ebde

Browse files
authored
Merge pull request #436 from wodCZ/fix/storage-wrapper-typings
fix(types): provide simplistic storage interfaces
2 parents 50a4b8b + 8f21bf7 commit 566ebde

File tree

11 files changed

+124
-68
lines changed

11 files changed

+124
-68
lines changed

examples/react-native/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"dependencies": {
1313
"@apollo/client": "^3.3.6",
1414
"@react-native-async-storage/async-storage": "^1.13.2",
15-
"apollo3-cache-persist": "^0.10.0",
15+
"apollo3-cache-persist": "../../lib",
1616
"graphql": "^15.4.0",
1717
"react": "16.13.1",
1818
"react-native": "0.63.4",

examples/react-native/src/hooks/useApolloClient.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { useCallback, useEffect, useState } from 'react';
1+
import {useCallback, useEffect, useState} from 'react';
22
import {
33
ApolloClient,
44
InMemoryCache,
55
NormalizedCacheObject,
66
createHttpLink,
77
} from '@apollo/client';
8-
import { AsyncStorageWrapper, CachePersistor } from 'apollo3-cache-persist';
8+
import {AsyncStorageWrapper, CachePersistor} from 'apollo3-cache-persist';
99
import AsyncStorage from '@react-native-async-storage/async-storage';
1010

11-
import { persistenceMapper, createPersistLink } from '../utils/persistence';
11+
import {persistenceMapper, createPersistLink} from '../utils/persistence';
1212

1313
export const useApolloClient = () => {
1414
const [client, setClient] = useState<ApolloClient<NormalizedCacheObject>>();
@@ -27,8 +27,6 @@ export const useApolloClient = () => {
2727
const cache = new InMemoryCache();
2828
let newPersistor = new CachePersistor({
2929
cache,
30-
// https://github.com/apollographql/apollo-cache-persist/issues/426
31-
// @ts-ignore
3230
storage: new AsyncStorageWrapper(AsyncStorage),
3331
debug: __DEV__,
3432
trigger: 'write',
@@ -37,7 +35,7 @@ export const useApolloClient = () => {
3735
await newPersistor.restore();
3836
setPersistor(newPersistor);
3937
const persistLink = createPersistLink();
40-
const httpLink = createHttpLink({ uri: 'https://api.spacex.land/graphql' });
38+
const httpLink = createHttpLink({uri: 'https://api.spacex.land/graphql'});
4139
setClient(
4240
new ApolloClient({
4341
link: persistLink.concat(httpLink),

examples/react-native/src/utils/persistence/persistenceMapper.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
1-
export const persistenceMapper = (data: any) => {
1+
export const persistenceMapper = async (data: any) => {
22
const parsed = JSON.parse(data);
33

44
const mapped: any = {};
55
const persistEntities: any[] = [];
66
const rootQuery = parsed['ROOT_QUERY'];
77

8-
mapped['ROOT_QUERY'] = Object.keys(rootQuery).reduce((obj: any, key: string) => {
9-
if (key === '__typename') return obj;
8+
mapped['ROOT_QUERY'] = Object.keys(rootQuery).reduce(
9+
(obj: any, key: string) => {
10+
if (key === '__typename') return obj;
1011

11-
if (/@persist$/.test(key)) {
12-
obj[key] = rootQuery[key];
12+
if (/@persist$/.test(key)) {
13+
obj[key] = rootQuery[key];
1314

14-
if (Array.isArray(rootQuery[key])) {
15-
const entities = rootQuery[key].map((item: any) => item.__ref);
16-
persistEntities.push(...entities);
17-
} else {
18-
const entity = rootQuery[key].__ref;
19-
persistEntities.push(entity);
15+
if (Array.isArray(rootQuery[key])) {
16+
const entities = rootQuery[key].map((item: any) => item.__ref);
17+
persistEntities.push(...entities);
18+
} else {
19+
const entity = rootQuery[key].__ref;
20+
persistEntities.push(entity);
21+
}
2022
}
21-
}
2223

23-
return obj;
24-
}, { __typename: 'Query' });
24+
return obj;
25+
},
26+
{__typename: 'Query'},
27+
);
2528

2629
persistEntities.reduce((obj, key) => {
2730
obj[key] = parsed[key];

examples/react-native/yarn.lock

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,10 +1570,8 @@ anymatch@^3.0.3:
15701570
normalize-path "^3.0.0"
15711571
picomatch "^2.0.4"
15721572

1573-
apollo3-cache-persist@^0.10.0:
1574-
version "0.10.0"
1575-
resolved "https://registry.yarnpkg.com/apollo3-cache-persist/-/apollo3-cache-persist-0.10.0.tgz#8dd186818898bd433a9952fe4055adf3f4fb16a4"
1576-
integrity sha512-3W558cKQ9OymUaLMD3Mv8FuUmIDu/GP6aJA+5iLH6fw5MxG4dwF09fFz8NBHn/qfa/zrxv8AtDzKehZUPm107A==
1573+
apollo3-cache-persist@../../lib:
1574+
version "0.0.0"
15771575

15781576
argparse@^1.0.7:
15791577
version "1.0.10"

src/storageWrappers/AsyncStorageWrapper.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,29 @@ import { PersistentStorage } from '../types';
1212
* });
1313
*
1414
*/
15-
export class AsyncStorageWrapper implements PersistentStorage<string> {
16-
// Actual type definition: https://github.com/react-native-async-storage/async-storage/blob/master/types/index.d.ts
15+
export class AsyncStorageWrapper implements PersistentStorage<string | null> {
1716
private storage;
1817

19-
constructor(storage: any) {
18+
constructor(storage: AsyncStorageInterface) {
2019
this.storage = storage;
2120
}
2221

23-
getItem(key: string): string | Promise<string | null> | null {
22+
getItem(key: string): Promise<string | null> {
2423
return this.storage.getItem(key);
2524
}
2625

27-
removeItem(key: string): void | Promise<void> {
26+
removeItem(key: string): Promise<void> {
2827
return this.storage.removeItem(key);
2928
}
3029

31-
setItem(key: string, value: string): void | Promise<void> {
30+
setItem(key: string, value: string | null): Promise<void> {
3231
return this.storage.setItem(key, value);
3332
}
3433
}
34+
35+
interface AsyncStorageInterface {
36+
// Actual type definition: https://github.com/react-native-async-storage/async-storage/blob/master/types/index.d.ts
37+
getItem(key: string): Promise<string | null>;
38+
setItem(key: string, value: string | null): Promise<void>;
39+
removeItem(key: string): Promise<void>;
40+
}
Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
import { PersistentStorage } from '../types';
22

3-
export class IonicStorageWrapper implements PersistentStorage<string> {
4-
// Actual type definition: https://github.com/ionic-team/ionic-storage/blob/main/src/storage.ts#L102
3+
export class IonicStorageWrapper implements PersistentStorage<string | null> {
54
private storage;
65

7-
constructor(storage: any) {
6+
constructor(storage: IonicStorageInterface) {
87
this.storage = storage;
98
}
109

11-
getItem(key: string): string | Promise<string | null> | null {
10+
getItem(key: string): Promise<string | null> {
1211
return this.storage.get(key);
1312
}
1413

15-
removeItem(key: string): void | Promise<void> {
14+
removeItem(key: string): Promise<void> {
1615
return this.storage.remove(key);
1716
}
1817

19-
setItem(key: string, value: string): void | Promise<void> {
18+
setItem(key: string, value: string | null): Promise<void> {
2019
return this.storage.set(key, value);
2120
}
2221
}
22+
23+
interface IonicStorageInterface {
24+
// Actual type definition: https://github.com/ionic-team/ionic-storage/blob/main/lib/src/index.ts
25+
get(key: string): Promise<string | null>;
26+
set(key: string, value: string | null): Promise<void>;
27+
remove(key: string): Promise<void>;
28+
}
Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import { PersistentStorage } from '../types';
22

3-
export class LocalForageWrapper implements PersistentStorage<string | object> {
4-
// Actual type definition: https://github.com/localForage/localForage/blob/master/typings/localforage.d.ts#L17
3+
export class LocalForageWrapper
4+
implements PersistentStorage<string | object | null> {
55
private storage;
66

7-
constructor(storage: any) {
7+
constructor(storage: LocalForageInterface) {
88
this.storage = storage;
99
}
1010

11-
getItem(key: string): string | Promise<string | null> | null {
11+
getItem(key: string): Promise<string | null> {
1212
return this.storage.getItem(key);
1313
}
1414

15-
removeItem(key: string): void | Promise<void> {
15+
removeItem(key: string): Promise<void> {
1616
return this.storage.removeItem(key);
1717
}
1818

19-
setItem(key: string, value: string): void | Promise<void> {
19+
setItem(key: string, value: string | object | null): Promise<void> {
2020
return new Promise((resolve, reject) => {
2121
this.storage
2222
.setItem(key, value)
@@ -25,3 +25,10 @@ export class LocalForageWrapper implements PersistentStorage<string | object> {
2525
});
2626
}
2727
}
28+
29+
interface LocalForageInterface {
30+
// Actual type definition: https://github.com/localForage/localForage/blob/master/typings/localforage.d.ts#L17
31+
getItem(key: string): Promise<string | null>;
32+
setItem(key: string, value: string | object | null): Promise<void>;
33+
removeItem(key: string): Promise<void>;
34+
}
Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
11
import { PersistentStorage } from '../types';
22

3-
export class LocalStorageWrapper implements PersistentStorage<string> {
4-
// Actual type definition: https://github.com/microsoft/TypeScript/blob/master/lib/lib.dom.d.ts#L15286
3+
export class LocalStorageWrapper implements PersistentStorage<string | null> {
54
private storage;
65

7-
constructor(storage: any) {
6+
constructor(storage: LocalStorageInterface) {
87
this.storage = storage;
98
}
109

11-
getItem(key: string): string | Promise<string | null> | null {
10+
getItem(key: string): string | null {
1211
return this.storage.getItem(key);
1312
}
1413

15-
removeItem(key: string): void | Promise<void> {
14+
removeItem(key: string): void {
1615
return this.storage.removeItem(key);
1716
}
1817

19-
setItem(key: string, value: string): void | Promise<void> {
20-
return this.storage.setItem(key, value);
18+
setItem(key: string, value: string | null): void {
19+
if (value !== null) {
20+
// setting null to localstorage stores "null" as string
21+
return this.storage.setItem(key, value);
22+
} else {
23+
return this.removeItem(key);
24+
}
2125
}
2226
}
27+
28+
interface LocalStorageInterface {
29+
// Actual type definition: https://github.com/microsoft/TypeScript/blob/main/lib/lib.dom.d.ts#L14276
30+
getItem(key: string): string | null;
31+
setItem(key: string, value: string): void;
32+
removeItem(key: string): void;
33+
}

src/storageWrappers/MMKVStorageWrapper.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,30 @@ import { PersistentStorage } from '../types';
1111
* });
1212
*
1313
*/
14-
export class MMKVStorageWrapper implements PersistentStorage<string> {
15-
// Actual type definition: https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/index.d.ts#L27
14+
export class MMKVStorageWrapper
15+
implements PersistentStorage<string | null | undefined> {
1616
private storage;
1717

18-
constructor(storage: any) {
18+
constructor(storage: MMKVStorageInterface) {
1919
this.storage = storage;
2020
}
2121

22-
getItem(key: string): string | Promise<string | null> | null {
22+
getItem(key: string): Promise<string | null | undefined> {
2323
return this.storage.getItem(key);
2424
}
2525

26-
removeItem(key: string): void | Promise<void> {
26+
removeItem(key: string): Promise<void> {
2727
return new Promise((resolve, reject) => {
28-
this.storage
29-
.removeItem(key)
28+
// Ensure the removeItem is thenable, even if it's not, by wrapping it to Promise.resolve
29+
// The MMKV storage's removeItem is synchronous since 0.5.7, this Promise wrap allows backward compatibility
30+
// https://stackoverflow.com/a/27746324/2078771
31+
Promise.resolve(this.storage.removeItem(key))
3032
.then(() => resolve())
3133
.catch(() => reject());
3234
});
3335
}
3436

35-
setItem(key: string, value: string): void | Promise<void> {
37+
setItem(key: string, value: string | null | undefined): Promise<void> {
3638
return new Promise((resolve, reject) => {
3739
this.storage
3840
.setItem(key, value)
@@ -41,3 +43,10 @@ export class MMKVStorageWrapper implements PersistentStorage<string> {
4143
});
4244
}
4345
}
46+
47+
interface MMKVStorageInterface {
48+
// Actual type definition: https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/index.d.ts#L27
49+
getItem(key: string): Promise<string | null | undefined>;
50+
setItem(key: string, value: string): Promise<boolean | undefined>;
51+
removeItem(key: string): boolean | undefined | Promise<boolean | undefined>;
52+
}
Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
11
import { PersistentStorage } from '../types';
22

3-
export class SessionStorageWrapper implements PersistentStorage<string> {
4-
// Actual type definition: https://github.com/microsoft/TypeScript/blob/master/lib/lib.dom.d.ts#L15286
3+
export class SessionStorageWrapper implements PersistentStorage<string | null> {
54
private storage;
65

7-
constructor(storage: any) {
6+
constructor(storage: SessionStorageInterface) {
87
this.storage = storage;
98
}
109

11-
getItem(key: string): string | Promise<string | null> | null {
10+
getItem(key: string): string | null {
1211
return this.storage.getItem(key);
1312
}
1413

15-
removeItem(key: string): void | Promise<void> {
14+
removeItem(key: string): void {
1615
return this.storage.removeItem(key);
1716
}
1817

19-
setItem(key: string, value: string): void | Promise<void> {
20-
return this.storage.setItem(key, value);
18+
setItem(key: string, value: string | null): void {
19+
if (value !== null) {
20+
// setting null to sessionstorage stores "null" as string
21+
return this.storage.setItem(key, value);
22+
} else {
23+
return this.removeItem(key);
24+
}
2125
}
2226
}
27+
28+
interface SessionStorageInterface {
29+
// Actual type definition: https://github.com/microsoft/TypeScript/blob/main/lib/lib.dom.d.ts#L14276
30+
getItem(key: string): string | null;
31+
setItem(key: string, value: string): void;
32+
removeItem(key: string): void;
33+
}

0 commit comments

Comments
 (0)