Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v2] Web Storage #216

Merged
merged 13 commits into from
Oct 20, 2019
Merged
8 changes: 6 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ const commonSettings = {
};

module.exports = {
setupFiles: ['jest-localstorage-mock'],
projects: [
{
...commonSettings,
displayName: 'core',
roots: ['<rootDir>/packages/core'],
testMatch: ['<rootDir>/packages/core/__tests__/*{.,-}test.ts'],
roots: ['<rootDir>/packages/core', '<rootDir>/packages/storage-web'],
testMatch: [
'<rootDir>/packages/core/__tests__/*{.,-}test.ts',
'<rootDir>/packages/storage-web/__tests__/*{.,-}test.ts',
],
},
],
};
4 changes: 2 additions & 2 deletions packages/core/src/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import {FactoryOptions, LoggerAction} from '../types';

export const factoryOptions: FactoryOptions = {
logger: __DEV__,
errorHandler: __DEV__,
logger: false,
errorHandler: false,
};

export function simpleErrorHandler(e: Error | string) {
Expand Down
70 changes: 70 additions & 0 deletions packages/storage-web/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import WebStorage from '../src';
import 'jest-localstorage-mock';

describe.each([['sessionStorage', false], ['localStorage', true]])(
'WebStorage',
(storageName, storageBool) => {
const webStorage = new WebStorage(storageBool);
const storage: any = storageBool ? sessionStorage : localStorage;

beforeEach(() => {
storage.clear();
});
describe(`main API with ${storageName}`, () => {
it(`gets single item from ${storage}`, async () => {
storage.setItem('key1', 'value1');
expect(await webStorage.getSingle('key1')).toBe('value1');
});

it(`saves single item to ${storageName}`, async () => {
await webStorage.setSingle('key1', 'value1');
expect(storage.__STORE__.key1).toBe('value1');
});

it(`gets multiple items from ${storageName}`, async () => {
storage.setItem('key1', 'value1');
storage.setItem('key2', 'value2');
expect(await webStorage.getMany(['key1', 'key2'])).toEqual([
'value1',
'value2',
]);
});

it(`saves multiple items to ${storageName}`, async () => {
await webStorage.setMany([{key1: 'value1'}, {key2: 'value2'}]);
expect(storage.__STORE__).toEqual({key1: 'value1', key2: 'value2'});
});

it(`removes single item from ${storageName}`, async () => {
storage.setItem('key1', 'value1');
storage.setItem('key2', 'value2');
await webStorage.removeSingle('key1');
expect(storage.__STORE__).toEqual({key2: 'value2'});
});

it(`removes multiple items from ${storageName}`, async () => {
storage.setItem('key1', 'value1');
storage.setItem('key2', 'value2');
storage.setItem('key3', 'value3');
await webStorage.removeMany(['key1', 'key2']);
expect(storage.__STORE__).toEqual({key3: 'value3'});
});

it(`gets keys from ${storageName}`, async () => {
storage.setItem('key1', 'value1');
storage.setItem('key2', 'value2');
expect(await webStorage.getKeys()).toEqual(['key1', 'key2']);
});

it(`removes all keys from ${storageName}`, async () => {
storage.setItem('key1', 'value1');
storage.setItem('key2', 'value2');
await webStorage.dropStorage();
expect(storage.__STORE__).toEqual({});
});
});
// describe('utils', () => {

// });
},
);
6 changes: 6 additions & 0 deletions packages/storage-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@
"react-native": ">=0.58"
},
"devDependencies": {
"jest-localstorage-mock": "^2.4.0",
"react": "^16.0",
"react-native": ">=0.58"
},
"jest": {
"setupFiles": [
"jest-localstorage-mock"
]
}
}
95 changes: 95 additions & 0 deletions packages/storage-web/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,98 @@
* LICENSE file in the root directory of this source tree.
*
*/
import {
IStorageBackend,
EmptyStorageModel,
StorageOptions,
} from '@react-native-community/async-storage';

class WebStorage<T extends EmptyStorageModel = EmptyStorageModel>
implements IStorageBackend<T> {
storage: any;
constructor(sessionStorage: boolean | string = false) {
this.storage = sessionStorage ? window.sessionStorage : window.localStorage;
}

async getSingle<K extends keyof T>(
key: K,
opts?: StorageOptions,
): Promise<T[K] | null> {
if (opts) {
// noop
}
return this.storage.getItem(key);
}

async setSingle<K extends keyof T>(
key: K,
value: T[K],
opts?: StorageOptions,
): Promise<void> {
if (opts && !opts.replaceCurrent) {
const current = this.storage.getItem(key);
if (!current) {
this.storage.setItem(key, value);
}
return;
}
return this.storage.setItem(key, value);
}

async getMany<K extends keyof T>(
keys: Array<K>,
opts?: StorageOptions,
): Promise<{[k in K]: T[k] | null}> {
if (opts) {
// noop
}
return Promise.all(keys.map(k => this.storage.getItem(k)));
}

async setMany<K extends keyof T>(
values: Array<{[k in K]: T[k]}>,
opts?: StorageOptions,
): Promise<void> {
if (opts) {
// noop
}
for (let keyValue of values) {
const key = Object.getOwnPropertyNames(keyValue)[0];
if (!key) {
continue;
}
this.storage.setItem(key, keyValue[key]);
}
}

async removeSingle(key: keyof T, opts?: StorageOptions): Promise<void> {
if (opts) {
// noop
}
return this.storage.removeItem(key);
}

async removeMany(keys: Array<keyof T>, opts?: StorageOptions): Promise<void> {
if (opts) {
// noop
}
Promise.all(keys.map(k => this.storage.removeItem(k)));
}

async getKeys(opts?: StorageOptions): Promise<Array<keyof T>> {
if (opts) {
// noop
}
return Object.keys(this.storage);
}

async dropStorage(opts?: StorageOptions): Promise<void> {
if (opts) {
// noop
}
const keys = await this.getKeys();
await this.removeMany(keys);
}
}

export default WebStorage;
39 changes: 39 additions & 0 deletions packages/storage-web/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,42 @@
* LICENSE file in the root directory of this source tree.
*
*/

import {
EmptyStorageModel,
IStorageBackend,
StorageOptions,
} from '@react-native-community/async-storage';
export default class WebStorage<T = EmptyStorageModel>
implements IStorageBackend<T> {
private readonly _asyncStorageNativeModule;
storage: Function;
getSingle<K extends keyof T>(
key: K,
opts?: StorageOptions,
): Promise<T[K] | null>;

setSingle<K extends keyof T>(
key: K,
value: T[K],
opts?: StorageOptions,
): Promise<void>;

getMany<K extends keyof T>(
keys: Array<K>,
opts?: StorageOptions,
): Promise<{[k in K]: T[k] | null}>;

setMany<K extends keyof T>(
values: Array<{[k in K]: T[k]}>,
opts?: StorageOptions,
): Promise<void>;

removeSingle(key: keyof T, opts?: StorageOptions): Promise<void>;

removeMany(keys: Array<keyof T>, opts?: StorageOptions): Promise<void>;

getKeys(opts?: StorageOptions): Promise<Array<keyof T>>;

dropStorage(opts?: StorageOptions): Promise<void>;
}
6 changes: 3 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"compilerOptions": {
"target": "ES2017",
"module": "commonjs",
"lib": ["es2017"],

"lib": ["es2017", "dom"],
"skipLibCheck": true,
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"noEmit": true,
"strict": true,
Expand All @@ -19,6 +19,6 @@
"@types/jest",
"packages/**/src/",
"packages/**/types/",
"packages/**/__tests__/",
"packages/**/__tests__/"
]
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5329,6 +5329,11 @@ jest-leak-detector@^24.8.0:
dependencies:
pretty-format "^24.8.0"

jest-localstorage-mock@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/jest-localstorage-mock/-/jest-localstorage-mock-2.4.0.tgz#c6073810735dd3af74020ea6c3885ec1cc6d0d13"
integrity sha512-/mC1JxnMeuIlAaQBsDMilskC/x/BicsQ/BXQxEOw+5b1aGZkkOAqAF3nu8yq449CpzGtp5jJ5wCmDNxLgA2m6A==

jest-matcher-utils@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.8.0.tgz#2bce42204c9af12bde46f83dc839efe8be832495"
Expand Down