Skip to content

Commit

Permalink
v0.5.4
Browse files Browse the repository at this point in the history
* fix(orderedReducer): `DOCUMENT_ADDED` and `DOCUMENT_MODIFIED` actions
correctly update state with subcollections - #101
* feat(tests): unit test added for `DOCUMENT_ADDED` with subcollection - #101
* feat(core): `ADD_SUCCESS` action payload now contains `id`
  • Loading branch information
prescottprue authored May 20, 2018
2 parents a4ff1fc + 267adfb commit 4b8acba
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 20 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "redux-firestore",
"version": "0.5.3",
"version": "0.5.4",
"description": "Redux bindings for Firestore.",
"main": "lib/index.js",
"module": "es/index.js",
Expand Down
5 changes: 4 additions & 1 deletion src/actions/firestore.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ export function add(firebase, dispatch, queryOption, ...args) {
args,
types: [
actionTypes.ADD_REQUEST,
actionTypes.ADD_SUCCESS,
{
type: actionTypes.ADD_SUCCESS,
payload: snap => ({ id: snap.id, data: args[0] }),
},
actionTypes.ADD_FAILURE,
],
});
Expand Down
53 changes: 39 additions & 14 deletions src/reducers/orderedReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
updateItemInArray,
createReducer,
preserveValuesFromState,
pathToArr,
} from '../utils/reducers';

const {
Expand All @@ -18,30 +19,54 @@ const {
} = actionTypes;

/**
* Case reducer for adding a document to a collection.
* Case reducer for modifying a document within a collection or
* subcollection. When storeAs is being used, subcollections are
* moved to the level of the storeAs (instead of on their parent doc).
* @param {Array} [collectionState=[]] - Redux state of current collection
* @param {Object} action - The action that was dispatched
* @return {Array} State with document modified
*/
function addDoc(array = [], action) {
return [
...array.slice(0, action.payload.ordered.newIndex),
{ id: action.meta.doc, ...action.payload.data },
...array.slice(action.payload.ordered.newIndex),
];
function modifyDoc(collectionState, action) {
if (!action.meta.subcollections || action.meta.storeAs) {
return updateItemInArray(collectionState, action.meta.doc, item =>
// Merge is used to prevent the removal of existing subcollections
mergeObjects(item, action.payload.data),
);
}

// TODO: make this recurisve so it will work multiple subcollections deep
const [, docId, subcollectionName, subDocId] = pathToArr(action.meta.path);

// Update document item within top arra
return updateItemInArray(collectionState, docId, item => ({
...item, // preserve document (only updating subcollection)
[subcollectionName]: updateItemInArray(
get(item, subcollectionName, []),
subDocId,
// Merge with existing subcollection doc (only updates changed keys)
subitem => mergeObjects(subitem, action.payload.data),
),
}));
}

/**
* Case reducer for modifying a document within a collection.
* @param {Array} collectionState - Redux state of current collection
* Case reducer for adding a document to a collection or subcollection.
* @param {Array} [collectionState=[]] - Redux state of current collection
* @param {Object} action - The action that was dispatched
* @return {Array} State with document modified
*/
function modifyDoc(collectionState, action) {
return updateItemInArray(collectionState, action.meta.doc, item =>
// Merge is used to prevent the removal of existing subcollections
mergeObjects(item, action.payload.data),
);
function addDoc(array = [], action) {
const { meta, payload } = action;
if (!meta.subcollections || meta.storeAs) {
return [
...array.slice(0, payload.ordered.newIndex),
{ id: meta.doc, ...payload.data },
...array.slice(payload.ordered.newIndex),
];
}

// Add doc to subcollection by modifying the existing doc at this level
return modifyDoc(array, action);
}

/**
Expand Down
43 changes: 40 additions & 3 deletions test/unit/reducers/orderedReducer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,54 @@ describe('orderedReducer', () => {
it('adds a document when collection is empty', () => {
const collection = 'test1';
const doc = 'test2';
const someDoc = { id: doc };
const someDoc = { some: 'value' };
const payload = {
ordered: { newIndex: 0, oldIndex: -1 },
data: someDoc,
};
const meta = { collection, doc };
action = { meta, payload, type: actionTypes.DOCUMENT_ADDED };
const result = orderedReducer({}, action);
// Id is set
expect(result).to.have.nested.property(`${collection}.0.id`, doc);
// Value is set
expect(result).to.have.nested.property(
`${collection}.0.id`,
someDoc.id,
`${collection}.0.some`,
someDoc.some,
);
});

it('adds a subcollection document when collection is empty', () => {
const collection = 'test1';
const doc = 'test2';
const subcollection = 'test3';
const subdoc = 'test4';
const fakeDoc = { some: 'value' };
const payload = {
ordered: { newIndex: 0, oldIndex: -1 },
data: fakeDoc,
};
const meta = {
collection,
doc,
subcollections: [{ collection: subcollection }],
path: `${collection}/${doc}/${subcollection}/${subdoc}`,
};
action = {
meta,
payload,
type: actionTypes.DOCUMENT_ADDED,
};
const result = orderedReducer({}, action);
// Id is set
expect(result).to.have.nested.property(
`${collection}.0.${subcollection}.0.id`,
subdoc,
);
// Value is set
expect(result).to.have.nested.property(
`${collection}.0.${subcollection}.0.some`,
fakeDoc.some,
);
});
});
Expand Down

0 comments on commit 4b8acba

Please sign in to comment.