mcpField
C
chkit

chkit

github.com/obsessiondb数据与数据库4262 次安装1 天前更新
代码仓库

关于 chkit

chkit 是面向 ClickHouse 的 TypeScript schema 与迁移工具包,供团队通过命令行管理数据库变更。它涵盖 SQL 生成、实时差异检测和 CI 策略检查。

主要功能

  1. 01用 TypeScript 定义 schema
  2. 02生成并预览迁移 SQL
  3. 03应用并跟踪迁移
  4. 04检测实时 schema 差异
  5. 05执行 CI 策略检查

适用场景

  1. 01管理 ClickHouse schema 变更
  2. 02应用前审查迁移 SQL
  3. 03在 CI 中检查 schema 差异
  4. 04恢复失败的迁移

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/obsessiondb/chkit --skill chkit

安装后在 Claude Code 中输入/chkit确认已加载。

详细介绍

chkit:ClickHouse 架构与迁移工具包

chkit 让你能够使用 TypeScript 定义 ClickHouse 架构、生成迁移 SQL、检测偏差,并通过单个 CLI 运行 CI 检查。

文档:https://chkit.obsessiondb.com

连接与授权

使用用户已提供的选项、目标详情和应用授权;仅询问缺失的信息。除非用户要求使用 Sync 或 Python,否则请专注于 TypeScript 架构管理工作流。

对于直接连接的 ClickHouse 目标,请获取 CLICKHOUSE_URL(HTTP/S 端点和端口)、CLICKHOUSE_USER、CLICKHOUSE_PASSWORD(明确为空也是有效值)和 CLICKHOUSE_DB。切勿将 localhost、默认用户名、空密码或数据库 default 推断为用户已确认的目标。除非用户提出要求,否则不要配置托管实例。

没有凭据时,请安装依赖并离线准备定义。只有在明确选择数据库命名空间后,才能生成迁移 SQL。不要对猜测的端点运行已连接的 pull、query、status、drift、check 或 migrate。如果数据库名称未知,请询问并暂缓生成;不要编造命名空间。如果先前尝试针对占位符生成了 SQL,请在连接前调整定义,并重新生成仅限从未应用过的初始产物。记录已准备的内容以及仍未验证的部分。

将真实凭据保存在进程环境或被忽略的 .env 中,切勿放入架构、迁移或交接文件。Bun 会加载根目录中的 .env;npm/Node 命令需要显式加载,例如在根目录运行 node --env-file=.env ./node_modules/chkit/dist/bin/chkit.js check --strict --json。嵌套配置需要使用加载器,以明确解析根目录中的 .env。

应用前,请验证实际数据库身份并检查生成的 SQL。对于已明确授权的开发数据库操作,不要重复征求批准;对于任务未授权的重大写入操作,请先取得授权。缺少凭据属于必要输入,但不是停止离线工作的理由。

配置

在项目根目录使用 clickhouse.config.ts,或通过 --config 指定自定义路径。架构文件应使用所选的数据库名称;每个受管理对象的 database 都必须指向预期数据库。

import { defineConfig } from '@chkit/core'

function required(name: string): string {
  const value = process.env[name]
  if (value === undefined || (name !== 'CLICKHOUSE_PASSWORD' && !value.trim())) {
    throw new Error(`Missing ${name}; configure the connection first.`)
  }
  return value
}

export default defineConfig(({ command }) => ({
  schema: './src/db/schema/**/*.ts',
  outDir: './chkit',
  migrationsDir: './chkit/migrations',
  metaDir: './chkit/meta', // snapshot.json; applied history is in ClickHouse
  plugins: [],
  // Preserve target metadata when supplied, including during generation.
  clickhouse: !process.env.CLICKHOUSE_URL && (command === 'generate' || command === 'snapshot') ? undefined : {
    url: required('CLICKHOUSE_URL'),
    username: required('CLICKHOUSE_USER'),
    password: required('CLICKHOUSE_PASSWORD'),
    database: required('CLICKHOUSE_DB'),
  },
  check: { failOnPending: true, failOnChecksumMismatch: true, failOnDrift: true },
  safety: { allowDestructive: false },
}))

generate 会离线将定义与快照进行差异比较。在线的 _chkit_migrations 表保存已应用的历史记录;本地没有 journal.json。已连接的迁移预览可能会初始化该日志,但不会执行待处理的迁移语句。

架构 DSL

架构文件是 TypeScript 文件,使用 @chkit/core 中的函数导出定义。

表
import { schema, table } from '@chkit/core'

const events = table({
  database: 'default',
  name: 'events',
  columns: [
    { name: 'id', type: 'UInt64' },
    { name: 'org_id', type: 'String' },
    { name: 'source', type: 'LowCardinality(String)' },
    { name: 'payload', type: 'String', nullable: true },
    { name: 'received_at', type: 'DateTime64(3)', default: { expression: 'now64(3)' } },
    { name: 'status', type: 'String', default: 'pending', comment: 'Processing status' },
  ],
  engine: 'MergeTree()',
  primaryKey: ['id'],
  orderBy: ['org_id', 'received_at', 'id'],
  partitionBy: 'toYYYYMM(received_at)',
  ttl: 'received_at + INTERVAL 90 DAY',
  settings: { index_granularity: 8192 },
  indexes: [
    { name: 'idx_source', expression: 'source', type: 'set', maxRows: 0, granularity: 1 },
  ],
})

export default schema(events)

必填表字段:database、name、columns、engine、primaryKey、orderBy。 可选字段:partitionBy、uniqueKey、ttl、settings、indexes、projections、comment、renamedFrom。

列默认值
  • 字符串是字面值,使用单引号:default: 'pending' → DEFAULT 'pending'
  • 数字和布尔值是字面值:default: 0 → DEFAULT 0
  • SQL 表达式使用 { expression }:default: { expression: 'now64(3)' } → DEFAULT now64(3)。表达式中的注释会在生成的 SQL 中被删除
  • 切勿将函数调用写成普通字符串:default: 'now64(3)' 是字面文本 now64(3),ClickHouse 会拒绝将其用于 DateTime64 列(用于 Nullable 列时则会存储为 NULL)。chkit 高于 0.2.0-beta.8 时,如果非字符串列的 DEFAULT 或 EPHEMERAL 默认值是这种写法,会在 generate 阶段拒绝它(column_default_looks_like_expression);对于 MATERIALIZED 或 ALIAS 列,则会拒绝所有普通字符串(column_expression_requires_fn)
  • default: 'fn:now64(3)' 是旧版等效写法,也是 chkit 0.2.0-beta.8 及更早版本唯一支持的写法:它们会将 { expression } 渲染为 DEFAULT [object Object]。如果生成的迁移中出现这种情况,请使用 fn:
  • defaultKind 用于选择子句(DEFAULT、MATERIALIZED、ALIAS、EPHEMERAL);所有类型的 default 写法都相同:{ name: 'day', type: 'Date', defaultKind: 'MATERIALIZED', default: { expression: 'toDate(ts)' } } → `day` Date MATERIALIZED toDate(ts)。MATERIALIZED 和 ALIAS 必须有 default,且写作 { expression }(常量字符串写作 { expression: "'text'" });EPHEMERAL 可以省略它
视图
import { view } from '@chkit/core'

const activeUsers = view({
  database: 'app',
  name: 'active_users',
  as: 'SELECT id, email FROM app.users WHERE active = 1',
})

在视图 SQL 中使用完全限定的 db.name 引用(app.users,而非 users):ClickHouse 会根据会话的当前数据库解析未限定的名称。chkit 高于 0.2.0-beta.8 时,还会读取这些引用,以便在视图所使用的视图、物化视图和字典创建后创建该视图。

使用高于 0.2.0-beta.8 的 chkit 时,as 可以跨行并包含 SQL 注释,其他 SQL 字段也可以(物化视图的 as、partitionBy、ttl、索引和投影 SQL、字典的 source/layout/lifetime):chkit 会在将查询写成一行之前删除注释。全文(type: 'text')索引表达式是例外:它们只会删除 -- 和非嵌套的 /* */ 注释。检查生成的迁移:如果单行语句(CREATE VIEW,或 CREATE TABLE 的 TTL 或 PARTITION BY)中仍有字符串字面值之外的 --、// 或 # 注释,说明已安装的 chkit 不会清除注释,而该注释会吞掉语句的其余部分。请升级 chkit,或使用 /* */ 注释。

物化视图
import { materializedView } from '@chkit/core'

const eventCounts = materializedView({
  database: 'analytics',
  name: 'event_counts_mv',
  to: { database: 'analytics', name: 'event_counts' },
  as: 'SELECT org_id, count() AS total FROM analytics.events GROUP BY org_id',
})
导出

使用 schema() 对定义进行分组,或逐个导出(任何具有有效 kind 的导出都会被发现):

export default schema(users, events, eventCounts)
// or
export const users = table({ ... })
export const events = table({ ... })

CLI 命令

所有命令都支持 --json,用于输出机器可读内容;也支持 --config <path>,用于指定自定义配置文件。

init:搭建项目脚手架
chkit init

创建 clickhouse.config.ts 和 src/db/schema/example.ts。

generate:创建迁移
chkit generate --name add-users-table
chkit generate --dryrun                        # Preview without writing
chkit generate --table analytics.events        # Scope to specific table
chkit generate --rename-table old.users=new.accounts
chkit generate --rename-column db.table.old=new

将架构定义与上一个快照进行比较。每项操作都会获得一个风险级别:

  • safe:CREATE TABLE、ADD COLUMN
  • caution:设置更改
  • danger:DROP TABLE、DROP COLUMN
migrate:应用迁移
chkit migrate --json           # Preview pending without applying
chkit migrate --apply          # Apply all pending
chkit migrate --apply --allow-destructive   # Allow danger operations
chkit migrate --apply --table analytics.events
chkit migrate --apply --retry <file>        # Resume a failed migration after editing its file
chkit migrate --abandon <file> --apply      # Reset a failed migration so the next apply starts it over

应用前会验证校验和。在 CI 中,破坏性操作需要显式指定 --allow-destructive。

迁移若中途失败,会保持进行中状态;使用 --apply 可恢复迁移,并跳过已完成的语句。使用高于 0.2.0-beta.8 的 chkit 时,编辑迁移文件后,如果没有语句被记录为已完成,--apply 会从第 1 条语句重新运行;否则请使用 --retry 或 --abandon,并先通过 --json 预览,但不要指定 --apply。切勿手动编辑 _chkit_migrations 日志表。这些版本还会拒绝应用不含可执行语句的待处理文件,例如尚未填充内容的 generate --empty 占位文件。

status:迁移状态
chkit status
# Output: Migrations: 5 total, 3 applied, 2 pending

需要连接 ClickHouse 才能读取迁移日志。已连接的配置可以在日志不存在时创建日志,但不会应用待处理的迁移语句。

drift:比较实时状态与预期状态
chkit drift
chkit drift --table analytics.events

将快照与实时 ClickHouse 进行比较。报告缺失或多余的对象以及列级差异。

check:CI 门禁
chkit check              # Run all policy checks
chkit check --strict     # Force all policies on
chkit check --json       # Machine-readable output

检查待处理的迁移、校验和不匹配、架构漂移和插件检查。失败时退出代码为 1。

snapshot:在并行分支后修复 snapshot.json

需要使用高于 0.2.0-beta.8 的 chkit 版本。

chkit snapshot rebuild --dryrun   # Report the entries that differ from the current snapshot.json
chkit snapshot rebuild            # Rewrite chkit/meta/snapshot.json from the schema definitions

当合并或变基两个都运行过 generate 的分支后,snapshot.json 中出现合并冲突标记时,请使用此命令。先解决架构文件冲突。切勿选择冲突的一方,也不要手动编辑文件:这会丢弃另一分支的条目。冲突文件无法进行比较,因此在暂存前请检查重建的文件:运行 git diff HEAD -- chkit/meta/snapshot.json,合并时再与 MERGE_HEAD 对比,变基时则与 REBASE_HEAD 对比。重建会将每个定义记录为已迁移,因此只有在每项架构变更都有迁移文件时才进行重建(每个分支上 chkit generate --dryrun 都报告 0 个操作);升级 chkit 后,请先运行 chkit generate。如果文件已损坏但已提交,且当前没有正在进行的合并或变基,请从 git 恢复快照,而不要重建(git checkout HEAD -- chkit/meta/snapshot.json);放弃失败的迁移后,也请恢复快照,再重新生成。此命令不支持 --table。如果两个分支都更改了同一张表或视图,请添加一项迁移以再次应用该更改:https://chkit.obsessiondb.com/cli/snapshot/

query:对配置的目标运行 SQL
chkit query "SELECT count() FROM users"
chkit query "SELECT count() FROM users" --json
chkit query "SELECT count() FROM users" --service customer-b  # ObsessionDB plugin

使用当前启用的执行器:默认使用直接配置的 clickhouse,如果已加载 ObsessionDB 插件服务,则使用该服务。

重命名工作流

如需重命名表或列而不执行删除并重建:

表重命名:在表上设置 renamedFrom:

const accounts = table({
  database: 'app',
  name: 'accounts',           // new name
  renamedFrom: { name: 'users' },  // old name
  // ... columns, engine, etc.
})

列重命名:在列上设置 renamedFrom:

columns: [
  { name: 'user_email', type: 'String', renamedFrom: 'email' },
]

CLI 标志会覆盖架构元数据:--rename-table old=new、--rename-column db.table.old=new。

插件

在 clickhouse.config.ts 中注册插件:

import { codegen } from '@chkit/plugin-codegen'

export default defineConfig({
  plugins: [
    codegen({ outFile: './src/generated/chkit-types.ts', emitZod: true }),
  ],
})
可用插件
插件安装命令用途
@chkit/plugin-codegenbun add -d @chkit/plugin-codegenchkit codegen生成 TypeScript 类型和 Zod 架构
@chkit/plugin-pullbun add -d @chkit/plugin-pullchkit pull将实时 ClickHouse 数据库结构导入架构文件
@chkit/plugin-backfillbun add -d @chkit/plugin-backfillchkit plugin backfill使用检查点重放分区和排序键
@chkit/plugin-obsessiondbbun add -d @chkit/plugin-obsessiondbchkit query --service <name>通过 ObsessionDB 服务路由命令

常见工作流

新建项目
bun add -d chkit
bunx chkit init
# Edit src/db/schema/example.ts with your tables
bunx chkit generate --name init
bunx chkit migrate --apply
添加表
  1. 在 src/db/schema/ 中创建新的架构文件
  2. 使用 table() 定义表,并通过 schema() 导出
  3. 运行 chkit generate --name add-my-table
  4. 运行 chkit migrate --apply
CI 流水线
chkit check --strict --json
# Fails if: pending migrations, checksum mismatches, schema drift, or plugin errors
接入已有数据的数据库

请参阅完整的接入指南。Pull 导入定义,而非已应用的历史记录。请将生成的基线与实时定义进行核对;单靠 CREATE ... IF NOT EXISTS 并不能验证已有对象。使用现有的受限目标时,只从尚未应用的基线中移除多余的数据库配置,然后按常规方式应用;在下一次 ALTER 之前,请验证数据和视图是否保留、日志校验和以及实时漂移。切勿编辑日志或重建快照来伪装接入已完成。

结构性属性与可更改属性

属性发生变化时,chkit 会判断需要使用 ALTER 还是 DROP+CREATE:

  • 结构性(需要删除并重新创建):engine、primaryKey、orderBy、partitionBy、uniqueKey
  • 可更改(原地 ALTER):列、索引、投影、设置、TTL、注释

视图和物化视图始终使用删除并重新创建的方式。

对于已填充数据的结构性变更,请勿将生成的 DROP/CREATE 用作数据保留方案。请使用分阶段复制/验证/切换方案,并明确协调写入方、制定恢复方案并跟踪 SQL 迁移。

回填插件目前按物理分区和排序键分块;--from/--to 使用元数据选择分区,而不是根据任意时间戳列筛选行。--time-column 和 --chunk-hours 不是当前的规划标志。新计划会获得新的标识;若要重试,请恢复已保存的计划,而不是重新规划。MV 重放适用于历史聚合目标;对同一张表进行复制可能会导致普通 MergeTree 行重复。对于任意源表到影子表的转换,请使用受跟踪的 SQL,并在执行前检查生成的插件 SQL。

文档

请访问 https://chkit.obsessiondb.com 阅读文档。请求页面时使用 Accept: text/markdown,即可获取 Markdown 输出。有关详细信息,请查阅相关指南。

curl -s -H "Accept: text/markdown" <url>
关键页面
页面URL适用场景
Schema DSL 参考https://chkit.obsessiondb.com/schema/dsl-reference/完整的字段规范、列类型和验证规则
配置https://chkit.obsessiondb.com/configuration/overview/所有配置选项及默认值
Codegen 插件https://chkit.obsessiondb.com/plugins/codegen/TypeScript 类型、Zod 模式、类型化插入助手
Pull 插件https://chkit.obsessiondb.com/plugins/pull/将运行中的 ClickHouse 内省并转换为 schema 文件
Backfill 插件https://chkit.obsessiondb.com/plugins/backfill/按分区/排序键重放并设置检查点
CI/CD 集成https://chkit.obsessiondb.com/guides/ci-cd/流水线设置、检查命令、部署
查找所有页面

获取索引以查找 CLI 命令页面和其他文档:

curl -s -H "Accept: text/markdown" https://chkit.obsessiondb.com/

评论

支持 Markdown