@hypequery/cli 0.0.9 → 1.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.
- package/README.md +15 -3
- package/dist/templates/queries.d.ts.map +1 -1
- package/dist/templates/queries.js +4 -4
- package/dist/test-utils.d.ts.map +1 -1
- package/dist/test-utils.js +0 -1
- package/dist/utils/load-api.d.ts.map +1 -1
- package/dist/utils/load-api.js +38 -26
- package/dist/utils/prompts.d.ts.map +1 -1
- package/dist/utils/prompts.js +2 -1
- package/package.json +12 -4
package/README.md
CHANGED
|
@@ -4,7 +4,14 @@ Command-line interface for Hypequery - the type-safe analytics layer for ClickHo
|
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The CLI scaffolds and runs the main hypequery path:
|
|
8
|
+
|
|
9
|
+
1. Generate schema types from ClickHouse
|
|
10
|
+
2. Build queries with the typed query builder
|
|
11
|
+
3. Wrap reusable queries with `query({ ... })`
|
|
12
|
+
4. Add `serve({ queries })` when you want HTTP routes and docs
|
|
13
|
+
|
|
14
|
+
Use `npx` to run commands directly:
|
|
8
15
|
|
|
9
16
|
```bash
|
|
10
17
|
# Initialize a new project
|
|
@@ -68,7 +75,7 @@ npx hypequery init
|
|
|
68
75
|
**What it does:**
|
|
69
76
|
- Connects to your ClickHouse database
|
|
70
77
|
- Generates TypeScript types from your schema
|
|
71
|
-
- Creates client,
|
|
78
|
+
- Creates the client, query, and serve files for the main path
|
|
72
79
|
- Sets up `.env` with connection details
|
|
73
80
|
- Updates `.gitignore` to protect secrets
|
|
74
81
|
|
|
@@ -192,7 +199,12 @@ npm run db:dev
|
|
|
192
199
|
|
|
193
200
|
## Documentation
|
|
194
201
|
|
|
195
|
-
Visit
|
|
202
|
+
Visit the main docs flow:
|
|
203
|
+
|
|
204
|
+
- [Quick Start](https://hypequery.com/docs/quick-start)
|
|
205
|
+
- [Core Concepts](https://hypequery.com/docs/core-concepts)
|
|
206
|
+
- [Query Building](https://hypequery.com/docs/query-building/basics)
|
|
207
|
+
- [Serve Runtime Reference](https://hypequery.com/docs/reference/runtime)
|
|
196
208
|
|
|
197
209
|
## License
|
|
198
210
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/templates/queries.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/templates/queries.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC/C,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CA+DT"}
|
|
@@ -5,14 +5,14 @@ export function generateQueriesTemplate(options) {
|
|
|
5
5
|
var hasExample = options.hasExample, tableName = options.tableName;
|
|
6
6
|
var metricKey = hasExample && tableName ? "".concat(camelCase(tableName), "Query") : 'exampleMetric';
|
|
7
7
|
var typeAlias = "".concat(pascalCase(metricKey), "Result");
|
|
8
|
-
var template = "import { initServe } from '@hypequery/serve';\nimport type { InferApiType } from '@hypequery/serve';\nimport { z } from 'zod';\nimport { db } from './client';\n\nconst serve = initServe({\n context: () => ({ db }),\n});\
|
|
8
|
+
var template = "import { initServe } from '@hypequery/serve';\nimport type { InferApiType } from '@hypequery/serve';\nimport { z } from 'zod';\nimport { db } from './client';\n\nconst { query, serve } = initServe({\n context: () => ({ db }),\n});\n\n";
|
|
9
9
|
if (hasExample && tableName) {
|
|
10
|
-
template += "\
|
|
10
|
+
template += "\nconst ".concat(camelCase(tableName), "Query = query({\n description: 'Example query using the ").concat(tableName, " table',\n query: async ({ ctx }) =>\n ctx.db\n .table('").concat(tableName, "')\n .select('*')\n .limit(10)\n .execute(),\n});");
|
|
11
11
|
}
|
|
12
12
|
else {
|
|
13
|
-
template += "\
|
|
13
|
+
template += "\nconst exampleMetric = query({\n description: 'Example metric that returns a simple value',\n output: z.object({ ok: z.boolean() }),\n query: async () => ({ ok: true }),\n});";
|
|
14
14
|
}
|
|
15
|
-
template += "\n }
|
|
15
|
+
template += "\nexport const api = serve({\n queries: {\n ".concat(metricKey, ",\n },\n});\n\nexport type ApiDefinition = InferApiType<typeof api>;\n\n/**\n * Inline usage example:\n *\n * const result = await api.execute('").concat(metricKey, "');\n * console.log(result);\n *\n * // import type { InferQueryResult } from '@hypequery/serve';\n * type ").concat(typeAlias, " = InferQueryResult<typeof api, '").concat(metricKey, "'>;\n *\n * // Register HTTP route:\n * api.route('/metrics/").concat(metricKey, "', api.queries.").concat(metricKey, ");\n *\n * Dev server:\n * npx hypequery dev analytics/queries.ts\n */\n");
|
|
16
16
|
return template;
|
|
17
17
|
}
|
|
18
18
|
/**
|
package/dist/test-utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC;;GAEG;AACH,wBAAgB,iBAAiB;;;;;;;;;EAWhC;AAED;;GAEG;AACH,wBAAgB,uBAAuB;;;;EAMtC;AAED;;GAEG;AACH,wBAAgB,mBAAmB;;;;;EAOlC;AAED;;GAEG;AACH,wBAAgB,gBAAgB;;;;;;;;;;;;EAc/B;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;;GAQhC;AAED;;GAEG;AACH,wBAAgB,YAAY;;;;;EAO3B;AAED;;GAEG;AACH,wBAAgB,cAAc;;;;EAuB7B;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACtB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIhC;AAED,wBAAgB,eAAe;;;
|
|
1
|
+
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC;;GAEG;AACH,wBAAgB,iBAAiB;;;;;;;;;EAWhC;AAED;;GAEG;AACH,wBAAgB,uBAAuB;;;;EAMtC;AAED;;GAEG;AACH,wBAAgB,mBAAmB;;;;;EAOlC;AAED;;GAEG;AACH,wBAAgB,gBAAgB;;;;;;;;;;;;EAc/B;AAED;;GAEG;AACH,wBAAgB,iBAAiB;;;;;GAQhC;AAED;;GAEG;AACH,wBAAgB,YAAY;;;;;EAO3B;AAED;;GAEG;AACH,wBAAgB,cAAc;;;;EAuB7B;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACtB,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIhC;AAED,wBAAgB,eAAe;;;EAc9B"}
|
package/dist/test-utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-api.d.ts","sourceRoot":"","sources":["../../src/utils/load-api.ts"],"names":[],"mappings":"AAaA,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"load-api.d.ts","sourceRoot":"","sources":["../../src/utils/load-api.ts"],"names":[],"mappings":"AAaA,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,gBA0ErD"}
|
package/dist/utils/load-api.js
CHANGED
|
@@ -36,7 +36,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
36
36
|
};
|
|
37
37
|
var _a, _b, _c, _d;
|
|
38
38
|
import { pathToFileURL } from 'node:url';
|
|
39
|
-
import { access, mkdtemp,
|
|
39
|
+
import { access, mkdtemp, rm, mkdir, writeFile } from 'node:fs/promises';
|
|
40
40
|
import os from 'node:os';
|
|
41
41
|
import path from 'node:path';
|
|
42
42
|
import { build } from 'esbuild';
|
|
@@ -47,21 +47,21 @@ var TYPESCRIPT_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts']);
|
|
|
47
47
|
var tsconfigCache = new Map();
|
|
48
48
|
export function loadApiModule(modulePath) {
|
|
49
49
|
return __awaiter(this, void 0, void 0, function () {
|
|
50
|
-
var resolved, _a, relativePath, extension, isTypeScript, moduleUrl, _b, mod, error_1, relativePath, api, relativePath, availableExports;
|
|
51
|
-
var
|
|
52
|
-
return __generator(this, function (
|
|
53
|
-
switch (
|
|
50
|
+
var resolved, _a, relativePath, extension, isTypeScript, moduleUrl, _b, mod, importOverride, _c, error_1, relativePath, api, relativePath, availableExports;
|
|
51
|
+
var _d;
|
|
52
|
+
return __generator(this, function (_e) {
|
|
53
|
+
switch (_e.label) {
|
|
54
54
|
case 0:
|
|
55
55
|
resolved = path.resolve(process.cwd(), modulePath);
|
|
56
|
-
|
|
56
|
+
_e.label = 1;
|
|
57
57
|
case 1:
|
|
58
|
-
|
|
58
|
+
_e.trys.push([1, 3, , 4]);
|
|
59
59
|
return [4 /*yield*/, access(resolved)];
|
|
60
60
|
case 2:
|
|
61
|
-
|
|
61
|
+
_e.sent();
|
|
62
62
|
return [3 /*break*/, 4];
|
|
63
63
|
case 3:
|
|
64
|
-
_a =
|
|
64
|
+
_a = _e.sent();
|
|
65
65
|
relativePath = path.relative(process.cwd(), resolved);
|
|
66
66
|
throw new Error("File not found: ".concat(relativePath, "\n\n") +
|
|
67
67
|
"Make sure the file exists and the path is correct.\n" +
|
|
@@ -73,22 +73,31 @@ export function loadApiModule(modulePath) {
|
|
|
73
73
|
if (!isTypeScript) return [3 /*break*/, 6];
|
|
74
74
|
return [4 /*yield*/, bundleTypeScriptModule(resolved)];
|
|
75
75
|
case 5:
|
|
76
|
-
_b =
|
|
76
|
+
_b = _e.sent();
|
|
77
77
|
return [3 /*break*/, 7];
|
|
78
78
|
case 6:
|
|
79
79
|
_b = "".concat(pathToFileURL(resolved).href, "?t=").concat(Date.now());
|
|
80
|
-
|
|
80
|
+
_e.label = 7;
|
|
81
81
|
case 7:
|
|
82
82
|
moduleUrl = _b;
|
|
83
|
-
|
|
83
|
+
_e.label = 8;
|
|
84
84
|
case 8:
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
_e.trys.push([8, 13, , 14]);
|
|
86
|
+
importOverride = globalState.__hypequeryCliImportOverride;
|
|
87
|
+
if (!importOverride) return [3 /*break*/, 10];
|
|
88
|
+
return [4 /*yield*/, importOverride(moduleUrl)];
|
|
87
89
|
case 9:
|
|
88
|
-
|
|
89
|
-
return [3 /*break*/,
|
|
90
|
-
case 10:
|
|
91
|
-
|
|
90
|
+
_c = _e.sent();
|
|
91
|
+
return [3 /*break*/, 12];
|
|
92
|
+
case 10: return [4 /*yield*/, import(/* @vite-ignore */ moduleUrl)];
|
|
93
|
+
case 11:
|
|
94
|
+
_c = _e.sent();
|
|
95
|
+
_e.label = 12;
|
|
96
|
+
case 12:
|
|
97
|
+
mod = _c;
|
|
98
|
+
return [3 /*break*/, 14];
|
|
99
|
+
case 13:
|
|
100
|
+
error_1 = _e.sent();
|
|
92
101
|
relativePath = path.relative(process.cwd(), resolved);
|
|
93
102
|
throw new Error("Failed to load module: ".concat(relativePath, "\n\n") +
|
|
94
103
|
"Error: ".concat(error_1.message, "\n\n") +
|
|
@@ -98,8 +107,8 @@ export function loadApiModule(modulePath) {
|
|
|
98
107
|
" \u2022 An import path is incorrect\n"
|
|
99
108
|
: "") +
|
|
100
109
|
(error_1.stack ? "\nStack trace:\n".concat(error_1.stack, "\n") : ''));
|
|
101
|
-
case
|
|
102
|
-
api = (
|
|
110
|
+
case 14:
|
|
111
|
+
api = (_d = mod.api) !== null && _d !== void 0 ? _d : mod.default;
|
|
103
112
|
if (!api || typeof api.handler !== 'function') {
|
|
104
113
|
relativePath = path.relative(process.cwd(), resolved);
|
|
105
114
|
availableExports = Object.keys(mod).filter(function (key) { return key !== '__esModule'; });
|
|
@@ -285,7 +294,7 @@ function installCleanupHooks() {
|
|
|
285
294
|
}
|
|
286
295
|
function bundleTypeScriptModule(entryPath) {
|
|
287
296
|
return __awaiter(this, void 0, void 0, function () {
|
|
288
|
-
var relativePath, tsconfigPath, result, output,
|
|
297
|
+
var relativePath, tsconfigPath, result, output, tempDir, timestamp, tempFile, contents, error_2;
|
|
289
298
|
var _a, _b, _c, _d;
|
|
290
299
|
return __generator(this, function (_e) {
|
|
291
300
|
switch (_e.label) {
|
|
@@ -322,16 +331,19 @@ function bundleTypeScriptModule(entryPath) {
|
|
|
322
331
|
if (!output) {
|
|
323
332
|
throw new Error('esbuild produced no output');
|
|
324
333
|
}
|
|
325
|
-
contents = "".concat(output.text, "\n//# sourceURL=").concat(pathToFileURL(entryPath).href);
|
|
326
334
|
return [4 /*yield*/, ensureTempDir()];
|
|
327
335
|
case 4:
|
|
328
336
|
tempDir = _e.sent();
|
|
329
|
-
|
|
337
|
+
timestamp = Date.now();
|
|
338
|
+
tempFile = path.join(tempDir, "".concat(path.basename(entryPath, path.extname(entryPath)), "-").concat(timestamp, ".mjs"));
|
|
339
|
+
contents = "".concat(output.text, "\n") +
|
|
340
|
+
"//# sourceURL=".concat(pathToFileURL(entryPath).href, "\n") +
|
|
341
|
+
"//# hypequery-ts-bundle=".concat(timestamp);
|
|
330
342
|
return [4 /*yield*/, writeFile(tempFile, contents, 'utf8')];
|
|
331
343
|
case 5:
|
|
332
344
|
_e.sent();
|
|
333
345
|
tempFiles.add(tempFile);
|
|
334
|
-
return [2 /*return*/, "".concat(pathToFileURL(tempFile).href, "?t=").concat(
|
|
346
|
+
return [2 /*return*/, "".concat(pathToFileURL(tempFile).href, "?t=").concat(timestamp)];
|
|
335
347
|
case 6:
|
|
336
348
|
error_2 = _e.sent();
|
|
337
349
|
throw new Error("Failed to compile ".concat(relativePath, " with esbuild.\n") +
|
|
@@ -386,14 +398,14 @@ function findNearestTsconfig(filePath) {
|
|
|
386
398
|
};
|
|
387
399
|
_b.label = 1;
|
|
388
400
|
case 1:
|
|
389
|
-
if (!
|
|
401
|
+
if (!dir) return [3 /*break*/, 3];
|
|
390
402
|
return [5 /*yield**/, _loop_1()];
|
|
391
403
|
case 2:
|
|
392
404
|
state_1 = _b.sent();
|
|
393
405
|
if (typeof state_1 === "object")
|
|
394
406
|
return [2 /*return*/, state_1.value];
|
|
395
407
|
return [3 /*break*/, 1];
|
|
396
|
-
case 3: return [2 /*return
|
|
408
|
+
case 3: return [2 /*return*/, null];
|
|
397
409
|
}
|
|
398
410
|
});
|
|
399
411
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAQzD;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAavE;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAAC,CAkCR;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CA6B7D;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS9D;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BnF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CASxE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASnE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAShE"}
|
package/dist/utils/prompts.js
CHANGED
|
@@ -45,8 +45,9 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
45
45
|
};
|
|
46
46
|
import prompts from 'prompts';
|
|
47
47
|
import { logger } from './logger.js';
|
|
48
|
+
var noop = function () { return undefined; };
|
|
48
49
|
// Configure prompts to not exit on cancel
|
|
49
|
-
prompts.override({ onCancel:
|
|
50
|
+
prompts.override({ onCancel: noop });
|
|
50
51
|
/**
|
|
51
52
|
* Prompt for database type selection
|
|
52
53
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypequery/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Command-line interface for hypequery",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"chalk": "^5.3.0",
|
|
16
16
|
"commander": "^12.0.0",
|
|
17
17
|
"dotenv": "^16.4.7",
|
|
18
|
-
"esbuild": "^0.
|
|
18
|
+
"esbuild": "^0.25.0",
|
|
19
19
|
"open": "^10.0.0",
|
|
20
20
|
"ora": "^8.0.1",
|
|
21
21
|
"prompts": "^2.4.2"
|
|
@@ -35,8 +35,16 @@
|
|
|
35
35
|
"@vitest/coverage-v8": "^2.1.6",
|
|
36
36
|
"typescript": "^5.7.3",
|
|
37
37
|
"vitest": "^2.1.6",
|
|
38
|
-
"@hypequery/clickhouse": "1.
|
|
39
|
-
"@hypequery/serve": "0.0
|
|
38
|
+
"@hypequery/clickhouse": "1.6.0",
|
|
39
|
+
"@hypequery/serve": "0.2.0"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "https://github.com/hypequery/hypequery.git"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://www.hypequery.com",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/hypequery/hypequery/issues"
|
|
40
48
|
},
|
|
41
49
|
"publishConfig": {
|
|
42
50
|
"access": "public"
|