Bug 1000837 - {DataStoreTask|DataStoreChangeEvent}.id and DataStoreTask.data have to be nullable, r=gene
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 28 Apr 2014 10:54:38 +0100
changeset 180517 f3a57f0d89b0e7133388aaffce4cd5c84a250c98
parent 180516 bbad533aa83e152b4e859b5d4c0861a2287a71a1
child 180518 e4ff4df25884c6eda82af0d9d081886e9b0455ea
push id42790
push useramarchesini@mozilla.com
push dateMon, 28 Apr 2014 09:54:58 +0000
treeherdermozilla-inbound@f3a57f0d89b0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgene
bugs1000837
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1000837 - {DataStoreTask|DataStoreChangeEvent}.id and DataStoreTask.data have to be nullable, r=gene
dom/datastore/DataStoreCursorImpl.jsm
dom/datastore/DataStoreImpl.jsm
dom/datastore/tests/file_changes.html
dom/datastore/tests/file_sync.html
dom/webidl/DataStore.webidl
dom/webidl/DataStoreChangeEvent.webidl
--- a/dom/datastore/DataStoreCursorImpl.jsm
+++ b/dom/datastore/DataStoreCursorImpl.jsm
@@ -146,17 +146,17 @@ this.DataStoreCursor.prototype = {
     }
 
     let self = this;
     let request = aRevisionStore.openCursor(null, 'prev');
     request.onsuccess = function(aEvent) {
       self._revision = aEvent.target.result.value;
       self._objectId = 0;
       self._state = STATE_SEND_ALL;
-      aResolve(Cu.cloneInto({ operation: 'clear' }, self._window));
+      aResolve(self.createTask('clear', null, '', null));
     }
   },
 
   stateMachineRevisionInit: function(aStore, aRevisionStore, aResolve, aReject) {
     debug('StateMachineRevisionInit');
 
     let self = this;
     let request = this._dataStore._db.getInternalRevisionId(
@@ -286,32 +286,31 @@ this.DataStoreCursor.prototype = {
     debug('StateMachineSendAll');
 
     let self = this;
     let request = aRevisionStore.openCursor(null, 'prev');
     request.onsuccess = function(aEvent) {
       if (self._revision.revisionId != aEvent.target.result.value.revisionId) {
         self._revision = aEvent.target.result.value;
         self._objectId = 0;
-        aResolve(Cu.cloneInto({ operation: 'clear' }, self._window));
+        aResolve(self.createTask('clear', null, '', null));
         return;
       }
 
       let request = aStore.openCursor(self._window.IDBKeyRange.lowerBound(self._objectId, true));
       request.onsuccess = function(aEvent) {
         let cursor = aEvent.target.result;
         if (!cursor) {
           self._state = STATE_REVISION_CHECK;
           self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
           return;
         }
 
         self._objectId = cursor.key;
-        aResolve(Cu.cloneInto({ operation: 'add', id: self._objectId,
-                                data: cursor.value }, self._window));
+        aResolve(self.createTask('add', self._objectId, '', cursor.value));
       };
     };
   },
 
   stateMachineRevisionSend: function(aStore, aRevisionStore, aResolve, aReject) {
     debug('StateMachineRevisionSend');
 
     if (!this._revisionsList.length) {
@@ -319,31 +318,30 @@ this.DataStoreCursor.prototype = {
       this.stateMachine(aStore, aRevisionStore, aResolve, aReject);
       return;
     }
 
     this._revision = this._revisionsList.shift();
 
     switch (this._revision.operation) {
       case REVISION_REMOVED:
-        aResolve(Cu.cloneInto({ operation: 'remove', id: this._revision.objectId },
-                              this._window));
+        aResolve(this.createTask('remove', this._revision.objectId, '', null));
         break;
 
       case REVISION_ADDED: {
         let request = aStore.get(this._revision.objectId);
         let self = this;
         request.onsuccess = function(aEvent) {
           if (aEvent.target.result == undefined) {
             self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
             return;
           }
 
-          aResolve(Cu.cloneInto({ operation: 'add', id: self._revision.objectId,
-                                  data: aEvent.target.result }, self._window));
+          aResolve(self.createTask('add', self._revision.objectId, '',
+                                   aEvent.target.result));
         }
         break;
       }
 
       case REVISION_UPDATED: {
         let request = aStore.get(this._revision.objectId);
         let self = this;
         request.onsuccess = function(aEvent) {
@@ -352,18 +350,18 @@ this.DataStoreCursor.prototype = {
             return;
           }
 
           if (aEvent.target.result.revisionId >  self._revision.internalRevisionId) {
             self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
             return;
           }
 
-          aResolve(Cu.cloneInto({ operation: 'update', id: self._revision.objectId,
-                                  data: aEvent.target.result }, self._window));
+          aResolve(self.createTask('update', self._revision.objectId, '',
+                                   aEvent.target.result));
         }
         break;
       }
 
       case REVISION_VOID:
         // Internal error!
         dump('Internal error: Revision "' + REVISION_VOID + '" should not be found!!!\n');
         break;
@@ -372,18 +370,17 @@ this.DataStoreCursor.prototype = {
         // This revision contains data that has already been sent by another one.
         this.stateMachine(aStore, aRevisionStore, aResolve, aReject);
         break;
     }
   },
 
   stateMachineDone: function(aStore, aRevisionStore, aResolve, aReject) {
     this.close();
-    aResolve(Cu.cloneInto({ revisionId: this._revision.revisionId,
-                            operation: 'done' }, this._window));
+    aResolve(this.createTask('done', null, this._revision.revisionId, null));
   },
 
   // public interface
 
   get store() {
     return this._dataStore.exposedObject;
   },
 
@@ -400,10 +397,15 @@ this.DataStoreCursor.prototype = {
           aReject(createDOMError(self._window, aEvent));
         }
       );
     });
   },
 
   close: function() {
     this._dataStore.syncTerminated(this);
+  },
+
+  createTask: function(aOperation, aId, aRevisionId, aData) {
+    return Cu.cloneInto({ operation: aOperation, id: aId,
+                          revisionId: aRevisionId, data: aData }, this._window);
   }
 };
--- a/dom/datastore/DataStoreImpl.jsm
+++ b/dom/datastore/DataStoreImpl.jsm
@@ -270,17 +270,17 @@ this.DataStore.prototype = {
     let self = this;
     let request = aStore.clear();
     request.onsuccess = function() {
       debug("ClearInternal success");
       self._db.clearRevisions(aRevisionStore,
         function() {
           debug("Revisions cleared");
 
-          self.addRevision(aRevisionStore, 0, REVISION_VOID,
+          self.addRevision(aRevisionStore, null, REVISION_VOID,
             function() {
               debug("ClearInternal - revisionId increased");
               aResolve();
             }
           );
         }
       );
     };
--- a/dom/datastore/tests/file_changes.html
+++ b/dom/datastore/tests/file_changes.html
@@ -61,21 +61,20 @@
     }, cbError);
   }
 
   function testStoreClear() {
     gStore.clear().catch(cbError);
   }
 
   function eventListener(evt) {
+    ok(evt instanceof DataStoreChangeEvent, "DataStoreChangeEvent has been received");
     ok(evt, "OnChangeListener is called with data");
     is(/[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}/.test(evt.revisionId), true, "event.revisionId returns something");
-    if (gChangeId) {
-      is(evt.id, gChangeId, "OnChangeListener is called with the right ID: " + evt.id);
-    }
+    is(evt.id, gChangeId, "OnChangeListener is called with the right ID: " + evt.id);
     is(evt.operation, gChangeOperation, "OnChangeListener is called with the right operation:" + evt.operation + " " + gChangeOperation);
     runTest();
   }
 
   var tests = [
     // Test for GetDataStore
     testGetDataStores,
 
@@ -94,17 +93,17 @@
     function() { gChangeId = 1; gChangeOperation = 'updated';
                  testStorePut({ number: 43 }, 1); },
 
     // Remove
     function() { gChangeId = 1; gChangeOperation = 'removed';
                  testStoreRemove(1, true); },
 
     // Clear
-    function() { gChangeId = 0; gChangeOperation = 'cleared';
+    function() { gChangeId = null; gChangeOperation = 'cleared';
                  testStoreClear(); },
 
     // Remove onchange function and replace it with addEventListener
     function() {
       gStore.onchange = null;
       gStore.addEventListener('change', eventListener);
       runTest();
     },
@@ -117,17 +116,17 @@
     function() { gChangeId = 2; gChangeOperation = 'updated';
                  testStorePut({ number: 43 }, 2); },
 
     // Remove
     function() { gChangeId = 2; gChangeOperation = 'removed';
                  testStoreRemove(2, true); },
 
     // Clear
-    function() { gChangeId = 0; gChangeOperation = 'cleared';
+    function() { gChangeId = null; gChangeOperation = 'cleared';
                  testStoreClear(); },
 
     // Remove event listener
     function() {
       gStore.removeEventListener('change', eventListener);
       runTest();
     },
   ];
--- a/dom/datastore/tests/file_sync.html
+++ b/dom/datastore/tests/file_sync.html
@@ -66,19 +66,24 @@
 
     var step = steps.shift();
     cursor.next().then(function(data) {
       ok(!!data, "Cursor.next returns data");
       is(data.operation, step.operation, "Waiting for operation: '" + step.operation + "' received '" + data.operation + "'");
 
 
       switch (data.operation) {
+        case 'clear':
+          is (data.id, null, "'clear' operation wants a null id");
+          break;
+
         case 'done':
           is(/[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}/.test(data.revisionId), true, "done has a valid revisionId");
           is (data.revisionId, gRevisions[gRevisions.length-1], "Last revision matches");
+          is (data.id, null, "'done' operation wants a null id");
           break;
 
         case 'add':
         case 'update':
           if ('id' in step) {
             is(data.id, step.id, "next() add: id matches: " + data.id + " " + step.id);
           }
 
--- a/dom/webidl/DataStore.webidl
+++ b/dom/webidl/DataStore.webidl
@@ -98,11 +98,13 @@ enum DataStoreOperation {
   "clear",
   "done"
 };
 
 dictionary DataStoreTask {
   DOMString revisionId;
 
   DataStoreOperation operation;
-  DataStoreKey id;
+
+  // When |operation| is "clear" or "done", this must return null.
+  DataStoreKey? id;
   any data;
 };
--- a/dom/webidl/DataStoreChangeEvent.webidl
+++ b/dom/webidl/DataStoreChangeEvent.webidl
@@ -1,21 +1,24 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 dictionary DataStoreChangeEventInit : EventInit {
   DOMString revisionId = "";
-  DataStoreKey id = 0;
+
+  // When |operation| is "clear" or "done", this must return null.
+  DataStoreKey? id = null;
+
   DOMString operation = "";
   DOMString owner = "";
 };
 
 [Func="Navigator::HasDataStoreSupport",
  Constructor(DOMString type, optional DataStoreChangeEventInit eventInitDict)]
 interface DataStoreChangeEvent : Event {
   readonly attribute DOMString revisionId;
-  readonly attribute DataStoreKey id;
+  readonly attribute DataStoreKey? id;
   readonly attribute DOMString operation;
   readonly attribute DOMString owner;
 };