add comments, fix foolish errors in various sql getter functions, add md5 helper util
authorAndrew Sutherland <asutherland@asutherland.org>
Fri, 11 Jul 2008 14:55:18 -0700
changeset 838 512b57925e95027a669716b14cacbde4266cd85b
parent 837 0f94c6fcee7f23f215ab00d48ad58344dc2784aa
child 839 81ffe51a097d5c27bf6f37be1a5e970bf7ca0bb1
push idunknown
push userunknown
push dateunknown
add comments, fix foolish errors in various sql getter functions, add md5 helper util
modules/datastore.js
modules/utils.js
--- a/modules/datastore.js
+++ b/modules/datastore.js
@@ -280,32 +280,48 @@ let GlodaDatastore = {
                            createInstance(Ci.mozIStorageStatementWrapper);
     wrappedStatement.initialize(statement);
     return wrappedStatement;
   },
 
   /** Simple nested transaction support as a performance optimization. */  
   _transactionDepth: 0,
   _transactionGood: false,
+  /**
+   * Begin a potentially nested transaction; only the outermost transaction gets
+   *  to be an actual transaction, and the failure of any nested transaction
+   *  results in a rollback of the entire outer transaction.  If you really
+   *  need an atomic transaction 
+   */
   _beginTransaction: function gloda_ds_beginTransaction() {
     if (this._transactionDepth == 0) {
       this.dbConnection.beginTransaction();
       this._transactionGood = true;
     }
     this._transactionDepth++;
   },
+  /**
+   * Commit a potentially nested transaction; if we are the outer-most
+   *  transaction and no sub-transaction issues a rollback
+   *  (via _rollbackTransaction) then we commit, otherwise we rollback.
+   */
   _commitTransaction: function gloda_ds_commitTransaction() {
     this._transactionDepth--;
     if (this._transactionDepth == 0) {
       if (this._transactionGood)
         this.dbConnection.commitTransaction();
       else
         this.dbConnection.rollbackTransaction();
     }
   },
+  /**
+   * Abort the commit of the potentially nested transaction.  If we are not the
+   *  outermost transaction, we set a flag that tells the outermost transaction
+   *  that it must roll back.
+   */
   _rollbackTransaction: function gloda_ds_rollbackTransaction() {
     this._transactionDepth--;
     this._transactionGood = false;
     if (this._transactionDepth == 0) {
       this.dbConnection.rollbackTransaction();
     }
   },
   
@@ -347,17 +363,20 @@ let GlodaDatastore = {
     let statement = this._createStatement(
       "SELECT * FROM attributeDefinitions");
     this.__defineGetter__("_selectAttributeDefinitionsStatement",
       function() statement);
     return this._selectAttributeDefinitionsStatement;
   },
   
   /**
-   * Look-up all the attribute definitions 
+   * Look-up all the attribute definitions, populating our authoritative 
+   *  _attributes and _attributeIDToDef maps.  (In other words, once this method
+   *  is called, those maps should always be in sync with the underlying
+   *  database.)
    */
   getAllAttributes: function gloda_ds_getAllAttributes() {
     // map compound name to the attribute
     let attribs = {};
     // map the attribute id to [attribute, parameter] where parameter is null
     //  in cases where parameter is unused.
     let idToAttribAndParam = {}
 
@@ -391,16 +410,22 @@ let GlodaDatastore = {
     this._selectAttributeDefinitionsStatement.reset();
 
     this._log.info("done loading all attribute defs");
     
     this._attributes = attribs;
     this._attributeIDToDef = idToAttribAndParam;
   },
   
+  /**
+   * Helper method for GlodaAttributeDef to tell us when their bindParameter
+   *  method is called and they have created a new binding (using
+   *  GlodaDatastore._createAttributeDef).  In theory, that method could take
+   *  an additional argument and obviate the need for this method.
+   */
   reportBinding: function gloda_ds_reportBinding(aID, aAttrDef, aParamValue) {
     this._attributeIDToDef[aID] = [aAttrDef, aParamValue];
   },
   
   /* ********** Folders ********** */
   
   get _insertFolderLocationStatement() {
     let statement = this._createStatement(
@@ -422,19 +447,25 @@ let GlodaDatastore = {
   get _selectAllFolderLocations() {
     let statement = this._createStatement(
       "SELECT id, folderURI FROM folderLocations");
     this.__defineGetter__("_selectAllFolderLocations",
       function() statement);
     return this._selectAllFolderLocations;
   },
   
+  /** Authoritative map from folder URI to folder ID */
   _folderURIs: {},
+  /** Authoritative map from folder ID to folder URI */
   _folderIDs: {},
   
+  /**
+   * Map a folder URI to a folder ID, creating the mapping if it does not yet
+   *  exist.
+   */
   _mapFolderURI: function gloda_ds_mapFolderURI(aFolderURI) {
     if (aFolderURI in this._folderURIs) {
       return this._folderURIs[aFolderURI];
     }
     
     var folderID;
     this._selectFolderLocationByURIStatement.params.folderURI = aFolderURI;
     if (this._selectFolderLocationByURIStatement.step()) {
@@ -885,17 +916,17 @@ let GlodaDatastore = {
   
     let scbi = this._selectContactByIDStatement;
     scbi.params.id = aContactID;
     if (scbi.step()) {
       contact = this._contactFromRow(scbi.row);
     }
     scbi.reset();
     
-    return scbi;
+    return contact;
   },
   
   /* ********** Identity ********** */
   get _insertIdentityStatement() {
     let statement = this._createStatement(
       "INSERT INTO identities (contactID, kind, value, description) \
               VALUES (:contactID, :kind, :value, :description)");
     this.__defineGetter__("_insertIdentityStatement", function() statement);
@@ -940,28 +971,28 @@ let GlodaDatastore = {
     }
     ibkv.reset();
     
     return identity;
   },
 
   get _selectIdentityByIDStatement() {
     let statement = this._createStatement(
-      "SELECT * FROM identities WHERE id :id");
+      "SELECT * FROM identities WHERE id = :id");
     this.__defineGetter__("_selectIdentityByIDStatement",
       function() statement);
     return this._selectIdentityByIDStatement;
   },
 
   getIdentityByID: function gloda_ds_getIdentity(aID) {
     let identity = null;
     
     let sibis = this._selectIdentityByIDStatement;
     sibis.params.id = aID;
     if (sibis.step()) {
-      sibis = this._identityFromRow(sibis.row);
+      identity = this._identityFromRow(sibis.row);
     }
     sibis.reset();
     
     return identity;
   },
 
 };
--- a/modules/utils.js
+++ b/modules/utils.js
@@ -73,9 +73,35 @@ let GlodaUtils = {
                                              names, fullAddresses);
     return {names: names.value, addresses: addresses.value,
             fullAddresses: fullAddresses.value,
             count: names.value.length}; 
   },
   
   extractBodySnippet: function gloda_utils_extractBodySnippet(aBodyString) {
   },
+  
+  /**
+   * MD5 hash a string and return the hex-string result. Impl from nsICryptoHash
+   *  docs.
+   */
+  md5HashString: function gloda_utils_md5hash(aString) {
+    let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
+                    createInstance(Ci.nsIScriptableUnicodeConverter);
+    let trash = {};
+    converter.charset = "UTF-8";
+    let emailArr = converter.convertToByteArray(aString, trash);
+
+    let hasher = Cc['@mozilla.org/security/hash;1'].
+                 createInstance(Ci.nsICryptoHash);
+    hasher.init(Ci.nsICryptoHash.MD5);
+    hasher.update(emailArr, emailArr.length);
+    let hash = hasher.finish(false);
+    
+     // return the two-digit hexadecimal code for a byte
+    function toHexString(charCode) {
+      return ("0" + charCode.toString(16)).slice(-2);
+    }
+
+    // convert the binary hash data to a hex string.
+    return [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
+  },
 };