qnc-server-tob/deploy/script/codegen.js

444 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* 代码生成统一入口脚本
* 整合了model生成和api生成功能
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const { generateApi } = require('./gen_api');
// 读取配置文件
const CONFIG_FILE = path.join(__dirname, 'config.json');
let config = {};
try {
if (fs.existsSync(CONFIG_FILE)) {
const configContent = fs.readFileSync(CONFIG_FILE, 'utf8');
config = JSON.parse(configContent);
console.log('Configuration loaded from config.json');
} else {
console.log('config.json not found, using default settings');
}
} catch (error) {
console.error('Error loading configuration:', error.message);
console.log('Using default settings');
}
// 默认数据库配置
const modelConfig = config.model || {
// 数据库连接信息
dbUrl: 'qnc:5vg67b3UNHu8@tcp(127.0.0.1:21001)/qnc',
// 输出目录
outputDir: './model',
// 模板目录
templateDir: '../template',
// 目标目录
targetDir: '../../app/user/model',
// 表名列表
tables: [
'agent',
'agent_audit',
'agent_real_name'
],
// 禁用的表名列表
disabledTables: []
};
// 默认API配置
const apiConfig = config.api || {
// API定义文件路径
apiFile: './app/user/cmd/api/desc/main.api',
// 输出目录
outputDir: './app/user/cmd/api',
// 模板目录
templateDir: './deploy/template',
// 是否使用样式
useStyle: false
};
/**
* 将表名转换为驼峰命名法
* @param {string} tableName 表名
* @returns {string} 驼峰命名的表名
*/
function convertToCamelCase(tableName) {
try {
// 将表名按_分割并将每个部分首字母大写
const parts = tableName.split('_');
let camelCase = '';
for (const part of parts) {
if (part.length > 0) {
camelCase += part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
}
}
return camelCase;
} catch (error) {
console.error(`Error in convertToCamelCase for table: ${tableName}`);
console.error(error.message);
return tableName; // 出错时返回原表名
}
}
/**
* 确保目录存在
* @param {string} dirPath 目录路径
*/
function ensureDirectoryExists(dirPath) {
if (!fs.existsSync(dirPath)) {
console.log(`Creating directory: ${dirPath}`);
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* 为单个表生成模型
* @param {string} table 表名
* @param {object} config 配置信息
*/
function generateModelForTable(table, config) {
try {
console.log('=========================================');
console.log(`Processing table: ${table}`);
// 生成模型
console.log('Generating model...');
const command = `goctl model mysql datasource -url="${config.dbUrl}" -table="${table}" -dir="${config.outputDir}" --home="${config.templateDir}" -cache=true --style=goZero`;
console.log(`Running command: ${command}`);
execSync(command, { stdio: 'inherit' });
// 将表名转换为驼峰命名法
const camelCaseName = convertToCamelCase(table);
console.log(`Table name converted to: ${camelCaseName}`);
// 定义源文件和目标文件路径
const sourceModelFile = path.join(config.outputDir, `${camelCaseName}Model.go`);
const sourceModelGenFile = path.join(config.outputDir, `${camelCaseName}Model_gen.go`);
const targetModelFile = path.join(config.targetDir, `${camelCaseName}Model.go`);
const targetModelGenFile = path.join(config.targetDir, `${camelCaseName}Model_gen.go`);
console.log('Source files:');
console.log(` - ${sourceModelFile}`);
console.log(` - ${sourceModelGenFile}`);
console.log('Target files:');
console.log(` - ${targetModelFile}`);
console.log(` - ${targetModelGenFile}`);
// 检查源文件是否存在并移动
if (fs.existsSync(sourceModelFile)) {
console.log(`Moving ${sourceModelFile} to ${targetModelFile}`);
fs.copyFileSync(sourceModelFile, targetModelFile);
fs.unlinkSync(sourceModelFile);
} else {
console.log(`WARNING: Source file not found: ${sourceModelFile}`);
}
if (fs.existsSync(sourceModelGenFile)) {
console.log(`Moving ${sourceModelGenFile} to ${targetModelGenFile}`);
fs.copyFileSync(sourceModelGenFile, targetModelGenFile);
fs.unlinkSync(sourceModelGenFile);
} else {
console.log(`WARNING: Source file not found: ${sourceModelGenFile}`);
}
console.log(`Processing completed for table: ${table}`);
} catch (error) {
console.error(`ERROR processing table: ${table}`);
console.error(error.message);
console.error(error.stack);
}
}
/**
* 生成指定表列表的模型
* @param {string[]} tables 表名列表
* @param {object} config 配置信息
*/
function generateModels(tables, config) {
try {
// 确保目录存在
ensureDirectoryExists(config.outputDir);
ensureDirectoryExists(config.targetDir);
if (tables.length === 0) {
console.log('No tables specified for generation.');
return;
}
// 为每个表生成模型
for (const table of tables) {
generateModelForTable(table, config);
}
console.log('=========================================');
console.log('All models generated successfully.');
} catch (error) {
console.error('ERROR in model generation:');
console.error(error.message);
console.error(error.stack);
process.exit(1);
}
}
/**
* 从数据库获取所有表名
* @param {string} dbUrl 数据库连接URL
* @returns {Promise<string[]>} 表名列表
*/
async function getAllTablesFromDB(dbUrl) {
try {
// 解析数据库连接信息
const dbName = dbUrl.split('/').pop().split('?')[0];
console.log(`Fetching all tables from database: ${dbName}`);
// 这里需要实现从数据库获取所有表的逻辑
// 由于需要依赖额外的库,这里只是示例
// 实际实现可能需要使用mysql2或其他数据库客户端库
// 模拟返回一些表名
return [
'agent',
'agent_audit',
'agent_real_name',
'agent_active_stat',
'agent_closure',
'agent_commission',
'agent_commission_deduction',
'agent_link',
'agent_membership_config',
'agent_membership_recharge_order',
'agent_membership_user_config',
'agent_order',
'agent_platform_deduction',
'agent_product_config',
'agent_rewards',
'agent_wallet',
'agent_withdrawal',
'feature',
'global_notifications',
'order',
'product',
'product_feature',
'query',
'user',
'user_auth',
'example',
'authorization',
'authorization_face'
];
} catch (error) {
console.error('Error fetching tables from database:', error.message);
return [];
}
}
/**
* 显示配置信息
*/
function showConfig() {
console.log('=========================================');
console.log('Current Configuration:');
console.log('\nModel Configuration:');
console.log(' Database URL:', modelConfig.dbUrl);
console.log(' Output Directory:', modelConfig.outputDir);
console.log(' Template Directory:', modelConfig.templateDir);
console.log(' Target Directory:', modelConfig.targetDir);
console.log(' Tables:');
modelConfig.tables.forEach(table => console.log(` - ${table}`));
if (modelConfig.disabledTables && modelConfig.disabledTables.length > 0) {
console.log(' Disabled Tables:');
modelConfig.disabledTables.forEach(table => console.log(` - ${table}`));
}
console.log('\nAPI Configuration:');
console.log(' API File:', apiConfig.apiFile);
console.log(' Output Directory:', apiConfig.outputDir);
console.log(' Template Directory:', apiConfig.templateDir);
console.log(' Use Style:', apiConfig.useStyle ? 'Yes' : 'No');
console.log('=========================================');
}
/**
* 保存配置到文件
* @param {object} config 配置对象
*/
function saveConfig(config) {
try {
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 4), 'utf8');
console.log('Configuration saved to config.json');
} catch (error) {
console.error('Error saving configuration:', error.message);
}
}
/**
* 显示帮助信息
*/
function showHelp() {
console.log('Usage: node codegen.js <command> [options]');
console.log('Commands:');
console.log(' model Generate database models');
console.log(' api Generate API code');
console.log(' config Show current configuration');
console.log(' help Show this help message');
console.log('');
console.log('Model Options:');
console.log(' --table <name> Generate model for specific table');
console.log(' --tables <names> Generate models for specific tables (comma-separated)');
console.log(' --exclude <names> Exclude specific tables (comma-separated)');
console.log(' --all Generate models for all tables in database');
console.log(' --db-url <url> Database connection URL');
console.log(' --template <dir> Template directory');
console.log(' --save Save specified tables to config.json');
console.log('');
console.log('API Options:');
console.log(' --api <file> API definition file path');
console.log(' --dir <dir> Output directory');
console.log(' --template <dir> Template directory');
console.log(' --style Use goZero style');
console.log('');
console.log('Configuration:');
console.log(' Settings are loaded from config.json');
console.log(' Command line options override config file settings');
console.log('');
console.log('Examples:');
console.log(' node codegen.js model --table agent');
console.log(' node codegen.js model --tables agent,user,order');
console.log(' node codegen.js model --exclude user,order');
console.log(' node codegen.js model --all --exclude system_table');
console.log(' node codegen.js model --tables agent,user --save');
process.exit(0);
}
/**
* 主函数
*/
async function main() {
// 解析命令行参数
const args = process.argv.slice(2);
if (args.length === 0 || args[0] === 'help') {
showHelp();
}
const command = args[0];
// 显示配置信息
if (command === 'config') {
showConfig();
return;
}
// 处理模型生成命令
if (command === 'model') {
const config = { ...modelConfig };
let singleTable = null;
let tablesToGenerate = [...config.tables];
let excludeTables = [];
let shouldSaveConfig = false;
let generateAllTables = false;
// 处理其他参数
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg === '--table' && i + 1 < args.length) {
singleTable = args[++i];
tablesToGenerate = [singleTable];
} else if (arg === '--tables' && i + 1 < args.length) {
const tableList = args[++i].split(',').map(t => t.trim()).filter(t => t);
tablesToGenerate = tableList;
} else if (arg === '--exclude' && i + 1 < args.length) {
excludeTables = args[++i].split(',').map(t => t.trim()).filter(t => t);
} else if (arg === '--all') {
generateAllTables = true;
} else if (arg === '--db-url' && i + 1 < args.length) {
config.dbUrl = args[++i];
} else if (arg === '--template' && i + 1 < args.length) {
config.templateDir = args[++i];
} else if (arg === '--save') {
shouldSaveConfig = true;
}
}
// 如果指定了--all参数获取所有表名
if (generateAllTables) {
tablesToGenerate = await getAllTablesFromDB(config.dbUrl);
}
// 排除指定的表
if (excludeTables.length > 0) {
tablesToGenerate = tablesToGenerate.filter(table => !excludeTables.includes(table));
}
// 保存配置
if (shouldSaveConfig) {
const newConfig = { ...config };
newConfig.tables = tablesToGenerate;
// 更新配置文件
if (fs.existsSync(CONFIG_FILE)) {
const existingConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
existingConfig.model = newConfig;
saveConfig(existingConfig);
} else {
saveConfig({ model: newConfig, api: apiConfig });
}
}
// 生成单个表的模型或所有表的模型
if (singleTable) {
generateModelForTable(singleTable, config);
} else {
generateModels(tablesToGenerate, config);
}
}
// 处理API生成命令
else if (command === 'api') {
const config = { ...apiConfig };
// 处理其他参数
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg === '--api' && i + 1 < args.length) {
config.apiFile = args[++i];
} else if (arg === '--dir' && i + 1 < args.length) {
config.outputDir = args[++i];
} else if (arg === '--template' && i + 1 < args.length) {
config.templateDir = args[++i];
} else if (arg === '--style') {
config.useStyle = true;
}
}
// 生成API代码
generateApi(config);
}
else {
console.error(`Unknown command: ${command}`);
showHelp();
}
}
// 执行主函数
if (require.main === module) {
main().catch(err => {
console.error('Error in main execution:', err);
process.exit(1);
});
}
// 导出函数,以便其他脚本可以调用
module.exports = {
generateModels,
generateModelForTable,
generateApi,
showConfig,
saveConfig,
getAllTablesFromDB
};