212 lines
5.6 KiB
JavaScript
212 lines
5.6 KiB
JavaScript
// 检查ClickHouse数据库结构的脚本
|
||
const { createClient } = require('@clickhouse/client');
|
||
const dotenv = require('dotenv');
|
||
const path = require('path');
|
||
const fs = require('fs');
|
||
|
||
// 加载环境变量
|
||
dotenv.config({ path: path.resolve(__dirname, '../../../.env.local') });
|
||
|
||
// 定义输出目录
|
||
const DB_REPORTS_DIR = path.resolve(__dirname, '../db-reports');
|
||
|
||
// 获取ClickHouse配置
|
||
const clickhouseHost = process.env.CLICKHOUSE_HOST || 'localhost';
|
||
const clickhousePort = process.env.CLICKHOUSE_PORT || '8123';
|
||
const clickhouseUser = process.env.CLICKHOUSE_USER || 'default';
|
||
const clickhousePassword = process.env.CLICKHOUSE_PASSWORD || '';
|
||
const clickhouseDatabase = process.env.CLICKHOUSE_DATABASE || 'default';
|
||
|
||
console.log('ClickHouse配置:');
|
||
console.log(` - 主机: ${clickhouseHost}`);
|
||
console.log(` - 端口: ${clickhousePort}`);
|
||
console.log(` - 用户: ${clickhouseUser}`);
|
||
console.log(` - 数据库: ${clickhouseDatabase}`);
|
||
|
||
// 创建ClickHouse客户端 - 使用0.2.10版本的API
|
||
const client = createClient({
|
||
url: `http://${clickhouseHost}:${clickhousePort}`,
|
||
username: clickhouseUser,
|
||
password: clickhousePassword,
|
||
database: clickhouseDatabase
|
||
});
|
||
|
||
// 获取所有表
|
||
async function getAllTables() {
|
||
console.log('\n获取所有表...');
|
||
|
||
try {
|
||
const query = `
|
||
SELECT name
|
||
FROM system.tables
|
||
WHERE database = '${clickhouseDatabase}'
|
||
`;
|
||
|
||
const resultSet = await client.query({
|
||
query,
|
||
format: 'JSONEachRow'
|
||
});
|
||
|
||
const tables = await resultSet.json();
|
||
|
||
if (!tables || tables.length === 0) {
|
||
console.log(`数据库 ${clickhouseDatabase} 中没有找到任何表`);
|
||
return null;
|
||
}
|
||
|
||
console.log(`数据库 ${clickhouseDatabase} 中找到以下表:`);
|
||
tables.forEach(table => {
|
||
console.log(` - ${table.name}`);
|
||
});
|
||
|
||
return tables.map(table => table.name);
|
||
} catch (error) {
|
||
console.error('获取所有表时出错:', error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 获取表结构
|
||
async function getTableSchema(tableName) {
|
||
console.log(`\n获取表 ${tableName} 的结构...`);
|
||
|
||
try {
|
||
const query = `
|
||
DESCRIBE TABLE ${clickhouseDatabase}.${tableName}
|
||
`;
|
||
|
||
const resultSet = await client.query({
|
||
query,
|
||
format: 'JSONEachRow'
|
||
});
|
||
|
||
const columns = await resultSet.json();
|
||
|
||
if (!columns || columns.length === 0) {
|
||
console.log(`表 ${tableName} 不存在或没有列`);
|
||
return null;
|
||
}
|
||
|
||
console.log(`表 ${tableName} 的列:`);
|
||
columns.forEach(column => {
|
||
console.log(` - ${column.name} (${column.type}, ${column.default_type === '' ? '无默认值' : `默认值: ${column.default_expression}`})`);
|
||
});
|
||
|
||
return columns;
|
||
} catch (error) {
|
||
console.error(`获取表 ${tableName} 结构时出错:`, error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 获取表数据示例
|
||
async function getTableDataSample(tableName, limit = 5) {
|
||
console.log(`\n获取表 ${tableName} 的数据示例 (最多 ${limit} 行)...`);
|
||
|
||
try {
|
||
const query = `
|
||
SELECT *
|
||
FROM ${clickhouseDatabase}.${tableName}
|
||
LIMIT ${limit}
|
||
`;
|
||
|
||
const resultSet = await client.query({
|
||
query,
|
||
format: 'JSONEachRow'
|
||
});
|
||
|
||
const rows = await resultSet.json();
|
||
|
||
if (!rows || rows.length === 0) {
|
||
console.log(`表 ${tableName} 中没有数据`);
|
||
return null;
|
||
}
|
||
|
||
console.log(`表 ${tableName} 的数据示例:`);
|
||
rows.forEach((row, index) => {
|
||
console.log(` 行 ${index + 1}:`);
|
||
Object.entries(row).forEach(([key, value]) => {
|
||
console.log(` ${key}: ${value}`);
|
||
});
|
||
});
|
||
|
||
return rows;
|
||
} catch (error) {
|
||
console.error(`获取表 ${tableName} 数据示例时出错:`, error);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// 主函数
|
||
async function main() {
|
||
let outputBuffer = '';
|
||
const originalConsoleLog = console.log;
|
||
|
||
// 重定向console.log到buffer和控制台
|
||
console.log = function() {
|
||
// 调用原始的console.log
|
||
originalConsoleLog.apply(console, arguments);
|
||
|
||
// 写入到buffer
|
||
outputBuffer += Array.from(arguments).join(' ') + '\n';
|
||
};
|
||
|
||
try {
|
||
// 获取所有表
|
||
const tables = await getAllTables();
|
||
|
||
if (!tables) {
|
||
console.error('无法获取表列表');
|
||
process.exit(1);
|
||
}
|
||
|
||
console.log('\n所有ClickHouse表:');
|
||
console.log(tables.join(', '));
|
||
|
||
// 获取每个表的结构,但不获取数据示例
|
||
for (const tableName of tables) {
|
||
await getTableSchema(tableName);
|
||
// 移除数据示例检查
|
||
// await getTableDataSample(tableName);
|
||
}
|
||
|
||
console.log('\nClickHouse数据库结构检查完成');
|
||
|
||
// 保存输出到指定目录
|
||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||
|
||
// 确保目录存在
|
||
if (!fs.existsSync(DB_REPORTS_DIR)) {
|
||
fs.mkdirSync(DB_REPORTS_DIR, { recursive: true });
|
||
}
|
||
|
||
const outputPath = path.join(DB_REPORTS_DIR, `clickhouse-schema-${timestamp}.log`);
|
||
fs.writeFileSync(outputPath, outputBuffer);
|
||
originalConsoleLog(`结果已保存到: ${outputPath}`);
|
||
|
||
} catch (error) {
|
||
console.error('检查ClickHouse数据库结构时出错:', error);
|
||
} finally {
|
||
// 恢复原始的console.log
|
||
console.log = originalConsoleLog;
|
||
|
||
// 关闭客户端连接
|
||
await client.close();
|
||
}
|
||
}
|
||
|
||
// 导出函数
|
||
module.exports = {
|
||
getAllTables,
|
||
getTableSchema,
|
||
getTableDataSample,
|
||
main
|
||
};
|
||
|
||
// 如果直接运行此脚本,则执行main函数
|
||
if (require.main === module) {
|
||
main().catch(error => {
|
||
console.error('运行脚本时出错:', error);
|
||
process.exit(1);
|
||
});
|
||
}
|