From db77b86f4757809bb85c1440cf9898f87ec4d7ce Mon Sep 17 00:00:00 2001 From: Marcelo Shima Date: Thu, 4 Feb 2021 08:57:54 -0300 Subject: [PATCH 1/3] Implement json data generation and change angular to use it. --- .../entities/user/user.service.spec.ts.ejs | 22 +-- ...ntity-management-detail.component.html.ejs | 2 +- ...ty-management-detail.component.spec.ts.ejs | 6 +- .../list/entity-management.component.html.ejs | 11 +- .../entity-management.component.spec.ts.ejs | 15 +- .../list/entity-management.component.ts.ejs | 2 +- ...gement-routing-resolve.service.spec.ts.ejs | 10 +- ...-management-routing-resolve.service.ts.ejs | 2 +- .../entity-management-routing.module.ts.ejs | 4 +- .../service/entity.service.spec.ts.ejs | 44 +++--- ...ntity-management-update.component.html.ejs | 8 +- ...ty-management-update.component.spec.ts.ejs | 32 ++-- .../integration/entity/entity.spec.ts.ejs | 2 +- .../templates/partials/save_template.ejs | 6 +- generators/entity/index.js | 33 ++-- generators/generator-base-private.js | 85 ++++++---- test/generator-base-private.spec.js | 4 +- test/utils-entity.spec.js | 1 + utils/entity.js | 149 +++++++++++------- utils/field.js | 11 +- utils/index.js | 9 ++ utils/relationship.js | 9 +- 22 files changed, 276 insertions(+), 191 deletions(-) diff --git a/generators/client/templates/angular/src/main/webapp/app/entities/user/user.service.spec.ts.ejs b/generators/client/templates/angular/src/main/webapp/app/entities/user/user.service.spec.ts.ejs index 490ec6b30e83..1c87fd898f25 100644 --- a/generators/client/templates/angular/src/main/webapp/app/entities/user/user.service.spec.ts.ejs +++ b/generators/client/templates/angular/src/main/webapp/app/entities/user/user.service.spec.ts.ejs @@ -18,6 +18,8 @@ -%> <%_ const tsKeyId = generateTestEntityId(user.primaryKey.type); +const testEntityPrimaryKey0 = generateTestEntityPrimaryKey(user.primaryKey, 0); +const testEntityPrimaryKey1 = generateTestEntityPrimaryKey(user.primaryKey, 1); _%> import { TestBed } from '@angular/core/testing'; import { HttpErrorResponse } from '@angular/common/http'; @@ -72,42 +74,42 @@ describe('Service Tests', () => { describe('addUserToCollectionIfMissing', () => { it('should add a User to an empty array', () => { - const user: IUser = <%- generateTestEntityPrimaryKey(user.primaryKey, 0) %>; + const user: IUser = <%- testEntityPrimaryKey0 %>; expectedResult = service.addUserToCollectionIfMissing([], user); expect(expectedResult).toHaveLength(1); expect(expectedResult).toContain(user); }); it('should not add a User to an array that contains it', () => { - const user: IUser = <%- generateTestEntityPrimaryKey(user.primaryKey, 0) %>; + const user: IUser = <%- testEntityPrimaryKey0 %>; const userCollection: IUser[] = [ { ...user, }, - <%- generateTestEntityPrimaryKey(user.primaryKey, 1) %>, + <%- testEntityPrimaryKey1 %>, ]; expectedResult = service.addUserToCollectionIfMissing(userCollection, user); expect(expectedResult).toHaveLength(2); }); it("should add a User to an array that doesn't contain it", () => { - const user: IUser = <%- generateTestEntityPrimaryKey(user.primaryKey, 0) %>; - const userCollection: IUser[] = [<%- generateTestEntityPrimaryKey(user.primaryKey, 1) %>]; + const user: IUser = <%- testEntityPrimaryKey0 %>; + const userCollection: IUser[] = [<%- testEntityPrimaryKey1 %>]; expectedResult = service.addUserToCollectionIfMissing(userCollection, user); expect(expectedResult).toHaveLength(2); expect(expectedResult).toContain(user); }); it('should add only unique User to an array', () => { - const userArray: IUser[] = [<%- generateTestEntityPrimaryKey(user.primaryKey, 0) %>, <%- generateTestEntityPrimaryKey(user.primaryKey, 1) %>, <%- generateTestEntityPrimaryKey(user.primaryKey) %>]; - const userCollection: IUser[] = [<%- generateTestEntityPrimaryKey(user.primaryKey, 1) %>]; + const userArray: IUser[] = [<%- testEntityPrimaryKey0 %>, <%- testEntityPrimaryKey1 %>, <%- generateTestEntityPrimaryKey(user.primaryKey) %>]; + const userCollection: IUser[] = [<%- testEntityPrimaryKey1 %>]; expectedResult = service.addUserToCollectionIfMissing(userCollection, ...userArray); expect(expectedResult).toHaveLength(3); }); it("should accept varargs", () => { - const user: IUser = <%- generateTestEntityPrimaryKey(user.primaryKey, 0) %>; - const user2: IUser = <%- generateTestEntityPrimaryKey(user.primaryKey, 1) %>; + const user: IUser = <%- testEntityPrimaryKey0 %>; + const user2: IUser = <%- testEntityPrimaryKey1 %>; expectedResult = service.addUserToCollectionIfMissing([], user, user2); expect(expectedResult).toHaveLength(2); expect(expectedResult).toContain(user); @@ -115,7 +117,7 @@ describe('Service Tests', () => { }); it("should accept null and undefined values", () => { - const user: IUser = <%- generateTestEntityPrimaryKey(user.primaryKey, 0) %>; + const user: IUser = <%- testEntityPrimaryKey0 %>; expectedResult = service.addUserToCollectionIfMissing([], null, user, undefined); expect(expectedResult).toHaveLength(1); expect(expectedResult).toContain(user); diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.html.ejs index 4d308ad5c05e..9e4f83fca705 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.html.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.html.ejs @@ -28,7 +28,7 @@ <<%= jhiPrefixDashed %>-alert>-alert>
- <%_ for (const field of fields) { + <%_ for (const field of fields.filter(field => !field.hidden)) { const fieldName = field.fieldName; const fieldType = field.fieldType; const fieldTypeBlobContent = field.fieldTypeBlobContent; diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.spec.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.spec.ts.ejs index 2d1e264f2e0b..665861daf7b2 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.spec.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/detail/entity-management-detail.component.spec.ts.ejs @@ -18,12 +18,12 @@ -%> <%_ const tsKeyId = generateTestEntityId(primaryKey.type); +const testEntity = generateTestEntityPrimaryKey(primaryKey, 0); _%> import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; -import { <%= entityAngularName %> } from '../<%= entityFileName %>.model'; <%_ if (fieldsContainBlob) { _%> import { DataUtils } from 'app/core/util/data-util.service'; <%_ } _%> @@ -44,7 +44,7 @@ describe('Component Tests', () => { providers: [ { provide: ActivatedRoute, - useValue: { data: of({ <%= entityInstance %>: new <%= entityAngularName %>(<%- tsKeyId %>) }) } + useValue: { data: of({ <%= entityInstance %>: <%- testEntity %> }) } } ] }) @@ -63,7 +63,7 @@ describe('Component Tests', () => { comp.ngOnInit(); // THEN - expect(comp.<%= entityInstance %>).toEqual(jasmine.objectContaining({ <%- primaryKey.name %>: <%- tsKeyId %> })); + expect(comp.<%= entityInstance %>).toEqual(jasmine.objectContaining(<%- testEntity %>)); }); }); diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.html.ejs index e85807a86b15..1a7436f3a921 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.html.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.html.ejs @@ -79,7 +79,7 @@ _%> <%= jhiPrefix %>Sort [(predicate)]="predicate" [(ascending)]="ascending" [callback]="<%= pagination !== 'infinite-scroll' ? 'loadPage.bind(this)' : 'reset.bind(this)'%>"<% } %>> - <%_ for (const field of fields) { _%> + <%_ for (const field of fields.filter(field => !field.hidden)) { _%> <%_ } _%> <%_ for (const relationship of relationships) { _%> @@ -97,9 +97,8 @@ _%> infinite-scroll (scrolled)="loadPage(page + 1)" [infiniteScrollDisabled]="page >= links['last']" [infiniteScrollDistance]="0"<% } %>> <%_ - const keys = idFields.map(idField => `${entityInstance}.${idField.fieldName}`); - const routerLink = idFields.length === 0 ? '' : ` [routerLink]="['/${ entityUrl }', ${ keys.join(', ') }, 'view']"`; - for ([idx, field] of fields.entries()) { + const routerLink = ` [routerLink]="['/${ entityUrl }', ${entityInstance}.${primaryKey.name}, 'view']"`; + for (field of fields.filter(field => !field.hidden)) { const fieldName = field.fieldName; const fieldNameCapitalized = field.fieldNameCapitalized; const fieldType = field.fieldType; @@ -155,11 +154,11 @@ _%> <%_ } else { _%> <%_ if (relationshipType === 'many-to-many') { _%> - {{ <%= relationshipFieldName %>.<%= otherEntityField %> }}{{ last ? '' : ', ' }} + {{ <%= relationshipFieldName %>.<%= otherEntityField %> }}{{ last ? '' : ', ' }} <%_ } else { _%>
"> - , 'view']" >{{ <%= entityInstance + "." + relationshipFieldName + "?." + otherEntityField %> }} + {{ <%= entityInstance + "." + relationshipFieldName + "?." + otherEntityField %> }}
<%_ } _%> <%_ } _%> diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.spec.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.spec.ts.ejs index 78433959694a..2d4b0cffb7e6 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.spec.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.spec.ts.ejs @@ -17,9 +17,9 @@ limitations under the License. -%> <%_ -const tsKeyId = generateTestEntityId(primaryKey.type); const entityArrayOptionalChainSymbol = pagination === 'infinite-scroll' ? '' : '?.'; const order = pagination === 'infinite-scroll' ? 'asc' : 'desc'; +const testEntityPrimaryKey = generateTestEntityPrimaryKey(primaryKey, 0); _%> <%_ if (pagination === 'pagination' || searchEngine !== false) { _%> jest.mock('@angular/router'); @@ -36,7 +36,6 @@ import { ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; import { <%= entityAngularName %>Service } from '../service/<%= entityFileName %>.service'; -import { <%= entityAngularName %> } from '../<%= entityFileName %>.model'; import { <%= entityAngularName %>Component } from './<%= entityFileName %>.component'; @@ -92,7 +91,7 @@ describe('Component Tests', () => { spyOn(service, 'query').and.returnValue( of( new HttpResponse({ - body: [new <%= entityAngularName %>(<%- tsKeyId %>)], + body: [<%- testEntityPrimaryKey %>], headers, }) ) @@ -105,7 +104,7 @@ describe('Component Tests', () => { // THEN expect(service.query).toHaveBeenCalled(); - expect(comp.<%= entityInstancePlural %><%= entityArrayOptionalChainSymbol %>[0]).toEqual(jasmine.objectContaining({ <%- primaryKey.name %>: <%- tsKeyId %> })); + expect(comp.<%= entityInstancePlural %><%= entityArrayOptionalChainSymbol %>[0]).toEqual(jasmine.objectContaining(<%- testEntityPrimaryKey %>)); }); <%_ if (pagination !== 'no') { _%> @@ -115,7 +114,7 @@ describe('Component Tests', () => { // THEN expect(service.query).toHaveBeenCalled(); - expect(comp.<%= entityInstancePlural %><%= entityArrayOptionalChainSymbol %>[0]).toEqual(jasmine.objectContaining({ <%- primaryKey.name %>: <%- tsKeyId %> })); + expect(comp.<%= entityInstancePlural %><%= entityArrayOptionalChainSymbol %>[0]).toEqual(jasmine.objectContaining(<%- testEntityPrimaryKey %>)); }); it('should calculate the sort attribute for an id', () => { @@ -123,7 +122,7 @@ describe('Component Tests', () => { comp.ngOnInit(); // THEN - expect(service.query).toHaveBeenCalledWith(expect.objectContaining({ sort: ['<%- primaryKey.name %>,<%= order %>'] })); + expect(service.query).toHaveBeenCalledWith(expect.objectContaining({ sort: ['<%- primaryKey.fields.map(field => field.fieldName).join(',') %>,<%= order %>'] })); }); it('should calculate the sort attribute for a non-id attribute', () => { @@ -137,7 +136,7 @@ describe('Component Tests', () => { comp.loadPage(1); // THEN - expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['name,<%= order %>', '<%- primaryKey.name %>'] })); + expect(service.query).toHaveBeenLastCalledWith(expect.objectContaining({ sort: ['name,<%= order %>', '<%- primaryKey.fields.map(field => field.fieldName).join(',') %>'] })); }); <%_ if (pagination === 'infinite-scroll') { _%> @@ -149,7 +148,7 @@ describe('Component Tests', () => { // THEN expect(comp.page).toEqual(0); expect(service.query).toHaveBeenCalledTimes(2); - expect(comp.<%= entityInstancePlural %>[0]).toEqual(jasmine.objectContaining({ <%- primaryKey.name %>: <%- tsKeyId %> })); + expect(comp.<%= entityInstancePlural %>[0]).toEqual(jasmine.objectContaining(<%- testEntityPrimaryKey %>)); }); <%_ } _%> <%_ } _%> diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.ts.ejs index 83793a6b6e24..ed670840648a 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/list/entity-management.component.ts.ejs @@ -57,7 +57,7 @@ export class <%= entityAngularName %>Component implements OnInit { <%_ } _%> <%_ if (primaryKey) { _%> - track<%= primaryKey.nameCapitalized %>(index: number, item: I<%= entityAngularName %>): <%= tsKeyType %> { + track<%= primaryKey.nameCapitalized %>(index: number, item: I<%= entityAngularName %>): <%= primaryKey.tsType %> { return item.<%= primaryKey.name %>!; } diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.spec.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.spec.ts.ejs index a91a745a68a5..d9dd28f3be80 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.spec.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.spec.ts.ejs @@ -53,10 +53,10 @@ describe('Service Tests', () => { }); describe('resolve', () => { - it('should return existing I<%= entityAngularName %> for existing id', () => { + it('should return I<%= entityAngularName %> returned by find', () => { // GIVEN - service.find = jest.fn(id => of(new HttpResponse({ body: new <%= entityAngularName %>(id) }))); - mockActivatedRouteSnapshot.params = { id: <%- tsKeyId %> }; + service.find = jest.fn(<%= primaryKey.name %> => of(new HttpResponse({ body: { <%= primaryKey.name %> } }))); + mockActivatedRouteSnapshot.params = { <%= primaryKey.name %>: <%- tsKeyId %> }; // WHEN routingResolveService.resolve(mockActivatedRouteSnapshot).subscribe(result => { @@ -65,7 +65,7 @@ describe('Service Tests', () => { // THEN expect(service.find).toBeCalledWith(<%- tsKeyId %>); - expect(result<%= entityAngularName %>).toEqual(new <%= entityAngularName %>(<%- tsKeyId %>)); + expect(result<%= entityAngularName %>).toEqual({ <%= primaryKey.name %>: <%- tsKeyId %> }); }); it('should return new I<%= entityAngularName %> if id is not provided', () => { @@ -86,7 +86,7 @@ describe('Service Tests', () => { it('should route to 404 page if data not found in server', () => { // GIVEN spyOn(service, 'find').and.returnValue(of(new HttpResponse({ body: null }))); - mockActivatedRouteSnapshot.params = { id: <%- tsKeyId %> }; + mockActivatedRouteSnapshot.params = { <%= primaryKey.name %>: <%- tsKeyId %> }; // WHEN routingResolveService.resolve(mockActivatedRouteSnapshot).subscribe(result => { diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.ts.ejs index 452656fe294f..23f601ed2e9b 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing-resolve.service.ts.ejs @@ -30,7 +30,7 @@ export class <%= entityAngularName %>RoutingResolveService implements ResolveService, protected router: Router) {} resolve(route: ActivatedRouteSnapshot): Observable> | Observable { - const id = route.params['id']; + const id = route.params['<%= primaryKey.name %>']; if (id) { return this.service.find(id).pipe( mergeMap((<%= entityInstance %>: HttpResponse<<%= entityAngularName %>>) => { diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing.module.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing.module.ts.ejs index 313ddc3b99cc..8d75c2724de2 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing.module.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/route/entity-management-routing.module.ts.ejs @@ -39,7 +39,7 @@ const <%= entityInstance %>Route: Routes = [ canActivate: [UserRouteAccessService] }, { - path: ':id/view', + path: ':<%= primaryKey.name %>/view', component: <%= entityAngularName %>DetailComponent, resolve: { <%= entityInstance %>: <%= entityAngularName %>RoutingResolveService @@ -56,7 +56,7 @@ const <%= entityInstance %>Route: Routes = [ canActivate: [UserRouteAccessService] }, { - path: ':id/edit', + path: ':<%= primaryKey.name %>/edit', component: <%= entityAngularName %>UpdateComponent, resolve: { <%= entityInstance %>: <%= entityAngularName %>RoutingResolveService diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/service/entity.service.spec.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/service/entity.service.spec.ts.ejs index bb4d1377b8ba..53feb24d0a0a 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/service/entity.service.spec.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/service/entity.service.spec.ts.ejs @@ -19,6 +19,8 @@ <%_ const tsKeyId = generateTestEntityId(primaryKey.type); const enumImports = generateEntityClientEnumImports(fields); +const testEntityPrimaryKey0 = generateTestEntityPrimaryKey(primaryKey, 0); +const testEntityPrimaryKey1 = generateTestEntityPrimaryKey(primaryKey, 1); _%> import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; @@ -59,30 +61,30 @@ describe('Service Tests', () => { currentDate = dayjs(); <%_ } _%> - elemDefault = new <%= entityAngularName %>( + elemDefault = { <%_ fields.forEach((field) => { const fieldType = field.fieldType; _%> <%_ if (field.fieldIsEnum) { _%> - <%= fieldType + '.' + field.enumValues[0].name %>, + <%= field.fieldName %>: <%= fieldType + '.' + field.enumValues[0].name %>, <%_ } else if (fieldType === 'Boolean') { _%> - false, + <%= field.fieldName %>: false, <%_ } else if (fieldType === 'Duration') { _%> - 'PT1S', + <%= field.fieldName %>: 'PT1S', <%_ } else if (['Integer', 'Long', 'Float', 'Double', 'BigDecimal'].includes(fieldType)) { _%> - 0, + <%= field.fieldName %>: 0, <%_ } else if (fieldType === 'String' || fieldType === 'UUID') { _%> - 'AAAAAAA', + <%= field.fieldName %>: 'AAAAAAA', <%_ } else if (['LocalDate', 'Instant', 'ZonedDateTime'].includes(fieldType)) { _%> - currentDate, + <%= field.fieldName %>: currentDate, <%_ } else if (['byte[]', 'ByteBuffer'].includes(fieldType) && field.fieldTypeBlobContent !== 'text') { _%> - 'image/png', - 'AAAAAAA', + <%= field.fieldName %>ContentType: 'image/png', + <%= field.fieldName %>: 'AAAAAAA', <%_ } else { // (fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent === 'any' || (fieldType === 'byte[]' || fieldType === 'ByteBuffer') && fieldTypeBlobContent === 'image' || fieldType === 'LocalDate' _%> - 'AAAAAAA', + <%= field.fieldName %>: 'AAAAAAA', <%_ } _%> <%_ }) _%> - ); + }; }); describe('Service methods', () => { @@ -238,39 +240,39 @@ describe('Service Tests', () => { describe('add<%= entityAngularName %>ToCollectionIfMissing', () => { it('should add a <%= entityAngularName %> to an empty array', () => { - const <%= entityInstance %>: I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 0) %>; + const <%= entityInstance %>: I<%= entityAngularName %> = <%- testEntityPrimaryKey0 %>; expectedResult = service.add<%= entityAngularName %>ToCollectionIfMissing([], <%= entityInstance %>); expect(expectedResult).toHaveLength(1); expect(expectedResult).toContain(<%= entityInstance %>); }); it('should not add a <%= entityAngularName %> to an array that contains it', () => { - const <%= entityInstance %>: I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 0) %>; + const <%= entityInstance %>: I<%= entityAngularName %> = <%- testEntityPrimaryKey0 %>; const <%= entityInstance %>Collection: I<%= entityAngularName %>[] = [{ ...<%= entityInstance %>, - }, <%- generateTestEntityPrimaryKey(primaryKey, 1) %>]; + }, <%- testEntityPrimaryKey1 %>]; expectedResult = service.add<%= entityAngularName %>ToCollectionIfMissing(<%= entityInstance %>Collection, <%= entityInstance %>); expect(expectedResult).toHaveLength(2); }); it("should add a <%= entityAngularName %> to an array that doesn't contain it", () => { - const <%= entityInstance %>: I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 0) %>; - const <%= entityInstance %>Collection: I<%= entityAngularName %>[] = [<%- generateTestEntityPrimaryKey(primaryKey, 1) %>]; + const <%= entityInstance %>: I<%= entityAngularName %> = <%- testEntityPrimaryKey0 %>; + const <%= entityInstance %>Collection: I<%= entityAngularName %>[] = [<%- testEntityPrimaryKey1 %>]; expectedResult = service.add<%= entityAngularName %>ToCollectionIfMissing(<%= entityInstance %>Collection, <%= entityInstance %>); expect(expectedResult).toHaveLength(2); expect(expectedResult).toContain(<%= entityInstance %>); }); it("should add only unique <%= entityAngularName %> to an array", () => { - const <%= entityInstance %>Array: I<%= entityAngularName %>[] = [<%- generateTestEntityPrimaryKey(primaryKey, 0) %>, <%- generateTestEntityPrimaryKey(primaryKey, 1) %>, <%- generateTestEntityPrimaryKey(primaryKey) %>]; - const <%= entityInstance %>Collection: I<%= entityAngularName %>[] = [<%- generateTestEntityPrimaryKey(primaryKey, 1) %>]; + const <%= entityInstance %>Array: I<%= entityAngularName %>[] = [<%- testEntityPrimaryKey0 %>, <%- testEntityPrimaryKey1 %>, <%- generateTestEntityPrimaryKey(primaryKey) %>]; + const <%= entityInstance %>Collection: I<%= entityAngularName %>[] = [<%- testEntityPrimaryKey0 %>]; expectedResult = service.add<%= entityAngularName %>ToCollectionIfMissing(<%= entityInstance %>Collection, ...<%= entityInstance %>Array); expect(expectedResult).toHaveLength(3); }); it("should accept varargs", () => { - const <%= entityInstance %>: I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 0) %>; - const <%= entityInstance %>2: I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 1) %>; + const <%= entityInstance %>: I<%= entityAngularName %> = <%- testEntityPrimaryKey0 %>; + const <%= entityInstance %>2: I<%= entityAngularName %> = <%- testEntityPrimaryKey1 %>; expectedResult = service.add<%= entityAngularName %>ToCollectionIfMissing([], <%= entityInstance %>, <%= entityInstance %>2); expect(expectedResult).toHaveLength(2); expect(expectedResult).toContain(<%= entityInstance %>); @@ -278,7 +280,7 @@ describe('Service Tests', () => { }); it("should accept null and undefined values", () => { - const <%= entityInstance %>: I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 0) %>; + const <%= entityInstance %>: I<%= entityAngularName %> = <%- testEntityPrimaryKey0 %>; expectedResult = service.add<%= entityAngularName %>ToCollectionIfMissing([], null, <%= entityInstance %>, undefined); expect(expectedResult).toHaveLength(1); expect(expectedResult).toContain(<%= entityInstance %>); diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.html.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.html.ejs index e49b5342b2c8..8e4fd1a04dca 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.html.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.html.ejs @@ -23,14 +23,14 @@
<<%= jhiPrefixDashed %>-alert-error>-alert-error> -<%_ for (const field of fields) { +<%_ for (const field of fields.filter(field => !field.hidden)) { const fieldName = field.fieldName; const fieldNameCapitalized = field.fieldNameCapitalized; const fieldNameHumanized = field.fieldNameHumanized; const fieldType = field.fieldType; const fieldTypeBlobContent = field.fieldTypeBlobContent; const id = !!field.id; - const readonly = !!field.id || !!field.readonly; + const readonly = field.readonly; let fieldInputType = 'text'; let ngModelOption = ''; const translationKey = field.fieldTranslationKey; @@ -47,7 +47,7 @@ } _%> -
[hidden]="editForm.get('<%= fieldName %>')!.value == null"<% } %>> +
[hidden]="editForm.get('<%= primaryKey.name %>')!.value == null"<% } %>> <%_ if (field.fieldIsEnum) { _%> [readonly]="true"<% } %>/> + formControlName="<%= fieldName %>"<% if (field.id && !field.autoGenerate) { %> [readonly]="editForm.get('<%= primaryKey.name %>')!.value != null"<% } else if (readonly) { %> [readonly]="true"<% } %>/> <%_ if (['byte[]', 'ByteBuffer'].includes(fieldType) && fieldTypeBlobContent !== 'text') { _%> diff --git a/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.spec.ts.ejs b/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.spec.ts.ejs index 95b350e2f7da..124be4e56943 100644 --- a/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.spec.ts.ejs +++ b/generators/entity-client/templates/angular/src/main/webapp/app/entities/update/entity-management-update.component.spec.ts.ejs @@ -22,6 +22,8 @@ const allRelationshipsByEntityNeedingOptions = Object .values(differentRelationships) .map(relationships => relationships.filter(rel => rel.ownerSide)) .filter(relationships => relationships.length > 0); +const testEntityPrimaryKey0 = generateTestEntityPrimaryKey(primaryKey, 0); +const testEntityPrimaryKey1 = generateTestEntityPrimaryKey(primaryKey, 1); _%> jest.mock('@angular/router'); @@ -38,10 +40,10 @@ import { I<%= entityAngularName %>, <%= entityAngularName %> } from '../<%= enti <%_ const otherEntity = relationshipsByEntityNeedingOptions[0].otherEntity; _%> <%_ if (isBuiltInUser(otherEntity.entityAngularName)) { _%> -import { IUser, User } from 'app/entities/user/user.model'; +import { IUser } from 'app/entities/user/user.model'; import { UserService } from 'app/entities/user/user.service'; <%_ } else { _%> -import { I<%= otherEntity.entityAngularName %>, <%= otherEntity.entityAngularName %> } from 'app/entities/<%= otherEntity.entityFolderName %>/<%= otherEntity.entityFileName %>.model'; +import { I<%= otherEntity.entityAngularName %> } from 'app/entities/<%= otherEntity.entityFolderName %>/<%= otherEntity.entityFileName %>.model'; import { <%= otherEntity.entityAngularName %>Service } from 'app/entities/<%= otherEntity.entityFolderName %>/service/<%= otherEntity.entityFileName %>.service'; <%_ } _%> <%_ } _%> @@ -84,9 +86,9 @@ describe('Component Tests', () => { <%_ const relationshipsWithCustomUniqueOptions = relationshipsByEntityNeedingOptions.filter(rel => rel.relationshipType === 'one-to-one' && rel.otherEntityName !== 'user'); _%> <%_ const relationshipsWithCustomSharedOptions = relationshipsByEntityNeedingOptions.filter(rel => !relationshipsWithCustomUniqueOptions.includes(rel)); _%> <%_ if (relationshipsWithCustomSharedOptions.length > 0) { _%> - <%_ const otherEntity = relationshipsByEntityNeedingOptions[0].otherEntity _%> + <%_ const otherEntity = relationshipsByEntityNeedingOptions[0].otherEntity; _%> it('Should call <%= otherEntity.entityAngularName %> query and add missing value', () => { - const <%= entityInstance %> : I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 1) %>; + const <%= entityInstance %> : I<%= entityAngularName %> = <%- testEntityPrimaryKey1 %>; <%_ for (const relationship of relationshipsWithCustomSharedOptions) { _%> <%_ const reference = relationship.reference _%> <%_ if (relationship.collection) { _%> @@ -121,7 +123,7 @@ describe('Component Tests', () => { <%_ const otherEntity = relationship.otherEntity _%> <%_ const reference = relationship.reference _%> it('Should call <%= reference.name %> query and add missing value', () => { - const <%= entityInstance %> : I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 1) %>; + const <%= entityInstance %> : I<%= entityAngularName %> = <%- testEntityPrimaryKey1 %>; const <%= reference.name %> : I<%= otherEntity.entityAngularName %> = <%- generateTestEntityPrimaryKey(otherEntity.primaryKey) %>; <%= entityInstance %>.<%= reference.name %> = <%= reference.name %>; @@ -141,7 +143,7 @@ describe('Component Tests', () => { <%_ } _%> <%_ } _%> it('Should update editForm', () => { - const <%= entityInstance %>: I<%= entityAngularName %> = <%- generateTestEntityPrimaryKey(primaryKey, 1) %>; + const <%= entityInstance %>: I<%= entityAngularName %> = <%- testEntityPrimaryKey1 %>; <%_ for (const relationshipsByEntityNeedingOptions of allRelationshipsByEntityNeedingOptions) { _%> <%_ for (const relationship of relationshipsByEntityNeedingOptions) { _%> <%_ const otherEntity = relationship.otherEntity _%> @@ -168,7 +170,7 @@ describe('Component Tests', () => { it('Should call update service on save for existing entity', () => { // GIVEN const saveSubject = new Subject(); - const <%= entityInstance %> = new <%= entityAngularName %>(<%- tsKeyId %>); + const <%= entityInstance %> = <%- testEntityPrimaryKey0 %>; spyOn(<%= entityInstance %>Service, 'update').and.returnValue(saveSubject); spyOn(comp, 'previousState'); activatedRoute.data = of({ <%= entityInstance %> }); @@ -210,7 +212,7 @@ describe('Component Tests', () => { it('Should set isSaving to false on error', () => { // GIVEN const saveSubject = new Subject(); - const <%= entityInstance %> = new <%= entityAngularName %>(<%- tsKeyId %>); + const <%= entityInstance %> = <%- testEntityPrimaryKey0 %>; spyOn(<%= entityInstance %>Service, 'update').and.returnValue(saveSubject); spyOn(comp, 'previousState'); activatedRoute.data = of({ <%= entityInstance %> }); @@ -238,7 +240,7 @@ _%> _%> describe('track<%= otherEntity.entityAngularName %>By<%= otherEntity.primaryKey.nameCapitalized %>', () => { it('Should return tracked <%= otherEntity.entityAngularName %> primary key', () => { - const entity = new <%= otherEntity.entityAngularName %>(<%- otherEntityTsKeyId %><% if (isBuiltInUser(otherEntity.entityAngularName)) { %>, 'user'<% } %>); + const entity = <%- generateTestEntityPrimaryKey(otherEntity.primaryKey, 0) %>; const trackResult = comp.track<%= otherEntity.entityAngularName %>By<%= otherEntity.primaryKey.nameCapitalized %>(0, entity); expect(trackResult).toEqual(entity.<%= otherEntity.primaryKey.name %>); }); @@ -260,15 +262,15 @@ _%> _%> describe('getSelected<%= otherEntity.entityAngularName %>', () => { it('Should return option if no <%= otherEntity.entityAngularName %> is selected', () => { - const option = new <%= otherEntity.entityAngularName %>(<%- otherEntityTsKeyId %><% if (isUserRelation) { %>, 'user'<% } %>); + const option = <%- generateTestEntityPrimaryKey(otherEntity.primaryKey, 0) %>; const result = comp.getSelected<%= otherEntity.entityAngularName %>(option); expect(result === option).toEqual(true); }); it('Should return selected <%= otherEntity.entityAngularName %> for according option', () => { - const option = new <%= otherEntity.entityAngularName %>(<%- otherEntityTsKeyId %><% if (isUserRelation) { %>, 'user'<% } %>); - const selected = new <%= otherEntity.entityAngularName %>(<%- otherEntityTsKeyId %><% if (isUserRelation) { %>, 'user'<% } %>); - const selected2 = new <%= otherEntity.entityAngularName %>(<%- otherEntityAlternativeTsKeyId %><% if (isUserRelation) { %>, 'user2'<% } %>); + const option = <%- generateTestEntityPrimaryKey(otherEntity.primaryKey, 0) %>; + const selected = <%- generateTestEntityPrimaryKey(otherEntity.primaryKey, 0) %>; + const selected2 = <%- generateTestEntityPrimaryKey(otherEntity.primaryKey, 1) %>; const result = comp.getSelected<%= otherEntity.entityAngularName %>(option, [selected2, selected]); expect(result === selected).toEqual(true); expect(result === selected2).toEqual(false); @@ -276,8 +278,8 @@ _%> }); it('Should return option if this <%= otherEntity.entityAngularName %> is not selected', () => { - const option = new <%= otherEntity.entityAngularName %>(<%- otherEntityTsKeyId %><% if (isUserRelation) { %>, 'user'<% } %>); - const selected = new <%= otherEntity.entityAngularName %>(<%- otherEntityAlternativeTsKeyId %><% if (isUserRelation) { %>, 'user2'<% } %>); + const option = <%- generateTestEntityPrimaryKey(otherEntity.primaryKey, 0) %>; + const selected = <%- generateTestEntityPrimaryKey(otherEntity.primaryKey, 1) %>; const result = comp.getSelected<%= otherEntity.entityAngularName %>(option, [selected]); expect(result === option).toEqual(true); expect(result === selected).toEqual(false); diff --git a/generators/entity-client/templates/common/src/test/javascript/cypress/integration/entity/entity.spec.ts.ejs b/generators/entity-client/templates/common/src/test/javascript/cypress/integration/entity/entity.spec.ts.ejs index 3fc63ae80046..0af73f3a442d 100644 --- a/generators/entity-client/templates/common/src/test/javascript/cypress/integration/entity/entity.spec.ts.ejs +++ b/generators/entity-client/templates/common/src/test/javascript/cypress/integration/entity/entity.spec.ts.ejs @@ -135,7 +135,7 @@ describe('<%= entityClass %> e2e test', () => { .then(({ request, response }) => startingEntitiesCount = response.body.length); cy.get(entityCreateButtonSelector).click({force: true}); cy.getEntityCreateUpdateHeading('<%= entityClass %>'); - <%_ fields.filter(field => !field.id).forEach((field) => { + <%_ fields.filter(field => (!field.id || !field.autoGenerate) && !field.hidden).forEach((field) => { const fieldName = field.fieldName; const fieldNameCapitalized = field.fieldNameCapitalized; const fieldType = field.fieldType; diff --git a/generators/entity-server/templates/partials/save_template.ejs b/generators/entity-server/templates/partials/save_template.ejs index e83896995b6e..38e8ac010452 100644 --- a/generators/entity-server/templates/partials/save_template.ejs +++ b/generators/entity-server/templates/partials/save_template.ejs @@ -43,14 +43,14 @@ if (isUsingMapsId === true) { resultEntity = asEntity(entityInstance); _%> <%= asEntity(entityClass) %> <%= asEntity(entityInstance) %> = <%= dtoToEntity %>(<%= instanceName %>); <%_ if (isUsingMapsId === true) { _%> - <%= mapsIdAssoc.otherEntityPrimaryKeyType %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); + <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); <%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= asEntity(entityInstance) %>::<%_ if (fluentMethods === false) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= mapsIdAssoc.relationshipName %><%_ } _%>); <%_ } _%> <%= asEntity(entityInstance) %> = <%= entityInstance %>Repository.save(<%= asEntity(entityInstance) %>); <%= returnPrefix %> <%= entityToDto %>(<%= asEntity(entityInstance) %>); <%_ } else { resultEntity = 'result'; _%> <%_ if (isUsingMapsId === true) { _%> - <%= mapsIdAssoc.otherEntityPrimaryKeyType %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); + <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); <%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= instanceName %>::<%_ if (fluentMethods === false) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= otherEntityName %><%_ } _%>); <%_ } _%> <%= returnPrefix %> <%= entityInstance %>Repository.save(<%= asEntity(entityInstance) %>); @@ -63,7 +63,7 @@ if (isUsingMapsId === true) { } } else { _%> <%_ if (isUsingMapsId === true && isController === false) { _%> - <%= mapsIdAssoc.otherEntityPrimaryKeyType %> <%= otherEntityName %>Id = <%= entityInstance %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); + <%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= entityInstance %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>(); <%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= entityInstance %>::<%_ if (fluentMethods === false) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= otherEntityName %><%_ } _%>); <%_ } _%> <%= returnPrefix %> <%= entityInstance %>Service.save(<%= instanceName %>); diff --git a/generators/entity/index.js b/generators/entity/index.js index e8ebb27e4d64..6334669a08e3 100644 --- a/generators/entity/index.js +++ b/generators/entity/index.js @@ -499,6 +499,19 @@ class EntityGenerator extends BaseBlueprintGenerator { // Public API method used by the getter and also by Blueprints _preparing() { return { + loadRelationships() { + this.context.relationships.forEach(relationship => { + const otherEntityName = this._.upperFirst(relationship.otherEntityName); + const otherEntity = this.configOptions.sharedEntities[otherEntityName]; + if (!otherEntity) { + throw new Error(`Error looking for otherEntity ${otherEntityName}`); + } + relationship.otherEntity = otherEntity; + otherEntity.otherRelationships = otherEntity.otherRelationships || []; + otherEntity.otherRelationships.push(relationship); + }); + }, + prepareEntityForTemplates() { const entity = this.context; prepareEntityForTemplates(entity, this); @@ -561,19 +574,6 @@ class EntityGenerator extends BaseBlueprintGenerator { } }); }, - - loadRelationships() { - this.context.relationships.forEach(relationship => { - const otherEntityName = this._.upperFirst(relationship.otherEntityName); - const otherEntity = this.configOptions.sharedEntities[otherEntityName]; - if (!otherEntity) { - throw new Error(`Error looking for otherEntity ${otherEntityName}`); - } - relationship.otherEntity = otherEntity; - otherEntity.otherRelationships = otherEntity.otherRelationships || []; - otherEntity.otherRelationships.push(relationship); - }); - }, }; } @@ -620,7 +620,12 @@ class EntityGenerator extends BaseBlueprintGenerator { }, processDerivedPrimaryKey() { - if (!this.context.derivedPrimaryKey) { + if (!this.context.primaryKey) { + return; + } + if (!this.context.primaryKey.derived) { + const derivedFields = this.context.primaryKey.derivedFields; + this.context.fields.unshift(...derivedFields); return; } const idFields = this.context.primaryKey.derivedFields; diff --git a/generators/generator-base-private.js b/generators/generator-base-private.js index aa968cf50d51..7c6b2057b31f 100644 --- a/generators/generator-base-private.js +++ b/generators/generator-base-private.js @@ -1098,18 +1098,24 @@ module.exports = class JHipsterBasePrivateGenerator extends Generator { * * @param {any} primaryKey - primary key definition * @param {number} index - the index of the primary key, currently it's possible to generate 2 values, index = 0 - first key (default), otherwise second key + * @param {boolean} [wrapped=true] - wrapped values for required types. */ - generateTestEntityId(primaryKey, index = 0) { + generateTestEntityId(primaryKey, index = 0, wrapped = true) { if (typeof primaryKey === 'object') { primaryKey = primaryKey.type; } + let value; if (primaryKey === 'String') { - return index === 0 ? "'123'" : "'456'"; + value = index === 0 ? 'ABC' : 'CBA'; + } else if (primaryKey === 'UUID') { + value = index === 0 ? '9fec3727-3421-4967-b213-ba36557ca194' : '1361f429-3817-4123-8ee3-fdf8943310b2'; + } else { + value = index === 0 ? 123 : 456; } - if (primaryKey === 'UUID') { - return index === 0 ? "'9fec3727-3421-4967-b213-ba36557ca194'" : "'1361f429-3817-4123-8ee3-fdf8943310b2'"; + if (wrapped && ['UUID', 'String'].includes(primaryKey)) { + return `'${value}'`; } - return index === 0 ? 123 : 456; + return value; } /** @@ -1118,13 +1124,14 @@ module.exports = class JHipsterBasePrivateGenerator extends Generator { * @param {any} primaryKey - primary key definition. * @param {number} [index] - index of the primary key sample, pass undefined for a random key. */ - generateTestEntityPrimaryKey(primaryKey, index) { + generateTestEntityPrimaryKey(primaryKey, index = 'random') { + const random = index === 'random'; const entries = primaryKey.references.map(reference => { const value = - index === undefined && reference.field ? reference.field.generateFakeData('ts') : this.generateTestEntityId(reference.type, index); - return `${reference.name}: ${value}`; + random && reference.field ? reference.field.generateFakeData('raw') : this.generateTestEntityId(reference.type, index, false); + return [reference.name, value]; }); - return `{${entries.join(',')}}`; + return JSON.stringify(Object.fromEntries(entries)); } /** @@ -1212,23 +1219,23 @@ module.exports = class JHipsterBasePrivateGenerator extends Generator { * @param {string} defaultValue - default value * @returns {string} java primary key value */ - getPrimaryKeyValue(primaryKeyType, databaseType = this.jhipsterConfig.databasetype, defaultValue = 1) { - let value; - switch (primaryKeyType) { - case 'String': - value = `"id${defaultValue}"`; - // Special case with a OneToOne relationship with User and @MapsId when using OAuth - if (databaseType === 'sql') { - value = 'UUID.randomUUID().toString()'; - } - break; - case 'UUID': - value = 'UUID.randomUUID()'; - break; - default: - value = `${defaultValue}L`; + getPrimaryKeyValue(primaryKey, databaseType = this.jhipsterConfig.databaseType, defaultValue = 1) { + if (typeof primaryKey === 'object' && primaryKey.composite) { + return `new ${primaryKey.type}(${primaryKey.references + .map(ref => this.getPrimaryKeyValue(ref.type, databaseType, defaultValue)) + .join(', ')})`; } - return value; + const primaryKeyType = typeof primaryKey === 'string' ? primaryKey : primaryKey.type; + if (primaryKeyType === 'String') { + if (databaseType === 'sql' && defaultValue === 0) { + return 'UUID.randomUUID().toString()'; + } + return `"id${defaultValue}"`; + } + if (primaryKeyType === 'UUID') { + return 'UUID.randomUUID()'; + } + return `${defaultValue}L`; } /** @@ -1669,21 +1676,30 @@ module.exports = class JHipsterBasePrivateGenerator extends Generator { /** * Create a java getter of reference. * - * @param {object} reference + * @param {object|string[]} reference * @return {string} */ buildJavaGet(reference) { - return reference.path.map(partialPath => `get${this.javaBeanCase(partialPath)}()`).join('.'); + let refPath; + if (typeof refPath === 'string') { + refPath = [reference]; + } else if (Array.isArray(reference)) { + refPath = reference; + } else { + refPath = [reference.name]; + } + return refPath.map(partialPath => `get${this.javaBeanCase(partialPath)}()`).join('.'); } /** * Create a dotted path of reference. * - * @param {object} reference + * @param {object|string[]} reference * @return {string} */ buildReferencePath(reference) { - return reference.path.join('.'); + const refPath = Array.isArray(reference) ? reference : reference.path; + return refPath.join('.'); } /** @@ -1708,6 +1724,17 @@ module.exports = class JHipsterBasePrivateGenerator extends Generator { return `set${this.javaBeanCase(reference.name)}(${valueDefinition})`; } + /** + * Create a java getter method of reference. + * + * @param {object} reference + * @param {string} valueDefinition + * @return {string} + */ + buildJavaFluentSetter(reference, valueDefinition = `${reference.type} ${reference.name}`) { + return `${reference.name}(${valueDefinition})`; + } + /** * Create a angular form path getter method of reference. * diff --git a/test/generator-base-private.spec.js b/test/generator-base-private.spec.js index ed2879467380..e8491f02359e 100644 --- a/test/generator-base-private.spec.js +++ b/test/generator-base-private.spec.js @@ -131,8 +131,8 @@ export * from './entityFolderName/entityFileName.state';`; }); }); describe('when called with String', () => { - it("return '123'", () => { - expect(BaseGenerator.generateTestEntityId('String')).to.equal("'123'"); + it("return 'ABC'", () => { + expect(BaseGenerator.generateTestEntityId('String')).to.equal("'ABC'"); }); }); describe('when called with UUID', () => { diff --git a/test/utils-entity.spec.js b/test/utils-entity.spec.js index 5ca23657c67b..39c5a84befd3 100644 --- a/test/utils-entity.spec.js +++ b/test/utils-entity.spec.js @@ -41,6 +41,7 @@ describe('entity utilities', () => { }); it('should adopt id field as @Id', () => { expect(entity.fields[0]).to.eql({ + dynamic: false, fieldName: 'id', fieldType: 'CustomType', id: true, diff --git a/utils/entity.js b/utils/entity.js index a163b003c7e2..b61942b4b06c 100644 --- a/utils/entity.js +++ b/utils/entity.js @@ -23,6 +23,7 @@ const { createFaker } = require('./faker'); const { parseLiquibaseChangelogDate } = require('./liquibase'); const { entityDefaultConfig } = require('../generators/generator-defaults'); const { stringHashCode } = require('../generators/utils'); +const { fieldToReference } = require('./field'); const BASE_TEMPLATE_DATA = { primaryKey: undefined, @@ -180,86 +181,124 @@ function prepareEntityForTemplates(entityWithConfig, generator) { id: true, fieldNameHumanized: 'ID', fieldTranslationKey: 'global.field.id', + autoGenerate: true, }; entityWithConfig.fields.unshift(idField); } entityWithConfig.idFields.push(idField); idCount++; - } - - if (idCount > 1) { - throw new Error('Composite id not implemented'); } else if (entityWithConfig.idRelationships.length > 0) { - const relationshipId = entityWithConfig.idRelationships[0]; - if (relationshipId.relationshipType === 'one-to-one' && idCount === 1) { - relationshipId.id = true; - entityWithConfig.derivedPrimaryKey = relationshipId; - const idFields = entityWithConfig.idFields; - entityWithConfig.primaryKey = { - fieldName: 'id', - derived: true, - get fields() { - return [...idFields, ...this.derivedFields]; - }, + entityWithConfig.idRelationships.forEach(relationship => { + // deprecated property + relationship.useJPADerivedIdentifier = true; + relationship.derivedPrimaryKey = { get derivedFields() { - return relationshipId.otherEntity.primaryKey.fields.map(field => ({ + return relationship.otherEntity.primaryKey.fields.map(field => ({ + originalField: field, ...field, derived: true, - derivedEntity: relationshipId.otherEntity, + derivedEntity: relationship.otherEntity, jpaGeneratedValue: false, liquibaseAutoIncrement: false, + // Mapsid is generated by relationship select + autoGenerate: true, + readonly: true, + get fieldName() { + return idCount === 1 ? field.fieldName : `${relationship.otherEntity.entityInstance}${field.fieldNameCapitalized}`; + }, + get fieldNameCapitalized() { + return idCount === 1 ? field.fieldNameCapitalized : `${relationship.otherEntity.entityClass}${field.fieldNameCapitalized}`; + }, + get columnName() { + return idCount === 1 ? field.columnName : `${generator.getColumnName(relationship.relationshipName)}_${field.columnName}`; + }, + get reference() { + return fieldToReference(entityWithConfig, this); + }, })); }, - relationships: entityWithConfig.idRelationships, - get name() { - return 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 references() { - return [ - ...idFields.map(field => field.reference), - ...relationshipId.otherEntity.primaryKey.references.map(ref => ({ ...ref })), - ]; - }, - get composite() { - return this.references.length > 1; - }, }; - } else { - throw new Error('Composite id not implemented'); - } + }); + } + + if (idCount === 1 && entityWithConfig.idRelationships.length === 1) { + const relationshipId = entityWithConfig.idRelationships[0]; + 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; + }, + relationships: entityWithConfig.idRelationships, + get name() { + return 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 references() { + return this.derivedFields.map(field => field.reference); + }, + get composite() { + return relationshipId.otherEntity.primaryKey.composite; + }, + }; } else { - const idField = entityWithConfig.idFields[0]; - // Allow ids type to be empty and fallback to default type for the database. - if (!idField.fieldType) { - idField.fieldType = generator.getPkType(entityWithConfig.databaseType); + const composite = idCount > 1; + let primaryKeyName; + let primaryKeyType; + if (composite) { + primaryKeyName = 'id'; + primaryKeyType = `${entityWithConfig.entityClass}Id`; + } else { + const idField = entityWithConfig.idFields[0]; + idField.dynamic = false; + // Allow ids type to be empty and fallback to default type for the database. + if (!idField.fieldType) { + idField.fieldType = generator.getPkType(entityWithConfig.databaseType); + } + primaryKeyName = idField.fieldName; + primaryKeyType = idField.fieldType; } + entityWithConfig.primaryKey = { derived: false, - fields: entityWithConfig.idFields, - relationships: [], - name: idField.fieldName, - nameCapitalized: _.upperFirst(idField.fieldName), - type: idField.fieldType, - tsType: generator.getTypescriptKeyType(idField.fieldType), + name: primaryKeyName, + nameCapitalized: _.upperFirst(primaryKeyName), + type: primaryKeyType, + tsType: generator.getTypescriptKeyType(primaryKeyType), + composite, + relationships: entityWithConfig.idRelationships, + get fields() { + return [...entityWithConfig.idFields, ...this.derivedFields]; + }, + get autoGenerate() { + return this.composite ? false : this.fields[0].autoGenerate; + }, get references() { - return entityWithConfig.idFields.map(field => field.reference); + return this.fields.map(field => field.reference); + }, + get derivedFields() { + return this.relationships.map(rel => rel.derivedPrimaryKey.derivedFields).flat(); }, - composite: entityWithConfig.idFields.length > 1, }; } } entityWithConfig.generateFakeData = type => { - const fieldsToGenerate = type === 'cypress' ? entityWithConfig.fields.filter(field => !field.id) : entityWithConfig.fields; + 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; diff --git a/utils/field.js b/utils/field.js index 76d1e6ec712b..5e9ab85417d8 100644 --- a/utils/field.js +++ b/utils/field.js @@ -163,9 +163,9 @@ function prepareFieldForTemplates(entityWithConfig, field, generator) { fieldNameUnderscored: _.snakeCase(field.fieldName), fieldNameHumanized: _.startCase(field.fieldName), fieldTranslationKey: `${entityWithConfig.i18nKeyPrefix}.${field.fieldName}`, + tsType: generator.getTypescriptKeyType(field.fieldType), }); const fieldType = field.fieldType; - if (field.mapstructExpression) { assert.equal( entityWithConfig.dto, @@ -179,15 +179,20 @@ function prepareFieldForTemplates(entityWithConfig, field, generator) { } if (field.id) { - if (field.autoGenerate === false || !['Long', 'UUID'].includes(field.fieldType)) { + if (field.autoGenerate === undefined) { + field.autoGenerate = !entityWithConfig.primaryKey.composite && ['Long', 'UUID'].includes(field.fieldType); + } + if (!field.autoGenerate) { field.liquibaseAutoIncrement = false; field.jpaGeneratedValue = false; } else if (entityWithConfig.reactive) { field.liquibaseAutoIncrement = true; field.jpaGeneratedValue = false; + field.readonly = true; } else { const defaultGenerationType = entityWithConfig.prodDatabaseType === 'mysql' ? 'identity' : 'sequence'; field.jpaGeneratedValue = field.jpaGeneratedValue || field.fieldType === 'Long' ? defaultGenerationType : true; + field.readonly = true; if (field.jpaGeneratedValue === 'identity') { field.liquibaseAutoIncrement = true; } @@ -354,4 +359,4 @@ function fieldToReference(entity, field, pathPrefix = []) { }; } -module.exports = { prepareFieldForTemplates, fieldIsEnum, getEnumValuesWithCustomValues }; +module.exports = { prepareFieldForTemplates, fieldIsEnum, getEnumValuesWithCustomValues, fieldToReference }; diff --git a/utils/index.js b/utils/index.js index cd1f5fab71fe..fbbb307dc062 100644 --- a/utils/index.js +++ b/utils/index.js @@ -37,6 +37,15 @@ module.exports = { if (key === 'otherRelationship') { return `[${value.relationshipName} relationship]`; } + if (key === 'otherRelationships') { + return '[otherRelationships]'; + } + if (key === 'derivedPrimaryKey') { + return `[${value.type} derivedPrimaryKey]`; + } + if (key === 'derivedFields') { + return '[derivedFields]'; + } return value; }, 4 diff --git a/utils/relationship.js b/utils/relationship.js index 8e39c08713bc..8242db7d90f6 100644 --- a/utils/relationship.js +++ b/utils/relationship.js @@ -31,13 +31,8 @@ function prepareRelationshipForTemplates(entityWithConfig, relationship, generat throw new Error(`Error at entity ${entityName}: could not find the entity of the relationship ${stringify(relationship)}`); } const otherEntityData = relationship.otherEntity; - if (otherEntityData.primaryKey) { - _.defaults(relationship, { - // otherEntityField should be id if not specified - otherEntityField: otherEntityData.primaryKey.name, - }); - relationship.otherEntityPrimaryKeyType = otherEntityData.primaryKey.type; - relationship.otherEntityField = relationship.otherEntityField || otherEntityData.primaryKey.name; + if (!relationship.otherEntityField && otherEntityData.primaryKey) { + relationship.otherEntityField = otherEntityData.primaryKey.name; } _.defaults(relationship, { From c06a8e971c40d24f1ed4859b34eea9227846472b Mon Sep 17 00:00:00 2001 From: Marcelo Boveto Shima Date: Fri, 5 Feb 2021 14:59:39 -0300 Subject: [PATCH 2/3] Move entity.idFields to entity.primaryKey.ownFields. --- .../liquibase/changelog/added_entity.xml.ejs | 2 +- .../added_entity_constraints.xml.ejs | 8 ++--- .../package/service/dto/EntityDTO.java.ejs | 2 +- .../service/mapper/EntityMapper.java.ejs | 4 +-- generators/entity/index.js | 1 - utils/entity.js | 32 ++++++++++++------- utils/relationship.js | 1 - 7 files changed, 28 insertions(+), 22 deletions(-) diff --git a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs index 1a7f10419a6e..953b08c17fa9 100644 --- a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs +++ b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs @@ -48,7 +48,7 @@ <%_ for (relationship of relationships) { if (relationship.relationshipType === 'many-to-one' || (relationship.relationshipType === 'one-to-one' && relationship.ownerSide === true && (relationship.id == null || relationship.id === false))) { - relationship.otherEntity.idFields.forEach(idField => { + relationship.otherEntity.primaryKey.ownFields.forEach(idField => { const uniqueConstraintName = relationship.relationshipType === 'one-to-one' ? getUXConstraintName(entity.entityTableName, relationship.columnName + '_' + idField.columnName, entity.prodDatabaseType) : null; _%> diff --git a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs index 4f70546f36d5..e98ff78572dd 100644 --- a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs +++ b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs @@ -35,11 +35,11 @@ let baseColumnNames; let referencedColumnNames; if (relationshipType === 'one-to-one' && ownerSide && relationship.id === true) { - baseColumnNames = relationship.otherEntity.idFields.map(field => getColumnName(field.columnName)).join(','); - referencedColumnNames = relationship.otherEntity.idFields.map(field => getColumnName(field.columnName)).join(','); + baseColumnNames = relationship.otherEntity.primaryKey.ownFields.map(field => getColumnName(field.columnName)).join(','); + referencedColumnNames = relationship.otherEntity.primaryKey.ownFields.map(field => getColumnName(field.columnName)).join(','); } else if (relationship.otherEntity) { - baseColumnNames = relationship.otherEntity.idFields.map(field => getColumnName(relationshipName + '_' + field.columnName)).join(','); - referencedColumnNames = relationship.otherEntity.idFields.map(field => getColumnName(field.columnName)).join(','); + baseColumnNames = relationship.otherEntity.primaryKey.ownFields.map(field => getColumnName(relationshipName + '_' + field.columnName)).join(','); + referencedColumnNames = relationship.otherEntity.primaryKey.ownFields.map(field => getColumnName(field.columnName)).join(','); } %> <%_ } _%> <%_ } _%> -<%_ const idNames = [...idFields.map(f => f.fieldName)] _%> +<%_ const idNames = primaryKey ? [...primaryKey.ownFields.map(f => f.fieldName)] : [] _%> @Override public boolean equals(Object o) { if (this == o) { diff --git a/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs b/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs index c254b66d6c1d..aa87038f9cca 100644 --- a/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs +++ b/generators/entity-server/templates/src/main/java/package/service/mapper/EntityMapper.java.ejs @@ -108,9 +108,9 @@ public interface <%= entityClass %>Mapper extends EntityMapper<<%= asDto(entityC <%_ if (!embedded) { // DTO -> entity mapping var renMapAnotDto = false; //Render Mapping Annotation during DTO to Entity conversion? - if(idFields.length > 1) { + if(primaryKey.ownFields.length > 1) { renMapAnotDto = true; - idFields.map(field => field.reference).forEach(reference => { _%> + primaryKey.ownFields.map(field => field.reference).forEach(reference => { _%> @Mapping(target = "id.<%= reference.name %>", source = "<%= buildReferencePath(reference) %>") <%_ }) diff --git a/generators/entity/index.js b/generators/entity/index.js index 6334669a08e3..c38a2dc67a28 100644 --- a/generators/entity/index.js +++ b/generators/entity/index.js @@ -629,7 +629,6 @@ class EntityGenerator extends BaseBlueprintGenerator { return; } const idFields = this.context.primaryKey.derivedFields; - this.context.idFields = idFields; this.context.fields.unshift(...idFields); }, diff --git a/utils/entity.js b/utils/entity.js index b61942b4b06c..ec6c7ec1e8f7 100644 --- a/utils/entity.js +++ b/utils/entity.js @@ -167,9 +167,9 @@ function prepareEntityForTemplates(entityWithConfig, generator) { entityWithConfig.dto === 'no'; if (!entityWithConfig.embedded) { - entityWithConfig.idFields = entityWithConfig.fields.filter(field => field.id); - entityWithConfig.idRelationships = entityWithConfig.relationships.filter(relationship => relationship.id); - let idCount = entityWithConfig.idFields.length + entityWithConfig.idRelationships.length; + 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'); @@ -185,12 +185,13 @@ function prepareEntityForTemplates(entityWithConfig, generator) { }; entityWithConfig.fields.unshift(idField); } - entityWithConfig.idFields.push(idField); + idFields.push(idField); idCount++; - } else if (entityWithConfig.idRelationships.length > 0) { - entityWithConfig.idRelationships.forEach(relationship => { + } else if (idRelationships.length > 0) { + idRelationships.forEach(relationship => { // deprecated property relationship.useJPADerivedIdentifier = true; + // 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 => ({ @@ -221,8 +222,11 @@ function prepareEntityForTemplates(entityWithConfig, generator) { }); } - if (idCount === 1 && entityWithConfig.idRelationships.length === 1) { - const relationshipId = entityWithConfig.idRelationships[0]; + 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, @@ -234,7 +238,10 @@ function prepareEntityForTemplates(entityWithConfig, generator) { get derivedFields() { return relationshipId.derivedPrimaryKey.derivedFields; }, - relationships: entityWithConfig.idRelationships, + get ownFields() { + return relationshipId.otherEntity.primaryKey.ownFields; + }, + relationships: idRelationships, get name() { return relationshipId.otherEntity.primaryKey.name; }, @@ -262,7 +269,7 @@ function prepareEntityForTemplates(entityWithConfig, generator) { primaryKeyName = 'id'; primaryKeyType = `${entityWithConfig.entityClass}Id`; } else { - const idField = entityWithConfig.idFields[0]; + const idField = idFields[0]; idField.dynamic = false; // Allow ids type to be empty and fallback to default type for the database. if (!idField.fieldType) { @@ -279,9 +286,10 @@ function prepareEntityForTemplates(entityWithConfig, generator) { type: primaryKeyType, tsType: generator.getTypescriptKeyType(primaryKeyType), composite, - relationships: entityWithConfig.idRelationships, + relationships: idRelationships, + ownFields: idFields, get fields() { - return [...entityWithConfig.idFields, ...this.derivedFields]; + return [...idFields, ...this.derivedFields]; }, get autoGenerate() { return this.composite ? false : this.fields[0].autoGenerate; diff --git a/utils/relationship.js b/utils/relationship.js index 8242db7d90f6..1f853609a948 100644 --- a/utils/relationship.js +++ b/utils/relationship.js @@ -258,7 +258,6 @@ function relationshipToReference(entity, relationship, pathPrefix = []) { return relationship.otherEntity.primaryKey ? relationship.otherEntity.primaryKey.type : undefined; }, path: [...pathPrefix, name], - idReferences: relationship.otherEntity.idFields ? relationship.otherEntity.idFields.map(field => field.reference) : [], valueReference: relationship.relatedField && relationship.relatedField.reference, }; return reference; From 698dde79b03345966e8b85120c0adcf2f1a4234a Mon Sep 17 00:00:00 2001 From: Marcelo Boveto Shima Date: Fri, 5 Feb 2021 17:07:51 -0300 Subject: [PATCH 3/3] Use only first id. --- utils/entity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/entity.js b/utils/entity.js index ec6c7ec1e8f7..9e8b2a3c69d8 100644 --- a/utils/entity.js +++ b/utils/entity.js @@ -262,7 +262,7 @@ function prepareEntityForTemplates(entityWithConfig, generator) { }, }; } else { - const composite = idCount > 1; + const composite = false; let primaryKeyName; let primaryKeyType; if (composite) {
<%= jhiPrefix %>SortBy="<%= field.fieldName %>"<% } %>>Translate="<%= field.fieldTranslationKey %>"><%= field.fieldNameHumanized %><% if (pagination !== 'no') { %> <% } %>