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
JavaScript
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),
};
}
;