Bug 1406181 - Add openForPrincipal static method and changes to IDB cursor wrapping in IndexedDB.jsm. r=aswan
authorLuca Greco <lgreco@mozilla.com>
Sat, 14 Apr 2018 15:10:29 +0200
changeset 421611 e98870938f1b4563910293f56d55a929f205d7ad
parent 421610 2174226b26dc180d6225780abf15ae1004e78dfa
child 421612 5851a229516db97350bd80b0bcb17a38e4bcaf4f
push id34099
push userncsoregi@mozilla.com
push dateWed, 06 Jun 2018 22:00:08 +0000
treeherdermozilla-central@1ab062fd31db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1406181
milestone62.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 1406181 - Add openForPrincipal static method and changes to IDB cursor wrapping in IndexedDB.jsm. r=aswan MozReview-Commit-ID: vicgBmHhJp
toolkit/modules/IndexedDB.jsm
--- a/toolkit/modules/IndexedDB.jsm
+++ b/toolkit/modules/IndexedDB.jsm
@@ -118,49 +118,79 @@ function forwardMethods(cls, target, met
   for (let method of methods) {
     cls.prototype[method] = function(...args) {
       return this[target][method](...args);
     };
   }
 }
 
 class Cursor {
-  constructor(cursor, source) {
-    this.cursor = cursor;
+  constructor(cursorRequest, source) {
+    this.cursorRequest = cursorRequest;
     this.source = source;
+    this.cursor = null;
+  }
+
+  get done() {
+    return !this.cursor;
+  }
+
+  // This method is used internally to wait the cursor's IDBRequest to have been
+  // completed and the internal cursor has been updated (used when we initially
+  // create the cursor from Cursed.openCursor/openKeyCursor, and in the method
+  // of this class defined by defineCursorUpdateMethods).
+  async awaitRequest() {
+    this.cursor = await wrapRequest(this.cursorRequest);
+    return this;
   }
 }
 
+/**
+ * Define the Cursor class methods that update the cursor (continue, continuePrimaryKey
+ * and advance) as async functions that call the related IDBCursor methods and
+ * await the cursor's IDBRequest to be completed.
+ *
+ * @param {function} cls
+ *        The class constructor for which to define the cursor update methods.
+ * @param {Array<string>} methods
+ *        A list of "cursor update" method names to define.
+ */
+function defineCursorUpdateMethods(cls, methods) {
+  for (let method of methods) {
+    cls.prototype[method] = async function(...args) {
+      const promise = this.awaitRequest();
+      this.cursor[method](...args);
+      await promise;
+    };
+  }
+}
+
+defineCursorUpdateMethods(Cursor, ["advance", "continue", "continuePrimaryKey"]);
+
 forwardGetters(Cursor, "cursor",
                ["direction", "key", "primaryKey"]);
-
 wrapMethods(Cursor, "cursor", ["delete", "update"]);
 
-forwardMethods(Cursor, "cursor",
-               ["advance", "continue", "continuePrimaryKey"]);
-
 class CursorWithValue extends Cursor {}
 
 forwardGetters(CursorWithValue, "cursor", ["value"]);
 
 class Cursed {
   constructor(cursed) {
     this.cursed = cursed;
   }
 
   openCursor(...args) {
-    return wrapRequest(this.cursed.openCursor(...args)).then(cursor => {
-      return new CursorWithValue(cursor, this);
-    });
+    const cursor = new CursorWithValue(this.cursed.openCursor(...args), this);
+    return cursor.awaitRequest();
   }
 
   openKeyCursor(...args) {
-    return wrapRequest(this.cursed.openKeyCursor(...args)).then(cursor => {
-      return new Cursor(cursor, this);
-    });
+    const cursor = new Cursor(this.cursed.openKeyCursor(...args), this);
+    return cursor.awaitRequest();
   }
 }
 
 wrapMethods(Cursed, "cursed",
             ["count", "get", "getAll", "getAllKeys", "getKey"]);
 
 class Index extends Cursed {
   constructor(index, objectStore) {
@@ -247,27 +277,57 @@ class IndexedDB {
    *        first parameter when the database needs to be created, or its
    *        schema needs to be upgraded. If this function is not provided, the
    *        {@link #onupgradeneeded} method will be called instead.
    *
    * @returns {Promise<IndexedDB>}
    */
   static open(dbName, options, onupgradeneeded = null) {
     let request = indexedDB.open(dbName, options);
+    return this._wrapOpenRequest(request, onupgradeneeded);
+  }
 
+  /**
+   * Opens the database for a given principal and with the given name, returns
+   * a Promise which resolves to an IndexedDB instance when the operation completes.
+   *
+   * @param {nsIPrincipal} principal
+   *        The principal to open the database for.
+   * @param {string} dbName
+   *        The name of the database to open.
+   * @param {object} options
+   *        The options with which to open the database.
+   * @param {integer} options.version
+   *        The schema version with which the database needs to be opened. If
+   *        the database does not exist, or its current schema version does
+   *        not match, the `onupgradeneeded` function will be called.
+   * @param {function} [onupgradeneeded]
+   *        A function which will be called with an IndexedDB object as its
+   *        first parameter when the database needs to be created, or its
+   *        schema needs to be upgraded. If this function is not provided, the
+   *        {@link #onupgradeneeded} method will be called instead.
+   *
+   * @returns {Promise<IndexedDB>}
+   */
+  static openForPrincipal(principal, dbName, options, onupgradeneeded = null) {
+    const request = indexedDB.openForPrincipal(principal, dbName, options);
+    return this._wrapOpenRequest(request, onupgradeneeded);
+  }
+
+  static _wrapOpenRequest(request, onupgradeneeded = null) {
     request.onupgradeneeded = event => {
       let db = new this(request.result);
       if (onupgradeneeded) {
         onupgradeneeded(db, event);
       } else {
         db.onupgradeneeded(event);
       }
     };
 
-    return wrapRequest(request).then(db => new IndexedDB(db));
+    return wrapRequest(request).then(db => new this(db));
   }
 
   constructor(db) {
     this.db = db;
   }
 
   onupgradeneeded() {}