UNPKG

gen-jhipster

Version:

Spring Boot + Angular/React/Vue in one handy generator

618 lines (617 loc) 31.3 kB
/** * Copyright 2013-2024 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. */ import { camelCase, intersection, kebabCase, lowerFirst, snakeCase, sortedUniq, startCase, uniq, upperFirst } from 'lodash-es'; import pluralize from 'pluralize'; import { getDatabaseTypeData, hibernateSnakeCase } from '../../server/support/index.js'; import { createFaker, getMicroserviceAppName, mutateData, parseChangelog, stringHashCode, upperFirstCamelCase, } from '../../base/support/index.js'; import { getEntityParentPathAddition, getTypescriptKeyType } from '../../client/support/index.js'; import { applicationTypes, databaseTypes, entityOptions, fieldTypes, searchEngineTypes } from '../../../lib/jhipster/index.js'; import { binaryOptions } from '../../../lib/jdl/core/built-in-options/index.js'; import { fieldToReference } from './prepare-field.js'; import { fieldIsEnum } from './field-utils.js'; const NO_SEARCH_ENGINE = searchEngineTypes.NO; const { MapperTypes } = entityOptions; const { GATEWAY, MICROSERVICE } = applicationTypes; const { CommonDBTypes } = fieldTypes; const { BOOLEAN, LONG, UUID, INTEGER } = CommonDBTypes; const { NO: NO_DTO } = MapperTypes; const NO_MAPPER = MapperTypes.NO; const { CASSANDRA, COUCHBASE, NEO4J, SQL, MONGODB } = databaseTypes; const { INSTANT, ZONED_DATE_TIME, DURATION, LOCAL_DATE, BIG_DECIMAL, STRING } = fieldTypes.CommonDBTypes; const { BYTES, BYTE_BUFFER } = fieldTypes.RelationalOnlyDBTypes; const { IMAGE, TEXT } = fieldTypes.BlobTypes; const BASE_TEMPLATE_DATA = { primaryKey: undefined, entityPackage: undefined, skipUiGrouping: false, anyFieldHasDocumentation: false, existingEnum: false, searchEngine: NO_SEARCH_ENGINE, microserviceName: undefined, entityAuthority: undefined, entityReadAuthority: undefined, adminEntity: undefined, builtInUserManagement: undefined, requiresPersistableImplementation: false, updatableEntity: undefined, anyFieldIsDateDerived: false, anyFieldIsTimeDerived: false, anyFieldIsInstant: false, anyFieldIsUUID: false, anyFieldIsZonedDateTime: false, anyFieldIsDuration: false, anyFieldIsLocalDate: false, anyFieldIsBigDecimal: false, anyFieldIsBlobDerived: false, anyFieldHasImageContentType: false, anyFieldHasTextContentType: false, anyFieldHasFileBasedContentType: false, anyPropertyHasValidation: false, fieldsContainNoOwnerOneToOne: false, get otherRelationships() { return []; }, get enums() { return []; }, // these variable hold field and relationship names for question options during update get fieldNameChoices() { return []; }, get differentRelationships() { return {}; }, }; function _derivedProperties(entityWithConfig) { const pagination = entityWithConfig.pagination; const dto = entityWithConfig.dto; const service = entityWithConfig.service; mutateData(entityWithConfig, { paginationPagination: pagination === 'pagination', paginationInfiniteScroll: pagination === 'infinite-scroll', paginationNo: pagination === 'no', dtoMapstruct: dto === 'mapstruct' || dto === 'any', dtoAny: dto && dto !== 'no', serviceClass: service === 'serviceClass', serviceImpl: service === 'serviceImpl', serviceNo: service === 'no', }); } export const entityDefaultConfig = { pagination: binaryOptions.DefaultValues[binaryOptions.Options.PAGINATION], anyPropertyHasValidation: false, dto: binaryOptions.DefaultValues[binaryOptions.Options.DTO], service: binaryOptions.DefaultValues[binaryOptions.Options.SERVICE], jpaMetamodelFiltering: false, readOnly: false, embedded: false, entityAngularJSSuffix: '', fluentMethods: true, clientRootFolder: '', get fields() { return []; }, get relationships() { return []; }, }; export default function prepareEntity(entityWithConfig, generator, application) { const { applicationTypeMicroservice, microfrontend } = application; const entityName = upperFirst(entityWithConfig.name); const entitySuffix = entityWithConfig.entitySuffix ?? application.entitySuffix; mutateData(entityWithConfig, entityDefaultConfig, BASE_TEMPLATE_DATA); if (entityWithConfig.changelogDate) { try { entityWithConfig.changelogDateForRecent = parseChangelog(String(entityWithConfig.changelogDate)); } catch (error) { throw new Error(`Error parsing changelog date for entity ${entityName}: ${error.message}`, { cause: error }); } } entityWithConfig.entityAngularJSSuffix = entityWithConfig.angularJSSuffix; if (entityWithConfig.entityAngularJSSuffix && !entityWithConfig.entityAngularJSSuffix.startsWith('-')) { entityWithConfig.entityAngularJSSuffix = `-${entityWithConfig.entityAngularJSSuffix}`; } entityWithConfig.useMicroserviceJson = entityWithConfig.useMicroserviceJson || entityWithConfig.microserviceName !== undefined; entityWithConfig.microserviceAppName = ''; if (generator.jhipsterConfig.applicationType === GATEWAY && entityWithConfig.useMicroserviceJson) { if (!entityWithConfig.microserviceName) { throw new Error('Microservice name for the entity is not found. Entity cannot be generated!'); } entityWithConfig.microserviceAppName = getMicroserviceAppName({ microserviceName: entityWithConfig.microserviceName }); entityWithConfig.skipServer = true; } mutateData(entityWithConfig, { entityNameCapitalized: entityName, entityClass: upperFirst(entityName), entityInstance: lowerFirst(entityName), entityTableName: hibernateSnakeCase(entityName), entityNamePlural: pluralize(entityName), entityAuthority: entityWithConfig.adminEntity ? 'ROLE_ADMIN' : undefined, entityUnderscoredName: snakeCase(entityName).toLowerCase(), }); mutateData(entityWithConfig, { persistClass: `${entityWithConfig.entityClass}${entitySuffix ?? ''}`, persistInstance: `${entityWithConfig.entityInstance}${entitySuffix ?? ''}`, }); const dto = entityWithConfig.dto && entityWithConfig.dto !== NO_DTO; if (dto) { const { dtoSuffix = '' } = application; mutateData(entityWithConfig, { dtoClass: `${entityWithConfig.entityClass}${dtoSuffix}`, dtoInstance: `${entityWithConfig.entityInstance}${dtoSuffix}`, restClass: ({ dtoClass }) => dtoClass, restInstance: ({ dtoInstance }) => dtoInstance, }); } else { mutateData(entityWithConfig, { restClass: ({ persistClass }) => persistClass, restInstance: ({ persistInstance }) => persistInstance, }); } mutateData(entityWithConfig, { entityNamePluralizedAndSpinalCased: kebabCase(entityWithConfig.entityNamePlural), entityClassPlural: upperFirst(entityWithConfig.entityNamePlural), entityInstancePlural: lowerFirst(entityWithConfig.entityNamePlural), }); mutateData(entityWithConfig, { // Implement i18n variant ex: 'male', 'female' when applied entityI18nVariant: 'default', entityClassHumanized: startCase(entityWithConfig.entityNameCapitalized), entityClassPluralHumanized: startCase(entityWithConfig.entityClassPlural), }); mutateData(entityWithConfig, { __override__: false, entityFileName: data => kebabCase(data.entityNameCapitalized + upperFirst(data.entityAngularJSSuffix)), entityAngularName: data => data.entityClass + upperFirstCamelCase(entityWithConfig.entityAngularJSSuffix), entityAngularNamePlural: data => pluralize(data.entityAngularName), entityApiUrl: data => data.entityNamePluralizedAndSpinalCased, }); entityWithConfig.entityFolderName = entityWithConfig.clientRootFolder ? `${entityWithConfig.clientRootFolder}/${entityWithConfig.entityFileName}` : entityWithConfig.entityFileName; entityWithConfig.entityModelFileName = entityWithConfig.entityFolderName; entityWithConfig.entityParentPathAddition = getEntityParentPathAddition(entityWithConfig.clientRootFolder); entityWithConfig.entityPluralFileName = entityWithConfig.entityNamePluralizedAndSpinalCased + entityWithConfig.entityAngularJSSuffix; entityWithConfig.entityServiceFileName = entityWithConfig.entityFileName; entityWithConfig.entityReactName = entityWithConfig.entityClass + upperFirstCamelCase(entityWithConfig.entityAngularJSSuffix); entityWithConfig.entityStateName = kebabCase(entityWithConfig.entityAngularName); entityWithConfig.entityUrl = entityWithConfig.entityStateName; entityWithConfig.entityTranslationKey = entityWithConfig.clientRootFolder ? camelCase(`${entityWithConfig.clientRootFolder}-${entityWithConfig.entityInstance}`) : entityWithConfig.entityInstance; entityWithConfig.entityTranslationKeyMenu = camelCase(entityWithConfig.clientRootFolder ? `${entityWithConfig.clientRootFolder}-${entityWithConfig.entityStateName}` : entityWithConfig.entityStateName); mutateData(entityWithConfig, { __override__: false, i18nKeyPrefix: data => data.i18nKeyPrefix ?? `${application.frontendAppName}.${data.entityTranslationKey}`, i18nAlertHeaderPrefix: data => (data.i18nAlertHeaderPrefix ?? data.microserviceAppName) ? `${data.microserviceAppName}.${data.entityTranslationKey}` : data.i18nKeyPrefix, hasRelationshipWithBuiltInUser: ({ relationships }) => relationships.some(relationship => relationship.otherEntity.builtInUser), saveUserSnapshot: ({ hasRelationshipWithBuiltInUser, dto }) => applicationTypeMicroservice && application.authenticationTypeOauth2 && hasRelationshipWithBuiltInUser && dto === NO_MAPPER, entityApi: ({ microserviceName }) => (microserviceName ? `services/${microserviceName.toLowerCase()}/` : ''), entityPage: ({ microserviceName, entityFileName }) => microserviceName && microfrontend && applicationTypeMicroservice ? `${microserviceName.toLowerCase()}/${entityFileName}` : `${entityFileName}`, }); entityWithConfig.generateFakeData = type => { const fieldsToGenerate = type === 'cypress' ? entityWithConfig.fields.filter(field => !field.id || !field.autoGenerate) : entityWithConfig.fields; const fieldEntries = fieldsToGenerate .map(field => { const fieldData = field.generateFakeData(type); if (!field.nullable && fieldData === null) return undefined; return [field.fieldName, fieldData]; }) .filter(Boolean); const withError = fieldEntries.find(entry => !entry); if (withError) { generator.log.warn(`Error generating a full sample for entity ${entityName}`); return undefined; } return Object.fromEntries(fieldEntries); }; _derivedProperties(entityWithConfig); return entityWithConfig; } export function derivedPrimaryKeyProperties(primaryKey) { mutateData(primaryKey, { hasUUID: primaryKey.fields?.some(field => field.fieldType === UUID), hasLong: primaryKey.fields?.some(field => field.fieldType === LONG), hasInteger: primaryKey.fields?.some(field => field.fieldType === INTEGER), typeUUID: primaryKey.type === UUID, typeString: primaryKey.type === STRING, typeLong: primaryKey.type === LONG, typeInteger: primaryKey.type === INTEGER, typeNumeric: !primaryKey.composite && primaryKey.fields[0].fieldTypeNumeric, }); } export function prepareEntityPrimaryKeyForTemplates({ entity: entityWithConfig, enableCompositeId = true, application }) { const idFields = entityWithConfig.fields.filter(field => field.id); const idRelationships = entityWithConfig.relationships.filter(relationship => relationship.id); let idCount = idFields.length + idRelationships.length; if (idCount === 0) { let idField = entityWithConfig.fields.find(field => field.fieldName === 'id'); if (idField) { idField.id = true; idField.autoGenerate = idField.autoGenerate ?? true; } else { if (entityWithConfig.microserviceName && !application?.microfrontend) { this?.log.warn("Microservice entities should have the id field type specified (e.g., id String) to make sure gateway and microservice types don't conflict"); } idField = { fieldName: 'id', id: true, fieldNameHumanized: 'ID', fieldTranslationKey: 'global.field.id', autoGenerate: true, fieldType: STRING, }; entityWithConfig.fields.unshift(idField); } idFields.push(idField); idCount++; } else if (idRelationships.length > 0) { idRelationships.forEach(relationship => { // relationships id data are not available at this point, so calculate it when needed. relationship.derivedPrimaryKey = { get derivedFields() { return relationship.otherEntity.primaryKey.fields.map(field => ({ originalField: field, ...field, derived: true, derivedEntity: relationship.otherEntity, jpaGeneratedValue: false, liquibaseAutoIncrement: false, // Mapsid is generated by relationship select autoGenerate: true, readonly: true, get derivedPath() { if (field.derivedPath) { if (relationship.otherEntity.primaryKey.derived) { return [relationship.relationshipName, ...field.derivedPath.splice(1)]; } return [relationship.relationshipName, ...field.derivedPath]; } return [relationship.relationshipName, field.fieldName]; }, get path() { return [relationship.relationshipName, ...field.path]; }, get fieldName() { return idCount === 1 ? field.fieldName : `${relationship.relationshipName}${field.fieldNameCapitalized}`; }, get fieldNameCapitalized() { return idCount === 1 ? field.fieldNameCapitalized : `${relationship.relationshipNameCapitalized}${field.fieldNameCapitalized}`; }, get columnName() { return idCount === 1 ? field.columnName : `${hibernateSnakeCase(relationship.relationshipName)}_${field.columnName}`; }, get reference() { return fieldToReference(entityWithConfig, this); }, get relationshipsPath() { return [relationship, ...field.relationshipsPath]; }, })); }, }; }); } if (idCount === 1 && idRelationships.length === 1) { const relationshipId = idRelationships[0]; // One-To-One relationships with id uses @MapsId. // Almost every info is taken from the parent, except some info like autoGenerate and derived. // calling fieldName as id is for backward compatibility, in the future we may want to prefix it with relationship name. entityWithConfig.primaryKey = { fieldName: 'id', derived: true, // MapsId copy the id from the relationship. autoGenerate: true, get fields() { return this.derivedFields; }, get derivedFields() { return relationshipId.derivedPrimaryKey.derivedFields; }, get ownFields() { return relationshipId.otherEntity.primaryKey.ownFields; }, relationships: idRelationships, get name() { return relationshipId.otherEntity.primaryKey.name; }, get hibernateSnakeCaseName() { return hibernateSnakeCase(relationshipId.otherEntity.primaryKey.name); }, get nameCapitalized() { return relationshipId.otherEntity.primaryKey.nameCapitalized; }, get type() { return relationshipId.otherEntity.primaryKey.type; }, get tsType() { return relationshipId.otherEntity.primaryKey.tsType; }, get composite() { return relationshipId.otherEntity.primaryKey.composite; }, get ids() { return this.fields.map(field => fieldToId(field)); }, }; } else { const composite = enableCompositeId ? idCount > 1 : false; let primaryKeyName; let primaryKeyType; if (composite) { primaryKeyName = 'id'; primaryKeyType = `${entityWithConfig.entityClass}Id`; } else { const idField = idFields[0]; idField.dynamic = false; // Allow ids type to be empty and fallback to default type for the database. if (!idField.fieldType) { idField.fieldType = application?.pkType ?? getDatabaseTypeData(entityWithConfig.databaseType).defaultPrimaryKeyType; } primaryKeyName = idField.fieldName; primaryKeyType = idField.fieldType; } entityWithConfig.primaryKey = { derived: false, name: primaryKeyName, hibernateSnakeCaseName: hibernateSnakeCase(primaryKeyName), nameCapitalized: upperFirst(primaryKeyName), type: primaryKeyType, tsType: getTypescriptKeyType(primaryKeyType), composite, relationships: idRelationships, // Fields declared in this entity ownFields: idFields, // Fields declared and inherited get fields() { return [...this.ownFields, ...this.derivedFields]; }, get autoGenerate() { return this.composite ? false : this.fields[0].autoGenerate; }, // Fields inherited from id relationships. get derivedFields() { return this.relationships.map(rel => rel.derivedPrimaryKey.derivedFields).flat(); }, get ids() { return this.fields.map(field => fieldToId(field)); }, }; } return entityWithConfig; } function fieldToId(field) { return { field, get name() { return field.fieldName; }, get nameCapitalized() { return field.fieldNameCapitalized; }, get nameDotted() { return field.derivedPath ? field.derivedPath.join('.') : field.fieldName; }, get nameDottedAsserted() { return field.derivedPath ? `${field.derivedPath.join('!.')}!` : `${field.fieldName}!`; }, get setter() { return `set${this.nameCapitalized}`; }, get getter() { return (field.fieldType === BOOLEAN ? 'is' : 'get') + this.nameCapitalized; }, get autoGenerate() { return !!field.autoGenerate; }, get relationshipsPath() { return field.relationshipsPath; }, }; } /** * Copy required application config into entity. * Some entity features are related to the backend instead of the current app. * This allows to entities files based on the backend features. * * @param {Object} entity - entity to copy the config into. * @param {Object} config - config object. * @returns {Object} the entity parameter for chaining. */ export function loadRequiredConfigIntoEntity(entity, config) { mutateData(entity, { __override__: false, applicationType: config.applicationType, baseName: config.baseName, authenticationType: config.authenticationType, reactive: config.reactive, microfrontend: config.microfrontend, // Workaround different paths clientFramework: config.clientFramework, databaseType: config.databaseType, prodDatabaseType: config.prodDatabaseType, searchEngine: config.searchEngine, jhiPrefix: config.jhiPrefix, entitySuffix: config.entitySuffix, dtoSuffix: config.dtoSuffix, packageName: config.packageName, microserviceName: ({ builtIn }) => (!builtIn && config.applicationType === MICROSERVICE ? config.baseName : undefined), }); if (entity.searchEngine === true && (!entity.microserviceName || entity.microserviceName === config.baseName)) { // If the entity belongs to this application and searchEngine is true. if (config.searchEngine && config.searchEngine !== NO_SEARCH_ENGINE) { // Replace with the searchEngine from the application. entity.searchEngine = config.searchEngine; } else { entity.searchEngine = NO_SEARCH_ENGINE; this?.log.warn('Search engine is enabled at entity level, but disabled at application level. Search engine will be disabled'); } } return entity; } export function preparePostEntityCommonDerivedProperties(entity) { const { fields } = entity; const fieldsType = sortedUniq(fields.map(({ fieldType }) => fieldType).filter(fieldType => !fieldIsEnum(fieldType))); // TODO move to server generator for (const field of fields) { if (field.autoGenerate && field.fieldType === STRING) { entity.anyFieldIsUUIDString = true; break; } } entity.anyFieldHasDocumentation = entity.fields.some(({ documentation }) => documentation); entity.anyFieldIsZonedDateTime = fieldsType.includes(ZONED_DATE_TIME); entity.anyFieldIsInstant = fieldsType.includes(INSTANT); entity.anyFieldIsDuration = fieldsType.includes(DURATION); entity.anyFieldIsLocalDate = fieldsType.includes(LOCAL_DATE); entity.anyFieldIsBigDecimal = fieldsType.includes(BIG_DECIMAL); entity.anyFieldIsUUID = fieldsType.includes(UUID); entity.anyFieldIsTimeDerived = entity.anyFieldIsZonedDateTime || entity.anyFieldIsInstant; entity.anyFieldIsDateDerived = entity.anyFieldIsTimeDerived || entity.anyFieldIsLocalDate; entity.anyFieldIsBlobDerived = intersection(fieldsType, [BYTES, BYTE_BUFFER]).length > 0; if (entity.anyFieldIsBlobDerived) { const blobFields = fields.filter(({ fieldType }) => [BYTES, BYTE_BUFFER].includes(fieldType)); const blobFieldsContentType = sortedUniq(blobFields.map(({ fieldTypeBlobContent }) => fieldTypeBlobContent)); entity.anyFieldHasImageContentType = blobFieldsContentType.includes(IMAGE); entity.anyFieldHasFileBasedContentType = blobFieldsContentType.some(fieldTypeBlobContent => fieldTypeBlobContent !== TEXT); entity.anyFieldHasTextContentType = blobFieldsContentType.includes(TEXT); } preparePostEntityCommonDerivedPropertiesNotTyped(entity); } function preparePostEntityCommonDerivedPropertiesNotTyped(entity) { const { relationships, fields } = entity; const oneToOneRelationships = relationships.filter(({ relationshipType }) => relationshipType === 'one-to-one'); entity.fieldsContainNoOwnerOneToOne = oneToOneRelationships.some(({ ownerSide }) => !ownerSide); entity.anyPropertyHasValidation = entity.anyPropertyHasValidation || relationships.some(({ relationshipValidate }) => relationshipValidate); const relationshipsByOtherEntity = relationships .map(relationship => [relationship.otherEntity.entityNameCapitalized, relationship]) .reduce((relationshipsByOtherEntity, [type, relationship]) => { if (!relationshipsByOtherEntity[type]) { relationshipsByOtherEntity[type] = [relationship]; } else { relationshipsByOtherEntity[type].push(relationship); } return relationshipsByOtherEntity; }, {}); entity.relationshipsByOtherEntity = relationshipsByOtherEntity; entity.differentRelationships = relationshipsByOtherEntity; entity.persistableOtherEntities = Object.values(relationshipsByOtherEntity).filter(relationships => relationships.some(({ persistableRelationship, otherEntity }) => persistableRelationship && otherEntity !== entity)); entity.anyPropertyHasValidation = entity.anyPropertyHasValidation || fields.some(({ fieldValidate }) => fieldValidate); entity.allReferences = [ ...entity.fields.map(field => field.reference), ...entity.relationships.map(relationship => relationship.reference), ]; entity.otherEntities = uniq(entity.relationships.map(rel => rel.otherEntity)); entity.persistableRelationships = relationships.filter(({ persistableRelationship }) => persistableRelationship); entity.otherEntitiesWithPersistableRelationship = uniq(entity.persistableRelationships.map(rel => rel.otherEntity)); entity.updatableEntity = entity.fields.some(field => !field.id && !field.transient) || entity.relationships.some(relationship => !relationship.id && relationship.persistableRelationship); entity.allReferences .filter(reference => reference.relationship?.relatedField) .forEach(reference => { reference.relatedReference = reference.relationship.relatedField.reference; }); entity.relationships.forEach(relationship => { relationship.relationshipCollection = ['one-to-many', 'many-to-many'].includes(relationship.relationshipType); relationship.relationshipReferenceField = relationship.relationshipCollection ? relationship.relationshipFieldNamePlural : relationship.relationshipFieldName; }); entity.entityContainsCollectionField = entity.relationships.some(relationship => relationship.relationshipCollection); if (entity.primaryKey) { derivedPrimaryKeyProperties(entity.primaryKey); entity.requiresPersistableImplementation = entity.requiresPersistableImplementation || entity.fields.some(field => field.requiresPersistableImplementation); } const types = entity.relationships .filter(rel => rel.otherEntity.primaryKey) .map(rel => rel.otherEntity.primaryKey.fields.map(f => f.fieldType)) .flat(); entity.otherEntityPrimaryKeyTypes = Array.from(new Set(types)); entity.otherEntityPrimaryKeyTypesIncludesUUID = types.includes(UUID); entity.relationships.forEach(relationship => { if (!relationship.otherEntity.primaryKey) { relationship.bagRelationship = false; relationship.relationshipEagerLoad = false; return; } mutateData(relationship, { bagRelationship: relationship.ownerSide && relationship.collection, relationshipEagerLoad: ({ relationshipEagerLoad, bagRelationship, ownerSide, otherEntity, otherEntityField }) => relationshipEagerLoad ?? (bagRelationship || entity.eagerLoad || // Fetch relationships if otherEntityField differs otherwise the id is enough (ownerSide && otherEntity.primaryKey.name !== otherEntityField)), }); }); entity.relationshipsContainEagerLoad = entity.relationships.some(relationship => relationship.relationshipEagerLoad); entity.containsBagRelationships = entity.relationships.some(relationship => relationship.bagRelationship); entity.implementsEagerLoadApis = // Cassandra doesn't provides *WithEagerRelationships apis ![CASSANDRA, COUCHBASE, NEO4J].includes(entity.databaseType) && // Only sql and mongodb provides *WithEagerRelationships apis for imperative implementation (entity.reactive || [SQL, MONGODB].includes(entity.databaseType)) && entity.relationshipsContainEagerLoad; entity.eagerRelations = entity.relationships.filter(rel => rel.relationshipEagerLoad); entity.regularEagerRelations = entity.eagerRelations.filter(rel => rel.id !== true); entity.reactiveEagerRelations = entity.relationships.filter(rel => rel.relationshipType === 'many-to-one' || (rel.relationshipType === 'one-to-one' && rel.ownerSide === true)); entity.reactiveRegularEagerRelations = entity.reactiveEagerRelations.filter(rel => rel.id !== true); } export function preparePostEntitiesCommonDerivedProperties(entities) { for (const entity of entities.filter(entity => !entity.dtoReferences)) { entity.dtoReferences = [ ...entity.fields.map(field => field.reference), ...entity.relationships .map(relationship => relationship.reference) .filter(reference => reference.owned || reference.relationship.otherEntity.embedded), ]; entity.restProperties = [ ...entity.fields, ...entity.relationships.filter(relationship => relationship.persistableRelationship || relationship.relationshipEagerLoad || relationship.otherEntity.embedded), ]; entity.otherReferences = entity.otherRelationships.map(relationship => relationship.reference); } for (const entity of entities.filter(entity => !entity.otherDtoReferences)) { // Get all required back references for dto. entity.otherDtoReferences = entity.otherReferences.filter(reference => reference.entity.dtoReferences.includes(reference)); } } export async function addFakerToEntity(entityWithConfig, nativeLanguage = 'en') { entityWithConfig.faker = entityWithConfig.faker || (await createFaker(nativeLanguage)); entityWithConfig.resetFakerSeed = (suffix = '') => entityWithConfig.faker.seed(stringHashCode(entityWithConfig.name.toLowerCase() + suffix)); entityWithConfig.resetFakerSeed(); }