From 2bf923bf8017c1cc9bcefc4ad5582bc1e4857ffe Mon Sep 17 00:00:00 2001
From: Tristan Cavelier <tristan.cavelier@tiolive.com>
Date: Tue, 23 Jul 2013 16:56:45 +0200
Subject: [PATCH] indexstorage upgraded to be used with gid storage

Database is not stored on metadata anymore. A document is created with the
database as attachment.
---
 src/jio.storage/indexstorage.js | 199 +++++++++++++++++++++++++++-----
 1 file changed, 168 insertions(+), 31 deletions(-)

diff --git a/src/jio.storage/indexstorage.js b/src/jio.storage/indexstorage.js
index 7e6fbfd..b2c9eb7 100644
--- a/src/jio.storage/indexstorage.js
+++ b/src/jio.storage/indexstorage.js
@@ -1,11 +1,23 @@
 /*
- * Copyright 2013, Nexedi SA
- * Released under the LGPL license.
- * http://www.gnu.org/licenses/lgpl.html
+ * JIO extension for resource indexing.
+ * Copyright (C) 2013  Nexedi SA
+ *
+ *   This library is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */
-/*global jIO: true, localStorage: true, define: true, complex_queries: true */
+/*global jIO, define, complex_queries */
 
 /**
  * JIO Index Storage.
@@ -15,7 +27,15 @@
  *   "type": "index",
  *   "indices": [{
  *     "id": "index_title_subject.json", // doc id where to store indices
- *     "index": ["title", "subject"] // metadata to index
+ *     "index": ["title", "subject"], // metadata to index
+ *     "attachment": "youhou", // default "body"
+ *     "metadata": { // default {}
+ *       "type": "Dataset",
+ *       "format": "application/json",
+ *       "date": "yyyy-mm-ddTHH:MM:SS+HH:MM",
+ *       "title": "My index database",
+ *       "creator": "Me"
+ *     },
  *     "sub_storage": <sub storage where to store index>
  *                    (default equal to parent sub_storage field)
  *   }, {
@@ -30,6 +50,21 @@
  * index_titre_subject.json
  * {
  *   "_id": "index_title_subject.json",
+ *   "type": "Dataset",
+ *   "format": "application/json",
+ *   "date": "yyyy-mm-ddTHH:MM:SS+HH:MM",
+ *   "title": "My index database",
+ *   "creator": "Me",
+ *   "_attachments": {
+ *     "youhou": {
+ *       "length": Num,
+ *       "digest": "XXX",
+ *       "content_type": "application/json"
+ *     }
+ *   }
+ * }
+ * Attachment "youhou"
+ * {
  *   "indexing": ["title", "subject"],
  *   "free": [0],
  *   "location": {
@@ -48,6 +83,12 @@
  * index_year.json
  * {
  *   "_id": "index_year.json",
+ *   "_attachments": {
+ *     "body": {..}
+ *   }
+ * }
+ * Attachment "body"
+ * {
  *   "indexing": ["year"],
  *   "free": [1],
  *   "location": {
@@ -170,6 +211,32 @@
       S4() + S4() + S4();
   }
 
+  /**
+   * Tool to get the date in W3C date format "2011-12-13T14:15:16+01:00"
+   *
+   * @param  {Any} date The new Date() parameter
+   * @return {String} The date in W3C date format
+   */
+  function w3cDate(date) {
+    var d = new Date(date), offset = -d.getTimezoneOffset();
+    return (
+      d.getFullYear() + "-" +
+        (d.getMonth() + 1) + "-" +
+        d.getDate() + "T" +
+        d.getHours() + ":" +
+        d.getMinutes() + ":" +
+        d.getSeconds() +
+        (offset < 0 ? "-" : "+") +
+        (offset / 60) + ":" +
+        (offset % 60)
+    ).replace(/[0-9]+/g, function (found) {
+      if (found.length < 2) {
+        return '0' + found;
+      }
+      return found;
+    });
+  }
+
   /**
    * A JSON Index manipulator
    *
@@ -188,6 +255,14 @@
      */
     that._id = spec._id;
 
+    /**
+     * The attachment id
+     *
+     * @property _attachment
+     * @type String
+     */
+    that._attachment = spec._attachment;
+
     /**
      * The array with metadata key to index
      *
@@ -231,13 +306,13 @@
      * @return {Boolean} true if added, false otherwise
      */
     that.put = function (meta) {
-      var underscored_meta_re = /^_.*$/, k, needed_meta = {}, ok = false;
+      var k, needed_meta = {}, ok = false;
       if (typeof meta._id !== "string" && meta._id !== "") {
         throw new TypeError("Corrupted Metadata");
       }
       for (k in meta) {
         if (meta.hasOwnProperty(k)) {
-          if (underscored_meta_re.test(k)) {
+          if (k[0] === "_") {
             if (k === "_id") {
               needed_meta[k] = meta[k];
             }
@@ -293,10 +368,13 @@
       var id, database_meta;
       if (typeof that._id !== "string" ||
           that._id === "" ||
-          type(that._free) !== "Array" ||
-          type(that._indexing) !== "Array" ||
-          type(that._location) !== "Object" ||
-          type(that._database) !== "Array" ||
+          typeof that._attachment !== "string" ||
+          that._attachment === "" ||
+          !Array.isArray(that._free) ||
+          !Array.isArray(that._indexing) ||
+          typeof that._location !== 'object' ||
+          Array.isArray(that._location) ||
+          !Array.isArray(that._database) ||
           that._indexing.length === 0) {
         throw new TypeError("Corrupted Index");
       }
@@ -381,7 +459,6 @@
      */
     that.serialized = function () {
       return {
-        "_id": that._id,
         "indexing": that._indexing,
         "free": that._free,
         "location": that._location,
@@ -467,17 +544,32 @@
      */
     priv.getIndexDatabase = function (option, number, callback) {
       that.addJob(
-        "get",
+        "getAttachment",
         priv.indices[number].sub_storage || priv.sub_storage,
-        {"_id": priv.indices[number].id},
+        {
+          "_id": priv.indices[number].id,
+          "_attachment": priv.indices[number].attachment || "body"
+        },
         option,
         function (response) {
-          callback(new JSONIndex(response));
+          try {
+            response = JSON.parse(response);
+            response._id = priv.indices[number].id;
+            response._attachment = priv.indices[number].attachment || "body";
+            callback(new JSONIndex(response));
+          } catch (e) {
+            return that.error(generateErrorObject(
+              e.message,
+              "Repair is necessary",
+              "corrupt"
+            ));
+          }
         },
         function (err) {
           if (err.status === 404) {
             callback(new JSONIndex({
               "_id": priv.indices[number].id,
+              "_attachment": priv.indices[number].attachment || "body",
               "indexing": priv.indices[number].index
             }));
             return;
@@ -502,6 +594,7 @@
           if (err.status === 404) {
             response_list[index] = new JSONIndex({
               "_id": priv.indices[index].id,
+              "_attachment": priv.indices[index].attachment || "body",
               "indexing": priv.indices[index].index
             });
             count += 1;
@@ -516,7 +609,19 @@
       };
       callbacks.success = function (index) {
         return function (response) {
-          response_list[index] = new JSONIndex(response);
+          try {
+            response = JSON.parse(response);
+            response._id = priv.indices[index].id;
+            response._attachment = priv.indices[index].attachment || "body";
+            console.log(response);
+            response_list[index] = new JSONIndex(response);
+          } catch (e) {
+            return that.error(generateErrorObject(
+              e.message,
+              "Repair is necessary",
+              "corrupt"
+            ));
+          }
           count += 1;
           if (count === priv.indices.length) {
             callback(response_list);
@@ -525,9 +630,12 @@
       };
       for (i = 0; i < priv.indices.length; i += 1) {
         that.addJob(
-          "get",
+          "getAttachment",
           priv.indices[i].sub_storage || priv.sub_storage,
-          {"_id": priv.indices[i].id},
+          {
+            "_id": priv.indices[i].id,
+            "_attachment": priv.indices[i].attachment || "body"
+          },
           option,
           callbacks.success(i),
           callbacks.error(i)
@@ -544,28 +652,56 @@
      * @param  {Function} callback The result callback(err, response)
      */
     priv.storeIndexDatabaseList = function (database_list, option, callback) {
-      var i, count = 0, count_max = 0, onResponse, onError;
-      onResponse = function (response) {
+      var i, count = 0, count_max = 0;
+      function onAttachmentResponse(response) {
         count += 1;
         if (count === count_max) {
           callback({"ok": true});
         }
-      };
-      onError = function (err) {
+      }
+      function onAttachmentError(err) {
         err.message = "Unable to store index database.";
         that.error(err);
-      };
+      }
+      function putAttachment(i) {
+        that.addJob(
+          "putAttachment",
+          priv.indices[i].sub_storage || priv.sub_storage,
+          {
+            "_id": database_list[i]._id,
+            "_attachment": database_list[i]._attachment,
+            "_data": JSON.stringify(database_list[i].serialized()),
+            "_mimetype": "application/json"
+          },
+          option,
+          onAttachmentResponse,
+          onAttachmentError
+        );
+      }
+      function post(i) {
+        var doc = priv.indices[i].metadata || {};
+        doc._id = database_list[i]._id;
+        that.addJob(
+          "post", // with id
+          priv.indices[i].sub_storage || priv.sub_storage,
+          doc,
+          option,
+          function (response) {
+            putAttachment(i);
+          },
+          function (err) {
+            if (err.status === 409) {
+              return putAttachment(i);
+            }
+            err.message = "Unable to store index database.";
+            that.error(err);
+          }
+        );
+      }
       for (i = 0; i < priv.indices.length; i += 1) {
         if (database_list[i] !== undefined) {
           count_max += 1;
-          that.addJob(
-            "put",
-            priv.indices[i].sub_storage || priv.sub_storage,
-            database_list[i].serialized(),
-            option,
-            onResponse,
-            onError
-          );
+          post(i);
         }
       }
     };
@@ -735,6 +871,7 @@
         function (response) {
           var db_list = [], db = new JSONIndex({
             "_id": command.getDocId(),
+            "_attachment": priv.indices[index].attachment || "body",
             "indexing": priv.indices[index].index
           });
           for (i = 0; i < response.rows.length; i += 1) {
-- 
2.30.9