Name

sn_mab_api.ConfigSortingService

Description

No description available

Script

var ConfigSortingService = Class.create();
ConfigSortingService.prototype = {
  initialize: function() {
      this.validationHandler = new sn_mab_api.ValidationHandler();
      this.errorHandler = new sn_mab_api.ErrorHandler();
  },

  sortNodes: function(inputData) {
      var sortedNodes = [];
      var nodesMap = this.parseNodes(inputData);
      this.connectNodes(nodesMap);

      var foundGraph;
      //Try to extract all the different graphs from our nodes one at a time
      do {
          foundGraph = false;
          var extractedGraph = this.extractGraph(nodesMap);
          if (extractedGraph && Object.keys(extractedGraph).length) {
              foundGraph = true;
              sortedNodes = this.concatArray(sortedNodes, this.sortGraphTopographicalOrder(extractedGraph));
          }
      } while(foundGraph);

      //Sanity check, we should have cleared out all our nodes or found a cycle and thrown an error
      if (Object.keys(nodesMap).length)
          this.errorHandler.throwInternalError('Error - Remaining nodes after sorting');

      //cleanup
      sortedNodes.forEach(function(currNode) {
          delete currNode.children;
          delete currNode.parents;
          delete currNode.tempMarked;
          delete currNode.marked;
      });

      return sortedNodes;
  },

  parseNodes: function(inputData) {
      var outputNodesMap = {};

      if (!inputData || !Object.keys(inputData).length)
          return outputNodesMap;

      //Flatten structure and create a map of sysId to nodes
      for (var currTableName in inputData) {
          for (var currSysId in inputData[currTableName]) {
              var outputNode = {'tableName': currTableName, 'sysId': currSysId, 'fields': inputData[currTableName][currSysId], 'children': [], 'parents': []};
              outputNodesMap[currSysId] = outputNode;
          }
      }

      return outputNodesMap;
  },

  connectNodes: function(nodes) {
      //Connect all nodes just by comparing sysIds, sysIds should be unique across all tables/rows
      for (var currNodeSysId in nodes) {
          var currNode = nodes[currNodeSysId];
          //loop through all nodes fields for any value which can represent a sysId
          for (var currFieldName in currNode.fields) {
              var possibleSysId = currNode.fields[currFieldName];
              //Does our curr field contain something like a sysId and does this sysId exist in our nodes?
              if (!this.validationHandler.isGeneratedOrNormalSysId(possibleSysId) || !nodes[possibleSysId])
                  continue;

              // if update node contains its sys_id dont connect as child or parent
              if (currNodeSysId === possibleSysId)
                  continue;

              currNode.children.push(possibleSysId);
              nodes[possibleSysId].parents.push(currNodeSysId);
          }
      }
  },

  extractGraph: function(nodesMap) {
      var nodesMapKeys = Object.keys(nodesMap);
      //Anything left to extract?
      if (!nodesMapKeys.length)
          return null;

      //If so grab the first one and follow it to extract out the graph connected to it
      var extractedGraphNodes = {};
      this.extractGraphNodes(nodesMapKeys[0], nodesMap, extractedGraphNodes);
      return extractedGraphNodes;
  },

  extractGraphNodes: function(currNodeSysId, allNodes, graphNodes) {
      //Does currNode exist?
      if (!allNodes[currNodeSysId])
          return;

      //Add ourselves to the output and delete from original node list
      var currNode = allNodes[currNodeSysId];
      graphNodes[currNodeSysId] = currNode;
      delete allNodes[currNodeSysId];

      //Process children and parent nodes
      currNode.children.forEach(function(currChildSysId){
          this.extractGraphNodes(currChildSysId, allNodes, graphNodes);
      }, this);
      currNode.parents.forEach(function(currParentSysId){
          this.extractGraphNodes(currParentSysId, allNodes, graphNodes);
      }, this);
  },

  //Topographical sort algorithm based on depth first search
  sortGraphTopographicalOrder: function(graphNodes) {
      var sortedNodes = [];
      var foundUnMarkedNode;
      do {
          foundUnMarkedNode = false;
          for(var currNodeSysId in graphNodes) {
              if (graphNodes[currNodeSysId].marked)
                  continue;

              foundUnMarkedNode = true;
              this.visitNode(graphNodes[currNodeSysId], graphNodes, sortedNodes);
          }
      } while(foundUnMarkedNode);

      return sortedNodes;
  },

  visitNode: function(node, graphNodes, sortedNodes) {
      if (!node || node.marked)
          return;

      if (node.tempMarked)
          this.errorHandler.throwBadRequestError('Error - Cycle found in nodes, cannot sort');

      node.tempMarked = true;

      node.children.forEach(function(currChildSysId){
          this.visitNode(graphNodes[currChildSysId], graphNodes, sortedNodes);
      }, this);

      node.tempMarked = false;
      node.marked = true;

      sortedNodes.push(node);
  },

  concatArray: function(first, second) {
      var outputArray = [];
      if (first)
          outputArray = first;

      if (second)
          second.forEach(function(currValue) {
              outputArray.push(currValue);
          });

      return outputArray;
  },

  type: 'ConfigSortingService'
};

Sys ID

72f75af353232010c722ddeeff7b126b

Offical Documentation

Official Docs: