@jantokic/chtype 0.1.0

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +192 -0
  3. package/dist/client/client.d.ts +41 -0
  4. package/dist/client/client.d.ts.map +1 -0
  5. package/dist/client/client.js +60 -0
  6. package/dist/client/client.js.map +1 -0
  7. package/dist/client/index.d.ts +2 -0
  8. package/dist/client/index.d.ts.map +1 -0
  9. package/dist/client/index.js +2 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/codegen/cli.d.ts +10 -0
  12. package/dist/codegen/cli.d.ts.map +1 -0
  13. package/dist/codegen/cli.js +100 -0
  14. package/dist/codegen/cli.js.map +1 -0
  15. package/dist/codegen/config.d.ts +73 -0
  16. package/dist/codegen/config.d.ts.map +1 -0
  17. package/dist/codegen/config.js +53 -0
  18. package/dist/codegen/config.js.map +1 -0
  19. package/dist/codegen/generator.d.ts +16 -0
  20. package/dist/codegen/generator.d.ts.map +1 -0
  21. package/dist/codegen/generator.js +95 -0
  22. package/dist/codegen/generator.js.map +1 -0
  23. package/dist/codegen/index.d.ts +5 -0
  24. package/dist/codegen/index.d.ts.map +1 -0
  25. package/dist/codegen/index.js +5 -0
  26. package/dist/codegen/index.js.map +1 -0
  27. package/dist/codegen/introspect.d.ts +60 -0
  28. package/dist/codegen/introspect.d.ts.map +1 -0
  29. package/dist/codegen/introspect.js +118 -0
  30. package/dist/codegen/introspect.js.map +1 -0
  31. package/dist/codegen/type-mapper.d.ts +16 -0
  32. package/dist/codegen/type-mapper.d.ts.map +1 -0
  33. package/dist/codegen/type-mapper.js +118 -0
  34. package/dist/codegen/type-mapper.js.map +1 -0
  35. package/dist/index.d.ts +4 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +5 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/query/expressions.d.ts +28 -0
  40. package/dist/query/expressions.d.ts.map +1 -0
  41. package/dist/query/expressions.js +65 -0
  42. package/dist/query/expressions.js.map +1 -0
  43. package/dist/query/index.d.ts +7 -0
  44. package/dist/query/index.d.ts.map +1 -0
  45. package/dist/query/index.js +6 -0
  46. package/dist/query/index.js.map +1 -0
  47. package/dist/query/insert-builder.d.ts +18 -0
  48. package/dist/query/insert-builder.d.ts.map +1 -0
  49. package/dist/query/insert-builder.js +27 -0
  50. package/dist/query/insert-builder.js.map +1 -0
  51. package/dist/query/param.d.ts +11 -0
  52. package/dist/query/param.d.ts.map +1 -0
  53. package/dist/query/param.js +16 -0
  54. package/dist/query/param.js.map +1 -0
  55. package/dist/query/query-builder.d.ts +30 -0
  56. package/dist/query/query-builder.d.ts.map +1 -0
  57. package/dist/query/query-builder.js +36 -0
  58. package/dist/query/query-builder.js.map +1 -0
  59. package/dist/query/select-builder.d.ts +64 -0
  60. package/dist/query/select-builder.d.ts.map +1 -0
  61. package/dist/query/select-builder.js +182 -0
  62. package/dist/query/select-builder.js.map +1 -0
  63. package/dist/query/types.d.ts +30 -0
  64. package/dist/query/types.d.ts.map +1 -0
  65. package/dist/query/types.js +2 -0
  66. package/dist/query/types.js.map +1 -0
  67. package/package.json +65 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 chtype contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,192 @@
1
+ # chtype
2
+
3
+ **Type-safe ClickHouse toolkit for TypeScript.**
4
+
5
+ Generate TypeScript types from your ClickHouse schema, then query with full IDE autocomplete and compile-time validation.
6
+
7
+ ```bash
8
+ npm install chtype
9
+ # or
10
+ bun add chtype
11
+ ```
12
+
13
+ ## Why chtype?
14
+
15
+ ClickHouse has no mature ORM for TypeScript. The official `@clickhouse/client` is excellent but gives you raw SQL strings — typos in column names only fail at runtime, result types are manually maintained, and schema drift silently breaks your code.
16
+
17
+ chtype fixes this with three subpath imports:
18
+
19
+ | Import | What it does |
20
+ |---|---|
21
+ | `chtype/codegen` | Introspects your ClickHouse DB and generates TypeScript interfaces |
22
+ | `chtype/query` | Type-safe query builder with ClickHouse-specific functions (argMax, FINAL, SETTINGS) |
23
+ | `chtype/client` | Thin wrapper over `@clickhouse/client` that connects query builder to execution |
24
+
25
+ ## Quick Start
26
+
27
+ ### 1. Generate types from your database
28
+
29
+ ```bash
30
+ npx chtype generate \
31
+ --host http://localhost:8123 \
32
+ --database my_db \
33
+ --output ./src/generated/schema.ts
34
+ ```
35
+
36
+ This produces a file like:
37
+
38
+ ```typescript
39
+ // @generated by chtype — do not edit manually
40
+
41
+ /**
42
+ * Table: `users`
43
+ * Engine: ReplacingMergeTree(updated_at)
44
+ * ORDER BY: (user_id)
45
+ */
46
+ export interface UsersRow {
47
+ user_id: string;
48
+ name: string;
49
+ score: number | null;
50
+ tags: string[];
51
+ updated_at: string;
52
+ }
53
+
54
+ /** Insert type for `users` — DEFAULT columns are optional. */
55
+ export interface UsersInsert {
56
+ user_id: string;
57
+ name: string;
58
+ score?: number | null;
59
+ tags?: string[];
60
+ updated_at?: string;
61
+ }
62
+
63
+ export interface Database {
64
+ users: {
65
+ row: UsersRow;
66
+ insert: UsersInsert;
67
+ engine: "ReplacingMergeTree";
68
+ versionColumn: "updated_at";
69
+ };
70
+ }
71
+ ```
72
+
73
+ ### 2. Query with full type safety
74
+
75
+ ```typescript
76
+ import { createQueryBuilder } from 'chtype/query';
77
+ import { createClient } from 'chtype/client';
78
+ import type { Database } from './generated/schema';
79
+
80
+ const qb = createQueryBuilder<Database>();
81
+ const ch = createClient<Database>({
82
+ url: 'http://localhost:8123',
83
+ database: 'my_db',
84
+ });
85
+
86
+ // Column names autocomplete — typos caught at compile time
87
+ const query = qb
88
+ .selectFrom('users')
89
+ .select(['user_id', 'name', 'score'])
90
+ .where('score', '>', qb.param('minScore', 'Float64'))
91
+ .orderBy('score', 'DESC')
92
+ .limit(20)
93
+ .compile();
94
+
95
+ const users = await ch.execute(query);
96
+ ```
97
+
98
+ ### 3. ClickHouse-specific features
99
+
100
+ ```typescript
101
+ // argMax — first-class citizen for ReplacingMergeTree tables
102
+ const latest = qb
103
+ .selectFrom('users')
104
+ .select([
105
+ 'user_id',
106
+ qb.fn.argMax('name', 'updated_at').as('name'),
107
+ qb.fn.argMax('score', 'updated_at').as('score'),
108
+ ])
109
+ .groupBy('user_id')
110
+ .compile();
111
+
112
+ // FINAL modifier (for debug/audit only)
113
+ const withFinal = qb
114
+ .selectFrom('users')
115
+ .select(['user_id', 'name'])
116
+ .final()
117
+ .compile();
118
+
119
+ // SETTINGS clause
120
+ const withSettings = qb
121
+ .selectFrom('users')
122
+ .select(['user_id'])
123
+ .settings({ max_execution_time: 30 })
124
+ .compile();
125
+
126
+ // Type-safe inserts — MATERIALIZED columns excluded, DEFAULT columns optional
127
+ await ch.insert('users', [
128
+ { user_id: '123', name: 'Alice' },
129
+ { user_id: '456', name: 'Bob', score: 42 },
130
+ ]);
131
+ ```
132
+
133
+ ### 4. All values are parameterized
134
+
135
+ The query builder **only** accepts `Param` or `Expression` values in WHERE clauses — raw strings are not allowed. This makes SQL injection impossible by design.
136
+
137
+ ```typescript
138
+ // This is the only way to pass values — always safe
139
+ qb.selectFrom('users')
140
+ .where('name', '=', qb.param('name', 'String'))
141
+
142
+ // Raw strings in WHERE are a type error — won't compile
143
+ ```
144
+
145
+ ## Config File
146
+
147
+ Instead of CLI flags, use a `chtype.config.ts` file:
148
+
149
+ ```typescript
150
+ import { defineConfig } from 'chtype/codegen';
151
+
152
+ export default defineConfig({
153
+ connection: {
154
+ host: 'http://localhost:8123',
155
+ database: 'my_db',
156
+ username: 'default',
157
+ password: process.env.CLICKHOUSE_PASSWORD,
158
+ },
159
+ output: './src/generated/schema.ts',
160
+ bigints: true, // set to true to map UInt64/Int64 to bigint instead of string
161
+ include: ['users', 'events', 'market_*'],
162
+ exclude: [],
163
+ });
164
+ ```
165
+
166
+ Then run:
167
+
168
+ ```bash
169
+ npx chtype generate --config chtype.config.ts
170
+ ```
171
+
172
+ ## How It Compares
173
+
174
+ | Feature | chtype | Raw @clickhouse/client | Kysely + CH dialect | hypequery |
175
+ |---|---|---|---|---|
176
+ | Column autocomplete | Yes | No | Yes (limited) | Yes |
177
+ | Schema drift detection | Yes (codegen) | No | No | Yes (codegen) |
178
+ | argMax / FINAL / SETTINGS | Yes | Manual SQL | No | No |
179
+ | Insert type validation | Yes (Row vs Insert) | No | No | No |
180
+ | Engine metadata in types | Yes | No | No | Partial |
181
+ | Zero runtime overhead | Yes | N/A | Yes | No (framework) |
182
+ | SQL injection prevention | By design | Manual | By design | By design |
183
+
184
+ ## Requirements
185
+
186
+ - Node.js >= 20 or Bun
187
+ - TypeScript >= 5.0
188
+ - ClickHouse server (any recent version)
189
+
190
+ ## License
191
+
192
+ MIT
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Type-safe ClickHouse client.
3
+ *
4
+ * Wraps @clickhouse/client with schema-aware methods.
5
+ */
6
+ import { type ClickHouseClient as BaseClient, type ClickHouseClientConfigOptions } from '@clickhouse/client';
7
+ import type { CompiledQuery, DatabaseSchema, InsertType, TableName } from '../query/types.js';
8
+ export interface ChtypeClient<DB extends DatabaseSchema> {
9
+ /** Execute a compiled query and return typed rows. */
10
+ execute<T = Record<string, unknown>>(query: CompiledQuery): Promise<T[]>;
11
+ /** Execute a raw SQL query with optional parameters. */
12
+ query<T = Record<string, unknown>>(sql: string, params?: Record<string, unknown>): Promise<T[]>;
13
+ /** Insert rows into a table. Type-checked against the table's Insert type. */
14
+ insert<T extends TableName<DB>>(table: T, rows: InsertType<DB, T>[]): Promise<void>;
15
+ /**
16
+ * Execute a DDL/ALTER command (raw SQL, no parameterization).
17
+ *
18
+ * WARNING: Never interpolate user input into the SQL string passed here.
19
+ * This method is for DDL statements only (CREATE TABLE, ALTER TABLE, etc.)
20
+ * where ClickHouse does not support parameterized queries.
21
+ */
22
+ command(sql: string): Promise<void>;
23
+ close(): Promise<void>;
24
+ readonly raw: BaseClient;
25
+ }
26
+ /**
27
+ * Create a type-safe ClickHouse client.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { createClient } from 'chtype/client';
32
+ * import type { Database } from './chtype.generated';
33
+ *
34
+ * const ch = createClient<Database>({
35
+ * url: 'http://localhost:8123',
36
+ * database: 'my_db',
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function createClient<DB extends DatabaseSchema>(options: ClickHouseClientConfigOptions): ChtypeClient<DB>;
41
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,gBAAgB,IAAI,UAAU,EACnC,KAAK,6BAA6B,EAEnC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9F,MAAM,WAAW,YAAY,CAAC,EAAE,SAAS,cAAc;IACrD,sDAAsD;IACtD,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAEzE,wDAAwD;IACxD,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAEhG,8EAA8E;IAC9E,MAAM,CAAC,CAAC,SAAS,SAAS,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpF;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,EAAE,SAAS,cAAc,EACpD,OAAO,EAAE,6BAA6B,GACrC,YAAY,CAAC,EAAE,CAAC,CA8ClB"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Type-safe ClickHouse client.
3
+ *
4
+ * Wraps @clickhouse/client with schema-aware methods.
5
+ */
6
+ import { createClient as createBaseClient, } from '@clickhouse/client';
7
+ /**
8
+ * Create a type-safe ClickHouse client.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { createClient } from 'chtype/client';
13
+ * import type { Database } from './chtype.generated';
14
+ *
15
+ * const ch = createClient<Database>({
16
+ * url: 'http://localhost:8123',
17
+ * database: 'my_db',
18
+ * });
19
+ * ```
20
+ */
21
+ export function createClient(options) {
22
+ const client = createBaseClient(options);
23
+ return {
24
+ async execute(query) {
25
+ const result = await client.query({
26
+ query: query.sql,
27
+ query_params: query.params,
28
+ format: 'JSONEachRow',
29
+ });
30
+ return result.json();
31
+ },
32
+ async query(sql, params) {
33
+ const result = await client.query({
34
+ query: sql,
35
+ query_params: params,
36
+ format: 'JSONEachRow',
37
+ });
38
+ return result.json();
39
+ },
40
+ async insert(table, rows) {
41
+ if (rows.length === 0)
42
+ return;
43
+ await client.insert({
44
+ table: table,
45
+ values: rows,
46
+ format: 'JSONEachRow',
47
+ });
48
+ },
49
+ async command(sql) {
50
+ await client.command({ query: sql });
51
+ },
52
+ async close() {
53
+ await client.close();
54
+ },
55
+ get raw() {
56
+ return client;
57
+ },
58
+ };
59
+ }
60
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAGL,YAAY,IAAI,gBAAgB,GACjC,MAAM,oBAAoB,CAAC;AA0B5B;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAsC;IAEtC,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEzC,OAAO;QACL,KAAK,CAAC,OAAO,CAA8B,KAAoB;YAC7D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;gBAChC,KAAK,EAAE,KAAK,CAAC,GAAG;gBAChB,YAAY,EAAE,KAAK,CAAC,MAAM;gBAC1B,MAAM,EAAE,aAAa;aACtB,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,IAAI,EAAK,CAAC;QAC1B,CAAC;QAED,KAAK,CAAC,KAAK,CACT,GAAW,EACX,MAAgC;YAEhC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;gBAChC,KAAK,EAAE,GAAG;gBACV,YAAY,EAAE,MAAM;gBACpB,MAAM,EAAE,aAAa;aACtB,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,IAAI,EAAK,CAAC;QAC1B,CAAC;QAED,KAAK,CAAC,MAAM,CAA0B,KAAQ,EAAE,IAAyB;YACvE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAC9B,MAAM,MAAM,CAAC,MAAM,CAAC;gBAClB,KAAK,EAAE,KAAe;gBACtB,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,aAAa;aACtB,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,GAAW;YACvB,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACvC,CAAC;QAED,KAAK,CAAC,KAAK;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAED,IAAI,GAAG;YACL,OAAO,MAAM,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createClient, type ChtypeClient } from './client.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createClient } from './client.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAqB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * chtype CLI — Generate TypeScript types from your ClickHouse schema.
4
+ *
5
+ * Usage:
6
+ * npx chtype generate --host http://localhost:8123 --database my_db
7
+ * npx chtype generate --config chtype.config.ts
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/codegen/cli.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG"}
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * chtype CLI — Generate TypeScript types from your ClickHouse schema.
4
+ *
5
+ * Usage:
6
+ * npx chtype generate --host http://localhost:8123 --database my_db
7
+ * npx chtype generate --config chtype.config.ts
8
+ */
9
+ import { writeFileSync } from 'node:fs';
10
+ import { resolve } from 'node:path';
11
+ import { createClient } from '@clickhouse/client';
12
+ import { defineCommand, runMain } from 'citty';
13
+ import { ChtypeConfigSchema, loadConfigFile } from './config.js';
14
+ import { generate } from './generator.js';
15
+ import { introspect } from './introspect.js';
16
+ const generateCommand = defineCommand({
17
+ meta: {
18
+ name: 'generate',
19
+ description: 'Generate TypeScript types from a ClickHouse database',
20
+ },
21
+ args: {
22
+ host: { type: 'string', description: 'ClickHouse HTTP URL', default: 'http://localhost:8123' },
23
+ database: { type: 'string', description: 'Database name' },
24
+ username: { type: 'string', description: 'ClickHouse username', default: 'default' },
25
+ password: { type: 'string', description: 'ClickHouse password', default: '' },
26
+ output: { type: 'string', alias: 'o', description: 'Output file path', default: './chtype.generated.ts' },
27
+ bigints: { type: 'boolean', description: 'Map UInt64/Int64 to bigint instead of string', default: false },
28
+ include: { type: 'string', description: 'Comma-separated table name patterns to include' },
29
+ exclude: { type: 'string', description: 'Comma-separated table name patterns to exclude' },
30
+ config: { type: 'string', alias: 'c', description: 'Path to config file (chtype.config.ts)' },
31
+ },
32
+ async run({ args }) {
33
+ let config;
34
+ if (args.config) {
35
+ const fileConfig = await loadConfigFile(resolve(args.config));
36
+ if (!fileConfig) {
37
+ process.exit(1);
38
+ }
39
+ config = fileConfig;
40
+ }
41
+ else {
42
+ config = ChtypeConfigSchema.parse({
43
+ connection: {
44
+ host: args.host,
45
+ database: args.database,
46
+ username: args.username,
47
+ password: args.password,
48
+ },
49
+ output: args.output,
50
+ bigints: args.bigints,
51
+ include: args.include ? args.include.split(',').map((s) => s.trim()) : [],
52
+ exclude: args.exclude ? args.exclude.split(',').map((s) => s.trim()) : [],
53
+ });
54
+ }
55
+ if (!config.connection.database) {
56
+ console.error('Error: --database is required');
57
+ process.exit(1);
58
+ }
59
+ console.log(`Connecting to ${config.connection.host}...`);
60
+ console.log(`Database: ${config.connection.database}`);
61
+ const client = createClient({
62
+ url: config.connection.host,
63
+ database: config.connection.database,
64
+ username: config.connection.username,
65
+ password: config.connection.password,
66
+ });
67
+ try {
68
+ const tables = await introspect(client, config.connection.database, {
69
+ include: config.include,
70
+ exclude: config.exclude,
71
+ });
72
+ console.log(`Found ${tables.length} tables`);
73
+ for (const table of tables) {
74
+ console.log(` ${table.name} (${table.engine}, ${table.columns.length} columns)`);
75
+ }
76
+ const output = generate(tables, {
77
+ database: config.connection.database,
78
+ bigints: config.bigints,
79
+ });
80
+ const outPath = resolve(config.output);
81
+ writeFileSync(outPath, output, 'utf-8');
82
+ console.log(`\nWrote ${tables.length} table types to ${outPath}`);
83
+ }
84
+ finally {
85
+ await client.close();
86
+ }
87
+ },
88
+ });
89
+ const main = defineCommand({
90
+ meta: {
91
+ name: 'chtype',
92
+ version: '0.1.0',
93
+ description: 'Type-safe ClickHouse toolkit for TypeScript',
94
+ },
95
+ subCommands: {
96
+ generate: generateCommand,
97
+ },
98
+ });
99
+ runMain(main);
100
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/codegen/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Configuration for chtype codegen.
3
+ */
4
+ import { z } from 'zod';
5
+ export declare const ChtypeConfigSchema: z.ZodObject<{
6
+ connection: z.ZodObject<{
7
+ host: z.ZodDefault<z.ZodString>;
8
+ database: z.ZodString;
9
+ username: z.ZodDefault<z.ZodString>;
10
+ password: z.ZodDefault<z.ZodString>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ host: string;
13
+ database: string;
14
+ username: string;
15
+ password: string;
16
+ }, {
17
+ database: string;
18
+ host?: string | undefined;
19
+ username?: string | undefined;
20
+ password?: string | undefined;
21
+ }>;
22
+ output: z.ZodDefault<z.ZodString>;
23
+ bigints: z.ZodDefault<z.ZodBoolean>;
24
+ include: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
25
+ exclude: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
26
+ }, "strip", z.ZodTypeAny, {
27
+ connection: {
28
+ host: string;
29
+ database: string;
30
+ username: string;
31
+ password: string;
32
+ };
33
+ output: string;
34
+ bigints: boolean;
35
+ include: string[];
36
+ exclude: string[];
37
+ }, {
38
+ connection: {
39
+ database: string;
40
+ host?: string | undefined;
41
+ username?: string | undefined;
42
+ password?: string | undefined;
43
+ };
44
+ output?: string | undefined;
45
+ bigints?: boolean | undefined;
46
+ include?: string[] | undefined;
47
+ exclude?: string[] | undefined;
48
+ }>;
49
+ export type ChtypeConfig = z.infer<typeof ChtypeConfigSchema>;
50
+ /**
51
+ * Helper for defining a typed config file.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * // chtype.config.ts
56
+ * import { defineConfig } from 'chtype/codegen';
57
+ *
58
+ * export default defineConfig({
59
+ * connection: {
60
+ * host: 'http://localhost:8123',
61
+ * database: 'my_db',
62
+ * },
63
+ * output: './src/generated/schema.ts',
64
+ * });
65
+ * ```
66
+ */
67
+ export declare function defineConfig(config: z.input<typeof ChtypeConfigSchema>): ChtypeConfig;
68
+ /**
69
+ * Load config from a file path. Uses dynamic import to support .ts files
70
+ * (requires Bun, tsx, or similar TypeScript-aware runtime).
71
+ */
72
+ export declare function loadConfigFile(configPath: string): Promise<ChtypeConfig | null>;
73
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/codegen/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,GAAG,YAAY,CAErF;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAUrF"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Configuration for chtype codegen.
3
+ */
4
+ import { z } from 'zod';
5
+ export const ChtypeConfigSchema = z.object({
6
+ connection: z.object({
7
+ host: z.string().url().default('http://localhost:8123'),
8
+ database: z.string().min(1),
9
+ username: z.string().default('default'),
10
+ password: z.string().default(''),
11
+ }),
12
+ output: z.string().default('./chtype.generated.ts'),
13
+ bigints: z.boolean().default(false),
14
+ include: z.array(z.string()).default([]),
15
+ exclude: z.array(z.string()).default([]),
16
+ });
17
+ /**
18
+ * Helper for defining a typed config file.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // chtype.config.ts
23
+ * import { defineConfig } from 'chtype/codegen';
24
+ *
25
+ * export default defineConfig({
26
+ * connection: {
27
+ * host: 'http://localhost:8123',
28
+ * database: 'my_db',
29
+ * },
30
+ * output: './src/generated/schema.ts',
31
+ * });
32
+ * ```
33
+ */
34
+ export function defineConfig(config) {
35
+ return ChtypeConfigSchema.parse(config);
36
+ }
37
+ /**
38
+ * Load config from a file path. Uses dynamic import to support .ts files
39
+ * (requires Bun, tsx, or similar TypeScript-aware runtime).
40
+ */
41
+ export async function loadConfigFile(configPath) {
42
+ try {
43
+ const mod = await import(configPath);
44
+ const raw = mod.default ?? mod;
45
+ return ChtypeConfigSchema.parse(raw);
46
+ }
47
+ catch (err) {
48
+ const message = err instanceof Error ? err.message : String(err);
49
+ console.error(`Failed to load config from ${configPath}: ${message}`);
50
+ return null;
51
+ }
52
+ }
53
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/codegen/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;QACvD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;QACvC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;KACjC,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;IACnD,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACzC,CAAC,CAAC;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,YAAY,CAAC,MAA0C;IACrE,OAAO,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAkB;IACrD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC;QAC/B,OAAO,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,8BAA8B,UAAU,KAAK,OAAO,EAAE,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * TypeScript code generator.
3
+ *
4
+ * Takes introspected table metadata and generates:
5
+ * - Per-table Row interfaces (for SELECT results)
6
+ * - Per-table Insert interfaces (DEFAULT fields optional, MATERIALIZED/ALIAS excluded)
7
+ * - A Database registry type mapping table names to their types + engine metadata
8
+ */
9
+ import type { IntrospectedTable } from './introspect.js';
10
+ import { type TypeMapperOptions } from './type-mapper.js';
11
+ export interface GeneratorOptions extends TypeMapperOptions {
12
+ database: string;
13
+ command?: string;
14
+ }
15
+ export declare function generate(tables: IntrospectedTable[], options: GeneratorOptions): string;
16
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/codegen/generator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EAAE,KAAK,iBAAiB,EAAqB,MAAM,kBAAkB,CAAC;AAE7E,MAAM,WAAW,gBAAiB,SAAQ,iBAAiB;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA+ED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAqBvF"}