UNPKG

generator-pyhipster

Version:

Python (Flask) + Angular/React/Vue in one handy generator

392 lines (358 loc) 14 kB
/** * Copyright 2013-2022 the original author or authors from the JHipster project. * * This file is part of the JHipster project, see https://www.jhipster.tech/ * for more information. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const JDLObject = require('../models/jdl-object'); const JDLEntity = require('../models/jdl-entity'); const JDLField = require('../models/jdl-field'); const JDLValidation = require('../models/jdl-validation'); const JDLEnum = require('../models/jdl-enum'); const JDLRelationship = require('../models/jdl-relationship'); const JDLUnaryOption = require('../models/jdl-unary-option'); const JDLBinaryOption = require('../models/jdl-binary-option'); const { BlobTypes, CommonDBTypes, RelationalOnlyDBTypes } = require('../jhipster/field-types'); const { OptionNames } = require('../jhipster/application-options'); const { ONE_TO_ONE, ONE_TO_MANY, MANY_TO_ONE, MANY_TO_MANY } = require('../jhipster/relationship-types'); const { JPA_DERIVED_IDENTIFIER } = require('../jhipster/relationship-options'); const { FILTER, NO_FLUENT_METHOD, READ_ONLY, EMBEDDED } = require('../jhipster/unary-options'); const { ANGULAR_SUFFIX, CLIENT_ROOT_FOLDER, DTO, MICROSERVICE, PAGINATION, SEARCH, SERVICE } = require('../jhipster/binary-options').Options; const { lowerFirst, upperFirst } = require('../utils/string-utils'); const { ANY, IMAGE, TEXT } = BlobTypes; const { BYTES } = RelationalOnlyDBTypes; module.exports = { convertEntitiesToJDL, }; const USER_ENTITY_NAME = 'User'; const USER_ENTITY = new JDLEntity({ name: USER_ENTITY_NAME }); let entities; let jdlObject; let skippedUserManagement; /** * Convert the passed entities (parsed from JSON files) to a JDL object. * @param {Object} params - an object containing the entities and relevant options. * @param {Map<string, Object>} params.entities - a Map having for keys the entity names and values the JSON entity files. * @param {boolean} params.skippedUserManagement - whether management of the User entity by JHipster is skipped. * @return {JDLObject} the parsed entities in the JDL form. */ function convertEntitiesToJDL(params) { if (!params.entities) { throw new Error('Entities have to be passed to be converted.'); } init(params); addEntities(); addRelationshipsToJDL(); return jdlObject; } function init(params) { entities = params.entities; jdlObject = new JDLObject(); skippedUserManagement = params.skippedUserManagement; } function addEntities() { entities.forEach((entity, entityName) => { addEntity(entity, entityName); }); } function addEntity(entity, entityName) { if (entityName === USER_ENTITY_NAME && !skippedUserManagement) { throw new Error(`User entity name is reserved if ${OptionNames.SKIP_USER_MANAGEMENT} is not set.`); } jdlObject.addEntity(convertJSONToJDLEntity(entity, entityName)); addEnumsToJDL(entity); addEntityOptionsToJDL(entity, entityName); } function convertJSONToJDLEntity(entity, entityName) { const jdlEntity = new JDLEntity({ name: entityName, tableName: entity.entityTableName, comment: entity.javadoc, }); addFields(jdlEntity, entity); return jdlEntity; } function addFields(jdlEntity, entity) { entity.fields.forEach(field => { jdlEntity.addField(convertJSONToJDLField(field)); }); } function convertJSONToJDLField(field) { const jdlField = new JDLField({ name: lowerFirst(field.fieldName), type: field.fieldType, comment: field.javadoc, }); if (jdlField.type === BYTES) { jdlField.type = getTypeForBlob(field.fieldTypeBlobContent); } if (field.fieldValidateRules) { addValidations(jdlField, field); } return jdlField; } function getTypeForBlob(blobContentType) { if ([ANY, IMAGE, TEXT].includes(blobContentType)) { return CommonDBTypes[`${blobContentType.toUpperCase()}_BLOB`]; } throw new Error(`Unrecognised blob type: '${blobContentType}'`); } function addValidations(jdlField, field) { field.fieldValidateRules.forEach(rule => { jdlField.addValidation(convertJSONToJDLValidation(rule, field)); }); } function convertJSONToJDLValidation(rule, field) { return new JDLValidation({ name: rule, value: field[`fieldValidateRules${upperFirst(rule)}`], }); } function addEnumsToJDL(entity) { entity.fields.forEach(field => { if (field.fieldValues !== undefined) { jdlObject.addEnum( new JDLEnum({ name: field.fieldType, values: getEnumValuesFromString(field.fieldValues), comment: field.fieldTypeJavadoc, }) ); } }); } function getEnumValuesFromString(valuesAsString) { return valuesAsString.split(',').map(fieldValue => { // if fieldValue looks like ENUM_VALUE (something) if (fieldValue.includes('(')) { const [key, value] = fieldValue .replace(/^(\w+)\s\((\w+)\)$/, (match, matchedKey, matchedValue) => `${matchedKey},${matchedValue}`) .split(','); return { key, value, }; } return { key: fieldValue }; }); } /* * Adds relationships for entities to JDL. * The jdl passed must contain the jdl entities concerned by the relationships */ function addRelationshipsToJDL() { entities.forEach((entity, entityName) => { dealWithRelationships(entity.relationships, entityName); }); } function dealWithRelationships(relationships, entityName) { if (!relationships) { return; } relationships.forEach(relationship => { const jdlRelationship = getRelationship(relationship, entityName); if (jdlRelationship) { jdlObject.addRelationship(jdlRelationship); } }); } function getRelationship(relationship, entityName) { let relationshipConfiguration = { sourceEntity: null, destinationEntity: null, type: null, injectedFieldInSourceEntity: null, injectedFieldInDestinationEntity: null, injectedFieldInDestinationIsRequired: false, injectedFieldInSourceIsRequired: false, commentForSourceEntity: null, commentForDestinationEntity: null, destinationEntityAsJDLEntity: null, options: {}, }; const sourceEntitySideAttributes = getSourceEntitySideAttributes(entityName, relationship); relationshipConfiguration = { ...relationshipConfiguration, ...sourceEntitySideAttributes, }; relationshipConfiguration.options = getRelationshipOptions(relationship); if (shouldHandleUserEntity(relationship)) { relationshipConfiguration.destinationEntityAsJDLEntity = USER_ENTITY; } else { const destinationEntity = upperFirst(relationship.otherEntityName); relationshipConfiguration.destinationEntity = entities.get(destinationEntity); relationshipConfiguration.destinationEntityAsJDLEntity = jdlObject.getEntity(destinationEntity); if (!relationshipConfiguration.destinationEntity) { return undefined; } const isEntityTheDestinationSideEntity = (otherEntityName, otherEntityRelationshipName) => otherEntityName === entityName && otherEntityRelationshipName === relationship.relationshipName; const destinationSideAttributes = getDestinationEntitySideAttributes( isEntityTheDestinationSideEntity, relationshipConfiguration.destinationEntity.relationships ); relationshipConfiguration = { ...relationshipConfiguration, ...destinationSideAttributes, }; } if (relationship.relationshipType === 'many-to-one') { if (relationshipConfiguration.injectedFieldInDestinationEntity) { // This is a bidirectional relationship so consider it as a OneToMany return getBidirectionalOneToManyRelationship(relationshipConfiguration); } // Unidirectional ManyToOne relationshipConfiguration.type = MANY_TO_ONE; } else if (relationship.relationshipType === 'one-to-one' && relationship.ownerSide === true) { relationshipConfiguration.type = ONE_TO_ONE; } else if (relationship.relationshipType === 'many-to-many' && relationship.ownerSide === true) { relationshipConfiguration.type = MANY_TO_MANY; } if (relationshipConfiguration.type) { return getDefaultRelationship(relationshipConfiguration); } return undefined; } function shouldHandleUserEntity(relationship) { return relationship.otherEntityName.toLowerCase() === USER_ENTITY_NAME.toLowerCase() && !skippedUserManagement; } function getSourceEntitySideAttributes(entityName, relationship) { return { sourceEntity: entityName, injectedFieldInSourceEntity: getInjectedFieldInSourceEntity(relationship), injectedFieldInSourceIsRequired: relationship.relationshipValidateRules, commentForSourceEntity: relationship.javadoc, }; } function getDestinationEntitySideAttributes(isEntityTheDestinationSideEntity, destinationEntityRelationships) { const foundDestinationSideEntity = destinationEntityRelationships.find(destinationEntityFromRelationship => { return isEntityTheDestinationSideEntity( upperFirst(destinationEntityFromRelationship.otherEntityName), destinationEntityFromRelationship.otherEntityRelationshipName ); }); if (!foundDestinationSideEntity) { return {}; } // Bidirectional relationship let injectedFieldInDestinationEntity = foundDestinationSideEntity.relationshipName; if (!!foundDestinationSideEntity.otherEntityField && foundDestinationSideEntity.otherEntityField !== 'id') { injectedFieldInDestinationEntity += `(${foundDestinationSideEntity.otherEntityField})`; } const injectedFieldInDestinationIsRequired = !!foundDestinationSideEntity.relationshipValidateRules; const commentForDestinationEntity = foundDestinationSideEntity.javadoc; return { injectedFieldInDestinationEntity, injectedFieldInDestinationIsRequired, commentForDestinationEntity, }; } function getRelationshipOptions(relationship) { const options = relationship.options || { global: {}, source: {}, destination: {}, }; if (relationship.useJPADerivedIdentifier) { options[JPA_DERIVED_IDENTIFIER] = true; } return options; } function getDefaultRelationship(relationshipConfiguration) { return new JDLRelationship({ from: relationshipConfiguration.sourceEntity, to: relationshipConfiguration.destinationEntityAsJDLEntity.name, type: relationshipConfiguration.type, injectedFieldInFrom: relationshipConfiguration.injectedFieldInSourceEntity, injectedFieldInTo: relationshipConfiguration.injectedFieldInDestinationEntity, isInjectedFieldInFromRequired: relationshipConfiguration.injectedFieldInSourceIsRequired, isInjectedFieldInToRequired: relationshipConfiguration.injectedFieldInDestinationIsRequired, commentInFrom: relationshipConfiguration.commentForSourceEntity, commentInTo: relationshipConfiguration.commentForDestinationEntity, options: relationshipConfiguration.options, }); } // Based on a ManyToOne relationship, we determine the OneToMany relationship. function getBidirectionalOneToManyRelationship(relationshipConfiguration) { return new JDLRelationship({ from: relationshipConfiguration.destinationEntityAsJDLEntity.name, to: relationshipConfiguration.sourceEntity, type: ONE_TO_MANY, injectedFieldInFrom: relationshipConfiguration.injectedFieldInDestinationEntity, injectedFieldInTo: relationshipConfiguration.injectedFieldInSourceEntity, isInjectedFieldInFromRequired: relationshipConfiguration.injectedFieldInDestinationIsRequired, isInjectedFieldInToRequired: relationshipConfiguration.injectedFieldInSourceIsRequired, commentInFrom: relationshipConfiguration.commentForDestinationEntity, commentInTo: relationshipConfiguration.commentForSourceEntity, options: relationshipConfiguration.options, }); } function getInjectedFieldInSourceEntity(relationship) { return ( relationship.relationshipName + (relationship.otherEntityField && relationship.otherEntityField !== 'id' ? `(${relationship.otherEntityField})` : '') ); } function addEntityOptionsToJDL(entity, entityName) { if (entity.fluentMethods === false) { addUnaryOptionToJDL(NO_FLUENT_METHOD, entityName); } [DTO, PAGINATION, SERVICE].forEach(option => { if (entity[option] && entity[option] !== 'no') { addBinaryOptionToJDL(option, entity[option], entityName); } }); if (entity.searchEngine) { addBinaryOptionToJDL(SEARCH, entity.searchEngine, entityName); } // angularSuffix in BinaryOptions, angularJSSuffix in Json if (entity.angularJSSuffix) { addBinaryOptionToJDL(ANGULAR_SUFFIX, entity.angularJSSuffix, entityName); } // microservice in BinaryOptions, microserviceName in Json if (entity.microserviceName !== undefined) { addBinaryOptionToJDL(MICROSERVICE, entity.microserviceName, entityName); } if (entity.jpaMetamodelFiltering === true) { addUnaryOptionToJDL(FILTER, entityName); } if (entity.readOnly === true) { addUnaryOptionToJDL(READ_ONLY, entityName); } if (entity.embedded === true) { addUnaryOptionToJDL(EMBEDDED, entityName); } if (entity.clientRootFolder) { addBinaryOptionToJDL(CLIENT_ROOT_FOLDER, entity.clientRootFolder, entityName); } } function addUnaryOptionToJDL(unaryOption, entityName) { jdlObject.addOption( new JDLUnaryOption({ name: unaryOption, entityNames: [entityName], }) ); } function addBinaryOptionToJDL(binaryOption, value, entityName) { jdlObject.addOption( new JDLBinaryOption({ name: binaryOption, value, entityNames: [entityName], }) ); }