Skip to content

Commit

Permalink
don't convert blob types in jdl (#27328)
Browse files Browse the repository at this point in the history
  • Loading branch information
mshima authored Sep 19, 2024
1 parent d62a1af commit 67d9b6b
Show file tree
Hide file tree
Showing 25 changed files with 231 additions and 173 deletions.
7 changes: 3 additions & 4 deletions generators/base-application/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
import type { TaskTypes as DefaultTaskTypes } from '../../lib/types/application/tasks.js';
import type { ApplicationType } from '../../lib/types/application/application.js';
import type { Entity } from '../../lib/types/application/entity.js';
import type { Entity as BaseEntity } from '../../lib/types/base/entity.js';
import type { GenericTaskGroup } from '../../lib/types/base/tasks.js';
import type { ApplicationConfiguration } from '../../lib/types/application/yo-rc.js';
import type SharedData from '../base/shared-data.js';
Expand Down Expand Up @@ -188,16 +187,16 @@ export default class BaseApplicationGenerator<
/**
* get sorted list of entities according to changelog date (i.e. the order in which they were added)
*/
getExistingEntities(): { name: string; definition: BaseEntity }[] {
getExistingEntities(): { name: string; definition: E }[] {
function isBefore(e1, e2) {
return (e1.definition.annotations?.changelogDate ?? 0) - (e2.definition.annotations?.changelogDate ?? 0);
}

const configDir = this.getEntitiesConfigPath();

const entities: { name: string; definition: BaseEntity }[] = [];
const entities: { name: string; definition: E }[] = [];
for (const entityName of [...new Set(((this.jhipsterConfig.entities as string[]) || []).concat(getEntitiesFromDir(configDir)))]) {
const definition: BaseEntity = this.getEntityConfig(entityName)?.getAll() as BaseEntity;
const definition: E = this.getEntityConfig(entityName)?.getAll() as unknown as E;
if (definition) {
entities.push({ name: entityName, definition });
}
Expand Down
36 changes: 21 additions & 15 deletions generators/base-application/support/prepare-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import { getTypescriptType, prepareField as prepareClientFieldForTemplates } fro
import { prepareField as prepareServerFieldForTemplates } from '../../server/support/index.js';
import { mutateData } from '../../../lib/utils/object.js';
import type CoreGenerator from '../../base-core/generator.js';
import { fieldIsEnum } from './field-utils.js';
import type { Field } from '../../../lib/types/application/field.js';
import type { Entity } from '../../../lib/types/application/entity.js';
import { fieldTypeValues, isFieldEnumType } from '../../../lib/application/field-types.js';
import { prepareProperty } from './prepare-property.js';

const { BlobTypes, CommonDBTypes, RelationalOnlyDBTypes } = fieldTypes;
Expand Down Expand Up @@ -164,9 +166,9 @@ function generateFakeDataForField(this: CoreGenerator, field, faker, changelogDa
data = data.substr(0, data.length - 3);
}
}
} else if (field.fieldType === BYTES && field.fieldTypeBlobContent !== TEXT) {
} else if (field.fieldTypeBinary && field.fieldTypeBlobContent !== TEXT) {
data = '../fake-data/blob/hipster.png';
} else if (field.fieldType === BYTES && field.fieldTypeBlobContent === TEXT) {
} else if (field.fieldTypeBinary && field.fieldTypeBlobContent === TEXT) {
data = '../fake-data/blob/hipster.txt';
} else if (field.fieldType === STRING) {
data = field.id ? faker.string.uuid() : faker.helpers.fake(fakeStringTemplateForFieldName(field.columnName));
Expand Down Expand Up @@ -268,7 +270,7 @@ export default function prepareField(entityWithConfig, field, generator) {
return field;
}

function prepareCommonFieldForTemplates(entityWithConfig, field, generator) {
function prepareCommonFieldForTemplates(entityWithConfig: Entity, field: Field, generator) {
mutateData(field, {
__override__: false,
path: [field.fieldName],
Expand All @@ -288,10 +290,14 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) {
});
const fieldType = field.fieldType;

field.fieldIsEnum = !field.id && fieldIsEnum(fieldType);
if (field.fieldIsEnum) {
const fieldIsEnum = isFieldEnumType(field);
field.fieldIsEnum = fieldIsEnum;
if (fieldIsEnum) {
if (fieldTypeValues.includes(fieldType)) {
throw new Error(`Field type '${fieldType}' is a reserved keyword and can't be used as an enum name.`);
}
field.enumFileName = kebabCase(field.fieldType);
field.enumValues = getEnumValuesWithCustomValues(field.fieldValues);
field.enumValues = getEnumValuesWithCustomValues(field.fieldValues!);
}

field.fieldWithContentType = (fieldType === BYTES || fieldType === BYTE_BUFFER) && field.fieldTypeBlobContent !== TEXT;
Expand All @@ -301,18 +307,18 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) {

field.fieldValidate = Array.isArray(field.fieldValidateRules) && field.fieldValidateRules.length >= 1;
defaults(field, {
nullable: !(field.fieldValidate === true && field.fieldValidateRules.includes(REQUIRED)),
nullable: !(field.fieldValidate === true && field.fieldValidateRules!.includes(REQUIRED)),
});
field.unique = field.fieldValidate === true && field.fieldValidateRules.includes(UNIQUE);
if (field.fieldValidate === true && field.fieldValidateRules.includes(MAXLENGTH)) {
field.unique = field.fieldValidate === true && field.fieldValidateRules!.includes(UNIQUE);
if (field.fieldValidate === true && field.fieldValidateRules!.includes(MAXLENGTH)) {
field.maxlength = field.fieldValidateRulesMaxlength || 255;
}

const faker = entityWithConfig.faker;
field.createRandexp = () => {
// check if regex is valid. If not, issue warning and we skip fake data generation.
try {
new RegExp(field.fieldValidateRulesPattern);
new RegExp(field.fieldValidateRulesPattern!);
} catch {
generator.log.warn(`${field.fieldName} pattern is not valid: ${field.fieldValidateRulesPattern}. Skipping generating fake data. `);
return undefined;
Expand All @@ -329,9 +335,9 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) {
field.generateFakeData = (type = 'csv') => {
let data = generateFakeDataForField.call(generator, field, faker, entityWithConfig.changelogDateForRecent, type);
// manage uniqueness
if ((field.fieldValidate === true && field.fieldValidateRules.includes(UNIQUE)) || field.id) {
if ((field.fieldValidate === true && field.fieldValidateRules!.includes(UNIQUE)) || field.id) {
let i = 0;
while (field.uniqueValue.indexOf(data) !== -1) {
while (field.uniqueValue!.indexOf(data) !== -1) {
if (i++ === 5) {
data = undefined;
break;
Expand All @@ -341,7 +347,7 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) {
if (data === undefined) {
generator.log.warn(`Error generating a unique value field ${field.fieldName} and type ${field.fieldType}`);
} else {
field.uniqueValue.push(data);
field.uniqueValue!.push(data);
}
}
if (data === undefined) {
Expand All @@ -361,7 +367,7 @@ function prepareCommonFieldForTemplates(entityWithConfig, field, generator) {
* @param {String} [enumValues] - an enum's values.
* @return {Array<String>} the formatted enum's values.
*/
export function getEnumValuesWithCustomValues(enumValues) {
export function getEnumValuesWithCustomValues(enumValues: string): { name: string; value: string }[] {
if (!enumValues || enumValues === '') {
throw new Error('Enumeration values must be passed to get the formatted values.');
}
Expand Down
4 changes: 3 additions & 1 deletion generators/base-application/support/prepare-property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
*/
import { snakeCase, upperFirst } from 'lodash-es';
import { mutateData } from '../../../lib/utils/object.js';
import type { Field } from '../../../lib/types/application/field.js';
import type { Relationship } from '../../../lib/types/application/relationship.js';

export const prepareProperty = (property: any) => {
export const prepareProperty = (property: Field | Relationship) => {
mutateData(property, {
__override__: false,
propertyNameCapitalized: ({ propertyName }) => upperFirst(propertyName),
Expand Down
16 changes: 16 additions & 0 deletions generators/bootstrap-application-base/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { lookupCommandsConfigs } from '../../lib/command/lookup-commands-configs
import { loadCommandConfigsIntoApplication, loadCommandConfigsKeysIntoTemplatesContext } from '../../lib/command/load.js';
import { getConfigWithDefaults } from '../../lib/jhipster/default-application-options.js';
import { removeFieldsWithNullishValues } from '../base/support/index.js';
import { convertFieldBlobType, getBlobContentType, isFieldBinaryType, isFieldBlobType } from '../../lib/application/field-types.js';
import { createAuthorityEntity, createUserEntity, createUserManagementEntity } from './utils.js';
import { exportJDLTransform, importJDLTransform } from './support/index.js';

Expand Down Expand Up @@ -224,6 +225,11 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator {
configureEntity({ entityStorage, entityConfig }) {
entityStorage.defaults({ fields: [], relationships: [], annotations: {} });

for (const field of entityConfig.fields!.filter(field => field.fieldType === 'byte[]')) {
convertFieldBlobType(field);
entityStorage.save();
}

if (entityConfig.changelogDate) {
entityConfig.annotations.changelogDate = entityConfig.changelogDate;
delete entityConfig.changelogDate;
Expand Down Expand Up @@ -343,6 +349,16 @@ export default class BootstrapApplicationBase extends BaseApplicationGenerator {
this.validateResult(loadEntitiesOtherSide(entities, { application }));

for (const entity of entities) {
for (const field of entity.fields) {
if (isFieldBinaryType(field)) {
field.fieldTypeBlobContent ??= getBlobContentType(field.fieldType);
if (application.databaseTypeCassandra || entity.databaseType === 'cassandra') {
field.fieldType = 'ByteBuffer';
} else if (isFieldBlobType(field)) {
field.fieldType = 'byte[]' as any;
}
}
}
for (const relationship of entity.relationships) {
if (relationship.ownerSide === undefined) {
// ownerSide backward compatibility
Expand Down
2 changes: 1 addition & 1 deletion generators/client/support/template-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('generator - client - support - template-utils', () => {
describe('generateTestEntityId', () => {
describe('when called with int', () => {
it('return 123', () => {
expect(generateTestEntityId('int')).to.equal(123);
expect(generateTestEntityId('Integer')).to.equal(123);
});
});
describe('when called with String', () => {
Expand Down
5 changes: 3 additions & 2 deletions generators/client/support/template-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import path from 'path';

import { clientFrameworkTypes, fieldTypes } from '../../../lib/jhipster/index.js';
import type { PrimaryKey } from '../../../lib/types/application/entity.js';
import type { FieldType } from '../../../lib/application/field-types.js';
import { getEntryIfTypeOrTypeAttribute } from './types-utils.js';

const { STRING: TYPE_STRING, UUID: TYPE_UUID } = fieldTypes.CommonDBTypes;
Expand Down Expand Up @@ -100,7 +101,7 @@ export const generateEntityClientEnumImports = (fields, clientFramework) => {
* @param {boolean} [wrapped=true] - wrapped values for required types.
*/

export const generateTestEntityId = (primaryKey: string | PrimaryKey, index: string | number = 0, wrapped = true) => {
export const generateTestEntityId = (primaryKey: FieldType | PrimaryKey, index: string | number = 0, wrapped = true) => {
primaryKey = getEntryIfTypeOrTypeAttribute(primaryKey);
let value;
if (primaryKey === TYPE_STRING) {
Expand All @@ -110,7 +111,7 @@ export const generateTestEntityId = (primaryKey: string | PrimaryKey, index: str
} else {
value = index === 0 ? 123 : 456;
}
if (wrapped && [TYPE_UUID, TYPE_STRING].includes(primaryKey)) {
if (wrapped && [TYPE_UUID, TYPE_STRING].includes(primaryKey as any)) {
return `'${value}'`;
}
return value;
Expand Down
5 changes: 3 additions & 2 deletions generators/client/support/types-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { FieldType } from '../../../lib/application/field-types.js';
import { fieldTypes } from '../../../lib/jhipster/index.js';
import type { PrimaryKey } from '../../../lib/types/application/entity.js';
import { fieldIsEnum } from '../../base-application/support/index.js';
Expand All @@ -37,7 +38,7 @@ const {
* @param key
* @returns {*}
*/
export const getEntryIfTypeOrTypeAttribute = (key: string | PrimaryKey) => {
export const getEntryIfTypeOrTypeAttribute = (key: FieldType | PrimaryKey): FieldType => {
if (typeof key === 'object') {
return key.type;
}
Expand All @@ -50,7 +51,7 @@ export const getEntryIfTypeOrTypeAttribute = (key: string | PrimaryKey) => {
* @param {string | object} primaryKey - primary key definition
* @returns {string} primary key type in Typescript
*/
const getTypescriptKeyType = primaryKey => {
const getTypescriptKeyType = (primaryKey: FieldType | PrimaryKey) => {
if ([TYPE_INTEGER, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, TYPE_BIG_DECIMAL].includes(getEntryIfTypeOrTypeAttribute(primaryKey))) {
return 'number';
}
Expand Down
12 changes: 10 additions & 2 deletions generators/info/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type { JHipsterGeneratorFeatures, JHipsterGeneratorOptions } from '../bas
import { YO_RC_FILE } from '../generator-constants.js';
import { applicationsLookup } from '../workspaces/support/applications-lookup.js';
import type { Entity } from '../../lib/types/base/entity.js';
import { convertFieldBlobType } from '../../lib/application/field-types.js';
import { replaceSensitiveConfig } from './support/utils.js';

const isInfoCommand = commandName => commandName === 'info' || undefined;
Expand Down Expand Up @@ -142,8 +143,15 @@ export default class InfoGenerator extends BaseApplicationGenerator {
let jdlObject;
const entities = new Map<string, Entity>();
try {
this.getExistingEntities().forEach(entity => {
entities.set(entity.name, entity.definition);
this.getExistingEntities().forEach(({ name, definition: entity }) => {
if (entity.fields) {
for (const field of entity.fields) {
if (field.fieldType === 'byte[]') {
convertFieldBlobType(field);
}
}
}
entities.set(name, entity);
});
jdlObject = JSONToJDLEntityConverter.convertEntitiesToJDL(entities);
JSONToJDLOptionConverter.convertServerOptionsToJDL({ 'generator-jhipster': this.config.getAll() }, jdlObject);
Expand Down
36 changes: 22 additions & 14 deletions generators/server/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ const { SUPPORTED_VALIDATION_RULES } = validations;
const { isReservedTableName } = reservedKeywords;
const { ANGULAR, REACT, VUE } = clientFrameworkTypes;
const { GRADLE, MAVEN } = buildToolTypes;
const { CASSANDRA, SQL, NO: NO_DATABASE } = databaseTypes;
const { SQL, NO: NO_DATABASE } = databaseTypes;
const { GATEWAY } = applicationTypes;

const { NO: NO_SEARCH_ENGINE } = searchEngineTypes;
const { CommonDBTypes, RelationalOnlyDBTypes } = fieldTypes;
const { INSTANT } = CommonDBTypes;
const { BYTES, BYTE_BUFFER } = RelationalOnlyDBTypes;
const { BYTE_BUFFER } = RelationalOnlyDBTypes;
const { PaginationTypes, ServiceTypes } = entityOptions;
const {
Validations: { MAX, MIN, MAXLENGTH, MINLENGTH, MAXBYTES, MINBYTES, PATTERN },
Expand Down Expand Up @@ -333,28 +333,16 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator {
},

configureFields({ application, entityConfig, entityName }) {
const databaseType = entityConfig.databaseType ?? application.databaseType;
// Validate entity json field content
const fields = entityConfig.fields;
fields!.forEach(field => {
// Migration from JodaTime to Java Time
if (field.fieldType === 'DateTime' || field.fieldType === 'Date') {
field.fieldType = INSTANT;
}
if (field.fieldType === BYTES && databaseType === CASSANDRA) {
field.fieldType = BYTE_BUFFER;
}

this._validateField(entityName, field);

if (field.fieldType === BYTE_BUFFER) {
this.log.warn(
`Cannot use validation in .jhipster/${entityName}.json for field ${stringifyApplicationData(field)}
Hibernate JPA 2 Metamodel does not work with Bean Validation 2 for LOB fields, so LOB validation is disabled`,
);
field.fieldValidate = false;
field.fieldValidateRules = [];
}
if (entityConfig.pagination && entityConfig.pagination !== NO_PAGINATION && isReservedPaginationWords(field.fieldName)) {
throw new Error(
`Field name '${field.fieldName}' found in ${entityConfig.name} is a reserved keyword, as it is used by Spring for pagination in the URL.`,
Expand Down Expand Up @@ -403,6 +391,26 @@ Hibernate JPA 2 Metamodel does not work with Bean Validation 2 for LOB fields, s
return this.delegateTasksToBlueprint(() => this.configuringEachEntity);
}

get loadingEntities() {
return this.asLoadingEntitiesTaskGroup({
loadEntityConfig({ entitiesToLoad }) {
for (const { entityName, entityBootstrap } of entitiesToLoad) {
for (const field of entityBootstrap.fields) {
if (field.fieldType === BYTE_BUFFER) {
this.log.warn(`Cannot use validation in .jhipster/${entityName}.json for field ${stringifyApplicationData(field)}`);
field.fieldValidate = false;
field.fieldValidateRules = [];
}
}
}
},
});
}

get [BaseApplicationGenerator.LOADING_ENTITIES]() {
return this.delegateTasksToBlueprint(() => this.loadingEntities);
}

get preparingEachEntity() {
return this.asPreparingEachEntityTaskGroup({
prepareEntity({ entity }) {
Expand Down
3 changes: 2 additions & 1 deletion generators/server/support/build-specification-mapper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { FieldType } from '../../../lib/application/field-types.js';
import { fieldTypes } from '../../../lib/jhipster/index.js';

const {
Expand All @@ -17,7 +18,7 @@ const {
* Return the method name which converts the filter to specification
* @param {string} fieldType
*/
export const getSpecificationBuildForType = (fieldType: string) => {
export const getSpecificationBuildForType = (fieldType: FieldType) => {
if (
[
TYPE_INTEGER,
Expand Down
3 changes: 2 additions & 1 deletion generators/spring-boot/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
websocketTypes,
} from '../../lib/jhipster/index.js';
import { getPomVersionProperties, parseMavenPom } from '../maven/support/index.js';
import type { FieldType } from '../../lib/application/field-types.js';
import { writeFiles as writeEntityFiles } from './entity-files.js';
import cleanupTask from './cleanup.js';
import { serverFiles } from './files.js';
Expand Down Expand Up @@ -346,7 +347,7 @@ public void set${javaBeanCase(propertyName)}(${propertyType} ${propertyName}) {
get preparingEachEntityField() {
return this.asPreparingEachEntityFieldTaskGroup({
prepareEntity({ field }) {
field.fieldJavaBuildSpecification = getSpecificationBuildForType(field.fieldType);
field.fieldJavaBuildSpecification = getSpecificationBuildForType(field.fieldType as FieldType);

field.filterableField = ![TYPE_BYTES, TYPE_BYTE_BUFFER].includes(field.fieldType) && !field.transient;
if (field.filterableField) {
Expand Down
Loading

0 comments on commit 67d9b6b

Please sign in to comment.