Bug 1365143 - Add schema version number for each Form Fill record in ProfileStorage.; r?lchang draft
authorSean Lee <selee@mozilla.com>
Tue, 16 May 2017 14:50:39 +0800
changeset 578697 488c5da465d8b2b7e2bef867980409533c964b79
parent 578175 3e166b6838931b3933ca274331f9e0e115af5cc0
child 628805 a358240dedfe86efe5ac4767a424538936af0d4e
push id59026
push userbmo:selee@mozilla.com
push dateTue, 16 May 2017 10:56:32 +0000
reviewerslchang
bugs1365143
milestone55.0a1
Bug 1365143 - Add schema version number for each Form Fill record in ProfileStorage.; r?lchang MozReview-Commit-ID: 6o7ThqX79Sx
browser/extensions/formautofill/ProfileStorage.jsm
browser/extensions/formautofill/test/unit/test_addressRecords.js
browser/extensions/formautofill/test/unit/test_creditCardRecords.js
--- a/browser/extensions/formautofill/ProfileStorage.jsm
+++ b/browser/extensions/formautofill/ProfileStorage.jsm
@@ -9,16 +9,17 @@
  * fields, using UTF-8 encoding. With indentation and computed fields applied,
  * the schema would look like this:
  *
  * {
  *   version: 1,
  *   addresses: [
  *     {
  *       guid,                 // 12 characters
+ *       version,              // schema version in integer
  *
  *       // address fields
  *       given-name,
  *       additional-name,
  *       family-name,
  *       organization,         // Company
  *       street-address,       // (Multiline)
  *       address-level2,       // City/Town
@@ -40,16 +41,17 @@
  *       timeLastUsed,         // in ms
  *       timeLastModified,     // in ms
  *       timesUsed
  *     }
  *   ],
  *   creditCards: [
  *     {
  *       guid,                 // 12 characters
+ *       version,              // schema version in integer
  *
  *       // credit card fields
  *       cc-name,
  *       cc-number-encrypted,
  *       cc-number-masked,     // e.g. ************1234
  *       cc-exp-month,
  *       cc-exp-year,          // 2-digit year will be converted to 4 digits
  *                             // upon saving
@@ -90,17 +92,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://formautofill/FormAutofillNameUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
 
 const PROFILE_JSON_FILE_NAME = "autofill-profiles.json";
 
-const SCHEMA_VERSION = 1;
+const STORAGE_SCHEMA_VERSION = 1;
+const ADDRESS_SCHEMA_VERSION = 1;
+const CREDIT_CARD_SCHEMA_VERSION = 1;
 
 const VALID_PROFILE_FIELDS = [
   "given-name",
   "additional-name",
   "family-name",
   "organization",
   "street-address",
   "address-level2",
@@ -116,16 +120,17 @@ const VALID_CREDIT_CARD_FIELDS = [
   "cc-number-encrypted",
   "cc-number-masked",
   "cc-exp-month",
   "cc-exp-year",
 ];
 
 const INTERNAL_FIELDS = [
   "guid",
+  "version",
   "timeCreated",
   "timeLastUsed",
   "timeLastModified",
   "timesUsed",
 ];
 
 /**
  * Class that manipulates records in a specified collection.
@@ -139,34 +144,37 @@ class AutofillRecords {
    * Creates an AutofillRecords.
    *
    * @param {JSONFile} store
    *        An instance of JSONFile.
    * @param {string} collectionName
    *        A key of "store.data".
    * @param {Array.<string>} validFields
    *        A list containing non-metadata field names.
+   * @param {number} schemaVersion
+   *        The schema version for the new record.
    */
-  constructor(store, collectionName, validFields) {
+  constructor(store, collectionName, validFields, schemaVersion) {
     FormAutofillUtils.defineLazyLogGetter(this, "AutofillRecords:" + collectionName);
 
     this.VALID_FIELDS = validFields;
 
     this._store = store;
     this._collectionName = collectionName;
+    this._schemaVersion = schemaVersion;
   }
 
   /**
    * Gets the schema version number.
    *
    * @returns {number}
    *          The current schema version number.
    */
   get version() {
-    return SCHEMA_VERSION;
+    return this._schemaVersion;
   }
 
   /**
    * Adds a new record.
    *
    * @param {Object} record
    *        The new record for saving.
    */
@@ -177,16 +185,17 @@ class AutofillRecords {
     this._normalizeRecord(recordToSave);
 
     let guid;
     while (!guid || this._findByGUID(guid)) {
       guid = gUUIDGenerator.generateUUID().toString()
                            .replace(/[{}-]/g, "").substring(0, 12);
     }
     recordToSave.guid = guid;
+    recordToSave.version = this.version;
 
     // Metadata
     let now = Date.now();
     recordToSave.timeCreated = now;
     recordToSave.timeLastModified = now;
     recordToSave.timeLastUsed = 0;
     recordToSave.timesUsed = 0;
 
@@ -366,17 +375,17 @@ class AutofillRecords {
   _recordReadProcessor(record, config) {}
 
   // An interface to be inherited.
   _recordWriteProcessor(record) {}
 }
 
 class Addresses extends AutofillRecords {
   constructor(store) {
-    super(store, "addresses", VALID_PROFILE_FIELDS);
+    super(store, "addresses", VALID_PROFILE_FIELDS, ADDRESS_SCHEMA_VERSION);
   }
 
   _recordReadProcessor(profile, {noComputedFields} = {}) {
     if (noComputedFields) {
       return;
     }
 
     // Compute name
@@ -441,17 +450,17 @@ class Addresses extends AutofillRecords 
         profile["street-address"] = addressLines.join("\n");
       }
     }
   }
 }
 
 class CreditCards extends AutofillRecords {
   constructor(store) {
-    super(store, "creditCards", VALID_CREDIT_CARD_FIELDS);
+    super(store, "creditCards", VALID_CREDIT_CARD_FIELDS, CREDIT_CARD_SCHEMA_VERSION);
   }
 
   _recordReadProcessor(creditCard, {noComputedFields} = {}) {
     if (noComputedFields) {
       return;
     }
 
     // Compute split names
@@ -533,16 +542,20 @@ class CreditCards extends AutofillRecord
 
 function ProfileStorage(path) {
   this._path = path;
   this._initializePromise = null;
   this.INTERNAL_FIELDS = INTERNAL_FIELDS;
 }
 
 ProfileStorage.prototype = {
+  get version() {
+    return STORAGE_SCHEMA_VERSION;
+  },
+
   get addresses() {
     if (!this._addresses) {
       this._store.ensureDataReady();
       this._addresses = new Addresses(this._store);
     }
     return this._addresses;
   },
 
@@ -568,17 +581,17 @@ ProfileStorage.prototype = {
         dataPostProcessor: this._dataPostProcessor.bind(this),
       });
       this._initializePromise = this._store.load();
     }
     return this._initializePromise;
   },
 
   _dataPostProcessor(data) {
-    data.version = SCHEMA_VERSION;
+    data.version = this.version;
     if (!data.addresses) {
       data.addresses = [];
     }
     if (!data.creditCards) {
       data.creditCards = [];
     }
     return data;
   },
--- a/browser/extensions/formautofill/test/unit/test_addressRecords.js
+++ b/browser/extensions/formautofill/test/unit/test_addressRecords.js
@@ -171,16 +171,17 @@ add_task(async function test_add() {
   let addresses = profileStorage.addresses.getAll();
 
   do_check_eq(addresses.length, 2);
 
   do_check_record_matches(addresses[0], TEST_ADDRESS_1);
   do_check_record_matches(addresses[1], TEST_ADDRESS_2);
 
   do_check_neq(addresses[0].guid, undefined);
+  do_check_eq(addresses[0].version, 1);
   do_check_neq(addresses[0].timeCreated, undefined);
   do_check_eq(addresses[0].timeLastModified, addresses[0].timeCreated);
   do_check_eq(addresses[0].timeLastUsed, 0);
   do_check_eq(addresses[0].timesUsed, 0);
 
   Assert.throws(() => profileStorage.addresses.add(TEST_ADDRESS_WITH_INVALID_FIELD),
     /"invalidField" is not a valid field\./);
 });
--- a/browser/extensions/formautofill/test/unit/test_creditCardRecords.js
+++ b/browser/extensions/formautofill/test/unit/test_creditCardRecords.js
@@ -183,16 +183,17 @@ add_task(async function test_add() {
   let creditCards = profileStorage.creditCards.getAll();
 
   do_check_eq(creditCards.length, 2);
 
   do_check_credit_card_matches(creditCards[0], TEST_CREDIT_CARD_1);
   do_check_credit_card_matches(creditCards[1], TEST_CREDIT_CARD_2);
 
   do_check_neq(creditCards[0].guid, undefined);
+  do_check_eq(creditCards[0].version, 1);
   do_check_neq(creditCards[0].timeCreated, undefined);
   do_check_eq(creditCards[0].timeLastModified, creditCards[0].timeCreated);
   do_check_eq(creditCards[0].timeLastUsed, 0);
   do_check_eq(creditCards[0].timesUsed, 0);
 
   Assert.throws(() => profileStorage.creditCards.add(TEST_CREDIT_CARD_WITH_INVALID_FIELD),
     /"invalidField" is not a valid field\./);
 });