Behavior of model.version()


#1
let model = await this.openOrCreateModel(collection, id, {}); // model created

console.log('version', model.version()); // version 1
model.root().value(newData);

console.log('version', model.version()); // version 1

I would expect the second log would be version 2. Is there a bug?


#2

Thanks for the questions!

The code as written, and the results being seen are technically correct. The model.version() represents the current version acknowledged by the server. When you mutate the data, the data is mutated locally and then communicated to the server. The version number will not be incremented until that local edit is committed at the sever. Since this happens asynchronously, and your code above will execute in the same JavaScript event loop, the version will still be 1.

Presently there is a “committed” event that you can listen for on the model that will let you know that all outstanding local changes have been committed at the server. I suspect if you were to listen for that even and then print out the version number, it would be version 2, as you expect. Additionally, if remote operations come in from the server (from other sessions) the version would be incremented then as well, since the local client knows that the server has already committed this operation.

Hope that helps.


#3

OK, that makes sense. Thanks. I tested with this code:

private _setDataAndConfirm(model:RealTimeModel, data:{}):Promise<void> {
    return new Promise((resolve) => {
      function onCommit():void {
        model.off(RealTimeModel.Events.COMMITTED, onCommit);
        console.log('model version', model.version());
        resolve();
      }

      model.on(RealTimeModel.Events.COMMITTED, onCommit);
      console.log('model version', model.version());
      model.root().value(data);
    });
  }

And called it with:

await this._setDataAndConfirm(model, newData);
console.log('model updated, version', model.version());

Which printed:

model version 2
model version 2
model updated, version 3

I would think that the second log statement would print version 3?


#4

It appears that the event is being fired, and then we are updating the internal model version. It might make sense to update the model version before firing the event, we will look into that to see if it is appropriate.

However, it might be good to understand the use case a little bit more. There is not a 1-to-1 mapping of operations and the COMMITTED event. For example, if the current version of the model is 2, and you make 3 changes to the model in one JavaScript event loop, then the COMMITTED event will not fire until all of them are acknowledged by the server. Thus, while each mutation is individually committed, the model as a whole will not return to a committed state until all three mutations are. So if you are monitoring the COMMITTED state you will be committed at version 2, and then again at version 5. You would not be notified of the application of versions 3 and 4.

If you are interested in knowing about each individual version, there is also a VERSION_CHANGED event on the RealTimeModel class that will notify you any time the version changes. This would include remote operations from other users as well as operations your local client sent over that have been acknowledged by the server.

Lastly, just for some house keeping, you are using model.on() and model.off() to essentially implement the event emitter “once()” pattern. We support that directly:

model.once(RealTimeModel.Events.COMMITTED, onCommit);