From c5f14c2a97da15fba4d50e1c0dbc8f15196e4888 Mon Sep 17 00:00:00 2001 From: abearxiong Date: Tue, 28 Oct 2025 01:38:59 +0800 Subject: [PATCH] uptate --- .env.example | 0 .gitignore | 3 + docker/clickhouse/config.xml | 25 +++++++ docker/clickhouse/users.xml | 34 +++++++++ docker/compose.yml | 26 +++++++ package.json | 10 +-- pnpm-lock.yaml | 56 +++++++-------- src/app.ts | 131 +++++++++++++++++++++++++++++++++-- src/demo.ts | 0 src/demo/connect.ts | 18 +++++ 10 files changed, 264 insertions(+), 39 deletions(-) create mode 100644 .env.example create mode 100644 docker/clickhouse/config.xml create mode 100644 docker/clickhouse/users.xml create mode 100644 docker/compose.yml create mode 100644 src/demo.ts create mode 100644 src/demo/connect.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore index ecff565..1c32990 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ .env node_modules dist +./docker/data + +!.env*.example \ No newline at end of file diff --git a/docker/clickhouse/config.xml b/docker/clickhouse/config.xml new file mode 100644 index 0000000..b89d9a9 --- /dev/null +++ b/docker/clickhouse/config.xml @@ -0,0 +1,25 @@ + + + + information + true + + + 8123 + 9000 + + :: + + 4096 + 3 + 100 + + /var/lib/clickhouse/ + /var/lib/clickhouse/tmp/ + /var/lib/clickhouse/user_files/ + + users.xml + + default + default + \ No newline at end of file diff --git a/docker/clickhouse/users.xml b/docker/clickhouse/users.xml new file mode 100644 index 0000000..7a54d91 --- /dev/null +++ b/docker/clickhouse/users.xml @@ -0,0 +1,34 @@ + + + + + 10000000000 + 0 + random + + + + + + password + + ::/0 + + default + default + + + + + + + 3600 + 0 + 0 + 0 + 0 + 0 + + + + \ No newline at end of file diff --git a/docker/compose.yml b/docker/compose.yml new file mode 100644 index 0000000..8697d35 --- /dev/null +++ b/docker/compose.yml @@ -0,0 +1,26 @@ +services: + clickhouse: + image: clickhouse/clickhouse-server:latest + container_name: clickhouse-server + ports: + - "8123:8123" # HTTP接口 + - "9000:9000" # TCP接口 + volumes: + - ./data/clickhouse_data:/var/lib/clickhouse + - ./data/clickhouse_logs:/var/log/clickhouse-server + - ./clickhouse/config.xml:/etc/clickhouse-server/config.xml + - ./clickhouse/users.xml:/etc/clickhouse-server/users.xml + environment: + - CLICKHOUSE_DB=default + - CLICKHOUSE_USER=default + - CLICKHOUSE_PASSWORD=password + ulimits: + nofile: + soft: 262144 + hard: 262144 + networks: + - clickhouse-network + +networks: + clickhouse-network: + driver: bridge \ No newline at end of file diff --git a/package.json b/package.json index 4dba196..14142ab 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,14 @@ "keywords": [], "author": "abearxiong (https://www.xiongxiao.me)", "license": "MIT", - "packageManager": "pnpm@10.6.2", + "packageManager": "pnpm@10.19.0", "type": "module", "dependencies": { - "@clickhouse/client": "^1.11.0", - "dotenv": "^16.4.7" + "@clickhouse/client": "^1.12.1", + "dotenv": "^17.2.3" }, "devDependencies": { - "@types/node": "^22.13.11", - "typescript": "^5.8.2" + "@types/node": "^24.9.1", + "typescript": "^5.9.3" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3353289..1026de0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,57 +9,57 @@ importers: .: dependencies: '@clickhouse/client': - specifier: ^1.11.0 - version: 1.11.0 + specifier: ^1.12.1 + version: 1.12.1 dotenv: - specifier: ^16.4.7 - version: 16.4.7 + specifier: ^17.2.3 + version: 17.2.3 devDependencies: '@types/node': - specifier: ^22.13.11 - version: 22.13.11 + specifier: ^24.9.1 + version: 24.9.1 typescript: - specifier: ^5.8.2 - version: 5.8.2 + specifier: ^5.9.3 + version: 5.9.3 packages: - '@clickhouse/client-common@1.11.0': - resolution: {integrity: sha512-O0xbwv7HiMXayokrf5dYIBpjBnYekcOXWz60T1cXLmiZ8vgrfNRCiOpybJkrMXKnw9D0mWCgPUu/rgMY7U1f4g==} + '@clickhouse/client-common@1.12.1': + resolution: {integrity: sha512-ccw1N6hB4+MyaAHIaWBwGZ6O2GgMlO99FlMj0B0UEGfjxM9v5dYVYql6FpP19rMwrVAroYs/IgX2vyZEBvzQLg==} - '@clickhouse/client@1.11.0': - resolution: {integrity: sha512-VYTQfR0y/BtrIDEjuSce1zv85OvHak5sUhZVyNYJzbAgWHy3jFf8Os7FdUSeqyKav0xGGy+2X+dRanTFjI5Oug==} + '@clickhouse/client@1.12.1': + resolution: {integrity: sha512-7ORY85rphRazqHzImNXMrh4vsaPrpetFoTWpZYueCO2bbO6PXYDXp/GQ4DgxnGIqbWB/Di1Ai+Xuwq2o7DJ36A==} engines: {node: '>=16'} - '@types/node@22.13.11': - resolution: {integrity: sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g==} + '@types/node@24.9.1': + resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==} - dotenv@16.4.7: - resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + dotenv@17.2.3: + resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} engines: {node: '>=12'} - typescript@5.8.2: - resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} snapshots: - '@clickhouse/client-common@1.11.0': {} + '@clickhouse/client-common@1.12.1': {} - '@clickhouse/client@1.11.0': + '@clickhouse/client@1.12.1': dependencies: - '@clickhouse/client-common': 1.11.0 + '@clickhouse/client-common': 1.12.1 - '@types/node@22.13.11': + '@types/node@24.9.1': dependencies: - undici-types: 6.20.0 + undici-types: 7.16.0 - dotenv@16.4.7: {} + dotenv@17.2.3: {} - typescript@5.8.2: {} + typescript@5.9.3: {} - undici-types@6.20.0: {} + undici-types@7.16.0: {} diff --git a/src/app.ts b/src/app.ts index 8c9e37b..a2324fb 100644 --- a/src/app.ts +++ b/src/app.ts @@ -3,16 +3,135 @@ import { createClient } from '@clickhouse/client'; dotenv.config(); +// 定义数据类型接口 +interface DataRecord { + id: number; + title: string; + description: string; + created_at: Date; +} + const clickhouse = createClient({ url: process.env.CLICKHOUSE_URL, username: process.env.CLICKHOUSE_USERNAME, password: process.env.CLICKHOUSE_PASSWORD, }); -clickhouse - .query({ - query: 'SELECT 1', - }) - .then((res) => { - console.log(res); +// 生成随机数据的函数 +function generateRandomData(count: number): DataRecord[] { + const titles = [ + '人工智能的未来', '云计算发展趋势', '区块链技术应用', '大数据分析实践', + '机器学习入门', '网络安全防护', '物联网架构设计', '5G技术展望', + '量子计算突破', '自动驾驶技术', '虚拟现实体验', '智能家居系统', + '数字化转型', '边缘计算应用', '分布式存储方案', '微服务架构实践', + '容器化部署', 'DevOps最佳实践', 'API设计原则', '数据库优化技巧' + ]; + + const descriptions = [ + '深入探讨技术发展趋势和未来前景,为行业发展提供重要参考。', + '详细介绍技术原理和实现方法,帮助读者快速掌握核心概念。', + '分析实际应用场景和案例研究,展示技术的实际价值。', + '总结最佳实践和经验教训,避免常见陷阱和错误。', + '展望未来发展方向和机遇挑战,为决策提供依据。' + ]; + + const data: DataRecord[] = []; + const now = new Date(); + + for (let i = 1; i <= count; i++) { + data.push({ + id: i, + title: titles[Math.floor(Math.random() * titles.length)], + description: descriptions[Math.floor(Math.random() * descriptions.length)], + created_at: new Date(now.getTime() - Math.floor(Math.random() * 30 * 24 * 60 * 60 * 1000)) + }); + } + + return data; +} + +// 创建表 +async function createTable() { + const createTableQuery = ` + CREATE TABLE IF NOT EXISTS data_records ( + id UInt32, + title String, + description String, + created_at DateTime + ) ENGINE = MergeTree() + ORDER BY id + `; + + await clickhouse.query({ + query: createTableQuery, }); + + console.log('Table created or already exists'); +} + +// 插入数据 - 修复数据格式问题 +async function insertData(records: DataRecord[]) { + // 将数据转换为JSONEachRow格式需要的对象数组 + const values = records.map(record => ({ + id: record.id, + title: record.title, + description: record.description, + created_at: record.created_at.toISOString().slice(0, 19).replace('T', ' ') + })); + + await clickhouse.insert({ + table: 'data_records', + values: values, + format: 'JSONEachRow' + }); + + console.log(`Inserted ${records.length} records`); +} + +// 主函数 +async function main() { + try { + // 测试连接 + const pingResult = await clickhouse.query({ + query: 'SELECT 1 as ping', + }); + console.log('Connected to ClickHouse'); + + // 创建表 + await createTable(); + + // 生成20条随机数据 + const randomData = generateRandomData(20); + console.log('Generated 20 random records'); + + // 插入数据 + await insertData(randomData); + + // 验证数据 + const result = await clickhouse.query({ + query: 'SELECT COUNT(*) as total FROM data_records', + }); + + const countData = await result.json() as { data: { total: string }[] }; + console.log('Total records in table:', countData.data[0].total); + + // 显示前5条记录 + const sample = await clickhouse.query({ + query: 'SELECT id, title, description FROM data_records ORDER by id LIMIT 5', + }); + + const sampleData = await sample.json() as { data: Array<{ id: number; title: string; description: string }> }; + console.log('Sample records:'); + sampleData.data.forEach((record) => { + console.log(`${record.id}: ${record.title} - ${record.description}`); + }); + + } catch (error) { + console.error('Error:', error); + } finally { + await clickhouse.close(); + } +} + +// 运行主函数 +main(); diff --git a/src/demo.ts b/src/demo.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/demo/connect.ts b/src/demo/connect.ts new file mode 100644 index 0000000..af5abd6 --- /dev/null +++ b/src/demo/connect.ts @@ -0,0 +1,18 @@ +import dotenv from 'dotenv'; +import { createClient } from '@clickhouse/client'; + +dotenv.config(); + +const clickhouse = createClient({ + url: process.env.CLICKHOUSE_URL, + username: process.env.CLICKHOUSE_USERNAME, + password: process.env.CLICKHOUSE_PASSWORD, +}); + +clickhouse + .query({ + query: 'SELECT 1', + }) + .then((res) => { + console.log('SELECT 1'); + });