@hypequery/clickhouse 1.6.1 → 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/dist/cli/generate-types.js +3 -81
- package/dist/cli/type-parsing.js +124 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.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/sql/index.d.ts +1 -1
- package/dist/migrations/sql/index.d.ts.map +1 -1
- package/dist/migrations/sql/render.d.ts +2 -3
- package/dist/migrations/sql/render.d.ts.map +1 -1
- package/dist/migrations/sql/render.js +38 -25
- package/dist/migrations/sql/types.d.ts +6 -1
- package/dist/migrations/sql/types.d.ts.map +1 -1
- package/dist/migrations/sql/write.d.ts +2 -1
- package/dist/migrations/sql/write.d.ts.map +1 -1
- package/dist/migrations/sql/write.js +5 -1
- package/dist/types/clickhouse-types.d.ts +5 -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 +1 -1
|
@@ -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,87 +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
|
-
export 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 value types
|
|
48
|
-
let valueTsType = 'unknown';
|
|
49
|
-
if (valueType.startsWith('Array(')) {
|
|
50
|
-
const innerType = valueType.slice(6, -1);
|
|
51
|
-
valueTsType = `Array<${clickhouseToTsType(innerType)}>`;
|
|
52
|
-
} else if (valueType.startsWith('Nullable(')) {
|
|
53
|
-
const innerType = valueType.slice(9, -1);
|
|
54
|
-
valueTsType = `${clickhouseToTsType(innerType)} | null`;
|
|
55
|
-
} else {
|
|
56
|
-
valueTsType = clickhouseToTsType(valueType);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// JSON object keys are strings even when ClickHouse map keys are numeric.
|
|
60
|
-
return `Record<string, ${valueTsType}>`;
|
|
61
|
-
}
|
|
62
|
-
return 'Record<string, unknown>';
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
switch (type.toLowerCase()) {
|
|
66
|
-
case 'string':
|
|
67
|
-
case 'fixedstring':
|
|
68
|
-
return 'string';
|
|
69
|
-
case 'int8':
|
|
70
|
-
case 'int16':
|
|
71
|
-
case 'int32':
|
|
72
|
-
case 'uint8':
|
|
73
|
-
case 'uint16':
|
|
74
|
-
case 'uint32':
|
|
75
|
-
return 'number';
|
|
76
|
-
case 'int64':
|
|
77
|
-
case 'uint64':
|
|
78
|
-
case 'uint128':
|
|
79
|
-
case 'uint256':
|
|
80
|
-
case 'int128':
|
|
81
|
-
case 'int256':
|
|
82
|
-
return 'string';
|
|
83
|
-
case 'float32':
|
|
84
|
-
case 'float64':
|
|
85
|
-
case 'decimal':
|
|
86
|
-
return 'number';
|
|
87
|
-
case 'datetime':
|
|
88
|
-
case 'datetime64':
|
|
89
|
-
return 'string'; // Use string for datetime
|
|
90
|
-
case 'date':
|
|
91
|
-
case 'date32':
|
|
92
|
-
return 'string'; // Use string for date
|
|
93
|
-
case 'bool':
|
|
94
|
-
case 'boolean':
|
|
95
|
-
return 'boolean';
|
|
96
|
-
default:
|
|
97
|
-
// For complex types or unknown types, return string as a safe default
|
|
98
|
-
return 'string';
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
24
|
/**
|
|
103
25
|
* Generates TypeScript type definitions from the ClickHouse database schema
|
|
104
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
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -31,11 +31,13 @@ export { introspectDimension, introspectMetric, getDatasetSchema, getAllDatasetS
|
|
|
31
31
|
export { defineConfig, resolveClickHouseConfig, DEFAULT_MIGRATIONS_OUT_DIR, DEFAULT_MIGRATIONS_PREFIX, DEFAULT_MIGRATIONS_TABLE, } from './migrations/config/index.js';
|
|
32
32
|
export { column, ClickHouseColumnBuilder, defineMaterializedView, defineSchema, defineTable, } from './migrations/schema/index.js';
|
|
33
33
|
export { diffSnapshots, } from './migrations/diff/index.js';
|
|
34
|
+
export { createMigrationPlan, isMigrationPlan, } from './migrations/plan/index.js';
|
|
34
35
|
export { serializeSchemaToSnapshot, snapshotToStableJson, hashSnapshot, } from './migrations/snapshot/index.js';
|
|
35
36
|
export { renderMigrationArtifacts, writeMigrationArtifacts, } from './migrations/sql/index.js';
|
|
36
37
|
export type { ClickHouseClusterConfig, ClickHouseMigrationDbCredentials, ClickHouseMigrationDirectoryConfig, HypequeryClickHouseConfig, MigrationFilePrefix, ResolvedHypequeryClickHouseConfig, } from './migrations/config/index.js';
|
|
37
38
|
export type { ClickHouseColumnDefinition, ClickHouseColumnBuilderLike, ClickHouseColumnDefaultValue, ClickHouseColumnType, ClickHouseDefaultInput, ClickHouseLowCardinalityColumnType, ClickHouseLiteralDefaultValue, ClickHouseMaterializedViewDefinition, ClickHouseMaterializedViewInputDefinition, ClickHouseNamedColumnType, ClickHouseNullableColumnType, ClickHouseSqlDefaultValue, ClickHouseSchemaAst, ClickHouseSchemaDefinition, ClickHouseSqlExpression, ClickHouseTableDefinition, ClickHouseTableInputDefinition, ClickHouseTableEngine, } from './migrations/schema/index.js';
|
|
38
39
|
export type { AddColumnOperation, AlterTableWithDependentViewsOperation, CreateMaterializedViewOperation, CreateTableOperation, DiffWarning, DropColumnOperation, DropMaterializedViewOperation, DropTableOperation, MigrationOperation, ModifyColumnDefaultOperation, ModifyColumnTypeOperation, RecreateMaterializedViewOperation, SnapshotDiffResult, TableMutationOperation, UnsupportedChange, } from './migrations/diff/index.js';
|
|
39
|
-
export type {
|
|
40
|
+
export type { ClickHouseMigrationSyncSetting, ClickHouseMigrationPlanContext, ClickHouseTableCostStats, CreateMigrationPlanOptions, MigrationPlanAnalyzer, MigrationPlanAnalyzerContext, MigrationPlanAnalyzerResult, MigrationOperationClassification, MigrationOperationCostEstimate, MigrationPlan, MigrationPlanBlocker, MigrationPlanConfirmation, MigrationPlanDiagnostic, MigrationPlanDiagnosticLevel, MigrationPlanInput, PlannedMigrationOperation, } from './migrations/plan/index.js';
|
|
41
|
+
export type { MigrationMeta, RenderMigrationArtifactsInput, RenderMigrationArtifactsOptions, RenderMigrationArtifactsResult, WriteMigrationArtifactsOptions, WriteMigrationArtifactsResult, } from './migrations/sql/index.js';
|
|
40
42
|
export type { Snapshot, SnapshotColumn, SnapshotColumnDefault, SnapshotDependencyEdge, SnapshotMaterializedView, SnapshotTable, SnapshotTableEngine, } from './migrations/snapshot/index.js';
|
|
41
43
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -27,5 +27,6 @@ export { introspectDimension, introspectMetric, getDatasetSchema, getAllDatasetS
|
|
|
27
27
|
export { defineConfig, resolveClickHouseConfig, DEFAULT_MIGRATIONS_OUT_DIR, DEFAULT_MIGRATIONS_PREFIX, DEFAULT_MIGRATIONS_TABLE, } from './migrations/config/index.js';
|
|
28
28
|
export { column, ClickHouseColumnBuilder, defineMaterializedView, defineSchema, defineTable, } from './migrations/schema/index.js';
|
|
29
29
|
export { diffSnapshots, } from './migrations/diff/index.js';
|
|
30
|
+
export { createMigrationPlan, isMigrationPlan, } from './migrations/plan/index.js';
|
|
30
31
|
export { serializeSchemaToSnapshot, snapshotToStableJson, hashSnapshot, } from './migrations/snapshot/index.js';
|
|
31
32
|
export { renderMigrationArtifacts, writeMigrationArtifacts, } from './migrations/sql/index.js';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createMigrationPlan, isMigrationPlan } from './plan.js';
|
|
2
|
+
export type { ClickHouseMigrationSyncSetting, ClickHouseMigrationPlanContext, ClickHouseTableCostStats, CreateMigrationPlanOptions, MigrationPlanAnalyzer, MigrationPlanAnalyzerContext, MigrationPlanAnalyzerResult, MigrationOperationClassification, MigrationOperationCostEstimate, MigrationPlan, MigrationPlanBlocker, MigrationPlanConfirmation, MigrationPlanDiagnostic, MigrationPlanDiagnosticLevel, MigrationPlanInput, PlannedMigrationOperation, } from './types.js';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrations/plan/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjE,YAAY,EACV,8BAA8B,EAC9B,8BAA8B,EAC9B,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,4BAA4B,EAC5B,2BAA2B,EAC3B,gCAAgC,EAChC,8BAA8B,EAC9B,aAAa,EACb,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,EACvB,4BAA4B,EAC5B,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createMigrationPlan, isMigrationPlan } from './plan.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SnapshotDiffResult } from '../diff/types.js';
|
|
2
|
+
import type { CreateMigrationPlanOptions, MigrationPlan, MigrationPlanInput } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Converts a raw snapshot diff into an explicit migration plan.
|
|
5
|
+
*
|
|
6
|
+
* The initial planner is intentionally static: it classifies operations and
|
|
7
|
+
* carries diagnostics/blockers without querying a live ClickHouse instance.
|
|
8
|
+
* Later phases can enrich this plan with system-table cost estimates.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createMigrationPlan(diff: SnapshotDiffResult, options?: CreateMigrationPlanOptions): MigrationPlan;
|
|
11
|
+
export declare function isMigrationPlan(input: MigrationPlanInput): input is MigrationPlan;
|
|
12
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/migrations/plan/plan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAIV,0BAA0B,EAG1B,aAAa,EAMb,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,kBAAkB,EACxB,OAAO,GAAE,0BAA+B,GACvC,aAAa,CAqFf;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,kBAAkB,GAAG,KAAK,IAAI,aAAa,CAMjF"}
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a raw snapshot diff into an explicit migration plan.
|
|
3
|
+
*
|
|
4
|
+
* The initial planner is intentionally static: it classifies operations and
|
|
5
|
+
* carries diagnostics/blockers without querying a live ClickHouse instance.
|
|
6
|
+
* Later phases can enrich this plan with system-table cost estimates.
|
|
7
|
+
*/
|
|
8
|
+
export function createMigrationPlan(diff, options = {}) {
|
|
9
|
+
const plannedOperations = diff.operations.map((operation, operationIndex) => planOperation(operation, operationIndex, diff, options));
|
|
10
|
+
const blockerDiagnostics = diff.unsupportedChanges.map((change) => ({
|
|
11
|
+
level: 'error',
|
|
12
|
+
kind: change.kind,
|
|
13
|
+
message: change.message,
|
|
14
|
+
}));
|
|
15
|
+
const warningDiagnostics = diff.warnings.map((warning) => ({
|
|
16
|
+
level: 'warning',
|
|
17
|
+
kind: warning.kind,
|
|
18
|
+
message: warning.message,
|
|
19
|
+
}));
|
|
20
|
+
const operationDiagnostics = plannedOperations.flatMap(operation => operation.diagnostics);
|
|
21
|
+
const requiredConfirmations = plannedOperations.flatMap(operation => operation.requiredConfirmations);
|
|
22
|
+
const recommendedSyncSettings = dedupeSyncSettings(plannedOperations.flatMap(operation => operation.recommendedSyncSettings));
|
|
23
|
+
const staticBlockers = plannedOperations.flatMap((operation, operationIndex) => operation.classification === 'forbidden'
|
|
24
|
+
? [{
|
|
25
|
+
kind: 'ForbiddenOperation',
|
|
26
|
+
operationIndex,
|
|
27
|
+
message: forbiddenOperationMessage(operation.operation),
|
|
28
|
+
}]
|
|
29
|
+
: []);
|
|
30
|
+
const unsupportedBlockers = diff.unsupportedChanges.map(change => ({
|
|
31
|
+
kind: change.kind,
|
|
32
|
+
message: change.message,
|
|
33
|
+
tableName: change.tableName,
|
|
34
|
+
...(change.columnName !== undefined ? { columnName: change.columnName } : {}),
|
|
35
|
+
}));
|
|
36
|
+
const plan = {
|
|
37
|
+
previousSnapshot: diff.previousSnapshot,
|
|
38
|
+
nextSnapshot: diff.nextSnapshot,
|
|
39
|
+
sourceSnapshotHash: diff.previousSnapshot.contentHash,
|
|
40
|
+
targetSnapshotHash: diff.nextSnapshot.contentHash,
|
|
41
|
+
operations: plannedOperations,
|
|
42
|
+
diagnostics: [
|
|
43
|
+
...blockerDiagnostics,
|
|
44
|
+
...warningDiagnostics,
|
|
45
|
+
...operationDiagnostics,
|
|
46
|
+
],
|
|
47
|
+
blockers: [
|
|
48
|
+
...unsupportedBlockers,
|
|
49
|
+
...staticBlockers,
|
|
50
|
+
],
|
|
51
|
+
requiredConfirmations,
|
|
52
|
+
recommendedSyncSettings,
|
|
53
|
+
// Backward-compatible alias. These settings are recommendations for the future executor,
|
|
54
|
+
// not proof that generated SQL has applied them.
|
|
55
|
+
requiredSyncSettings: recommendedSyncSettings,
|
|
56
|
+
};
|
|
57
|
+
const analyzerResult = runAnalyzers(plan, diff, options.analyzers ?? [], options.context);
|
|
58
|
+
if (analyzerResult.diagnostics.length === 0 &&
|
|
59
|
+
analyzerResult.blockers.length === 0 &&
|
|
60
|
+
analyzerResult.confirmations.length === 0) {
|
|
61
|
+
return plan;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
...plan,
|
|
65
|
+
diagnostics: [
|
|
66
|
+
...plan.diagnostics,
|
|
67
|
+
...analyzerResult.diagnostics,
|
|
68
|
+
],
|
|
69
|
+
blockers: [
|
|
70
|
+
...plan.blockers,
|
|
71
|
+
...analyzerResult.blockers,
|
|
72
|
+
],
|
|
73
|
+
requiredConfirmations: [
|
|
74
|
+
...plan.requiredConfirmations,
|
|
75
|
+
...analyzerResult.confirmations,
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function isMigrationPlan(input) {
|
|
80
|
+
return 'blockers' in input &&
|
|
81
|
+
'diagnostics' in input &&
|
|
82
|
+
'requiredConfirmations' in input &&
|
|
83
|
+
Array.isArray(input.operations) &&
|
|
84
|
+
input.operations.every(operation => 'operation' in operation && 'classification' in operation);
|
|
85
|
+
}
|
|
86
|
+
function planOperation(operation, operationIndex, diff, options) {
|
|
87
|
+
const classification = classifyOperation(operation, diff.previousSnapshot.tables);
|
|
88
|
+
const costEstimate = estimateOperationCost(operation, options.context);
|
|
89
|
+
const diagnostics = diagnosticsForOperation(operation, classification, operationIndex, costEstimate, options.context);
|
|
90
|
+
const requiredConfirmations = confirmationsForOperation(operation, classification, operationIndex, options);
|
|
91
|
+
return {
|
|
92
|
+
operation,
|
|
93
|
+
classification,
|
|
94
|
+
costEstimate,
|
|
95
|
+
diagnostics,
|
|
96
|
+
requiredConfirmations,
|
|
97
|
+
recommendedSyncSettings: syncSettingsForOperation(operation, classification),
|
|
98
|
+
requiredSyncSettings: syncSettingsForOperation(operation, classification),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function classifyOperation(operation, previousTables) {
|
|
102
|
+
switch (operation.kind) {
|
|
103
|
+
case 'ModifyColumnType':
|
|
104
|
+
return isKeyColumn(previousTables, operation.tableName, operation.columnName)
|
|
105
|
+
? 'forbidden'
|
|
106
|
+
: 'mutation';
|
|
107
|
+
case 'AlterTableWithDependentViews':
|
|
108
|
+
return classifyAlterTableWithDependentViews(operation, previousTables);
|
|
109
|
+
case 'DropColumn':
|
|
110
|
+
return isKeyColumn(previousTables, operation.tableName, operation.columnName)
|
|
111
|
+
? 'forbidden'
|
|
112
|
+
: 'metadata';
|
|
113
|
+
case 'AddColumn':
|
|
114
|
+
case 'CreateMaterializedView':
|
|
115
|
+
case 'CreateTable':
|
|
116
|
+
case 'DropMaterializedView':
|
|
117
|
+
case 'DropTable':
|
|
118
|
+
case 'ModifyColumnDefault':
|
|
119
|
+
case 'RecreateMaterializedView':
|
|
120
|
+
return 'metadata';
|
|
121
|
+
default: {
|
|
122
|
+
const exhaustiveCheck = operation;
|
|
123
|
+
return exhaustiveCheck;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function classifyAlterTableWithDependentViews(operation, previousTables) {
|
|
128
|
+
const nestedClassifications = operation.operations.map(nestedOperation => classifyTableMutationOperation(nestedOperation, previousTables));
|
|
129
|
+
if (nestedClassifications.includes('forbidden')) {
|
|
130
|
+
return 'forbidden';
|
|
131
|
+
}
|
|
132
|
+
if (nestedClassifications.includes('mutation')) {
|
|
133
|
+
return 'mutation';
|
|
134
|
+
}
|
|
135
|
+
if (nestedClassifications.includes('data-copy')) {
|
|
136
|
+
return 'data-copy';
|
|
137
|
+
}
|
|
138
|
+
return 'metadata';
|
|
139
|
+
}
|
|
140
|
+
function classifyTableMutationOperation(operation, previousTables) {
|
|
141
|
+
if ((operation.kind === 'DropColumn' || operation.kind === 'ModifyColumnType') &&
|
|
142
|
+
isKeyColumn(previousTables, operation.tableName, operation.columnName)) {
|
|
143
|
+
return 'forbidden';
|
|
144
|
+
}
|
|
145
|
+
return operation.kind === 'ModifyColumnType' ? 'mutation' : 'metadata';
|
|
146
|
+
}
|
|
147
|
+
function diagnosticsForOperation(operation, classification, operationIndex, costEstimate, context) {
|
|
148
|
+
const diagnostics = [];
|
|
149
|
+
if (classification === 'mutation') {
|
|
150
|
+
diagnostics.push({
|
|
151
|
+
level: 'warning',
|
|
152
|
+
kind: 'MutationOperation',
|
|
153
|
+
operationIndex,
|
|
154
|
+
message: `Operation "${operation.kind}" may trigger a ClickHouse mutation. ` +
|
|
155
|
+
'Review table size and mutation impact before applying.',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (classification === 'forbidden') {
|
|
159
|
+
diagnostics.push({
|
|
160
|
+
level: 'error',
|
|
161
|
+
kind: 'ForbiddenOperation',
|
|
162
|
+
operationIndex,
|
|
163
|
+
message: forbiddenOperationMessage(operation),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (operation.kind === 'DropTable') {
|
|
167
|
+
diagnostics.push({
|
|
168
|
+
level: 'warning',
|
|
169
|
+
kind: 'DestructiveDropTable',
|
|
170
|
+
operationIndex,
|
|
171
|
+
message: `Operation drops table "${operation.tableName}".`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (operation.kind === 'DropColumn') {
|
|
175
|
+
diagnostics.push({
|
|
176
|
+
level: 'warning',
|
|
177
|
+
kind: 'DestructiveDropColumn',
|
|
178
|
+
operationIndex,
|
|
179
|
+
message: `Operation drops column "${operation.tableName}.${operation.columnName}".`,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
diagnostics.push(...costDiagnosticsForOperation(operation, classification, operationIndex, costEstimate, context));
|
|
183
|
+
return diagnostics;
|
|
184
|
+
}
|
|
185
|
+
function confirmationsForOperation(operation, classification, operationIndex, options) {
|
|
186
|
+
if (classification !== 'mutation' || options.requireConfirmationForMutations === false) {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
return [
|
|
190
|
+
{
|
|
191
|
+
kind: 'MutationRequiresConfirmation',
|
|
192
|
+
operationIndex,
|
|
193
|
+
message: `Operation "${operation.kind}" is classified as a mutation and should require explicit confirmation.`,
|
|
194
|
+
},
|
|
195
|
+
];
|
|
196
|
+
}
|
|
197
|
+
function syncSettingsForOperation(operation, classification) {
|
|
198
|
+
if (classification === 'forbidden') {
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
const settings = [];
|
|
202
|
+
if (operation.kind !== 'CreateTable' && operation.kind !== 'CreateMaterializedView') {
|
|
203
|
+
settings.push({
|
|
204
|
+
name: 'alter_sync',
|
|
205
|
+
value: 2,
|
|
206
|
+
reason: 'Wait for ClickHouse ALTER/DDL operations to finish on active replicas where supported.',
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (classification === 'mutation') {
|
|
210
|
+
settings.push({
|
|
211
|
+
name: 'mutations_sync',
|
|
212
|
+
value: 2,
|
|
213
|
+
reason: 'Wait for mutation-triggering ALTER operations to finish before marking the step complete.',
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return settings;
|
|
217
|
+
}
|
|
218
|
+
function dedupeSyncSettings(settings) {
|
|
219
|
+
const seen = new Set();
|
|
220
|
+
const deduped = [];
|
|
221
|
+
for (const setting of settings) {
|
|
222
|
+
const key = `${setting.name}:${setting.value}`;
|
|
223
|
+
if (seen.has(key)) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
seen.add(key);
|
|
227
|
+
deduped.push(setting);
|
|
228
|
+
}
|
|
229
|
+
return deduped;
|
|
230
|
+
}
|
|
231
|
+
function runAnalyzers(plan, diff, analyzers, context) {
|
|
232
|
+
const results = analyzers.map((analyzer, index) => {
|
|
233
|
+
try {
|
|
234
|
+
return analyzer(plan, { diff, clickhouse: context });
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
238
|
+
return {
|
|
239
|
+
diagnostics: [{
|
|
240
|
+
level: 'error',
|
|
241
|
+
kind: 'AnalyzerError',
|
|
242
|
+
message: `Analyzer at index ${index} failed: ${message}`,
|
|
243
|
+
}],
|
|
244
|
+
blockers: [{
|
|
245
|
+
kind: 'AnalyzerError',
|
|
246
|
+
message: `Analyzer at index ${index} failed: ${message}`,
|
|
247
|
+
}],
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
return {
|
|
252
|
+
diagnostics: results.flatMap(result => result.diagnostics ?? []),
|
|
253
|
+
blockers: results.flatMap(result => result.blockers ?? []),
|
|
254
|
+
confirmations: results.flatMap(result => result.confirmations ?? []),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function estimateOperationCost(operation, context) {
|
|
258
|
+
const tableName = getOperationTableName(operation);
|
|
259
|
+
if (!tableName) {
|
|
260
|
+
return {
|
|
261
|
+
source: 'static',
|
|
262
|
+
confidence: 'none',
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const stats = getTableStats(context, tableName);
|
|
266
|
+
if (!stats) {
|
|
267
|
+
return {
|
|
268
|
+
tableName,
|
|
269
|
+
source: 'static',
|
|
270
|
+
confidence: 'none',
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
tableName,
|
|
275
|
+
affectedRows: stats.totalRows,
|
|
276
|
+
affectedBytes: stats.totalBytes,
|
|
277
|
+
activeParts: stats.activeParts,
|
|
278
|
+
pendingMutations: stats.pendingMutations,
|
|
279
|
+
replicaAbsoluteDelaySeconds: stats.replicaAbsoluteDelaySeconds,
|
|
280
|
+
replicaQueueSize: stats.replicaQueueSize,
|
|
281
|
+
source: 'provided-context',
|
|
282
|
+
confidence: 'medium',
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function costDiagnosticsForOperation(operation, classification, operationIndex, costEstimate, context) {
|
|
286
|
+
if (costEstimate.source !== 'provided-context') {
|
|
287
|
+
return [];
|
|
288
|
+
}
|
|
289
|
+
const diagnostics = [];
|
|
290
|
+
const mutationWarningBytes = atLeast(context?.mutationWarningBytes, 0, 1024 ** 3);
|
|
291
|
+
const mutationWarningRows = atLeast(context?.mutationWarningRows, 1, 100_000_000);
|
|
292
|
+
const activePartsWarningThreshold = atLeast(context?.activePartsWarningThreshold, 1, 200);
|
|
293
|
+
const pendingMutationsWarningThreshold = atLeast(context?.pendingMutationsWarningThreshold, 0, 0);
|
|
294
|
+
const replicaDelayWarningSeconds = atLeast(context?.replicaDelayWarningSeconds, 0, 60);
|
|
295
|
+
if (classification === 'mutation' &&
|
|
296
|
+
costEstimate.affectedBytes !== undefined &&
|
|
297
|
+
costEstimate.affectedBytes >= mutationWarningBytes) {
|
|
298
|
+
diagnostics.push({
|
|
299
|
+
level: 'warning',
|
|
300
|
+
kind: 'ExpensiveMutationBytes',
|
|
301
|
+
operationIndex,
|
|
302
|
+
message: `Operation "${operation.kind}" may mutate ${costEstimate.affectedBytes} bytes ` +
|
|
303
|
+
`on table "${costEstimate.tableName}".`,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
if (classification === 'mutation' &&
|
|
307
|
+
costEstimate.affectedRows !== undefined &&
|
|
308
|
+
costEstimate.affectedRows >= mutationWarningRows) {
|
|
309
|
+
diagnostics.push({
|
|
310
|
+
level: 'warning',
|
|
311
|
+
kind: 'ExpensiveMutationRows',
|
|
312
|
+
operationIndex,
|
|
313
|
+
message: `Operation "${operation.kind}" may mutate ${costEstimate.affectedRows} rows ` +
|
|
314
|
+
`on table "${costEstimate.tableName}".`,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
if (costEstimate.activeParts !== undefined && costEstimate.activeParts >= activePartsWarningThreshold) {
|
|
318
|
+
diagnostics.push({
|
|
319
|
+
level: 'warning',
|
|
320
|
+
kind: 'HighActivePartCount',
|
|
321
|
+
operationIndex,
|
|
322
|
+
message: `Table "${costEstimate.tableName}" has ${costEstimate.activeParts} active parts. ` +
|
|
323
|
+
'Consider reducing part pressure before applying DDL.',
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
if (costEstimate.pendingMutations !== undefined &&
|
|
327
|
+
costEstimate.pendingMutations > pendingMutationsWarningThreshold) {
|
|
328
|
+
diagnostics.push({
|
|
329
|
+
level: 'warning',
|
|
330
|
+
kind: 'PendingMutations',
|
|
331
|
+
operationIndex,
|
|
332
|
+
message: `Table "${costEstimate.tableName}" has ${costEstimate.pendingMutations} pending mutation(s).`,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
if (costEstimate.replicaAbsoluteDelaySeconds !== undefined &&
|
|
336
|
+
costEstimate.replicaAbsoluteDelaySeconds >= replicaDelayWarningSeconds) {
|
|
337
|
+
diagnostics.push({
|
|
338
|
+
level: 'warning',
|
|
339
|
+
kind: 'ReplicaDelay',
|
|
340
|
+
operationIndex,
|
|
341
|
+
message: `Table "${costEstimate.tableName}" has replica delay of ` +
|
|
342
|
+
`${costEstimate.replicaAbsoluteDelaySeconds} second(s).`,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return diagnostics;
|
|
346
|
+
}
|
|
347
|
+
function forbiddenOperationMessage(operation) {
|
|
348
|
+
if (operation.kind === 'DropColumn' || operation.kind === 'ModifyColumnType') {
|
|
349
|
+
return [
|
|
350
|
+
`Cannot ${operation.kind === 'DropColumn' ? 'drop' : 'modify'} key column ` +
|
|
351
|
+
`"${operation.tableName}.${operation.columnName}" automatically.`,
|
|
352
|
+
'ClickHouse key columns participate in ORDER BY, PRIMARY KEY, PARTITION BY, or SAMPLE BY expressions.',
|
|
353
|
+
'Recommended approach: create a new table with the desired schema, backfill data in controlled batches, swap tables, then drop the old table.',
|
|
354
|
+
'Use a custom SQL migration if you understand the operational risk.',
|
|
355
|
+
].join(' ');
|
|
356
|
+
}
|
|
357
|
+
return [
|
|
358
|
+
`Operation "${operation.kind}" cannot be generated safely.`,
|
|
359
|
+
'Use a custom SQL migration or split the schema evolution into supported steps.',
|
|
360
|
+
].join(' ');
|
|
361
|
+
}
|
|
362
|
+
function atLeast(value, minimum, fallback) {
|
|
363
|
+
if (value === undefined || Number.isNaN(value)) {
|
|
364
|
+
return fallback;
|
|
365
|
+
}
|
|
366
|
+
return Math.max(minimum, value);
|
|
367
|
+
}
|
|
368
|
+
function getOperationTableName(operation) {
|
|
369
|
+
switch (operation.kind) {
|
|
370
|
+
case 'AddColumn':
|
|
371
|
+
case 'AlterTableWithDependentViews':
|
|
372
|
+
case 'DropColumn':
|
|
373
|
+
case 'DropTable':
|
|
374
|
+
case 'ModifyColumnDefault':
|
|
375
|
+
case 'ModifyColumnType':
|
|
376
|
+
return operation.tableName;
|
|
377
|
+
case 'CreateTable':
|
|
378
|
+
return operation.table.name;
|
|
379
|
+
case 'CreateMaterializedView':
|
|
380
|
+
case 'DropMaterializedView':
|
|
381
|
+
case 'RecreateMaterializedView':
|
|
382
|
+
return undefined;
|
|
383
|
+
default: {
|
|
384
|
+
const exhaustiveCheck = operation;
|
|
385
|
+
return exhaustiveCheck;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function getTableStats(context, tableName) {
|
|
390
|
+
if (!context?.tables) {
|
|
391
|
+
return undefined;
|
|
392
|
+
}
|
|
393
|
+
if (Array.isArray(context.tables)) {
|
|
394
|
+
return context.tables.find(table => table.tableName === tableName);
|
|
395
|
+
}
|
|
396
|
+
return context.tables[tableName];
|
|
397
|
+
}
|
|
398
|
+
function isKeyColumn(tables, tableName, columnName) {
|
|
399
|
+
const table = tables.find(candidate => candidate.name === tableName);
|
|
400
|
+
if (!table) {
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
return [
|
|
404
|
+
...table.engine.orderBy,
|
|
405
|
+
...table.engine.primaryKey,
|
|
406
|
+
table.engine.partitionBy,
|
|
407
|
+
table.engine.sampleBy,
|
|
408
|
+
].some(expression => expression !== undefined && expressionReferencesColumn(expression, columnName));
|
|
409
|
+
}
|
|
410
|
+
function expressionReferencesColumn(expression, columnName) {
|
|
411
|
+
if (expression === columnName) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
const escapedColumn = columnName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
415
|
+
return new RegExp(`(^|[^A-Za-z0-9_])${escapedColumn}([^A-Za-z0-9_]|$)`).test(expression);
|
|
416
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { MigrationOperation, SnapshotDiffResult } from '../diff/types.js';
|
|
2
|
+
import type { Snapshot } from '../snapshot/types.js';
|
|
3
|
+
export type MigrationOperationClassification = 'metadata' | 'mutation' | 'data-copy' | 'forbidden';
|
|
4
|
+
export type MigrationPlanDiagnosticLevel = 'warning' | 'error';
|
|
5
|
+
export interface MigrationPlanDiagnostic {
|
|
6
|
+
level: MigrationPlanDiagnosticLevel;
|
|
7
|
+
kind: string;
|
|
8
|
+
message: string;
|
|
9
|
+
operationIndex?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface MigrationPlanBlocker {
|
|
12
|
+
kind: string;
|
|
13
|
+
message: string;
|
|
14
|
+
tableName?: string;
|
|
15
|
+
columnName?: string;
|
|
16
|
+
operationIndex?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface MigrationPlanConfirmation {
|
|
19
|
+
kind: string;
|
|
20
|
+
message: string;
|
|
21
|
+
operationIndex: number;
|
|
22
|
+
}
|
|
23
|
+
export interface ClickHouseMigrationSyncSetting {
|
|
24
|
+
name: 'alter_sync' | 'mutations_sync' | 'replication_alter_partitions_sync' | 'distributed_ddl_task_timeout';
|
|
25
|
+
value: string | number;
|
|
26
|
+
reason: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ClickHouseTableCostStats {
|
|
29
|
+
tableName: string;
|
|
30
|
+
totalRows?: number;
|
|
31
|
+
totalBytes?: number;
|
|
32
|
+
activeParts?: number;
|
|
33
|
+
pendingMutations?: number;
|
|
34
|
+
replicaAbsoluteDelaySeconds?: number;
|
|
35
|
+
replicaQueueSize?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface ClickHouseMigrationPlanContext {
|
|
38
|
+
tables?: Record<string, ClickHouseTableCostStats> | ClickHouseTableCostStats[];
|
|
39
|
+
mutationWarningBytes?: number;
|
|
40
|
+
mutationWarningRows?: number;
|
|
41
|
+
activePartsWarningThreshold?: number;
|
|
42
|
+
pendingMutationsWarningThreshold?: number;
|
|
43
|
+
replicaDelayWarningSeconds?: number;
|
|
44
|
+
}
|
|
45
|
+
export interface MigrationOperationCostEstimate {
|
|
46
|
+
tableName?: string;
|
|
47
|
+
affectedRows?: number;
|
|
48
|
+
affectedBytes?: number;
|
|
49
|
+
activeParts?: number;
|
|
50
|
+
pendingMutations?: number;
|
|
51
|
+
replicaAbsoluteDelaySeconds?: number;
|
|
52
|
+
replicaQueueSize?: number;
|
|
53
|
+
source: 'static' | 'provided-context';
|
|
54
|
+
confidence: 'none' | 'low' | 'medium';
|
|
55
|
+
}
|
|
56
|
+
export interface PlannedMigrationOperation {
|
|
57
|
+
operation: MigrationOperation;
|
|
58
|
+
classification: MigrationOperationClassification;
|
|
59
|
+
costEstimate: MigrationOperationCostEstimate;
|
|
60
|
+
diagnostics: MigrationPlanDiagnostic[];
|
|
61
|
+
requiredConfirmations: MigrationPlanConfirmation[];
|
|
62
|
+
recommendedSyncSettings: ClickHouseMigrationSyncSetting[];
|
|
63
|
+
requiredSyncSettings: ClickHouseMigrationSyncSetting[];
|
|
64
|
+
}
|
|
65
|
+
export interface MigrationPlan {
|
|
66
|
+
previousSnapshot: Snapshot;
|
|
67
|
+
nextSnapshot: Snapshot;
|
|
68
|
+
sourceSnapshotHash: string;
|
|
69
|
+
targetSnapshotHash: string;
|
|
70
|
+
operations: PlannedMigrationOperation[];
|
|
71
|
+
diagnostics: MigrationPlanDiagnostic[];
|
|
72
|
+
blockers: MigrationPlanBlocker[];
|
|
73
|
+
requiredConfirmations: MigrationPlanConfirmation[];
|
|
74
|
+
recommendedSyncSettings: ClickHouseMigrationSyncSetting[];
|
|
75
|
+
requiredSyncSettings: ClickHouseMigrationSyncSetting[];
|
|
76
|
+
}
|
|
77
|
+
export interface MigrationPlanAnalyzerContext {
|
|
78
|
+
diff: SnapshotDiffResult;
|
|
79
|
+
clickhouse?: ClickHouseMigrationPlanContext;
|
|
80
|
+
}
|
|
81
|
+
export interface MigrationPlanAnalyzerResult {
|
|
82
|
+
diagnostics?: MigrationPlanDiagnostic[];
|
|
83
|
+
blockers?: MigrationPlanBlocker[];
|
|
84
|
+
confirmations?: MigrationPlanConfirmation[];
|
|
85
|
+
}
|
|
86
|
+
export type MigrationPlanAnalyzer = (plan: MigrationPlan, context: MigrationPlanAnalyzerContext) => MigrationPlanAnalyzerResult;
|
|
87
|
+
export interface CreateMigrationPlanOptions {
|
|
88
|
+
requireConfirmationForMutations?: boolean;
|
|
89
|
+
analyzers?: MigrationPlanAnalyzer[];
|
|
90
|
+
context?: ClickHouseMigrationPlanContext;
|
|
91
|
+
}
|
|
92
|
+
export type MigrationPlanInput = SnapshotDiffResult | MigrationPlan;
|
|
93
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/migrations/plan/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { renderMigrationArtifacts } from './render.js';
|
|
2
2
|
export { writeMigrationArtifacts } from './write.js';
|
|
3
|
-
export type { MigrationMeta, RenderMigrationArtifactsOptions, RenderMigrationArtifactsResult, WriteMigrationArtifactsOptions, WriteMigrationArtifactsResult, } from './types.js';
|
|
3
|
+
export type { MigrationMeta, RenderMigrationArtifactsInput, RenderMigrationArtifactsOptions, RenderMigrationArtifactsResult, WriteMigrationArtifactsOptions, WriteMigrationArtifactsResult, } from './types.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAErD,YAAY,EACV,aAAa,EACb,+BAA+B,EAC/B,8BAA8B,EAC9B,8BAA8B,EAC9B,6BAA6B,GAC9B,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAErD,YAAY,EACV,aAAa,EACb,6BAA6B,EAC7B,+BAA+B,EAC/B,8BAA8B,EAC9B,8BAA8B,EAC9B,6BAA6B,GAC9B,MAAM,YAAY,CAAC"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { RenderMigrationArtifactsOptions, RenderMigrationArtifactsResult } from './types.js';
|
|
1
|
+
import type { RenderMigrationArtifactsInput, RenderMigrationArtifactsOptions, RenderMigrationArtifactsResult } from './types.js';
|
|
3
2
|
/**
|
|
4
3
|
* Renders a snapshot diff into reviewable migration artifacts.
|
|
5
4
|
*
|
|
@@ -7,5 +6,5 @@ import type { RenderMigrationArtifactsOptions, RenderMigrationArtifactsResult }
|
|
|
7
6
|
* also sequences dependent materialized views around table mutations so stored
|
|
8
7
|
* view SELECT definitions are dropped and recreated with the target snapshot.
|
|
9
8
|
*/
|
|
10
|
-
export declare function renderMigrationArtifacts(
|
|
9
|
+
export declare function renderMigrationArtifacts(input: RenderMigrationArtifactsInput, options: RenderMigrationArtifactsOptions): RenderMigrationArtifactsResult;
|
|
11
10
|
//# sourceMappingURL=render.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/render.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/render.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAEV,6BAA6B,EAC7B,+BAA+B,EAC/B,8BAA8B,EAG/B,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,6BAA6B,EACpC,OAAO,EAAE,+BAA+B,GACvC,8BAA8B,CAkDhC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createMigrationPlan, isMigrationPlan } from '../plan/index.js';
|
|
1
2
|
/**
|
|
2
3
|
* Renders a snapshot diff into reviewable migration artifacts.
|
|
3
4
|
*
|
|
@@ -5,22 +6,27 @@
|
|
|
5
6
|
* also sequences dependent materialized views around table mutations so stored
|
|
6
7
|
* view SELECT definitions are dropped and recreated with the target snapshot.
|
|
7
8
|
*/
|
|
8
|
-
export function renderMigrationArtifacts(
|
|
9
|
-
|
|
9
|
+
export function renderMigrationArtifacts(input, options) {
|
|
10
|
+
const plan = isMigrationPlan(input) ? input : createMigrationPlan(input);
|
|
11
|
+
assertNoPlanBlockers(plan);
|
|
10
12
|
const upStatements = [];
|
|
11
13
|
const downStatements = [];
|
|
12
14
|
const consumedViewNames = new Set();
|
|
13
15
|
const renderedOperations = [];
|
|
14
16
|
let containsManualSteps = false;
|
|
15
|
-
for (const
|
|
17
|
+
for (const plannedOperation of normalizeOperationsForRendering(plan.operations)) {
|
|
18
|
+
const { operation } = plannedOperation;
|
|
16
19
|
if (isMaterializedViewOperation(operation) && consumedViewNames.has(getOperationViewName(operation))) {
|
|
17
20
|
continue;
|
|
18
21
|
}
|
|
19
|
-
renderedOperations.push({
|
|
20
|
-
|
|
22
|
+
renderedOperations.push({
|
|
23
|
+
kind: operation.kind,
|
|
24
|
+
classification: plannedOperation.classification,
|
|
25
|
+
});
|
|
26
|
+
upStatements.push(...renderOperationUp(operation, { plan, cluster: options.cluster }, consumedViewNames));
|
|
21
27
|
const renderedDown = renderOperationDown(operation, {
|
|
22
|
-
previousSnapshot:
|
|
23
|
-
nextSnapshot:
|
|
28
|
+
previousSnapshot: plan.previousSnapshot,
|
|
29
|
+
nextSnapshot: plan.nextSnapshot,
|
|
24
30
|
cluster: options.cluster,
|
|
25
31
|
}, consumedViewNames);
|
|
26
32
|
downStatements.unshift(...renderedDown.statements);
|
|
@@ -33,12 +39,15 @@ export function renderMigrationArtifacts(diff, options) {
|
|
|
33
39
|
name: options.name,
|
|
34
40
|
timestamp: options.timestamp,
|
|
35
41
|
operations: renderedOperations,
|
|
36
|
-
sourceSnapshotHash:
|
|
37
|
-
targetSnapshotHash:
|
|
42
|
+
sourceSnapshotHash: plan.sourceSnapshotHash,
|
|
43
|
+
targetSnapshotHash: plan.targetSnapshotHash,
|
|
38
44
|
custom: false,
|
|
39
|
-
unsafe:
|
|
45
|
+
unsafe: plan.diagnostics.some(diagnostic => diagnostic.level === 'warning') ||
|
|
46
|
+
plan.blockers.length > 0 ||
|
|
47
|
+
containsManualSteps,
|
|
40
48
|
containsManualSteps,
|
|
41
49
|
},
|
|
50
|
+
plan,
|
|
42
51
|
};
|
|
43
52
|
}
|
|
44
53
|
function renderOperationUp(operation, context, consumedViewNames) {
|
|
@@ -53,7 +62,7 @@ function renderOperationUp(operation, context, consumedViewNames) {
|
|
|
53
62
|
return [renderAlterTableDropColumn(operation.tableName, operation.columnName, context.cluster)];
|
|
54
63
|
case 'ModifyColumnDefault':
|
|
55
64
|
case 'ModifyColumnType': {
|
|
56
|
-
const nextColumn = requireColumn(context.
|
|
65
|
+
const nextColumn = requireColumn(context.plan.nextSnapshot, operation.tableName, operation.columnName);
|
|
57
66
|
return [renderAlterTableModifyColumn(operation.tableName, nextColumn, context.cluster)];
|
|
58
67
|
}
|
|
59
68
|
case 'CreateMaterializedView':
|
|
@@ -137,7 +146,7 @@ function renderAlterTableWithDependentViewsUp(operation, context, consumedViewNa
|
|
|
137
146
|
}
|
|
138
147
|
for (const viewName of operation.dependentViewNames) {
|
|
139
148
|
statements.push(renderCreateMaterializedView({
|
|
140
|
-
view: requireMaterializedView(context.
|
|
149
|
+
view: requireMaterializedView(context.plan.nextSnapshot, viewName),
|
|
141
150
|
cluster: context.cluster,
|
|
142
151
|
}));
|
|
143
152
|
}
|
|
@@ -297,21 +306,25 @@ function escapeStringLiteral(value) {
|
|
|
297
306
|
.replace(/'/g, "\\'");
|
|
298
307
|
}
|
|
299
308
|
function normalizeOperationsForRendering(operations) {
|
|
300
|
-
return operations.map(
|
|
301
|
-
if (operation.kind !== 'AlterTableWithDependentViews') {
|
|
302
|
-
return
|
|
309
|
+
return operations.map(plannedOperation => {
|
|
310
|
+
if (plannedOperation.operation.kind !== 'AlterTableWithDependentViews') {
|
|
311
|
+
return plannedOperation;
|
|
303
312
|
}
|
|
304
313
|
return {
|
|
305
|
-
...
|
|
306
|
-
|
|
314
|
+
...plannedOperation,
|
|
315
|
+
operation: {
|
|
316
|
+
...plannedOperation.operation,
|
|
317
|
+
operations: normalizeTableMutationOperations(plannedOperation.operation.operations),
|
|
318
|
+
},
|
|
307
319
|
};
|
|
308
|
-
}).filter(
|
|
309
|
-
if (operation.kind !== 'ModifyColumnDefault') {
|
|
320
|
+
}).filter(plannedOperation => {
|
|
321
|
+
if (plannedOperation.operation.kind !== 'ModifyColumnDefault') {
|
|
310
322
|
return true;
|
|
311
323
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
candidate.
|
|
324
|
+
const operation = plannedOperation.operation;
|
|
325
|
+
return !operations.some(candidate => candidate.operation.kind === 'ModifyColumnType' &&
|
|
326
|
+
candidate.operation.tableName === operation.tableName &&
|
|
327
|
+
candidate.operation.columnName === operation.columnName);
|
|
315
328
|
});
|
|
316
329
|
}
|
|
317
330
|
function normalizeTableMutationOperations(operations) {
|
|
@@ -324,11 +337,11 @@ function normalizeTableMutationOperations(operations) {
|
|
|
324
337
|
candidate.columnName === operation.columnName);
|
|
325
338
|
});
|
|
326
339
|
}
|
|
327
|
-
function
|
|
328
|
-
if (
|
|
340
|
+
function assertNoPlanBlockers(plan) {
|
|
341
|
+
if (plan.blockers.length === 0) {
|
|
329
342
|
return;
|
|
330
343
|
}
|
|
331
344
|
throw new Error('Cannot render migration with unsupported changes:\n' +
|
|
332
|
-
|
|
345
|
+
plan.blockers.map(blocker => `- ${blocker.message}`).join('\n') +
|
|
333
346
|
'\n\nUse a custom SQL migration for this change, or split the schema evolution into supported steps.');
|
|
334
347
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { MigrationOperation, SnapshotDiffResult } from '../diff/types.js';
|
|
2
|
+
import type { MigrationOperationClassification, MigrationPlan, MigrationPlanInput } from '../plan/types.js';
|
|
2
3
|
import type { Snapshot, SnapshotMaterializedView } from '../snapshot/types.js';
|
|
3
4
|
export interface MigrationMeta {
|
|
4
5
|
name: string;
|
|
5
6
|
timestamp: string;
|
|
6
7
|
operations: Array<{
|
|
7
8
|
kind: MigrationOperation['kind'];
|
|
9
|
+
classification: MigrationOperationClassification;
|
|
8
10
|
}>;
|
|
9
11
|
sourceSnapshotHash: string;
|
|
10
12
|
targetSnapshotHash: string;
|
|
@@ -21,9 +23,10 @@ export interface RenderMigrationArtifactsResult {
|
|
|
21
23
|
upSql: string;
|
|
22
24
|
downSql: string;
|
|
23
25
|
meta: MigrationMeta;
|
|
26
|
+
plan: MigrationPlan;
|
|
24
27
|
}
|
|
25
28
|
export interface RenderSqlContext {
|
|
26
|
-
|
|
29
|
+
plan: MigrationPlan;
|
|
27
30
|
cluster?: string;
|
|
28
31
|
}
|
|
29
32
|
export interface MaterializedViewRenderContext {
|
|
@@ -40,9 +43,11 @@ export interface WriteMigrationArtifactsResult {
|
|
|
40
43
|
upPath: string;
|
|
41
44
|
downPath: string;
|
|
42
45
|
metaPath: string;
|
|
46
|
+
planPath: string;
|
|
43
47
|
}
|
|
44
48
|
export interface SnapshotLookup {
|
|
45
49
|
previousSnapshot: Snapshot;
|
|
46
50
|
nextSnapshot: Snapshot;
|
|
47
51
|
}
|
|
52
|
+
export type RenderMigrationArtifactsInput = MigrationPlanInput | SnapshotDiffResult;
|
|
48
53
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAE/E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,KAAK,EACV,gCAAgC,EAChC,aAAa,EACb,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAE/E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACjC,cAAc,EAAE,gCAAgC,CAAC;KAClD,CAAC,CAAC;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,8BAA8B,CAAC;CAC3C;AAED,MAAM,WAAW,6BAA6B;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,QAAQ,CAAC;IAC3B,YAAY,EAAE,QAAQ,CAAC;CACxB;AAED,MAAM,MAAM,6BAA6B,GAAG,kBAAkB,GAAG,kBAAkB,CAAC"}
|
|
@@ -3,7 +3,8 @@ import type { WriteMigrationArtifactsOptions, WriteMigrationArtifactsResult } fr
|
|
|
3
3
|
* Writes rendered migration artifacts to a migration directory.
|
|
4
4
|
*
|
|
5
5
|
* The migration name must be a single safe path segment. The writer creates
|
|
6
|
-
* `up.sql`, `down.sql`, and `
|
|
6
|
+
* `up.sql`, `down.sql`, `meta.json`, and `plan.json` files under
|
|
7
|
+
* `outDir/migrationName`.
|
|
7
8
|
*/
|
|
8
9
|
export declare function writeMigrationArtifacts(options: WriteMigrationArtifactsOptions): Promise<WriteMigrationArtifactsResult>;
|
|
9
10
|
//# sourceMappingURL=write.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAC9B,MAAM,YAAY,CAAC;AAEpB
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/write.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAC9B,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,6BAA6B,CAAC,CAuBxC"}
|
|
@@ -4,7 +4,8 @@ import path from 'node:path';
|
|
|
4
4
|
* Writes rendered migration artifacts to a migration directory.
|
|
5
5
|
*
|
|
6
6
|
* The migration name must be a single safe path segment. The writer creates
|
|
7
|
-
* `up.sql`, `down.sql`, and `
|
|
7
|
+
* `up.sql`, `down.sql`, `meta.json`, and `plan.json` files under
|
|
8
|
+
* `outDir/migrationName`.
|
|
8
9
|
*/
|
|
9
10
|
export async function writeMigrationArtifacts(options) {
|
|
10
11
|
assertValidMigrationName(options.migrationName);
|
|
@@ -13,14 +14,17 @@ export async function writeMigrationArtifacts(options) {
|
|
|
13
14
|
const upPath = path.join(migrationDir, 'up.sql');
|
|
14
15
|
const downPath = path.join(migrationDir, 'down.sql');
|
|
15
16
|
const metaPath = path.join(migrationDir, 'meta.json');
|
|
17
|
+
const planPath = path.join(migrationDir, 'plan.json');
|
|
16
18
|
await writeFile(upPath, `${options.artifacts.upSql}\n`, 'utf8');
|
|
17
19
|
await writeFile(downPath, `${options.artifacts.downSql}\n`, 'utf8');
|
|
18
20
|
await writeFile(metaPath, `${JSON.stringify(options.artifacts.meta, null, 2)}\n`, 'utf8');
|
|
21
|
+
await writeFile(planPath, `${JSON.stringify(options.artifacts.plan, null, 2)}\n`, 'utf8');
|
|
19
22
|
return {
|
|
20
23
|
migrationDir,
|
|
21
24
|
upPath,
|
|
22
25
|
downPath,
|
|
23
26
|
metaPath,
|
|
27
|
+
planPath,
|
|
24
28
|
};
|
|
25
29
|
}
|
|
26
30
|
function assertValidMigrationName(migrationName) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ParseTopLevelArgs } from './type-helpers.js';
|
|
1
2
|
export type ClickHouseInteger = 'Int8' | 'Int16' | 'Int32' | 'Int64' | 'Int128' | 'Int256' | 'UInt8' | 'UInt16' | 'UInt32' | 'UInt64' | 'UInt128' | 'UInt256';
|
|
2
3
|
export type ClickHouseJsSafeInteger = 'Int8' | 'Int16' | 'Int32' | 'UInt8' | 'UInt16' | 'UInt32';
|
|
3
4
|
export type ClickHouseJsUnsafeInteger = Exclude<ClickHouseInteger, ClickHouseJsSafeInteger>;
|
|
@@ -8,8 +9,10 @@ export type ClickHouseString = 'String' | `FixedString(${number})` | 'UUID';
|
|
|
8
9
|
export type ClickHouseBoolean = 'Bool' | 'Boolean';
|
|
9
10
|
export type ClickHouseEnum = `Enum8(${string})` | `Enum16(${string})`;
|
|
10
11
|
export type ClickHouseBaseType = ClickHouseInteger | ClickHouseFloat | ClickHouseDecimal | ClickHouseDateTime | ClickHouseString | ClickHouseBoolean | ClickHouseEnum;
|
|
11
|
-
export type ClickHouseType = ClickHouseBaseType | `Array(${ClickHouseBaseType})` | `Array(Nullable(${ClickHouseBaseType}))` | `Array(LowCardinality(String))` | `Array(LowCardinality(${ClickHouseEnum}))` | `Nullable(${ClickHouseBaseType})` | `Nullable(Array(${ClickHouseBaseType}))` | `LowCardinality(${ClickHouseString})` | `LowCardinality(${ClickHouseEnum})` | `LowCardinality(Nullable(${ClickHouseString}))` | `LowCardinality(Nullable(${ClickHouseEnum}))` | `Map(String, ${ClickHouseBaseType})` | `Map(String, Array(${ClickHouseBaseType}))` | `Map(String, Nullable(${ClickHouseBaseType}))` | `Map(LowCardinality(String), ${ClickHouseBaseType})` | `Map(LowCardinality(String), Array(${ClickHouseBaseType}))` | `Map(LowCardinality(String), Nullable(${ClickHouseBaseType}))` | `Map(${ClickHouseInteger}, ${ClickHouseBaseType})` | `Map(${ClickHouseInteger}, Array(${ClickHouseBaseType}))` | `Map(${ClickHouseInteger}, Nullable(${ClickHouseBaseType}))` | `Array(Map(String, ${ClickHouseBaseType}))` | `Array(Map(LowCardinality(String), ${ClickHouseBaseType}))` | `Array(Map(${ClickHouseInteger}, ${ClickHouseBaseType}))` | `Nullable(Map(String, ${ClickHouseBaseType}))` | `Nullable(Map(LowCardinality(String), ${ClickHouseBaseType}))`;
|
|
12
|
-
export type InferClickHouseType<T extends
|
|
12
|
+
export type ClickHouseType = ClickHouseBaseType | `Array(${ClickHouseBaseType})` | `Array(Nullable(${ClickHouseBaseType}))` | `Array(LowCardinality(String))` | `Array(LowCardinality(${ClickHouseEnum}))` | `Array(Tuple(${string}))` | `Nullable(${ClickHouseBaseType})` | `Nullable(Array(${ClickHouseBaseType}))` | `Nullable(Array(Tuple(${string})))` | `Nullable(Tuple(${string}))` | `LowCardinality(${ClickHouseString})` | `LowCardinality(${ClickHouseEnum})` | `LowCardinality(Nullable(${ClickHouseString}))` | `LowCardinality(Nullable(${ClickHouseEnum}))` | `Map(String, ${ClickHouseBaseType})` | `Map(String, Array(${ClickHouseBaseType}))` | `Map(String, Nullable(${ClickHouseBaseType}))` | `Map(String, Tuple(${string}))` | `Map(String, Array(Tuple(${string})))` | `Map(LowCardinality(String), ${ClickHouseBaseType})` | `Map(LowCardinality(String), Array(${ClickHouseBaseType}))` | `Map(LowCardinality(String), Nullable(${ClickHouseBaseType}))` | `Map(LowCardinality(String), Tuple(${string}))` | `Map(LowCardinality(String), Array(Tuple(${string})))` | `Map(${ClickHouseInteger}, ${ClickHouseBaseType})` | `Map(${ClickHouseInteger}, Array(${ClickHouseBaseType}))` | `Map(${ClickHouseInteger}, Nullable(${ClickHouseBaseType}))` | `Map(${ClickHouseInteger}, Tuple(${string}))` | `Map(${ClickHouseInteger}, Array(Tuple(${string})))` | `Array(Map(String, ${ClickHouseBaseType}))` | `Array(Map(String, Tuple(${string})))` | `Array(Map(LowCardinality(String), ${ClickHouseBaseType}))` | `Array(Map(LowCardinality(String), Tuple(${string})))` | `Array(Map(${ClickHouseInteger}, ${ClickHouseBaseType}))` | `Array(Map(${ClickHouseInteger}, Tuple(${string})))` | `Nullable(Map(String, ${ClickHouseBaseType}))` | `Nullable(Map(String, Tuple(${string})))` | `Nullable(Map(LowCardinality(String), ${ClickHouseBaseType}))` | `Nullable(Map(LowCardinality(String), Tuple(${string})))` | `Tuple(${string})`;
|
|
13
|
+
export type InferClickHouseType<T extends string, Depth extends number = 0> = Depth extends 5 ? unknown : T extends ClickHouseJsSafeInteger ? number : T extends ClickHouseJsUnsafeInteger ? string : T extends ClickHouseFloat ? number : T extends ClickHouseDecimal ? number : T extends ClickHouseDateTime ? string : T extends ClickHouseString ? string : T extends ClickHouseEnum ? string : T extends ClickHouseBoolean ? boolean : T extends `Array(${infer U})` ? U extends ClickHouseType ? Array<InferClickHouseType<U, Add1<Depth>>> : unknown[] : T extends `Tuple(${infer U})` ? ParseTopLevelArgs<U> extends infer Parts extends string[] ? {
|
|
14
|
+
[K in keyof Parts]: InferClickHouseType<Parts[K] & ClickHouseType, Add1<Depth>>;
|
|
15
|
+
} : unknown[] : T extends `Nullable(${infer U})` ? U extends ClickHouseType ? InferClickHouseType<U, Add1<Depth>> | null : unknown | null : T extends `LowCardinality(${infer U})` ? U extends `Nullable(${infer V})` ? V extends ClickHouseString | ClickHouseEnum ? InferClickHouseType<V, Add1<Depth>> | null : unknown | null : U extends ClickHouseString | ClickHouseEnum ? InferClickHouseType<U, Add1<Depth>> : unknown : T extends `Map(${string}, ${infer V})` ? V extends ClickHouseType ? Record<string, InferClickHouseType<V, Add1<Depth>>> : Record<string, unknown> : unknown;
|
|
13
16
|
type Add1<T extends number> = T extends 0 ? 1 : T extends 1 ? 2 : T extends 2 ? 3 : T extends 3 ? 4 : 5;
|
|
14
17
|
export type ClickHouseSchema = Record<string, ClickHouseType>;
|
|
15
18
|
export type InferSchemaType<T extends ClickHouseSchema> = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clickhouse-types.d.ts","sourceRoot":"","sources":["../../src/types/clickhouse-types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GACzB,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAC1D,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAErE,MAAM,MAAM,uBAAuB,GAC/B,MAAM,GAAG,OAAO,GAAG,OAAO,GAC1B,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAElC,MAAM,MAAM,yBAAyB,GACnC,OAAO,CAAC,iBAAiB,EAAE,uBAAuB,CAAC,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GACzB,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,YAAY,GACvD,WAAW,MAAM,KAAK,MAAM,GAAG,CAAC;AAEpC,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GAAG,QAAQ,GACjB,UAAU,GACV,aAAa,MAAM,IAAI,GACvB,cAAc,MAAM,GAAG,GACvB,cAAc,MAAM,MAAM,MAAM,IAAI,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GACxB,QAAQ,GACR,eAAe,MAAM,GAAG,GACxB,MAAM,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEnD,MAAM,MAAM,cAAc,GACtB,SAAS,MAAM,GAAG,GAClB,UAAU,MAAM,GAAG,CAAC;AAExB,MAAM,MAAM,kBAAkB,GAC1B,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,kBAAkB,GAClB,gBAAgB,GAChB,iBAAiB,GACjB,cAAc,CAAC;AAEnB,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,SAAS,kBAAkB,GAAG,GAC9B,kBAAkB,kBAAkB,IAAI,GACxC,+BAA+B,GAC/B,wBAAwB,cAAc,IAAI,GAC1C,YAAY,kBAAkB,GAAG,GACjC,kBAAkB,kBAAkB,IAAI,GACxC,kBAAkB,gBAAgB,GAAG,GACrC,kBAAkB,cAAc,GAAG,GACnC,2BAA2B,gBAAgB,IAAI,GAC/C,2BAA2B,cAAc,IAAI,GAC7C,eAAe,kBAAkB,GAAG,GACpC,qBAAqB,kBAAkB,IAAI,GAC3C,wBAAwB,kBAAkB,IAAI,GAC9C,+BAA+B,kBAAkB,GAAG,GACpD,qCAAqC,kBAAkB,IAAI,GAC3D,wCAAwC,kBAAkB,IAAI,GAC9D,OAAO,iBAAiB,KAAK,kBAAkB,GAAG,GAClD,OAAO,iBAAiB,WAAW,kBAAkB,IAAI,GACzD,OAAO,iBAAiB,cAAc,kBAAkB,IAAI,GAC5D,qBAAqB,kBAAkB,IAAI,GAC3C,qCAAqC,kBAAkB,IAAI,GAC3D,aAAa,iBAAiB,KAAK,kBAAkB,IAAI,GACzD,wBAAwB,kBAAkB,IAAI,GAC9C,wCAAwC,kBAAkB,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"clickhouse-types.d.ts","sourceRoot":"","sources":["../../src/types/clickhouse-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,MAAM,iBAAiB,GACzB,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAC1D,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAErE,MAAM,MAAM,uBAAuB,GAC/B,MAAM,GAAG,OAAO,GAAG,OAAO,GAC1B,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAElC,MAAM,MAAM,yBAAyB,GACnC,OAAO,CAAC,iBAAiB,EAAE,uBAAuB,CAAC,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GACzB,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,YAAY,GACvD,WAAW,MAAM,KAAK,MAAM,GAAG,CAAC;AAEpC,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GAAG,QAAQ,GACjB,UAAU,GACV,aAAa,MAAM,IAAI,GACvB,cAAc,MAAM,GAAG,GACvB,cAAc,MAAM,MAAM,MAAM,IAAI,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GACxB,QAAQ,GACR,eAAe,MAAM,GAAG,GACxB,MAAM,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEnD,MAAM,MAAM,cAAc,GACtB,SAAS,MAAM,GAAG,GAClB,UAAU,MAAM,GAAG,CAAC;AAExB,MAAM,MAAM,kBAAkB,GAC1B,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,kBAAkB,GAClB,gBAAgB,GAChB,iBAAiB,GACjB,cAAc,CAAC;AAEnB,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,SAAS,kBAAkB,GAAG,GAC9B,kBAAkB,kBAAkB,IAAI,GACxC,+BAA+B,GAC/B,wBAAwB,cAAc,IAAI,GAC1C,eAAe,MAAM,IAAI,GACzB,YAAY,kBAAkB,GAAG,GACjC,kBAAkB,kBAAkB,IAAI,GACxC,wBAAwB,MAAM,KAAK,GACnC,kBAAkB,MAAM,IAAI,GAC5B,kBAAkB,gBAAgB,GAAG,GACrC,kBAAkB,cAAc,GAAG,GACnC,2BAA2B,gBAAgB,IAAI,GAC/C,2BAA2B,cAAc,IAAI,GAC7C,eAAe,kBAAkB,GAAG,GACpC,qBAAqB,kBAAkB,IAAI,GAC3C,wBAAwB,kBAAkB,IAAI,GAC9C,qBAAqB,MAAM,IAAI,GAC/B,2BAA2B,MAAM,KAAK,GACtC,+BAA+B,kBAAkB,GAAG,GACpD,qCAAqC,kBAAkB,IAAI,GAC3D,wCAAwC,kBAAkB,IAAI,GAC9D,qCAAqC,MAAM,IAAI,GAC/C,2CAA2C,MAAM,KAAK,GACtD,OAAO,iBAAiB,KAAK,kBAAkB,GAAG,GAClD,OAAO,iBAAiB,WAAW,kBAAkB,IAAI,GACzD,OAAO,iBAAiB,cAAc,kBAAkB,IAAI,GAC5D,OAAO,iBAAiB,WAAW,MAAM,IAAI,GAC7C,OAAO,iBAAiB,iBAAiB,MAAM,KAAK,GACpD,qBAAqB,kBAAkB,IAAI,GAC3C,2BAA2B,MAAM,KAAK,GACtC,qCAAqC,kBAAkB,IAAI,GAC3D,2CAA2C,MAAM,KAAK,GACtD,aAAa,iBAAiB,KAAK,kBAAkB,IAAI,GACzD,aAAa,iBAAiB,WAAW,MAAM,KAAK,GACpD,wBAAwB,kBAAkB,IAAI,GAC9C,8BAA8B,MAAM,KAAK,GACzC,wCAAwC,kBAAkB,IAAI,GAC9D,8CAA8C,MAAM,KAAK,GACzD,SAAS,MAAM,GAAG,CAAC;AAGvB,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,SAAS,MAAM,GAAG,CAAC,IACxE,KAAK,SAAS,CAAC,GACb,OAAO,GACP,CAAC,SAAS,uBAAuB,GAAG,MAAM,GAC1C,CAAC,SAAS,yBAAyB,GAAG,MAAM,GAC5C,CAAC,SAAS,eAAe,GAAG,MAAM,GAClC,CAAC,SAAS,iBAAiB,GAAG,MAAM,GACpC,CAAC,SAAS,kBAAkB,GAAG,MAAM,GACrC,CAAC,SAAS,gBAAgB,GAAG,MAAM,GACnC,CAAC,SAAS,cAAc,GAAG,MAAM,GACjC,CAAC,SAAS,iBAAiB,GAAG,OAAO,GACrC,CAAC,SAAS,SAAS,MAAM,CAAC,GAAG,GAC7B,CAAC,SAAS,cAAc,GACxB,KAAK,CAAC,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAC1C,OAAO,EAAE,GACT,CAAC,SAAS,SAAS,MAAM,CAAC,GAAG,GAC7B,iBAAiB,CAAC,CAAC,CAAC,SAAS,MAAM,KAAK,SAAS,MAAM,EAAE,GACvD;KAAG,CAAC,IAAI,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;CAAE,GACnF,OAAO,EAAE,GACX,CAAC,SAAS,YAAY,MAAM,CAAC,GAAG,GAChC,CAAC,SAAS,cAAc,GACxB,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,GAC1C,OAAO,GAAG,IAAI,GACd,CAAC,SAAS,kBAAkB,MAAM,CAAC,GAAG,GACtC,CAAC,SAAS,YAAY,MAAM,CAAC,GAAG,GAC9B,CAAC,SAAS,gBAAgB,GAAG,cAAc,GACzC,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,GAC1C,OAAO,GAAG,IAAI,GAChB,CAAC,SAAS,gBAAgB,GAAG,cAAc,GACzC,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GACnC,OAAO,GACX,CAAC,SAAS,OAAO,MAAM,KAAK,MAAM,CAAC,GAAG,GACtC,CAAC,SAAS,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GACnD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,OAAO,CAAC;AAEZ,KAAK,IAAI,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAGxG,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAG9D,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,gBAAgB,IAAI;KACvD,CAAC,IAAI,MAAM,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC1C,CAAC"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC"}
|
package/dist/types/index.js
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type TrimLeft<S extends string> = S extends ` ${infer R}` ? TrimLeft<R> : S;
|
|
2
|
+
type TrimRight<S extends string> = S extends `${infer R} ` ? TrimRight<R> : S;
|
|
3
|
+
type Trim<S extends string> = TrimLeft<TrimRight<S>>;
|
|
4
|
+
type Push<T extends string[], V extends string> = [...T, V];
|
|
5
|
+
export type ParseTopLevelArgs<S extends string, Current extends string = '', Depth extends string[] = [], Result extends string[] = []> = S extends `${infer First}${infer Rest}` ? First extends '(' ? ParseTopLevelArgs<Rest, `${Current}${First}`, Push<Depth, First>, Result> : First extends ')' ? Depth extends [...infer Remaining extends string[], string] ? ParseTopLevelArgs<Rest, `${Current}${First}`, Remaining, Result> : ParseTopLevelArgs<Rest, `${Current}${First}`, Depth, Result> : First extends ',' ? Depth['length'] extends 0 ? ParseTopLevelArgs<Rest, '', Depth, Push<Result, Trim<Current>>> : ParseTopLevelArgs<Rest, `${Current}${First}`, Depth, Result> : ParseTopLevelArgs<Rest, `${Current}${First}`, Depth, Result> : Current extends '' ? Result : Push<Result, Trim<Current>>;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=type-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-helpers.d.ts","sourceRoot":"","sources":["../../src/types/type-helpers.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC5E,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC9E,KAAK,IAAI,CAAC,CAAC,SAAS,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,KAAK,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;AAG5D,MAAM,MAAM,iBAAiB,CAC3B,CAAC,SAAS,MAAM,EAChB,OAAO,SAAS,MAAM,GAAG,EAAE,EAC3B,KAAK,SAAS,MAAM,EAAE,GAAG,EAAE,EAC3B,MAAM,SAAS,MAAM,EAAE,GAAG,EAAE,IAC1B,CAAC,SAAS,GAAG,MAAM,KAAK,GAAG,MAAM,IAAI,EAAE,GACvC,KAAK,SAAS,GAAG,GACf,iBAAiB,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,KAAK,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,GACzE,KAAK,SAAS,GAAG,GACf,KAAK,SAAS,CAAC,GAAG,MAAM,SAAS,SAAS,MAAM,EAAE,EAAE,MAAM,CAAC,GACzD,iBAAiB,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,GAChE,iBAAiB,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAC9D,KAAK,SAAS,GAAG,GACf,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,GACvB,iBAAiB,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAC/D,iBAAiB,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAC9D,iBAAiB,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAClE,OAAO,SAAS,EAAE,GAChB,MAAM,GACN,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|