Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to custom ids. #13258

Merged
merged 12 commits into from
Dec 14, 2020
6 changes: 3 additions & 3 deletions .github/workflows/angular.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,14 @@ jobs:
- ngx-gradle-h2disk-ws-nocache
include:
- app-type: ngx-default
entity: sql
entity: sqlfull
jdl-entity: '*'
environment: prod
war: 0
e2e: 1
testcontainers: 1
- app-type: ngx-mysql-es-noi18n-mapsid
entity: sqlfull
jdl-entity: '*'
entity: sql
environment: prod
war: 0
e2e: 1
Expand Down
103 changes: 82 additions & 21 deletions generators/database-changelog-liquibase/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* limitations under the License.
*/
const assert = require('assert');
const _ = require('lodash');

const BaseGenerator = require('../generator-base');
const { addEntityFiles, updateEntityFiles, updateConstraintsFiles, updateMigrateFiles, fakeFiles } = require('./files');
Expand All @@ -36,37 +37,92 @@ module.exports = class extends BaseGenerator {

assert(this.options.databaseChangelog, 'Changelog is required');
this.databaseChangelog = this.options.databaseChangelog;

// Set number of rows to be generated
this.numberOfRows = 10;
}

// Public API method used by the getter and also by Blueprints
_default() {
_preparing() {
return {
setupConstants() {
// Make constants available in templates
this.LIQUIBASE_DTD_VERSION = LIQUIBASE_DTD_VERSION;
},
prepareEntityForTemplates() {
const databaseChangelog = this.databaseChangelog;
this.entity = this.configOptions.sharedEntities[databaseChangelog.entityName];
if (!this.entity) {
throw new Error(`Shared entity ${databaseChangelog.entityName} was not found`);
}

// Remove fields with custom ids, drop once templates supports them
this.entity = { ...this.entity, fields: this.entity.fieldsNoId };

if (databaseChangelog.type === 'entity-new') {
this.fields = this.entity.fields.map(field => prepareFieldForLiquibaseTemplates(this.entity, field));
this.relationships = this.entity.relationships.map(relationship =>
this._prepareRelationshipForTemplates(this.entity, relationship)
);
} else {
this.addedFields = this.databaseChangelog.addedFields
.map(field => prepareFieldForTemplates(this.entity, field, this))
.map(field => prepareFieldForLiquibaseTemplates(this.entity, field));
this.removedFields = this.databaseChangelog.removedFields
.map(field => prepareFieldForTemplates(this.entity, field, this))
.map(field => prepareFieldForLiquibaseTemplates(this.entity, field));
}
},

setupReproducibility() {
if (this.jhipsterConfig.skipServer || this.entity.skipServer) {
return;
}

// In order to have consistent results with Faker, restart seed with current entity name hash.
this.entity.resetFakerSeed();
},

prepareFakeData() {
const databaseChangelog = this.databaseChangelog;
this.entity.liquibaseFakeData = [];
for (let rowNumber = 0; rowNumber < this.numberOfRows; rowNumber++) {
const rowData = {};
const fields = databaseChangelog.type === 'entity-new' ? this.fields : this.addedFields;
fields.forEach((field, idx) => {
if (field.derived) {
Object.defineProperty(rowData, field.fieldName, {
get: () => {
if (
!field.derivedEntity.liquibaseFakeData ||
rowNumber >= field.derivedEntity.liquibaseFakeData.length
) {
return undefined;
}
return field.derivedEntity.liquibaseFakeData[rowNumber][field.fieldName];
},
});
return;
}
let data;
if (field.id && field.fieldType === 'Long') {
data = rowNumber + 1;
} else {
data = field.generateFakeData();
}
rowData[field.fieldName] = data;
});

this.entity.liquibaseFakeData.push(rowData);
}
this.configOptions.sharedLiquibaseFakeData = this.configOptions.sharedLiquibaseFakeData || {};
this.configOptions.sharedLiquibaseFakeData[_.upperFirst(this.entity.name)] = this.entity.liquibaseFakeData;
},
};
}

get preparing() {
return this._preparing();
}

_preparingRelationships() {
return {
prepareRelationshipsForTemplates() {
const databaseChangelog = this.databaseChangelog;
if (databaseChangelog.type === 'entity-new') {
this.relationships = this.entity.relationships.map(relationship =>
this._prepareRelationshipForTemplates(this.entity, relationship)
);
} else {
this.addedRelationships = this.databaseChangelog.addedRelationships
.map(relationship => {
const otherEntityName = this._.upperFirst(relationship.otherEntityName);
Expand Down Expand Up @@ -102,22 +158,27 @@ module.exports = class extends BaseGenerator {
};
}

get preparingRelationships() {
return this._preparingRelationships();
}

// Public API method used by the getter and also by Blueprints
_default() {
return {
setupConstants() {
// Make constants available in templates
this.LIQUIBASE_DTD_VERSION = LIQUIBASE_DTD_VERSION;
},
};
}

get default() {
return this._default();
}

// Public API method used by the getter and also by Blueprints
_writing() {
return {
setupReproducibility() {
if (this.jhipsterConfig.skipServer || this.entity.skipServer) {
return;
}

// In order to have consistent results with Faker, restart seed with current entity name hash.
this.entity.resetFakerSeed();
},

writeLiquibaseFiles() {
const config = this.jhipsterConfig;
if (config.skipServer || this.entity.skipServer || config.databaseType !== 'sql') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,22 @@
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-<%= LIQUIBASE_DTD_VERSION %>.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">

<% let autoIncrementValue = entity.primaryKeyType !== 'String';
let databasePKType = entity.primaryKeyType !== 'String' ? 'bigint' : 'varchar(100)';
const isAutoIncrementDB = reactive || prodDatabaseType === 'mysql';
_%>
<%_ if (isAutoIncrementDB) { _%>
<property name="autoIncrement" value="<%- autoIncrementValue %>"/>
<%_ } _%>

<!--
Added the entity <%= entity.entityClass %>.
-->
<changeSet id="<%= changelogDate %>-1" author="jhipster">
<createTable tableName="<%= entity.entityTableName %>"<%- formatAsLiquibaseRemarks(entity.javadoc, true) %>>
<column name="id" type="<%= databasePKType %>" <%_ if (entity.primaryKeyType === 'String' ) { _%> <% } else if (isAutoIncrementDB) { %> autoIncrement="${autoIncrement}" <%_ } %>>
<constraints primaryKey="true" nullable="false"/>
</column>
<%_ for (idx in fields) {
const nullable = fields[idx].nullable;
const fieldType = fields[idx].fieldType;
const fieldTypeBlobContent = fields[idx].fieldTypeBlobContent;
const columnName = fields[idx].fieldNameAsDatabaseColumn;
const columnType = fields[idx].columnType;
_%>
<column name="<%= columnName %>" type="<%= columnType %>"<%- formatAsLiquibaseRemarks(fields[idx].javadoc, true) %>>
<%_ if (fields[idx].unique) { _%>
<column name="<%= columnName %>" type="<%= columnType %>"<%- formatAsLiquibaseRemarks(fields[idx].javadoc, true) %><% if (fields[idx].id && fields[idx].liquibaseAutoIncrement) { %> autoIncrement="true" <%_ } %>>
<%_ if (fields[idx].id) { _%>
<constraints primaryKey="true" nullable="false"/>
<%_ } else if (fields[idx].unique) { _%>
<constraints nullable="<%= nullable %>" unique="true" uniqueConstraintName="<%= fields[idx].uniqueConstraintName %>" />
<%_ } else { _%>
<constraints nullable="<%= nullable %>" />
Expand All @@ -70,18 +61,16 @@
if (relationships[idx].relationshipValidate === true && relationships[idx].relationshipRequired) {
nullable_relation = false;
}
if (relationships[idx].relationshipType === 'many-to-one') { _%>
<column name="<%= relationships[idx].columnName %>_id" type="<%= relationshipColumnType %>">
<constraints nullable="<%= relationships[idx].nullable %>" />
</column>
<%_ } else if (relationshipType === 'one-to-one' && relationships[idx].ownerSide === true
&& (relationships[idx].useJPADerivedIdentifier == null || relationships[idx].useJPADerivedIdentifier === false)) {
const uniqueConstraintName = getUXConstraintName(entity.entityTableName, relationships[idx].columnName + '_id', entity.prodDatabaseType);
_%>
<column name="<%= relationships[idx].columnName %>_id" type="<%= relationshipColumnType %>">
<constraints unique="true" nullable="<%= relationships[idx].nullable %>" uniqueConstraintName="<%= uniqueConstraintName %>" />
if (relationships[idx].relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && relationships[idx].ownerSide === true
&& (relationships[idx].useJPADerivedIdentifier == null || relationships[idx].useJPADerivedIdentifier === false))) {
relationships[idx].otherEntity.idFields.forEach(idField => {
const uniqueConstraintName = relationshipType === 'one-to-one' ? getUXConstraintName(entity.entityTableName, relationships[idx].columnName + '_' + idField.columnName, entity.prodDatabaseType) : null;
_%>
<column name="<%= relationships[idx].columnName %>_<%= idField.columnName %>" type="<%= idField.columnType %>">
<constraints nullable="<%= relationships[idx].nullable %>"<% if (uniqueConstraintName) { %> unique="true" uniqueConstraintName="<%= uniqueConstraintName %>"<% } %> />
</column>
<%_ }
<%_ });
}
} _%>
<!-- jhipster-needle-liquibase-add-column - JHipster will add columns here -->
</createTable>
Expand Down Expand Up @@ -131,7 +120,6 @@
file="config/liquibase/fake-data/<%= !entity.incrementalChangelog ? entity.entityTableName : databaseChangelog.changelogDate + '_entity_' + entity.entityClass %>.csv"
separator=";"
tableName="<%= entity.entityTableName %>">
<column name="id" type="numeric"/>
<%_ for (idx in fields) {
_%>
<column name="<%= fields[idx].columnName %>" type="<%= fields[idx].loadColumnType %>"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@
otherEntityTableName = relationships[idx].otherEntityTableName;
if (relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && ownerSide)) {
const constraintName = getFKConstraintName(entity.entityTableName, relationshipName, prodDatabaseType);
let baseColumnName = getColumnName(relationshipName) + '_id';
let baseColumnNames;
let referencedColumnNames;
if (relationshipType === 'one-to-one' && ownerSide && relationships[idx].useJPADerivedIdentifier === true) {
baseColumnName = 'id';
baseColumnNames = relationships[idx].otherEntity.idFields.map(field => getColumnName(field.columnName)).join(',');
referencedColumnNames = relationships[idx].otherEntity.idFields.map(field => getColumnName(field.columnName)).join(',');
} else if (relationships[idx].otherEntity) {
baseColumnNames = relationships[idx].otherEntity.idFields.map(field => getColumnName(relationshipName + '_' + field.columnName)).join(',');
referencedColumnNames = relationships[idx].otherEntity.idFields.map(field => getColumnName(field.columnName)).join(',');
} %>
<addForeignKeyConstraint baseColumnNames="<%= baseColumnName %>"
<addForeignKeyConstraint baseColumnNames="<%= baseColumnNames %>"
baseTableName="<%= entity.entityTableName %>"
constraintName="<%= constraintName %>"
referencedColumnNames="id"
referencedColumnNames="<%= referencedColumnNames %>"
referencedTableName="<%= otherEntityTableName %>"/>
<%_ } else if (relationships[idx].shouldCreateJoinTable) {
const joinTableName = getJoinTableName(entity.entityTableName, relationshipName, prodDatabaseType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,28 @@ let table = [];

// Generate CSV header
let header = [];
header.push('id');
for (idx in fields) {
header.push(fields[idx].columnName);
if (fields[idx].fieldType === 'byte[]' && fields[idx].fieldTypeBlobContent !== 'text') {
header.push(fields[idx].columnName + '_content_type');
for (field of fields) {
header.push(field.columnName);
if (field.fieldType === 'byte[]' && field.fieldTypeBlobContent !== 'text') {
header.push(field.columnName + '_content_type');
}
}
for (idx in relationships) {
const relationshipType = relationships[idx].relationshipType
for (relationship of relationships) {
const relationshipType = relationship.relationshipType
if (
(relationshipType === "many-to-one"
|| (relationshipType === "one-to-one" && relationships[idx].ownerSide === true
&& (relationships[idx].useJPADerivedIdentifier == null || relationships[idx].useJPADerivedIdentifier === false))
) && (relationships[idx].relationshipValidate === true && relationships[idx].relationshipRequired)
|| (relationshipType === "one-to-one" && relationship.ownerSide === true
&& (relationship.useJPADerivedIdentifier == null || relationship.useJPADerivedIdentifier === false))
) && (relationship.relationshipValidate === true && relationship.relationshipRequired)
) {
header.push(getColumnName(relationships[idx].relationshipName) + "_id");
header.push(getColumnName(relationship.relationshipName) + "_id");
}
}
table.push(header);

// Set number of rows to be generated
let numberOfRows = 10;
for (idx in relationships) {
if ( relationships[idx].useJPADerivedIdentifier === true ) {
const otherEntityNameCapitalized = relationships[idx].otherEntityNameCapitalized;
if ( relationship.useJPADerivedIdentifier === true ) {
const otherEntityNameCapitalized = relationship.otherEntityNameCapitalized;
if (otherEntityNameCapitalized === 'User') {
// Only few user records are generated
numberOfRows = (authenticationType === 'oauth2') ? 0 : 2;
Expand All @@ -54,47 +51,44 @@ for (idx in relationships) {
}
}

// store unique values
const uniqueValues = {};
for (idx in fields) {
if (fields[idx].fieldValidate === true && fields[idx].fieldValidateRules.includes('unique')) {
uniqueValues[idx] = [];
}
}

// Generate CSV rows

for (lineNb = 1; lineNb <= numberOfRows; lineNb++) {
let line = [ lineNb ];
for (idx in fields) {
let data = fields[idx].generateFakeData();
for (lineNb = 0; lineNb < entity.liquibaseFakeData.length; lineNb++) {
const rowData = entity.liquibaseFakeData[lineNb];
let line = [];
for (field of fields) {
let data = rowData[field.fieldName];
// manage required
if (data === undefined) {
if (fields[idx].fieldValidateRules.includes('required')) {
if (field.id || (field.fieldValidateRules && field.fieldValidateRules.includes('required'))) {
// Remove row;
line = [];
break;
}
data = '';
}

line.push(data);
if (fields[idx].columnType === 'blob' || fields[idx].columnType === 'longblob') {
if (field.columnType === 'blob' || field.columnType === 'longblob') {
line.push('image/png');
}
}

for (idx in relationships) {
const relationshipType = relationships[idx].relationshipType;
for (relationship of relationships) {
const relationshipType = relationship.relationshipType;
if (
(relationshipType === "many-to-one"
|| (relationshipType === "one-to-one" && relationships[idx].ownerSide === true
&& (relationships[idx].useJPADerivedIdentifier == null || relationships[idx].useJPADerivedIdentifier === false))
) && (relationships[idx].relationshipValidate === true && relationships[idx].relationshipRequired)
|| (relationshipType === "one-to-one" && relationship.ownerSide === true
&& (relationship.useJPADerivedIdentifier == null || relationship.useJPADerivedIdentifier === false))
) && (relationship.relationshipValidate === true && relationship.relationshipRequired)
) {
if (relationships[idx].otherEntityNameCapitalized === 'User') {
line.push(entity.faker.random.number({min: 1, max: 2}));
} else {
line.push(lineNb);
const otherLiquibaseFakeData = relationship.otherEntity.liquibaseFakeData;
let relationshipRow = lineNb;
if (relationship.otherEntity.builtIn) {
relationshipRow = entity.faker.random.number({min: 1, max: otherLiquibaseFakeData.length}) - 1;
}
if (relationshipRow < otherLiquibaseFakeData.length) {
line.push(otherLiquibaseFakeData[relationshipRow][relationship.otherEntity.primaryKey.name]);
}
}
}
Expand Down
Loading