diff --git a/generators/base-application/generator.mts b/generators/base-application/generator.mts index 5600ccd2f06f..4ce690677c95 100644 --- a/generators/base-application/generator.mts +++ b/generators/base-application/generator.mts @@ -36,6 +36,7 @@ import { mutateApplication } from '../base/support/config.mjs'; const { LOADING, PREPARING, + POST_PREPARING, CONFIGURING_EACH_ENTITY, LOADING_ENTITIES, PREPARING_EACH_ENTITY, @@ -341,6 +342,7 @@ export default class BaseApplicationGenerator< ![ LOADING, PREPARING, + POST_PREPARING, CONFIGURING_EACH_ENTITY, LOADING_ENTITIES, diff --git a/generators/base-application/generator.spec.mts b/generators/base-application/generator.spec.mts index 4d56f431b32b..86d8b99ba175 100644 --- a/generators/base-application/generator.spec.mts +++ b/generators/base-application/generator.spec.mts @@ -62,6 +62,7 @@ describe(`generator - ${generator}`, () => { // application arg const loading = esmocha.fn(); const preparing = esmocha.fn(); + const postPreparing = esmocha.fn(); const writing = esmocha.fn(); const postWriting = esmocha.fn(); const install = esmocha.fn(); @@ -106,6 +107,10 @@ describe(`generator - ${generator}`, () => { return { preparing }; } + get [Generator.POST_PREPARING]() { + return { postPreparing }; + } + get [Generator.CONFIGURING_EACH_ENTITY]() { return { configuringEachEntity }; } @@ -236,6 +241,7 @@ describe(`generator - ${generator}`, () => { expect(configuring).toBeCalledWith(controlArg); expect(composing).toBeCalledWith(controlArg); expect(loading).toBeCalledWith(applicationDefaultsArg); + expect(postPreparing).toBeCalledWith(applicationSourceArg); expect(configuringEachEntity).toBeCalledTimes(3); expect(configuringEachEntity).toHaveBeenNthCalledWith(1, { ...entityConfiguringArg, entityName: 'One' }); diff --git a/generators/base-application/tasks.d.mts b/generators/base-application/tasks.d.mts index 0f8eab2dc9dc..b244c8645b97 100644 --- a/generators/base-application/tasks.d.mts +++ b/generators/base-application/tasks.d.mts @@ -84,7 +84,13 @@ export type BaseApplicationGeneratorDefinition< // Add application to existing priorities Record<'loadingTaskParam' | 'preparingTaskParam', ApplicationTaskParam & ApplicationDefaultsTaskParam> & Record< - 'defaultTaskParam' | 'postWritingTaskParam' | 'preConflictsTaskParam' | 'installTaskParam' | 'postInstallTaskParam' | 'endTaskParam', + | 'postPreparingTaskParam' + | 'defaultTaskParam' + | 'postWritingTaskParam' + | 'preConflictsTaskParam' + | 'installTaskParam' + | 'postInstallTaskParam' + | 'endTaskParam', ApplicationTaskParam > & Record<'writingTaskParam', ApplicationTaskParam & { configChanges?: Record }> & diff --git a/generators/base-core/generator.mts b/generators/base-core/generator.mts index c2cef6683096..475f64f3ffa1 100644 --- a/generators/base-core/generator.mts +++ b/generators/base-core/generator.mts @@ -58,8 +58,21 @@ import { GENERATOR_JHIPSTER, YO_RC_FILE } from '../generator-constants.mjs'; import { convertConfigToOption } from '../../lib/internal/index.mjs'; const { merge, get, set } = _; -const { INITIALIZING, PROMPTING, CONFIGURING, COMPOSING, LOADING, PREPARING, DEFAULT, WRITING, POST_WRITING, INSTALL, POST_INSTALL, END } = - PRIORITY_NAMES; +const { + INITIALIZING, + PROMPTING, + CONFIGURING, + COMPOSING, + LOADING, + PREPARING, + POST_PREPARING, + DEFAULT, + WRITING, + POST_WRITING, + INSTALL, + POST_INSTALL, + END, +} = PRIORITY_NAMES; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -89,6 +102,8 @@ export default class CoreGenerator extends YeomanGenerator { + return this.asPreparingTaskGroup({}); + } + + /** + * Utility method to get typed objects for autocomplete. + */ + asPostPreparingTaskGroup( + taskGroup: GenericTaskGroup, + ): GenericTaskGroup { + return taskGroup; + } + /** * Priority API stub for blueprints. * diff --git a/generators/base/priorities.mjs b/generators/base/priorities.mjs index ef9638f35ff0..00822bf07f54 100644 --- a/generators/base/priorities.mjs +++ b/generators/base/priorities.mjs @@ -50,6 +50,9 @@ const LOADING_QUEUE = `${QUEUE_PREFIX}${LOADING}`; const PREPARING = 'preparing'; const PREPARING_QUEUE = `${QUEUE_PREFIX}${PREPARING}`; +const POST_PREPARING = 'postPreparing'; +const POST_PREPARING_QUEUE = `${QUEUE_PREFIX}${POST_PREPARING}`; + const MULTISTEP_TRANSFORM = 'multistepTransform'; const MULTISTEP_TRANSFORM_QUEUE = `${QUEUE_PREFIX}${MULTISTEP_TRANSFORM}`; @@ -98,9 +101,15 @@ export const CUSTOM_PRIORITIES = [ { priorityName: PREPARING, queueName: PREPARING_QUEUE, - before: DEFAULT, + before: POST_PREPARING, args: generator => generator.getArgsForPriority(PREPARING), }, + { + priorityName: POST_PREPARING, + queueName: POST_PREPARING_QUEUE, + before: DEFAULT, + args: generator => generator.getArgsForPriority(POST_PREPARING), + }, { priorityName: DEFAULT, args: generator => generator.getArgsForPriority(DEFAULT), @@ -153,6 +162,7 @@ export const PRIORITY_NAMES = { COMPOSING, LOADING, PREPARING, + POST_PREPARING, DEFAULT, WRITING, @@ -172,6 +182,7 @@ export const PRIORITY_NAMES_LIST = [ COMPOSING, LOADING, PREPARING, + POST_PREPARING, DEFAULT, WRITING, @@ -190,6 +201,7 @@ export const QUEUES = { COMPOSING_QUEUE, LOADING_QUEUE, PREPARING_QUEUE, + POST_PREPARING_QUEUE, DEFAULT_QUEUE: DEFAULT, WRITING_QUEUE: WRITING, diff --git a/generators/base/tasks.d.mts b/generators/base/tasks.d.mts index c6b1737bfe72..0dd4560bdcd0 100644 --- a/generators/base/tasks.d.mts +++ b/generators/base/tasks.d.mts @@ -29,5 +29,4 @@ export type BaseGeneratorDefinition & - Record<'postWritingTaskParam', SourceTaskParam> & - Record<'preparingTaskParam', SourceTaskParam>; + Record<'preparingTaskParam' | 'postPreparingTaskParam' | 'postWritingTaskParam', SourceTaskParam>; diff --git a/generators/entity/generator.mjs b/generators/entity/generator.mjs index 7326a9dc359c..3925fc0b64e2 100644 --- a/generators/entity/generator.mjs +++ b/generators/entity/generator.mjs @@ -25,107 +25,111 @@ import * as _ from 'lodash-es'; import BaseApplicationGenerator from '../base-application/index.mjs'; import prompts from './prompts.mjs'; import { JHIPSTER_CONFIG_DIR } from '../generator-constants.mjs'; -import { applicationTypes, clientFrameworkTypes, getConfigWithDefaults, reservedKeywords } from '../../jdl/jhipster/index.mjs'; -import { GENERATOR_ENTITIES, GENERATOR_ENTITY } from '../generator-list.mjs'; -import { removeFieldsWithNullishValues } from '../base/support/index.mjs'; -import { - getDBTypeFromDBValue, - hibernateSnakeCase, - loadDerivedPlatformConfig, - loadDerivedServerConfig, - loadServerConfig, -} from '../server/support/index.mjs'; -import { loadAppConfig, loadDerivedAppConfig } from '../app/support/index.mjs'; -import { loadClientConfig, loadDerivedClientConfig } from '../client/support/index.mjs'; -import { loadLanguagesConfig } from '../languages/support/index.mjs'; +import { applicationTypes, reservedKeywords } from '../../jdl/jhipster/index.mjs'; +import { GENERATOR_BOOTSTRAP_APPLICATION, GENERATOR_ENTITIES, GENERATOR_ENTITY } from '../generator-list.mjs'; +import { getDBTypeFromDBValue, hibernateSnakeCase } from '../server/support/index.mjs'; import command from './command.mjs'; const { GATEWAY, MICROSERVICE } = applicationTypes; -const { NO: CLIENT_FRAMEWORK_NO } = clientFrameworkTypes; const { isReservedClassName } = reservedKeywords; export default class EntityGenerator extends BaseApplicationGenerator { + name; + application = {}; + constructor(args, options, features) { super(args, options, { unique: 'argument', ...features }); } async beforeQueue() { - this.parseJHipsterArguments(command.arguments); - const name = _.upperFirst(this.name).replace('.json', ''); - this.entityStorage = this.getEntityConfig(name, true); - this.entityConfig = this.entityStorage.createProxy(); - - const configExisted = this.entityStorage.existed; - const filename = path.join(JHIPSTER_CONFIG_DIR, `${name}.json`); - const entityExisted = fs.existsSync(this.destinationPath(filename)); - - this.jhipsterConfig.entities = [...(this.jhipsterConfig.entities ?? []), name]; - this.context = { - name, - filename, - configExisted, - entityExisted, - configurationFileExists: this.fs.exists(this.destinationPath(filename)), - }; - if (!this.fromBlueprint) { - await this.composeWithBlueprints(GENERATOR_ENTITY, { - generatorOptions: { - entityExisted, - configExisted, - arguments: [name], - }, - }); + await this.composeWithBlueprints(GENERATOR_ENTITY); } - this._setupEntityOptions(this, this, this.context); + if (!this.delegateToBlueprint) { + await this.dependsOnJHipster(GENERATOR_BOOTSTRAP_APPLICATION); + } } // Public API method used by the getter and also by Blueprints get initializing() { - return { - /* Use need microservice path to load the entity file */ - askForMicroserviceJson: prompts.askForMicroserviceJson, + return this.asInitializingTaskGroup({ + parseOptions() { + this.parseJHipsterArguments(command.arguments); + const name = _.upperFirst(this.name).replace('.json', ''); + this.entityStorage = this.getEntityConfig(name, true); + this.entityConfig = this.entityStorage.createProxy(); + + const configExisted = this.entityStorage.existed; + const filename = path.join(JHIPSTER_CONFIG_DIR, `${name}.json`); + const entityExisted = fs.existsSync(this.destinationPath(filename)); + + this.jhipsterConfig.entities = [...(this.jhipsterConfig.entities ?? []), name]; + this.entityData = { + name, + filename, + configExisted, + entityExisted, + configurationFileExists: this.fs.exists(this.destinationPath(filename)), + }; - loadSharedConfig() { - this.application = {}; - loadAppConfig({ - config: this.jhipsterConfigWithDefaults, - application: this.application, - useVersionPlaceholders: this.useVersionPlaceholders, - }); - loadClientConfig({ config: this.jhipsterConfigWithDefaults, application: this.application }); - loadLanguagesConfig({ application: this.application, config: this.jhipsterConfigWithDefaults }); - // Try to load server config from microservice side, falling back to the app config. - loadServerConfig({ - config: getConfigWithDefaults({ - ...removeFieldsWithNullishValues(this.jhipsterConfig), - ...removeFieldsWithNullishValues(this.microserviceConfig ?? {}), - }), - application: this.application, - }); + this._setupEntityOptions(this, this, this.entityData); + }, + + loadOptions() { + if (this.options.db) { + this.entityConfig.databaseType = getDBTypeFromDBValue(this.options.db); + if (this.entityConfig.databaseType === 'sql') { + this.entityConfig.prodDatabaseType = this.options.db; + this.entityConfig.devDatabaseType = this.options.db; + } + } - loadDerivedAppConfig({ application: this.application }); - loadDerivedClientConfig({ application: this.application }); - loadDerivedServerConfig({ application: this.application }); - loadDerivedPlatformConfig({ application: this.application }); + if (this.options.skipServer !== undefined) { + this.entityConfig.skipServer = this.options.skipServer; + } + if (this.options.skipDbChangelog !== undefined) { + this.entityConfig.skipDbChangelog = this.options.skipDbChangelog; + } + if (this.options.skipClient !== undefined) { + this.entityConfig.skipClient = this.options.skipClient; + } }, + }); + } + get [BaseApplicationGenerator.INITIALIZING]() { + return this.delegateTasksToBlueprint(() => this.initializing); + } + + get prompting() { + return this.asPromptingTaskGroup({ + /* Use need microservice path to load the entity file */ + askForMicroserviceJson: prompts.askForMicroserviceJson, + }); + } + + get [BaseApplicationGenerator.PROMPTING]() { + return this.delegateTasksToBlueprint(() => this.prompting); + } + + get loading() { + return this.asLoadingTaskGroup({ isBuiltInEntity() { - if (this.isBuiltInUser(this.context.name) || this.isBuiltInAuthority(this.context.name)) { - throw new Error(`Is not possible to override built in ${this.context.name}`); + if (this.isBuiltInUser(this.entityData.name) || this.isBuiltInAuthority(this.entityData.name)) { + throw new Error(`Is not possible to override built in ${this.entityData.name}`); } }, - setupMicroServiceEntity() { - const context = this.context; + setupMicroServiceEntity({ application }) { + const context = this.entityData; - if (this.application.applicationType === MICROSERVICE) { + if (application.applicationType === MICROSERVICE) { context.microserviceName = this.entityConfig.microserviceName = this.jhipsterConfig.baseName; if (!this.entityConfig.clientRootFolder) { context.clientRootFolder = this.entityConfig.clientRootFolder = this.entityConfig.microserviceName; } - } else if (this.application.applicationType === GATEWAY) { + } else if (application.applicationType === GATEWAY) { // If microservicePath is set we are loading the entity from the microservice side. context.useMicroserviceJson = !!this.entityConfig.microservicePath; if (context.useMicroserviceJson) { @@ -150,48 +154,25 @@ export default class EntityGenerator extends BaseApplicationGenerator { ? '' : this.entityConfig.microserviceName; } - - if (this.jhipsterConfig.applications && !this.entityConfig.skipClient) { - const remoteConfig = this.jhipsterConfig.applications[this.entityConfig.microserviceName]; - if (remoteConfig && remoteConfig.clientFramework && remoteConfig.clientFramework !== CLIENT_FRAMEWORK_NO) { - // Gateway requires entities to discover a microfrontend. - // Microfrontends is generated at the microservice side, so skip it at gateway side. - this.entityConfig.skipClient = true; - } - } } }, - loadOptions() { - const context = this.context; - - if (this.options.db) { - context.databaseType = getDBTypeFromDBValue(this.options.db); - context.prodDatabaseType = this.options.db; - context.devDatabaseType = this.options.db; - } - - context.skipServer = context.skipServer || this.options.skipServer; - context.skipDbChangelog = context.skipDbChangelog || this.options.skipDbChangelog; - context.skipClient = context.skipClient || this.options.skipClient; - }, - - loadEntitySpecificOptions() { - this.context.skipClient = this.context.skipClient || this.entityConfig.skipClient; - this.context.databaseType = this.context.databaseType || this.entityConfig.databaseType || this.jhipsterConfig.databaseType; + loadEntitySpecificOptions({ application }) { + this.entityData.skipClient = this.entityData.skipClient || this.entityConfig.skipClient; + this.entityData.databaseType = this.entityData.databaseType || this.entityConfig.databaseType || application.databaseType; }, validateEntityName() { - const validation = this._validateEntityName(this.context.name); + const validation = this._validateEntityName(this.entityData.name); if (validation !== true) { throw new Error(validation); } }, - bootstrapConfig() { - const context = this.context; + bootstrapConfig({ application }) { + const context = this.entityData; const entityName = context.name; - if ([MICROSERVICE, GATEWAY].includes(this.application.applicationType)) { + if ([MICROSERVICE, GATEWAY].includes(application.applicationType)) { if (this.entityConfig.databaseType === undefined) { this.entityConfig.databaseType = context.databaseType; } @@ -208,16 +189,15 @@ export default class EntityGenerator extends BaseApplicationGenerator { this.log.verboseInfo(`\nThe entity ${entityName} is being created.\n`); } }, - }; + }); } - get [BaseApplicationGenerator.INITIALIZING]() { - return this.delegateTasksToBlueprint(() => this.initializing); + get [BaseApplicationGenerator.LOADING]() { + return this.delegateTasksToBlueprint(() => this.loading); } - // Public API method used by the getter and also by Blueprints - get prompting() { - return { + get postPreparing() { + return this.asPostPreparingTaskGroup({ /* ask question to user if s/he wants to update entity */ askForUpdate: prompts.askForUpdate, askForFields: prompts.askForFields, @@ -229,20 +209,20 @@ export default class EntityGenerator extends BaseApplicationGenerator { askForFiltering: prompts.askForFiltering, askForReadOnly: prompts.askForReadOnly, askForPagination: prompts.askForPagination, - }; + }); } - get [BaseApplicationGenerator.PROMPTING]() { - return this.delegateTasksToBlueprint(() => this.prompting); + get [BaseApplicationGenerator.POST_PREPARING]() { + return this.delegateTasksToBlueprint(() => this.postPreparing); } // Public API method used by the getter and also by Blueprints - get composing() { - return this.asComposingTaskGroup({ + get default() { + return this.asDefaultTaskGroup({ async composeEntities() { // We need to compose with others entities to update relationships. await this.composeWithJHipster(GENERATOR_ENTITIES, { - generatorArgs: this.options.singleEntity ? [this.context.name] : [], + generatorArgs: this.options.singleEntity ? [this.entityData.name] : [], generatorOptions: { skipDbChangelog: this.options.skipDbChangelog, skipInstall: this.options.skipInstall, @@ -252,15 +232,15 @@ export default class EntityGenerator extends BaseApplicationGenerator { }); } - get [BaseApplicationGenerator.COMPOSING]() { - return this.delegateTasksToBlueprint(() => this.composing); + get [BaseApplicationGenerator.DEFAULT]() { + return this.delegateTasksToBlueprint(() => this.default); } // Public API method used by the getter and also by Blueprints get end() { return { end() { - this.log.log(chalk.bold.green(`Entity ${this.context.entityNameCapitalized} generated successfully.`)); + this.log.log(chalk.bold.green(`Entity ${this.entityData.entityNameCapitalized} generated successfully.`)); }, }; } @@ -328,7 +308,7 @@ export default class EntityGenerator extends BaseApplicationGenerator { if (entityName.indexOf('Detail', entityName.length - 'Detail'.length) !== -1) { return "The entity name cannot end with 'Detail'"; } - if (!this.context.skipServer && isReservedClassName(entityName)) { + if (!this.entityData.skipServer && isReservedClassName(entityName)) { return 'The entity name cannot contain a Java or JHipster reserved keyword'; } return true; diff --git a/generators/entity/prompts.mjs b/generators/entity/prompts.mjs index 3a7c367e7ddb..647d053a983a 100644 --- a/generators/entity/prompts.mjs +++ b/generators/entity/prompts.mjs @@ -80,7 +80,7 @@ const getFieldNameUndercored = fields => ); function askForMicroserviceJson() { - const context = this.context; + const context = this.entityData; if (this.jhipsterConfig.applicationType !== GATEWAY || context.configExisted) { return undefined; } @@ -120,7 +120,7 @@ function askForMicroserviceJson() { } function askForUpdate() { - const context = this.context; + const context = this.entityData; // ask only if running an existing entity without arg option --force or --regenerate const isForce = this.options.force || context.regenerate; context.updateEntity = 'regenerate'; // default if skipping questions by --force @@ -163,7 +163,7 @@ function askForUpdate() { } function askForFields() { - const context = this.context; + const context = this.entityData; // don't prompt if data is imported from a file if (this.options.defaults || (context.useConfigurationFile && context.updateEntity !== 'add')) { return undefined; @@ -177,7 +177,7 @@ function askForFields() { } function askForFieldsToRemove() { - const context = this.context; + const context = this.entityData; // prompt only if data is imported from a file if (!context.useConfigurationFile || context.updateEntity !== 'remove' || this.entityConfig.fields.length === 0) { return undefined; @@ -217,7 +217,7 @@ function askForFieldsToRemove() { } function askForRelationships() { - const context = this.context; + const context = this.entityData; if (this.options.defaults) { return undefined; } @@ -233,7 +233,7 @@ function askForRelationships() { } function askForRelationsToRemove() { - const context = this.context; + const context = this.entityData; // prompt only if data is imported from a file if (!context.useConfigurationFile || context.updateEntity !== 'remove' || this.entityConfig.relationships.length === 0) { return undefined; @@ -279,7 +279,7 @@ function askForRelationsToRemove() { } function askForFiltering() { - const context = this.context; + const context = this.entityData; // don't prompt if server is skipped, or the backend is not sql, or no service requested if (context.useConfigurationFile || context.skipServer || context.databaseType !== 'sql' || this.entityConfig.service === 'no') { return undefined; @@ -308,7 +308,7 @@ function askForFiltering() { } function askForReadOnly() { - const context = this.context; + const context = this.entityData; // don't prompt if data is imported from a file if (context.useConfigurationFile) { return undefined; @@ -327,7 +327,7 @@ function askForReadOnly() { } function askForDTO() { - const context = this.context; + const context = this.entityData; // don't prompt if data is imported from a file or server is skipped or if no service layer if (context.useConfigurationFile || context.skipServer || this.entityConfig.service === 'no') { return undefined; @@ -356,7 +356,7 @@ function askForDTO() { } function askForService() { - const context = this.context; + const context = this.entityData; // don't prompt if data is imported from a file or server is skipped if (context.useConfigurationFile || context.skipServer) { return undefined; @@ -389,7 +389,7 @@ function askForService() { } function askForPagination() { - const context = this.context; + const context = this.entityData; // don't prompt if data are imported from a file if (context.useConfigurationFile) { return undefined; @@ -429,7 +429,7 @@ function askForPagination() { * ask question for a field creation */ function askForField() { - const context = this.context; + const context = this.entityData; this.log.log(chalk.green(`\nGenerating field #${this.entityConfig.fields.length + 1}\n`)); const skipServer = context.skipServer; const databaseType = context.databaseType; @@ -879,7 +879,7 @@ function askForField() { * ask question for a relationship creation */ function askForRelationship() { - const context = this.context; + const context = this.entityData; const name = context.name; this.log.log(chalk.green('\nGenerating relationships to other entities\n')); const prompts = [ @@ -1072,7 +1072,7 @@ function askForRelationship() { * Show the entity and it's fields and relationships in console */ function logFieldsAndRelationships() { - const context = this.context; + const context = this.entityData; if (this.entityConfig.fields.length > 0 || this.entityConfig.relationships.length > 0) { this.log.log(chalk.red(chalk.white('\n================= ') + context.name + chalk.white(' ================='))); } diff --git a/generators/server/generator.mjs b/generators/server/generator.mjs index 51b3fdf247b4..96818b40fd69 100644 --- a/generators/server/generator.mjs +++ b/generators/server/generator.mjs @@ -142,10 +142,6 @@ const WAIT_TIMEOUT = 3 * 60000; const { NO: NO_PAGINATION } = PaginationTypes; const { NO: NO_SERVICE } = ServiceTypes; -/** - * @class - * @extends {BaseApplicationGenerator} - */ export default class JHipsterServerGenerator extends BaseApplicationGenerator { /** @type {string} */ jhipsterDependenciesVersion; @@ -452,21 +448,17 @@ export default class JHipsterServerGenerator extends BaseApplicationGenerator { } }, configureEntityTable({ application, entityName, entityConfig, entityStorage }) { + if ((application.applicationTypeGateway && entityConfig.microserviceName) || entityConfig.skipServer) return; + entityConfig.entityTableName = entityConfig.entityTableName || hibernateSnakeCase(entityName); - const fixedEntityTableName = this._fixEntityTableName( - entityConfig.entityTableName, - entityConfig.prodDatabaseType ?? application.prodDatabaseType, - application.jhiTablePrefix, - ); + const databaseType = + entityConfig.prodDatabaseType ?? application.prodDatabaseType ?? entityConfig.databaseType ?? application.databaseType; + const fixedEntityTableName = this._fixEntityTableName(entityConfig.entityTableName, databaseType, application.jhiTablePrefix); if (fixedEntityTableName !== entityConfig.entityTableName) { entityConfig.entityTableName = fixedEntityTableName; } - const validation = this._validateTableName( - entityConfig.entityTableName, - entityConfig.prodDatabaseType ?? application.prodDatabaseType, - entityConfig, - ); + const validation = this._validateTableName(entityConfig.entityTableName, databaseType, entityConfig); if (validation !== true) { throw new Error(validation); }