Skip to content

Commit

Permalink
AsyncStorage interfaces (#1016)
Browse files Browse the repository at this point in the history
  • Loading branch information
Krzysztof Borowy authored Nov 22, 2023
1 parent bd4c170 commit 622d505
Show file tree
Hide file tree
Showing 126 changed files with 1,451 additions and 272 deletions.
1 change: 1 addition & 0 deletions .config/tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"strict": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"strictNullChecks": true,
"allowJs": true,
"checkJs": true,
"allowSyntheticDefaultImports": true,
Expand Down
30 changes: 15 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
test-name: [lint, ts]
workspace: [default-storage-backend, core]
workspace: [default-storage, api]
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down Expand Up @@ -44,11 +44,11 @@ jobs:
with:
gradle-version: wrapper
arguments: react-native-async-storage_async-storage:test
build-root-directory: packages/default-storage-backend/example/android
build-root-directory: packages/default-storage/example/android
- name: Build e2e binary
run: |
yarn build:e2e:android
working-directory: packages/default-storage-backend
working-directory: packages/default-storage

ios:
name: iOS
Expand All @@ -59,7 +59,7 @@ jobs:
- name: Cache /.ccache
uses: actions/cache@v3
with:
path: packages/default-storage-backend/.ccache
path: packages/default-storage/.ccache
key: ccache-ios-${{ hashFiles('yarn.lock') }}
restore-keys: ccache-ios-
- name: Set up Node.js
Expand All @@ -73,15 +73,15 @@ jobs:
- name: Bundle JS
run: |
yarn bundle:ios
working-directory: packages/default-storage-backend
working-directory: packages/default-storage
- name: Install Pods
run: |
RCT_NEW_ARCH_ENABLED=1 pod install
working-directory: packages/default-storage-backend/example/ios
working-directory: packages/default-storage/example/ios
- name: Build e2e binary
run: |
yarn build:e2e:ios
working-directory: packages/default-storage-backend
working-directory: packages/default-storage

macos:
name: macOS
Expand All @@ -92,7 +92,7 @@ jobs:
- name: Cache /.ccache
uses: actions/cache@v3
with:
path: packages/default-storage-backend/.ccache
path: packages/default-storage/.ccache
key: ccache-macos-${{ hashFiles('yarn.lock') }}
restore-keys: ccache-macos-
- name: Set up Node.js
Expand All @@ -106,20 +106,20 @@ jobs:
- name: Bundle JS
run: |
yarn bundle:macos
working-directory: packages/default-storage-backend
working-directory: packages/default-storage
- name: Install Pods
run: |
RCT_NEW_ARCH_ENABLED=1 pod install
working-directory: packages/default-storage-backend/example/macos
working-directory: packages/default-storage/example/macos
- name: Build
run: |
yarn build:e2e:macos
working-directory: packages/default-storage-backend
working-directory: packages/default-storage
- name: Test
if: false
run: |
yarn test:e2e:macos
working-directory: packages/default-storage-backend
working-directory: packages/default-storage

windows:
name: Windows
Expand All @@ -142,11 +142,11 @@ jobs:
- name: Install Windows test app
run: |
yarn install-windows-test-app -p example/windows
working-directory: packages/default-storage-backend
working-directory: packages/default-storage
- name: Build
run: |
yarn react-native run-windows --release --arch x64 --logging --no-packager --no-launch --no-deploy --msbuildprops "BundleEntryFile=index.ts" --no-telemetry
working-directory: packages/default-storage-backend
working-directory: packages/default-storage

release:
name: Release
Expand Down Expand Up @@ -178,4 +178,4 @@ jobs:
git config user.email ${{ secrets.GH_BOT_EMAIL }}
git config user.name ${{ secrets.GH_BOT_NAME }}
yarn semantic-release
working-directory: packages/default-storage-backend
working-directory: packages/default-storage
File renamed without changes.
17 changes: 17 additions & 0 deletions packages/api/example/ExampleExtension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { StorageExtension } from "../src";

export interface MyExampleExtension extends StorageExtension {
double: (num: number) => Promise<number>;

uppercase: (text: string) => string;

key: string;
}

export class ExampleExtension implements MyExampleExtension {
key = "my-example-storage";

double = async (num: number) => num * 2;

uppercase = (text: string): string => text.toUpperCase();
}
69 changes: 69 additions & 0 deletions packages/api/example/ExampleStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { AsyncStorage, StorageKeys, StorageModel } from "../src";
import { ExampleExtension, MyExampleExtension } from "./ExampleExtension";

type MyModel = StorageModel<{
age: number;
name: string;
likes: boolean[];
}>;

// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
class ExampleStorage implements AsyncStorage<MyModel, MyExampleExtension> {
private storage: MyModel = {
age: null,
name: null,
likes: null,
};

getItem = async <K extends keyof MyModel>(key: K): Promise<MyModel[K]> => {
return this.storage[key];
};

setItem = async <K extends StorageKeys<MyModel>>(
key: K,
value: MyModel[K]
): Promise<void> => {
this.storage[key] = value;
};

removeItem = async <K extends StorageKeys<MyModel>>(
key: K
): Promise<void> => {
this.storage[key] = null;
};

getMany = async <K extends StorageKeys<MyModel>>(
keys: K[]
): Promise<{ [k in K]: MyModel[k] }> => {
return keys.reduce((entries, key) => {
entries[key] = this.storage[key] ?? null;
return entries;
}, {} as { [k in K]: MyModel[k] });
};

setMany = async <K extends StorageKeys<MyModel>>(entries: {
[k in K]: MyModel[k];
}): Promise<void> => {
Object.entries(entries).forEach((entry) => {
const key = entry[0] as K;
this.storage[key] = entry[1] as MyModel[K];
});
};

removeMany = async <K extends StorageKeys<MyModel>>(
keys: K[]
): Promise<void> => {
keys.forEach((k) => {
this.storage[k] = null;
});
};

clear = async (): Promise<void> => {
this.storage.age = null;
this.storage.name = null;
this.storage.likes = null;
};

ext: MyExampleExtension = new ExampleExtension();
}
5 changes: 5 additions & 0 deletions packages/api/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};
8 changes: 6 additions & 2 deletions packages/core/package.json → packages/api/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@react-native-async-storage/core",
"name": "@react-native-async-storage/api",
"version": "0.0.0",
"description": "Core API of Async Storage",
"source": "src/index.ts",
Expand All @@ -17,7 +17,8 @@
"prepack": "yarn build",
"build": "bob build",
"test:lint": "eslint src/**",
"test:ts": "tsc --noEmit"
"test:ts": "tsc --noEmit",
"test:jest": "jest"
},
"keywords": [
"react-native",
Expand All @@ -30,8 +31,11 @@
"author": "Krzysztof Borowy <[email protected]>",
"license": "MIT",
"devDependencies": {
"@types/jest": "29.5.4",
"eslint": "8.26.0",
"jest": "29.5.0",
"react-native-builder-bob": "0.20.0",
"ts-jest": "29.1.1",
"typescript": "4.9.5"
},
"react-native-builder-bob": {
Expand Down
74 changes: 74 additions & 0 deletions packages/api/src/AsyncStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { StorageKeys, StorageModel } from "./StorageModel";
import type { StorageExtension } from "./StorageExtension";

/**
* AsyncStorage Interface
* Provides methods for managing asynchronous storage operations.
* @typeParam S - type of the storage model.
* @typeParam E - type of the storage extension, or unknown, if no extension is provided.
*/
export interface AsyncStorage<
S extends StorageModel,
E extends StorageExtension | unknown = unknown
> {
/**
* Retrieves a single item from storage based on the provided key.
* @param key - The key to identify the item within the storage.
* @returns Promise resolving to the value associated with the key,
* or null if the key does not exist.
*/
getItem<K extends StorageKeys<S>>(key: K): Promise<S[K]>;

/**
* Sets the value of the specified item in the storage.
* @param key - The key under which the value should be stored.
* @param value - The value to be stored.
* @returns Promise that resolves when the operation is completed.
*/
setItem<K extends StorageKeys<S>>(key: K, value: S[K]): Promise<void>;

/**
* Removes the item from storage identified by the provided key.
* @param key - The key of the item to be removed.
* @returns Promise that resolves when the operation is completed.
*/
removeItem<K extends StorageKeys<S>>(key: K): Promise<void>;

/**
* Retrieves multiple items from storage based on the provided keys.
* @param keys - An array of keys to identify the items to be retrieved.
* @returns Promise resolving to an object with key-value pairs,
* where the values are associated with the keys,
* or null if a key does not exist.
*/
getMany<K extends StorageKeys<S>>(keys: K[]): Promise<{ [k in K]: S[k] }>;

/**
* Sets multiple items in the storage.
* @param entries - An object containing key-value pairs to be stored.
* @returns Promise that resolves when the operation is completed.
*/
setMany<K extends StorageKeys<S>>(entries: {
[k in K]: S[k];
}): Promise<void>;

/**
* Removes multiple items from storage based on the provided keys.
* @param keys - An array of keys identifying the items to be removed.
* @returns Promise that resolves when the operation is completed.
*/
removeMany<K extends StorageKeys<S>>(keys: K[]): Promise<void>;

/**
* Clears all the data from the storage.
* @returns Promise that resolves when the operation is completed.
*/
clear(): Promise<void>;

/**
* Represents the extension for providing additional functionality
* beyond the standard storage interface.
* See {@link StorageExtension} for more details.
*/
ext: E;
}
6 changes: 6 additions & 0 deletions packages/api/src/StorageExtension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* The StorageExtension type serves as a means to extend the functionalities of the
* core interface beyond its operations. It acts as a placeholder for implementing
* additional methods.
*/
export type StorageExtension = {};
13 changes: 13 additions & 0 deletions packages/api/src/StorageModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* A type used to define the structure and shape of the data to be stored.
*/
export type StorageModel<
T extends Record<string, unknown> | unknown = unknown
> = {
[K in keyof T]: NonNullable<T[K]> | null;
};

/**
* A utility type to extract key.
*/
export type StorageKeys<T> = keyof T;
3 changes: 3 additions & 0 deletions packages/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { AsyncStorage } from "./AsyncStorage";
export type { StorageExtension } from "./StorageExtension";
export type { StorageKeys, StorageModel } from "./StorageModel";
7 changes: 7 additions & 0 deletions packages/api/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../.config/tsconfig.base.json",
"include": ["./src/**/*", "./example/**/*"],
"compilerOptions": {
"types": ["jest"]
}
}
5 changes: 0 additions & 5 deletions packages/core/src/index.ts

This file was deleted.

4 changes: 0 additions & 4 deletions packages/core/tsconfig.json

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ build/
.gradle
local.properties
*.iml
!android/gradlew*

# Visual Studio
#
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if [[ "$CCACHE_DISABLE" != "1" ]]; then

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

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

export CC="${CCACHE_HOME}/libexec/clang"
export CXX="${CCACHE_HOME}/libexec/clang++"
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 622d505

Please sign in to comment.