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');
+ });