diff --git a/.github/workflows/linked-issue-check.yml b/.github/workflows/linked-issue-check.yml index e0317f733e10..ed4b95842ddc 100644 --- a/.github/workflows/linked-issue-check.yml +++ b/.github/workflows/linked-issue-check.yml @@ -59,38 +59,41 @@ jobs: uses: actions/checkout@v4 with: path: generator-jhipster - fetch-depth: 1 - - name: 'SETUP: environment' - id: setup - uses: ./generator-jhipster/.github/actions/setup + fetch-depth: 2 - uses: ./generator-jhipster/.github/actions/setup-default-node-java - uses: jhipster/actions/setup-runner@v0 with: maven-cache: true gradle-cache: true + binary-dir: ${{ github.workspace }}/generator-jhipster/bin #---------------------------------------------------------------------- # Install JHipster and generate project+entities #---------------------------------------------------------------------- - - name: 'GENERATION: install JHipster' - run: $JHI_SCRIPTS/10-install-jhipster.sh + - run: npm ci --ignore-scripts + working-directory: ${{ github.workspace }}/generator-jhipster - name: 'GENERATION: project' id: project - run: jhipster from-issue "${{ matrix.linked-issue }}" --no-code-workspace --disable-blueprints - - name: 'GENERATION: jhipster info' + run: jhipster.cjs from-issue "${{ matrix.linked-issue }}" --no-code-workspace --disable-blueprints + env: + # generate-sample uses JHI_FOLDER_APP to generate the application. + JHI_FOLDER_APP: ${{ github.workspace }}/app + - run: jhipster.cjs info if: steps.project.outputs.contains-sample != 'false' - run: $JHI_SCRIPTS/14-jhipster-info.sh #---------------------------------------------------------------------- # Launch tests #---------------------------------------------------------------------- - - name: 'PREPARE: npm install' - if: steps.project.outputs.contains-sample != 'false' - run: npm install - timeout-minutes: 7 + - uses: jhipster/actions/build-jhipster-bom@v0 + with: + jhipster-bom-ref: main - name: 'TESTS: backend' if: steps.project.outputs.contains-sample != 'false' id: backend run: npm run ci:backend:test --if-present timeout-minutes: 15 + - name: 'PREPARE: npm install' + if: steps.project.outputs.contains-sample != 'false' + run: npm install + timeout-minutes: 7 - name: 'TESTS: frontend' if: steps.project.outputs.contains-sample != 'false' id: frontend diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.spec.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.spec.ts.ejs index 5fe453418af3..f49c6923fdd2 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.spec.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.spec.ts.ejs @@ -19,8 +19,8 @@ <%_ const tsKeyId = this.generateTestEntityId(primaryKey.type); const allRelationshipsByEntityNeedingOptions = Object - .values(differentRelationships) - .map(relationships => relationships.filter(rel => rel.persistableRelationship)) + .values(relationshipsByOtherEntity) + .map(relationships => relationships.filter(rel => rel.persistableRelationship && !rel.otherEntity.embedded)) .filter(relationships => relationships.length > 0); const testEntityPrimaryKey0 = this.generateTestEntityPrimaryKey(primaryKey, 0); const testEntityPrimaryKey1 = this.generateTestEntityPrimaryKey(primaryKey, 1); @@ -245,7 +245,7 @@ describe('<%= entityAngularName %> Management Update Component', () => { <%_ } _%> }); -<%_ const trackedRelationships = Object.values(differentRelationships).filter(arr => arr.some(rel => rel.persistableRelationship && rel.otherEntity.primaryKey)); +<%_ const trackedRelationships = Object.values(relationshipsByOtherEntity).filter(arr => arr.some(rel => rel.persistableRelationship && !rel.otherEntity.embedded)); if (trackedRelationships.length > 0) { _%> diff --git a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.ts.ejs b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.ts.ejs index 3b883465a5ed..3c217954d618 100644 --- a/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.ts.ejs +++ b/generators/angular/templates/src/main/webapp/app/entities/_entityFolder_/update/_entityFile_-update.component.ts.ejs @@ -18,8 +18,8 @@ -%> <%_ const allRelationshipsByEntityNeedingOptions = Object - .values(differentRelationships) - .map(relationships => relationships.filter(rel => rel.persistableRelationship)) + .values(relationshipsByOtherEntity) + .map(relationships => relationships.filter(rel => rel.persistableRelationship && !rel.otherEntity.embedded)) .filter(relationships => relationships.length > 0); _%> import { Component, inject, OnInit<% if (anyFieldHasImageContentType) { %>, ElementRef<% } %> } from '@angular/core'; @@ -39,10 +39,8 @@ import { AlertError } from 'app/shared/alert/alert-error.model'; import { EventManager, EventWithContent } from 'app/core/util/event-manager.service'; import { DataUtils, FileLoadError } from 'app/core/util/data-util.service'; <%_ } _%> -<%_ -Object.keys(differentRelationships).forEach(key => { - if (differentRelationships[key].some(rel => rel.persistableRelationship)) { - const uniqueRel = differentRelationships[key][0]; +<%_ for (const relationshipsByEntityNeedingOptions of allRelationshipsByEntityNeedingOptions) { + const uniqueRel = relationshipsByEntityNeedingOptions[0]; if (uniqueRel.otherEntityAngularName !== entityAngularName) { _%> import { I<%= uniqueRel.otherEntityAngularName %> } from 'app/entities/<%= uniqueRel.otherEntityPath %>/<%= uniqueRel.otherEntityFileName %>.model'; @@ -50,7 +48,6 @@ import { <%= uniqueRel.otherEntityAngularName %>Service } from 'app/entities/<%= <%_ } } -}); _%> <%_ const enumImports = this.generateEntityClientEnumImports(fields); _%> <%_ enumImports.forEach( (importedPath, importedType) => { _%> @@ -70,7 +67,7 @@ export class <%= entityAngularName %>UpdateComponent implements OnInit { <%- this._.lowerFirst(importedType) %>Values = Object.keys(<%- importedType %>); <%_ }); _%> -<%_ for (const relationshipsByEntityNeedingOptions of Object.values(differentRelationships).map(relationships => relationships.filter(rel => rel.persistableRelationship)).filter(relationships => relationships.length > 0)) { _%> +<%_ for (const relationshipsByEntityNeedingOptions of allRelationshipsByEntityNeedingOptions) { _%> <%_ const relationshipsWithCustomUniqueOptions = relationshipsByEntityNeedingOptions.filter(rel => rel.relationshipOneToOne && rel.otherRelationship); _%> <%_ if (relationshipsByEntityNeedingOptions.length > relationshipsWithCustomUniqueOptions.length) { _%> <%_ const otherEntity = relationshipsByEntityNeedingOptions[0].otherEntity _%> @@ -87,17 +84,14 @@ export class <%= entityAngularName %>UpdateComponent implements OnInit { <%_ } _%> protected <%= entityInstance %>Service = inject(<%= entityAngularName %>Service); protected <%= entityInstance %>FormService = inject(<%= entityAngularName %>FormService); -<%_ -Object.keys(differentRelationships).forEach(key => { - if (differentRelationships[key].some(rel => rel.persistableRelationship)) { - const uniqueRel = differentRelationships[key][0]; +<%_ for (const relationshipsByEntityNeedingOptions of allRelationshipsByEntityNeedingOptions) { + const uniqueRel = relationshipsByEntityNeedingOptions[0]; if (uniqueRel.otherEntityAngularName !== entityAngularName) { _%> protected <%= uniqueRel.otherEntity.entityInstance %>Service = inject(<%= uniqueRel.otherEntityAngularName %>Service); <%_ } } -}); _%> <%_ if (anyFieldHasImageContentType) { _%> protected elementRef = inject(ElementRef); @@ -107,8 +101,8 @@ _%> // eslint-disable-next-line @typescript-eslint/member-ordering editForm: <%= entityAngularName %>FormGroup = this.<%= entityInstance %>FormService.create<%= entityAngularName %>FormGroup(); -<%_ for (const relationshipsByEntity of Object.values(differentRelationships).filter(arr => arr.some(rel => rel.persistableRelationship && rel.otherEntity.primaryKey))) { - const { otherEntity } = relationshipsByEntity[0]; +<%_ for (const relationshipsByEntityNeedingOptions of allRelationshipsByEntityNeedingOptions) { + const { otherEntity } = relationshipsByEntityNeedingOptions[0]; _%> compare<%= otherEntity.entityAngularName %> = (o1: I<%= otherEntity.entityAngularName %> | null, o2: I<%= otherEntity.entityAngularName %> | null): boolean => @@ -122,7 +116,7 @@ _%> this.updateForm(<%= entityInstance %>); } -<%_ if (relationships.filter(rel => rel.persistableRelationship && !rel.otherEntityIsEmbedded).length > 0) { _%> +<%_ if (relationships.filter(rel => rel.persistableRelationship && !rel.otherEntity.embedded).length > 0) { _%> this.loadRelationshipsOptions(); <%_ } _%> }); @@ -225,7 +219,7 @@ _%> <%_ if (relationships.filter(rel => rel.persistableRelationship && !rel.otherEntityIsEmbedded).length > 0) { _%> protected loadRelationshipsOptions(): void { - <%_ for (const relationshipsByEntityNeedingOptions of Object.values(differentRelationships).map(relationships => relationships.filter(rel => rel.persistableRelationship)).filter(relationships => relationships.length > 0)) { _%> + <%_ for (const relationshipsByEntityNeedingOptions of allRelationshipsByEntityNeedingOptions) { _%> <%_ const relationshipsWithCustomUniqueOptions = relationshipsByEntityNeedingOptions.filter(rel => rel.relationshipOneToOne && rel.otherRelationship); %> <%_ const relationshipsWithCustomSharedOptions = relationshipsByEntityNeedingOptions.filter(rel => !relationshipsWithCustomUniqueOptions.includes(rel)); %> <%_ const { otherEntity } = relationshipsByEntityNeedingOptions[0] _%> diff --git a/generators/base-application/support/prepare-relationship.js b/generators/base-application/support/prepare-relationship.js index d57f4b82647c..27db1fbe455e 100644 --- a/generators/base-application/support/prepare-relationship.js +++ b/generators/base-application/support/prepare-relationship.js @@ -90,10 +90,10 @@ export default function prepareRelationship(entityWithConfig, relationship, gene // let ownerSide true when type is 'many-to-one' for convenience. // means that this side should control the reference. - ownerSide: relationshipManyToOne || (relationshipLeftSide && !relationshipOneToMany), + ownerSide: relationship.otherEntity.embedded || relationshipManyToOne || (relationshipLeftSide && !relationshipOneToMany), persistableRelationship: ({ ownerSide }) => ownerSide, - relationshipUpdateBackReference: ({ ownerSide, relationshipRightSide }) => - entityWithConfig.databaseType === NEO4J ? relationshipRightSide : !ownerSide, + relationshipUpdateBackReference: ({ ownerSide, relationshipRightSide, otherEntity }) => + !otherEntity.embedded && (entityWithConfig.databaseType === NEO4J ? relationshipRightSide : !ownerSide), // DB properties columnName: hibernateSnakeCase(relationshipName), @@ -119,6 +119,7 @@ export default function prepareRelationship(entityWithConfig, relationship, gene relationship.otherSideReferenceExists = true; } else if ( !ignoreMissingRequiredRelationship && + !relationship.otherEntity.embedded && !relationship.relationshipIgnoreBackReference && entityWithConfig.databaseType !== NEO4J && entityWithConfig.databaseType !== DATABASE_NO && diff --git a/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs b/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs index 3582acd37fce..d19fe3f98112 100644 --- a/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs +++ b/generators/java/generators/domain/templates/src/main/java/_package_/_entityPackage_/domain/_persistClass_.java.jhi.ejs @@ -134,7 +134,7 @@ public class <%= persistClass %> <&- fragments.extendsSection() -&>implements Se <%_ // An embedded entity should not reference entities that embed it, unless the other entities are also embedded -for (relationship of relationships.filter(relationship => !relationship.embedded || relationship.otherEntity.embedded || relationship.ownerSide)) { +for (relationship of relationships) { if (typeof relationship.fieldApiDescription) { _%> <%- relationship.relationshipJavadoc %> <%_ if (!dtoMapstruct && relationship.relationshipyApiDescription) { _%> @@ -223,10 +223,6 @@ for (relationship of relationships.filter(relationship => !relationship.embedded <&- fragments.classAdditionalFieldsMethodsSection('\n\n') -&> <%_ for (const relationship of relationships) { - // An embedded entity should not reference entities that embed it, unless the other entities are also embedded - if (embedded && !relationship.otherEntity.embedded && !relationship.ownerSide) { - continue; - } _%> <%_ if (relationship.collection) { _%> public Set<<%= relationship.otherEntity.persistClass %>> get<%= relationship.relationshipNameCapitalizedPlural %>() { diff --git a/generators/java/generators/domain/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Asserts.java.ejs b/generators/java/generators/domain/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Asserts.java.ejs index 79d3d0f34ce9..c0185c6de85e 100644 --- a/generators/java/generators/domain/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Asserts.java.ejs +++ b/generators/java/generators/domain/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Asserts.java.ejs @@ -78,7 +78,7 @@ public class <%= persistClass %>Asserts { <%_ for (const field of fields.filter(field => !field.transient && field.autoGenerate)) { _%> .satisfies(e -> assertThat(e.get<%- field.fieldInJavaBeanMethod %>()).as("check <%- field.propertyName %>").isEqualTo(actual.get<%- field.fieldInJavaBeanMethod %>())) <%_ } _%> - <%_ for (const relationship of relationships.filter(relationship => relationship.autoGenerate && !relationship.otherEntity.builtInUser)) { _%> + <%_ for (const relationship of relationships.filter(relationship => (!embedded || relationship.otherEntity.embedded) && relationship.autoGenerate && !relationship.otherEntity.builtInUser)) { _%> .satisfies(e -> assertThat(e.get<%- relationship.propertyJavaBeanName %>()).as("check <%- relationship.propertyName %>").isEqualTo(actual.get<%- relationship.propertyJavaBeanName %>())) <%_ } _%> ; @@ -121,10 +121,10 @@ public class <%= persistClass %>Asserts { <%_ if (relationships.some(relationship => relationship.persistableRelationship && !relationship.id && !relationship.autoGenerate && !relationship.otherEntity.builtInUser)) { _%> assertThat(expected) .as("Verify <%- persistClass %> relationships") - <%_ for (const relationship of relationships.filter(relationship => relationship.persistableRelationship && !relationship.id && !relationship.autoGenerate && !relationship.otherEntity.builtInUser)) { _%> + <%_ for (const relationship of relationships.filter(relationship => (!embedded || relationship.otherEntity.embedded) && relationship.persistableRelationship && !relationship.id && !relationship.autoGenerate && !relationship.otherEntity.builtInUser)) { _%> .satisfies(e -> assertThat(e.get<%- relationship.propertyJavaBeanName %>()).as("check <%- relationship.propertyName %>").isEqualTo(actual.get<%- relationship.propertyJavaBeanName %>())) <%_ } _%> ; <%_ } _%> } -} \ No newline at end of file +} diff --git a/generators/java/generators/domain/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Test.java.ejs b/generators/java/generators/domain/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Test.java.ejs index 7201fea06bf2..43854944fc95 100644 --- a/generators/java/generators/domain/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Test.java.ejs +++ b/generators/java/generators/domain/templates/src/test/java/_package_/_entityPackage_/domain/_persistClass_Test.java.ejs @@ -62,7 +62,7 @@ class <%= persistClass %>Test { assertThat(<%= persistInstance %>).hasSameHashCodeAs(<%= persistInstance %>1); } <%_ } _%> -<%_ for (const relationship of relationships.filter(relationship => !relationship.otherEntity.builtIn)) { _%> +<%_ for (const relationship of relationships.filter(rel => !rel.otherEntity.builtIn && (!embedded || (rel.otherEntity.embedded && rel.ownerSide)))) { _%> @Test void <%- relationship.relationshipName %>Test() throws Exception { diff --git a/generators/server/support/prepare-entity.js b/generators/server/support/prepare-entity.js index dfccf44ed3ba..b3feac1b8fef 100644 --- a/generators/server/support/prepare-entity.js +++ b/generators/server/support/prepare-entity.js @@ -90,8 +90,8 @@ export function preparePostEntityServerDerivedProperties(entity) { .forEach(relationship => { relationship.ignoreOtherSideProperty = entity.databaseType !== NEO4J && - !relationship.embedded && - !!relationship.otherEntity && + !entity.embedded && + !relationship.otherEntity.embedded && relationship.otherEntity.relationships.length > 0; }); entity.relationshipsContainOtherSideIgnore = entity.relationships.some(relationship => relationship.ignoreOtherSideProperty); diff --git a/generators/server/support/relationship.ts b/generators/server/support/relationship.ts index 51555edcd4c8..0641e2734b1c 100644 --- a/generators/server/support/relationship.ts +++ b/generators/server/support/relationship.ts @@ -31,6 +31,7 @@ export const addEntitiesOtherRelationships = (entities: JSONEntity[]): Validatio for (const relationship of entity.relationships ?? []) { if ( !relationship.otherRelationship && + !relationship.otherEntity.embedded && (relationship.otherEntityRelationshipName || relationship.relationshipType === 'many-to-many' || // OneToOne back reference is required due to filtering diff --git a/test-integration/samples/.jhipster/DocumentBankAccount.json b/test-integration/samples/.jhipster/DocumentBankAccount.json index 64d4aa7aea0b..94bad95ff2d8 100644 --- a/test-integration/samples/.jhipster/DocumentBankAccount.json +++ b/test-integration/samples/.jhipster/DocumentBankAccount.json @@ -20,9 +20,15 @@ "relationships": [ { "otherEntityName": "embeddedOperation", - "otherEntityRelationshipName": "documentBankAccount", - "relationshipName": "embeddedOperation", + "otherEntityRelationshipName": "documentBankAccountToOne", + "relationshipName": "manyEmbeddedOperation", "relationshipType": "one-to-many" + }, + { + "otherEntityName": "embeddedOperation", + "otherEntityRelationshipName": "documentBankAccountToMany", + "relationshipName": "oneEmbeddedOperation", + "relationshipType": "many-to-one" } ], "service": "serviceImpl" diff --git a/test-integration/samples/.jhipster/EmbeddedOperation.json b/test-integration/samples/.jhipster/EmbeddedOperation.json index c1943ec3d1eb..b38fa614c960 100644 --- a/test-integration/samples/.jhipster/EmbeddedOperation.json +++ b/test-integration/samples/.jhipster/EmbeddedOperation.json @@ -14,7 +14,6 @@ { "otherEntityField": "name", "otherEntityName": "documentBankAccount", - "otherEntityRelationshipName": "embeddedOperation", "relationshipName": "documentBankAccount", "relationshipType": "many-to-one" }