changeset 12:9ed45c82a731

Refactoring: made a new ordered dictionary class and made the DB use that.
author Atul Varma <varmaa@toolness.com>
date Fri, 10 Apr 2009 14:29:26 -0700
parents 89c6105c2d1e
children 07e8dc256570
files browser-couch.js
diffstat 1 files changed, 89 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/browser-couch.js	Fri Apr 10 12:55:47 2009 -0700
+++ b/browser-couch.js	Fri Apr 10 14:29:26 2009 -0700
@@ -39,7 +39,7 @@
     var self = this;
 
     function createDb() {
-      cb(new self._DB(name, storage, JSON));
+      cb(new self._DB(name, storage, new self._Dictionary(JSON)));
     }
 
     if (!storage) {
@@ -84,53 +84,107 @@
     doc.body.appendChild(script);
   },
 
-  _DB: function BC__DB(name, storage, JSON) {
+  _Dictionary: function BC__Dictionary(JSON) {
+    var keysAndValues = [];
+    var keyIndex = {};
+
+    function sort() {
+      keyIndex = {};
+      keysAndValues.sort(function compare(a, b) {
+                           if (a[0] < b[0])
+                             return -1;
+                           if (a[0] > b[0])
+                             return 1;
+                           return 0;
+                         });
+      for (var i = 0; i < keysAndValues.length; i++) {
+        var tuple = keysAndValues[i];
+        keyIndex[tuple[0]] = i;
+      }
+    }
+
+    this.has = function Dictionary_has(key) {
+      return (key in keyIndex);
+    };
+
+    this.getNthValue = function Dictionary_getNthValue(index) {
+      return keysAndValues[index][1];
+    };
+
+    this.getLength = function Dictionary_getLength() {
+      return keysAndValues.length;
+    };
+
+    this.get = function Dictionary_get(key) {
+      var index = keyIndex[key];
+      if (index)
+        return keysAndValues[index][1];
+      else
+        throw new Error("key not in dictionary: " + key);
+    };
+
+    this.set = function Dictionary_set(key, value) {
+      if (key in keyIndex)
+        keysAndValues[keyIndex[key]][1] = value;
+      else {
+        keysAndValues.push([key, value]);
+        sort();
+      }
+    };
+
+    this.delete = function Dictionary_delete(key) {
+      delete keysAndValues[keyIndex[key]];
+      sort();
+    };
+
+    this.clear = function Dictionary_clear() {
+      keysAndValues = [];
+      keyIndex = {};
+    };
+
+    this.toJSON = function Dictionary_toJSON() {
+      return JSON.stringify({keysAndValues: keysAndValues,
+                             keyIndex: keyIndex});
+    };
+
+    this.fromJSON = function Dictionary_fromJSON(string) {
+      var obj = JSON.parse(string);
+      keysAndValues = obj.keysAndValues;
+      keyIndex = obj.keyIndex;
+    };
+  },
+
+  _DB: function BC__DB(name, storage, dict) {
     var dbName = 'BrowserCouch_DB_' + name;
 
-    var documents = [];
-    var docIdIndex = {};
-
-    if (dbName in storage && storage[dbName].value) {
-      var db = JSON.parse(storage[dbName].value);
-      documents = db.documents;
-      docIdIndex = db.docIdIndex;
-    }
+    if (dbName in storage && storage[dbName].value)
+      dict.fromJSON(storage[dbName].value);
 
     function commitToStorage() {
-      storage[dbName].value = JSON.stringify(
-        {documents: documents,
-         docIdIndex: docIdIndex}
-      );
+      storage[dbName].value = dict.toJSON();
     }
 
     this.wipe = function DB_wipe(cb) {
-      documents = [];
-      docIdIndex = {};
+      dict.clear();
       commitToStorage();
       if (cb)
         cb();
     };
 
     this.get = function DB_get(id, cb) {
-      if (id in docIdIndex)
-        cb(documents[docIdIndex[id]]);
+      if (dict.has(id))
+        cb(dict.get(id));
       else
         cb(null);
     };
 
     this.put = function DB_put(document, cb) {
-      function putSingleDocument(doc) {
-        if (doc.id in docIdIndex)
-          documents[docIdIndex[doc.id]] = doc;
-        else
-          docIdIndex[doc.id] = documents.push(doc) - 1;
-      }
-
       if (document.constructor.name == "Array") {
         for (var i = 0; i < document.length; i++)
-          putSingleDocument(document[i]);
+          dict.set(document[i].id, document[i]);
       } else
-        putSingleDocument(document);
+        dict.set(document.id, document);
+
       commitToStorage();
       cb();
     };
@@ -145,15 +199,16 @@
 
       BrowserCouch._mapReduce(options.map,
                               options.reduce,
-                              documents,
+                              dict,
                               options.progress,
                               options.finished,
                               options.chunkSize);
     };
   },
 
-  _mapReduce: function BC__mapReduce(map, reduce, documents, progress,
+  _mapReduce: function BC__mapReduce(map, reduce, dict, progress,
                                      finished, chunkSize) {
+    var len = dict.getLength();
     var mapResult = {};
 
     function emit(key, value) {
@@ -165,7 +220,7 @@
       mapResult[key].push(value);
     }
 
-    // Maximum number of documents to process before giving the UI a chance
+    // Maximum number of items to process before giving the UI a chance
     // to breathe.
     var DEFAULT_CHUNK_SIZE = 1000;
 
@@ -182,16 +237,16 @@
       var iAtStart = i;
 
       do {
-        map(documents[i], emit);
+        map(dict.getNthValue(i), emit);
         i++;
       } while (i - iAtStart < chunkSize &&
-               i < documents.length)
+               i < len)
 
-      if (i == documents.length)
+      if (i == len)
         doReduce();
       else {
         if (progress)
-          progress(i / documents.length, continueMap);
+          progress(i / len, continueMap);
         else
           window.setTimeout(continueMap, DEFAULT_UI_BREATHE_TIME);
       }