Skip to content

Commit b8a2ebb

Browse files
committed
Return Timestamp for date related fields
This has been the default for Firebase for a while now.
1 parent da2895a commit b8a2ebb

File tree

6 files changed

+73
-21
lines changed

6 files changed

+73
-21
lines changed

src/firebase.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var autoId = require('firebase-auto-ids');
77
var Query = require('./query');
88
var Snapshot = require('./snapshot');
99
var Queue = require('./queue').Queue;
10+
var Timestamp = require('./timestamp');
1011
var utils = require('./utils');
1112
var Auth = require('./firebase-auth');
1213
var validate = require('./validators');
@@ -186,11 +187,11 @@ MockFirebase.prototype.update = function (changes, callback) {
186187
self._defer('update', _.toArray(arguments), function () {
187188
if (!err) {
188189
var base = self.getData();
189-
var data = _.isObject(base) ? base : {};
190+
var data = _.isPlainObject(base) ? base : {};
190191
// operate as a multi-set
191192
_.keys(changes).forEach(function (key) {
192193
var val = changes[key];
193-
_.set(data, key.replace(/^\//, '').replace(/\//g, '.'), _.isObject(val) ? utils.updateToRtdbObject(val) : val);
194+
_.set(data, key.replace(/^\//, '').replace(/\//g, '.'), _.isPlainObject(val) ? utils.updateToRtdbObject(val) : val);
194195
});
195196
data = utils.removeEmptyRtdbProperties(data);
196197
self._dataChanged(data);
@@ -444,16 +445,16 @@ MockFirebase.prototype._dataChanged = function (unparsedData) {
444445
var data = utils.cleanData(unparsedData);
445446

446447
if (utils.isServerTimestamp(data)) {
447-
data = utils.getServerTime();
448+
data = Timestamp.fromMillis(utils.getServerTime());
448449
}
449450

450451
if (pri !== this.priority) {
451452
this._priChanged(pri);
452453
}
453454
if (!_.isEqual(data, this.data)) {
454455
// _.keys() in Lodash 3 automatically coerces non-object to object
455-
var oldKeys = _.isObject(this.data) ? _.keys(this.data).sort() : [];
456-
var newKeys = _.isObject(data) ? _.keys(data).sort() : [];
456+
var oldKeys = _.isPlainObject(this.data) ? _.keys(this.data).sort() : [];
457+
var newKeys = _.isPlainObject(data) ? _.keys(data).sort() : [];
457458
var keysToRemove = _.difference(oldKeys, newKeys);
458459
var keysToChange = _.difference(newKeys, keysToRemove);
459460
var events = [];
@@ -462,22 +463,22 @@ MockFirebase.prototype._dataChanged = function (unparsedData) {
462463
self._removeChild(key, events);
463464
});
464465

465-
if (!_.isObject(data)) {
466+
if (!_.isPlainObject(data)) {
466467
events.push(false);
467468
this.data = data;
468469
}
469470
else {
470471
keysToChange.forEach(function (key) {
471472
var childData = unparsedData[key];
472473
if (utils.isServerTimestamp(childData)) {
473-
childData = utils.getServerTime();
474+
childData = Timestamp.fromMillis(utils.getServerTime());
474475
}
475476
self._updateOrAdd(key, childData, events);
476477
});
477478
}
478479

479480
// update order of my child keys
480-
if (_.isObject(this.data))
481+
if (_.isPlainObject(this.data))
481482
this._resort();
482483

483484
// trigger parent notifications after all children have
@@ -488,7 +489,7 @@ MockFirebase.prototype._dataChanged = function (unparsedData) {
488489

489490
MockFirebase.prototype._priChanged = function (newPriority) {
490491
if (utils.isServerTimestamp(newPriority)) {
491-
newPriority = utils.getServerTime();
492+
newPriority = Timestamp.fromMillis(utils.getServerTime());
492493
}
493494
this.priority = newPriority;
494495
if (this.parent) {
@@ -573,7 +574,7 @@ MockFirebase.prototype._triggerAll = function (events) {
573574
};
574575

575576
MockFirebase.prototype._updateOrAdd = function (key, data, events) {
576-
var exists = _.isObject(this.data) && this.data.hasOwnProperty(key);
577+
var exists = _.isPlainObject(this.data) && this.data.hasOwnProperty(key);
577578
if (!exists) {
578579
return this._addChild(key, data, events);
579580
}
@@ -583,7 +584,7 @@ MockFirebase.prototype._updateOrAdd = function (key, data, events) {
583584
};
584585

585586
MockFirebase.prototype._addChild = function (key, data, events) {
586-
if (!_.isObject(this.data)) {
587+
if (!_.isPlainObject(this.data)) {
587588
this.data = {};
588589
}
589590
this._addKey(key);
@@ -610,7 +611,7 @@ MockFirebase.prototype._removeChild = function (key, events) {
610611

611612
MockFirebase.prototype._updateChild = function (key, data, events) {
612613
var cdata = utils.cleanData(data);
613-
if (_.isObject(this.data) && _.has(this.data, key) && !_.isEqual(this.data[key], cdata)) {
614+
if (_.isPlainObject(this.data) && _.has(this.data, key) && !_.isEqual(this.data[key], cdata)) {
614615
this.data[key] = cdata;
615616
var c = this.child(key);
616617
c._dataChanged(data);
@@ -629,7 +630,7 @@ MockFirebase.prototype._nextErr = function (type) {
629630
};
630631

631632
MockFirebase.prototype._hasChild = function (key) {
632-
return _.isObject(this.data) && _.has(this.data, key);
633+
return _.isPlainObject(this.data) && _.has(this.data, key);
633634
};
634635

635636
MockFirebase.prototype._childData = function (key) {
@@ -695,7 +696,7 @@ function extractName(path) {
695696
}
696697

697698
function render(datum) {
698-
if (datum && _.isObject(datum)) {
699+
if (datum && _.isPlainObject(datum)) {
699700
var keys = _.keys(datum);
700701

701702
if (_.every(keys, RegExp.prototype.test.bind(/^\d+$/))) {

src/firestore-document.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ MockFirestoreDocument.prototype.create = function (data, callback) {
113113
if (err === null) {
114114
var time = Timestamp.fromMillis(utils.getServerTime());
115115
var result = new WriteResult(time);
116+
data = utils.removeEmptyFirestoreProperties(data);
116117
self._dataChanged(data);
117118
resolve(result);
118119
} else {
@@ -136,6 +137,7 @@ MockFirestoreDocument.prototype.set = function (data, opts, callback) {
136137
return new Promise(function (resolve, reject) {
137138
self._defer('set', _.toArray(arguments), function () {
138139
if (err === null) {
140+
data = utils.removeEmptyFirestoreProperties(data);
139141
self._dataChanged(data);
140142
resolve();
141143
} else {

src/utils.js

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

33
var Snapshot = require('./snapshot');
4+
var Timestamp = require('./timestamp');
45
var FieldValue = require('./firestore-field-value');
56
var _ = require('./lodash');
67

@@ -132,6 +133,7 @@ exports.removeEmptyFirestoreProperties = function removeEmptyFirestoreProperties
132133
return obj;
133134
}
134135
if (obj instanceof Date) return obj;
136+
if (obj instanceof Timestamp) return obj;
135137

136138
var keys = getKeys(obj);
137139
if (keys.length > 0) {
@@ -141,7 +143,7 @@ exports.removeEmptyFirestoreProperties = function removeEmptyFirestoreProperties
141143
delete obj[s];
142144
}
143145
if (FieldValue.serverTimestamp().isEqual(value)) {
144-
obj[s] = new Date();
146+
obj[s] = Timestamp.fromMillis(exports.getServerTime());
145147
}
146148
}
147149
}

test/unit/firebase.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ describe('MockFirebase', function () {
7575
it('parses server timestamps', function () {
7676
ref.set(Firebase.ServerValue.TIMESTAMP);
7777
ref.flush();
78-
expect(ref.getData()).to.equal(new Date().getTime());
78+
expect(ref.getData()).to.have.property('seconds', 0);
7979
});
8080

8181
it('parses server timestamps in child data', function () {
@@ -84,26 +84,26 @@ describe('MockFirebase', function () {
8484
foo: Firebase.ServerValue.TIMESTAMP
8585
});
8686
ref.flush();
87-
expect(child.getData()).to.equal(new Date().getTime());
87+
expect(child.getData()).to.have.property('seconds', 0);
8888
});
8989

9090
it('parses server timestamps in priorities', function () {
9191
ref.setPriority(Firebase.ServerValue.TIMESTAMP);
9292
ref.flush();
93-
expect(ref).to.have.property('priority', new Date().getTime());
93+
expect(ref.priority).to.have.property('seconds', 0);
9494
});
9595

9696
describe('Firebase#setClock', function () {
9797

9898
afterEach(Firebase.restoreClock);
9999

100100
it('sets a timestamp factory function', function () {
101-
var customClock = sinon.stub().returns(10);
101+
var customClock = sinon.stub().returns(10000);
102102
Firebase.setClock(customClock);
103103
ref.set(Firebase.ServerValue.TIMESTAMP);
104104
ref.flush();
105105
expect(customClock.callCount).to.equal(1);
106-
expect(ref.getData()).to.equal(10);
106+
expect(ref.getData()).to.have.property('seconds', 10);
107107
});
108108

109109
});
@@ -116,7 +116,7 @@ describe('MockFirebase', function () {
116116
ref.set(Firebase.ServerValue.TIMESTAMP);
117117
ref.flush();
118118
expect(spy.called).to.equal(false);
119-
expect(ref.getData()).to.equal(new Date().getTime());
119+
expect(ref.getData()).to.have.property('seconds', 0);
120120
});
121121

122122
});

test/unit/firestore-document.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,20 @@ describe('MockFirestoreDocument', function () {
128128
db.flush();
129129
});
130130

131+
it('creates a new doc with server time values', function (done) {
132+
var createDoc = db.doc('createDoc');
133+
134+
createDoc.create({serverTime: Firestore.FieldValue.serverTimestamp()});
135+
136+
createDoc.get().then(function (snap) {
137+
expect(snap.exists).to.equal(true);
138+
expect(snap.get('serverTime')).to.have.property('seconds');
139+
done();
140+
}).catch(done);
141+
142+
db.flush();
143+
});
144+
131145
it('throws an error when a doc already exists', function (done) {
132146
var createDoc = db.doc('createDoc');
133147
createDoc.create({prop: 'data'});
@@ -172,6 +186,19 @@ describe('MockFirestoreDocument', function () {
172186

173187
db.flush();
174188
});
189+
190+
it('sets value of doc with server timestamp', function (done) {
191+
doc.set({
192+
serverTime: Firestore.FieldValue.serverTimestamp()
193+
});
194+
doc.get().then(function(snap) {
195+
expect(snap.exists).to.equal(true);
196+
expect(snap.get('serverTime')).to.have.property('seconds');
197+
done();
198+
}).catch(done);
199+
200+
db.flush();
201+
});
175202
});
176203

177204
describe('#set with {merge: true}', function () {
@@ -306,6 +333,20 @@ describe('MockFirestoreDocument', function () {
306333
db.flush();
307334
});
308335

336+
it('updates value of doc with server time value', function (done) {
337+
doc.update({
338+
serverTime: Firestore.FieldValue.serverTimestamp()
339+
});
340+
341+
doc.get().then(function (snap) {
342+
expect(snap.exists).to.equal(true);
343+
expect(snap.get('serverTime')).to.have.property('seconds');
344+
done();
345+
}).catch(done);
346+
347+
db.flush();
348+
});
349+
309350
it('removes property when using FieldValue.delete()', function (done) {
310351
doc.set({
311352
title: 'title2'

test/unit/utils.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var removeEmptyRtdbProperties = require('../../src/utils').removeEmptyRtdbProper
77
var removeEmptyFirestoreProperties = require('../../src/utils').removeEmptyFirestoreProperties;
88
var updateToRtdbObject = require('../../src/utils').updateToRtdbObject;
99
var updateToFirestoreObject = require('../../src/utils').updateToFirestoreObject;
10+
var Timestamp = require('../../src/timestamp');
1011

1112
describe('utils', function () {
1213
describe('removeEmptyRtdbProperties', function () {
@@ -81,6 +82,11 @@ describe('utils', function () {
8182
expect(removeEmptyFirestoreProperties(date)).to.eql(date);
8283
});
8384

85+
it('should make no changes, when obj is a Timestamp', function () {
86+
var ts = new Timestamp(123, 123);
87+
expect(removeEmptyFirestoreProperties(ts)).to.eql(ts);
88+
});
89+
8490
it('should make no changes, when obj is a NaN', function () {
8591
expect(removeEmptyFirestoreProperties(NaN)).to.eql(NaN);
8692
});

0 commit comments

Comments
 (0)