All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ml-modules.root.data-hub.data-services.mapping.mappable-entity-lib.mjs Maven / Gradle / Ivy

There is a newer version: 6.1.1
Show newest version
import entityLib from "/data-hub/5/impl/entity-lib.mjs";
import consts from "/data-hub/5/impl/consts.mjs";

const modelArray = fn.collection(entityLib.getModelCollection()).toArray().map(entityModel => {
  return entityModel.toObject();
});
const responseArray = [];

function getEntitiesForUI(targetEntityName) {
  let targetEntityModel = getEntityModel(targetEntityName);
  const entityModelsReferringToTargetEntity = findEntityModelsWithPropertyThatRefersToTargetEntity(targetEntityModel, targetEntityName);

  //Used to avoid cyclical dependencies
  let entitiesNotToExpand = [targetEntityName];
  const targetEntityContext = {
    "entityName": targetEntityName,
    targetEntityName,
    "entityProperties": expandStructuredProperties(targetEntityModel, targetEntityName)
  };

  entitiesNotToExpand = entitiesNotToExpand.concat(entityModelsReferringToTargetEntity.map(entityModel => entityModel.info.title));
  addRelatedMappableEntities(targetEntityContext, entitiesNotToExpand, {"mappingTitle": targetEntityName, "entityType": targetEntityName}, targetEntityName);

  entityModelsReferringToTargetEntity.forEach(entityModel => {
    const entityName = entityModel.info.title;
    const entityContext = {
      "entityName": entityName,
      targetEntityName,
      "entityProperties": expandStructuredProperties(entityModel, entityName)
    };
    addRelatedMappableEntities(entityContext, entitiesNotToExpand, {"entityType": entityName}, entityName, "");
  });
  return responseArray;
}

function addRelatedMappableEntities(entityContext, entitiesNotToExpand, entityResponseObject, propertyPath, pathSoFar) {
  const entityName = entityContext.entityName;
  const targetEntityName = entityContext.targetEntityName;
  const entityProperties = entityContext.entityProperties;

  if (!entityResponseObject.entityType) {
    entityResponseObject.entityType = entityName;
  }
  addMappableEntityToResponse(entityName, entityProperties, entityResponseObject);
  for (let entityPropertyName in entityProperties) {
    let entityPropertyValue = entityProperties[entityPropertyName];
    if (entityPropertyValue["relatedEntityType"] || (entityPropertyValue.items && entityPropertyValue.items["relatedEntityType"])) {
      let relatedEntityType = entityPropertyValue["relatedEntityType"] ? entityPropertyValue["relatedEntityType"] : entityPropertyValue.items["relatedEntityType"];
      let relatedEntityName = relatedEntityType.substring(relatedEntityType.lastIndexOf('/') + 1);
      let joinPropertyName = null;
      if (entityPropertyValue["joinPropertyName"] != "") {
        joinPropertyName = entityPropertyValue["joinPropertyName"] ? entityPropertyValue["joinPropertyName"] : entityPropertyValue.items["joinPropertyName"];
      }
      if (relatedEntityName==targetEntityName) {
        if (joinPropertyName) {
          const targetEntityResponse = responseArray.find(response => response.entityType == targetEntityName);
          if (!entityHasMultipleForeignKey(targetEntityResponse, entityName)) {
            const entityMappingId =  targetEntityName + "." + joinPropertyName + ":" + entityName;
            const mappingTitle = entityName + " (" + entityPropertyName + " "+ relatedEntityName + ")";
            entityResponseObject.entityMappingId = entityMappingId;
            entityResponseObject.mappingTitle = mappingTitle;
            setRelatedEntityMappings(targetEntityResponse, mappingTitle, entityMappingId);
            pathSoFar = targetEntityName + "." + joinPropertyName;
          }
        }
      } else if (!entitiesNotToExpand.includes(relatedEntityName)) {
        propertyPath += "." + entityPropertyName;
        pathSoFar = pathSoFar ?  pathSoFar + ":" + propertyPath : propertyPath;
        let relatedEntityResponseObject = createRelatedEntityResponseObject(entityName, relatedEntityName, entityPropertyName, propertyPath, pathSoFar);
        setRelatedEntityMappings(entityResponseObject, entityPropertyName + " " + relatedEntityName, relatedEntityResponseObject.entityMappingId);
        entitiesNotToExpand.push(relatedEntityName);
        let relatedEntityProperties = expandStructuredProperties(getEntityModel(relatedEntityName), relatedEntityName);
        const entityContext = {
          "entityName": relatedEntityName,
          targetEntityName,
          "entityProperties": relatedEntityProperties
        };
        addRelatedMappableEntities(entityContext, entitiesNotToExpand, relatedEntityResponseObject, relatedEntityName, pathSoFar);
        pathSoFar = pathSoFar.lastIndexOf(":") != -1 ? pathSoFar.substring(0, pathSoFar.lastIndexOf(":")) : pathSoFar;
        propertyPath = propertyPath.lastIndexOf(".") != -1 ? propertyPath.substring(0, propertyPath.lastIndexOf(".")) : propertyPath;
        entitiesNotToExpand.pop();
      }
    }
    if (entityPropertyValue["subProperties"]) {
      const entityContext = {
        entityName,
        targetEntityName,
        "entityProperties": entityPropertyValue["subProperties"]
      };
      addRelatedMappableEntities(entityContext, entitiesNotToExpand, entityResponseObject, propertyPath+ "." + entityPropertyName, pathSoFar);
      propertyPath = propertyPath.lastIndexOf(".") != -1 ? propertyPath.substring(0, propertyPath.lastIndexOf(".")) : propertyPath;
    }
  }
}

function entityHasMultipleForeignKey(targetEntityResponse, entityName) {
  let relatedEntityMapping;
  if (targetEntityResponse.relatedEntityMappings) {
    relatedEntityMapping = targetEntityResponse.relatedEntityMappings.find(relatedEntityMapping => {
      relatedEntityMapping.entityMappingId.substring(relatedEntityMapping.entityMappingId.lastIndexOf(":")) == entityName;
    });
  }
  return relatedEntityMapping ? true : false;
}

function createRelatedEntityResponseObject(entityName, relatedEntityName, entityPropertyName, propertyPath, pathSoFar) {
  let relatedEntityResponseObject ={};
  relatedEntityResponseObject.entityMappingId = pathSoFar + ":"+ relatedEntityName;
  relatedEntityResponseObject.entityType = relatedEntityName;
  relatedEntityResponseObject.mappingTitle = relatedEntityName + " (" + entityName + " " +entityPropertyName + ")";
  return relatedEntityResponseObject;
}

function setRelatedEntityMappings(responseObject, mappingLinkText, entityMappingId) {
  if (responseObject) {
    if (!responseObject.relatedEntityMappings) {
      responseObject.relatedEntityMappings = [];
    }
    responseObject.relatedEntityMappings.push({"mappingLinkText": mappingLinkText, "entityMappingId": entityMappingId});
  }
}

//'entityProperties' have their structured properties expanded by 'expandStructuredProperties' function
function addMappableEntityToResponse(entityName, entityProperties, entityResponseObject) {
  const entityModel = getEntityModel(entityName);
  let expandedEntityModel = Object.assign({}, entityModel);
  if (!entityResponseObject.entityModel) {
    expandedEntityModel.definitions = {};
    expandedEntityModel.definitions[entityName] = {};
    expandedEntityModel.definitions[entityName].properties = entityProperties;
    entityResponseObject.entityModel =  expandedEntityModel;
    responseArray.push(entityResponseObject);
  }
}

function getEntityModel(entityName) {
  const model = modelArray.find(model => model.info.title == entityName);
  if (!model) {
    throw new Error(`Cannot find referenced model: ${entityName}`);
  }
  return model;
}

function expandStructuredProperties(entityModel, entityName) {
  // avoid throwing an error if a structured definition doesn't exist yet
  if (!entityModel.definitions[entityName]) {
    return {};
  }
  let entityProperties = entityModel.definitions[entityName].properties;

  for (let entityPropertyName in entityProperties) {
    let entityPropertyValue = entityProperties[entityPropertyName];
    if (entityPropertyValue["$ref"] || (entityPropertyValue["items"] && entityPropertyValue["items"]["$ref"])) {
      let ref = entityPropertyValue["$ref"] ? entityPropertyValue["$ref"] : entityPropertyValue["items"]["$ref"];
      if (ref.startsWith("#/")) {
        let subEntityName = ref.substring(ref.lastIndexOf('/') + 1);
        entityPropertyValue["subProperties"] = expandStructuredProperties(entityModel, subEntityName);
      } else {
        //Remove external references as they shouldn't show up in mapping
        delete entityProperties[entityPropertyName];
      }
    } else {
      entityProperties[entityPropertyName] = entityPropertyValue;
    }
  }
  return entityProperties;
}


function findEntityModelsWithPropertyThatRefersToTargetEntity(targetEntityModel, targetEntityName) {
  const entityTypeId = entityLib.getEntityTypeId(targetEntityModel, targetEntityName);
  const entityModelsWithPropertyThatRefersToTargetEntity = cts.search(cts.andQuery([cts.collectionQuery(consts.ENTITY_MODEL_COLLECTION),
    cts.jsonPropertyValueQuery("relatedEntityType", entityTypeId, "case-insensitive")]), ["unfiltered", "score-zero", "unfaceted"]).toArray().map(entityModel => {
    return entityModel.toObject();
  });
  return entityModelsWithPropertyThatRefersToTargetEntity;
}

export default {
  getEntitiesForUI,
  findEntityModelsWithPropertyThatRefersToTargetEntity,
  expandStructuredProperties
};




© 2015 - 2024 Weber Informatics LLC | Privacy Policy