mcpField
C
chkit

chkit

github.com/obsessiondbデータ・データベース4262 回インストール2 日前に更新
リポジトリ

chkit について

chkitは、CLIでデータベース変更を管理するチーム向けのClickHouse用TypeScriptスキーマ・マイグレーションツールキットです。SQL生成、実環境とのドリフト検出、CIポリシーチェックを備えています。

主な機能

  1. 01TypeScriptでスキーマを定義
  2. 02マイグレーションSQLの生成とプレビュー
  3. 03マイグレーションの適用と追跡
  4. 04実環境のスキーマドリフト検出
  5. 05CIポリシーチェックの実行

活用シーン

  1. 01ClickHouseスキーマ変更の管理
  2. 02適用前のマイグレーションSQL確認
  3. 03CIでのスキーマドリフト検査
  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

スキーマファイルは、@chkit/core の関数を使用して定義をエクスポートする TypeScript ファイルです。

テーブル
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 として保存します)。0.2.0-beta.8 より新しい chkit では、文字列以外のカラムの 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 参照(users ではなく app.users)を記述してください。ClickHouse は、修飾されていない名前をセッションの現在のデータベースに対して解決します。0.2.0-beta.8 より新しい chkit では、ビューの作成時に、使用するビュー、マテリアライズドビュー、辞書の後に作成するため、これらの参照も読み取ります。

0.2.0-beta.8 より新しい chkit では、as を複数行にまたがらせたり、SQL コメントを含めたりできます。他の SQL フィールド(マテリアライズドビューの as、partitionBy、ttl、インデックスおよびプロジェクションの SQL、辞書の source/layout/lifetime)も同様です。chkit はクエリを 1 行にして書き込む前にコメントを削除します。全文検索(type: 'text')インデックス式は例外で、削除されるのは -- と、ネストされていない /* */ コメントのみです。生成されたマイグレーションを確認してください。文字列リテラルの外にある --、//、または # コメントが、1 行のステートメント(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 の修復

chkit 0.2.0-beta.8 より新しいバージョンが必要です。

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 を実行した 2 つのブランチをマージまたはリベースした後に、snapshot.json にマージコンフリクトのマーカーが残っている場合に使用します。まずスキーマファイルの競合を解決してください。競合の片方を採用したり、ファイルを手作業で編集したりしないでください。もう一方のブランチのエントリーが失われます。競合中のファイルは比較できないため、ステージする前に再構築したファイルを確認してください。git diff HEAD -- chkit/meta/snapshot.json を実行し、次にマージ中は MERGE_HEAD、リベース中は REBASE_HEAD に対して同じ差分を確認します。再構築するとすべての定義が移行済みとして記録されるため、すべてのスキーマ変更に移行ファイルがある場合にのみ再構築してください(各ブランチで chkit generate --dryrun が 0 件の操作を報告していること)。chkit をアップグレードした後は、まず chkit generate を実行してください。ファイルが破損していてもコミット済みであり、マージまたはリベースが進行中でない場合(git checkout HEAD -- chkit/meta/snapshot.json)、または失敗した移行を中止して再生成する場合は、再構築する代わりに Git からスナップショットを復元してください。--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 codegenTypeScript 型と 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 は、現在のプランニングフラグではありません。新しいプランには新しい ID が割り当てられます。再試行する場合は再プランニングせず、保存済みのプランを再開してください。MV の再生は過去の集計先を対象としています。同一テーブルへのコピーでは、通常の MergeTree の行が重複する可能性があります。任意のソースからシャドウへの変換には、追跡可能な SQL を使用し、実行前に生成されたプラグイン SQL を確認してください。

ドキュメント

ドキュメントは https://chkit.obsessiondb.com をご覧ください。Markdown 形式で出力するには、Accept: text/markdown を指定してページをリクエストしてください。このスキルで扱う内容の詳細については、該当するガイドを取得してください。

curl -s -H "Accept: text/markdown" <url>
主なページ
ページURL使用する場面
スキーマ DSL リファレンスhttps://chkit.obsessiondb.com/schema/dsl-reference/フィールドの仕様、カラム型、検証ルールの全容を確認する場合
設定https://chkit.obsessiondb.com/configuration/overview/すべての設定オプションとデフォルト値を確認する場合
Codegen プラグインhttps://chkit.obsessiondb.com/plugins/codegen/TypeScript 型、Zod スキーマ、型付き insert ヘルパーを確認する場合
Pull プラグインhttps://chkit.obsessiondb.com/plugins/pull/稼働中の ClickHouse をイントロスペクションしてスキーマファイルを作成する場合
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/

コメント