Skip to content

Commit 2d0a880

Browse files
author
gewfy
authored
Merge pull request #2 from 29ki/fieldvalue-array
Adds support for FieldValue.arrayRemove(), FieldValue.arrayUnion() and array membership queries
2 parents 82a3b9d + 57626a8 commit 2d0a880

File tree

12 files changed

+146
-39
lines changed

12 files changed

+146
-39
lines changed

package-lock.json

Lines changed: 19 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"lodash.set": "^4.3.2",
6767
"lodash.size": "^4.2.0",
6868
"lodash.toarray": "^4.4.0",
69+
"lodash.union": "^4.6.0",
6970
"rsvp": "^3.6.2"
7071
},
7172
"devDependencies": {
@@ -92,7 +93,7 @@
9293
"karma-mocha": "^1.3.0",
9394
"karma-phantomjs-launcher": "^1.0.4",
9495
"karma-sinon": "^1.0.5",
95-
"mocha": "^5.1.1",
96+
"mocha": "^5.2.0",
9697
"phantomjs-prebuilt": "^2.1.16",
9798
"semver": "^5.5.0",
9899
"sinon": "^4.5.0",

src/firestore-document.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ MockFirestoreDocument.prototype._update = function (changes, opts, callback) {
159159
self._defer('update', _.toArray(arguments), function () {
160160
if (!err) {
161161
var base = self._getData();
162+
var original = _.cloneDeep(base);
162163
var data;
163164
if (_opts.setMerge) {
164165
data = _.merge(_.isObject(base) ? base : {}, changes);
@@ -172,7 +173,7 @@ MockFirestoreDocument.prototype._update = function (changes, opts, callback) {
172173
data = _.assign(_.isObject(base) ? base : {}, utils.updateToFirestoreObject(changes));
173174
}
174175
}
175-
data = utils.removeEmptyFirestoreProperties(data, utils.getServerTime());
176+
data = utils.removeEmptyFirestoreProperties(data, utils.getServerTime(), original);
176177
self._dataChanged(data);
177178
resolve(data);
178179
} else {

src/firestore-field-value.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use strict';
22

3-
function MockFirestoreFieldValue(type) {
3+
function MockFirestoreFieldValue(type, arg) {
44
this.type = type;
5+
this.arg = arg;
56
}
67

78
MockFirestoreFieldValue.prototype.isEqual = function (other) {
@@ -19,4 +20,12 @@ MockFirestoreFieldValue.serverTimestamp = function () {
1920
return new MockFirestoreFieldValue('serverTimestamp');
2021
};
2122

23+
MockFirestoreFieldValue.arrayRemove = function (arg) {
24+
return new MockFirestoreFieldValue('arrayRemove', arg);
25+
};
26+
27+
MockFirestoreFieldValue.arrayUnion = function (arg) {
28+
return new MockFirestoreFieldValue('arrayUnion', arg);
29+
};
30+
2231
module.exports = MockFirestoreFieldValue;

src/firestore-query.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ MockFirestoreQuery.prototype.where = function (property, operator, value) {
128128
var path = getPropertyPath(property);
129129

130130
// check if unsupported operator
131-
if (operator !== '==') {
131+
if (['==', 'array-contains'].indexOf(operator) === -1) {
132132
console.warn('Using unsupported where() operator for firebase-mock, returning entire dataset');
133133
return this;
134134
} else {
@@ -142,6 +142,12 @@ MockFirestoreQuery.prototype.where = function (property, operator, value) {
142142
results[key] = _.cloneDeep(data);
143143
}
144144
break;
145+
case 'array-contains':
146+
var dt = _.get(data, property);
147+
if (Array.isArray(dt) && dt.indexOf(value) > -1) {
148+
results[key] = _.cloneDeep(data);
149+
}
150+
break;
145151
default:
146152
results[key] = _.cloneDeep(data);
147153
break;

src/lodash.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@ module.exports = {
3535
reduce: require('lodash.reduce'),
3636
remove: require('lodash.remove'),
3737
size: require('lodash.size'),
38-
toArray: require('lodash.toarray')
38+
toArray: require('lodash.toarray'),
39+
union: require('lodash.union'),
3940
};

src/utils.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,23 +127,36 @@ exports.removeEmptyRtdbProperties = function removeEmptyRtdbProperties(obj) {
127127
}
128128
};
129129

130-
exports.removeEmptyFirestoreProperties = function removeEmptyFirestoreProperties(obj, serverTime) {
130+
exports.removeEmptyFirestoreProperties = function removeEmptyFirestoreProperties(obj, serverTime, current) {
131131
if (!_.isPlainObject(obj)) {
132132
return obj;
133133
}
134134

135135
var keys = getKeys(obj);
136136
if (keys.length > 0) {
137-
for (var s in obj) {
138-
var value = removeEmptyFirestoreProperties(obj[s], serverTime);
137+
Object.keys(obj).forEach(function(s) {
138+
var value = removeEmptyFirestoreProperties(obj[s], serverTime, current);
139139
if (FieldValue.delete().isEqual(value)) {
140140
delete obj[s];
141141
} else if (FieldValue.serverTimestamp().isEqual(value)) {
142142
obj[s] = new Date(serverTime);
143143
} else if (value instanceof Timestamp) {
144144
obj[s] = value.toDate();
145145
}
146-
}
146+
147+
if (value && typeof value === 'object' && 'arg' in value) {
148+
var replacement = Array.isArray(value.arg) ? value.arg : [value.arg];
149+
150+
if (FieldValue.arrayRemove().isEqual(value)) {
151+
obj[s] = current[s].filter(function(e) {
152+
return replacement.indexOf(e) === -1;
153+
});
154+
}
155+
if (FieldValue.arrayUnion().isEqual(value)) {
156+
obj[s] = _.union(current[s], replacement);
157+
}
158+
}
159+
});
147160
}
148161
return obj;
149162

test/unit/data.json

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,21 +85,30 @@
8585
"name_type": "string",
8686
"complex": {
8787
"name": "a"
88-
}
88+
},
89+
"array": [
90+
"a", "b"
91+
]
8992
},
9093
"b": {
9194
"name": "b",
9295
"name_type": "string",
9396
"complex": {
9497
"name": "b"
95-
}
98+
},
99+
"array": [
100+
"a", "c"
101+
]
96102
},
97103
"c": {
98104
"name": "c",
99105
"name_type": "string",
100106
"complex": {
101107
"name": "c"
102-
}
108+
},
109+
"array": [
110+
"b", "c"
111+
]
103112
},
104113
"1": {
105114
"name": 1,

test/unit/firestore-collection.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,15 @@ describe('MockFirestoreCollection', function () {
233233
]);
234234
});
235235

236+
it('returns matched documents for operator "array-contains"', function() {
237+
var results1 = collection.where('array', 'array-contains', 'a').get();
238+
db.flush();
239+
240+
return Promise.all([
241+
expect(results1).to.eventually.have.property('size').to.equal(2),
242+
]);
243+
});
244+
236245
it('returns all documents when using unsupported operator', function() {
237246
var expected = 6;
238247

test/unit/firestore-document.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,40 @@ describe('MockFirestoreDocument', function () {
379379
db.flush();
380380
});
381381

382+
it('updates an array property when using FieldValue.arrayRemove()', function (done) {
383+
doc.set({
384+
titles: ['title1', 'title2']
385+
});
386+
doc.update({
387+
titles: Firestore.FieldValue.arrayRemove('title2')
388+
});
389+
390+
doc.get().then(function (snap) {
391+
expect(snap.exists).to.equal(true);
392+
expect(snap.data()).to.deep.equal({titles: ['title1']});
393+
done();
394+
}).catch(done);
395+
396+
db.flush();
397+
});
398+
399+
it('updates an array property when using FieldValue.arrayUnion()', function (done) {
400+
doc.set({
401+
titles: ['title1']
402+
});
403+
doc.update({
404+
titles: Firestore.FieldValue.arrayUnion('title2')
405+
});
406+
407+
doc.get().then(function (snap) {
408+
expect(snap.exists).to.equal(true);
409+
expect(snap.data()).to.deep.equal({titles: ['title1', 'title2']});
410+
done();
411+
}).catch(done);
412+
413+
db.flush();
414+
});
415+
382416
it('does not merge nested properties recursively by default', function (done) {
383417
doc.set({
384418
nested: {

0 commit comments

Comments
 (0)