From efd49d1007be04c7cea8cb2196f77089eb3101a5 Mon Sep 17 00:00:00 2001
From: Johannes Goderbauer <j.goderbauer@adito.de>
Date: Mon, 15 Jun 2020 11:32:54 +0200
Subject: [PATCH] [Projekt: Entwicklung - Neon][TicketNr.: 1054657][Person
 Index affectedIds retrurn [null]] refactoring and comments

---
 .../recordcontainers/index/affectedIds.js     |  85 ++++++++-------
 .../recordcontainers/index/affectedIds.js     |  95 +++++++++-------
 process/IndexSearch_lib/process.js            | 102 ++++++++++++++----
 3 files changed, 183 insertions(+), 99 deletions(-)

diff --git a/entity/Organisation_entity/recordcontainers/index/affectedIds.js b/entity/Organisation_entity/recordcontainers/index/affectedIds.js
index 0c1b6c5b8f..1accd7f911 100644
--- a/entity/Organisation_entity/recordcontainers/index/affectedIds.js
+++ b/entity/Organisation_entity/recordcontainers/index/affectedIds.js
@@ -10,46 +10,53 @@ tableName = vars.get("$local.table");
 idValue = vars.get("$local.idvalue");
 action = vars.get("$local.action");
 
-if(action == "D")
-    result.object([idValue]);
-else
-{
-    infoContainer =  IndexsearchUtils.createAffectedInfoContainer(idValue, null, vars.get("$local.action")
-        ,function (){return vars.get("$local.columns")}
-        ,function (){return vars.get("$local.oldvalues")}
-        ,function (){return vars.get("$local.values")});
+infoContainer =  IndexsearchUtils.createAffectedInfoContainer(idValue, null, vars.get("$local.action")
+    ,function (){return vars.get("$local.columns")}
+    ,function (){return vars.get("$local.oldvalues")}
+    ,function (){return vars.get("$local.values")});
 
-    switch (tableName)
-    {
-        case "CONTACT":
-            res = [idValue];
-            break;    
-        case "ORGANISATION":
+switch (tableName)
+{
+    case "CONTACT":
+        res = [idValue];
+        break;    
+    case "ORGANISATION":
+        //if an organisation is created or deleted there is no need to do this for the ORGANISATION and CONTACT-table twice, since everytime a 
+        //entry in ORGANISATION is done´, it is also done in CONTACT which is handled in the switch case above => skip then the ORGANISATION-part
+        //(also on delete the record does not exist anymore)
+        if (action == "U") 
+        {
             res = newSelect("CONTACT.CONTACTID")
-                    .from("CONTACT")
-                    .where("CONTACT.PERSON_ID is null")
-                    .and("CONTACT.ORGANISATION_ID", idValue)
+                .from("CONTACT")
+                .where("CONTACT.PERSON_ID is null")
+                .and("CONTACT.ORGANISATION_ID", idValue)
+                .arrayColumn();
+        }
+        break;
+    case "ADDRESS":
+        //do not skip here if it's a delete action since it could be that only an address is removed and not a whole record-set of 
+        //organisation, address, communication, etc.
+        res = IndexsearchUtils.getAffectedIdValues("CONTACT_ID", infoContainer, function (id){
+            return newSelect("ADDRESS.CONTACT_ID")
+                    .from("ADDRESS")
+                    .where("ADDRESS.ADDRESSID", id)
                     .arrayColumn();
-            break;
-        case "ADDRESS":
-            res = IndexsearchUtils.getAffectedIdValues("CONTACT_ID", infoContainer, function (id){
-                return newSelect("ADDRESS.CONTACT_ID")
-                        .from("ADDRESS")
-                        .where("ADDRESS.ADDRESSID", id)
-                        .arrayColumn();
-            });
-            break;
-        case "COMMUNICATION":
-            res = IndexsearchUtils.getAffectedIdValues("CONTACT_ID", infoContainer, function (id){
-                return newSelect("COMMUNICATION.CONTACT_ID")
-                        .from("COMMUNICATION")
-                        .where("COMMUNICATION.COMMUNICATIONID", id)
-                        .arrayColumn();
-            });
-            break;
-        default:
-            res = [];   //needed, because the Index is being rebuilt if nothing gets returned
-    }
-
-        result.object(res);
+        });
+        break;
+    case "COMMUNICATION":
+        //do not skip here if it's a delete action since it could be that only a communication-entry is removed and not a whole record-set of 
+        //organisation, address, communication, etc.
+        res = IndexsearchUtils.getAffectedIdValues("CONTACT_ID", infoContainer, function (id){
+            return newSelect("COMMUNICATION.CONTACT_ID")
+                    .from("COMMUNICATION")
+                    .where("COMMUNICATION.COMMUNICATIONID", id)
+                    .arrayColumn();
+        });
+        break;
 }
+
+//needed, because the complete index (fullIndexer) is being rebuilt if nothing gets returned here
+if (res)
+    result.object(res);
+else
+    result.object([]);
diff --git a/entity/Person_entity/recordcontainers/index/affectedIds.js b/entity/Person_entity/recordcontainers/index/affectedIds.js
index 9388ac4456..00a8f1a6c4 100644
--- a/entity/Person_entity/recordcontainers/index/affectedIds.js
+++ b/entity/Person_entity/recordcontainers/index/affectedIds.js
@@ -9,52 +9,65 @@ var infoContainer, onUpdFn, tableName, res, action;
 tableName = vars.get("$local.table");
 idValue = vars.get("$local.idvalue");
 action = vars.get("$local.action");
-if (action == "D")
-    result.object([idValue]);
-else
-{
-    infoContainer =  IndexsearchUtils.createAffectedInfoContainer(idValue, null, vars.get("$local.action")
-        ,function (){return vars.get("$local.columns")}
-        ,function (){return vars.get("$local.oldvalues")}
-        ,function (){return vars.get("$local.values")});
 
-    switch (tableName)
-    {
-        case "CONTACT":
-            res = [idValue];
-            break;    
-        case "PERSON":
+infoContainer =  IndexsearchUtils.createAffectedInfoContainer(idValue, null, vars.get("$local.action")
+    ,function (){return vars.get("$local.columns")}
+    ,function (){return vars.get("$local.oldvalues")}
+    ,function (){return vars.get("$local.values")});
+
+switch (tableName)
+{
+    case "CONTACT":
+        res = [idValue];
+        break;    
+    case "PERSON":
+        //if a contact person is created or deleted there is no need to determine the index-uid for the PERSON and CONTACT-table, since everytime a 
+        //entry in PERSON is done, there is also  one mande in the CONTACT table which is handled in the switch case above 
+        //=> skip then the PERSON-part (also on delete the record does not exist anymore)
+        if (action == "U") 
+        {
             res = newSelect("CONTACT.CONTACTID")
-                        .from("CONTACT")
-                        .where("CONTACT.PERSON_ID", idValue)
-                        .arrayColumn();
-            break;
-        case "ORGANISATION":
+                .from("CONTACT")
+                .where("CONTACT.PERSON_ID", idValue)
+                .arrayColumn();
+        }
+        break;
+    case "ORGANISATION":
+        //an organisation can only be deleted if there are no persons left and if  an organisation is created there is no entry for person that has
+        //to be indexed => only in the update-case necessary
+        if (action == "U") 
+        {
             res = newSelect("CONTACT.CONTACTID")
                         .from("CONTACT")
                         .where("CONTACT.ORGANISATION_ID", idValue)
                         .and("CONTACT.PERSON_ID is not null")
                         .arrayColumn();
-            break;
-        case "ADDRESS":
-            res = IndexsearchUtils.getAffectedIdValues("CONTACT_ID", infoContainer, function (id){
-                return newSelect("ADDRESS.CONTACT_ID")
-                        .from("ADDRESS")
-                        .where("ADDRESS.ADDRESSID", id)
-                        .arrayColumn();
-            });
-            break;
-        case "COMMUNICATION":
-            res = IndexsearchUtils.getAffectedIdValues("CONTACT_ID", infoContainer, function (id){
-                return newSelect("COMMUNICATION.CONTACT_ID")
-                        .from("COMMUNICATION")
-                        .where("COMMUNICATION.COMMUNICATIONID", id)
-                        .arrayColumn();
-            });
-            break;
-        default:
-            res = [];   //needed, because the Index is being rebuilt if nothing gets returned
-    }
+        }
+        break;
+    case "ADDRESS":
+        //do not skip here if it's a delete action since it could be that only an address is removed and not a whole record-set of organisation,
+        //person, address, communication, etc.
+        res = IndexsearchUtils.getAffectedIdValues("CONTACT_ID", infoContainer, function (id){
+            return newSelect("ADDRESS.CONTACT_ID")
+                    .from("ADDRESS")
+                    .where("ADDRESS.ADDRESSID", id)
+                    .arrayColumn();
+        });
+        break;
+    case "COMMUNICATION":
+        //do not skip here if it's a delete action since it could be that only a communication-entry is removed and not a whole record-set of 
+        //organisation, person, address, communication, etc.
+        res = IndexsearchUtils.getAffectedIdValues("CONTACT_ID", infoContainer, function (id){
+            return newSelect("COMMUNICATION.CONTACT_ID")
+                    .from("COMMUNICATION")
+                    .where("COMMUNICATION.COMMUNICATIONID", id)
+                    .arrayColumn();
+        });
+        break;
+}
 
-        result.object(res);
-}
\ No newline at end of file
+//needed, because the complete index (fullIndexer) is being rebuilt if nothing gets returned here
+if (res)
+    result.object(res);
+else
+    result.object([]);
diff --git a/process/IndexSearch_lib/process.js b/process/IndexSearch_lib/process.js
index 4b22c05366..be35ad2cc8 100644
--- a/process/IndexSearch_lib/process.js
+++ b/process/IndexSearch_lib/process.js
@@ -5,20 +5,66 @@ import("system.text");
  * provides static methods for special handling of entities in JDito-Processes
  * do not create an instance of this
  * 
- * TODO: lib has to be updated with new Indexsearch when it is available
- * 
  * @class
  */
 function IndexsearchUtils() {}
 
 /**
- * TODO: Comment everything!
+ * Searches within an affectedInfoContainer for an id value <br/>
+ * This id value can be used in the affectedIds-process of an index-recordContainer for example <br/>
+ * 
+ * Depending on the provided action the given ID-field is searched in: <br/>
+ * <ul>
+ * <li>the newValues (action: I), no other values are yet present</li>
+ * <li>the oldValues (action: D), other values are not anymore present</li>
+ * <li>another source by calling a function (action: U), in the update case only values are provided that acutally changed so 
+ *      another source (usually the dattabase) is needed to perform the lookup</li>
+ * <li>Otherwise an empty array is given (action X for example)</li>
+ * </ul>
+ * 
+ * @param {String} fieldname                <p> Name of the field that shall be searched within the infocontainer
+ * @param {Object} affectedInfoContainer    <p> affectedInfoContainer like it is provided by the IndexsearchUtils.createAffectedInfoContainer-function
+ *
+ * @param {Function} updateFn               <p> a callback function that is called when an update-action is provided in the affectedInfoContianer 
+ *                                          (which means there are no [useful] newvalues/oldvalues) 
+ *
+ * @return {Array}                          <p> 1D-array of Strings with all affectedIds that where found depeding on the information in the 
+ *                                          affectedInfoContainer
+ * @example 
+ * //example for an affectedIds-procces for a indexer that is built on top of the database table OFFER
+ * //explanations of the example are written as code-comments
+ * ...imports, variables and more code here...
+ * //this is always the uid of the record that has been changed, so if an OFFER-entry has been changed the OFFERID is returned, if an OFFERITEM-entry 
+ * //has been changed the OFFERITEMID is returned and so on
+ * var idValue = vars.get("$local.idvalue");
+ * var infoContainer =  ...code for creating a infoContainer...
  * 
- * @param {} fieldname
- * @param {} affectedInfoContainer
- * @param {} updateFn
+ * switch (tableName)//the tableName is always the name of the DB table that has been changed (changed = inserted, updated or deleted)
+ * {
+ *     //if the OFFER itself has been changed it's very easy because it's possible to return the OFFERID directly
+ *     case "OFFER": 
+ *         res = [idValue];
+ *         break;    
+ *     //for other items (like the OFFERITEM in this exmaple) however it is not that easy, because the index-UID is needed as result in the 
+ *     //affectedIdsProcess, so we have find the correct OFFERID for the OFFERITEM that has been changed
+ *     // therefore we have to define the columnname of the index-UID we are searching within our table (here: OFFER_ID) and we have to define a 
+ *     //callback function that returns the index-UID with for the given ID of the record that has been changed [to see why we need a function see the
+ *     //descriptiontext of this function]
+ *     case "OFFERITEM": 
+ *         res = IndexsearchUtils.getAffectedIdValues("OFFER_ID", infoContainer, function (offerItemId){
+ *             return newSelect("OFFERITEM.OFFER_ID")
+ *             .from("OFFERITEM")
+ *             .where("OFFERITEM.OFFERITEMID", offerItemId)
+ *             .arrayColumn();
+ *         });
+ *         break;
+ * }
  * 
- * @return {}
+ * //this needed as a savegate, because the Index is being rebuilt by the indexer if nothing gets returned => do a final check here!
+ * if (res)
+ *     result.object(res);
+ * else
+ *     result.object([]);
  */
 IndexsearchUtils.getAffectedIdValues = function(fieldname, affectedInfoContainer, updateFn) {
     var affectedIds;
@@ -26,33 +72,51 @@ IndexsearchUtils.getAffectedIdValues = function(fieldname, affectedInfoContainer
     {
         case "I":
             affectedIds = affectedInfoContainer.newValues[affectedInfoContainer.columns.indexOf(fieldname)];
-            affectedIds = affectedIds ? [affectedIds] : []
+            affectedIds = affectedIds ? [affectedIds] : [];//check if affectedIds are present because otherwise we may would return [null]
             break;
         case "U":
             affectedIds = updateFn.call(null, affectedInfoContainer.id);
             break;
         case "D":
             affectedIds = affectedInfoContainer.oldValues[affectedInfoContainer.columns.indexOf(fieldname)];
-            affectedIds = affectedIds ? [affectedIds] : []
+            affectedIds = affectedIds ? [affectedIds] : [];//check if affectedIds are present because otherwise we may would return [null]
             break;
     }
-    if(affectedIds.length > 0)
-        return affectedIds || [];
+    if(affectedIds)
+        return affectedIds;
     else
         return [];
 }
 
 /**
- * TODO: Comment everything!
+ * Builds an object with various properties and returns the newly created object.
+ * The object that is retruned is so called affectedInfoContainer, but the type and prototype is still object.<br/>
+ * <br/>
+ * Each object represents one audited change in a db table with a sepcific type (insert, update, delete, etc.) for one row. 
+ * The object is basically a unified blueprint for such a change.<br/>
+ * <br/>
+ * Main purpose of the object is to make the handling of given values within a affectedIdProcess in an entity-indexRecordContainer easier.
+ * However it could be used in other cases too, for example in the auditProcess.
  * 
- * @param {} changedIdValue
- * @param {} changedTable
- * @param {} action
- * @param {} columnsFn
- * @param {} oldValueFn
- * @param {} newValueFn
+ * @param {String} changedIdValue   <p> UID of the row where the change has been audited
+ * @param {String} changedTable     <p> name of the db table where the change has been audited
+ * @param {String} action           <p> action type of the audited change in short form, for exmaple: I, U, D, ...
+ * @param {Function} columnsFn      <p> callbackFunction that has to return an array with the column names of the audited table
+ * @param {Function} oldValueFn     <p> callbackFunction that has to return an array with the new values that exist after the audited change
+ * @param {Function} newValueFn     <p> callbackFunction that has to return an array with the old values that have existed before the audited change
  * 
- * @return {}
+ * @return {Object} object with the following properties (values depend on the parameters):
+ * <ul>
+ * <li>id: uid of the changed record</li>
+ * <li>table: name of the database table of the changed record</li>
+ * <li>action: type of the change, this is usually "I" for insert, "U" for update, "D" for delete and "X" for unknown</li>
+ * <li>columns: array of column names of the table that have been audited (if present)</li>
+ * <li>oldValues: detemined values before the change (if present)</li>
+ * <li>newValues: detemined values after the change (if present)</li>
+ * </ul>
+ * <br/>
+ * Note that this only what the object SHOULD contain, the actual values depend on the input parameters.
+ *
  */
 IndexsearchUtils.createAffectedInfoContainer = function(changedIdValue, changedTable, action, columnsFn, oldValueFn, newValueFn) {
     var res, internalStorage;
-- 
GitLab