Files

107 lines
3.0 KiB
JavaScript

#!/usr/bin/env node
/**
* Soul 创业派对 - MySQL 直接执行脚本
* 当 MCP MySQL 因端口非 3306 无法连接时,用此脚本执行 SQL。
*
* 用法:
* node run.js "SELECT 1"
* node run.js -f migration.sql
* node run.js --dsn "user:pass@tcp(host:port)/db" "SELECT 1"
*
* 凭证来源(优先级):
* 1. 环境变量 DB_DSN
* 2. 参数 --dsn
* 3. 读取 soul-api/.env 中的 DB_DSN
*/
const fs = require('fs');
const path = require('path');
function parseDsn(dsn) {
// user:password@tcp(host:port)/database?params
const match = dsn.match(/^([^:]+):([^@]+)@tcp\(([^:]+):(\d+)\)\/([^?]+)/);
if (!match) throw new Error('DB_DSN 格式应为: user:password@tcp(host:port)/database');
return {
user: match[1],
password: match[2],
host: match[3],
port: parseInt(match[4], 10),
database: match[5],
};
}
function loadDsn() {
if (process.env.DB_DSN) return process.env.DB_DSN;
const envPath = path.resolve(__dirname, '../../../soul-api/.env');
if (fs.existsSync(envPath)) {
const content = fs.readFileSync(envPath, 'utf8');
const line = content.split('\n').find((l) => l.trim().startsWith('DB_DSN='));
if (line) {
const val = line.split('=')[1]?.trim();
if (val) return val.replace(/^["']|["']$/g, '');
}
}
return null;
}
async function main() {
let dsn = process.argv.find((a) => a.startsWith('--dsn='))?.split('=')[1];
if (!dsn) dsn = loadDsn();
if (!dsn) {
console.error('未找到 DB_DSN。请设置环境变量 DB_DSN 或确保 soul-api/.env 中有 DB_DSN');
process.exit(1);
}
let sql = '';
const fileArg = process.argv.indexOf('-f');
if (fileArg !== -1 && process.argv[fileArg + 1]) {
const filePath = path.resolve(process.cwd(), process.argv[fileArg + 1]);
if (!fs.existsSync(filePath)) {
console.error('文件不存在:', filePath);
process.exit(1);
}
sql = fs.readFileSync(filePath, 'utf8');
} else {
const sqlArg = process.argv.find((a, i) => i > 0 && !a.startsWith('-') && a !== '-f');
if (!sqlArg) {
console.error('用法: node run.js "SQL" 或 node run.js -f migration.sql');
process.exit(1);
}
sql = sqlArg;
}
if (!sql.trim()) {
console.error('SQL 为空');
process.exit(1);
}
const config = parseDsn(dsn);
const mysql = require('mysql2/promise');
const conn = await mysql.createConnection({
host: config.host,
port: config.port,
user: config.user,
password: config.password,
database: config.database,
multipleStatements: true,
});
try {
const [result] = await conn.query(sql);
if (Array.isArray(result)) {
console.log(JSON.stringify(result, null, 2));
} else if (result && typeof result === 'object' && 'affectedRows' in result) {
console.log(JSON.stringify({ affectedRows: result.affectedRows, insertId: result.insertId }, null, 2));
} else {
console.log(result);
}
} catch (err) {
console.error('执行失败:', err.message);
process.exit(1);
} finally {
await conn.end();
}
}
main();