内容
<p align="center">
<img src="./website-next/public/logo.png" alt="hypequery logo" width="300" />
</p>
<p align="center">
<h3 align="center">ClickHouse 的类型安全分析后端</h3>
</p>
<h4 align="center">定义 ClickHouse 分析一次,然后在内联、HTTP、React 或代理中运行它们。</h4>
<p align="center">
<a href="https://github.com/hypequery/hypequery/blob/main/LICENSE">
<img alt="hypequery license: Apache-2.0" src="https://img.shields.io/badge/hypequery-license%20Apache%202.0-2ea44f?style=for-the-badge" />
</a>
<a href="https://www.npmjs.com/package/@hypequery/cli">
<img alt="npm @hypequery/cli" src="https://img.shields.io/npm/v/%40hypequery%2Fcli?style=for-the-badge&label=%40hypequery%2Fcli" />
</a>
<a href="https://www.npmjs.com/package/@hypequery/clickhouse">
<img alt="npm @hypequery/clickhouse" src="https://img.shields.io/npm/v/%40hypequery%2Fclickhouse?style=for-the-badge&label=%40hypequery%2Fclickhouse" />
</a>
<a href="https://www.npmjs.com/package/@hypequery/datasets">
<img alt="npm @hypequery/datasets" src="https://img.shields.io/npm/v/%40hypequery%2Fdatasets?style=for-the-badge&label=%40hypequery%2Fdatasets" />
</a>
<a href="https://www.npmjs.com/package/@hypequery/serve">
<img alt="npm @hypequery/serve" src="https://img.shields.io/npm/v/%40hypequery%2Fserve?style=for-the-badge&label=%40hypequery%2Fserve" />
</a>
<a href="https://www.npmjs.com/package/@hypequery/react">
<img alt="npm @hypequery/react" src="https://img.shields.io/npm/v/%40hypequery%2Freact?style=for-the-badge&label=%40hypequery%2Freact" />
</a>
</p>
<p align="center">
<a href="https://www.npmjs.com/package/@hypequery/clickhouse">
<img src="./.github/assets/hypequery-clickhouse-downloads.png" alt="@hypequery/clickhouse npm downloads growth" width="920" />
</a>
</p>
<p align="center">
<a href="https://hypequery.com/docs">文档</a> •
<a href="https://hypequery.featurebase.app/roadmap">路线图</a> •
<a href="https://github.com/hypequery/hypequery-examples">示例</a>
</p>
## 问题
使用官方客户端从 TypeScript 查询 ClickHouse 意味着编写原始 SQL 字符串,将结果强制转换为 `any`,并维护手动滚动的类型,这些类型会偏离您的实际架构。
随着分析功能的增长,业务含义也会发生变化。`revenue`、`active users`、租户范围和时间粒度规则被复制到仪表盘、API 处理程序、作业和代理工具中,直到产品对同一个问题有多个答案:
```ts
// 原始 @clickhouse/client - 没有类型,没有安全性,会默默地破坏
const result = await client.query({
query: `SELECT region, sum(total) as revenue
FROM orders
WHERE created_at >= '2026-01-01'
GROUP BY region
ORDER BY revenue DESC`,
format: 'JSONEachRow',
});
const rows = await result.json(); // 类型为 any[]
// ^^^^ 架构漂移、拼写错误和运行时错误都由你负责
```
## 解决方案
hypequery 为 TypeScript 团队提供了两个协同工作的层:
- `@hypequery/clickhouse` 从实时 ClickHouse 架构中生成 TypeScript 类型,并为您提供一个流畅的查询构建器,其中每个表名、列、筛选器和结果都是完全类型的。
- `@hypequery/datasets` 添加了一个代码优先的语义层,以便维度、度量、指标、租户规则和时间语义被定义一次,并在任何地方重用。
```ts
import { createQueryBuilder } from '@hypequery/clickhouse';
import type { IntrospectedSchema } from './analytics/schema.js';
const db = createQueryBuilder<IntrospectedSchema>({ /* connection */ });
const revenueByRegion = await db
.table('orders') // ✅ 自动完成您的实际表
.select(['region']) // ✅ 仅此表的有效列
.where('created_at', 'gte', '2026-01-01') // ✅ 类型检查的操作符 + 值
.sum('total', 'revenue') // ✅ 类型化的聚合
.groupBy('region')
.orderBy('revenue', 'DESC')
.execute();
// revenueByRegion 是完全类型的 - 没有强制转换,没有惊喜
```
当需要共享计算时,将其提升为数据集:
```ts
import { dataset, dimension, measure } from '@hypequery/datasets';
export const Orders = dataset('orders', {
source: 'orders',
tenantKey: 'tenant_id',
timeKey: 'created_at',
dimensions: {
region: dimension.string(),
status: dimension.string(),
createdAt: dimension.timestamp({ column: 'created_at' }),
},
measures: {
revenue: measure.sum('total'),
orderCount: measure.count('id'),
},
});
export const revenue = Orders.metric('revenue', {
measure: 'revenue',
label: 'Revenue',
});
```
## 为什么选择 hypequery
- 在您的真实 ClickHouse 架构之上构建,而不是手动维护查询类型
- 在 TypeScript 中保留共享的分析含义,而不是 YAML、原始 SQL 字符串或单独的 BI 服务器
- 在脚本、API、React 应用程序和代理中重用相同的查询定义
- 将租户隔离和时间语义作为模型的一部分,而不是每个查询的约定
- 使用查询构建器本地启动,然后仅在需要时添加 HTTP 路由
- 保持输入、输出和 SQL 行为明确到可以测试和推理
## 软件包
- `@hypequery/clickhouse`:类型化的 ClickHouse 查询构建器
- `@hypequery/datasets`:维度、度量、指标、租户范围和时间粒度的数据代码优先语义层
- `@hypequery/serve`:查询合约、HTTP 路由、文档和适配器的代码优先运行时
- `@hypequery/react`:用于 hypequery API 的薄 TanStack Query 钩子
- `@hypequery/mcp`:用于向代理公开受控分析工具的 MCP 服务器
- `@hypequery/schema`:ClickHouse 架构定义、迁移和数据集兼容性检查
- `@hypequery/cli`:脚手架、架构生成和本地开发工具
## 快速入门
```bash
npm install -D @hypequery/cli
npx hypequery init
```
这为您提供了主要路径:
1. 从 ClickHouse 生成架构类型
2. 在本地编写类型化的查询
3. 将共享的分析概念提升为数据集和指标
4. 在需要共享合约时,通过 HTTP 公开查询、数据集或指标
对于语义层直接:
```bash
npm install @hypequery/datasets @hypequery/clickhouse
```
## 按需添加合约和 HTTP
```ts
import { initServe } from '@hypequery/serve';
import { z } from 'zod';
import { db } from './analytics/client.js';
const { query, serve } = initServe({
context: () => ({ db }),
basePath: '/api/analytics',
});
const activeUsers = query({
description: '按地区列出活跃用户',
input: z.object({ region: z.string() }),
query: ({ ctx, input }) =>
ctx.db
.table('users')
.where('status', 'eq', 'active')
.where('region', 'eq', input.region)
.execute(),
});
export const api = serve({
queries: { activeUsers },
});
api.route('/activeUsers', api.queries.activeUsers);
```
同一个查询可以:
- 直接使用 `api.execute(...)` 执行
- 作为 HTTP 路由公开
- 从 React 使用 `@hypequery/react`
- 为工具和代理描述
## CLI
```bash
# 搭建分析文件和环境变量
npx hypequery init
# 运行带有文档的本地开发服务器
npx hypequery dev
# 重新生成架构类型
npx hypequery generate
```
## 了解更多
- [快速入门](https://hypequery.com/docs/quick-start)
- [核心概念](https://hypequery.com/docs/core-concepts)
- [数据集](https://hypequery.com/docs/datasets/overview)
- [指标](https://hypequery.com/docs/datasets/metrics)
- [查询构建](https://hypequery.com/docs/query-building/basics)
- [CLI 参考](https://hypequery.com/docs/reference/api/cli)
## 许可证
Apache-2.0。参见 [LICENSE](LICENSE)。