Skip to content

Commit 622d505

Browse files
author
Krzysztof Borowy
authored
AsyncStorage interfaces (#1016)
1 parent bd4c170 commit 622d505

File tree

126 files changed

+1451
-272
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+1451
-272
lines changed

.config/tsconfig.base.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"strict": true,
1313
"moduleResolution": "node",
1414
"resolveJsonModule": true,
15+
"strictNullChecks": true,
1516
"allowJs": true,
1617
"checkJs": true,
1718
"allowSyntheticDefaultImports": true,

.github/workflows/ci.yml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
strategy:
1212
matrix:
1313
test-name: [lint, ts]
14-
workspace: [default-storage-backend, core]
14+
workspace: [default-storage, api]
1515
steps:
1616
- name: Checkout
1717
uses: actions/checkout@v3
@@ -44,11 +44,11 @@ jobs:
4444
with:
4545
gradle-version: wrapper
4646
arguments: react-native-async-storage_async-storage:test
47-
build-root-directory: packages/default-storage-backend/example/android
47+
build-root-directory: packages/default-storage/example/android
4848
- name: Build e2e binary
4949
run: |
5050
yarn build:e2e:android
51-
working-directory: packages/default-storage-backend
51+
working-directory: packages/default-storage
5252

5353
ios:
5454
name: iOS
@@ -59,7 +59,7 @@ jobs:
5959
- name: Cache /.ccache
6060
uses: actions/cache@v3
6161
with:
62-
path: packages/default-storage-backend/.ccache
62+
path: packages/default-storage/.ccache
6363
key: ccache-ios-${{ hashFiles('yarn.lock') }}
6464
restore-keys: ccache-ios-
6565
- name: Set up Node.js
@@ -73,15 +73,15 @@ jobs:
7373
- name: Bundle JS
7474
run: |
7575
yarn bundle:ios
76-
working-directory: packages/default-storage-backend
76+
working-directory: packages/default-storage
7777
- name: Install Pods
7878
run: |
7979
RCT_NEW_ARCH_ENABLED=1 pod install
80-
working-directory: packages/default-storage-backend/example/ios
80+
working-directory: packages/default-storage/example/ios
8181
- name: Build e2e binary
8282
run: |
8383
yarn build:e2e:ios
84-
working-directory: packages/default-storage-backend
84+
working-directory: packages/default-storage
8585

8686
macos:
8787
name: macOS
@@ -92,7 +92,7 @@ jobs:
9292
- name: Cache /.ccache
9393
uses: actions/cache@v3
9494
with:
95-
path: packages/default-storage-backend/.ccache
95+
path: packages/default-storage/.ccache
9696
key: ccache-macos-${{ hashFiles('yarn.lock') }}
9797
restore-keys: ccache-macos-
9898
- name: Set up Node.js
@@ -106,20 +106,20 @@ jobs:
106106
- name: Bundle JS
107107
run: |
108108
yarn bundle:macos
109-
working-directory: packages/default-storage-backend
109+
working-directory: packages/default-storage
110110
- name: Install Pods
111111
run: |
112112
RCT_NEW_ARCH_ENABLED=1 pod install
113-
working-directory: packages/default-storage-backend/example/macos
113+
working-directory: packages/default-storage/example/macos
114114
- name: Build
115115
run: |
116116
yarn build:e2e:macos
117-
working-directory: packages/default-storage-backend
117+
working-directory: packages/default-storage
118118
- name: Test
119119
if: false
120120
run: |
121121
yarn test:e2e:macos
122-
working-directory: packages/default-storage-backend
122+
working-directory: packages/default-storage
123123

124124
windows:
125125
name: Windows
@@ -142,11 +142,11 @@ jobs:
142142
- name: Install Windows test app
143143
run: |
144144
yarn install-windows-test-app -p example/windows
145-
working-directory: packages/default-storage-backend
145+
working-directory: packages/default-storage
146146
- name: Build
147147
run: |
148148
yarn react-native run-windows --release --arch x64 --logging --no-packager --no-launch --no-deploy --msbuildprops "BundleEntryFile=index.ts" --no-telemetry
149-
working-directory: packages/default-storage-backend
149+
working-directory: packages/default-storage
150150

151151
release:
152152
name: Release
@@ -178,4 +178,4 @@ jobs:
178178
git config user.email ${{ secrets.GH_BOT_EMAIL }}
179179
git config user.name ${{ secrets.GH_BOT_NAME }}
180180
yarn semantic-release
181-
working-directory: packages/default-storage-backend
181+
working-directory: packages/default-storage
File renamed without changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { StorageExtension } from "../src";
2+
3+
export interface MyExampleExtension extends StorageExtension {
4+
double: (num: number) => Promise<number>;
5+
6+
uppercase: (text: string) => string;
7+
8+
key: string;
9+
}
10+
11+
export class ExampleExtension implements MyExampleExtension {
12+
key = "my-example-storage";
13+
14+
double = async (num: number) => num * 2;
15+
16+
uppercase = (text: string): string => text.toUpperCase();
17+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { AsyncStorage, StorageKeys, StorageModel } from "../src";
2+
import { ExampleExtension, MyExampleExtension } from "./ExampleExtension";
3+
4+
type MyModel = StorageModel<{
5+
age: number;
6+
name: string;
7+
likes: boolean[];
8+
}>;
9+
10+
// @ts-ignore
11+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
12+
class ExampleStorage implements AsyncStorage<MyModel, MyExampleExtension> {
13+
private storage: MyModel = {
14+
age: null,
15+
name: null,
16+
likes: null,
17+
};
18+
19+
getItem = async <K extends keyof MyModel>(key: K): Promise<MyModel[K]> => {
20+
return this.storage[key];
21+
};
22+
23+
setItem = async <K extends StorageKeys<MyModel>>(
24+
key: K,
25+
value: MyModel[K]
26+
): Promise<void> => {
27+
this.storage[key] = value;
28+
};
29+
30+
removeItem = async <K extends StorageKeys<MyModel>>(
31+
key: K
32+
): Promise<void> => {
33+
this.storage[key] = null;
34+
};
35+
36+
getMany = async <K extends StorageKeys<MyModel>>(
37+
keys: K[]
38+
): Promise<{ [k in K]: MyModel[k] }> => {
39+
return keys.reduce((entries, key) => {
40+
entries[key] = this.storage[key] ?? null;
41+
return entries;
42+
}, {} as { [k in K]: MyModel[k] });
43+
};
44+
45+
setMany = async <K extends StorageKeys<MyModel>>(entries: {
46+
[k in K]: MyModel[k];
47+
}): Promise<void> => {
48+
Object.entries(entries).forEach((entry) => {
49+
const key = entry[0] as K;
50+
this.storage[key] = entry[1] as MyModel[K];
51+
});
52+
};
53+
54+
removeMany = async <K extends StorageKeys<MyModel>>(
55+
keys: K[]
56+
): Promise<void> => {
57+
keys.forEach((k) => {
58+
this.storage[k] = null;
59+
});
60+
};
61+
62+
clear = async (): Promise<void> => {
63+
this.storage.age = null;
64+
this.storage.name = null;
65+
this.storage.likes = null;
66+
};
67+
68+
ext: MyExampleExtension = new ExampleExtension();
69+
}

packages/api/jest.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
};

packages/core/package.json renamed to packages/api/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "@react-native-async-storage/core",
2+
"name": "@react-native-async-storage/api",
33
"version": "0.0.0",
44
"description": "Core API of Async Storage",
55
"source": "src/index.ts",
@@ -17,7 +17,8 @@
1717
"prepack": "yarn build",
1818
"build": "bob build",
1919
"test:lint": "eslint src/**",
20-
"test:ts": "tsc --noEmit"
20+
"test:ts": "tsc --noEmit",
21+
"test:jest": "jest"
2122
},
2223
"keywords": [
2324
"react-native",
@@ -30,8 +31,11 @@
3031
"author": "Krzysztof Borowy <[email protected]>",
3132
"license": "MIT",
3233
"devDependencies": {
34+
"@types/jest": "29.5.4",
3335
"eslint": "8.26.0",
36+
"jest": "29.5.0",
3437
"react-native-builder-bob": "0.20.0",
38+
"ts-jest": "29.1.1",
3539
"typescript": "4.9.5"
3640
},
3741
"react-native-builder-bob": {

packages/api/src/AsyncStorage.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import type { StorageKeys, StorageModel } from "./StorageModel";
2+
import type { StorageExtension } from "./StorageExtension";
3+
4+
/**
5+
* AsyncStorage Interface
6+
* Provides methods for managing asynchronous storage operations.
7+
* @typeParam S - type of the storage model.
8+
* @typeParam E - type of the storage extension, or unknown, if no extension is provided.
9+
*/
10+
export interface AsyncStorage<
11+
S extends StorageModel,
12+
E extends StorageExtension | unknown = unknown
13+
> {
14+
/**
15+
* Retrieves a single item from storage based on the provided key.
16+
* @param key - The key to identify the item within the storage.
17+
* @returns Promise resolving to the value associated with the key,
18+
* or null if the key does not exist.
19+
*/
20+
getItem<K extends StorageKeys<S>>(key: K): Promise<S[K]>;
21+
22+
/**
23+
* Sets the value of the specified item in the storage.
24+
* @param key - The key under which the value should be stored.
25+
* @param value - The value to be stored.
26+
* @returns Promise that resolves when the operation is completed.
27+
*/
28+
setItem<K extends StorageKeys<S>>(key: K, value: S[K]): Promise<void>;
29+
30+
/**
31+
* Removes the item from storage identified by the provided key.
32+
* @param key - The key of the item to be removed.
33+
* @returns Promise that resolves when the operation is completed.
34+
*/
35+
removeItem<K extends StorageKeys<S>>(key: K): Promise<void>;
36+
37+
/**
38+
* Retrieves multiple items from storage based on the provided keys.
39+
* @param keys - An array of keys to identify the items to be retrieved.
40+
* @returns Promise resolving to an object with key-value pairs,
41+
* where the values are associated with the keys,
42+
* or null if a key does not exist.
43+
*/
44+
getMany<K extends StorageKeys<S>>(keys: K[]): Promise<{ [k in K]: S[k] }>;
45+
46+
/**
47+
* Sets multiple items in the storage.
48+
* @param entries - An object containing key-value pairs to be stored.
49+
* @returns Promise that resolves when the operation is completed.
50+
*/
51+
setMany<K extends StorageKeys<S>>(entries: {
52+
[k in K]: S[k];
53+
}): Promise<void>;
54+
55+
/**
56+
* Removes multiple items from storage based on the provided keys.
57+
* @param keys - An array of keys identifying the items to be removed.
58+
* @returns Promise that resolves when the operation is completed.
59+
*/
60+
removeMany<K extends StorageKeys<S>>(keys: K[]): Promise<void>;
61+
62+
/**
63+
* Clears all the data from the storage.
64+
* @returns Promise that resolves when the operation is completed.
65+
*/
66+
clear(): Promise<void>;
67+
68+
/**
69+
* Represents the extension for providing additional functionality
70+
* beyond the standard storage interface.
71+
* See {@link StorageExtension} for more details.
72+
*/
73+
ext: E;
74+
}

packages/api/src/StorageExtension.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* The StorageExtension type serves as a means to extend the functionalities of the
3+
* core interface beyond its operations. It acts as a placeholder for implementing
4+
* additional methods.
5+
*/
6+
export type StorageExtension = {};

packages/api/src/StorageModel.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* A type used to define the structure and shape of the data to be stored.
3+
*/
4+
export type StorageModel<
5+
T extends Record<string, unknown> | unknown = unknown
6+
> = {
7+
[K in keyof T]: NonNullable<T[K]> | null;
8+
};
9+
10+
/**
11+
* A utility type to extract key.
12+
*/
13+
export type StorageKeys<T> = keyof T;

packages/api/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { AsyncStorage } from "./AsyncStorage";
2+
export type { StorageExtension } from "./StorageExtension";
3+
export type { StorageKeys, StorageModel } from "./StorageModel";

packages/api/tsconfig.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "../../.config/tsconfig.base.json",
3+
"include": ["./src/**/*", "./example/**/*"],
4+
"compilerOptions": {
5+
"types": ["jest"]
6+
}
7+
}

packages/core/src/index.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

packages/core/tsconfig.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

packages/default-storage-backend/example/.gitignore renamed to packages/default-storage/example/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ build/
2929
.gradle
3030
local.properties
3131
*.iml
32+
!android/gradlew*
3233

3334
# Visual Studio
3435
#

packages/default-storage-backend/scripts/macos_e2e.sh renamed to packages/default-storage/scripts/macos_e2e.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ if [[ "$CCACHE_DISABLE" != "1" ]]; then
1010

1111
CCACHE_HOME=$(dirname $(dirname $(which ccache)))/opt/ccache
1212

13-
export CCACHE_DIR="$(git rev-parse --show-toplevel)/packages/default-storage-backend/.ccache"
13+
export CCACHE_DIR="$(git rev-parse --show-toplevel)/packages/default-storage/.ccache"
1414

1515
export CC="${CCACHE_HOME}/libexec/clang"
1616
export CXX="${CCACHE_HOME}/libexec/clang++"

0 commit comments

Comments
 (0)