@hypequery/clickhouse 1.6.0 → 1.6.2
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 +19 -14
- package/dist/cli/generate-types.js +3 -88
- package/dist/cli/type-parsing.js +124 -0
- package/dist/core/adapters/clickhouse-adapter.d.ts +14 -0
- package/dist/core/adapters/clickhouse-adapter.d.ts.map +1 -0
- package/dist/core/adapters/clickhouse-adapter.js +58 -0
- package/dist/core/adapters/database-adapter.d.ts +13 -0
- package/dist/core/adapters/database-adapter.d.ts.map +1 -0
- package/dist/core/adapters/database-adapter.js +1 -0
- package/dist/core/cache/cache-manager.d.ts.map +1 -1
- package/dist/core/cache/cache-manager.js +6 -5
- package/dist/core/dialects/clickhouse-dialect.d.ts +10 -0
- package/dist/core/dialects/clickhouse-dialect.d.ts.map +1 -0
- package/dist/core/dialects/clickhouse-dialect.js +47 -0
- package/dist/core/dialects/sql-dialect.d.ts +11 -0
- package/dist/core/dialects/sql-dialect.d.ts.map +1 -0
- package/dist/core/dialects/sql-dialect.js +1 -0
- package/dist/core/features/aggregations.d.ts +5 -5
- package/dist/core/features/analytics.d.ts +804 -5
- package/dist/core/features/analytics.d.ts.map +1 -1
- package/dist/core/features/analytics.js +6 -9
- package/dist/core/features/executor.d.ts.map +1 -1
- package/dist/core/features/executor.js +26 -53
- package/dist/core/features/filtering.d.ts +5 -5
- package/dist/core/features/joins.d.ts +1 -1
- package/dist/core/features/query-modifiers.d.ts +6 -6
- package/dist/core/query-builder.d.ts +17 -6
- package/dist/core/query-builder.d.ts.map +1 -1
- package/dist/core/query-builder.js +25 -32
- package/dist/core/tests/integration/setup.d.ts +3 -1
- package/dist/core/tests/integration/setup.d.ts.map +1 -1
- package/dist/core/tests/test-utils.d.ts.map +1 -1
- package/dist/core/tests/test-utils.js +12 -2
- package/dist/core/types/select-types.d.ts +1 -1
- package/dist/core/types/select-types.d.ts.map +1 -1
- package/dist/core/utils/streaming-helpers.d.ts.map +1 -1
- package/dist/core/utils/streaming-helpers.js +8 -0
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/core/utils.js +3 -0
- package/dist/dataset/definition.d.ts +135 -0
- package/dist/dataset/definition.d.ts.map +1 -0
- package/dist/dataset/definition.js +265 -0
- package/dist/dataset/helpers.d.ts +136 -0
- package/dist/dataset/helpers.d.ts.map +1 -0
- package/dist/dataset/helpers.js +189 -0
- package/dist/dataset/index.d.ts +51 -0
- package/dist/dataset/index.d.ts.map +1 -0
- package/dist/dataset/index.js +59 -0
- package/dist/dataset/introspection.d.ts +133 -0
- package/dist/dataset/introspection.d.ts.map +1 -0
- package/dist/dataset/introspection.js +239 -0
- package/dist/dataset/sql-tag.d.ts +51 -0
- package/dist/dataset/sql-tag.d.ts.map +1 -0
- package/dist/dataset/sql-tag.js +86 -0
- package/dist/dataset/types.d.ts +300 -0
- package/dist/dataset/types.d.ts.map +1 -0
- package/dist/dataset/types.js +11 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -15
- package/dist/migrations/config/index.d.ts +3 -0
- package/dist/migrations/config/index.d.ts.map +1 -0
- package/dist/migrations/config/index.js +1 -0
- package/dist/migrations/config/types.d.ts +45 -0
- package/dist/migrations/config/types.d.ts.map +1 -0
- package/dist/migrations/config/types.js +28 -0
- package/dist/migrations/diff/diff.d.ts +11 -0
- package/dist/migrations/diff/diff.d.ts.map +1 -0
- package/dist/migrations/diff/diff.js +240 -0
- package/dist/migrations/diff/index.d.ts +3 -0
- package/dist/migrations/diff/index.d.ts.map +1 -0
- package/dist/migrations/diff/index.js +1 -0
- package/dist/migrations/diff/types.d.ts +74 -0
- package/dist/migrations/diff/types.d.ts.map +1 -0
- package/dist/migrations/diff/types.js +1 -0
- package/dist/migrations/plan/index.d.ts +3 -0
- package/dist/migrations/plan/index.d.ts.map +1 -0
- package/dist/migrations/plan/index.js +1 -0
- package/dist/migrations/plan/plan.d.ts +12 -0
- package/dist/migrations/plan/plan.d.ts.map +1 -0
- package/dist/migrations/plan/plan.js +416 -0
- package/dist/migrations/plan/types.d.ts +93 -0
- package/dist/migrations/plan/types.d.ts.map +1 -0
- package/dist/migrations/plan/types.js +1 -0
- package/dist/migrations/schema/column.d.ts +71 -0
- package/dist/migrations/schema/column.d.ts.map +1 -0
- package/dist/migrations/schema/column.js +123 -0
- package/dist/migrations/schema/define.d.ts +24 -0
- package/dist/migrations/schema/define.d.ts.map +1 -0
- package/dist/migrations/schema/define.js +47 -0
- package/dist/migrations/schema/index.d.ts +4 -0
- package/dist/migrations/schema/index.d.ts.map +1 -0
- package/dist/migrations/schema/index.js +2 -0
- package/dist/migrations/schema/types.d.ts +74 -0
- package/dist/migrations/schema/types.d.ts.map +1 -0
- package/dist/migrations/schema/types.js +1 -0
- package/dist/migrations/snapshot/index.d.ts +3 -0
- package/dist/migrations/snapshot/index.d.ts.map +1 -0
- package/dist/migrations/snapshot/index.js +1 -0
- package/dist/migrations/snapshot/serialize.d.ts +21 -0
- package/dist/migrations/snapshot/serialize.d.ts.map +1 -0
- package/dist/migrations/snapshot/serialize.js +127 -0
- package/dist/migrations/snapshot/types.d.ts +47 -0
- package/dist/migrations/snapshot/types.d.ts.map +1 -0
- package/dist/migrations/snapshot/types.js +1 -0
- package/dist/migrations/sql/index.d.ts +4 -0
- package/dist/migrations/sql/index.d.ts.map +1 -0
- package/dist/migrations/sql/index.js +2 -0
- package/dist/migrations/sql/render.d.ts +10 -0
- package/dist/migrations/sql/render.d.ts.map +1 -0
- package/dist/migrations/sql/render.js +347 -0
- package/dist/migrations/sql/types.d.ts +53 -0
- package/dist/migrations/sql/types.d.ts.map +1 -0
- package/dist/migrations/sql/types.js +1 -0
- package/dist/migrations/sql/write.d.ts +10 -0
- package/dist/migrations/sql/write.d.ts.map +1 -0
- package/dist/migrations/sql/write.js +35 -0
- package/dist/types/base.d.ts +2 -1
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/clickhouse-types.d.ts +7 -2
- package/dist/types/clickhouse-types.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/type-helpers.d.ts +7 -0
- package/dist/types/type-helpers.d.ts.map +1 -0
- package/dist/types/type-helpers.js +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h1>@hypequery/clickhouse</h1>
|
|
3
|
-
<p>A
|
|
3
|
+
<p>A TypeScript-first query builder for ClickHouse and the foundation of the hypequery path.</p>
|
|
4
4
|
|
|
5
5
|
[](https://github.com/hypequery/hypequery/blob/main/LICENSE)
|
|
6
6
|
[](https://badge.fury.io/js/@hypequery%2Fclickhouse)
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
12
12
|
|
|
13
|
-
hypequery is
|
|
13
|
+
`@hypequery/clickhouse` is the first step in the main hypequery flow. Generate types from your ClickHouse schema, build typed queries locally, then promote important queries into `query({ ... })` and `serve({ queries })` when they need to be reused across your app.
|
|
14
14
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
@@ -41,6 +41,13 @@ npm install @hypequery/clickhouse @clickhouse/client-web
|
|
|
41
41
|
|
|
42
42
|
## Quick Start
|
|
43
43
|
|
|
44
|
+
Main path:
|
|
45
|
+
|
|
46
|
+
1. Generate schema types
|
|
47
|
+
2. Create a typed `db` with `createQueryBuilder(...)`
|
|
48
|
+
3. Build and execute queries locally
|
|
49
|
+
4. Add `@hypequery/serve` later if a query needs a reusable contract or HTTP surface
|
|
50
|
+
|
|
44
51
|
### Node.js Environments
|
|
45
52
|
|
|
46
53
|
```typescript
|
|
@@ -126,18 +133,15 @@ const rows = await db
|
|
|
126
133
|
await db.cache.invalidateTags(['users']);
|
|
127
134
|
```
|
|
128
135
|
|
|
129
|
-
Use `.cache()` to attach defaults to a fluent chain, pass `execute({ cache: { ... } })` for one-off overrides, or call `db.cache.*` for manual invalidation. For a deep dive on cache modes, invalidation, advanced serialization, and bring-your-own-provider recipes (Redis/Upstash, compression, etc.), see the [Caching guide](https://hypequery.com/docs/
|
|
136
|
+
Use `.cache()` to attach defaults to a fluent chain, pass `execute({ cache: { ... } })` for one-off overrides, or call `db.cache.*` for manual invalidation. For a deep dive on cache modes, invalidation, advanced serialization, and bring-your-own-provider recipes (Redis/Upstash, compression, etc.), see the [Caching guide](https://hypequery.com/docs/caching).
|
|
130
137
|
|
|
131
138
|
## Schema Generation
|
|
132
139
|
|
|
133
|
-
|
|
140
|
+
Use the hypequery CLI to generate TypeScript types from your ClickHouse schema:
|
|
134
141
|
|
|
135
142
|
```bash
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
# Generate schema types
|
|
140
|
-
npx hypequery-generate-types --host your-clickhouse-host --database your-database
|
|
143
|
+
npm install -D @hypequery/cli
|
|
144
|
+
npx hypequery generate
|
|
141
145
|
```
|
|
142
146
|
|
|
143
147
|
This creates a `generated-schema.ts` file that you can import in your application:
|
|
@@ -278,12 +282,13 @@ hypequery follows semantic versioning and provides multiple release channels:
|
|
|
278
282
|
|
|
279
283
|
## Documentation
|
|
280
284
|
|
|
281
|
-
For detailed documentation and examples, visit
|
|
285
|
+
For detailed documentation and examples, visit the main docs flow.
|
|
282
286
|
|
|
283
|
-
- [
|
|
284
|
-
- [
|
|
285
|
-
- [
|
|
286
|
-
- [
|
|
287
|
+
- [Quick Start](https://hypequery.com/docs/quick-start)
|
|
288
|
+
- [Core Concepts](https://hypequery.com/docs/core-concepts)
|
|
289
|
+
- [Query Building](https://hypequery.com/docs/query-building/basics)
|
|
290
|
+
- [Filtering](https://hypequery.com/docs/query-building/where)
|
|
291
|
+
- [API Reference](https://hypequery.com/docs/reference/query-builder)
|
|
287
292
|
|
|
288
293
|
|
|
289
294
|
## Troubleshooting
|
|
@@ -2,6 +2,9 @@ import { ClickHouseConnection } from '../core/connection.js';
|
|
|
2
2
|
import fs from 'fs/promises';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
|
+
import { clickhouseToTsType } from './type-parsing.js';
|
|
6
|
+
|
|
7
|
+
export { clickhouseToTsType } from './type-parsing.js';
|
|
5
8
|
|
|
6
9
|
// Load environment variables from the current directory
|
|
7
10
|
dotenv.config();
|
|
@@ -18,94 +21,6 @@ dotenv.config();
|
|
|
18
21
|
* @property {string[]} [excludeTables] - List of tables to exclude
|
|
19
22
|
*/
|
|
20
23
|
|
|
21
|
-
/**
|
|
22
|
-
* Converts ClickHouse types to TypeScript types
|
|
23
|
-
* @param {string} type - The ClickHouse type to convert
|
|
24
|
-
* @returns {string} - The corresponding TypeScript type
|
|
25
|
-
*/
|
|
26
|
-
const clickhouseToTsType = (type) => {
|
|
27
|
-
if (type.startsWith('Array(')) {
|
|
28
|
-
const innerType = type.slice(6, -1);
|
|
29
|
-
return `Array<${clickhouseToTsType(innerType)}>`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Handle Nullable types
|
|
33
|
-
if (type.startsWith('Nullable(')) {
|
|
34
|
-
const innerType = type.slice(9, -1);
|
|
35
|
-
return `${clickhouseToTsType(innerType)} | null`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Handle Map types
|
|
39
|
-
if (type.startsWith('Map(')) {
|
|
40
|
-
// Extract key and value types from Map(KeyType, ValueType)
|
|
41
|
-
const mapContent = type.slice(4, -1); // Remove 'Map(' and ')'
|
|
42
|
-
const commaIndex = mapContent.lastIndexOf(',');
|
|
43
|
-
if (commaIndex !== -1) {
|
|
44
|
-
const keyType = mapContent.substring(0, commaIndex).trim();
|
|
45
|
-
const valueType = mapContent.substring(commaIndex + 1).trim();
|
|
46
|
-
|
|
47
|
-
// Handle different key types
|
|
48
|
-
let keyTsType = 'string';
|
|
49
|
-
if (keyType === 'LowCardinality(String)') {
|
|
50
|
-
keyTsType = 'string';
|
|
51
|
-
} else if (keyType.includes('Int') || keyType.includes('UInt')) {
|
|
52
|
-
keyTsType = 'number';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Handle different value types
|
|
56
|
-
let valueTsType = 'unknown';
|
|
57
|
-
if (valueType.startsWith('Array(')) {
|
|
58
|
-
const innerType = valueType.slice(6, -1);
|
|
59
|
-
valueTsType = `Array<${clickhouseToTsType(innerType)}>`;
|
|
60
|
-
} else if (valueType.startsWith('Nullable(')) {
|
|
61
|
-
const innerType = valueType.slice(9, -1);
|
|
62
|
-
valueTsType = `${clickhouseToTsType(innerType)} | null`;
|
|
63
|
-
} else {
|
|
64
|
-
valueTsType = clickhouseToTsType(valueType);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return `Record<${keyTsType}, ${valueTsType}>`;
|
|
68
|
-
}
|
|
69
|
-
return 'Record<string, unknown>';
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
switch (type.toLowerCase()) {
|
|
73
|
-
case 'string':
|
|
74
|
-
case 'fixedstring':
|
|
75
|
-
return 'string';
|
|
76
|
-
case 'int8':
|
|
77
|
-
case 'int16':
|
|
78
|
-
case 'int32':
|
|
79
|
-
case 'uint8':
|
|
80
|
-
case 'int64':
|
|
81
|
-
case 'uint16':
|
|
82
|
-
case 'uint32':
|
|
83
|
-
case 'uint64':
|
|
84
|
-
return 'number';
|
|
85
|
-
case 'uint128':
|
|
86
|
-
case 'uint256':
|
|
87
|
-
case 'int128':
|
|
88
|
-
case 'int256':
|
|
89
|
-
return 'string';
|
|
90
|
-
case 'float32':
|
|
91
|
-
case 'float64':
|
|
92
|
-
case 'decimal':
|
|
93
|
-
return 'number';
|
|
94
|
-
case 'datetime':
|
|
95
|
-
case 'datetime64':
|
|
96
|
-
return 'string'; // Use string for datetime
|
|
97
|
-
case 'date':
|
|
98
|
-
case 'date32':
|
|
99
|
-
return 'string'; // Use string for date
|
|
100
|
-
case 'bool':
|
|
101
|
-
case 'boolean':
|
|
102
|
-
return 'boolean';
|
|
103
|
-
default:
|
|
104
|
-
// For complex types or unknown types, return string as a safe default
|
|
105
|
-
return 'string';
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
|
|
109
24
|
/**
|
|
110
25
|
* Generates TypeScript type definitions from the ClickHouse database schema
|
|
111
26
|
* @param {string} outputPath - The file path where the type definitions will be written
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
function splitTopLevelArgs(value) {
|
|
2
|
+
const parts = [];
|
|
3
|
+
let current = '';
|
|
4
|
+
let depth = 0;
|
|
5
|
+
|
|
6
|
+
for (const char of value) {
|
|
7
|
+
if (char === '(') {
|
|
8
|
+
depth += 1;
|
|
9
|
+
current += char;
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (char === ')') {
|
|
14
|
+
depth -= 1;
|
|
15
|
+
current += char;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (char === ',' && depth === 0) {
|
|
20
|
+
parts.push(current.trim());
|
|
21
|
+
current = '';
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
current += char;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (current.trim()) {
|
|
29
|
+
parts.push(current.trim());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return parts;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function unwrapType(type, wrapperName) {
|
|
36
|
+
const prefix = `${wrapperName}(`;
|
|
37
|
+
return type.startsWith(prefix) && type.endsWith(')')
|
|
38
|
+
? type.slice(prefix.length, -1)
|
|
39
|
+
: null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getPrimitiveTsType(type) {
|
|
43
|
+
const lowerType = type.toLowerCase();
|
|
44
|
+
|
|
45
|
+
switch (lowerType) {
|
|
46
|
+
case 'string':
|
|
47
|
+
case 'uuid':
|
|
48
|
+
return 'string';
|
|
49
|
+
case 'int8':
|
|
50
|
+
case 'int16':
|
|
51
|
+
case 'int32':
|
|
52
|
+
case 'uint8':
|
|
53
|
+
case 'uint16':
|
|
54
|
+
case 'uint32':
|
|
55
|
+
return 'number';
|
|
56
|
+
case 'int64':
|
|
57
|
+
case 'uint64':
|
|
58
|
+
case 'uint128':
|
|
59
|
+
case 'uint256':
|
|
60
|
+
case 'int128':
|
|
61
|
+
case 'int256':
|
|
62
|
+
return 'string';
|
|
63
|
+
case 'float32':
|
|
64
|
+
case 'float64':
|
|
65
|
+
case 'decimal':
|
|
66
|
+
return 'number';
|
|
67
|
+
case 'datetime':
|
|
68
|
+
case 'datetime64':
|
|
69
|
+
case 'date':
|
|
70
|
+
case 'date32':
|
|
71
|
+
return 'string';
|
|
72
|
+
case 'bool':
|
|
73
|
+
case 'boolean':
|
|
74
|
+
return 'boolean';
|
|
75
|
+
default:
|
|
76
|
+
if (type.startsWith('FixedString(')) return 'string';
|
|
77
|
+
if (type.startsWith('Decimal(')) return 'number';
|
|
78
|
+
if (type.startsWith('DateTime64(')) return 'string';
|
|
79
|
+
if (type.startsWith('DateTime(')) return 'string';
|
|
80
|
+
if (type.startsWith('Enum8(')) return 'string';
|
|
81
|
+
if (type.startsWith('Enum16(')) return 'string';
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const clickhouseToTsType = (type) => {
|
|
87
|
+
const wrappedArrayType = unwrapType(type, 'Array');
|
|
88
|
+
if (wrappedArrayType) {
|
|
89
|
+
return `Array<${clickhouseToTsType(wrappedArrayType)}>`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const wrappedNullableType = unwrapType(type, 'Nullable');
|
|
93
|
+
if (wrappedNullableType) {
|
|
94
|
+
return `${clickhouseToTsType(wrappedNullableType)} | null`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const wrappedLowCardinalityType = unwrapType(type, 'LowCardinality');
|
|
98
|
+
if (wrappedLowCardinalityType) {
|
|
99
|
+
return clickhouseToTsType(wrappedLowCardinalityType);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const wrappedTupleType = unwrapType(type, 'Tuple');
|
|
103
|
+
if (wrappedTupleType) {
|
|
104
|
+
const tupleParts = splitTopLevelArgs(wrappedTupleType);
|
|
105
|
+
return `[${tupleParts.map(clickhouseToTsType).join(', ')}]`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const wrappedMapType = unwrapType(type, 'Map');
|
|
109
|
+
if (wrappedMapType) {
|
|
110
|
+
const mapParts = splitTopLevelArgs(wrappedMapType);
|
|
111
|
+
if (mapParts.length === 2) {
|
|
112
|
+
const [, valueType] = mapParts;
|
|
113
|
+
// JSON object keys are strings even when ClickHouse map keys are numeric.
|
|
114
|
+
return `Record<string, ${clickhouseToTsType(valueType)}>`;
|
|
115
|
+
}
|
|
116
|
+
return 'Record<string, unknown>';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const primitiveType = getPrimitiveTsType(type);
|
|
120
|
+
if (primitiveType) return primitiveType;
|
|
121
|
+
|
|
122
|
+
// Unsupported or more complex ClickHouse types currently preserve the historical fallback.
|
|
123
|
+
return 'string';
|
|
124
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DatabaseAdapter, QueryExecutionOptions } from './database-adapter.js';
|
|
2
|
+
import type { ClickHouseConfig } from '../query-builder.js';
|
|
3
|
+
export declare class ClickHouseAdapter implements DatabaseAdapter {
|
|
4
|
+
private config;
|
|
5
|
+
readonly name = "clickhouse";
|
|
6
|
+
readonly namespace?: string;
|
|
7
|
+
private client;
|
|
8
|
+
constructor(config: ClickHouseConfig);
|
|
9
|
+
query<T>(sql: string, params?: unknown[], options?: QueryExecutionOptions): Promise<T[]>;
|
|
10
|
+
stream<T>(sql: string, params?: unknown[], options?: QueryExecutionOptions): Promise<ReadableStream<T[]>>;
|
|
11
|
+
render(sql: string, params?: unknown[]): string;
|
|
12
|
+
}
|
|
13
|
+
export declare function createClickHouseAdapter(config: ClickHouseConfig): DatabaseAdapter;
|
|
14
|
+
//# sourceMappingURL=clickhouse-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse-adapter.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/clickhouse-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAGpF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA2B5D,qBAAa,iBAAkB,YAAW,eAAe;IAK3C,OAAO,CAAC,MAAM;IAJ1B,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAmB;gBAEb,MAAM,EAAE,gBAAgB;IAKtC,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAW5F,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IAYnH,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,MAAM;CAGpD;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,eAAe,CAEjF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { isClientConfig } from '../query-builder.js';
|
|
2
|
+
import { substituteParameters } from '../utils.js';
|
|
3
|
+
import { createJsonEachRowStream } from '../utils/streaming-helpers.js';
|
|
4
|
+
import { getAutoClientModule } from '../env/auto-client.js';
|
|
5
|
+
function createClickHouseClient(config) {
|
|
6
|
+
if (isClientConfig(config)) {
|
|
7
|
+
return config.client;
|
|
8
|
+
}
|
|
9
|
+
const clientModule = getAutoClientModule();
|
|
10
|
+
return clientModule.createClient(config);
|
|
11
|
+
}
|
|
12
|
+
function deriveNamespace(config) {
|
|
13
|
+
if ('client' in config && config.client) {
|
|
14
|
+
return 'client';
|
|
15
|
+
}
|
|
16
|
+
const host = 'host' in config ? config.host : 'unknown-host';
|
|
17
|
+
const database = 'database' in config ? config.database : 'default';
|
|
18
|
+
const username = 'username' in config ? config.username : 'default';
|
|
19
|
+
return `${host || 'unknown-host'}|${database || 'default'}|${username || 'default'}`;
|
|
20
|
+
}
|
|
21
|
+
export class ClickHouseAdapter {
|
|
22
|
+
config;
|
|
23
|
+
name = 'clickhouse';
|
|
24
|
+
namespace;
|
|
25
|
+
client;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.config = config;
|
|
28
|
+
this.namespace = deriveNamespace(config);
|
|
29
|
+
this.client = createClickHouseClient(config);
|
|
30
|
+
}
|
|
31
|
+
async query(sql, params = [], options) {
|
|
32
|
+
const finalSQL = substituteParameters(sql, params);
|
|
33
|
+
const result = await this.client.query({
|
|
34
|
+
query: finalSQL,
|
|
35
|
+
format: 'JSONEachRow',
|
|
36
|
+
clickhouse_settings: options?.clickhouseSettings,
|
|
37
|
+
query_id: options?.queryId,
|
|
38
|
+
});
|
|
39
|
+
return result.json();
|
|
40
|
+
}
|
|
41
|
+
async stream(sql, params = [], options) {
|
|
42
|
+
const finalSQL = substituteParameters(sql, params);
|
|
43
|
+
const result = await this.client.query({
|
|
44
|
+
query: finalSQL,
|
|
45
|
+
format: 'JSONEachRow',
|
|
46
|
+
clickhouse_settings: options?.clickhouseSettings,
|
|
47
|
+
query_id: options?.queryId,
|
|
48
|
+
});
|
|
49
|
+
const stream = result.stream();
|
|
50
|
+
return createJsonEachRowStream(stream);
|
|
51
|
+
}
|
|
52
|
+
render(sql, params = []) {
|
|
53
|
+
return substituteParameters(sql, params);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function createClickHouseAdapter(config) {
|
|
57
|
+
return new ClickHouseAdapter(config);
|
|
58
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ClickHouseSettings } from '@clickhouse/client-common';
|
|
2
|
+
export interface QueryExecutionOptions {
|
|
3
|
+
clickhouseSettings?: ClickHouseSettings;
|
|
4
|
+
queryId?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DatabaseAdapter {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly namespace?: string;
|
|
9
|
+
query<T>(sql: string, params?: unknown[], options?: QueryExecutionOptions): Promise<T[]>;
|
|
10
|
+
stream?<T>(sql: string, params?: unknown[], options?: QueryExecutionOptions): Promise<ReadableStream<T[]>>;
|
|
11
|
+
render?(sql: string, params?: unknown[]): string;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=database-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-adapter.d.ts","sourceRoot":"","sources":["../../../src/core/adapters/database-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACzF,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3G,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;CAClD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache-manager.d.ts","sourceRoot":"","sources":["../../../src/core/cache/cache-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"cache-manager.d.ts","sourceRoot":"","sources":["../../../src/core/cache/cache-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AA4DnF,wBAAsB,gBAAgB,CACpC,MAAM,SAAS,gBAAgB,CAAC,MAAM,CAAC,EACvC,KAAK,SAAS,eAAe,EAE7B,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,EACpC,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CA4J5B"}
|
|
@@ -14,11 +14,10 @@ function deriveTags(builder) {
|
|
|
14
14
|
joins.forEach(join => tags.add(join.table));
|
|
15
15
|
return Array.from(tags);
|
|
16
16
|
}
|
|
17
|
-
async function logCacheHit({
|
|
18
|
-
const finalSQL = substituteParameters(sql, parameters);
|
|
17
|
+
async function logCacheHit({ renderSql, parameters, status, cacheKey, options, rowCount, ageMs, queryId }) {
|
|
19
18
|
const timestamp = Date.now();
|
|
20
19
|
logger.logQuery({
|
|
21
|
-
query:
|
|
20
|
+
query: renderSql,
|
|
22
21
|
parameters,
|
|
23
22
|
startTime: timestamp,
|
|
24
23
|
endTime: timestamp,
|
|
@@ -46,13 +45,15 @@ export async function executeWithCache(builder, options) {
|
|
|
46
45
|
}
|
|
47
46
|
const activeProvider = provider;
|
|
48
47
|
const { sql, parameters } = builder.toSQLWithParams();
|
|
48
|
+
const adapter = builder.getAdapter();
|
|
49
|
+
const renderSql = adapter.render ? adapter.render(sql, parameters) : substituteParameters(sql, parameters);
|
|
49
50
|
const tableName = builder.getTableName();
|
|
50
51
|
const namespace = mergedOptions.namespace || runtime.namespace;
|
|
51
52
|
const key = mergedOptions.key || computeCacheKey({
|
|
52
53
|
namespace,
|
|
53
54
|
sql,
|
|
54
55
|
parameters,
|
|
55
|
-
settings: builder.getConfig().settings
|
|
56
|
+
settings: builder.getConfig().settings,
|
|
56
57
|
version: runtime.versionTag,
|
|
57
58
|
tableName
|
|
58
59
|
});
|
|
@@ -82,7 +83,7 @@ export async function executeWithCache(builder, options) {
|
|
|
82
83
|
runtime.stats.staleHits += 1;
|
|
83
84
|
}
|
|
84
85
|
await logCacheHit({
|
|
85
|
-
|
|
86
|
+
renderSql,
|
|
86
87
|
parameters,
|
|
87
88
|
status,
|
|
88
89
|
cacheKey: key,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { QueryConfig } from '../../types/index.js';
|
|
2
|
+
import type { CompileQueryContext, SqlDialect } from './sql-dialect.js';
|
|
3
|
+
export declare class ClickHouseDialect implements SqlDialect {
|
|
4
|
+
readonly name = "clickhouse";
|
|
5
|
+
private formatter;
|
|
6
|
+
compileQuery(config: QueryConfig<any, any>, context: CompileQueryContext): string;
|
|
7
|
+
formatTimeInterval(column: string, interval: string, method: string): string;
|
|
8
|
+
formatSettings(settings: Record<string, unknown>): string;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=clickhouse-dialect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickhouse-dialect.d.ts","sourceRoot":"","sources":["../../../src/core/dialects/clickhouse-dialect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAExE,qBAAa,iBAAkB,YAAW,UAAU;IAClD,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,OAAO,CAAC,SAAS,CAAsB;IAEvC,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM;IAyCjF,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAQ5E,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;CAK1D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SQLFormatter } from '../formatters/sql-formatter.js';
|
|
2
|
+
export class ClickHouseDialect {
|
|
3
|
+
name = 'clickhouse';
|
|
4
|
+
formatter = new SQLFormatter();
|
|
5
|
+
compileQuery(config, context) {
|
|
6
|
+
const parts = [];
|
|
7
|
+
if (config.ctes?.length) {
|
|
8
|
+
parts.push(`WITH ${config.ctes.join(', ')}`);
|
|
9
|
+
}
|
|
10
|
+
parts.push(`SELECT ${this.formatter.formatSelect(config)}`);
|
|
11
|
+
parts.push(`FROM ${context.tableName}`);
|
|
12
|
+
if (config.joins?.length) {
|
|
13
|
+
parts.push(this.formatter.formatJoins(config));
|
|
14
|
+
}
|
|
15
|
+
if (config.where?.length) {
|
|
16
|
+
parts.push(`WHERE ${this.formatter.formatWhere(config)}`);
|
|
17
|
+
}
|
|
18
|
+
if (config.groupBy?.length) {
|
|
19
|
+
parts.push(`GROUP BY ${this.formatter.formatGroupBy(config)}`);
|
|
20
|
+
}
|
|
21
|
+
if (config.having?.length) {
|
|
22
|
+
parts.push(`HAVING ${config.having.join(' AND ')}`);
|
|
23
|
+
}
|
|
24
|
+
if (config.orderBy?.length) {
|
|
25
|
+
const orderBy = config.orderBy
|
|
26
|
+
.map(({ column, direction }) => `${String(column)} ${direction}`.trim())
|
|
27
|
+
.join(', ');
|
|
28
|
+
parts.push(`ORDER BY ${orderBy}`);
|
|
29
|
+
}
|
|
30
|
+
if (config.limit) {
|
|
31
|
+
const offsetClause = config.offset ? `OFFSET ${config.offset}` : '';
|
|
32
|
+
parts.push(`LIMIT ${config.limit} ${offsetClause}`);
|
|
33
|
+
}
|
|
34
|
+
return parts.join(' ').trim();
|
|
35
|
+
}
|
|
36
|
+
formatTimeInterval(column, interval, method) {
|
|
37
|
+
if (method === 'toStartOfInterval') {
|
|
38
|
+
return `${method}(${column}, INTERVAL ${interval})`;
|
|
39
|
+
}
|
|
40
|
+
return `${method}(${column})`;
|
|
41
|
+
}
|
|
42
|
+
formatSettings(settings) {
|
|
43
|
+
return Object.entries(settings)
|
|
44
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
45
|
+
.join(', ');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { QueryConfig } from '../../types/index.js';
|
|
2
|
+
export interface CompileQueryContext {
|
|
3
|
+
tableName: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SqlDialect {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
compileQuery(config: QueryConfig<any, any>, context: CompileQueryContext): string;
|
|
8
|
+
formatTimeInterval(column: string, interval: string, method: string): string;
|
|
9
|
+
formatSettings(settings: Record<string, unknown>): string;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=sql-dialect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-dialect.d.ts","sourceRoot":"","sources":["../../../src/core/dialects/sql-dialect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAAC;IAClF,kBAAkB,CAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,CAAC;IACV,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC;CAC3D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -20,7 +20,7 @@ export declare class AggregationFeature<Schema extends SchemaDefinition<Schema>,
|
|
|
20
20
|
parameters?: any[];
|
|
21
21
|
ctes?: string[];
|
|
22
22
|
unionQueries?: string[];
|
|
23
|
-
settings?:
|
|
23
|
+
settings?: import("@clickhouse/client-common").ClickHouseSettings;
|
|
24
24
|
};
|
|
25
25
|
count(column: string, alias: string): {
|
|
26
26
|
select: string[];
|
|
@@ -38,7 +38,7 @@ export declare class AggregationFeature<Schema extends SchemaDefinition<Schema>,
|
|
|
38
38
|
parameters?: any[];
|
|
39
39
|
ctes?: string[];
|
|
40
40
|
unionQueries?: string[];
|
|
41
|
-
settings?:
|
|
41
|
+
settings?: import("@clickhouse/client-common").ClickHouseSettings;
|
|
42
42
|
};
|
|
43
43
|
avg(column: string, alias: string): {
|
|
44
44
|
select: string[];
|
|
@@ -56,7 +56,7 @@ export declare class AggregationFeature<Schema extends SchemaDefinition<Schema>,
|
|
|
56
56
|
parameters?: any[];
|
|
57
57
|
ctes?: string[];
|
|
58
58
|
unionQueries?: string[];
|
|
59
|
-
settings?:
|
|
59
|
+
settings?: import("@clickhouse/client-common").ClickHouseSettings;
|
|
60
60
|
};
|
|
61
61
|
min(column: string, alias: string): {
|
|
62
62
|
select: string[];
|
|
@@ -74,7 +74,7 @@ export declare class AggregationFeature<Schema extends SchemaDefinition<Schema>,
|
|
|
74
74
|
parameters?: any[];
|
|
75
75
|
ctes?: string[];
|
|
76
76
|
unionQueries?: string[];
|
|
77
|
-
settings?:
|
|
77
|
+
settings?: import("@clickhouse/client-common").ClickHouseSettings;
|
|
78
78
|
};
|
|
79
79
|
max(column: string, alias: string): {
|
|
80
80
|
select: string[];
|
|
@@ -92,7 +92,7 @@ export declare class AggregationFeature<Schema extends SchemaDefinition<Schema>,
|
|
|
92
92
|
parameters?: any[];
|
|
93
93
|
ctes?: string[];
|
|
94
94
|
unionQueries?: string[];
|
|
95
|
-
settings?:
|
|
95
|
+
settings?: import("@clickhouse/client-common").ClickHouseSettings;
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
98
|
//# sourceMappingURL=aggregations.d.ts.map
|