@hypequery/cli 0.0.0-canary-20260306132943

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 (63) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +199 -0
  3. package/dist/bin/cli.d.ts +3 -0
  4. package/dist/bin/cli.d.ts.map +1 -0
  5. package/dist/bin/cli.js +86 -0
  6. package/dist/cli.d.ts +4 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +163 -0
  9. package/dist/commands/dev.d.ts +12 -0
  10. package/dist/commands/dev.d.ts.map +1 -0
  11. package/dist/commands/dev.js +265 -0
  12. package/dist/commands/generate.d.ts +8 -0
  13. package/dist/commands/generate.d.ts.map +1 -0
  14. package/dist/commands/generate.js +175 -0
  15. package/dist/commands/init.d.ts +10 -0
  16. package/dist/commands/init.d.ts.map +1 -0
  17. package/dist/commands/init.js +408 -0
  18. package/dist/generators/clickhouse.d.ts +7 -0
  19. package/dist/generators/clickhouse.d.ts.map +1 -0
  20. package/dist/generators/clickhouse.js +229 -0
  21. package/dist/generators/index.d.ts +7 -0
  22. package/dist/generators/index.d.ts.map +1 -0
  23. package/dist/generators/index.js +13 -0
  24. package/dist/templates/client.d.ts +5 -0
  25. package/dist/templates/client.d.ts.map +1 -0
  26. package/dist/templates/client.js +6 -0
  27. package/dist/templates/env.d.ts +14 -0
  28. package/dist/templates/env.d.ts.map +1 -0
  29. package/dist/templates/env.js +37 -0
  30. package/dist/templates/gitignore.d.ts +13 -0
  31. package/dist/templates/gitignore.d.ts.map +1 -0
  32. package/dist/templates/gitignore.js +22 -0
  33. package/dist/templates/queries.d.ts +8 -0
  34. package/dist/templates/queries.d.ts.map +1 -0
  35. package/dist/templates/queries.js +27 -0
  36. package/dist/test-utils.d.ts +86 -0
  37. package/dist/test-utils.d.ts.map +1 -0
  38. package/dist/test-utils.js +153 -0
  39. package/dist/utils/clickhouse-client.d.ts +11 -0
  40. package/dist/utils/clickhouse-client.d.ts.map +1 -0
  41. package/dist/utils/clickhouse-client.js +86 -0
  42. package/dist/utils/dependency-installer.d.ts +2 -0
  43. package/dist/utils/dependency-installer.d.ts.map +1 -0
  44. package/dist/utils/dependency-installer.js +180 -0
  45. package/dist/utils/detect-database.d.ts +21 -0
  46. package/dist/utils/detect-database.d.ts.map +1 -0
  47. package/dist/utils/detect-database.js +224 -0
  48. package/dist/utils/error-messages.d.ts +6 -0
  49. package/dist/utils/error-messages.d.ts.map +1 -0
  50. package/dist/utils/error-messages.js +19 -0
  51. package/dist/utils/find-files.d.ts +21 -0
  52. package/dist/utils/find-files.d.ts.map +1 -0
  53. package/dist/utils/find-files.js +183 -0
  54. package/dist/utils/load-api.d.ts +2 -0
  55. package/dist/utils/load-api.d.ts.map +1 -0
  56. package/dist/utils/load-api.js +400 -0
  57. package/dist/utils/logger.d.ts +54 -0
  58. package/dist/utils/logger.d.ts.map +1 -0
  59. package/dist/utils/logger.js +122 -0
  60. package/dist/utils/prompts.d.ts +39 -0
  61. package/dist/utils/prompts.d.ts.map +1 -0
  62. package/dist/utils/prompts.js +282 -0
  63. package/package.json +50 -0
@@ -0,0 +1,408 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import { mkdir, writeFile, readFile, access } from 'node:fs/promises';
38
+ import path from 'node:path';
39
+ import ora from 'ora';
40
+ import { logger } from '../utils/logger.js';
41
+ import { promptDatabaseType, promptClickHouseConnection, promptOutputDirectory, promptGenerateExample, promptTableSelection, confirmOverwrite, promptRetry, promptContinueWithoutDb, } from '../utils/prompts.js';
42
+ import { validateConnection, getTableCount, getTables, } from '../utils/detect-database.js';
43
+ import { hasEnvFile, hasGitignore } from '../utils/find-files.js';
44
+ import { generateEnvTemplate, appendToEnv } from '../templates/env.js';
45
+ import { generateClientTemplate } from '../templates/client.js';
46
+ import { generateQueriesTemplate } from '../templates/queries.js';
47
+ import { appendToGitignore } from '../templates/gitignore.js';
48
+ import { getTypeGenerator } from '../generators/index.js';
49
+ import { installServeDependencies } from '../utils/dependency-installer.js';
50
+ function determineDatabase(options) {
51
+ return __awaiter(this, void 0, void 0, function () {
52
+ var dbType, _a;
53
+ var _b;
54
+ return __generator(this, function (_c) {
55
+ switch (_c.label) {
56
+ case 0:
57
+ if (!((_b = options.database) !== null && _b !== void 0)) return [3 /*break*/, 1];
58
+ _a = _b;
59
+ return [3 /*break*/, 3];
60
+ case 1: return [4 /*yield*/, promptDatabaseType()];
61
+ case 2:
62
+ _a = (_c.sent());
63
+ _c.label = 3;
64
+ case 3:
65
+ dbType = _a;
66
+ if (!dbType) {
67
+ logger.info('Setup cancelled');
68
+ process.exit(0);
69
+ }
70
+ if (dbType !== 'clickhouse') {
71
+ logger.error("".concat(dbType, " is not yet supported. Only ClickHouse is available."));
72
+ process.exit(1);
73
+ }
74
+ return [2 /*return*/, dbType];
75
+ }
76
+ });
77
+ });
78
+ }
79
+ function resolveConnectionConfig(options) {
80
+ return __awaiter(this, void 0, void 0, function () {
81
+ var required;
82
+ var _a;
83
+ return __generator(this, function (_b) {
84
+ if (options.noInteractive) {
85
+ required = function (key) {
86
+ var value = process.env[key];
87
+ if (!value) {
88
+ throw new Error("Missing ".concat(key, ". Provide ClickHouse connection info via environment variables when using --no-interactive."));
89
+ }
90
+ return value;
91
+ };
92
+ return [2 /*return*/, {
93
+ host: required('CLICKHOUSE_HOST'),
94
+ database: required('CLICKHOUSE_DATABASE'),
95
+ username: required('CLICKHOUSE_USERNAME'),
96
+ password: (_a = process.env.CLICKHOUSE_PASSWORD) !== null && _a !== void 0 ? _a : '',
97
+ }];
98
+ }
99
+ return [2 /*return*/, promptClickHouseConnection()];
100
+ });
101
+ });
102
+ }
103
+ function testConnection(connectionConfig, dbType) {
104
+ return __awaiter(this, void 0, void 0, function () {
105
+ var spinner, isValid, tableCount;
106
+ return __generator(this, function (_a) {
107
+ switch (_a.label) {
108
+ case 0:
109
+ spinner = ora('Testing connection...').start();
110
+ process.env.CLICKHOUSE_HOST = connectionConfig.host;
111
+ process.env.CLICKHOUSE_DATABASE = connectionConfig.database;
112
+ process.env.CLICKHOUSE_USERNAME = connectionConfig.username;
113
+ process.env.CLICKHOUSE_PASSWORD = connectionConfig.password;
114
+ return [4 /*yield*/, validateConnection(dbType)];
115
+ case 1:
116
+ isValid = _a.sent();
117
+ if (!isValid) {
118
+ spinner.fail('Connection failed');
119
+ logger.newline();
120
+ logger.error("Could not connect to ClickHouse at ".concat(connectionConfig.host));
121
+ logger.newline();
122
+ logger.info('Common issues:');
123
+ logger.indent('• Check your host URL includes http:// or https://');
124
+ logger.indent('• Verify username and password');
125
+ logger.indent('• Ensure database exists');
126
+ logger.indent('• Check firewall/network access');
127
+ logger.newline();
128
+ return [2 /*return*/, { hasValidConnection: false, tableCount: 0 }];
129
+ }
130
+ return [4 /*yield*/, getTableCount(dbType)];
131
+ case 2:
132
+ tableCount = _a.sent();
133
+ spinner.succeed("Connected successfully (".concat(tableCount, " tables found)"));
134
+ logger.newline();
135
+ return [2 /*return*/, { hasValidConnection: true, tableCount: tableCount }];
136
+ }
137
+ });
138
+ });
139
+ }
140
+ export function initCommand() {
141
+ return __awaiter(this, arguments, void 0, function (options) {
142
+ var dbType, connectionConfig, hasValidConnection, tableCount, _a, valid, count, retry, continueWithout, outputDir, resolvedOutputDir, filesToCreate, existingFiles, _i, filesToCreate_1, file, _b, shouldOverwrite, generateExample, selectedTable, tables, envPath, envExists, existingEnv, newEnv, envPath, envExists, placeholderConfig, schemaPath, typeSpinner, generator, error_1, clientPath, queriesPath, gitignorePath, gitignoreExists, existingGitignore, newGitignore, exampleQueryKey;
143
+ if (options === void 0) { options = {}; }
144
+ return __generator(this, function (_c) {
145
+ switch (_c.label) {
146
+ case 0:
147
+ logger.newline();
148
+ logger.header('Welcome to hypequery!');
149
+ logger.info("Let's set up your analytics layer.");
150
+ logger.newline();
151
+ return [4 /*yield*/, determineDatabase(options)];
152
+ case 1:
153
+ dbType = _c.sent();
154
+ return [4 /*yield*/, resolveConnectionConfig(options)];
155
+ case 2:
156
+ connectionConfig = _c.sent();
157
+ hasValidConnection = false;
158
+ tableCount = 0;
159
+ if (!!connectionConfig) return [3 /*break*/, 3];
160
+ logger.info('Skipping database connection for now.');
161
+ logger.newline();
162
+ return [3 /*break*/, 8];
163
+ case 3:
164
+ if (!options.skipConnection) return [3 /*break*/, 4];
165
+ logger.info('Skipping database connection test (requested).');
166
+ logger.newline();
167
+ return [3 /*break*/, 8];
168
+ case 4: return [4 /*yield*/, testConnection(connectionConfig, dbType)];
169
+ case 5:
170
+ _a = _c.sent(), valid = _a.hasValidConnection, count = _a.tableCount;
171
+ hasValidConnection = valid;
172
+ tableCount = count;
173
+ if (!!hasValidConnection) return [3 /*break*/, 8];
174
+ return [4 /*yield*/, promptRetry('Try again?')];
175
+ case 6:
176
+ retry = _c.sent();
177
+ if (retry) {
178
+ return [2 /*return*/, initCommand(options)];
179
+ }
180
+ return [4 /*yield*/, promptContinueWithoutDb()];
181
+ case 7:
182
+ continueWithout = _c.sent();
183
+ if (!continueWithout) {
184
+ logger.info('Setup cancelled');
185
+ process.exit(0);
186
+ }
187
+ logger.newline();
188
+ logger.info('Continuing without database connection.');
189
+ logger.info('You can configure the connection later in .env');
190
+ logger.newline();
191
+ connectionConfig = null;
192
+ _c.label = 8;
193
+ case 8:
194
+ outputDir = options.path;
195
+ if (!(!outputDir && !options.noInteractive)) return [3 /*break*/, 10];
196
+ return [4 /*yield*/, promptOutputDirectory()];
197
+ case 9:
198
+ outputDir = _c.sent();
199
+ return [3 /*break*/, 11];
200
+ case 10:
201
+ if (!outputDir) {
202
+ outputDir = 'analytics';
203
+ }
204
+ _c.label = 11;
205
+ case 11:
206
+ resolvedOutputDir = path.resolve(process.cwd(), outputDir);
207
+ filesToCreate = [
208
+ path.join(resolvedOutputDir, 'client.ts'),
209
+ path.join(resolvedOutputDir, 'schema.ts'),
210
+ path.join(resolvedOutputDir, 'queries.ts'),
211
+ ];
212
+ existingFiles = [];
213
+ _i = 0, filesToCreate_1 = filesToCreate;
214
+ _c.label = 12;
215
+ case 12:
216
+ if (!(_i < filesToCreate_1.length)) return [3 /*break*/, 17];
217
+ file = filesToCreate_1[_i];
218
+ _c.label = 13;
219
+ case 13:
220
+ _c.trys.push([13, 15, , 16]);
221
+ return [4 /*yield*/, access(file)];
222
+ case 14:
223
+ _c.sent();
224
+ existingFiles.push(path.relative(process.cwd(), file));
225
+ return [3 /*break*/, 16];
226
+ case 15:
227
+ _b = _c.sent();
228
+ return [3 /*break*/, 16];
229
+ case 16:
230
+ _i++;
231
+ return [3 /*break*/, 12];
232
+ case 17:
233
+ if (!(existingFiles.length > 0 && !options.force)) return [3 /*break*/, 19];
234
+ logger.warn('Files already exist');
235
+ logger.newline();
236
+ return [4 /*yield*/, confirmOverwrite(existingFiles)];
237
+ case 18:
238
+ shouldOverwrite = _c.sent();
239
+ if (!shouldOverwrite) {
240
+ logger.info('Setup cancelled');
241
+ process.exit(0);
242
+ }
243
+ logger.newline();
244
+ _c.label = 19;
245
+ case 19:
246
+ generateExample = !options.noExample && hasValidConnection;
247
+ selectedTable = null;
248
+ if (!(generateExample && !options.noInteractive && hasValidConnection)) return [3 /*break*/, 23];
249
+ return [4 /*yield*/, promptGenerateExample()];
250
+ case 20:
251
+ generateExample = _c.sent();
252
+ if (!generateExample) return [3 /*break*/, 23];
253
+ return [4 /*yield*/, getTables(dbType)];
254
+ case 21:
255
+ tables = _c.sent();
256
+ return [4 /*yield*/, promptTableSelection(tables)];
257
+ case 22:
258
+ selectedTable = _c.sent();
259
+ generateExample = selectedTable !== null;
260
+ _c.label = 23;
261
+ case 23:
262
+ logger.newline();
263
+ // Step 7: Create directory
264
+ return [4 /*yield*/, mkdir(resolvedOutputDir, { recursive: true })];
265
+ case 24:
266
+ // Step 7: Create directory
267
+ _c.sent();
268
+ if (!connectionConfig) return [3 /*break*/, 31];
269
+ envPath = path.join(process.cwd(), '.env');
270
+ return [4 /*yield*/, hasEnvFile()];
271
+ case 25:
272
+ envExists = _c.sent();
273
+ if (!envExists) return [3 /*break*/, 28];
274
+ return [4 /*yield*/, readFile(envPath, 'utf-8')];
275
+ case 26:
276
+ existingEnv = _c.sent();
277
+ newEnv = appendToEnv(existingEnv, generateEnvTemplate(connectionConfig));
278
+ return [4 /*yield*/, writeFile(envPath, newEnv)];
279
+ case 27:
280
+ _c.sent();
281
+ logger.success('Updated .env');
282
+ return [3 /*break*/, 30];
283
+ case 28: return [4 /*yield*/, writeFile(envPath, generateEnvTemplate(connectionConfig))];
284
+ case 29:
285
+ _c.sent();
286
+ logger.success('Created .env');
287
+ _c.label = 30;
288
+ case 30: return [3 /*break*/, 34];
289
+ case 31:
290
+ envPath = path.join(process.cwd(), '.env');
291
+ return [4 /*yield*/, hasEnvFile()];
292
+ case 32:
293
+ envExists = _c.sent();
294
+ placeholderConfig = {
295
+ host: 'YOUR_CLICKHOUSE_HOST',
296
+ database: 'YOUR_DATABASE',
297
+ username: 'YOUR_USERNAME',
298
+ password: 'YOUR_PASSWORD',
299
+ };
300
+ if (!!envExists) return [3 /*break*/, 34];
301
+ return [4 /*yield*/, writeFile(envPath, generateEnvTemplate(placeholderConfig))];
302
+ case 33:
303
+ _c.sent();
304
+ logger.success('Created .env (configure your credentials)');
305
+ _c.label = 34;
306
+ case 34:
307
+ schemaPath = path.join(resolvedOutputDir, 'schema.ts');
308
+ if (!hasValidConnection) return [3 /*break*/, 39];
309
+ typeSpinner = ora('Generating TypeScript types...').start();
310
+ _c.label = 35;
311
+ case 35:
312
+ _c.trys.push([35, 37, , 38]);
313
+ generator = getTypeGenerator('clickhouse');
314
+ return [4 /*yield*/, generator({ outputPath: schemaPath })];
315
+ case 36:
316
+ _c.sent();
317
+ typeSpinner.succeed("Generated TypeScript types (".concat(path.relative(process.cwd(), schemaPath), ")"));
318
+ return [3 /*break*/, 38];
319
+ case 37:
320
+ error_1 = _c.sent();
321
+ typeSpinner.fail('Failed to generate types');
322
+ logger.error(error_1 instanceof Error ? error_1.message : String(error_1));
323
+ process.exit(1);
324
+ return [3 /*break*/, 38];
325
+ case 38: return [3 /*break*/, 41];
326
+ case 39:
327
+ // Create placeholder schema file
328
+ return [4 /*yield*/, writeFile(schemaPath, "// Generated by hypequery\n// Run 'npx hypequery generate' after configuring your database connection\n\nexport interface IntrospectedSchema {\n // Your table types will appear here after generation\n}\n")];
329
+ case 40:
330
+ // Create placeholder schema file
331
+ _c.sent();
332
+ logger.success("Created placeholder schema (".concat(path.relative(process.cwd(), schemaPath), ")"));
333
+ _c.label = 41;
334
+ case 41:
335
+ clientPath = path.join(resolvedOutputDir, 'client.ts');
336
+ return [4 /*yield*/, writeFile(clientPath, generateClientTemplate())];
337
+ case 42:
338
+ _c.sent();
339
+ logger.success("Created ClickHouse client (".concat(path.relative(process.cwd(), clientPath), ")"));
340
+ queriesPath = path.join(resolvedOutputDir, 'queries.ts');
341
+ return [4 /*yield*/, writeFile(queriesPath, generateQueriesTemplate({
342
+ hasExample: generateExample,
343
+ tableName: selectedTable || undefined,
344
+ }))];
345
+ case 43:
346
+ _c.sent();
347
+ logger.success("Created queries file (".concat(path.relative(process.cwd(), queriesPath), ")"));
348
+ if (generateExample && selectedTable) {
349
+ logger.success("Created example query using '".concat(selectedTable, "' table"));
350
+ }
351
+ gitignorePath = path.join(process.cwd(), '.gitignore');
352
+ return [4 /*yield*/, hasGitignore()];
353
+ case 44:
354
+ gitignoreExists = _c.sent();
355
+ if (!gitignoreExists) return [3 /*break*/, 48];
356
+ return [4 /*yield*/, readFile(gitignorePath, 'utf-8')];
357
+ case 45:
358
+ existingGitignore = _c.sent();
359
+ newGitignore = appendToGitignore(existingGitignore);
360
+ if (!(newGitignore !== existingGitignore)) return [3 /*break*/, 47];
361
+ return [4 /*yield*/, writeFile(gitignorePath, newGitignore)];
362
+ case 46:
363
+ _c.sent();
364
+ logger.success('Updated .gitignore');
365
+ _c.label = 47;
366
+ case 47: return [3 /*break*/, 50];
367
+ case 48: return [4 /*yield*/, writeFile(gitignorePath, appendToGitignore(''))];
368
+ case 49:
369
+ _c.sent();
370
+ logger.success('Created .gitignore');
371
+ _c.label = 50;
372
+ case 50:
373
+ // Step 13: Ensure required hypequery packages are installed
374
+ return [4 /*yield*/, installServeDependencies()];
375
+ case 51:
376
+ // Step 13: Ensure required hypequery packages are installed
377
+ _c.sent();
378
+ // Step 14: Success message
379
+ logger.newline();
380
+ logger.header('Setup complete!');
381
+ if (hasValidConnection) {
382
+ logger.info('Try your first query:');
383
+ logger.newline();
384
+ logger.indent("import { api } from './".concat(path.relative(process.cwd(), queriesPath).replace(/\.ts$/, '.js'), "'"));
385
+ exampleQueryKey = generateExample && selectedTable
386
+ ? "".concat(selectedTable.replace(/_([a-z])/g, function (_, l) { return l.toUpperCase(); }), "Query")
387
+ : 'exampleMetric';
388
+ logger.indent("const result = await api.execute('".concat(exampleQueryKey, "')"));
389
+ logger.newline();
390
+ logger.info('Next:');
391
+ logger.indent('npx hypequery dev Start development server');
392
+ logger.newline();
393
+ }
394
+ else {
395
+ logger.info('Next steps:');
396
+ logger.newline();
397
+ logger.indent('1. Configure your database connection in .env');
398
+ logger.indent('2. Run: npx hypequery generate (to generate types)');
399
+ logger.indent('3. Run: npx hypequery dev (to start dev server)');
400
+ logger.newline();
401
+ }
402
+ logger.info('Docs: https://hypequery.com/docs');
403
+ logger.newline();
404
+ return [2 /*return*/];
405
+ }
406
+ });
407
+ });
408
+ }
@@ -0,0 +1,7 @@
1
+ export interface ClickHouseGeneratorOptions {
2
+ outputPath: string;
3
+ includeTables?: string[];
4
+ excludeTables?: string[];
5
+ }
6
+ export declare function generateClickHouseTypes(options: ClickHouseGeneratorOptions): Promise<void>;
7
+ //# sourceMappingURL=clickhouse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clickhouse.d.ts","sourceRoot":"","sources":["../../src/generators/clickhouse.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AA4HD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,0BAA0B,iBA0ChF"}
@@ -0,0 +1,229 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import fs from 'node:fs/promises';
38
+ import path from 'node:path';
39
+ import { getClickHouseClient } from '../utils/clickhouse-client.js';
40
+ var DEFAULT_WARNING = 'Warning: No tables match the filter criteria. Check your include/exclude options.';
41
+ var capitalizeFirstLetter = function (value) { return value.charAt(0).toUpperCase() + value.slice(1); };
42
+ var clickhouseToTsType = function (type) {
43
+ if (type.startsWith('Array(')) {
44
+ var innerType = type.slice(6, -1);
45
+ return "Array<".concat(clickhouseToTsType(innerType), ">");
46
+ }
47
+ if (type.startsWith('Nullable(')) {
48
+ var innerType = type.slice(9, -1);
49
+ return "".concat(clickhouseToTsType(innerType), " | null");
50
+ }
51
+ if (type.startsWith('Map(')) {
52
+ var mapContent = type.slice(4, -1);
53
+ var commaIndex = mapContent.lastIndexOf(',');
54
+ if (commaIndex !== -1) {
55
+ var keyType = mapContent.substring(0, commaIndex).trim();
56
+ var valueType = mapContent.substring(commaIndex + 1).trim();
57
+ var keyTsType = 'string';
58
+ if (keyType === 'LowCardinality(String)') {
59
+ keyTsType = 'string';
60
+ }
61
+ else if (keyType.includes('Int') || keyType.includes('UInt')) {
62
+ keyTsType = 'number';
63
+ }
64
+ var valueTsType = 'unknown';
65
+ if (valueType.startsWith('Array(')) {
66
+ var innerType = valueType.slice(6, -1);
67
+ valueTsType = "Array<".concat(clickhouseToTsType(innerType), ">");
68
+ }
69
+ else if (valueType.startsWith('Nullable(')) {
70
+ var innerType = valueType.slice(9, -1);
71
+ valueTsType = "".concat(clickhouseToTsType(innerType), " | null");
72
+ }
73
+ else {
74
+ valueTsType = clickhouseToTsType(valueType);
75
+ }
76
+ return "Record<".concat(keyTsType, ", ").concat(valueTsType, ">");
77
+ }
78
+ return 'Record<string, unknown>';
79
+ }
80
+ switch (type.toLowerCase()) {
81
+ case 'string':
82
+ case 'fixedstring':
83
+ return 'string';
84
+ case 'int8':
85
+ case 'int16':
86
+ case 'int32':
87
+ case 'uint8':
88
+ case 'int64':
89
+ case 'uint16':
90
+ case 'uint32':
91
+ case 'uint64':
92
+ return 'number';
93
+ case 'uint128':
94
+ case 'uint256':
95
+ case 'int128':
96
+ case 'int256':
97
+ return 'string';
98
+ case 'float32':
99
+ case 'float64':
100
+ case 'decimal':
101
+ return 'number';
102
+ case 'datetime':
103
+ case 'datetime64':
104
+ case 'date':
105
+ case 'date32':
106
+ return 'string';
107
+ case 'bool':
108
+ case 'boolean':
109
+ return 'boolean';
110
+ default:
111
+ return 'string';
112
+ }
113
+ };
114
+ function fetchTables(includeTables, excludeTables) {
115
+ return __awaiter(this, void 0, void 0, function () {
116
+ var client, tablesQuery, tables;
117
+ return __generator(this, function (_a) {
118
+ switch (_a.label) {
119
+ case 0:
120
+ client = getClickHouseClient();
121
+ return [4 /*yield*/, client.query({
122
+ query: 'SHOW TABLES',
123
+ format: 'JSONEachRow',
124
+ })];
125
+ case 1:
126
+ tablesQuery = _a.sent();
127
+ return [4 /*yield*/, tablesQuery.json()];
128
+ case 2:
129
+ tables = (_a.sent());
130
+ if (includeTables === null || includeTables === void 0 ? void 0 : includeTables.length) {
131
+ tables = tables.filter(function (table) { return includeTables.includes(table.name); });
132
+ }
133
+ if (excludeTables === null || excludeTables === void 0 ? void 0 : excludeTables.length) {
134
+ tables = tables.filter(function (table) { return !excludeTables.includes(table.name); });
135
+ }
136
+ return [2 /*return*/, tables];
137
+ }
138
+ });
139
+ });
140
+ }
141
+ function fetchColumns(table) {
142
+ return __awaiter(this, void 0, void 0, function () {
143
+ var client, columnsQuery;
144
+ return __generator(this, function (_a) {
145
+ switch (_a.label) {
146
+ case 0:
147
+ client = getClickHouseClient();
148
+ return [4 /*yield*/, client.query({
149
+ query: "DESCRIBE TABLE ".concat(table),
150
+ format: 'JSONEachRow',
151
+ })];
152
+ case 1:
153
+ columnsQuery = _a.sent();
154
+ return [4 /*yield*/, columnsQuery.json()];
155
+ case 2: return [2 /*return*/, (_a.sent())];
156
+ }
157
+ });
158
+ });
159
+ }
160
+ export function generateClickHouseTypes(options) {
161
+ return __awaiter(this, void 0, void 0, function () {
162
+ var outputPath, includeTables, excludeTables, tables, typeDefinitions, _i, tables_1, table, columns, _a, columns_1, column, clickHouseType, _b, tables_2, table, columns, _c, columns_2, column, tsType, outputDir;
163
+ return __generator(this, function (_d) {
164
+ switch (_d.label) {
165
+ case 0:
166
+ outputPath = options.outputPath, includeTables = options.includeTables, excludeTables = options.excludeTables;
167
+ return [4 /*yield*/, fetchTables(includeTables, excludeTables)];
168
+ case 1:
169
+ tables = _d.sent();
170
+ if (tables.length === 0) {
171
+ console.warn(DEFAULT_WARNING);
172
+ }
173
+ typeDefinitions = "// Generated by hypequery\n" +
174
+ "// This file defines TypeScript types based on your ClickHouse database schema\n\n" +
175
+ "export interface IntrospectedSchema {";
176
+ _i = 0, tables_1 = tables;
177
+ _d.label = 2;
178
+ case 2:
179
+ if (!(_i < tables_1.length)) return [3 /*break*/, 5];
180
+ table = tables_1[_i];
181
+ return [4 /*yield*/, fetchColumns(table.name)];
182
+ case 3:
183
+ columns = _d.sent();
184
+ typeDefinitions += "\n ".concat(table.name, ": {");
185
+ for (_a = 0, columns_1 = columns; _a < columns_1.length; _a++) {
186
+ column = columns_1[_a];
187
+ clickHouseType = column.type.replace(/'/g, "\\'");
188
+ typeDefinitions += "\n '".concat(column.name, "': '").concat(clickHouseType, "';");
189
+ }
190
+ typeDefinitions += '\n };';
191
+ _d.label = 4;
192
+ case 4:
193
+ _i++;
194
+ return [3 /*break*/, 2];
195
+ case 5:
196
+ typeDefinitions += '\n}\n';
197
+ typeDefinitions += "\n// Type-safe record types for each table\n";
198
+ _b = 0, tables_2 = tables;
199
+ _d.label = 6;
200
+ case 6:
201
+ if (!(_b < tables_2.length)) return [3 /*break*/, 9];
202
+ table = tables_2[_b];
203
+ return [4 /*yield*/, fetchColumns(table.name)];
204
+ case 7:
205
+ columns = _d.sent();
206
+ typeDefinitions += "export interface ".concat(capitalizeFirstLetter(table.name), "Record {");
207
+ for (_c = 0, columns_2 = columns; _c < columns_2.length; _c++) {
208
+ column = columns_2[_c];
209
+ tsType = clickhouseToTsType(column.type).replace(/'/g, '');
210
+ typeDefinitions += "\n '".concat(column.name, "': ").concat(tsType, ";");
211
+ }
212
+ typeDefinitions += '\n}\n\n';
213
+ _d.label = 8;
214
+ case 8:
215
+ _b++;
216
+ return [3 /*break*/, 6];
217
+ case 9:
218
+ outputDir = path.dirname(path.resolve(outputPath));
219
+ return [4 /*yield*/, fs.mkdir(outputDir, { recursive: true })];
220
+ case 10:
221
+ _d.sent();
222
+ return [4 /*yield*/, fs.writeFile(path.resolve(outputPath), typeDefinitions)];
223
+ case 11:
224
+ _d.sent();
225
+ return [2 /*return*/];
226
+ }
227
+ });
228
+ });
229
+ }
@@ -0,0 +1,7 @@
1
+ import type { DatabaseType } from '../utils/detect-database.js';
2
+ import { type ClickHouseGeneratorOptions } from './clickhouse.js';
3
+ export type TypeGeneratorOptions = ClickHouseGeneratorOptions;
4
+ type GeneratorFn = (options: TypeGeneratorOptions) => Promise<void>;
5
+ export declare function getTypeGenerator(dbType: DatabaseType): GeneratorFn;
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAA2B,KAAK,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE3F,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAE9D,KAAK,WAAW,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAMpE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAYlE"}