Skip to content

Commit e1051d4

Browse files
authored
v0.4.3 (#87)
* fix(orderedReducer): subcollection updates correctly update document - #86 * feat(test): tests added to confirm changes fix sub collections updates - #86
1 parent b394053 commit e1051d4

File tree

4 files changed

+160
-6
lines changed

4 files changed

+160
-6
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.4.2",
3+
"version": "0.4.3",
44
"description": "Redux bindings for Firestore.",
55
"main": "lib/index.js",
66
"module": "es/index.js",

src/reducers/orderedReducer.js

+25
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,31 @@ function writeCollection(collectionState, action) {
7171
if (merge.collection && size(collectionState)) {
7272
return unionBy(collectionState, action.payload.ordered, 'id');
7373
}
74+
75+
// Handle subcollections
76+
if (meta.doc && meta.subcollections) {
77+
if (!size(collectionState)) {
78+
// Collection state does not already exist, create it with item containing
79+
// subcollection
80+
return [
81+
{
82+
id: meta.doc,
83+
[meta.subcollections[0].collection]: action.payload.ordered,
84+
},
85+
];
86+
}
87+
// Merge with existing document if collection state exists
88+
return updateItemInArray(collectionState, meta.doc, item =>
89+
mergeObjects(item, {
90+
[meta.subcollections[0].collection]: action.payload.ordered,
91+
}),
92+
);
93+
}
94+
if (meta.doc && size(collectionState)) {
95+
return updateItemInArray(collectionState, meta.doc, item =>
96+
mergeObjects(item, action.payload.ordered[0]),
97+
);
98+
}
7499
return action.payload.ordered;
75100
}
76101

test/unit/reducers/orderedReducer.spec.js

+133-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ describe('orderedReducer', () => {
1717

1818
describe('actionTypes', () => {
1919
describe('DOCUMENT_ADDED', () => {
20-
it('throws for no collection', () => {
20+
it('adds a document when collection is empty', () => {
2121
const collection = 'test1';
2222
const doc = 'test2';
2323
const someDoc = { id: doc };
@@ -34,6 +34,32 @@ describe('orderedReducer', () => {
3434
);
3535
});
3636
});
37+
38+
describe('DOCUMENT_REMOVED', () => {
39+
it('removes document from collection', () => {
40+
const collection = 'test1';
41+
const doc = 'test2';
42+
const someDoc = { id: doc };
43+
const someDoc2 = { id: 'test3' };
44+
const payload = {
45+
ordered: { newIndex: 0, oldIndex: -1 },
46+
data: someDoc,
47+
};
48+
const meta = { collection, doc };
49+
action = { meta, payload, type: actionTypes.DOCUMENT_REMOVED };
50+
const result = orderedReducer(
51+
{ [collection]: [someDoc, someDoc2] },
52+
action,
53+
);
54+
// Confirm first item is
55+
expect(result).to.have.nested.property(
56+
`${collection}.0.id`,
57+
someDoc2.id,
58+
);
59+
expect(result[collection]).to.have.length(1);
60+
});
61+
});
62+
3763
describe('LISTENER_RESPONSE', () => {
3864
it('returns state if payload is not defined', () => {
3965
action = { meta: 'test', type: actionTypes.LISTENER_RESPONSE };
@@ -91,7 +117,7 @@ describe('orderedReducer', () => {
91117
});
92118

93119
describe('doc', () => {
94-
it.skip('adds a new doc within state', () => {
120+
it('adds a new doc within state', () => {
95121
const orderedData = { id: 'doc' };
96122
action = {
97123
meta: { collection: 'testing', doc: 'doc' },
@@ -122,6 +148,98 @@ describe('orderedReducer', () => {
122148
});
123149
});
124150

151+
describe('subcollections', () => {
152+
it('adds a new doc within state with subcollection', () => {
153+
const orderedData = { id: 'subDoc' };
154+
const subcollection = { collection: 'testing2' };
155+
action = {
156+
meta: {
157+
collection: 'testing',
158+
doc: 'doc',
159+
subcollections: [subcollection],
160+
},
161+
type: actionTypes.LISTENER_RESPONSE,
162+
payload: { ordered: [orderedData] },
163+
};
164+
state = {};
165+
expect(orderedReducer(state, action)).to.have.nested.property(
166+
`testing.0.${subcollection.collection}.0.id`,
167+
orderedData.id,
168+
);
169+
});
170+
171+
it('adds subcollection to existing doc within state', () => {
172+
const orderedData = { id: 'subDoc', someOther: 'thing' };
173+
const subcollection = { collection: 'testing2' };
174+
action = {
175+
meta: {
176+
collection: 'testing',
177+
doc: 'doc',
178+
subcollections: [subcollection],
179+
},
180+
merge: {}, // reset merge settings
181+
type: actionTypes.LISTENER_RESPONSE,
182+
payload: { ordered: [orderedData] },
183+
};
184+
state = { testing: [{ id: 'doc', another: 'thing' }] };
185+
const result = orderedReducer(state, action);
186+
// Adds subcollection to document
187+
expect(result).to.have.nested.property(
188+
`testing.0.${subcollection.collection}.0.id`,
189+
orderedData.id,
190+
);
191+
// Preserves original value
192+
expect(result).to.have.nested.property('testing.0.another', 'thing');
193+
});
194+
195+
it('perserves existing collections on doc updates', () => {
196+
const orderedData = { id: 'doc', someOther: 'thing' };
197+
const original = [{ id: 'subDoc' }];
198+
action = {
199+
meta: {
200+
collection: 'testing',
201+
doc: 'doc',
202+
},
203+
merge: {}, // reset merge settings
204+
type: actionTypes.LISTENER_RESPONSE,
205+
payload: { ordered: [orderedData] },
206+
};
207+
state = { testing: [{ id: 'doc', original }] };
208+
const result = orderedReducer(state, action);
209+
// Updates parameter in document
210+
expect(result).to.have.nested.property(
211+
`testing.0.someOther`,
212+
orderedData.someOther,
213+
);
214+
// Preserves documents in original subcollection
215+
expect(result).to.have.nested.property(
216+
'testing.0.original.0.id',
217+
original[0].id,
218+
);
219+
});
220+
221+
it('updates the reference of subcollection docs on parent doc update', () => {
222+
const orderedData = { id: 'doc', someOther: 'thing' };
223+
const original = [{ id: 'subDoc' }];
224+
action = {
225+
meta: {
226+
collection: 'testing',
227+
doc: 'doc',
228+
},
229+
merge: {}, // reset merge settings
230+
type: actionTypes.LISTENER_RESPONSE,
231+
payload: { ordered: [orderedData] },
232+
};
233+
state = { testing: [{ id: 'doc', original }] };
234+
const result = orderedReducer(state, action);
235+
// Updates reference of documents in original subcollection
236+
expect(result).to.not.have.nested.property(
237+
'testing.0.original',
238+
original,
239+
);
240+
});
241+
});
242+
125243
it('stores data under storeAs', () => {
126244
const orderedData = [{}];
127245
const storeAs = 'other';
@@ -173,15 +291,26 @@ describe('orderedReducer', () => {
173291
it('removes all data from state', () => {
174292
action = {
175293
type: actionTypes.CLEAR_DATA,
294+
meta: { collection: 'testing' }, // meta is required to trigger ordered reducer
176295
};
177296
state = {};
178297
expect(orderedReducer(state, action)).to.be.empty;
298+
expect(orderedReducer(state, action)).to.be.empty;
299+
});
300+
301+
it('sets a new reference when clearing', () => {
302+
action = {
303+
type: actionTypes.CLEAR_DATA,
304+
meta: { collection: 'testing' }, // meta is required to trigger ordered reducer
305+
};
306+
state = {};
307+
expect(orderedReducer(state, action)).to.not.equal(state);
179308
});
180309

181310
describe('preserve parameter', () => {
182311
it('array saves keys from state', () => {
183312
action = {
184-
meta: 'test',
313+
meta: { collection: 'testing' }, // meta is required to trigger ordered reducer
185314
type: actionTypes.CLEAR_DATA,
186315
payload: {},
187316
preserve: { ordered: ['some'] },
@@ -192,7 +321,7 @@ describe('orderedReducer', () => {
192321

193322
it('function returns state to save', () => {
194323
action = {
195-
meta: 'test',
324+
meta: { collection: 'testing' }, // meta is required to trigger ordered reducer
196325
type: actionTypes.CLEAR_DATA,
197326
payload: {},
198327
preserve: { ordered: currentState => currentState },

0 commit comments

Comments
 (0)