@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.
Files changed (128) hide show
  1. package/README.md +19 -14
  2. package/dist/cli/generate-types.js +3 -88
  3. package/dist/cli/type-parsing.js +124 -0
  4. package/dist/core/adapters/clickhouse-adapter.d.ts +14 -0
  5. package/dist/core/adapters/clickhouse-adapter.d.ts.map +1 -0
  6. package/dist/core/adapters/clickhouse-adapter.js +58 -0
  7. package/dist/core/adapters/database-adapter.d.ts +13 -0
  8. package/dist/core/adapters/database-adapter.d.ts.map +1 -0
  9. package/dist/core/adapters/database-adapter.js +1 -0
  10. package/dist/core/cache/cache-manager.d.ts.map +1 -1
  11. package/dist/core/cache/cache-manager.js +6 -5
  12. package/dist/core/dialects/clickhouse-dialect.d.ts +10 -0
  13. package/dist/core/dialects/clickhouse-dialect.d.ts.map +1 -0
  14. package/dist/core/dialects/clickhouse-dialect.js +47 -0
  15. package/dist/core/dialects/sql-dialect.d.ts +11 -0
  16. package/dist/core/dialects/sql-dialect.d.ts.map +1 -0
  17. package/dist/core/dialects/sql-dialect.js +1 -0
  18. package/dist/core/features/aggregations.d.ts +5 -5
  19. package/dist/core/features/analytics.d.ts +804 -5
  20. package/dist/core/features/analytics.d.ts.map +1 -1
  21. package/dist/core/features/analytics.js +6 -9
  22. package/dist/core/features/executor.d.ts.map +1 -1
  23. package/dist/core/features/executor.js +26 -53
  24. package/dist/core/features/filtering.d.ts +5 -5
  25. package/dist/core/features/joins.d.ts +1 -1
  26. package/dist/core/features/query-modifiers.d.ts +6 -6
  27. package/dist/core/query-builder.d.ts +17 -6
  28. package/dist/core/query-builder.d.ts.map +1 -1
  29. package/dist/core/query-builder.js +25 -32
  30. package/dist/core/tests/integration/setup.d.ts +3 -1
  31. package/dist/core/tests/integration/setup.d.ts.map +1 -1
  32. package/dist/core/tests/test-utils.d.ts.map +1 -1
  33. package/dist/core/tests/test-utils.js +12 -2
  34. package/dist/core/types/select-types.d.ts +1 -1
  35. package/dist/core/types/select-types.d.ts.map +1 -1
  36. package/dist/core/utils/streaming-helpers.d.ts.map +1 -1
  37. package/dist/core/utils/streaming-helpers.js +8 -0
  38. package/dist/core/utils.d.ts.map +1 -1
  39. package/dist/core/utils.js +3 -0
  40. package/dist/dataset/definition.d.ts +135 -0
  41. package/dist/dataset/definition.d.ts.map +1 -0
  42. package/dist/dataset/definition.js +265 -0
  43. package/dist/dataset/helpers.d.ts +136 -0
  44. package/dist/dataset/helpers.d.ts.map +1 -0
  45. package/dist/dataset/helpers.js +189 -0
  46. package/dist/dataset/index.d.ts +51 -0
  47. package/dist/dataset/index.d.ts.map +1 -0
  48. package/dist/dataset/index.js +59 -0
  49. package/dist/dataset/introspection.d.ts +133 -0
  50. package/dist/dataset/introspection.d.ts.map +1 -0
  51. package/dist/dataset/introspection.js +239 -0
  52. package/dist/dataset/sql-tag.d.ts +51 -0
  53. package/dist/dataset/sql-tag.d.ts.map +1 -0
  54. package/dist/dataset/sql-tag.js +86 -0
  55. package/dist/dataset/types.d.ts +300 -0
  56. package/dist/dataset/types.d.ts.map +1 -0
  57. package/dist/dataset/types.js +11 -0
  58. package/dist/index.d.ts +23 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +26 -15
  61. package/dist/migrations/config/index.d.ts +3 -0
  62. package/dist/migrations/config/index.d.ts.map +1 -0
  63. package/dist/migrations/config/index.js +1 -0
  64. package/dist/migrations/config/types.d.ts +45 -0
  65. package/dist/migrations/config/types.d.ts.map +1 -0
  66. package/dist/migrations/config/types.js +28 -0
  67. package/dist/migrations/diff/diff.d.ts +11 -0
  68. package/dist/migrations/diff/diff.d.ts.map +1 -0
  69. package/dist/migrations/diff/diff.js +240 -0
  70. package/dist/migrations/diff/index.d.ts +3 -0
  71. package/dist/migrations/diff/index.d.ts.map +1 -0
  72. package/dist/migrations/diff/index.js +1 -0
  73. package/dist/migrations/diff/types.d.ts +74 -0
  74. package/dist/migrations/diff/types.d.ts.map +1 -0
  75. package/dist/migrations/diff/types.js +1 -0
  76. package/dist/migrations/plan/index.d.ts +3 -0
  77. package/dist/migrations/plan/index.d.ts.map +1 -0
  78. package/dist/migrations/plan/index.js +1 -0
  79. package/dist/migrations/plan/plan.d.ts +12 -0
  80. package/dist/migrations/plan/plan.d.ts.map +1 -0
  81. package/dist/migrations/plan/plan.js +416 -0
  82. package/dist/migrations/plan/types.d.ts +93 -0
  83. package/dist/migrations/plan/types.d.ts.map +1 -0
  84. package/dist/migrations/plan/types.js +1 -0
  85. package/dist/migrations/schema/column.d.ts +71 -0
  86. package/dist/migrations/schema/column.d.ts.map +1 -0
  87. package/dist/migrations/schema/column.js +123 -0
  88. package/dist/migrations/schema/define.d.ts +24 -0
  89. package/dist/migrations/schema/define.d.ts.map +1 -0
  90. package/dist/migrations/schema/define.js +47 -0
  91. package/dist/migrations/schema/index.d.ts +4 -0
  92. package/dist/migrations/schema/index.d.ts.map +1 -0
  93. package/dist/migrations/schema/index.js +2 -0
  94. package/dist/migrations/schema/types.d.ts +74 -0
  95. package/dist/migrations/schema/types.d.ts.map +1 -0
  96. package/dist/migrations/schema/types.js +1 -0
  97. package/dist/migrations/snapshot/index.d.ts +3 -0
  98. package/dist/migrations/snapshot/index.d.ts.map +1 -0
  99. package/dist/migrations/snapshot/index.js +1 -0
  100. package/dist/migrations/snapshot/serialize.d.ts +21 -0
  101. package/dist/migrations/snapshot/serialize.d.ts.map +1 -0
  102. package/dist/migrations/snapshot/serialize.js +127 -0
  103. package/dist/migrations/snapshot/types.d.ts +47 -0
  104. package/dist/migrations/snapshot/types.d.ts.map +1 -0
  105. package/dist/migrations/snapshot/types.js +1 -0
  106. package/dist/migrations/sql/index.d.ts +4 -0
  107. package/dist/migrations/sql/index.d.ts.map +1 -0
  108. package/dist/migrations/sql/index.js +2 -0
  109. package/dist/migrations/sql/render.d.ts +10 -0
  110. package/dist/migrations/sql/render.d.ts.map +1 -0
  111. package/dist/migrations/sql/render.js +347 -0
  112. package/dist/migrations/sql/types.d.ts +53 -0
  113. package/dist/migrations/sql/types.d.ts.map +1 -0
  114. package/dist/migrations/sql/types.js +1 -0
  115. package/dist/migrations/sql/write.d.ts +10 -0
  116. package/dist/migrations/sql/write.d.ts.map +1 -0
  117. package/dist/migrations/sql/write.js +35 -0
  118. package/dist/types/base.d.ts +2 -1
  119. package/dist/types/base.d.ts.map +1 -1
  120. package/dist/types/clickhouse-types.d.ts +7 -2
  121. package/dist/types/clickhouse-types.d.ts.map +1 -1
  122. package/dist/types/index.d.ts +1 -0
  123. package/dist/types/index.d.ts.map +1 -1
  124. package/dist/types/index.js +1 -0
  125. package/dist/types/type-helpers.d.ts +7 -0
  126. package/dist/types/type-helpers.d.ts.map +1 -0
  127. package/dist/types/type-helpers.js +1 -0
  128. 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 typescript-first library for building type-safe dashboards with ClickHouse</p>
3
+ <p>A TypeScript-first query builder for ClickHouse and the foundation of the hypequery path.</p>
4
4
 
5
5
  [![GitHub license](https://img.shields.io/github/license/hypequery/hypequery)](https://github.com/hypequery/hypequery/blob/main/LICENSE)
6
6
  [![npm version](https://badge.fury.io/js/@hypequery%2Fclickhouse.svg)](https://badge.fury.io/js/@hypequery%2Fclickhouse)
@@ -10,7 +10,7 @@
10
10
 
11
11
  ## Overview
12
12
 
13
- hypequery is a typescript-first query builder for ClickHouse designed specifically for building type-safe analytics dashboards. Unlike generic SQL query builders, hypequery understands your ClickHouse schema and provides full type checking, making it ideal for data-intensive applications.
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/features/caching).
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
- hypequery provides a CLI tool to generate TypeScript types from your ClickHouse schema:
140
+ Use the hypequery CLI to generate TypeScript types from your ClickHouse schema:
134
141
 
135
142
  ```bash
136
- # Install globally (optional)
137
- npm install -g @hypequery/clickhouse
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 our [documentation site](https://hypequery.com/docs).
285
+ For detailed documentation and examples, visit the main docs flow.
282
286
 
283
- - [Getting Started](https://hypequery.com/docs/installation)
284
- - [Query Building](https://hypequery.com/docs/guides/query-building)
285
- - [Filtering](https://hypequery.com/docs/guides/filtering)
286
- - [API Reference](https://hypequery.com/docs/reference/api)
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;AA6DnF,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,CA0J5B"}
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({ sql, parameters, status, cacheKey, options, rowCount, ageMs, queryId }) {
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: finalSQL,
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 ? { settings: builder.getConfig().settings } : undefined,
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
- sql,
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?: string;
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?: string;
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?: string;
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?: string;
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?: string;
95
+ settings?: import("@clickhouse/client-common").ClickHouseSettings;
96
96
  };
97
97
  }
98
98
  //# sourceMappingURL=aggregations.d.ts.map