@hypequery/cli 1.0.0 → 1.1.1
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/generators/clickhouse.d.ts +2 -0
- package/dist/generators/clickhouse.d.ts.map +1 -1
- package/dist/generators/clickhouse.js +84 -41
- 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 +1 -0
- package/dist/utils/load-api.d.ts.map +1 -1
- package/dist/utils/load-api.js +86 -50
- package/dist/utils/load-hypequery-config.d.ts +7 -0
- package/dist/utils/load-hypequery-config.d.ts.map +1 -0
- package/dist/utils/load-hypequery-config.js +89 -0
- 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
|
|
|
@@ -3,5 +3,7 @@ export interface ClickHouseGeneratorOptions {
|
|
|
3
3
|
includeTables?: string[];
|
|
4
4
|
excludeTables?: string[];
|
|
5
5
|
}
|
|
6
|
+
declare const clickhouseToTsType: (type: string) => string;
|
|
7
|
+
export { clickhouseToTsType };
|
|
6
8
|
export declare function generateClickHouseTypes(options: ClickHouseGeneratorOptions): Promise<void>;
|
|
7
9
|
//# sourceMappingURL=clickhouse.d.ts.map
|
|
@@ -1 +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;
|
|
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;AAmGD,QAAA,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,MAsC1C,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAgC9B,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,0BAA0B,iBA0ChF"}
|
|
@@ -39,57 +39,53 @@ import path from 'node:path';
|
|
|
39
39
|
import { getClickHouseClient } from '../utils/clickhouse-client.js';
|
|
40
40
|
var DEFAULT_WARNING = 'Warning: No tables match the filter criteria. Check your include/exclude options.';
|
|
41
41
|
var capitalizeFirstLetter = function (value) { return value.charAt(0).toUpperCase() + value.slice(1); };
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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, ">");
|
|
42
|
+
function splitTopLevelArgs(value) {
|
|
43
|
+
var parts = [];
|
|
44
|
+
var current = '';
|
|
45
|
+
var depth = 0;
|
|
46
|
+
for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
|
|
47
|
+
var char = value_1[_i];
|
|
48
|
+
if (char === '(') {
|
|
49
|
+
depth += 1;
|
|
50
|
+
current += char;
|
|
51
|
+
continue;
|
|
77
52
|
}
|
|
78
|
-
|
|
53
|
+
if (char === ')') {
|
|
54
|
+
depth -= 1;
|
|
55
|
+
current += char;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (char === ',' && depth === 0) {
|
|
59
|
+
parts.push(current.trim());
|
|
60
|
+
current = '';
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
current += char;
|
|
79
64
|
}
|
|
80
|
-
|
|
65
|
+
if (current.trim()) {
|
|
66
|
+
parts.push(current.trim());
|
|
67
|
+
}
|
|
68
|
+
return parts;
|
|
69
|
+
}
|
|
70
|
+
function unwrapType(type, wrapperName) {
|
|
71
|
+
var prefix = "".concat(wrapperName, "(");
|
|
72
|
+
return type.startsWith(prefix) && type.endsWith(')') ? type.slice(prefix.length, -1) : null;
|
|
73
|
+
}
|
|
74
|
+
function getPrimitiveTsType(type) {
|
|
75
|
+
var lowerType = type.toLowerCase();
|
|
76
|
+
switch (lowerType) {
|
|
81
77
|
case 'string':
|
|
82
|
-
case '
|
|
78
|
+
case 'uuid':
|
|
83
79
|
return 'string';
|
|
84
80
|
case 'int8':
|
|
85
81
|
case 'int16':
|
|
86
82
|
case 'int32':
|
|
87
83
|
case 'uint8':
|
|
88
|
-
case 'int64':
|
|
89
84
|
case 'uint16':
|
|
90
85
|
case 'uint32':
|
|
91
|
-
case 'uint64':
|
|
92
86
|
return 'number';
|
|
87
|
+
case 'int64':
|
|
88
|
+
case 'uint64':
|
|
93
89
|
case 'uint128':
|
|
94
90
|
case 'uint256':
|
|
95
91
|
case 'int128':
|
|
@@ -108,9 +104,56 @@ var clickhouseToTsType = function (type) {
|
|
|
108
104
|
case 'boolean':
|
|
109
105
|
return 'boolean';
|
|
110
106
|
default:
|
|
111
|
-
|
|
107
|
+
if (type.startsWith('FixedString('))
|
|
108
|
+
return 'string';
|
|
109
|
+
if (type.startsWith('Decimal('))
|
|
110
|
+
return 'number';
|
|
111
|
+
if (type.startsWith('DateTime64('))
|
|
112
|
+
return 'string';
|
|
113
|
+
if (type.startsWith('DateTime('))
|
|
114
|
+
return 'string';
|
|
115
|
+
if (type.startsWith('Enum8('))
|
|
116
|
+
return 'string';
|
|
117
|
+
if (type.startsWith('Enum16('))
|
|
118
|
+
return 'string';
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
var clickhouseToTsType = function (type) {
|
|
123
|
+
var wrappedArrayType = unwrapType(type, 'Array');
|
|
124
|
+
if (wrappedArrayType) {
|
|
125
|
+
return "Array<".concat(clickhouseToTsType(wrappedArrayType), ">");
|
|
126
|
+
}
|
|
127
|
+
var wrappedNullableType = unwrapType(type, 'Nullable');
|
|
128
|
+
if (wrappedNullableType) {
|
|
129
|
+
return "".concat(clickhouseToTsType(wrappedNullableType), " | null");
|
|
130
|
+
}
|
|
131
|
+
var wrappedLowCardinalityType = unwrapType(type, 'LowCardinality');
|
|
132
|
+
if (wrappedLowCardinalityType) {
|
|
133
|
+
return clickhouseToTsType(wrappedLowCardinalityType);
|
|
134
|
+
}
|
|
135
|
+
var wrappedTupleType = unwrapType(type, 'Tuple');
|
|
136
|
+
if (wrappedTupleType) {
|
|
137
|
+
var tupleParts = splitTopLevelArgs(wrappedTupleType);
|
|
138
|
+
return "[".concat(tupleParts.map(clickhouseToTsType).join(', '), "]");
|
|
139
|
+
}
|
|
140
|
+
var wrappedMapType = unwrapType(type, 'Map');
|
|
141
|
+
if (wrappedMapType) {
|
|
142
|
+
var mapParts = splitTopLevelArgs(wrappedMapType);
|
|
143
|
+
if (mapParts.length === 2) {
|
|
144
|
+
var valueType = mapParts[1];
|
|
145
|
+
// JSON object keys are strings even when ClickHouse map keys are numeric.
|
|
146
|
+
return "Record<string, ".concat(clickhouseToTsType(valueType), ">");
|
|
147
|
+
}
|
|
148
|
+
return 'Record<string, unknown>';
|
|
112
149
|
}
|
|
150
|
+
var primitiveType = getPrimitiveTsType(type);
|
|
151
|
+
if (primitiveType)
|
|
152
|
+
return primitiveType;
|
|
153
|
+
// Unsupported or more complex ClickHouse types currently preserve the historical fallback.
|
|
154
|
+
return 'string';
|
|
113
155
|
};
|
|
156
|
+
export { clickhouseToTsType };
|
|
114
157
|
function fetchTables(includeTables, excludeTables) {
|
|
115
158
|
return __awaiter(this, void 0, void 0, function () {
|
|
116
159
|
var client, tablesQuery, tables;
|
|
@@ -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
package/dist/utils/load-api.d.ts
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,gBAkDrD;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,gBAkClD"}
|
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,8 +47,62 @@ 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,
|
|
51
|
-
var
|
|
50
|
+
var resolved, mod, error_1, relativePath, api, relativePath, availableExports;
|
|
51
|
+
var _a;
|
|
52
|
+
return __generator(this, function (_b) {
|
|
53
|
+
switch (_b.label) {
|
|
54
|
+
case 0:
|
|
55
|
+
resolved = path.resolve(process.cwd(), modulePath);
|
|
56
|
+
_b.label = 1;
|
|
57
|
+
case 1:
|
|
58
|
+
_b.trys.push([1, 3, , 4]);
|
|
59
|
+
return [4 /*yield*/, loadModule(modulePath)];
|
|
60
|
+
case 2:
|
|
61
|
+
mod = _b.sent();
|
|
62
|
+
return [3 /*break*/, 4];
|
|
63
|
+
case 3:
|
|
64
|
+
error_1 = _b.sent();
|
|
65
|
+
if (error_1 instanceof Error && error_1.message.startsWith('File not found:')) {
|
|
66
|
+
relativePath = path.relative(process.cwd(), resolved);
|
|
67
|
+
throw new Error("File not found: ".concat(relativePath, "\n\n") +
|
|
68
|
+
"Make sure the file exists and the path is correct.\n" +
|
|
69
|
+
"You can specify a different file with:\n" +
|
|
70
|
+
" hypequery dev path/to/your/queries.ts");
|
|
71
|
+
}
|
|
72
|
+
throw error_1;
|
|
73
|
+
case 4:
|
|
74
|
+
api = (_a = mod.api) !== null && _a !== void 0 ? _a : mod.default;
|
|
75
|
+
if (!api || typeof api.handler !== 'function') {
|
|
76
|
+
relativePath = path.relative(process.cwd(), resolved);
|
|
77
|
+
availableExports = Object.keys(mod).filter(function (key) { return key !== '__esModule'; });
|
|
78
|
+
throw new Error("Invalid API module: ".concat(relativePath, "\n\n") +
|
|
79
|
+
"The module must export a 'defineServe' result as 'api'.\n\n" +
|
|
80
|
+
(availableExports.length > 0
|
|
81
|
+
? "Found exports: ".concat(availableExports.join(', '), "\n\n")
|
|
82
|
+
: "No exports found in the module.\n\n") +
|
|
83
|
+
"Expected format:\n\n" +
|
|
84
|
+
" import { initServe } from '@hypequery/serve';\n" +
|
|
85
|
+
" \n" +
|
|
86
|
+
" const { define, queries, query } = initServe({\n" +
|
|
87
|
+
" context: () => ({ db }),\n" +
|
|
88
|
+
" });\n" +
|
|
89
|
+
" \n" +
|
|
90
|
+
" export const api = define({\n" +
|
|
91
|
+
" queries: queries({\n" +
|
|
92
|
+
" myQuery: query.query(async ({ ctx }) => {\n" +
|
|
93
|
+
" // ...\n" +
|
|
94
|
+
" }),\n" +
|
|
95
|
+
" }),\n" +
|
|
96
|
+
" });\n");
|
|
97
|
+
}
|
|
98
|
+
return [2 /*return*/, api];
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export function loadModule(modulePath) {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
105
|
+
var resolved, _a, relativePath, extension, isTypeScript, moduleUrl, _b, importOverride, _c, error_2, relativePath;
|
|
52
106
|
return __generator(this, function (_d) {
|
|
53
107
|
switch (_d.label) {
|
|
54
108
|
case 0:
|
|
@@ -63,10 +117,7 @@ export function loadApiModule(modulePath) {
|
|
|
63
117
|
case 3:
|
|
64
118
|
_a = _d.sent();
|
|
65
119
|
relativePath = path.relative(process.cwd(), resolved);
|
|
66
|
-
throw new Error("File not found: ".concat(relativePath
|
|
67
|
-
"Make sure the file exists and the path is correct.\n" +
|
|
68
|
-
"You can specify a different file with:\n" +
|
|
69
|
-
" hypequery dev path/to/your/queries.ts");
|
|
120
|
+
throw new Error("File not found: ".concat(relativePath));
|
|
70
121
|
case 4:
|
|
71
122
|
extension = path.extname(resolved).toLowerCase();
|
|
72
123
|
isTypeScript = TYPESCRIPT_EXTENSIONS.has(extension);
|
|
@@ -82,48 +133,30 @@ export function loadApiModule(modulePath) {
|
|
|
82
133
|
moduleUrl = _b;
|
|
83
134
|
_d.label = 8;
|
|
84
135
|
case 8:
|
|
85
|
-
_d.trys.push([8,
|
|
86
|
-
|
|
136
|
+
_d.trys.push([8, 13, , 14]);
|
|
137
|
+
importOverride = globalState.__hypequeryCliImportOverride;
|
|
138
|
+
if (!importOverride) return [3 /*break*/, 10];
|
|
139
|
+
return [4 /*yield*/, importOverride(moduleUrl)];
|
|
87
140
|
case 9:
|
|
88
|
-
|
|
89
|
-
return [3 /*break*/,
|
|
90
|
-
case 10:
|
|
91
|
-
|
|
141
|
+
_c = _d.sent();
|
|
142
|
+
return [3 /*break*/, 12];
|
|
143
|
+
case 10: return [4 /*yield*/, import(/* @vite-ignore */ moduleUrl)];
|
|
144
|
+
case 11:
|
|
145
|
+
_c = _d.sent();
|
|
146
|
+
_d.label = 12;
|
|
147
|
+
case 12: return [2 /*return*/, _c];
|
|
148
|
+
case 13:
|
|
149
|
+
error_2 = _d.sent();
|
|
92
150
|
relativePath = path.relative(process.cwd(), resolved);
|
|
93
151
|
throw new Error("Failed to load module: ".concat(relativePath, "\n\n") +
|
|
94
|
-
"Error: ".concat(
|
|
95
|
-
(
|
|
152
|
+
"Error: ".concat(error_2.message, "\n\n") +
|
|
153
|
+
(error_2.code === 'ERR_MODULE_NOT_FOUND'
|
|
96
154
|
? "This usually means:\n" +
|
|
97
155
|
" \u2022 A dependency is missing (run 'npm install')\n" +
|
|
98
156
|
" \u2022 An import path is incorrect\n"
|
|
99
157
|
: "") +
|
|
100
|
-
(
|
|
101
|
-
case
|
|
102
|
-
api = (_c = mod.api) !== null && _c !== void 0 ? _c : mod.default;
|
|
103
|
-
if (!api || typeof api.handler !== 'function') {
|
|
104
|
-
relativePath = path.relative(process.cwd(), resolved);
|
|
105
|
-
availableExports = Object.keys(mod).filter(function (key) { return key !== '__esModule'; });
|
|
106
|
-
throw new Error("Invalid API module: ".concat(relativePath, "\n\n") +
|
|
107
|
-
"The module must export a 'defineServe' result as 'api'.\n\n" +
|
|
108
|
-
(availableExports.length > 0
|
|
109
|
-
? "Found exports: ".concat(availableExports.join(', '), "\n\n")
|
|
110
|
-
: "No exports found in the module.\n\n") +
|
|
111
|
-
"Expected format:\n\n" +
|
|
112
|
-
" import { initServe } from '@hypequery/serve';\n" +
|
|
113
|
-
" \n" +
|
|
114
|
-
" const { define, queries, query } = initServe({\n" +
|
|
115
|
-
" context: () => ({ db }),\n" +
|
|
116
|
-
" });\n" +
|
|
117
|
-
" \n" +
|
|
118
|
-
" export const api = define({\n" +
|
|
119
|
-
" queries: queries({\n" +
|
|
120
|
-
" myQuery: query.query(async ({ ctx }) => {\n" +
|
|
121
|
-
" // ...\n" +
|
|
122
|
-
" }),\n" +
|
|
123
|
-
" }),\n" +
|
|
124
|
-
" });\n");
|
|
125
|
-
}
|
|
126
|
-
return [2 /*return*/, api];
|
|
158
|
+
(error_2.stack ? "\nStack trace:\n".concat(error_2.stack, "\n") : ''));
|
|
159
|
+
case 14: return [2 /*return*/];
|
|
127
160
|
}
|
|
128
161
|
});
|
|
129
162
|
});
|
|
@@ -285,7 +318,7 @@ function installCleanupHooks() {
|
|
|
285
318
|
}
|
|
286
319
|
function bundleTypeScriptModule(entryPath) {
|
|
287
320
|
return __awaiter(this, void 0, void 0, function () {
|
|
288
|
-
var relativePath, tsconfigPath, result, output,
|
|
321
|
+
var relativePath, tsconfigPath, result, output, tempDir, timestamp, tempFile, contents, error_3;
|
|
289
322
|
var _a, _b, _c, _d;
|
|
290
323
|
return __generator(this, function (_e) {
|
|
291
324
|
switch (_e.label) {
|
|
@@ -322,20 +355,23 @@ function bundleTypeScriptModule(entryPath) {
|
|
|
322
355
|
if (!output) {
|
|
323
356
|
throw new Error('esbuild produced no output');
|
|
324
357
|
}
|
|
325
|
-
contents = "".concat(output.text, "\n//# sourceURL=").concat(pathToFileURL(entryPath).href);
|
|
326
358
|
return [4 /*yield*/, ensureTempDir()];
|
|
327
359
|
case 4:
|
|
328
360
|
tempDir = _e.sent();
|
|
329
|
-
|
|
361
|
+
timestamp = Date.now();
|
|
362
|
+
tempFile = path.join(tempDir, "".concat(path.basename(entryPath, path.extname(entryPath)), "-").concat(timestamp, ".mjs"));
|
|
363
|
+
contents = "".concat(output.text, "\n") +
|
|
364
|
+
"//# sourceURL=".concat(pathToFileURL(entryPath).href, "\n") +
|
|
365
|
+
"//# hypequery-ts-bundle=".concat(timestamp);
|
|
330
366
|
return [4 /*yield*/, writeFile(tempFile, contents, 'utf8')];
|
|
331
367
|
case 5:
|
|
332
368
|
_e.sent();
|
|
333
369
|
tempFiles.add(tempFile);
|
|
334
|
-
return [2 /*return*/, "".concat(pathToFileURL(tempFile).href, "?t=").concat(
|
|
370
|
+
return [2 /*return*/, "".concat(pathToFileURL(tempFile).href, "?t=").concat(timestamp)];
|
|
335
371
|
case 6:
|
|
336
|
-
|
|
372
|
+
error_3 = _e.sent();
|
|
337
373
|
throw new Error("Failed to compile ".concat(relativePath, " with esbuild.\n") +
|
|
338
|
-
"Original error: ".concat((_d =
|
|
374
|
+
"Original error: ".concat((_d = error_3 === null || error_3 === void 0 ? void 0 : error_3.message) !== null && _d !== void 0 ? _d : error_3));
|
|
339
375
|
case 7: return [2 /*return*/];
|
|
340
376
|
}
|
|
341
377
|
});
|
|
@@ -386,14 +422,14 @@ function findNearestTsconfig(filePath) {
|
|
|
386
422
|
};
|
|
387
423
|
_b.label = 1;
|
|
388
424
|
case 1:
|
|
389
|
-
if (!
|
|
425
|
+
if (!dir) return [3 /*break*/, 3];
|
|
390
426
|
return [5 /*yield**/, _loop_1()];
|
|
391
427
|
case 2:
|
|
392
428
|
state_1 = _b.sent();
|
|
393
429
|
if (typeof state_1 === "object")
|
|
394
430
|
return [2 /*return*/, state_1.value];
|
|
395
431
|
return [3 /*break*/, 1];
|
|
396
|
-
case 3: return [2 /*return
|
|
432
|
+
case 3: return [2 /*return*/, null];
|
|
397
433
|
}
|
|
398
434
|
});
|
|
399
435
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedHypequeryClickHouseConfig } from '@hypequery/clickhouse';
|
|
2
|
+
export declare const DEFAULT_HYPEQUERY_CONFIG_PATH = "hypequery.config.ts";
|
|
3
|
+
export declare const DEFAULT_MIGRATIONS_OUT_DIR = "./migrations";
|
|
4
|
+
export declare const DEFAULT_MIGRATIONS_TABLE = "_hypequery_migrations";
|
|
5
|
+
export declare const DEFAULT_MIGRATIONS_PREFIX: "timestamp";
|
|
6
|
+
export declare function loadHypequeryConfig(configPath?: string): Promise<ResolvedHypequeryClickHouseConfig>;
|
|
7
|
+
//# sourceMappingURL=load-hypequery-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-hypequery-config.d.ts","sourceRoot":"","sources":["../../src/utils/load-hypequery-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,iCAAiC,EAClC,MAAM,uBAAuB,CAAC;AAG/B,eAAO,MAAM,6BAA6B,wBAAwB,CAAC;AACnE,eAAO,MAAM,0BAA0B,iBAAiB,CAAC;AACzD,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAChE,eAAO,MAAM,yBAAyB,EAAG,WAAoB,CAAC;AAE9D,wBAAsB,mBAAmB,CACvC,UAAU,SAAgC,GACzC,OAAO,CAAC,iCAAiC,CAAC,CA0C5C"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
+
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);
|
|
23
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
+
function step(op) {
|
|
26
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
+
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;
|
|
29
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
+
switch (op[0]) {
|
|
31
|
+
case 0: case 1: t = op; break;
|
|
32
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
+
default:
|
|
36
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
+
if (t[2]) _.ops.pop();
|
|
41
|
+
_.trys.pop(); continue;
|
|
42
|
+
}
|
|
43
|
+
op = body.call(thisArg, _);
|
|
44
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
import { loadModule } from './load-api.js';
|
|
49
|
+
export var DEFAULT_HYPEQUERY_CONFIG_PATH = 'hypequery.config.ts';
|
|
50
|
+
export var DEFAULT_MIGRATIONS_OUT_DIR = './migrations';
|
|
51
|
+
export var DEFAULT_MIGRATIONS_TABLE = '_hypequery_migrations';
|
|
52
|
+
export var DEFAULT_MIGRATIONS_PREFIX = 'timestamp';
|
|
53
|
+
export function loadHypequeryConfig() {
|
|
54
|
+
return __awaiter(this, arguments, void 0, function (configPath) {
|
|
55
|
+
var mod, candidate, config;
|
|
56
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
57
|
+
if (configPath === void 0) { configPath = DEFAULT_HYPEQUERY_CONFIG_PATH; }
|
|
58
|
+
return __generator(this, function (_h) {
|
|
59
|
+
switch (_h.label) {
|
|
60
|
+
case 0: return [4 /*yield*/, loadModule(configPath)];
|
|
61
|
+
case 1:
|
|
62
|
+
mod = _h.sent();
|
|
63
|
+
candidate = (_a = mod.default) !== null && _a !== void 0 ? _a : mod.config;
|
|
64
|
+
if (!candidate || typeof candidate !== 'object') {
|
|
65
|
+
throw new Error("Invalid hypequery config: ".concat(configPath, "\n\n") +
|
|
66
|
+
"The config module must export a ClickHouse config as the default export.");
|
|
67
|
+
}
|
|
68
|
+
config = candidate;
|
|
69
|
+
if (config.dialect !== 'clickhouse') {
|
|
70
|
+
throw new Error("Invalid hypequery config: ".concat(configPath, "\n\n") +
|
|
71
|
+
"Expected \"dialect\" to be \"clickhouse\".");
|
|
72
|
+
}
|
|
73
|
+
if (typeof config.schema !== 'string' || config.schema.length === 0) {
|
|
74
|
+
throw new Error("Invalid hypequery config: ".concat(configPath, "\n\n") +
|
|
75
|
+
"Expected \"schema\" to be a non-empty string.");
|
|
76
|
+
}
|
|
77
|
+
if (!config.dbCredentials || typeof config.dbCredentials !== 'object') {
|
|
78
|
+
throw new Error("Invalid hypequery config: ".concat(configPath, "\n\n") +
|
|
79
|
+
"Expected \"dbCredentials\" to be defined.");
|
|
80
|
+
}
|
|
81
|
+
return [2 /*return*/, __assign(__assign({}, config), { migrations: {
|
|
82
|
+
out: (_c = (_b = config.migrations) === null || _b === void 0 ? void 0 : _b.out) !== null && _c !== void 0 ? _c : DEFAULT_MIGRATIONS_OUT_DIR,
|
|
83
|
+
table: (_e = (_d = config.migrations) === null || _d === void 0 ? void 0 : _d.table) !== null && _e !== void 0 ? _e : DEFAULT_MIGRATIONS_TABLE,
|
|
84
|
+
prefix: (_g = (_f = config.migrations) === null || _f === void 0 ? void 0 : _f.prefix) !== null && _g !== void 0 ? _g : DEFAULT_MIGRATIONS_PREFIX,
|
|
85
|
+
} })];
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
@@ -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": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
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/
|
|
39
|
-
"@hypequery/
|
|
38
|
+
"@hypequery/clickhouse": "1.6.2",
|
|
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"
|