Skip to content

Commit

Permalink
feat: composite id backend support
Browse files Browse the repository at this point in the history
  • Loading branch information
yelhouti committed Sep 27, 2022
1 parent f785acd commit 51e38a6
Show file tree
Hide file tree
Showing 37 changed files with 638 additions and 305 deletions.
53 changes: 10 additions & 43 deletions generators/bootstrap-application/generator.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ const filterEntity = entity => ({
ownFields: '[ownFields] getter',
fields: '[fields] getter',
derivedFields: '[derivedFields] getter',
ids: entity.primaryKey.ids.map(id => ({
...id,
field: `[field] ${id.field.fieldName}`,
})),
ids: '[ids] getter',
},
});

Expand Down Expand Up @@ -207,6 +204,8 @@ Object {
"fieldName": "id",
"fieldNameAsDatabaseColumn": "id",
"fieldNameCapitalized": "Id",
"fieldNameDotted": "id",
"fieldNameDottedAsserted": "id!",
"fieldNameHumanized": "ID",
"fieldNameUnderscored": "id",
"fieldTranslationKey": "global.field.id",
Expand Down Expand Up @@ -517,19 +516,7 @@ Object {
"fields": "[fields] getter",
"hasLong": true,
"hasUUID": false,
"ids": Array [
Object {
"autoGenerate": true,
"field": "[field] id",
"getter": "getId",
"name": "id",
"nameCapitalized": "Id",
"nameDotted": "id",
"nameDottedAsserted": "id!",
"relationshipsPath": Array [],
"setter": "setId",
},
],
"ids": "[ids] getter",
"name": "id",
"nameCapitalized": "Id",
"ownFields": "[ownFields] getter",
Expand Down Expand Up @@ -631,6 +618,8 @@ Object {
"fieldName": "id",
"fieldNameAsDatabaseColumn": "id",
"fieldNameCapitalized": "Id",
"fieldNameDotted": "id",
"fieldNameDottedAsserted": "id!",
"fieldNameHumanized": "Id",
"fieldNameUnderscored": "id",
"fieldTranslationKey": "jhipsterApp.entityA.id",
Expand Down Expand Up @@ -739,19 +728,7 @@ Object {
"fields": "[fields] getter",
"hasLong": false,
"hasUUID": true,
"ids": Array [
Object {
"autoGenerate": true,
"field": "[field] id",
"getter": "getId",
"name": "id",
"nameCapitalized": "Id",
"nameDotted": "id",
"nameDottedAsserted": "id!",
"relationshipsPath": Array [],
"setter": "setId",
},
],
"ids": "[ids] getter",
"name": "id",
"nameCapitalized": "Id",
"ownFields": "[ownFields] getter",
Expand Down Expand Up @@ -909,6 +886,8 @@ Object {
"fieldName": "id",
"fieldNameAsDatabaseColumn": "id",
"fieldNameCapitalized": "Id",
"fieldNameDotted": "id",
"fieldNameDottedAsserted": "id!",
"fieldNameHumanized": "Id",
"fieldNameUnderscored": "id",
"fieldTranslationKey": "jhipsterApp.entityA.id",
Expand Down Expand Up @@ -1017,19 +996,7 @@ Object {
"fields": "[fields] getter",
"hasLong": false,
"hasUUID": true,
"ids": Array [
Object {
"autoGenerate": true,
"field": "[field] id",
"getter": "getId",
"name": "id",
"nameCapitalized": "Id",
"nameDotted": "id",
"nameDottedAsserted": "id!",
"relationshipsPath": Array [],
"setter": "setId",
},
],
"ids": "[ids] getter",
"name": "id",
"nameCapitalized": "Id",
"ownFields": "[ownFields] getter",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@
<%_ } _%>
<%_ for (relationship of relationships) {
if ((relationship.relationshipType === 'many-to-one' || (relationship.relationshipType === 'one-to-one' && relationship.ownerSide === true))
&& !relationship.id) {
&& (!relationship.id || entity.primaryKey.composite)) {
relationship.otherEntity.primaryKey.fields.forEach(idField => {
const uniqueConstraintName = relationship.relationshipType === 'one-to-one' ? getUXConstraintName(entity.entityTableName, relationship.columnName + '_' + idField.columnName, entity.prodDatabaseType) : null;
const uniqueConstraintName = relationship.relationshipType === 'one-to-one' ? getUXConstraintName(entity.entityTableName, relationship.columnNamePrefix + idField.columnName, entity.prodDatabaseType) : null;
_%>
<column name="<%= relationship.columnName %>_<%= idField.columnName %>" type="<%= idField.columnType %>">
<constraints nullable="<%= relationship.nullable %>"<% if (uniqueConstraintName) { %> unique="true" uniqueConstraintName="<%= uniqueConstraintName %>"<% } %> />
<column name="<%= relationship.columnNamePrefix %><%= idField.columnName %>" type="<%= idField.columnType %>">
<constraints <% if (relationship.id) { %>primaryKey="true" <% } %>nullable="<%= relationship.nullable %>"<% if (uniqueConstraintName) { %> unique="true" uniqueConstraintName="<%= uniqueConstraintName %>"<% } %> />
</column>
<%_ });
}
Expand All @@ -74,7 +74,7 @@ _%>
<createTable tableName="<%= relationship.joinTable.name %>">
<%_ for (field of relationship.otherEntity.primaryKey.fields) { _%>
<column name="<%= relationship.columnName %>_<%= field.columnName %>" type="<%= field.columnType %>">
<column name="<%= relationship.columnNamePrefix %><%= field.columnName %>" type="<%= field.columnType %>">
<constraints nullable="false"/>
</column>
<%_ } _%>
Expand All @@ -85,7 +85,7 @@ _%>
<%_ } _%>
</createTable>
<addPrimaryKey columnNames="<%= entity.primaryKey.fields.map(field => `${entity.entityTableName}_${field.columnName}`).join(', ') %>, <%= relationship.otherEntity.primaryKey.fields.map(field => `${relationship.columnName}_${field.columnName}`).join(', ') %>" tableName="<%= relationship.joinTable.name %>"/>
<addPrimaryKey columnNames="<%= entity.primaryKey.fields.map(field => `${entity.entityTableName}_${field.columnName}`).join(', ') %>, <%= relationship.otherEntity.primaryKey.fields.map(field => `${relationship.columnNamePrefix}${field.columnName}`).join(', ') %>" tableName="<%= relationship.joinTable.name %>"/>
<%_ } _%>
</changeSet>
<%_ } _%>
Expand Down Expand Up @@ -113,17 +113,12 @@ _%>
<column name="<%= field.columnName %>_content_type" type="string"/>
<%_ } _%>
<%_ } _%>
<%_ for (relationship of relationships) {
if (relationship.relationshipValidate === true && relationship.relationshipRequired
&& (relationship.relationshipType === "many-to-one"
|| (relationship.relationshipType === "one-to-one" && relationship.ownerSide === true
&& (relationship.id == null || relationship.id === false))
)) {
_%>
<%_ for (field of relationship.otherEntity.primaryKey.fields) { _%>
<column name="<%= relationship.columnName %>_<%= field.columnName %>" type="<%= field.loadColumnType %>"/>
<%_ } _%>
<%_ } _%>
<%_ const relationshipsToGenerate = [...relationships.filter(r => r.id && entity.primaryKey.composite), ...relationships.filter(r => !r.id && r.relationshipRequired && (r.relationshipManyToOne || (r.relationshipOneToOne && r.ownerSide)))];
for (relationship of relationshipsToGenerate) {
_%>
<%_ for (field of relationship.otherEntity.primaryKey.fields) { _%>
<column name="<%= relationship.columnNamePrefix %><%= field.columnName %>" type="<%= field.loadColumnType %>"/>
<%_ } _%>
<%_ } _%>
<!-- jhipster-needle-liquibase-add-loadcolumn - JHipster (and/or extensions) can add load columns here -->
</loadData>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,9 @@ for (field of fieldsToGenerate) {
header.push(field.columnName + '_content_type');
}
}
for (relationship of relationships) {
const { relationshipType, joinColumnNames } = relationship;
if (
(relationshipType === "many-to-one"
|| (relationshipType === "one-to-one" && relationship.ownerSide === true
&& (relationship.id == null || relationship.id === false))
) && (relationship.relationshipValidate === true && relationship.relationshipRequired)
) {
header.push(joinColumnNames[0]);
}
const relationshipsToGenerate = [...relationships.filter(r => r.id && entity.primaryKey.composite), ...relationships.filter(r => !r.id && r.relationshipRequired && (r.relationshipManyToOne || (r.relationshipOneToOne && r.ownerSide)))];
for (relationship of relationshipsToGenerate) {
header.push(...relationship.joinColumnNames);
}
table.push(header);
Expand All @@ -59,27 +52,21 @@ for (lineNb = 0; lineNb < entity.fakeDataCount; lineNb++) {
}
line.push(data);
if (field.columnType === 'blob' || field.columnType === 'longblob') {
if (field.fieldType === 'byte[]' && field.fieldTypeBlobContent !== 'text') {
line.push('image/png');
}
}
for (relationship of relationships) {
const relationshipType = relationship.relationshipType;
if (
(relationshipType === "many-to-one"
|| (relationshipType === "one-to-one" && relationship.ownerSide === true
&& (relationship.id == null || relationship.id === false))
) && (relationship.relationshipValidate === true && relationship.relationshipRequired)
) {
const otherLiquibaseFakeData = relationship.otherEntity.liquibaseFakeData;
let relationshipRow = lineNb;
if (relationshipRow >= relationship.otherEntity.fakeDataCount && !relationship.unique) {
relationshipRow = entity.faker.datatype.number({min: 1, max: relationship.otherEntity.fakeDataCount}) - 1;
}
if (relationshipRow < relationship.otherEntity.fakeDataCount) {
line.push(otherLiquibaseFakeData[relationshipRow][relationship.otherEntity.primaryKey.name]);
}
for (relationship of relationshipsToGenerate) {
let relationshipRow = lineNb;
if (relationshipRow >= relationship.otherEntity.fakeDataCount && !relationship.unique) {
relationshipRow = entity.faker.datatype.number({min: 1, max: relationship.otherEntity.fakeDataCount}) - 1;
}
if (relationshipRow < relationship.otherEntity.fakeDataCount) {
relationship.otherEntity.primaryKey.fields.forEach(field => {
const otherLiquibaseFakeData = field.entity.liquibaseFakeData;
line.push(otherLiquibaseFakeData[relationshipRow][field.propertyName]);
})
}
}
if (line.length === header.length) {
Expand Down
10 changes: 10 additions & 0 deletions generators/entity-server/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ const modelFiles = {
},
],
},
{
condition: generator => generator.primaryKey && generator.primaryKey.composite && !generator.primaryKey.derived,
path: SERVER_MAIN_SRC_DIR,
templates: [
{
file: 'package/domain/EntityId.java',
renameTo: generator => `${generator.entityAbsoluteFolder}/domain/${generator.persistClass}Id.java`,
},
],
},
],
modelTestFiles: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ int databaseSizeBeforeUpdate = <%= entityInstance %>Repository.findAll()<%= call
// Update the <%= entityInstance %> using partial update
<%= persistClass %> partialUpdated<%= persistClass %> = new <%= persistClass %>();
partialUpdated<%= persistClass %>.set<%= primaryKey.nameCapitalized %>(<%= persistInstance %>.get<%= primaryKey.nameCapitalized %>());
<%_ primaryKey.composite && fields.filter(f => f.id).forEach(f => { _%>
partialUpdated<%= persistClass %>.set<%= f.fieldNameCapitalized %>(<%= persistInstance %>.get<%= f.fieldNameCapitalized %>());
<%_ }) _%>
<%_ relationships.filter(r => r.id).forEach(r => { _%>
partialUpdated<%= persistClass %>.set<%= r.relationshipNameCapitalized %>(<%= persistInstance %>.get<%= r.relationshipNameCapitalized %>());
<%_ }) _%>
<%_ fieldsToUpdate = fields.filter(field => field.includeField) %>
<%_ if (fluentMethods && fieldsToUpdate.length > 0) { _%>
partialUpdated<%= persistClass %><% for (field of fieldsToUpdate) { %>
Expand All @@ -47,7 +53,7 @@ webTestClient
.expectStatus()
.isOk();
<%_ } else { _%>
rest<%= entityClass %>MockMvc.perform(patch(ENTITY_API_URL_ID, partialUpdated<%= persistClass %>.get<%= primaryKey.nameCapitalized %>())<% if (testsNeedCsrf) { %>.with(csrf())<% }%>
rest<%= entityClass %>MockMvc.perform(patch(ENTITY_API_URL_ID, <%- persistInstanceUrlId.replaceAll(persistInstance, 'partialUpdated' + persistClass) %>)<% if (testsNeedCsrf) { %>.with(csrf())<% }%>
.contentType("application/merge-patch+json")
.content(TestUtil.convertObjectToJsonBytes(<%= 'partialUpdated' + persistClass %>)))
.andExpect(status().isOk());
Expand Down
4 changes: 2 additions & 2 deletions generators/entity-server/templates/partials/save_template.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ if (isUsingMapsId) {
<%_ resultEntity = persistInstance; _%>
<%= persistClass %> <%= persistInstance %> = <%= dtoToEntity %>(<%= instanceName %>);
<%_ if (isUsingMapsId) { _%>
<%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>();
<%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <% if (primaryKey.composite) { %><%= mapper %>.toEntity(<%= instanceName %>)<% } else { %><%= instanceName %><% } %><% if (primaryKey.fields.length === 1) { %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>()<% } %>.get<%= primaryKey.nameCapitalized %>();
<%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= persistInstance %>::<%_ if (!fluentMethods) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= mapsIdAssoc.relationshipName %><%_ } _%>);
<%_ } _%>
<%= persistInstance %> = <%= entityInstance %>Repository.save(<%= persistInstance %>);
<%= returnPrefix %> <%= entityToDto %>(<%= persistInstance %>);
<%_ } else {
resultEntity = 'result'; _%>
<%_ if (isUsingMapsId) { _%>
<%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>();
<%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %><% if (primaryKey.fields.length === 1) { %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>()<% } %>.get<%= primaryKey.nameCapitalized %>();
<%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= instanceName %>::<%_ if (!fluentMethods) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= otherEntityName %><%_ } _%>);
<%_ } _%>
<%= returnPrefix %> <%= entityInstance %>Repository.save(<%= persistInstance %>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ if (isUsingMapsId) {
<%= persistInstance %>.setIsPersisted();
<%_ } _%>
<%_ if (isUsingMapsId) { _%>
<%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>();
<%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <% if (primaryKey.composite) { %><%= mapper %>.toEntity(<%= instanceName %>)<% } else { %><%= instanceName %><% } %><% if (primaryKey.fields.length === 1) { %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>()<% } %>.get<%= primaryKey.nameCapitalized %>();
<%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= persistInstance %>::<%_ if (!fluentMethods) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= mapsIdAssoc.relationshipName %><%_ } _%>);
<%_ } _%>
<%_ if (updatableEntity) { _%>
Expand All @@ -53,7 +53,7 @@ if (isUsingMapsId) {
<%_ } else {
resultEntity = 'result'; _%>
<%_ if (isUsingMapsId) { _%>
<%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>().get<%= primaryKey.nameCapitalized %>();
<%= mapsIdAssoc.otherEntity.primaryKey.type %> <%= otherEntityName %>Id = <%= instanceName %><% if (primaryKey.fields.length === 1) { %>.get<%= mapsIdAssoc.relationshipNameCapitalized %>()<% } %>.get<%= primaryKey.nameCapitalized %>();
<%= mapsIdRepoInstance %>.findById(<%= otherEntityName %>Id).ifPresent(<%= instanceName %>::<%_ if (!fluentMethods) { _%>set<%= mapsIdAssoc.relationshipNameCapitalized %> <%_ } else { _%><%= otherEntityName %><%_ } _%>);
<%_ } _%>
<%_ if (isPersisted) { _%>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
if (viaService) {
beans.push({class: `${entityClass}Service`, instance: `${entityInstance}Service`});
beans.push({class: `${entityClass}Repository`, instance: `${entityInstance}Repository`});
if (dtoMapstruct && primaryKey.composite) {
beans.push({class: `${entityClass}Mapper`, instance: `${entityInstance}Mapper`});
}
if (queryService) {
beans.push({class: `${entityClass}QueryService`, instance: `${entityInstance}QueryService`});
}
Expand All @@ -32,7 +35,7 @@
}
} else {
beans.push({class: `${entityClass}Repository`, instance: `${entityInstance}Repository`});
if (dtoMapstruct) {
if (dtoMapstruct || primaryKey.composite) {
beans.push({class: `${entityClass}Mapper`, instance: `${entityInstance}Mapper`});
}
if (searchEngineElasticsearch) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ _%>
Optional<<%= instanceType %>> result = <%= entityInstance %>Service.partialUpdate(<%= instanceName %>);
<%_ } _%>
<%_ } else { %>
<%- returnPrefix %> <%= entityInstance %>Repository.findById(<%= instanceName %>.get<%= primaryKey.nameCapitalized %>())
<%- returnPrefix %> <%= entityInstance %>Repository.findById(<%= primaryKey.composite && dtoMapstruct ? `${mapper}.toEntity(${instanceName})` : instanceName %>.get<%= primaryKey.nameCapitalized %>())
.map(existing<%= entityClass %> -> {
<%_ if (dtoMapstruct) { _%>
<%= mapper %>.partialUpdate(existing<%= entityClass %>, <%= instanceName %>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ public class <%= persistClass %> <&- fragments.extendsSection() -&>implements Se
private static final long serialVersionUID = 1L;

<%_ if (!embedded && primaryKey.composite) { _%>
@Id
@EmbeddedId
private <%= primaryKey.type %> <%= primaryKey.name %>;
<%_ } _%>
<&- fragments.classStaticFieldsSection() -&>
<&- fragments.classFieldsSection() -&>
<%_ for (const field of fields.filter(field => !field.javaInherited && !field.transient && (embedded || !field.id || !primaryKey.composite))) { _%>
<%_ for (const field of fields.filter(field => !field.javaInherited && !field.transient && (embedded || !(field.id && primaryKey.composite && primaryKey.fields.length === 1)))) { _%>
<&- fragments.field<%- field.fieldNameCapitalized %>CustomDeclarationSection() -&>
<&_ if (!fragments.field<%- field.fieldNameCapitalized %>CustomDeclarationSection()) { -&>
<%_ if (typeof field.javadoc !== 'undefined') { _%>
Expand Down Expand Up @@ -176,7 +176,24 @@ for (relationship of relationships.filter(relationship => !relationship.embedded
<%_ }; _%>
<&- fragments.classAdditionalRelationshipsSection() -&>
// jhipster-needle-entity-add-field - JHipster will add fields here
<%_ for (const field of fields.filter(field => !field.transient && (embedded || !field.id || !primaryKey.composite))) { _%>
<%_ if (!embedded && primaryKey.composite) { _%>
public <%= primaryKey.type %> get<%= primaryKey.nameCapitalized %>() {
return this.<%= primaryKey.name %>;
}
<%_ if (fluentMethods) { _%>
public <%= persistClass %> <%= primaryKey.name %>(<%= primaryKey.type %> <%= primaryKey.name %>) {
this.set<%= primaryKey.nameCapitalized %>(<%= primaryKey.name %>);
return this;
}
<%_ } _%>
public void set<%= primaryKey.nameCapitalized %>(<%= primaryKey.type %> <%= primaryKey.name %>) {
this.<%= primaryKey.name %> = <%= primaryKey.name %>;
}
<%_ } _%>
<%_ for (const field of fields.filter(field => !field.transient && (embedded || !(field.id && primaryKey.composite && primaryKey.fields.length === 1)))) { _%>
<&- fragments.field<%- field.fieldNameCapitalized %>CustomMethodsSection() -&>
<&_ if (!fragments.field<%- field.fieldNameCapitalized %>CustomMethodsSection()) { -&>
Expand Down
Loading

0 comments on commit 51e38a6

Please sign in to comment.