Commit bec3f283 authored by xiegelin's avatar xiegelin

feat: 支持选择所有表或指定表模式,复用数据库连接

mysql.js 和 postgreSQL.js 新增交互式模式选择(1: 所有表, 2: 指定表),
选择所有表时自动查询 information_schema 获取全部 BASE TABLE 并逐一生成 XML。
同时将数据库连接从循环内提取到循环外复用,避免重复创建连接。
Co-Authored-By: default avatarClaude Opus 4.6 (1M context) <noreply@anthropic.com>
parent 1c12d7bf
......@@ -16,25 +16,28 @@ npm run pgsql # Run PostgreSQL version (interactive CLI)
npm run md2drawio # Convert Markdown table file to Draw.io XML
```
No test suite or linter is configured.
Requires Node.js v18+. No test suite or linter is configured.
## Architecture
Three entry points:
Three independent entry points, no shared modules:
- `mysql.js` — MySQL via `mysql2/promise`, queries `information_schema.COLUMNS`. Generates both table-structure XML and sample-data XML.
- `postgreSQL.js` — PostgreSQL via `pg`, joins `information_schema.columns` with `pg_catalog.pg_description` for comments. Generates table-structure XML only.
- `mdToDrawio.js` — Parses a Markdown table file (pipe-delimited) and generates a Draw.io table XML.
- `mysql.js` — MySQL via `mysql2/promise`, queries `information_schema.COLUMNS` and `information_schema.TABLES`. Generates both table-structure XML (with table comment in label) and sample-data XML.
- `postgreSQL.js` — PostgreSQL via `pg`, joins `information_schema.columns` with `pg_catalog.pg_description` for column comments. Generates table-structure XML only (no table comment in label, no sample-data XML).
- `mdToDrawio.js` — Parses a Markdown table file (pipe-delimited) and generates a Draw.io table XML into `sampleDataXml/`.
### Core Flow (mysql.js / postgreSQL.js)
1. **Interactive Input**: readline prompts for comma-separated table names (supports Chinese comma `,`)
2. **Name Processing**: rejects Chinese characters, converts camelCase → snake_case
3. **Database Query**: fetches column names + comments from information_schema
4. **XML Generation**: `generateXMLWithTableColumns` builds mxGraph XML with swimlane container and per-column cells. Audit fields (created_at, updated_at, deleted_at, etc.) are styled gray. MySQL version also calls `generateSampleDataXML` to produce a horizontal table layout with header row and empty data row.
4. **XML Generation**: `generateXMLWithTableColumns` builds mxGraph XML with swimlane container and per-column cells. Audit fields (created_at, updated_at, deleted_at, etc.) are styled gray (#B3B3B3). MySQL version also calls `generateSampleDataXML` for a horizontal table layout.
### Key Cross-File Difference
MySQL result rows use uppercase keys (`row.COLUMN_NAME`, `row.COLUMN_COMMENT`) while PostgreSQL uses lowercase (`row.column_name`, `row.column_comment`). This matters when adding shared logic or modifying XML generation.
### Output Directories
- `tableStructureXml/` — swimlane-style table structure diagrams (mysql.js writes here; postgreSQL.js also writes here)
- `sampleDataXml/` — horizontal table-layout diagrams for sample data (mysql.js `generateSampleDataXML` and mdToDrawio.js write here)
- `tableStructureXml/` — swimlane-style table structure diagrams
- `sampleDataXml/` — horizontal table-layout diagrams for sample data
### Database Configuration
Credentials are hardcoded at the top of each database file. Modify directly in source to point at different databases.
......@@ -42,9 +45,9 @@ Credentials are hardcoded at the top of each database file. Modify directly in s
### Known Constraints
- `&` in column comments breaks XML output (no escaping)
- Table names must not contain Chinese characters
- Fixed geometry: x=340, y=140, width=260 for structure XML
- Fixed geometry: x=340, y=140, width=260 for structure XML; colWidth=120 for sample data XML
- PostgreSQL version hardcodes schema to `public`
- PostgreSQL version does not generate sample-data XML
- PostgreSQL version does not generate sample-data XML or include table comments in the label
## Language
README and console messages are in Chinese. Code uses English variable/function names.
......@@ -29,55 +29,69 @@ async function main() {
// const password = 'fxkc@2024';
// const database = 'data_governance_mining';
let tableNames = await askQuestion(
const mode = await askQuestion(
'请选择模式 — 1: 所有表, 2: 指定表 (默认2): '
);
// Create connection
const connection = await mysql.createConnection({
host,
port: parseInt(port),
user,
password,
database,
});
console.log('\nConnecting to database...');
console.log('Connected to database successfully!\n');
let tableNames;
if (mode.trim() === '1') {
// Fetch all table names from the database
const [allTables] = await connection.execute(
`SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = 'BASE TABLE' ORDER BY TABLE_NAME`,
[database]
);
tableNames = allTables.map((r) => r.TABLE_NAME);
console.log(`共找到 ${tableNames.length} 张表\n`);
} else {
const input = await askQuestion(
'Enter table names (separated by commas): '
);
if (!tableNames) {
if (!input) {
console.log('表名不得为空!');
return;
}
// Split table names by both Chinese and English commas, and trim whitespace
tableNames = tableNames
tableNames = input
.split(/[,,]/)
.map((name) => name.trim())
.filter((name) => name);
// Process each table name
for (const tableName of tableNames) {
.filter((name) => name)
.map((name) => {
// Check if table name contains Chinese characters
if (/[\u4e00-\u9fa5]/.test(tableName)) {
console.error(`Table name "${tableName}" 不能有中文.`);
continue;
if (/[\u4e00-\u9fa5]/.test(name)) {
console.error(`Table name "${name}" 不能有中文,已跳过.`);
return null;
}
// Convert camelCase to snake_case
let processedTableName = tableName
.replace(/([A-Z])/g, '_$1')
.toLowerCase();
// Remove leading underscore if present
if (processedTableName[0] === '_') {
processedTableName = processedTableName.slice(1);
let processed = name.replace(/([A-Z])/g, '_$1').toLowerCase();
if (processed[0] === '_') {
processed = processed.slice(1);
}
return processed;
})
.filter(Boolean);
}
console.log('Processing table:', processedTableName);
console.log('\nConnecting to database...');
// Create connection
const connection = await mysql.createConnection({
host,
port: parseInt(port),
user,
password,
database,
});
console.log('Connected to database successfully!\n');
// Execute query
const sql = `SELECT COLUMN_NAME, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? order by ordinal_position`;
console.log('Executing query...\n');
// Process each table
for (const processedTableName of tableNames) {
console.log('Processing table:', processedTableName);
const [rows] = await connection.execute(sql, [
database,
processedTableName,
......@@ -101,11 +115,11 @@ async function main() {
`===== XML file generated successfully for ${processedTableName}! =====`
);
}
}
// Close connection
await connection.end();
console.log('\nConnection closed.');
}
} catch (error) {
console.error('Error:', error.message);
} finally {
......
......@@ -21,7 +21,7 @@ async function main() {
const port = '5432';
const user = 'postgres';
const password = '123456';
const database = 'ai_data_governance';
const database = 'diting';
// Alternative configuration (commented out)
// const host = '10.10.10.132';
......@@ -30,55 +30,64 @@ async function main() {
// const password = 'your_password';
// const database = 'your_database';
let tableNames = await askQuestion(
const mode = await askQuestion(
'请选择模式 — 1: 所有表, 2: 指定表 (默认2): '
);
const client = new Client({
host,
port: parseInt(port),
user,
password,
database,
});
console.log('\nConnecting to database...');
await client.connect();
console.log('Connected to database successfully!\n');
let tableNames;
if (mode.trim() === '1') {
// Fetch all table names from public schema
const allTablesResult = await client.query(
`SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
ORDER BY table_name`
);
tableNames = allTablesResult.rows.map((r) => r.table_name);
console.log(`共找到 ${tableNames.length} 张表\n`);
} else {
const input = await askQuestion(
'Enter table names (separated by commas): '
);
if (!tableNames) {
if (!input) {
console.log('表名不得为空!');
return;
}
// Split table names by both Chinese and English commas, and trim whitespace
tableNames = tableNames
tableNames = input
.split(/[,,]/)
.map((name) => name.trim())
.filter((name) => name);
// Process each table name
for (const tableName of tableNames) {
.filter((name) => name)
.map((name) => {
// Check if table name contains Chinese characters
if (/[\u4e00-\u9fa5]/.test(tableName)) {
console.error(`Table name "${tableName}" 不能有中文.`);
continue;
if (/[\u4e00-\u9fa5]/.test(name)) {
console.error(`Table name "${name}" 不能有中文,已跳过.`);
return null;
}
// Convert camelCase to snake_case
let processedTableName = tableName
.replace(/([A-Z])/g, '_$1')
.toLowerCase();
// Remove leading underscore if present
if (processedTableName[0] === '_') {
processedTableName = processedTableName.slice(1);
let processed = name.replace(/([A-Z])/g, '_$1').toLowerCase();
if (processed[0] === '_') {
processed = processed.slice(1);
}
return processed;
})
.filter(Boolean);
}
console.log('Processing table:', processedTableName);
console.log('\nConnecting to database...');
// Create PostgreSQL client
const client = new Client({
host,
port: parseInt(port),
user,
password,
database,
});
await client.connect();
console.log('Connected to database successfully!\n');
// Execute query - PostgreSQL uses different column names in information_schema
// col_description function is used to get column comments in PostgreSQL
// Column query SQL
const sql = `
SELECT
c.column_name,
......@@ -95,7 +104,10 @@ async function main() {
ORDER BY c.ordinal_position
`;
console.log('Executing query...\n');
// Process each table
for (const processedTableName of tableNames) {
console.log('Processing table:', processedTableName);
const result = await client.query(sql, ['public', processedTableName]);
const rows = result.rows;
......@@ -109,11 +121,11 @@ async function main() {
`===== XML file generated successfully for ${processedTableName}! =====`
);
}
}
// Close connection
await client.end();
console.log('\nConnection closed.');
}
} catch (error) {
console.error('Error:', error.message);
} finally {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment