Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way with emberfire to specify that a timestamp attribute on a model should be given the Firebase.ServerValue.TIMESTAMP value?

I have a model with a timestamp attribute. When records are created on the server I would like the value of this attribute to be initialized with a value by the server rather than the client providing the value, so that these timestamps are consistent between different clients.

If I was using the firebase API directly then I understand that I could use the special token Firebase.ServerValue.TIMESTAMP to achieve this. But I can't work out how to do this with ember-data and the emberfire adapter.

like image 412
solsberg Avatar asked Dec 19 '22 10:12

solsberg


1 Answers

Sorry, I know this is late, but I ran into the same problem.

You can define a custom attribute type with a DS.Transform that just passes that value through, as is, when you serialize it. I just named mine timestamp.

// transforms/timestamp.js
/* global Firebase */
import DS from 'ember-data';

export default DS.DateTransform.extend({
    serialize: function(date) {
        if(date === Firebase.ServerValue.TIMESTAMP){
            return date;
        }
        return this._super(date);
    }
});

Then you can use it about as expected:

// models/somemodel.js
import DS from 'ember-data';

export default DS.Model.extend({
    createdAt: DS.attr("timestamp")
});

And then in some controller or something:

this.store.createRecord("somemodel", { createdAt: Firebase.ServerValue.TIMESTAMP });

When you save it, it'll set the field with the right value on the server's copy, but the local record won't be updated with that value. I'm still working out how to approach fixing this, but the new Ember Data Store.fetch() method seems like a worst case solution once EmberFire is brought up to date.

edit:

Did some more digging. Some notes:

  • When you create a record with this method, and call save() on it, DS.Store calls a didCreateRecord event handler that normally deserializes the server returned record (which is where you normally get model IDs and stuff), but in this case, it doesn't deserialize, because FirebaseAdapter's create/updateRecord methods return promises that call their resolve handlers without any arguments (https://github.com/firebase/emberfire/blob/v1.3.1/src/data.js#L492), so the Store method gets undefined, instead of a serialized record. In terms of paving this use case, this is where I'd want to target a solution, ideally.

  • It looks like the server time is generated as an estimate, synchronously on the client anyway via a time offset variable that gets set when you connect the server websocket. So when you go to save/update a record with the Firebase.ServerValues.TIMESTAMP value, it takes the client time, modifies it by the offset, and creates the update data with it. This looks to get modified to the actual value on the server, and the modification will eventually propagate to the client. -- If you really need the value immediately, you can save your record a second time, and it will give you the server generated value.

like image 109
Dave-Choi Avatar answered May 16 '23 07:05

Dave-Choi