diff --git a/lib/export/jhipster_entity_exporter.js b/lib/export/jhipster_entity_exporter.js index aee9b391..8949fcbb 100644 --- a/lib/export/jhipster_entity_exporter.js +++ b/lib/export/jhipster_entity_exporter.js @@ -18,6 +18,7 @@ */ const fs = require('fs'); +const ApplicationTypes = require('../core/jhipster/application_types'); const readEntityJSON = require('../reader/json_file_reader').readEntityJSON; const toFilePath = require('../reader/json_file_reader').toFilePath; const FileUtils = require('../utils/file_utils'); @@ -26,6 +27,8 @@ const BuildException = require('../exceptions/exception_factory').BuildException const exceptions = require('../exceptions/exception_factory').exceptions; const DeprecationUtils = require('../utils/deprecation_utils'); +let configuration = {}; + module.exports = { exportToJSON, exportEntities, @@ -37,45 +40,60 @@ module.exports = { * Exports the passed entities to JSON. * @param entities the entities to export. * @param forceNoFiltering whether to filter out unchanged entities. + * @param applicationName + * @param applicationType * @returns The exported entities. * @deprecated Use ::exportEntities instead. */ -function exportToJSON(entities, forceNoFiltering) { +function exportToJSON(entities, forceNoFiltering, applicationName, applicationType) { DeprecationUtils.displayMethodDeprecationMessage({ deprecatedMethod: 'JHipsterEntityExporter::exportToJSON', preferredMethod: 'JHipsterEntityExporter::exportEntities' }); return exportEntities({ entities, - forceNoFiltering + forceNoFiltering, + applicationName, + applicationType }); } /** * Exports the passed entities to JSON. - * @param configuration the object having the keys: + * @param passedConfiguration the object having the keys: * - entities: the entities to export, * - forceNoFiltering: whether to filter out unchanged entities + * - applicationName: the application name, + * - applicationType: the application type * @returns {*} The exported entities. */ -function exportEntities(configuration) { - if (!configuration.entities) { - throw new BuildException( - exceptions.NullPointer, - 'Entities have to be passed to be exported.'); - } +function exportEntities(passedConfiguration) { + init(passedConfiguration); createJHipsterJSONFolder(); if (!configuration.forceNoFiltering) { - configuration.entities = filterOutUnchangedEntities(configuration.entities); + filterOutUnchangedEntities(); } - for (let i = 0, entityNames = Object.keys(configuration.entities); i < entityNames.length; i++) { - const filePath = toFilePath(entityNames[i]); - const entity = updateChangelogDate(filePath, configuration.entities[entityNames[i]]); - fs.writeFileSync(filePath, JSON.stringify(entity, null, 4)); + if (shouldFilterOutEntitiesBasedOnMicroservice()) { + filterOutEntitiesByMicroservice(); } + writeEntities(); return configuration.entities; } +function init(passedConfiguration) { + if (!passedConfiguration.entities) { + throw new BuildException( + exceptions.NullPointer, + 'Entities have to be passed to be exported.'); + } + configuration = passedConfiguration; +} + +function shouldFilterOutEntitiesBasedOnMicroservice() { + return configuration.applicationType && configuration.applicationType === ApplicationTypes.MICROSERVICE + && configuration.applicationName; +} + /** * Creates the JHipster entity folder, if possible. */ @@ -83,6 +101,14 @@ function createJHipsterJSONFolder() { FileUtils.createDirectory('.jhipster'); } +function writeEntities() { + for (let i = 0, entityNames = Object.keys(configuration.entities); i < entityNames.length; i++) { + const filePath = toFilePath(entityNames[i]); + const entity = updateChangelogDate(filePath, configuration.entities[entityNames[i]]); + fs.writeFileSync(filePath, JSON.stringify(entity, null, 4)); + } +} + function updateChangelogDate(filePath, entity) { if (FileUtils.doesFileExist(filePath)) { const fileOnDisk = readEntityJSON(filePath); @@ -93,14 +119,23 @@ function updateChangelogDate(filePath, entity) { return entity; } -function filterOutUnchangedEntities(entities) { - const filtered = {}; - for (let i = 0, entityNames = Object.keys(entities); i < entityNames.length; i++) { +function filterOutUnchangedEntities() { + for (let i = 0, entityNames = Object.keys(configuration.entities); i < entityNames.length; i++) { const entityName = entityNames[i]; const filePath = toFilePath(entityName); - if (!(FileUtils.doesFileExist(filePath) && areJHipsterEntitiesEqual(readEntityJSON(filePath), entities[entityName]))) { - filtered[entityName] = (entities[entityName]); + if (FileUtils.doesFileExist(filePath) + && areJHipsterEntitiesEqual(readEntityJSON(filePath), configuration.entities[entityName])) { + delete configuration.entities[entityName]; + } + } +} + +function filterOutEntitiesByMicroservice() { + for (let i = 0, entityNames = Object.keys(configuration.entities); i < entityNames.length; i++) { + const entity = configuration.entities[entityNames[i]]; + if (entity.microserviceName + && entity.microserviceName.toLowerCase() !== configuration.applicationName.toLowerCase()) { + delete configuration.entities[entityNames[i]]; } } - return filtered; } diff --git a/test/spec/export/jhipster_entity_exporter_test.js b/test/spec/export/jhipster_entity_exporter_test.js index 2fa630bb..692274c8 100644 --- a/test/spec/export/jhipster_entity_exporter_test.js +++ b/test/spec/export/jhipster_entity_exporter_test.js @@ -22,175 +22,299 @@ const expect = require('chai').expect; const fs = require('fs'); const fail = expect.fail; +const ApplicationTypes = require('../../../lib/core/jhipster/application_types'); const Exporter = require('../../../lib/export/jhipster_entity_exporter'); const DocumentParser = require('../../../lib/parser/document_parser'); const EntityParser = require('../../../lib/parser/entity_parser'); const parseFromFiles = require('../../../lib/reader/jdl_reader').parseFromFiles; +const FileUtils = require('../../../lib/utils/file_utils'); -// todo client this test file -describe('::exportToJSON', () => { - describe('when passing invalid parameters', () => { - describe('such as undefined', () => { - it('throws an error', () => { - try { - Exporter.exportToJSON(); - fail(); - } catch (error) { - expect(error.name).to.eq('NullPointerException'); - } - }); - }); - }); - describe('when passing valid arguments', () => { - describe('when exporting JDL to entity json for SQL type', () => { - const input = parseFromFiles(['./test/test_files/complex_jdl.jdl']); - const content = EntityParser.parse({ - jdlObject: DocumentParser.parse(input, 'sql'), - databaseType: 'sql' - }); - Exporter.exportToJSON(content); - const department = JSON.parse(fs.readFileSync('.jhipster/Department.json', { encoding: 'utf-8' })); - const jobHistory = JSON.parse(fs.readFileSync('.jhipster/JobHistory.json', { encoding: 'utf-8' })); - it('exports it', () => { - expect(fs.statSync('.jhipster/Department.json').isFile()).to.be.true; - expect(fs.statSync('.jhipster/JobHistory.json').isFile()).to.be.true; - expect(fs.statSync('.jhipster/Job.json').isFile()).to.be.true; - expect(fs.statSync('.jhipster/Employee.json').isFile()).to.be.true; - expect(fs.statSync('.jhipster/Location.json').isFile()).to.be.true; - expect(fs.statSync('.jhipster/Task.json').isFile()).to.be.true; - expect(fs.statSync('.jhipster/Country.json').isFile()).to.be.true; - expect(fs.statSync('.jhipster/Region.json').isFile()).to.be.true; - expect(department.relationships).to.deep.eq([ - { - relationshipType: 'one-to-one', - relationshipName: 'location', - otherEntityName: 'location', - otherEntityField: 'id', - ownerSide: true, - otherEntityRelationshipName: 'department' - }, - { - relationshipType: 'one-to-many', - javadoc: 'A relationship', - relationshipName: 'employee', - otherEntityName: 'employee', - otherEntityRelationshipName: 'department' +describe('JHipsterEntityExporter', () => { + describe('::exportEntities', () => { + context('when passing invalid parameters', () => { + context('such as undefined', () => { + it('throws an error', () => { + try { + Exporter.exportToJSON(); + fail(); + } catch (error) { + expect(error.name).to.eq('NullPointerException'); } - ]); - expect(department.fields).to.deep.eq([ - { - fieldName: 'departmentId', - fieldType: 'Long' - }, - { - fieldName: 'departmentName', - fieldType: 'String', - fieldValidateRules: ['required'] - }, - { - fieldName: 'description', - fieldType: 'byte[]', - fieldTypeBlobContent: 'text' - }, - { - fieldName: 'advertisement', - fieldType: 'byte[]', - fieldTypeBlobContent: 'any' - }, - { - fieldName: 'logo', - fieldType: 'byte[]', - fieldTypeBlobContent: 'image' - } - ]); - expect(department.dto).to.eq('no'); - expect(department.service).to.eq('no'); - expect(department.pagination).to.eq('no'); - expect(jobHistory.relationships).to.deep.eq([ - { - relationshipType: 'one-to-one', - relationshipName: 'department', - otherEntityName: 'department', - otherEntityField: 'id', - ownerSide: true, - otherEntityRelationshipName: 'jobHistory' - }, - { - relationshipType: 'one-to-one', - relationshipName: 'job', - otherEntityName: 'job', - otherEntityField: 'id', - ownerSide: true, - otherEntityRelationshipName: 'jobHistory' - }, - { - relationshipType: 'one-to-one', - relationshipName: 'employee', - otherEntityName: 'employee', - otherEntityField: 'id', - ownerSide: true, - otherEntityRelationshipName: 'jobHistory' - } - ]); - expect(jobHistory.fields).to.deep.eq([ - { - fieldName: 'startDate', - fieldType: 'ZonedDateTime' - }, - { - fieldName: 'endDate', - fieldType: 'ZonedDateTime' - }, - { - fieldName: 'language', - fieldType: 'Language', - fieldValues: 'FRENCH,ENGLISH,SPANISH' - } - ]); - expect(jobHistory.dto).to.eq('no'); - expect(jobHistory.service).to.eq('no'); - expect(jobHistory.pagination).to.eq('infinite-scroll'); - // clean up the mess... - fs.unlinkSync('.jhipster/Department.json'); - fs.unlinkSync('.jhipster/JobHistory.json'); - fs.unlinkSync('.jhipster/Job.json'); - fs.unlinkSync('.jhipster/Employee.json'); - fs.unlinkSync('.jhipster/Location.json'); - fs.unlinkSync('.jhipster/Task.json'); - fs.unlinkSync('.jhipster/Country.json'); - fs.unlinkSync('.jhipster/Region.json'); - fs.rmdirSync('.jhipster'); + }); }); }); - describe('when exporting JDL to entity json for an existing entity', () => { - let input = parseFromFiles(['./test/test_files/valid_jdl.jdl']); - let content = EntityParser.parse({ - jdlObject: DocumentParser.parse(input, 'sql'), - databaseType: 'sql' + context('when passing valid arguments', () => { + context('when exporting JDL to entity json for SQL type', () => { + let department = null; + let jobHistory = null; + + before(() => { + const input = parseFromFiles(['./test/test_files/complex_jdl.jdl']); + const content = EntityParser.parse({ + jdlObject: DocumentParser.parseFromConfigurationObject({ + document: input, + databaseType: 'sql' + }), + databaseType: 'sql' + }); + Exporter.exportToJSON(content); + department = JSON.parse(fs.readFileSync('.jhipster/Department.json', { encoding: 'utf-8' })); + jobHistory = JSON.parse(fs.readFileSync('.jhipster/JobHistory.json', { encoding: 'utf-8' })); + }); + + it('exports it', () => { + expect(fs.statSync('.jhipster/Department.json').isFile()).to.be.true; + expect(fs.statSync('.jhipster/JobHistory.json').isFile()).to.be.true; + expect(fs.statSync('.jhipster/Job.json').isFile()).to.be.true; + expect(fs.statSync('.jhipster/Employee.json').isFile()).to.be.true; + expect(fs.statSync('.jhipster/Location.json').isFile()).to.be.true; + expect(fs.statSync('.jhipster/Task.json').isFile()).to.be.true; + expect(fs.statSync('.jhipster/Country.json').isFile()).to.be.true; + expect(fs.statSync('.jhipster/Region.json').isFile()).to.be.true; + expect(department.relationships).to.deep.eq([ + { + relationshipType: 'one-to-one', + relationshipName: 'location', + otherEntityName: 'location', + otherEntityField: 'id', + ownerSide: true, + otherEntityRelationshipName: 'department' + }, + { + relationshipType: 'one-to-many', + javadoc: 'A relationship', + relationshipName: 'employee', + otherEntityName: 'employee', + otherEntityRelationshipName: 'department' + } + ]); + expect(department.fields).to.deep.eq([ + { + fieldName: 'departmentId', + fieldType: 'Long' + }, + { + fieldName: 'departmentName', + fieldType: 'String', + fieldValidateRules: ['required'] + }, + { + fieldName: 'description', + fieldType: 'byte[]', + fieldTypeBlobContent: 'text' + }, + { + fieldName: 'advertisement', + fieldType: 'byte[]', + fieldTypeBlobContent: 'any' + }, + { + fieldName: 'logo', + fieldType: 'byte[]', + fieldTypeBlobContent: 'image' + } + ]); + expect(department.dto).to.eq('no'); + expect(department.service).to.eq('no'); + expect(department.pagination).to.eq('no'); + expect(jobHistory.relationships).to.deep.eq([ + { + relationshipType: 'one-to-one', + relationshipName: 'department', + otherEntityName: 'department', + otherEntityField: 'id', + ownerSide: true, + otherEntityRelationshipName: 'jobHistory' + }, + { + relationshipType: 'one-to-one', + relationshipName: 'job', + otherEntityName: 'job', + otherEntityField: 'id', + ownerSide: true, + otherEntityRelationshipName: 'jobHistory' + }, + { + relationshipType: 'one-to-one', + relationshipName: 'employee', + otherEntityName: 'employee', + otherEntityField: 'id', + ownerSide: true, + otherEntityRelationshipName: 'jobHistory' + } + ]); + expect(jobHistory.fields).to.deep.eq([ + { + fieldName: 'startDate', + fieldType: 'ZonedDateTime' + }, + { + fieldName: 'endDate', + fieldType: 'ZonedDateTime' + }, + { + fieldName: 'language', + fieldType: 'Language', + fieldValues: 'FRENCH,ENGLISH,SPANISH' + } + ]); + expect(jobHistory.dto).to.eq('no'); + expect(jobHistory.service).to.eq('no'); + expect(jobHistory.pagination).to.eq('infinite-scroll'); + }); + + after(() => { + fs.unlinkSync('.jhipster/Department.json'); + fs.unlinkSync('.jhipster/JobHistory.json'); + fs.unlinkSync('.jhipster/Job.json'); + fs.unlinkSync('.jhipster/Employee.json'); + fs.unlinkSync('.jhipster/Location.json'); + fs.unlinkSync('.jhipster/Task.json'); + fs.unlinkSync('.jhipster/Country.json'); + fs.unlinkSync('.jhipster/Region.json'); + fs.rmdirSync('.jhipster'); + }); }); - it('exports it with same changeLogDate', (done) => { - Exporter.exportToJSON(content); - expect(fs.statSync('.jhipster/A.json').isFile()).to.be.true; - const changeLogDate = JSON.parse(fs.readFileSync('.jhipster/A.json', { encoding: 'utf-8' })).changelogDate; - setTimeout(() => { - input = parseFromFiles(['./test/test_files/valid_jdl.jdl']); - content = EntityParser.parse({ - jdlObject: DocumentParser.parse(input, 'sql'), + context('when exporting JDL to entity json for an existing entity', () => { + let changeLogDate = null; + + before(() => { + const input = parseFromFiles(['./test/test_files/valid_jdl.jdl']); + const content = EntityParser.parse({ + jdlObject: DocumentParser.parseFromConfigurationObject({ + document: input, + databaseType: 'sql' + }), databaseType: 'sql' }); - Exporter.exportToJSON(content, true); - expect(fs.statSync('.jhipster/A.json').isFile()).to.be.true; - const newChangeLogDate = JSON.parse(fs.readFileSync('.jhipster/A.json', { encoding: 'utf-8' })).changelogDate; - expect(newChangeLogDate).to.eq(changeLogDate); - // clean up the mess... + Exporter.exportToJSON(content); + changeLogDate = JSON.parse(fs.readFileSync('.jhipster/A.json', { encoding: 'utf-8' })).changelogDate; + }); + + it('exports it with same changeLogDate', (done) => { + setTimeout(() => { + const input = parseFromFiles(['./test/test_files/valid_jdl.jdl']); + const content = EntityParser.parse({ + jdlObject: DocumentParser.parseFromConfigurationObject({ + document: input, + databaseType: 'sql' + }), + databaseType: 'sql' + }); + Exporter.exportToJSON(content, true); + expect(fs.statSync('.jhipster/A.json').isFile()).to.be.true; + const newChangeLogDate = JSON.parse(fs.readFileSync('.jhipster/A.json', { encoding: 'utf-8' })).changelogDate; + expect(newChangeLogDate).to.eq(changeLogDate); + done(); + }, 1000); + }); + + after(() => { fs.unlinkSync('.jhipster/A.json'); fs.unlinkSync('.jhipster/B.json'); fs.unlinkSync('.jhipster/C.json'); fs.unlinkSync('.jhipster/D.json'); fs.rmdirSync('.jhipster'); - done(); - }, 1000); + }); + }); + context('when passing an application name and application type', () => { + context('inside a monolith', () => { + before(() => { + const input = parseFromFiles(['./test/test_files/two_microservices.jdl']); + const content = EntityParser.parse({ + jdlObject: DocumentParser.parseFromConfigurationObject({ + document: input, + databaseType: 'sql' + }), + databaseType: 'sql', + applicationType: ApplicationTypes.MONOLITH + }); + Exporter.exportEntities({ + entities: content, + applicationName: 'client', + applicationType: ApplicationTypes.MONOLITH + }); + }); + + it('exports every entity', () => { + expect(FileUtils.doesFileExist('.jhipster/Client.json')); + expect(FileUtils.doesFileExist('.jhipster/Location.json')); + expect(FileUtils.doesFileExist('.jhipster/LocalStore.json')); + expect(FileUtils.doesFileExist('.jhipster/Product.json')); + }); + + after(() => { + fs.unlinkSync('.jhipster/Client.json'); + fs.unlinkSync('.jhipster/Location.json'); + fs.unlinkSync('.jhipster/LocalStore.json'); + fs.unlinkSync('.jhipster/Product.json'); + fs.rmdirSync('.jhipster'); + }); + }); + context('inside a microservice', () => { + context('and when entities without the microservice option are passed', () => { + before(() => { + const input = parseFromFiles(['./test/test_files/no_microservice.jdl']); + const content = EntityParser.parse({ + jdlObject: DocumentParser.parseFromConfigurationObject({ + document: input, + databaseType: 'sql' + }), + databaseType: 'sql', + applicationType: ApplicationTypes.MICROSERVICE + }); + Exporter.exportEntities({ + entities: content, + applicationName: 'client', + applicationType: ApplicationTypes.MICROSERVICE + }); + }); + + it('exports every entity', () => { + ['A', 'B', 'C', 'D', 'E', 'F', 'G'].forEach((entityName) => { + expect(FileUtils.doesFileExist(`.jhipster/${entityName}.json`)).to.be.true; + }); + }); + + after(() => { + ['A', 'B', 'C', 'D', 'E', 'F', 'G'].forEach((entityName) => { + fs.unlinkSync(`.jhipster/${entityName}.json`); + }); + fs.rmdirSync('.jhipster'); + }); + }); + context('and when microservice entities are passed', () => { + before(() => { + const input = parseFromFiles(['./test/test_files/two_microservices.jdl']); + const content = EntityParser.parse({ + jdlObject: DocumentParser.parseFromConfigurationObject({ + document: input, + databaseType: 'sql' + }), + databaseType: 'sql', + applicationType: ApplicationTypes.MICROSERVICE + }); + Exporter.exportEntities({ + entities: content, + applicationName: 'client', + applicationType: ApplicationTypes.MICROSERVICE + }); + }); + + it('only exports the entities that should be inside the microservice', () => { + expect(FileUtils.doesFileExist('.jhipster/Client.json')); + expect(FileUtils.doesFileExist('.jhipster/Location.json')); + }); + + after(() => { + fs.unlinkSync('.jhipster/Client.json'); + fs.unlinkSync('.jhipster/Location.json'); + fs.rmdirSync('.jhipster'); + }); + }); + }); }); }); }); }); + diff --git a/test/test_files/two_microservices.jdl b/test/test_files/two_microservices.jdl new file mode 100644 index 00000000..0054b89f --- /dev/null +++ b/test/test_files/two_microservices.jdl @@ -0,0 +1,16 @@ +entity Client (client) +entity Location (location) +entity LocalStore (local_store) +entity Product (product) { + name String +} + +relationship OneToMany { + Location{clients} to Client{location}, + LocalStore{products} to Product{store} +} + +service Client, Location, LocalStore, Product with serviceClass +microservice Client, Location with client +filter Client, Location, LocalStore, Product +microservice LocalStore, Product with store