Skip to content

Commit

Permalink
Merge pull request #3 from MatiasArriola/master
Browse files Browse the repository at this point in the history
Add key argument to serialize and unserialize invocations
  • Loading branch information
zewish authored Oct 5, 2021
2 parents 70f31df + e8713e0 commit 505c0b3
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 22 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ API reference
2. **rememberedKeys** *(required)* - an array of persistable keys - if an empty array is provided nothing will get persisted;
3. **options** *(optional)* - plain object of extra options:
- **prefix**: storage key prefix *(default: `'@@remember-'`)*;
- **serialize** - a plain function that takes unserialized store state and returns serialized state to be persisted *(default: `JSON.stringify`)*;
- **unserialize** - a plain function that takes serialized persisted state and returns unserialized to be set in the store *(default: `JSON.parse`)*;
- **serialize** - a plain function that takes unserialized store state and its key (`serialize(state, keyStr)`) and returns serialized state to be persisted *(default: `JSON.stringify`)*;
- **unserialize** - a plain function that takes serialized persisted state and its key (`serialize(serializedStr, keyStr)`) and returns unserialized to be set in the store *(default: `JSON.parse`)*;
- **persistThrottle** - how much time should the persistence be throttled in milliseconds *(default: `100`)*
- **persistWholeStore** - a boolean which specifies if the whole store should be persisted at once. Generally only use this if you're using your own storage driver which has gigabytes of storage limits. Don't use this when using window.localStorage, window.sessionStorage or AsyncStorage as their limits are quite small - *(default: `false`)*;
- **persistWholeStore** - a boolean which specifies if the whole store should be persisted at once. Generally only use this if you're using your own storage driver which has gigabytes of storage limits. Don't use this when using window.localStorage, window.sessionStorage or AsyncStorage as their limits are quite small. When using this option, key won't be passed to `serialize` nor `unserialize` functions - *(default: `false`)*;
- Returns - an enhancer to be used with Redux
4 changes: 2 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Action, AnyAction, Reducer, StoreEnhancer } from 'redux';
declare const REMEMBER_REHYDRATED = "@@REMEMBER_REHYDRATED";
declare const REMEMBER_PERSISTED = "@@REMEMBER_PERSISTED";
type SerializeFunction = (data: any) => any;
type UnserializeFunction = (data: any) => any;
type SerializeFunction = (data: any, key?: string) => any;
type UnserializeFunction = (data: any, key?: string) => any;
type Driver = {
getItem: (key: string) => any;
setItem: (key: string, value: any) => any;
Expand Down
44 changes: 43 additions & 1 deletion src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('index.js', () => {
rehydrateReducer: jest.fn(() => 'REHYDRATE_REDUCER')
};

let mockInit: Function;
let mockInit: jest.Mock;
let index: typeof indexModule;

beforeEach(() => {
Expand Down Expand Up @@ -168,5 +168,47 @@ describe('index.js', () => {
{ driver, ...opts }
)
});

it('calls init() with default options', () => {
let optionDefaults: any;
mockInit.mockImplementationOnce((store, rememberedKeys, opts) => {
optionDefaults = opts;
});
const store = 'the store!!!';

const driver = {
getItem() {},
setItem() {}
};

const rememberedKeys = [ 'zz', 'bb', 'kk' ];

const rootReducer = () => 'the root of the reducers';
const initialState = 'yup, initial state';
const enhancer: any = 'another enhancer';

index.rememberEnhancer(driver, rememberedKeys)(() => store)(
rootReducer, initialState, enhancer
);

expect(mockInit).toBeCalledWith(
store,
rememberedKeys,
{ driver, ...optionDefaults }
)

const stringifySpy = jest.spyOn(JSON, 'stringify');
const parseSpy = jest.spyOn(JSON, 'parse');

expect(optionDefaults).toMatchObject({
prefix : '@persist-',
persistThrottle : 100,
persistWholeStore : false
});
expect(optionDefaults.serialize('hello', 'auth')).toEqual('\"hello\"');
expect(stringifySpy).toHaveBeenCalledWith('hello');
expect(optionDefaults.unserialize('\"bye\"', 'auth')).toEqual('bye');
expect(parseSpy).toHaveBeenCalledWith('\"bye\"');
});
});
});
4 changes: 2 additions & 2 deletions src/__tests__/persist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ describe('persist.js', () => {
);

expect(mockSerialize).nthCalledWith(
1, 'yay'
1, 'yay', 'key1'
);

expect(mockSerialize).nthCalledWith(
2, 'wow'
2, 'wow', 'key3'
);
});

Expand Down
20 changes: 12 additions & 8 deletions src/__tests__/rehydrate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ describe('rehydrate.js', () => {

beforeEach(() => {
mockDriver = {
getItem: jest.fn((key) => `"${key}"`),
getItem: jest.fn((key) => `valueFor:${key.replace(mockPrefix, '')}`),
setItem() {}
};

Expand All @@ -135,19 +135,23 @@ describe('rehydrate.js', () => {
});

it('returns unserialized state', async () => {
const mockUnserialize = jest.fn()
.mockImplementation((str) => str.toUpperCase());

const res = await exec({
rememberedKeys: [ 'yay', 'k' ],
unserialize: (
jest.fn()
.mockReturnValueOnce('val1')
.mockReturnValueOnce('val2')
)
unserialize: mockUnserialize
});

expect(res).toEqual({
yay: 'val1',
k: 'val2'
yay: 'VALUEFOR:YAY',
k: 'VALUEFOR:K'
});

expect(mockUnserialize)
.nthCalledWith(1, 'valueFor:yay', 'yay')
expect(mockUnserialize)
.nthCalledWith(2, 'valueFor:k', 'k')
});

it('returns state filtering null and undefined', async () => {
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ const rememberEnhancer = <Ext = {}, StateExt = {}>(
rememberedKeys: string[],
{
prefix = '@persist-',
serialize = JSON.stringify,
unserialize = JSON.parse,
serialize = (data) => JSON.stringify(data),
unserialize = (data) => JSON.parse(data),
persistThrottle = 100,
persistWholeStore = false
}: Partial<Options> = {}
Expand Down
2 changes: 1 addition & 1 deletion src/persist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const saveAllKeyed = (

return driver.setItem(
`${prefix}${key}`,
serialize(state[key])
serialize(state[key], key)
);
})
);
Expand Down
2 changes: 1 addition & 1 deletion src/rehydrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const loadAllKeyed = async ({

return rememberedKeys.reduce((obj: { [key: string]: any }, key, i) => {
if (items[i] !== null && items[i] !== undefined) {
obj[key] = unserialize(items[i]);
obj[key] = unserialize(items[i], key);
}

return obj;
Expand Down
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export type SerializeFunction = (data: any) => any;
export type UnserializeFunction = (data: any) => any;
export type SerializeFunction = (data: any, key?: string) => any;
export type UnserializeFunction = (data: any, key?: string) => any;

export type Driver = {
getItem: (key: string) => any;
Expand Down

0 comments on commit 505c0b3

Please # to comment.