Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,36 @@ persistentStore(counter, {
}
}
```
### Pausing and resuming the save to the database

Saving the state to the database can be paused and resumed
via the `PAUSE_SAVING` and `RESUME_SAVING` actions.

```js
import { PAUSE_SAVING, RESUME_SAVING, persistentStore, persistentReducer }
from 'redux-pouchdb-plus';


// create the store the usual way...

store.dispatch( { type: 'INCREMENT' } ); // will be saved as usual

store.dispatch( { type: 'PAUSE_SAVING' } );

store.dispatch( { type: 'INCREMENT' } ); // won't be saved

store.dispatch( { type: 'INCREMENT' } ); // won't be saved either

store.dispatch( { type: 'RESUME_SAVING' } ); // saving is resumed

store.dispatch( { type: 'INCREMENT' } ); // will be saved as usual
```

If the store changed between a `PAUSE_SAVING` and the following
`RESUME_SAVING`, the `RESUME_SAVING` will immediately trigger a save.

Note that `PAUSE_SAVING` prevents the local store from saving its
changes to the database, but won't prevent updates coming from the database.

## Notes

Expand Down
52 changes: 34 additions & 18 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const REINIT = '@@redux-pouchdb-plus/REINIT';
const INIT = '@@redux-pouchdb-plus/INIT';
const SET_REDUCER = '@@redux-pouchdb-plus/SET_REDUCER';

export const PAUSE_SAVING = '@@redux-pouchdb-plus/PAUSE_SAVING';
export const RESUME_SAVING = '@@redux-pouchdb-plus/RESUME_SAVING';

const allReducers = [];

export function reinit(reducerName) {
Expand Down Expand Up @@ -46,6 +49,7 @@ export const persistentReducer = (reducer, reducerOptions={}) => {
let saveReducer;
let currentState;
let name = reducerOptions.name ? reducerOptions.name : reducer.name;
let paused = false;

initializedReducers[name] = false;

Expand Down Expand Up @@ -176,9 +180,37 @@ export const persistentReducer = (reducer, reducerOptions={}) => {
return equalDeep(x, y);
}

const reduceAndMaybeSave = (state,action) => {
const nextState = reducer(state, action);

if (!initialState) {
initialState = nextState;
}

const isInitialized = initializedReducers[name];

if (isInitialized && !paused && !isEqual(nextState, currentState)) {
currentState = nextState;
saveReducer(name, toPouch(currentState)).then(() => {
onSave(currentState);
});
}
else if (!paused ) currentState = nextState;

return nextState;
};

// the proxy function that wraps the real reducer
const proxyReducer = (state, action) => {
switch (action.type) {
case PAUSE_SAVING:
paused = true;
return state;

case RESUME_SAVING:
paused = false;
return reduceAndMaybeSave(state,action);

case INIT:
store = action.store;
storeOptions = action.storeOptions;
Expand All @@ -205,24 +237,8 @@ export const persistentReducer = (reducer, reducerOptions={}) => {
}
// falls through

default: {
const nextState = reducer(state, action);

if (!initialState) {
initialState = nextState;
}

const isInitialized = initializedReducers[name];
if (isInitialized && !isEqual(nextState, currentState)) {
currentState = nextState;
saveReducer(name, toPouch(currentState)).then(() => {
onSave(currentState);
});
}
else currentState = nextState;

return currentState;
}
default:
return reduceAndMaybeSave(state,action);
}
};

Expand Down
48 changes: 47 additions & 1 deletion tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import PouchDB from 'pouchdb';
import timeout from 'timeout-then';
import { Map, toJS, fromJS, is } from 'immutable';
import uuid from 'uuid';
import { persistentStore, persistentReducer, reinit, inSync } from '../src/index';
import { PAUSE_SAVING, RESUME_SAVING, persistentStore, persistentReducer, reinit, inSync } from '../src/index';

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
Expand Down Expand Up @@ -588,3 +588,49 @@ test('should allow creation of multiple redux stores with the same reducer name'
//single store with the same reducer name
t.throws(() => {createPersistentStore(combineReducers([thirdFinalReducer, forthFinalReducer]))});
});

test('should allow to pause and resume saving', t => {
t.plan(4);

const db = new PouchDB('testdb', {db : require('memdown')});
const createPersistentStore = persistentStore({db})(createStore);
const reducer = setupPlainReducer();
const finalReducer = persistentReducer(reducer, {name: 'test'});
const store = createPersistentStore(finalReducer);

const state_x = () => store.getState().x;
const getDb = () => db.get('test').then( doc => doc.state );

timeout(500)
.then(() => {
store.dispatch({ type: INCREMENT });
return timeout(500);
})
.then(getDb)
.then( doc => {
// right now, we are in sync
t.equal( doc.x, state_x() );
store.dispatch({ type: PAUSE_SAVING });
store.dispatch({ type: INCREMENT });

return timeout(500);
})
.then( getDb )
.then( doc => {
// we are paused, so out of sync
t.notEqual( doc.x, state_x() );

store.dispatch({ type: RESUME_SAVING });
return timeout(500);
})
.then( getDb )
.then( doc => {
// resuming should have kicked off a save
t.equal( doc.x, state_x() );
store.dispatch({ type: INCREMENT });
return timeout(500);
})
.then( getDb )
.then( doc => t.equal( doc.x, state_x() ) ) // still syncing
;
});