- 重构sys模块架构,严格按admin/api/core分层 - 对齐所有sys实体与数据库表结构 - 实现完整的adminapi控制器,匹配PHP/Java契约 - 修复依赖注入问题,确保服务正确注册 - 添加自动迁移工具和契约验证 - 完善多租户支持和审计功能 - 统一命名规范,与PHP业务逻辑保持一致
103 lines
3.7 KiB
JavaScript
103 lines
3.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const repoRoot = path.resolve(__dirname, '..');
|
|
const sqlFile = path.join(repoRoot, 'sql', 'wwjcloud.sql');
|
|
const outDir = path.join(repoRoot, 'temp', 'entities');
|
|
|
|
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
|
|
|
const sql = fs.readFileSync(sqlFile, 'utf8');
|
|
|
|
// crude parser: split by CREATE TABLE `table`
|
|
const tableRegex = /CREATE TABLE\s+`([^`]+)`\s*\(([^;]+)\)\s*ENGINE=[^;]+;/gim;
|
|
|
|
function pascalCase(name) {
|
|
return name
|
|
.replace(/^[^a-zA-Z]+/, '')
|
|
.split(/[_\-\s]+/)
|
|
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
|
.join('');
|
|
}
|
|
|
|
function mapColumnType(def) {
|
|
const d = def.toLowerCase();
|
|
if (d.startsWith('int') || d.startsWith('tinyint') || d.startsWith('smallint') || d.startsWith('bigint')) return { type: 'int' };
|
|
if (d.startsWith('varchar')) {
|
|
const m = d.match(/varchar\((\d+)\)/);
|
|
return { type: 'varchar', length: m ? parseInt(m[1], 10) : 255 };
|
|
}
|
|
if (d.startsWith('text') || d.includes('longtext')) return { type: 'text' };
|
|
if (d.startsWith('decimal')) {
|
|
const m = d.match(/decimal\((\d+)\s*,\s*(\d+)\)/);
|
|
return { type: 'decimal', precision: m ? parseInt(m[1], 10) : 10, scale: m ? parseInt(m[2], 10) : 2 };
|
|
}
|
|
if (d.startsWith('timestamp')) return { type: 'int' };
|
|
if (d.startsWith('datetime')) return { type: 'int' };
|
|
if (d.startsWith('enum')) return { type: 'varchar', length: 255 };
|
|
return { type: 'varchar', length: 255 };
|
|
}
|
|
|
|
function parseDefault(defPart) {
|
|
const m = defPart.match(/default\s+([^\s]+)/i);
|
|
if (!m) return undefined;
|
|
let v = m[1].trim();
|
|
v = v.replace(/^'/, '').replace(/'$/, '');
|
|
if (v.toLowerCase() === 'null') return undefined;
|
|
if (/^[0-9.]+$/.test(v)) return Number(v);
|
|
return `'${v}'`;
|
|
}
|
|
|
|
function generateEntity(tableName, columnsBlock) {
|
|
const className = pascalCase(tableName);
|
|
const lines = columnsBlock.split(/\n/).map((l) => l.trim()).filter(Boolean);
|
|
const fields = [];
|
|
for (const line of lines) {
|
|
if (line.startsWith('PRIMARY KEY') || line.startsWith('UNIQUE') || line.startsWith('KEY') || line.startsWith(')')) continue;
|
|
const m = line.match(/^`([^`]+)`\s+([^\s,]+)([^,]*),?$/);
|
|
if (!m) continue;
|
|
const col = m[1];
|
|
const typeDef = m[2];
|
|
const rest = m[3] || '';
|
|
const isPk = /auto_increment/i.test(rest) || col === 'id';
|
|
const { type, length, precision, scale } = mapColumnType(typeDef);
|
|
const defVal = parseDefault(rest);
|
|
fields.push({ col, isPk, type, length, precision, scale, defVal });
|
|
}
|
|
|
|
const imports = new Set(['Entity', 'Column']);
|
|
if (fields.some((f) => f.isPk)) imports.add('PrimaryGeneratedColumn');
|
|
const importLine = `import { ${Array.from(imports).join(', ')} } from 'typeorm';`;
|
|
|
|
const props = fields.map((f) => {
|
|
if (f.isPk) {
|
|
return ` @PrimaryGeneratedColumn({ type: 'int' })\n id: number;`;
|
|
}
|
|
const opts = [];
|
|
opts.push(`name: '${f.col}'`);
|
|
opts.push(`type: '${f.type}'`);
|
|
if (f.length) opts.push(`length: ${f.length}`);
|
|
if (f.precision) opts.push(`precision: ${f.precision}`);
|
|
if (f.scale !== undefined) opts.push(`scale: ${f.scale}`);
|
|
if (f.defVal !== undefined) opts.push(`default: ${f.defVal}`);
|
|
const propName = f.col.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
return ` @Column({ ${opts.join(', ')} })\n ${propName}: ${f.type === 'decimal' ? 'string' : 'any'};`;
|
|
}).join('\n\n');
|
|
|
|
return `${importLine}\n\n@Entity('${tableName}')\nexport class ${className} {\n${props}\n}\n`;
|
|
}
|
|
|
|
let match;
|
|
let count = 0;
|
|
while ((match = tableRegex.exec(sql)) !== null) {
|
|
const table = match[1];
|
|
const body = match[2];
|
|
const ts = generateEntity(table, body);
|
|
const outFile = path.join(outDir, `${table}.ts`);
|
|
fs.writeFileSync(outFile, ts, 'utf8');
|
|
count++;
|
|
}
|
|
|
|
console.log(`Generated ${count} entities into ${path.relative(repoRoot, outDir)}`);
|