genie-uml
Version:
UML support for JHipster via XMI files
405 lines (379 loc) • 15.9 kB
JavaScript
const chalk = require('chalk'),
_ = require('lodash'),
merge = require('./utils/object_utils').merge,
isNoSQL = require('./types/types_helper').isNoSQL,
checkValidityOfAssociation = require('./helpers/association_helper').checkValidityOfAssociation,
cardinalities = require('./cardinalities'),
formatComment = require('./helpers/comment_helper').formatComment,
readJSONFiles = require('./utils/jhipster_utils').readJSONFiles,
buildException = require('./exceptions/exception_factory').buildException,
exceptions = require('./exceptions/exception_factory').exceptions;
const USER = 'user';
var entitiesToSuppress;
var listDTO;
var listPagination;
var listService;
var microserviceNames;
var entities;
var onDiskEntities;
var searchEngines;
var databaseTypes;
var parsedData;
var noUserManagement;
module.exports = {
/**
* Keys of args:
* - listDTO,
* - listPagination,
* - listService,
* - microserviceNames,
* - searchEngines.
*/
createEntities: createEntities
};
function createEntities(parsedData, databaseTypes, options) {
var merged = merge(defaults(), options);
if (!parsedData || !databaseTypes) {
throw new buildException(
exceptions.NullPointer,
'The parsed data and database types are mandatory.');
}
init(merged, parsedData, databaseTypes);
checkNoSQLModeling();
onDiskEntities = readJSONFiles(parsedData.classNames);
initializeEntities();
fillEntities();
return entities;
}
function init(args, passedParsedData, passedDatabaseTypes) {
entitiesToSuppress = [];
listDTO = args.listDTO;
listPagination = args.listPagination;
listService = args.listService;
microserviceNames = args.microserviceNames;
searchEngines = args.searchEngines;
databaseTypes = passedDatabaseTypes;
parsedData = passedParsedData;
entities = {};
onDiskEntities = {};
noUserManagement = args.noUserManagement;
}
function checkNoSQLModeling() {
if (isNoSQL(databaseTypes) && Object.keys(parsedData.associations).length !== 0) {
throw new buildException(
exceptions.NoSQLModeling, "NoSQL entities don't have relationships.");
}
}
function initializeEntities() {
var index = 0;
for (let classId in parsedData.classes) {
if (parsedData.classes.hasOwnProperty(classId)) {
let initializedEntity = {
fluentMethods: true,
relationships: [],
fields: [],
changelogDate: getChangelogDate(classId, index),
dto: parsedData.getClass(classId).dto,
pagination: parsedData.getClass(classId).pagination,
service: parsedData.getClass(classId).service,
microserviceName: parsedData.getClass(classId).microserviceName,
searchEngine: parsedData.getClass(classId).searchEngine,
javadoc: formatComment(parsedData.getClass(classId).comment),
entityTableName: _.snakeCase(parsedData.getClass(classId).tableName)
};
initializedEntity =
setOptions(initializedEntity, parsedData.getClass(classId).name);
entities[classId] = initializedEntity;
index++;
}
}
}
function getChangelogDate(classId, increment) {
if (onDiskEntities[parsedData.getClass(classId).name]) {
return onDiskEntities[parsedData.getClass(classId).name].changelogDate;
}
return dateFormatForLiquibase(increment);
}
function dateFormatForLiquibase(increment) {
var now = new Date();
var now_utc = new Date(
now.getUTCFullYear(),
now.getUTCMonth(),
now.getUTCDate(),
now.getUTCHours(),
now.getUTCMinutes(),
now.getUTCSeconds());
var year = '' + now_utc.getFullYear();
var month = '' + (now_utc.getMonth() + 1);
if (month.length === 1) {
month = `0${month}`;
}
var day = '' + now_utc.getDate();
if (day.length === 1) {
day = `0${day}`;
}
var hour = '' + now_utc.getHours();
if (hour.length === 1) {
hour = `0${hour}`;
}
var minute = '' + now_utc.getMinutes();
if (minute.length === 1) {
minute = `0${minute}`;
}
var second = '' + (now_utc.getSeconds() + increment) % 60;
if (second.length === 1) {
second = `0${second}`;
}
return `${year}${month}${day}${hour}${minute}${second}`;
}
function setOptions(entity, entityName) {
if (listDTO.hasOwnProperty(entityName)) {
entity.dto = listDTO[entityName];
}
if (listPagination.hasOwnProperty(entityName)) {
entity.pagination = listPagination[entityName];
}
if (listService.hasOwnProperty(entityName)) {
entity.service = listService[entityName];
}
if (microserviceNames.hasOwnProperty(entityName)) {
entity.microserviceName = microserviceNames[entityName];
}
if (searchEngines.hasOwnProperty(entityName)) {
entity.searchEngine = searchEngines[entityName];
}
return entity;
}
function defaults() {
return {
listDTO: [],
listPagination: {},
listService: {},
microserviceNames: {},
searchEngines: []
};
}
function fillEntities() {
for (let classId in parsedData.classes) {
/*
* If the user adds a 'User' entity we consider it as the already
* created JHipster User entity and none of its fields and ownerside
* relationships will be considered.
*/
if (parsedData.getClass(classId).name.toLowerCase() === USER && !noUserManagement) {
console.warn(
chalk.yellow(
"Warning: An Entity called 'User' was defined: 'User' is an" +
' entity created by default by JHipster. All relationships toward' +
' it will be kept but all attributes and relationships from it' +
' will be disregarded.'));
entitiesToSuppress.push(classId);
}
setFieldsOfEntity(classId);
setRelationshipOfEntity(classId);
}
for (let entity in entitiesToSuppress) {
delete entities[entity];
}
}
function setFieldsOfEntity(classId) {
for (let i = 0; i < parsedData.classes[classId].fields.length; i++) {
let fieldId = parsedData.classes[classId].fields[i];
let fieldData = {
fieldName: _.camelCase(parsedData.getField(fieldId).name)
};
let comment = formatComment(parsedData.getField(fieldId).comment);
if (comment) {
fieldData.comment = comment;
}
if (parsedData.types[parsedData.getField(fieldId).type]) {
fieldData.fieldType = parsedData.getType(parsedData.getField(fieldId).type).name;
} else if (parsedData.getEnum(parsedData.getField(fieldId).type)) {
fieldData.fieldType = parsedData.getEnum(parsedData.getField(fieldId).type).name;
fieldData.fieldValues = parsedData.getEnum(parsedData.getField(fieldId).type).values.join(',');
}
switch (fieldData.fieldType) {
case 'Blob':
case 'AnyBlob':
fieldData.fieldType = 'byte[]';
fieldData.fieldTypeBlobContent = 'any';
break;
case 'ImageBlob':
fieldData.fieldType = 'byte[]';
fieldData.fieldTypeBlobContent = 'image';
break;
case 'TextBlob':
fieldData.fieldType = 'byte[]';
fieldData.fieldTypeBlobContent = 'text';
break;
default:
}
setValidationsOfField(fieldData, fieldId);
entities[classId].fields.push(fieldData);
}
}
function setValidationsOfField(field, fieldId) {
if (parsedData.getField(fieldId).validations.length === 0) {
return;
}
field.fieldValidateRules = [];
for (let i = 0; i < parsedData.getField(fieldId).validations.length; i++) {
let validation = parsedData.getValidation(parsedData.getField(fieldId).validations[i]);
field.fieldValidateRules.push(validation.name);
if (validation.name !== 'required') {
field['fieldValidateRules' + _.capitalize(validation.name)] =
validation.value;
}
}
}
function getRelatedAssociations(classId, associations) {
var relationships = {
from: [],
to: []
};
for (let associationId in associations) {
let association = associations[associationId];
if (association.from === classId) {
relationships.from.push(associationId);
}
if (association.to === classId && association.injectedFieldInTo) {
relationships.to.push(associationId);
}
}
return relationships;
}
/**
* Parses the string "<relationshipName>(<otherEntityField>)"
* @param{String} field
* @return{Object} where 'relationshipName' is the relationship name and
* 'otherEntityField' is the other entity field name
*/
function extractField(field) {
var splitField = {
otherEntityField: 'id', // id by default
relationshipName: ''
};
if (field) {
var chunks = field.replace('(', '/').replace(')', '').split('/');
splitField.relationshipName = chunks[0];
if (chunks.length > 1) {
splitField.otherEntityField = chunks[1];
}
}
return splitField;
}
function setRelationshipOfEntity(classId) {
var relatedAssociations = getRelatedAssociations(
classId,
parsedData.associations);
setSourceAssociationsForClass(relatedAssociations, classId);
setDestinationAssociationsForClass(relatedAssociations, classId);
}
function setSourceAssociationsForClass(relatedAssociations, classId) {
for (let i = 0; i < relatedAssociations.from.length; i++) {
let otherSplitField;
let splitField;
let association = parsedData.getAssociation(relatedAssociations.from[i]);
checkValidityOfAssociation(
association,
parsedData.getClass(association.from).name,
parsedData.getClass(association.to).name);
let relationship = {
relationshipType: association.type
};
if (association.isInjectedFieldInToRequired && association.type === cardinalities.ONE_TO_MANY) {
console.warn(
chalk.yellow(
`From ${parsedData.getClass(association.from).name} to ${parsedData.getClass(association.to).name}, a One-to-Many exists and the Many side can't be required. Removing the required flag.`));
association.isInjectedFieldInToRequired = false;
}
if (association.isInjectedFieldInFromRequired && association.type === cardinalities.MANY_TO_ONE) {
console.warn(
chalk.yellow(
`From ${parsedData.getClass(association.from).name} to ${parsedData.getClass(association.to).name}, a Many-to-One exists and the Many side can't be required. Removing the required flag.`));
association.isInjectedFieldInFromRequired = false;
}
if (association.isInjectedFieldInFromRequired) {
relationship.relationshipValidateRules = 'required';
}
if (association.type === cardinalities.ONE_TO_ONE) {
splitField = extractField(association.injectedFieldInFrom);
relationship.relationshipName = _.camelCase(splitField.relationshipName);
relationship.otherEntityName = _.lowerFirst(_.camelCase(parsedData.getClass(association.to).name));
relationship.otherEntityField = _.lowerFirst(splitField.otherEntityField);
relationship.ownerSide = true;
relationship.otherEntityRelationshipName = _.lowerFirst(association.injectedFieldInTo || parsedData.getClass(association.from).name);
} else if (association.type === cardinalities.ONE_TO_MANY) {
splitField = extractField(association.injectedFieldInFrom);
otherSplitField = extractField(association.injectedFieldInTo);
relationship.relationshipName = _.lowerFirst(_.camelCase(splitField.relationshipName || parsedData.getClass(association.to).name));
relationship.otherEntityName = _.lowerFirst(_.camelCase(parsedData.getClass(association.to).name));
relationship.otherEntityRelationshipName = _.lowerFirst(otherSplitField.relationshipName);
if (!association.injectedFieldInTo) {
relationship.otherEntityRelationshipName = _.lowerFirst(parsedData.getClass(association.from).name);
otherSplitField = extractField(association.injectedFieldInTo);
let otherSideRelationship = {
relationshipName: _.camelCase(_.lowerFirst(parsedData.getClass(association.from).name)),
otherEntityName: _.lowerFirst(_.camelCase(parsedData.getClass(association.from).name)),
relationshipType: cardinalities.MANY_TO_ONE,
otherEntityField: _.lowerFirst(otherSplitField.otherEntityField)
};
association.type = cardinalities.MANY_TO_ONE;
entities[association.to].relationships.push(otherSideRelationship);
}
} else if (association.type === cardinalities.MANY_TO_ONE && association.injectedFieldInFrom) {
splitField = extractField(association.injectedFieldInFrom);
relationship.relationshipName = _.camelCase(splitField.relationshipName);
relationship.otherEntityName = _.lowerFirst(_.camelCase(parsedData.getClass(association.to).name));
relationship.otherEntityField = _.lowerFirst(splitField.otherEntityField);
} else if (association.type === cardinalities.MANY_TO_MANY) {
splitField = extractField(association.injectedFieldInFrom);
relationship.otherEntityRelationshipName = _.lowerFirst(extractField(association.injectedFieldInTo).relationshipName);
relationship.relationshipName = _.camelCase(splitField.relationshipName);
relationship.otherEntityName = _.lowerFirst(_.camelCase(parsedData.getClass(association.to).name));
relationship.otherEntityField = _.lowerFirst(splitField.otherEntityField);
relationship.ownerSide = true;
}
entities[classId].relationships.push(relationship);
}
}
function setDestinationAssociationsForClass(relatedAssociations, classId) {
for (let i = 0; i < relatedAssociations.to.length; i++) {
let splitField;
let otherSplitField;
let association = parsedData.getAssociation(relatedAssociations.to[i]);
let relationship = {
relationshipType: (association.type === cardinalities.ONE_TO_MANY ? cardinalities.MANY_TO_ONE : association.type)
};
if (association.isInjectedFieldInToRequired) {
relationship.relationshipValidateRules = 'required';
}
if (association.type === cardinalities.ONE_TO_ONE) {
splitField = extractField(association.injectedFieldInTo);
otherSplitField = extractField(association.injectedFieldInFrom);
relationship.relationshipName = _.camelCase(splitField.relationshipName);
relationship.otherEntityName = _.lowerFirst(_.camelCase(parsedData.getClass(association.from).name));
relationship.ownerSide = false;
relationship.otherEntityRelationshipName = _.lowerFirst(otherSplitField.relationshipName);
} else if (association.type === cardinalities.ONE_TO_MANY) {
association.injectedFieldInTo = association.injectedFieldInTo || _.lowerFirst(association.from);
splitField = extractField(association.injectedFieldInTo);
relationship.relationshipName = _.lowerFirst(_.camelCase(splitField.relationshipName || parsedData.getClass(association.from).name));
relationship.otherEntityName = _.lowerFirst(_.camelCase(parsedData.getClass(association.from).name));
relationship.otherEntityField = _.lowerFirst(splitField.otherEntityField);
} else if (association.type === cardinalities.MANY_TO_ONE && association.injectedFieldInTo) {
splitField = extractField(association.injectedFieldInTo);
relationship.relationshipName = _.camelCase(splitField.relationshipName);
relationship.otherEntityName = _.lowerFirst(_.camelCase(parsedData.getClass(association.from).name));
relationship.otherEntityField = _.lowerFirst(splitField.otherEntityField);
} else if (association.type === cardinalities.MANY_TO_MANY) {
splitField = extractField(association.injectedFieldInTo);
relationship.relationshipName = _.camelCase(splitField.relationshipName);
relationship.otherEntityName = _.lowerFirst(_.camelCase(parsedData.getClass(association.from).name));
relationship.ownerSide = false;
relationship.otherEntityRelationshipName = _.lowerFirst(extractField(association.injectedFieldInFrom).relationshipName);
}
entities[classId].relationships.push(relationship);
}
}
;