Skip to content

Commit 4b8acba

Browse files
authored
v0.5.4
* 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`
2 parents a4ff1fc + 267adfb commit 4b8acba

File tree

5 files changed

+85
-20
lines changed

5 files changed

+85
-20
lines changed

package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "redux-firestore",
3-
"version": "0.5.3",
3+
"version": "0.5.4",
44
"description": "Redux bindings for Firestore.",
55
"main": "lib/index.js",
66
"module": "es/index.js",

src/actions/firestore.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ export function add(firebase, dispatch, queryOption, ...args) {
3232
args,
3333
types: [
3434
actionTypes.ADD_REQUEST,
35-
actionTypes.ADD_SUCCESS,
35+
{
36+
type: actionTypes.ADD_SUCCESS,
37+
payload: snap => ({ id: snap.id, data: args[0] }),
38+
},
3639
actionTypes.ADD_FAILURE,
3740
],
3841
});

src/reducers/orderedReducer.js

+39-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
updateItemInArray,
66
createReducer,
77
preserveValuesFromState,
8+
pathToArr,
89
} from '../utils/reducers';
910

1011
const {
@@ -18,30 +19,54 @@ const {
1819
} = actionTypes;
1920

2021
/**
21-
* Case reducer for adding a document to a collection.
22+
* Case reducer for modifying a document within a collection or
23+
* subcollection. When storeAs is being used, subcollections are
24+
* moved to the level of the storeAs (instead of on their parent doc).
2225
* @param {Array} [collectionState=[]] - Redux state of current collection
2326
* @param {Object} action - The action that was dispatched
2427
* @return {Array} State with document modified
2528
*/
26-
function addDoc(array = [], action) {
27-
return [
28-
...array.slice(0, action.payload.ordered.newIndex),
29-
{ id: action.meta.doc, ...action.payload.data },
30-
...array.slice(action.payload.ordered.newIndex),
31-
];
29+
function modifyDoc(collectionState, action) {
30+
if (!action.meta.subcollections || action.meta.storeAs) {
31+
return updateItemInArray(collectionState, action.meta.doc, item =>
32+
// Merge is used to prevent the removal of existing subcollections
33+
mergeObjects(item, action.payload.data),
34+
);
35+
}
36+
37+
// TODO: make this recurisve so it will work multiple subcollections deep
38+
const [, docId, subcollectionName, subDocId] = pathToArr(action.meta.path);
39+
40+
// Update document item within top arra
41+
return updateItemInArray(collectionState, docId, item => ({
42+
...item, // preserve document (only updating subcollection)
43+
[subcollectionName]: updateItemInArray(
44+
get(item, subcollectionName, []),
45+
subDocId,
46+
// Merge with existing subcollection doc (only updates changed keys)
47+
subitem => mergeObjects(subitem, action.payload.data),
48+
),
49+
}));
3250
}
3351

3452
/**
35-
* Case reducer for modifying a document within a collection.
36-
* @param {Array} collectionState - Redux state of current collection
53+
* Case reducer for adding a document to a collection or subcollection.
54+
* @param {Array} [collectionState=[]] - Redux state of current collection
3755
* @param {Object} action - The action that was dispatched
3856
* @return {Array} State with document modified
3957
*/
40-
function modifyDoc(collectionState, action) {
41-
return updateItemInArray(collectionState, action.meta.doc, item =>
42-
// Merge is used to prevent the removal of existing subcollections
43-
mergeObjects(item, action.payload.data),
44-
);
58+
function addDoc(array = [], action) {
59+
const { meta, payload } = action;
60+
if (!meta.subcollections || meta.storeAs) {
61+
return [
62+
...array.slice(0, payload.ordered.newIndex),
63+
{ id: meta.doc, ...payload.data },
64+
...array.slice(payload.ordered.newIndex),
65+
];
66+
}
67+
68+
// Add doc to subcollection by modifying the existing doc at this level
69+
return modifyDoc(array, action);
4570
}
4671

4772
/**

test/unit/reducers/orderedReducer.spec.js

+40-3
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,54 @@ describe('orderedReducer', () => {
2020
it('adds a document when collection is empty', () => {
2121
const collection = 'test1';
2222
const doc = 'test2';
23-
const someDoc = { id: doc };
23+
const someDoc = { some: 'value' };
2424
const payload = {
2525
ordered: { newIndex: 0, oldIndex: -1 },
2626
data: someDoc,
2727
};
2828
const meta = { collection, doc };
2929
action = { meta, payload, type: actionTypes.DOCUMENT_ADDED };
3030
const result = orderedReducer({}, action);
31+
// Id is set
32+
expect(result).to.have.nested.property(`${collection}.0.id`, doc);
33+
// Value is set
3134
expect(result).to.have.nested.property(
32-
`${collection}.0.id`,
33-
someDoc.id,
35+
`${collection}.0.some`,
36+
someDoc.some,
37+
);
38+
});
39+
40+
it('adds a subcollection document when collection is empty', () => {
41+
const collection = 'test1';
42+
const doc = 'test2';
43+
const subcollection = 'test3';
44+
const subdoc = 'test4';
45+
const fakeDoc = { some: 'value' };
46+
const payload = {
47+
ordered: { newIndex: 0, oldIndex: -1 },
48+
data: fakeDoc,
49+
};
50+
const meta = {
51+
collection,
52+
doc,
53+
subcollections: [{ collection: subcollection }],
54+
path: `${collection}/${doc}/${subcollection}/${subdoc}`,
55+
};
56+
action = {
57+
meta,
58+
payload,
59+
type: actionTypes.DOCUMENT_ADDED,
60+
};
61+
const result = orderedReducer({}, action);
62+
// Id is set
63+
expect(result).to.have.nested.property(
64+
`${collection}.0.${subcollection}.0.id`,
65+
subdoc,
66+
);
67+
// Value is set
68+
expect(result).to.have.nested.property(
69+
`${collection}.0.${subcollection}.0.some`,
70+
fakeDoc.some,
3471
);
3572
});
3673
});

0 commit comments

Comments
 (0)