@housekit/kit 0.1.16 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -3
- package/dist/index.js +36 -12
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ HouseKit CLI brings a modern, streamlined developer experience to the ClickHouse
|
|
|
15
15
|
|
|
16
16
|
- **Declarative Workflows**: Define your source of truth in TypeScript.
|
|
17
17
|
- **Automatic Drift Detection**: Compares your code against the live DB schema instantly.
|
|
18
|
+
- **Engine-Aware Diffing**: Normalizes local engine objects vs. remote SQL to avoid false changes.
|
|
18
19
|
- **Blue-Green Deployments**: Safe, zero-downtime structural changes for Materialized Views and Tables.
|
|
19
20
|
- **Cluster Awareness**: First-class support for sharded clusters using `{cluster}` macros and sharding keys.
|
|
20
21
|
- **Zero Runtime Dependencies**: Powered by `jiti` for native TS loading—no pre-compilation or heavy binaries required.
|
|
@@ -104,8 +105,14 @@ export default {
|
|
|
104
105
|
HouseKit simplifies managing Replicated and Distributed tables across a cluster.
|
|
105
106
|
|
|
106
107
|
```typescript
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
import { defineTable, t, Engine } from '@housekit/orm';
|
|
109
|
+
|
|
110
|
+
// Define a table that lives on a cluster (object syntax still supported)
|
|
111
|
+
export const events = defineTable('events', {
|
|
112
|
+
id: t.uuid('id').primaryKey(),
|
|
113
|
+
userId: t.uuid('user_id'),
|
|
114
|
+
createdAt: t.timestamp('created_at').default('now()'),
|
|
115
|
+
}, {
|
|
109
116
|
engine: Engine.ReplicatedMergeTree(),
|
|
110
117
|
|
|
111
118
|
// High Portability: Using '{cluster}' tells ClickHouse to use the
|
|
@@ -116,6 +123,9 @@ export const events = defineTable('events', { ... }, {
|
|
|
116
123
|
shardKey: 'user_id',
|
|
117
124
|
orderBy: 'id'
|
|
118
125
|
});
|
|
126
|
+
|
|
127
|
+
// Callback syntax is also available when you want presets or composition:
|
|
128
|
+
// defineTable('events', (t) => ({ ... }), { ... })
|
|
119
129
|
```
|
|
120
130
|
When you run `housekit push`, the CLI automatically detects the cluster configuration and executes the `ALTER` or `CREATE` statements across all nodes using the specified macro.
|
|
121
131
|
|
|
@@ -131,6 +141,7 @@ Have an existing database with 100 tables? Don't write the code by hand.
|
|
|
131
141
|
bunx housekit pull --database production
|
|
132
142
|
```
|
|
133
143
|
This will scan your ClickHouse instance and generate a clean, readable `schema.ts` file with all table definitions, engines, and settings preserved.
|
|
144
|
+
Engine strings from ClickHouse are stored as `customEngine` to guarantee a lossless round-trip.
|
|
134
145
|
|
|
135
146
|
---
|
|
136
147
|
|
|
@@ -144,4 +155,4 @@ This will scan your ClickHouse instance and generate a clean, readable `schema.t
|
|
|
144
155
|
|
|
145
156
|
## License
|
|
146
157
|
|
|
147
|
-
MIT © [Pablo Fernandez Ruiz](https://github.com/pablofdezr)
|
|
158
|
+
MIT © [Pablo Fernandez Ruiz](https://github.com/pablofdezr)
|
package/dist/index.js
CHANGED
|
@@ -6004,7 +6004,7 @@ function resolveDatabase(config, name) {
|
|
|
6004
6004
|
import { detectMaterializedViewDrift, extractMVQuery } from "@housekit/orm";
|
|
6005
6005
|
|
|
6006
6006
|
// src/schema/diff.ts
|
|
6007
|
-
import { normalizeHousekitMetadata, upgradeMetadataVersion } from "@housekit/orm";
|
|
6007
|
+
import { normalizeHousekitMetadata, upgradeMetadataVersion, renderEngineSQL } from "@housekit/orm";
|
|
6008
6008
|
function columnType(col) {
|
|
6009
6009
|
return col.toSQL();
|
|
6010
6010
|
}
|
|
@@ -6290,9 +6290,20 @@ function diffTable(table, localCols, remote, opts) {
|
|
|
6290
6290
|
warnings.push(`${label} differs (remote="${r || "unset"}", local="${l || "unset"}")`);
|
|
6291
6291
|
}
|
|
6292
6292
|
};
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6293
|
+
let localEngineSQL = "MergeTree";
|
|
6294
|
+
if (localOpts.customEngine) {
|
|
6295
|
+
localEngineSQL = localOpts.customEngine;
|
|
6296
|
+
} else if (localOpts.engine) {
|
|
6297
|
+
localEngineSQL = renderEngineSQL(localOpts.engine);
|
|
6298
|
+
}
|
|
6299
|
+
const normalizeEngine = (engine) => engine.replace(/\s+/g, "").replace(/\(\)/g, "").toLowerCase();
|
|
6300
|
+
const localEngineNorm = normalizeEngine(localEngineSQL);
|
|
6301
|
+
const remoteEngineNorm = normalizeEngine(remoteOpts.engine || "MergeTree");
|
|
6302
|
+
if (localEngineNorm !== remoteEngineNorm) {
|
|
6303
|
+
optionChanges.push("engine");
|
|
6304
|
+
destructiveReasons.push(`engine change (local="${localEngineSQL}", remote="${remoteOpts.engine}") (requires shadow swap)`);
|
|
6305
|
+
warnings.push("Engine mismatch requires full table recreation");
|
|
6306
|
+
}
|
|
6296
6307
|
compare("orderBy", localOpts.orderBy, remoteOpts.orderBy, () => {
|
|
6297
6308
|
destructiveReasons.push("order by change");
|
|
6298
6309
|
plan.push(`ALTER TABLE \`${tableName}\` MODIFY ORDER BY (${normalizeClause(localOpts.orderBy)})`);
|
|
@@ -7314,7 +7325,11 @@ function extractHousekitMetadata2(comment) {
|
|
|
7314
7325
|
}
|
|
7315
7326
|
return null;
|
|
7316
7327
|
}
|
|
7317
|
-
function
|
|
7328
|
+
function extractEngineFromCreate(statement) {
|
|
7329
|
+
const match2 = statement.match(/ENGINE\s*=\s*(.+?)(\s+(?:ORDER|PARTITION|PRIMARY|SAMPLE|TTL|SETTINGS|COMMENT)|$)/i);
|
|
7330
|
+
return match2 ? match2[1].trim() : "MergeTree()";
|
|
7331
|
+
}
|
|
7332
|
+
function buildTableFile(table, columns, engineSQL, format3 = "ts", metadata) {
|
|
7318
7333
|
const mappedColumns = columns.map((col) => ({
|
|
7319
7334
|
name: col.name,
|
|
7320
7335
|
comment: col.comment,
|
|
@@ -7341,6 +7356,8 @@ function buildTableFile(table, columns, format3 = "ts", metadata) {
|
|
|
7341
7356
|
const comment = `// Auto-generated on ${timestamp}
|
|
7342
7357
|
`;
|
|
7343
7358
|
const optionLines = [];
|
|
7359
|
+
const escapedEngine = engineSQL.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
7360
|
+
optionLines.push(` customEngine: "${escapedEngine}"`);
|
|
7344
7361
|
if (metadata?.version) {
|
|
7345
7362
|
optionLines.push(` metadataVersion: "${metadata.version}"`);
|
|
7346
7363
|
} else {
|
|
@@ -7359,9 +7376,12 @@ ${optionLines.join(`,
|
|
|
7359
7376
|
const exportStatement = `export const ${variableName} = defineTable('${table}', (t) => ({
|
|
7360
7377
|
${columnLines}
|
|
7361
7378
|
})${optionsBlock});`;
|
|
7362
|
-
|
|
7379
|
+
const importLine = `import { t, defineTable, Engine } from '@housekit/orm';`;
|
|
7380
|
+
const typeAlias = `
|
|
7381
|
+
`;
|
|
7382
|
+
return `${comment}${importLine}
|
|
7363
7383
|
|
|
7364
|
-
${exportStatement}
|
|
7384
|
+
${exportStatement}${typeAlias}
|
|
7365
7385
|
`;
|
|
7366
7386
|
}
|
|
7367
7387
|
function persistLanguagePreference(configPath, lang) {
|
|
@@ -7543,6 +7563,7 @@ async function pullCommand(options) {
|
|
|
7543
7563
|
const createParsed = await createResult.json();
|
|
7544
7564
|
const createRows = Array.isArray(createParsed) ? createParsed : createParsed?.data ?? [];
|
|
7545
7565
|
const createStatement = Array.isArray(createRows) && createRows.length > 0 ? createRows[0]?.statement || "" : "";
|
|
7566
|
+
const engineSQL = extractEngineFromCreate(createStatement);
|
|
7546
7567
|
let tableMetadata = null;
|
|
7547
7568
|
try {
|
|
7548
7569
|
const commentRes = await client.query({
|
|
@@ -7691,7 +7712,7 @@ async function pullCommand(options) {
|
|
|
7691
7712
|
comment: commentFromDescribe || commentFromCreate
|
|
7692
7713
|
};
|
|
7693
7714
|
});
|
|
7694
|
-
const content = buildTableFile(tableName, columns, fileFormat, tableMetadata);
|
|
7715
|
+
const content = buildTableFile(tableName, columns, engineSQL, fileFormat, tableMetadata);
|
|
7695
7716
|
writeFileSync3(join4(targetDir, `${tableName}.${fileExtension}`), content);
|
|
7696
7717
|
describeSpinner.stop();
|
|
7697
7718
|
success(`Wrote schema file for ${quoteName(tableName)}`);
|
|
@@ -8764,22 +8785,25 @@ export default {
|
|
|
8764
8785
|
mkdirSync4(schemaPath, { recursive: true });
|
|
8765
8786
|
success(`Created schema directory: ${quoteName(schemaPath)}`);
|
|
8766
8787
|
const exampleSchemaPath = join7(schemaPath, `logs.${fileType}`);
|
|
8788
|
+
const importLine = `import { t, defineTable, Engine } from '@housekit/orm';`;
|
|
8789
|
+
const typeAliasLine = `
|
|
8790
|
+
`;
|
|
8767
8791
|
const exampleSchemaContent = `// Example table - This is a sample schema file to demonstrate HouseKit usage
|
|
8768
|
-
|
|
8792
|
+
${importLine}
|
|
8769
8793
|
|
|
8770
|
-
export const logs = defineTable('logs', {
|
|
8794
|
+
export const logs = defineTable('logs', (t) => ({
|
|
8771
8795
|
id: t.uuid('id').autoGenerate().primaryKey(),
|
|
8772
8796
|
message: t.string('message').comment('Log message content'),
|
|
8773
8797
|
level: t.enum('level', ['info', 'warning', 'error']).default('info').comment('Log severity level'),
|
|
8774
8798
|
tags: t.array(t.string('tag')).nullable().comment('Array of tags for categorizing logs'),
|
|
8775
8799
|
metadata: t.json('metadata').nullable().comment('Additional log metadata'),
|
|
8776
8800
|
createdAt: t.timestamp('created_at').default('now()'),
|
|
8777
|
-
}, {
|
|
8801
|
+
}), {
|
|
8778
8802
|
engine: Engine.MergeTree(),
|
|
8779
8803
|
orderBy: ['createdAt', 'id'],
|
|
8780
8804
|
appendOnly: false
|
|
8781
8805
|
});
|
|
8782
|
-
`;
|
|
8806
|
+
${typeAliasLine}`;
|
|
8783
8807
|
writeFileSync4(exampleSchemaPath, exampleSchemaContent);
|
|
8784
8808
|
info(`Created example schema: ${quoteName(exampleSchemaPath)}`);
|
|
8785
8809
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@housekit/kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "CLI tool for HouseKit - manage ClickHouse schemas, migrations, and database operations with type-safe workflows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@clickhouse/client": "^1.14.0",
|
|
51
|
-
"@housekit/orm": "
|
|
51
|
+
"@housekit/orm": "workspace:*",
|
|
52
52
|
"chalk": "^5.6.2",
|
|
53
53
|
"cli-table3": "^0.6.5",
|
|
54
54
|
"commander": "^12.0.0",
|