UNPKG

quick-erd

Version:

quick and easy text-based ERD + code generator for migration, query, typescript types and orm entity

255 lines (242 loc) 7.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.textToSpring = textToSpring; exports.setupDirectories = setupDirectories; exports.initPackage = initPackage; exports.findDir = findDir; exports.findSrcDir = findSrcDir; exports.findSpringBootApplication = findSpringBootApplication; exports.toJavaType = toJavaType; const fs_1 = require("fs"); const path_1 = require("path"); const ast_1 = require("../core/ast"); const sort_tables_1 = require("./sort-tables"); const case_1 = require("../utils/case"); const file_1 = require("../utils/file"); const enum_1 = require("../core/enum"); function textToSpring(dbClient, text) { const result = (0, ast_1.parse)(text); const table_list = (0, sort_tables_1.sortTables)(result.table_list); const package_name_list = ['entity', 'repository', 'projection']; const app = setupDirectories(package_name_list); for (const table of table_list) { setupEntity(dbClient, app, table); setupRepository(app, table); } } function setupDirectories(package_name_list) { const srcDir = findSrcDir(); const app = findSpringBootApplication(srcDir); if (!app) { console.error('Error: failed to locate spring boot application package'); process.exit(1); } for (const name of package_name_list) { initPackage(app, name); } return app; } function initPackage(app, name) { const dir = (0, path_1.join)(app.dir, name); (0, fs_1.mkdirSync)(dir, { recursive: true }); } function findDir(dirname) { let rootDir = '.'; let srcDir; for (;;) { srcDir = (0, path_1.join)(rootDir, dirname); if ((0, fs_1.existsSync)(srcDir)) break; const newRootDir = (0, path_1.join)('..', rootDir); if ((0, path_1.resolve)(newRootDir) == (0, path_1.resolve)(rootDir)) { throw new Error(`failed to locate the ${dirname} directory of java project`); } rootDir = newRootDir; } return srcDir; } function findSrcDir() { try { return findDir('src'); } catch (error) { console.error(`Error: failed to locate the src directory of java project`); process.exit(1); } } function findSpringBootApplication(dir) { for (const filename of (0, fs_1.readdirSync)(dir)) { const file = (0, path_1.join)(dir, filename); const stat = (0, fs_1.statSync)(file); if (stat.isFile() && filename.endsWith('Application.java')) { const packageName = findSpringBootApplicationPackage(file); if (packageName) { return { dir, package: packageName }; } } if (stat.isDirectory()) { const res = findSpringBootApplication(file); if (res) return res; } } } function findSpringBootApplicationPackage(file) { const code = (0, fs_1.readFileSync)(file).toString(); let packageName; let isSpringApplication = false; for (let line of code.split('\n')) { line = line.trim(); isSpringApplication ||= line.startsWith('@SpringBootApplication'); packageName ||= line.match(/^package ([\w\.]+);/)?.[1]; if (isSpringApplication && packageName) return packageName; } } function setupEntity(dbClient, app, table) { const dir = (0, path_1.join)(app.dir, 'entity'); const ClassName = (0, case_1.snake_to_Pascal)(table.name) + 'Entity'; const file = (0, path_1.join)(dir, `${ClassName}.java`); const imports = new Set(); let fieldLines = ''; let methodLines = ''; for (const field of table.field_list) { if (field.name === 'id') { continue; } const is_enum = field.type.match(/^enum/i); if (is_enum) { setupEnum(app, table, field); imports.add('import jakarta.persistence.EnumType;'); } const type = toJavaType(table, field); if (type.import) { imports.add(type.import); } const fieldName = (0, case_1.snake_to_camel)(field.name); const FieldName = (0, case_1.snake_to_Pascal)(field.name); let annotation = `@Column(name = "\`${field.name}\`", nullable = ${field.is_null})`; if (is_enum) { annotation += '\n @Enumerated(EnumType.STRING)'; } fieldLines += ` ${annotation} private ${type.Class} ${fieldName};`; methodLines += ` public ${type.Class} get${FieldName}() { return ${fieldName}; } public void set${FieldName}(${type.Class} ${fieldName}) { this.${fieldName} = ${fieldName}; }`; } let importLines = Array.from(imports).join('\n'); importLines = ` import jakarta.persistence.*; ${importLines} `.trim(); const idAnnotation = dbClient == 'postgresql' ? '@GeneratedValue(strategy = GenerationType.IDENTITY)' : '@GeneratedValue'; const code = ` package ${app.package}.entity; ${importLines} @Entity @Table(name = "\`${table.name}\`") public class ${ClassName} { @Id ${idAnnotation} @Column(name = "\`id\`") private Long id; ${fieldLines.trim()} public Long getId() { return id; } public void setId(Long id) { this.id = id; } ${methodLines.trim()} `.trim() + ` }`; (0, file_1.writeSrcFileIfNeeded)(file, code); } function setupEnum(app, table, field) { const dir = (0, path_1.join)(app.dir, 'entity'); const ClassName = (0, case_1.snake_to_Pascal)(table.name) + (0, case_1.snake_to_Pascal)(field.name); const file = (0, path_1.join)(dir, `${ClassName}.java`); const values = (0, enum_1.parseEnumValues)(field.type); let code = ` package ${app.package}.entity; public enum ${ClassName} {`; code += values.map(value => '\n ' + value + ',').join(''); code += '\n}'; (0, file_1.writeSrcFileIfNeeded)(file, code); } function setupRepository(app, table) { const dir = (0, path_1.join)(app.dir, 'repository'); const ClassName = (0, case_1.snake_to_Pascal)(table.name); const file = (0, path_1.join)(dir, `${ClassName}Repository.java`); if ((0, fs_1.existsSync)(file)) return; const code = ` package ${app.package}.repository; import ${app.package}.entity.${ClassName}Entity; import org.springframework.data.repository.CrudRepository; public interface ${ClassName}Repository extends CrudRepository<${ClassName}Entity, Long> { } `; (0, file_1.writeSrcFile)(file, code); } function toJavaType(table, field) { const type = field.type; if (type.match(/^n?varchar/i) || type.match(/^char/i) || type.match(/^string/i) || type.match(/^text/i)) { return { Class: 'String' }; } if (type.match(/^integer/i)) { return { Class: 'Long' }; } if (type.match(/^int/i)) { return { Class: 'Integer' }; } if (type.match(/^real/i)) { return { Class: 'Double' }; } if (type.match(/^float/i)) { return { Class: 'Float' }; } if (type.match(/^timestamp/i)) { return { Class: 'Timestamp', import: 'import java.sql.Timestamp;', }; } if (type.match(/^date/i)) { return { Class: 'Date', import: 'import java.sql.Date;', }; } if (type.match(/^time/i)) { return { Class: 'Time', import: 'import java.sql.Time;', }; } if (type.match(/^enum/i)) { return { Class: (0, case_1.snake_to_Pascal)(table.name) + (0, case_1.snake_to_Pascal)(field.name), import: 'import jakarta.persistence.Enumerated;', }; } if (type.match(/^boolean/i)) { return { Class: 'Boolean' }; } console.error('Unknown Java class for field.type:', field.type); return { Class: (0, case_1.snake_to_Pascal)(field.type), }; }