Skip to content

Commit

Permalink
(fix): Allow override of primary key type (#1430)
Browse files Browse the repository at this point in the history
* (fix): Allow override of primary key type

* Fix code formatting

* Conditionally add nullable operator

* Add Guid handling in domain and repository classes

* Simplify primary key type usage

* Use update sub-command instead of install

* Remove unnecessary nullable operator

* Respect primary key override

* Add entity with UUID primary key

* Fix Blazor primary key override handling

* Fix null primary key handling

* Add using statement

* Fix formatting

* Fix Blazor generation

* Handle mongodb database types correctly

* Add missing using and remove unused functions

* Handle mongodb primary key

* Handle testing DateTime and LocalDate

* Fix formatting

* Fix linting errors

* Handle null IDs

* Fix code smells

* Fix linting and formatting errors

* Remove duplicate functions

* Use mongodb-friendly string

* Provide ID type for conversion

---------

Co-authored-by: Alrick Telfer <[email protected]>
  • Loading branch information
JeSuisAlrick and KCL-TelferAA authored Dec 22, 2023
1 parent d995469 commit 48f7d73
Show file tree
Hide file tree
Showing 33 changed files with 421 additions and 78 deletions.
16 changes: 16 additions & 0 deletions .blueprint/generate-sample/templates/samples/jdl-default/app.jdl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ entity JobHistory {
language Language
}

entity TimeSheet {
id UUID
timeSheetDate LocalDate
}

entity TimeSheetEntry {
activityName String
startTimeMilitary Integer
endTimeMilitary Integer
totalTime BigDecimal
}

enum Language {
FRENCH, ENGLISH, SPANISH
}
Expand Down Expand Up @@ -85,6 +97,10 @@ relationship OneToMany {
* Another side of the same relationship
*/
Employee{department}

Employee to TimeSheet{employee}

TimeSheet to TimeSheetEntry{timeSheet}
}

relationship ManyToOne {
Expand Down
57 changes: 53 additions & 4 deletions generators/blazor/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import { createNeedleCallback } from 'generator-jhipster/generators/base/support
import { CLIENT_SRC_DIR, CLIENT_TEST_DIR } from '../generator-dotnetcore-constants.js';
import { files } from './files-blazor.js';
import { entityFiles } from './entities-blazor.js';
import {
getNonNullableType,
getNullableResolvedType,
isNumericPrimaryKey,
getPrimaryKeyType,
defaultNilValue,
defaultValue,
updatedValue,
} from '../utils.js';

export default class extends BaseApplicationGenerator {
constructor(args, opts, features) {
Expand Down Expand Up @@ -91,6 +100,43 @@ export default class extends BaseApplicationGenerator {
...entity,
asDto: str => `${str}${application.dtoSuffix}`,
asModel: str => `${str}${application.modelSuffix}`,
getNullableResolvedType,
getPrimaryKeyType,
isNumericPrimaryKey,
defaultValue,
defaultNilValue,
updatedValue,
getNonNullableType,
enumDefaultValue: field => {
const enums = field.fieldValues.split(',').map(fieldValue => fieldValue.trim());
if (enums.length > 0) {
return `${field.fieldType}.${enums[0]}`;
}
return 'null';
},
enumUpdatedValue: field => {
const enums = field.fieldValues.split(',').map(fieldValue => fieldValue.trim());
if (enums.length > 1) {
return `${field.fieldType}.${enums[1]}`;
}
return 'null';
},
hasDateTimeTypeField: fields => {
let dateTimeTypeField = false;
let idx = 0;
while (idx < fields.length && !dateTimeTypeField) {
if (
fields[idx].fieldType === 'LocalDate' ||
fields[idx].fieldType === 'Instant' ||
fields[idx].fieldType === 'ZonedDateTime' ||
fields[idx].fieldType === 'Duration'
) {
dateTimeTypeField = true;
}
idx += 1;
}
return dateTimeTypeField;
},
},
});
}
Expand Down Expand Up @@ -156,9 +202,12 @@ export default class extends BaseApplicationGenerator {
await this.spawnCommand('libman');
} catch (error) {
try {
await this.spawnCommand('dotnet tool install -g Microsoft.Web.LibraryManager.Cli');
// If a tool is already installed the install sub-command will return 1
// We'll use the update sub-command which behaves the way we'd expected.
// See: https://github.com/dotnet/sdk/issues/9500
await this.spawnCommand('dotnet tool update -g Microsoft.Web.LibraryManager.Cli');
} catch (error) {
throw new Error('Could not install Microsoft.Web.LibraryManager.Cli');
throw new Error('Could not install/update Microsoft.Web.LibraryManager.Cli');
}
this.log(chalk.green.bold('Microsoft.Web.LibraryManager.Cli successfully installed.\n'));
}
Expand All @@ -167,9 +216,9 @@ export default class extends BaseApplicationGenerator {
await this.spawnCommand('webcompiler');
} catch (error) {
try {
await this.spawnCommand('dotnet tool install Excubo.WebCompiler --global');
await this.spawnCommand('dotnet tool update Excubo.WebCompiler --global');
} catch (error) {
throw new Error('Could not install Excubo.WebCompiler');
throw new Error('Could not install/update Excubo.WebCompiler');
}
this.log(chalk.green.bold('Excubo.WebCompiler successfully installed.\n'));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ public class <%= asModel(entityClassName) %> : BaseModel<<%= primaryKeyType %>>
[Required]
<%_ } _%>
<%_ if (fields[idx].fieldIsEnum) { _%>
public <%= fields[idx].fieldType %> <%= fieldNamePascalized %> { get; set; }
public <%= getNullableResolvedType(fields[idx].fieldType, required) %> <%= fieldNamePascalized %> { get; set; }
<%_ } else { _%>
public <%= fieldType %> <%= fieldNamePascalized %> { get; set; }
public <%= getNullableResolvedType(fieldType, required) %> <%= fieldNamePascalized %> { get; set; }
<%_ } _%>
<%_ }
for (idx in relationships) {
Expand All @@ -67,7 +67,7 @@ public class <%= asModel(entityClassName) %> : BaseModel<<%= primaryKeyType %>>
if(otherEntityNamePascalized === 'User') { _%>
public string UserId { get; set; }
<%_ } else { _%>
public <%= primaryKeyType _%> <%_ if(primaryKeyType !== 'string') { _%>?<%_ } %> <%= relationshipFieldNamePascalized %>Id { get; set; }
public <%= getPrimaryKeyType(relationships[idx].otherEntity) %> <%= relationshipFieldNamePascalized %>Id { get; set; }
<%_ }
}
if(relationshipType === 'one-to-many') { _%>
Expand All @@ -79,7 +79,7 @@ public class <%= asModel(entityClassName) %> : BaseModel<<%= primaryKeyType %>>
if(otherEntityNamePascalized === 'User') { _%>
public string UserId { get; set; }
<%_ } else { _%>
public <%= primaryKeyType _%> <%_ if(primaryKeyType !== 'string') { _%>?<%_ } %> <%= relationshipFieldNamePascalized %>Id { get; set; }
public <%= getPrimaryKeyType(relationships[idx].otherEntity) %> <%= relationshipFieldNamePascalized %>Id { get; set; }
<%_ }
} else if (relationshipType === 'many-to-many') { _%>
public IList<<%= asModel(otherEntityNamePascalized) %>> <%= relationshipFieldNamePascalizedPlural %> { get; set; } = new List<<%= asModel(otherEntityNamePascalized) %>>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const entityClassName = pascalizedEntityClass;
const entityVariableName = camelCasedEntityClass;
const entityClassNamePluralized = pascalizedEntityClassPlural;
_%>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ _%>
<%_ if(relation.otherEntityNamePascalized === 'User') { _%>
@if (<%= lowerCasedEntityClass %>.<%= relation.relationshipFieldNamePascalized %>Id != string.Empty)
<%_ } else { _%>
<%_ if(primaryKeyType !== 'string') { %>
<%_ if (isNumericPrimaryKey(getPrimaryKeyType(relation.otherEntity))) { _%>
@if (<%= lowerCasedEntityClass %>.<%= relation.relationshipFieldNamePascalized %>Id != 0)
<%_ } else { _%>
<%_ } else { _%>
@if (<%= lowerCasedEntityClass %>.<%= relation.relationshipFieldNamePascalized %>Id != null)
<%_ } _%>
<%_ } _%>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const entityClassName = pascalizedEntityClass;
const entityVariableName = camelCasedEntityClass;
const entityClassNamePluralized = pascalizedEntityClassPlural;
_%>
using System;
using System.Threading.Tasks;
using <%= namespace %>.Client.Models;
using <%= namespace %>.Client.Pages.Utils;
Expand All @@ -42,8 +43,8 @@ namespace <%= namespace %>.Client.Pages.Entities.<%= entityClassName %>

protected override async Task OnInitializedAsync()
{
<%_ if(primaryKeyType !== 'string') { %>
if (Id != 0)
<%_ if (isNumericPrimaryKey(primaryKeyType)) { _%>
if (Id != 0 && Id != null)
<%_ } else { _%>
if (Id != null)
<%_ } _%>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ const entityClassName = pascalizedEntityClass;
const entityVariableName = camelCasedEntityClass;
const entityClassNamePluralized = pascalizedEntityClassPlural;
_%>
@page "/<%= lowerCasedEntityClass %>/{Id<%_ if(primaryKeyType !== 'string') { %>:<%= primaryKeyType %> <%_ } _%> }/view"
@page "/<%= lowerCasedEntityClass %>/{Id<%_ if(primaryKeyType !== 'string') { %>:<%= getNonNullableType(primaryKeyType) %> <%_ } _%> }/view"
@using Microsoft.AspNetCore.Authorization
@namespace <%= namespace %>.Client.Pages.Entities.<%= entityClassName %>

@attribute [Authorize(Roles = "ROLE_USER")]

<div class="row justify-content-center">
<div class="col-8">
<%_ if(primaryKeyType !== 'string') { %>
@if (<%= entityClassName %> != null && <%= entityClassName %>.Id != 0)
<%_ if (isNumericPrimaryKey(primaryKeyType)) { _%>
@if (<%= entityClassName %> != null && <%= entityClassName %>.Id != 0 && <%= entityClassName %>.Id.ToString().Length > 0)
<%_ } else { _%>
@if (<%= entityClassName %> != null && <%= entityClassName %>.Id != null)
<%_ } _%>
Expand All @@ -41,9 +41,9 @@ _%>
<%_ if(relation.otherEntityNamePascalized === 'User') { _%>
@if (<%= entityClassName %>.<%= relation.relationshipFieldNamePascalized %>Id != string.Empty)
<%_ } else { _%>
<%_ if(primaryKeyType !== 'string') { %>
<%_ if (isNumericPrimaryKey(getPrimaryKeyType(relation.otherEntity))) { _%>
@if (<%= entityClassName %>.<%= relation.relationshipFieldNamePascalized %>Id != 0)
<%_ } else { _%>
<%_ } else { _%>
@if (<%= entityClassName %>.<%= relation.relationshipFieldNamePascalized %>Id != null)
<%_ } _%>
<%_ } _%>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const entityClassName = pascalizedEntityClass;
const entityVariableName = camelCasedEntityClass;
const entityClassNamePluralized = pascalizedEntityClassPlural;
_%>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -64,47 +65,50 @@ namespace <%= namespace %>.Client.Pages.Entities.<%= entityClassName %>
public <%= asModel(entityClassName) %> <%= asModel(entityClassName) %> { get; set; } = new <%= asModel(entityClassName) %>();

<%_ relationships.forEach(relation => { _%>
<%_ var relationPrimaryKeyType = getPrimaryKeyType(relation.otherEntity); _%>
<%_ if (relation.relationshipType === 'one-to-one' || relation.relationshipType === 'many-to-one') {
if(relation.otherEntityNamePascalized === 'User') { _%>
public IEnumerable<string> <%= relation.otherEntityNamePascalized %>Ids { get; set; } = new List<string>();
public string <%= relation.otherEntityNamePascalized %>Id { get; set; }
<%_ } else { _%>
public IEnumerable<<%= primaryKeyType %>> <%= relation.otherEntityNamePascalized %>Ids { get; set; } = new List<<%= primaryKeyType %>>();
public IEnumerable<<%= relationPrimaryKeyType %>> <%= relation.otherEntityNamePascalized %>Ids { get; set; } = new List<<%= relationPrimaryKeyType %>>();
public <%= primaryKeyType _%> <%_ if(primaryKeyType !== 'string') { _%>?<%_ } %> <%= relation.otherEntityNamePascalized %>Id { get; set; }
public <%= relationPrimaryKeyType %> <%= relation.otherEntityNamePascalized %>Id { get; set; }
<%_ } _%>
<%_ } else if ((relation.relationshipType === 'many-to-many' || relation.relationshipType === 'one-to-many') && relation.ownerSide === true ) { _%>
public IReadOnlyList<<%= primaryKeyType %>> <%= relation.otherEntityNamePascalized %>Ids { get; set; } = new List<<%= primaryKeyType %>>();
public IReadOnlyList<<%= relationPrimaryKeyType %>> <%= relation.otherEntityNamePascalized %>Ids { get; set; } = new List<<%= relationPrimaryKeyType %>>();
public IReadOnlyList<<%= primaryKeyType %>> Selected<%= relation.relationshipFieldNamePascalizedPlural %> { get; set; }
public IReadOnlyList<<%= relationPrimaryKeyType %>> Selected<%= relation.relationshipFieldNamePascalizedPlural %> { get; set; }
<%_ }
}); _%>
protected override async Task OnInitializedAsync()
{
<%_ relationships.forEach(relation => {
var relationPrimaryKeyType = getPrimaryKeyType(relation.otherEntity);
if (relation.relationshipType === 'one-to-one' || relation.relationshipType === 'many-to-one') { _%>
<%= relation.relationshipFieldNamePascalizedPlural %> = await <%= relation.otherEntityNamePascalized %>Service.GetAll();
<%= relation.otherEntityNamePascalized %>Ids = <%= relation.relationshipFieldNamePascalizedPlural %>.Select(<%= relation.otherEntityNameLowerCased %> => <%= relation.otherEntityNameLowerCased %>.Id).ToList();
<%_ } else if ((relation.relationshipType === 'many-to-many' || relation.relationshipType === 'one-to-many') && relation.ownerSide === true ) { _%>
<%= relation.relationshipFieldNamePascalizedPlural %> = await <%= relation.otherEntityNamePascalized %>Service.GetAll();
<%= relation.otherEntityNamePascalized %>Ids = <%= relation.relationshipFieldNamePascalizedPlural %>.Select(<%= relation.otherEntityNameLowerCased %> => <%= relation.otherEntityNameLowerCased %>.Id).ToList();
<%_ }}); _%>
<%_ if(primaryKeyType !== 'string') { %>
if (Id != 0)
<%_ if(isNumericPrimaryKey(primaryKeyType)) { %>
if (Id != 0 && Id != null)
<%_ } else { _%>
if (Id != null)
<%_ } _%>
{
<%= asModel(entityClassName) %> = await <%= entityClassName %>Service.Get(Id.ToString());
<%_ relationships.forEach(relation => {
var relationPrimaryKeyType = getPrimaryKeyType(relation.otherEntity);
if (relation.relationshipType === 'one-to-one' || relation.relationshipType === 'many-to-one') { _%>
<%= relation.otherEntityNamePascalized %>Id = <%= asModel(entityClassName) %>.<%= relation.relationshipFieldNamePascalized %>Id;
<%_ } else if ((relation.relationshipType === 'many-to-many' || relation.relationshipType === 'one-to-many') && relation.ownerSide === true ) { _%>
Selected<%= relation.relationshipFieldNamePascalizedPlural %> = new List<<%= primaryKeyType %>>(<%= asModel(entityClassName) %>.<%= relation.relationshipFieldNamePascalizedPlural %>.Select(<%= relation.otherEntityNameLowerCased %> => <%= relation.otherEntityNameLowerCased %>.Id));
Selected<%= relation.relationshipFieldNamePascalizedPlural %> = new List<<%= relationPrimaryKeyType %>>(<%= asModel(entityClassName) %>.<%= relation.relationshipFieldNamePascalizedPlural %>.Select(<%= relation.otherEntityNameLowerCased %> => <%= relation.otherEntityNameLowerCased %>.Id));
<%_ }
}); _%>
}
Expand All @@ -118,6 +122,7 @@ namespace <%= namespace %>.Client.Pages.Entities.<%= entityClassName %>
private async Task Save()
{
<%_ relationships.forEach(relation => {
var relationPrimaryKeyType = getPrimaryKeyType(relation.otherEntity);
if (relation.relationshipType === 'one-to-one' || relation.relationshipType === 'many-to-one') { _%>
<%= asModel(entityClassName) %>.<%= relation.relationshipFieldNamePascalized %>Id = <%= relation.relationshipFieldNamePascalizedPlural %>?.SingleOrDefault(<%= relation.otherEntityNameLowerCased %> => <%= relation.otherEntityNameLowerCased %>.Id.Equals(<%= relation.otherEntityNamePascalized %>Id))?.Id;
<%_ } else if ((relation.relationshipType === 'many-to-many' || relation.relationshipType === 'one-to-many') && relation.ownerSide === true ) { _%>
Expand All @@ -130,8 +135,8 @@ namespace <%= namespace %>.Client.Pages.Entities.<%= entityClassName %>
<%= asModel(entityClassName) %>.<%= relation.relationshipFieldNamePascalizedPlural %> = null;
}
<%_ }}); _%>
<%_ if(primaryKeyType !== 'string') { %>
if (Id != 0)
<%_ if(isNumericPrimaryKey(primaryKeyType)) { %>
if (Id != 0 && Id != null)
<%_ } else { _%>
if (Id != null)
<%_ } _%>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const entityVariableName = camelCasedEntityClass;
const entityClassNamePluralized = pascalizedEntityClassPlural;
_%>
@page "/<%= lowerCasedEntityClass %>/new"
@page "/<%= lowerCasedEntityClass %>/{Id<%_ if(primaryKeyType !== 'string') { %>:<%= primaryKeyType %> <%_ } _%> }/edit"
@page "/<%= lowerCasedEntityClass %>/{Id<%_ if(primaryKeyType !== 'string') { %>:<%= getNonNullableType(primaryKeyType) %> <%_ } _%> }/edit"
@using Microsoft.AspNetCore.Authorization
@namespace <%= namespace %>.Client.Pages.Entities.<%= entityClassName %>

Expand All @@ -22,8 +22,8 @@ _%>
<jhi-alert-error></jhi-alert-error>
*@

<%_ if(primaryKeyType !== 'string') { %>
@if (Id != 0)
<%_ if(isNumericPrimaryKey(primaryKeyType)) { %>
@if (Id != 0 && Id.ToString().Length > 0)
<%_ } else { _%>
@if (Id != null)
<%_ } _%>
Expand Down Expand Up @@ -59,7 +59,7 @@ _%>
<option value="0"></option>
@foreach (var <%= relation.otherEntityNameLowerCased %> in <%= relation.otherEntityNamePascalized %>Ids)
{
if (Id <% if(primaryKeyType !== 'string') { %> != 0 <%_ } else { _%> != null <%_ } _%> && <%= relation.otherEntityNameLowerCased %> == <%= asModel(entityClassName) %>?.<%= relation.relationshipFieldNamePascalized %>Id)
if (Id <% if(isNumericPrimaryKey(primaryKeyType)) { %> != 0 <%_ } else { _%> != null <%_ } _%> && <%= relation.otherEntityNameLowerCased %> == <%= asModel(entityClassName) %>?.<%= relation.relationshipFieldNamePascalized %>Id)
{
<option selected="selected">@<%= relation.otherEntityNameLowerCased %></option>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const entityTableName = snakeCasedEntityClass;
const entityClassName = pascalizedEntityClass;
const entityVariableName = camelCasedEntityClass;
_%>
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using <%= namespace %>.Client.Models;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const entityTableName = snakeCasedEntityClass;
const entityClassName = pascalizedEntityClass;
const entityVariableName = camelCasedEntityClass;
_%>
using System;
using System.Net.Http;
using AutoMapper;
using <%= namespace %>.Client.Models;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public class <%= entityClassName %>DetailTest : TestContext
//Arrange
var <%= lowerCasedEntityClass %> = _fixture.Create<<%= asModel(entityClassName) %>>();
_<%= lowerCasedEntityClass %>Service.Setup(service => service.Get(It.IsAny<string>())).Returns(Task.FromResult(<%= lowerCasedEntityClass %>));
var <%= lowerCasedEntityClass %>Detail = RenderComponent<<%= entityClassName %>Detail>(ComponentParameter.CreateParameter("Id", <% if(primaryKeyType !== 'string') { _%> 1L <%_ } else { _%> "1" <%_ } _%>));
var <%= lowerCasedEntityClass %>Detail = RenderComponent<<%= entityClassName %>Detail>(ComponentParameter.CreateParameter("Id", <%= lowerCasedEntityClass %>.Id));

// Act
var title = <%= lowerCasedEntityClass %>Detail.Find("h2");
Expand Down
Loading

0 comments on commit 48f7d73

Please sign in to comment.