@hypequery/clickhouse 1.6.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README-CLI.md +43 -88
  2. package/README.md +84 -253
  3. package/dist/cli/bin.js +16 -8
  4. package/dist/cli/generate-types.js +3 -81
  5. package/dist/cli/type-parsing.js +124 -0
  6. package/dist/core/adapters/clickhouse-adapter.d.ts.map +1 -1
  7. package/dist/core/adapters/clickhouse-adapter.js +3 -2
  8. package/dist/core/cache/cache-manager.d.ts.map +1 -1
  9. package/dist/core/cache/cache-manager.js +5 -3
  10. package/dist/core/connection.d.ts +6 -6
  11. package/dist/core/connection.js +9 -9
  12. package/dist/core/cross-filter.js +1 -1
  13. package/dist/core/dialects/clickhouse-dialect.d.ts +2 -2
  14. package/dist/core/dialects/clickhouse-dialect.d.ts.map +1 -1
  15. package/dist/core/dialects/clickhouse-dialect.js +39 -22
  16. package/dist/core/dialects/sql-dialect.d.ts +2 -2
  17. package/dist/core/dialects/sql-dialect.d.ts.map +1 -1
  18. package/dist/core/env/auto-client.d.ts.map +1 -1
  19. package/dist/core/env/auto-client.js +1 -1
  20. package/dist/core/features/aggregations.d.ts +7 -90
  21. package/dist/core/features/aggregations.d.ts.map +1 -1
  22. package/dist/core/features/aggregations.js +19 -7
  23. package/dist/core/features/analytics.d.ts +5 -870
  24. package/dist/core/features/analytics.d.ts.map +1 -1
  25. package/dist/core/features/analytics.js +15 -13
  26. package/dist/core/features/cross-filtering.d.ts +1 -1
  27. package/dist/core/features/cross-filtering.d.ts.map +1 -1
  28. package/dist/core/features/cross-filtering.js +28 -73
  29. package/dist/core/features/executor.d.ts +1 -1
  30. package/dist/core/features/executor.d.ts.map +1 -1
  31. package/dist/core/features/executor.js +9 -11
  32. package/dist/core/features/filtering.d.ts +5 -91
  33. package/dist/core/features/filtering.d.ts.map +1 -1
  34. package/dist/core/features/filtering.js +63 -77
  35. package/dist/core/features/joins.d.ts +2 -19
  36. package/dist/core/features/joins.d.ts.map +1 -1
  37. package/dist/core/features/joins.js +16 -5
  38. package/dist/core/features/query-modifiers.d.ts +10 -109
  39. package/dist/core/features/query-modifiers.d.ts.map +1 -1
  40. package/dist/core/features/query-modifiers.js +64 -18
  41. package/dist/core/formatters/sql-formatter.d.ts +16 -5
  42. package/dist/core/formatters/sql-formatter.d.ts.map +1 -1
  43. package/dist/core/formatters/sql-formatter.js +197 -93
  44. package/dist/core/join-relationships.d.ts +22 -5
  45. package/dist/core/join-relationships.d.ts.map +1 -1
  46. package/dist/core/join-relationships.js +1 -1
  47. package/dist/core/query-builder.d.ts +63 -12
  48. package/dist/core/query-builder.d.ts.map +1 -1
  49. package/dist/core/query-builder.js +210 -153
  50. package/dist/core/query-node.d.ts +7 -0
  51. package/dist/core/query-node.d.ts.map +1 -0
  52. package/dist/core/query-node.js +80 -0
  53. package/dist/core/tests/integration/setup.d.ts +1 -0
  54. package/dist/core/tests/integration/setup.d.ts.map +1 -1
  55. package/dist/core/tests/integration/setup.js +4 -2
  56. package/dist/core/types/select-types.d.ts +3 -0
  57. package/dist/core/types/select-types.d.ts.map +1 -1
  58. package/dist/core/utils/connection-endpoint.d.ts +3 -0
  59. package/dist/core/utils/connection-endpoint.d.ts.map +1 -0
  60. package/dist/core/utils/connection-endpoint.js +9 -0
  61. package/dist/core/utils/filter-application.d.ts +15 -0
  62. package/dist/core/utils/filter-application.d.ts.map +1 -0
  63. package/dist/core/utils/filter-application.js +32 -0
  64. package/dist/core/utils/query-config-compat.d.ts +48 -0
  65. package/dist/core/utils/query-config-compat.d.ts.map +1 -0
  66. package/dist/core/utils/query-config-compat.js +137 -0
  67. package/dist/core/utils/relation-application.d.ts +9 -0
  68. package/dist/core/utils/relation-application.d.ts.map +1 -0
  69. package/dist/core/utils/relation-application.js +19 -0
  70. package/dist/core/utils/relation-validation.d.ts +6 -0
  71. package/dist/core/utils/relation-validation.d.ts.map +1 -0
  72. package/dist/core/utils/relation-validation.js +29 -0
  73. package/dist/core/utils/sql-expressions.d.ts +14 -0
  74. package/dist/core/utils/sql-expressions.d.ts.map +1 -1
  75. package/dist/core/utils/sql-expressions.js +40 -0
  76. package/dist/core/utils/tuple-filter-validation.d.ts +3 -0
  77. package/dist/core/utils/tuple-filter-validation.d.ts.map +1 -0
  78. package/dist/core/utils/tuple-filter-validation.js +16 -0
  79. package/dist/index.d.ts +2 -11
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +3 -7
  82. package/dist/types/base.d.ts +88 -22
  83. package/dist/types/base.d.ts.map +1 -1
  84. package/dist/types/clickhouse-types.d.ts +5 -2
  85. package/dist/types/clickhouse-types.d.ts.map +1 -1
  86. package/dist/types/filters.d.ts +9 -5
  87. package/dist/types/filters.d.ts.map +1 -1
  88. package/dist/types/index.d.ts +1 -0
  89. package/dist/types/index.d.ts.map +1 -1
  90. package/dist/types/index.js +1 -0
  91. package/dist/types/type-helpers.d.ts +7 -0
  92. package/dist/types/type-helpers.d.ts.map +1 -0
  93. package/package.json +5 -5
  94. package/dist/migrations/config/index.d.ts +0 -3
  95. package/dist/migrations/config/index.d.ts.map +0 -1
  96. package/dist/migrations/config/index.js +0 -1
  97. package/dist/migrations/config/types.d.ts +0 -45
  98. package/dist/migrations/config/types.d.ts.map +0 -1
  99. package/dist/migrations/config/types.js +0 -28
  100. package/dist/migrations/diff/diff.d.ts +0 -11
  101. package/dist/migrations/diff/diff.d.ts.map +0 -1
  102. package/dist/migrations/diff/diff.js +0 -240
  103. package/dist/migrations/diff/index.d.ts +0 -3
  104. package/dist/migrations/diff/index.d.ts.map +0 -1
  105. package/dist/migrations/diff/index.js +0 -1
  106. package/dist/migrations/diff/types.d.ts +0 -74
  107. package/dist/migrations/diff/types.d.ts.map +0 -1
  108. package/dist/migrations/schema/column.d.ts +0 -71
  109. package/dist/migrations/schema/column.d.ts.map +0 -1
  110. package/dist/migrations/schema/column.js +0 -123
  111. package/dist/migrations/schema/define.d.ts +0 -24
  112. package/dist/migrations/schema/define.d.ts.map +0 -1
  113. package/dist/migrations/schema/define.js +0 -47
  114. package/dist/migrations/schema/index.d.ts +0 -4
  115. package/dist/migrations/schema/index.d.ts.map +0 -1
  116. package/dist/migrations/schema/index.js +0 -2
  117. package/dist/migrations/schema/types.d.ts +0 -74
  118. package/dist/migrations/schema/types.d.ts.map +0 -1
  119. package/dist/migrations/schema/types.js +0 -1
  120. package/dist/migrations/snapshot/index.d.ts +0 -3
  121. package/dist/migrations/snapshot/index.d.ts.map +0 -1
  122. package/dist/migrations/snapshot/index.js +0 -1
  123. package/dist/migrations/snapshot/serialize.d.ts +0 -21
  124. package/dist/migrations/snapshot/serialize.d.ts.map +0 -1
  125. package/dist/migrations/snapshot/serialize.js +0 -127
  126. package/dist/migrations/snapshot/types.d.ts +0 -47
  127. package/dist/migrations/snapshot/types.d.ts.map +0 -1
  128. package/dist/migrations/snapshot/types.js +0 -1
  129. package/dist/migrations/sql/index.d.ts +0 -4
  130. package/dist/migrations/sql/index.d.ts.map +0 -1
  131. package/dist/migrations/sql/index.js +0 -2
  132. package/dist/migrations/sql/render.d.ts +0 -11
  133. package/dist/migrations/sql/render.d.ts.map +0 -1
  134. package/dist/migrations/sql/render.js +0 -334
  135. package/dist/migrations/sql/types.d.ts +0 -48
  136. package/dist/migrations/sql/types.d.ts.map +0 -1
  137. package/dist/migrations/sql/types.js +0 -1
  138. package/dist/migrations/sql/write.d.ts +0 -9
  139. package/dist/migrations/sql/write.d.ts.map +0 -1
  140. package/dist/migrations/sql/write.js +0 -31
  141. /package/dist/{migrations/diff/types.js → types/type-helpers.js} +0 -0
@@ -1,74 +0,0 @@
1
- import type { SQLExpression } from '../../dataset/sql-tag.js';
2
- export type ClickHouseSqlExpression = string | SQLExpression;
3
- export type ClickHouseDefaultInput = string | number | boolean | null | SQLExpression;
4
- export interface ClickHouseSchemaAst {
5
- tables: ClickHouseTableDefinition[];
6
- materializedViews?: ClickHouseMaterializedViewDefinition[];
7
- }
8
- export interface ClickHouseSchemaDefinition {
9
- tables: ClickHouseTableDefinition[];
10
- materializedViews?: ClickHouseMaterializedViewDefinition[];
11
- }
12
- export interface ClickHouseTableDefinition {
13
- kind: 'table';
14
- name: string;
15
- columns: ClickHouseColumnDefinition[];
16
- engine: ClickHouseTableEngine;
17
- settings?: Record<string, string | number | boolean>;
18
- }
19
- export interface ClickHouseTableInputDefinition {
20
- columns: Record<string, ClickHouseColumnBuilderLike>;
21
- engine: ClickHouseTableEngine;
22
- settings?: Record<string, string | number | boolean>;
23
- }
24
- export interface ClickHouseColumnDefinition {
25
- name: string;
26
- type: ClickHouseColumnType;
27
- default?: ClickHouseColumnDefaultValue;
28
- }
29
- export interface ClickHouseColumnBuilderLike {
30
- build(name: string): ClickHouseColumnDefinition;
31
- }
32
- export type ClickHouseColumnDefaultValue = ClickHouseLiteralDefaultValue | ClickHouseSqlDefaultValue;
33
- export interface ClickHouseLiteralDefaultValue {
34
- kind: 'literal';
35
- value: string | number | boolean | null;
36
- }
37
- export interface ClickHouseSqlDefaultValue {
38
- kind: 'sql';
39
- value: ClickHouseSqlExpression;
40
- }
41
- export type ClickHouseColumnType = ClickHouseNamedColumnType | ClickHouseNullableColumnType | ClickHouseLowCardinalityColumnType;
42
- export interface ClickHouseNamedColumnType {
43
- kind: 'named';
44
- name: string;
45
- arguments?: Array<string | number>;
46
- }
47
- export interface ClickHouseNullableColumnType {
48
- kind: 'nullable';
49
- inner: ClickHouseColumnType;
50
- }
51
- export interface ClickHouseLowCardinalityColumnType {
52
- kind: 'low_cardinality';
53
- inner: ClickHouseColumnType;
54
- }
55
- export interface ClickHouseTableEngine {
56
- type: string;
57
- orderBy?: ClickHouseSqlExpression[];
58
- partitionBy?: ClickHouseSqlExpression;
59
- primaryKey?: ClickHouseSqlExpression[];
60
- sampleBy?: ClickHouseSqlExpression;
61
- }
62
- export interface ClickHouseMaterializedViewDefinition {
63
- kind: 'materialized_view';
64
- name: string;
65
- from: string;
66
- to?: string;
67
- select: ClickHouseSqlExpression;
68
- }
69
- export interface ClickHouseMaterializedViewInputDefinition {
70
- from: string | ClickHouseTableDefinition;
71
- to?: string | ClickHouseTableDefinition;
72
- select: ClickHouseSqlExpression;
73
- }
74
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/migrations/schema/types.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,3 +0,0 @@
1
- export { hashSnapshot, serializeSchemaToSnapshot, snapshotToStableJson, } from './serialize.js';
2
- export type { Snapshot, SnapshotColumn, SnapshotColumnDefault, SnapshotDependencyEdge, SnapshotMaterializedView, SnapshotTable, SnapshotTableEngine, } from './types.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/migrations/snapshot/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,QAAQ,EACR,cAAc,EACd,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EACxB,aAAa,EACb,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
@@ -1 +0,0 @@
1
- export { hashSnapshot, serializeSchemaToSnapshot, snapshotToStableJson, } from './serialize.js';
@@ -1,21 +0,0 @@
1
- import type { ClickHouseSchemaAst } from '../schema/types.js';
2
- import type { Snapshot } from './types.js';
3
- type SnapshotWithoutHash = Omit<Snapshot, 'contentHash'>;
4
- /**
5
- * Converts a schema AST into a deterministic ClickHouse snapshot.
6
- *
7
- * Snapshot serialization normalizes ordering, SQL-expression whitespace, type
8
- * wrappers, settings, and materialized-view dependencies before computing the
9
- * content hash used by migration metadata.
10
- */
11
- export declare function serializeSchemaToSnapshot(schema: ClickHouseSchemaAst): Snapshot;
12
- /**
13
- * Serializes a snapshot with stable formatting for writing to disk and hashing.
14
- */
15
- export declare function snapshotToStableJson(snapshot: Snapshot | SnapshotWithoutHash): string;
16
- /**
17
- * Computes the SHA-256 content hash for a normalized snapshot.
18
- */
19
- export declare function hashSnapshot(snapshot: Snapshot | SnapshotWithoutHash): string;
20
- export {};
21
- //# sourceMappingURL=serialize.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../../../src/migrations/snapshot/serialize.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAGV,mBAAmB,EAEpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EACV,QAAQ,EAMT,MAAM,YAAY,CAAC;AAEpB,KAAK,mBAAmB,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,mBAAmB,GAAG,QAAQ,CA6D/E;AAgBD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,GAAG,mBAAmB,GAAG,MAAM,CAErF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,mBAAmB,GAAG,MAAM,CAE7E"}
@@ -1,127 +0,0 @@
1
- import { createHash } from 'node:crypto';
2
- import { isSQLExpression } from '../../dataset/sql-tag.js';
3
- /**
4
- * Converts a schema AST into a deterministic ClickHouse snapshot.
5
- *
6
- * Snapshot serialization normalizes ordering, SQL-expression whitespace, type
7
- * wrappers, settings, and materialized-view dependencies before computing the
8
- * content hash used by migration metadata.
9
- */
10
- export function serializeSchemaToSnapshot(schema) {
11
- const snapshot = {
12
- version: 1,
13
- dialect: 'clickhouse',
14
- tables: [...schema.tables]
15
- .sort((left, right) => left.name.localeCompare(right.name))
16
- .map((table) => ({
17
- name: table.name,
18
- columns: [...table.columns]
19
- .sort((left, right) => left.name.localeCompare(right.name))
20
- .map((column) => ({
21
- name: column.name,
22
- type: normalizeColumnType(column.type),
23
- ...(column.default !== undefined
24
- ? { default: normalizeColumnDefault(column.default) }
25
- : {}),
26
- })),
27
- engine: {
28
- type: table.engine.type,
29
- orderBy: (table.engine.orderBy ?? []).map(normalizeSqlExpression),
30
- ...(table.engine.partitionBy !== undefined
31
- ? { partitionBy: normalizeSqlExpression(table.engine.partitionBy) }
32
- : {}),
33
- primaryKey: (table.engine.primaryKey ?? []).map(normalizeSqlExpression),
34
- ...(table.engine.sampleBy !== undefined
35
- ? { sampleBy: normalizeSqlExpression(table.engine.sampleBy) }
36
- : {}),
37
- },
38
- settings: Object.fromEntries(Object.entries(table.settings ?? {})
39
- .sort(([left], [right]) => left.localeCompare(right))
40
- .map(([key, value]) => [key, String(value)])),
41
- })),
42
- materializedViews: [...(schema.materializedViews ?? [])]
43
- .sort((left, right) => left.name.localeCompare(right.name))
44
- .map((view) => ({
45
- name: view.name,
46
- from: view.from,
47
- ...(view.to !== undefined ? { to: view.to } : {}),
48
- select: normalizeSqlExpression(view.select),
49
- })),
50
- dependencies: [...(schema.materializedViews ?? [])]
51
- .sort((left, right) => left.name.localeCompare(right.name))
52
- .map((view) => ({
53
- from: view.from,
54
- to: view.name,
55
- kind: 'table_to_materialized_view',
56
- })),
57
- };
58
- return {
59
- ...snapshot,
60
- contentHash: hashSnapshot(snapshot),
61
- };
62
- }
63
- function normalizeColumnDefault(defaultValue) {
64
- if (defaultValue.kind === 'literal') {
65
- return {
66
- kind: 'literal',
67
- value: defaultValue.value,
68
- };
69
- }
70
- return {
71
- kind: 'sql',
72
- value: normalizeSqlExpression(defaultValue.value),
73
- };
74
- }
75
- /**
76
- * Serializes a snapshot with stable formatting for writing to disk and hashing.
77
- */
78
- export function snapshotToStableJson(snapshot) {
79
- return JSON.stringify(snapshot, null, 2);
80
- }
81
- /**
82
- * Computes the SHA-256 content hash for a normalized snapshot.
83
- */
84
- export function hashSnapshot(snapshot) {
85
- return createHash('sha256').update(snapshotToStableJson(snapshot)).digest('hex');
86
- }
87
- function normalizeColumnType(type) {
88
- switch (type.kind) {
89
- case 'named': {
90
- const args = type.arguments?.length ? `(${type.arguments.join(', ')})` : '';
91
- return `${type.name}${args}`;
92
- }
93
- case 'nullable':
94
- return `Nullable(${normalizeColumnType(type.inner)})`;
95
- case 'low_cardinality':
96
- return `LowCardinality(${normalizeColumnType(type.inner)})`;
97
- default: {
98
- const exhaustiveCheck = type;
99
- return exhaustiveCheck;
100
- }
101
- }
102
- }
103
- function normalizeSqlExpression(expression) {
104
- const sql = typeof expression === 'string'
105
- ? expression
106
- : isSQLExpression(expression)
107
- ? expression.sql
108
- : String(expression);
109
- const lines = sql
110
- .replace(/\r\n/g, '\n')
111
- .split('\n')
112
- .map(line => line.replace(/\s+$/g, ''));
113
- while (lines.length > 0 && lines[0].trim() === '') {
114
- lines.shift();
115
- }
116
- while (lines.length > 0 && lines[lines.length - 1].trim() === '') {
117
- lines.pop();
118
- }
119
- const indents = lines
120
- .filter(line => line.trim().length > 0)
121
- .map(line => line.match(/^\s*/)?.[0].length ?? 0);
122
- const minIndent = indents.length > 0 ? Math.min(...indents) : 0;
123
- return lines
124
- .map(line => line.slice(minIndent))
125
- .join('\n')
126
- .trim();
127
- }
@@ -1,47 +0,0 @@
1
- export interface Snapshot {
2
- version: 1;
3
- dialect: 'clickhouse';
4
- tables: SnapshotTable[];
5
- materializedViews: SnapshotMaterializedView[];
6
- dependencies: SnapshotDependencyEdge[];
7
- contentHash: string;
8
- }
9
- export interface SnapshotTable {
10
- name: string;
11
- columns: SnapshotColumn[];
12
- engine: SnapshotTableEngine;
13
- settings: Record<string, string>;
14
- }
15
- export interface SnapshotColumn {
16
- name: string;
17
- type: string;
18
- default?: SnapshotColumnDefault;
19
- }
20
- export type SnapshotColumnDefault = SnapshotLiteralColumnDefault | SnapshotSqlColumnDefault;
21
- export interface SnapshotLiteralColumnDefault {
22
- kind: 'literal';
23
- value: string | number | boolean | null;
24
- }
25
- export interface SnapshotSqlColumnDefault {
26
- kind: 'sql';
27
- value: string;
28
- }
29
- export interface SnapshotTableEngine {
30
- type: string;
31
- orderBy: string[];
32
- partitionBy?: string;
33
- primaryKey: string[];
34
- sampleBy?: string;
35
- }
36
- export interface SnapshotMaterializedView {
37
- name: string;
38
- from: string;
39
- to?: string;
40
- select: string;
41
- }
42
- export interface SnapshotDependencyEdge {
43
- from: string;
44
- to: string;
45
- kind: 'table_to_materialized_view';
46
- }
47
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/migrations/snapshot/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,iBAAiB,EAAE,wBAAwB,EAAE,CAAC;IAC9C,YAAY,EAAE,sBAAsB,EAAE,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACjC;AAED,MAAM,MAAM,qBAAqB,GAAG,4BAA4B,GAAG,wBAAwB,CAAC;AAE5F,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,4BAA4B,CAAC;CACpC"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,4 +0,0 @@
1
- export { renderMigrationArtifacts } from './render.js';
2
- export { writeMigrationArtifacts } from './write.js';
3
- export type { MigrationMeta, RenderMigrationArtifactsOptions, RenderMigrationArtifactsResult, WriteMigrationArtifactsOptions, WriteMigrationArtifactsResult, } from './types.js';
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
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,2 +0,0 @@
1
- export { renderMigrationArtifacts } from './render.js';
2
- export { writeMigrationArtifacts } from './write.js';
@@ -1,11 +0,0 @@
1
- import type { SnapshotDiffResult } from '../diff/types.js';
2
- import type { RenderMigrationArtifactsOptions, RenderMigrationArtifactsResult } from './types.js';
3
- /**
4
- * Renders a snapshot diff into reviewable migration artifacts.
5
- *
6
- * The renderer produces forward SQL, best-effort reverse SQL, and metadata. It
7
- * also sequences dependent materialized views around table mutations so stored
8
- * view SELECT definitions are dropped and recreated with the target snapshot.
9
- */
10
- export declare function renderMigrationArtifacts(diff: SnapshotDiffResult, options: RenderMigrationArtifactsOptions): RenderMigrationArtifactsResult;
11
- //# sourceMappingURL=render.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,KAAK,EAEV,+BAA+B,EAC/B,8BAA8B,EAG/B,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,+BAA+B,GACvC,8BAA8B,CAuChC"}
@@ -1,334 +0,0 @@
1
- /**
2
- * Renders a snapshot diff into reviewable migration artifacts.
3
- *
4
- * The renderer produces forward SQL, best-effort reverse SQL, and metadata. It
5
- * also sequences dependent materialized views around table mutations so stored
6
- * view SELECT definitions are dropped and recreated with the target snapshot.
7
- */
8
- export function renderMigrationArtifacts(diff, options) {
9
- assertNoUnsupportedChanges(diff);
10
- const upStatements = [];
11
- const downStatements = [];
12
- const consumedViewNames = new Set();
13
- const renderedOperations = [];
14
- let containsManualSteps = false;
15
- for (const operation of normalizeOperationsForRendering(diff.operations)) {
16
- if (isMaterializedViewOperation(operation) && consumedViewNames.has(getOperationViewName(operation))) {
17
- continue;
18
- }
19
- renderedOperations.push({ kind: operation.kind });
20
- upStatements.push(...renderOperationUp(operation, { diff, cluster: options.cluster }, consumedViewNames));
21
- const renderedDown = renderOperationDown(operation, {
22
- previousSnapshot: diff.previousSnapshot,
23
- nextSnapshot: diff.nextSnapshot,
24
- cluster: options.cluster,
25
- }, consumedViewNames);
26
- downStatements.unshift(...renderedDown.statements);
27
- containsManualSteps = containsManualSteps || renderedDown.manual;
28
- }
29
- return {
30
- upSql: joinStatements(upStatements),
31
- downSql: joinStatements(downStatements),
32
- meta: {
33
- name: options.name,
34
- timestamp: options.timestamp,
35
- operations: renderedOperations,
36
- sourceSnapshotHash: diff.previousSnapshot.contentHash,
37
- targetSnapshotHash: diff.nextSnapshot.contentHash,
38
- custom: false,
39
- unsafe: diff.warnings.length > 0 || diff.unsupportedChanges.length > 0 || containsManualSteps,
40
- containsManualSteps,
41
- },
42
- };
43
- }
44
- function renderOperationUp(operation, context, consumedViewNames) {
45
- switch (operation.kind) {
46
- case 'CreateTable':
47
- return [renderCreateTable(operation.table, context.cluster)];
48
- case 'DropTable':
49
- return [renderDropTable(operation.tableName, context.cluster)];
50
- case 'AddColumn':
51
- return [renderAlterTableAddColumn(operation.tableName, operation.column, context.cluster)];
52
- case 'DropColumn':
53
- return [renderAlterTableDropColumn(operation.tableName, operation.columnName, context.cluster)];
54
- case 'ModifyColumnDefault':
55
- case 'ModifyColumnType': {
56
- const nextColumn = requireColumn(context.diff.nextSnapshot, operation.tableName, operation.columnName);
57
- return [renderAlterTableModifyColumn(operation.tableName, nextColumn, context.cluster)];
58
- }
59
- case 'CreateMaterializedView':
60
- return [renderCreateMaterializedView({ view: operation.view, cluster: context.cluster })];
61
- case 'DropMaterializedView':
62
- return [renderDropMaterializedView(operation.viewName, context.cluster)];
63
- case 'RecreateMaterializedView':
64
- return [
65
- renderDropMaterializedView(operation.previousView.name, context.cluster),
66
- renderCreateMaterializedView({ view: operation.nextView, cluster: context.cluster }),
67
- ];
68
- case 'AlterTableWithDependentViews':
69
- return renderAlterTableWithDependentViewsUp(operation, context, consumedViewNames);
70
- default: {
71
- const exhaustiveCheck = operation;
72
- return exhaustiveCheck;
73
- }
74
- }
75
- }
76
- function renderOperationDown(operation, lookup, consumedViewNames) {
77
- switch (operation.kind) {
78
- case 'CreateTable':
79
- return { statements: [renderDropTable(operation.table.name, lookup.cluster)], manual: false };
80
- case 'DropTable':
81
- return { statements: [manualDownComment(`recreate dropped table "${operation.tableName}" manually`)], manual: true };
82
- case 'AddColumn':
83
- return {
84
- statements: [renderAlterTableDropColumn(operation.tableName, operation.column.name, lookup.cluster)],
85
- manual: false,
86
- };
87
- case 'DropColumn':
88
- return {
89
- statements: [manualDownComment(`recreate dropped column "${operation.tableName}.${operation.columnName}" manually`)],
90
- manual: true,
91
- };
92
- case 'ModifyColumnDefault': {
93
- const previousColumn = requireColumn(lookup.previousSnapshot, operation.tableName, operation.columnName);
94
- return {
95
- statements: [renderAlterTableModifyColumn(operation.tableName, previousColumn, lookup.cluster)],
96
- manual: false,
97
- };
98
- }
99
- case 'ModifyColumnType':
100
- return {
101
- statements: [manualDownComment(`revert type change for "${operation.tableName}.${operation.columnName}" manually`)],
102
- manual: true,
103
- };
104
- case 'CreateMaterializedView':
105
- return { statements: [renderDropMaterializedView(operation.view.name, lookup.cluster)], manual: false };
106
- case 'DropMaterializedView': {
107
- const previousView = requireMaterializedView(lookup.previousSnapshot, operation.viewName);
108
- return {
109
- statements: [renderCreateMaterializedView({ view: previousView, cluster: lookup.cluster })],
110
- manual: false,
111
- };
112
- }
113
- case 'RecreateMaterializedView':
114
- return {
115
- statements: [
116
- renderDropMaterializedView(operation.nextView.name, lookup.cluster),
117
- renderCreateMaterializedView({ view: operation.previousView, cluster: lookup.cluster }),
118
- ],
119
- manual: false,
120
- };
121
- case 'AlterTableWithDependentViews':
122
- return renderAlterTableWithDependentViewsDown(operation, lookup, consumedViewNames);
123
- default: {
124
- const exhaustiveCheck = operation;
125
- return exhaustiveCheck;
126
- }
127
- }
128
- }
129
- function renderAlterTableWithDependentViewsUp(operation, context, consumedViewNames) {
130
- const statements = [];
131
- for (const viewName of operation.dependentViewNames) {
132
- statements.push(renderDropMaterializedView(viewName, context.cluster));
133
- consumedViewNames.add(viewName);
134
- }
135
- for (const nestedOperation of normalizeTableMutationOperations(operation.operations)) {
136
- statements.push(...renderOperationUp(nestedOperation, context, consumedViewNames));
137
- }
138
- for (const viewName of operation.dependentViewNames) {
139
- statements.push(renderCreateMaterializedView({
140
- view: requireMaterializedView(context.diff.nextSnapshot, viewName),
141
- cluster: context.cluster,
142
- }));
143
- }
144
- return statements;
145
- }
146
- function renderAlterTableWithDependentViewsDown(operation, lookup, consumedViewNames) {
147
- const statements = [];
148
- let manual = false;
149
- for (const viewName of operation.dependentViewNames) {
150
- statements.push(renderDropMaterializedView(viewName, lookup.cluster));
151
- consumedViewNames.add(viewName);
152
- }
153
- for (const nestedOperation of [...normalizeTableMutationOperations(operation.operations)].reverse()) {
154
- const rendered = renderOperationDown(nestedOperation, lookup, consumedViewNames);
155
- statements.push(...rendered.statements);
156
- manual = manual || rendered.manual;
157
- }
158
- for (const viewName of operation.dependentViewNames) {
159
- statements.push(renderCreateMaterializedView({
160
- view: requireMaterializedView(lookup.previousSnapshot, viewName),
161
- cluster: lookup.cluster,
162
- }));
163
- }
164
- return { statements, manual };
165
- }
166
- function renderCreateTable(table, cluster) {
167
- const columns = table.columns
168
- .map(column => ` ${quoteIdentifier(column.name)} ${column.type}${renderColumnDefault(column)}`)
169
- .join(',\n');
170
- const settings = Object.keys(table.settings).length > 0
171
- ? `\nSETTINGS ${Object.entries(table.settings).map(([key, value]) => `${key} = ${value}`).join(', ')}`
172
- : '';
173
- return [
174
- `CREATE TABLE ${quoteIdentifier(table.name)}${renderClusterClause(cluster)} (`,
175
- columns,
176
- `) ENGINE = ${renderTableEngine(table)}${settings};`,
177
- ].join('\n');
178
- }
179
- function renderDropTable(tableName, cluster) {
180
- return `DROP TABLE ${quoteIdentifier(tableName)}${renderClusterClause(cluster)};`;
181
- }
182
- function renderAlterTableAddColumn(tableName, column, cluster) {
183
- return `ALTER TABLE ${quoteIdentifier(tableName)}${renderClusterClause(cluster)} ADD COLUMN ` +
184
- `${quoteIdentifier(column.name)} ${column.type}${renderColumnDefault(column)};`;
185
- }
186
- function renderAlterTableDropColumn(tableName, columnName, cluster) {
187
- return `ALTER TABLE ${quoteIdentifier(tableName)}${renderClusterClause(cluster)} DROP COLUMN ${quoteIdentifier(columnName)};`;
188
- }
189
- function renderAlterTableModifyColumn(tableName, column, cluster) {
190
- return `ALTER TABLE ${quoteIdentifier(tableName)}${renderClusterClause(cluster)} MODIFY COLUMN ` +
191
- `${quoteIdentifier(column.name)} ${column.type}${renderColumnDefault(column)};`;
192
- }
193
- function renderCreateMaterializedView(context) {
194
- const toClause = context.view.to ? `\nTO ${quoteIdentifier(context.view.to)}` : '';
195
- return [
196
- `CREATE MATERIALIZED VIEW ${quoteIdentifier(context.view.name)}${renderClusterClause(context.cluster)}${toClause} AS`,
197
- context.view.select,
198
- ';',
199
- ].join('\n');
200
- }
201
- function renderDropMaterializedView(viewName, cluster) {
202
- return `DROP TABLE ${quoteIdentifier(viewName)}${renderClusterClause(cluster)};`;
203
- }
204
- function renderTableEngine(table) {
205
- const parts = [table.engine.type, `ORDER BY (${table.engine.orderBy.join(', ')})`];
206
- if (table.engine.partitionBy) {
207
- parts.push(`PARTITION BY ${table.engine.partitionBy}`);
208
- }
209
- if (table.engine.primaryKey.length > 0) {
210
- parts.push(`PRIMARY KEY (${table.engine.primaryKey.join(', ')})`);
211
- }
212
- if (table.engine.sampleBy) {
213
- parts.push(`SAMPLE BY ${table.engine.sampleBy}`);
214
- }
215
- return parts.join('\n');
216
- }
217
- function renderColumnDefault(column) {
218
- return column.default !== undefined ? ` DEFAULT ${renderDefaultValue(column.default)}` : '';
219
- }
220
- function renderClusterClause(cluster) {
221
- return cluster ? ` ON CLUSTER ${quoteIdentifier(cluster)}` : '';
222
- }
223
- function quoteIdentifier(identifier) {
224
- if (identifier.trim() === '') {
225
- throw new Error('Invalid ClickHouse identifier: identifiers must not be empty.');
226
- }
227
- return `\`${identifier.replace(/`/g, '``')}\``;
228
- }
229
- function requireColumn(snapshot, tableName, columnName) {
230
- const table = snapshot.tables.find(candidate => candidate.name === tableName);
231
- if (!table) {
232
- throw new Error(`Table "${tableName}" not found in snapshot.`);
233
- }
234
- const column = table.columns.find(candidate => candidate.name === columnName);
235
- if (!column) {
236
- throw new Error(`Column "${tableName}.${columnName}" not found in snapshot.`);
237
- }
238
- return column;
239
- }
240
- function requireMaterializedView(snapshot, viewName) {
241
- const view = snapshot.materializedViews.find(candidate => candidate.name === viewName);
242
- if (!view) {
243
- throw new Error(`Materialized view "${viewName}" not found in snapshot.`);
244
- }
245
- return view;
246
- }
247
- function isMaterializedViewOperation(operation) {
248
- return operation.kind === 'DropMaterializedView' ||
249
- operation.kind === 'CreateMaterializedView' ||
250
- operation.kind === 'RecreateMaterializedView';
251
- }
252
- function getOperationViewName(operation) {
253
- switch (operation.kind) {
254
- case 'DropMaterializedView':
255
- return operation.viewName;
256
- case 'CreateMaterializedView':
257
- return operation.view.name;
258
- case 'RecreateMaterializedView':
259
- return operation.nextView.name;
260
- default: {
261
- const exhaustiveCheck = operation;
262
- return exhaustiveCheck;
263
- }
264
- }
265
- }
266
- function manualDownComment(message) {
267
- return `-- MANUAL STEP REQUIRED: ${message}`;
268
- }
269
- function joinStatements(statements) {
270
- return statements.join('\n\n').trim();
271
- }
272
- function renderDefaultValue(defaultValue) {
273
- if (defaultValue.kind === 'sql') {
274
- return defaultValue.value;
275
- }
276
- if (defaultValue.value === null) {
277
- return 'NULL';
278
- }
279
- if (typeof defaultValue.value === 'number') {
280
- return String(defaultValue.value);
281
- }
282
- if (typeof defaultValue.value === 'boolean') {
283
- return defaultValue.value ? 'true' : 'false';
284
- }
285
- return `'${escapeStringLiteral(defaultValue.value)}'`;
286
- }
287
- function escapeStringLiteral(value) {
288
- return value
289
- .replace(/\\/g, '\\\\')
290
- .replace(/\0/g, '\\0')
291
- .replace(/\x08/g, '\\b')
292
- .replace(/\f/g, '\\f')
293
- .replace(/\n/g, '\\n')
294
- .replace(/\r/g, '\\r')
295
- .replace(/\t/g, '\\t')
296
- .replace(/\v/g, '\\v')
297
- .replace(/'/g, "\\'");
298
- }
299
- function normalizeOperationsForRendering(operations) {
300
- return operations.map(operation => {
301
- if (operation.kind !== 'AlterTableWithDependentViews') {
302
- return operation;
303
- }
304
- return {
305
- ...operation,
306
- operations: normalizeTableMutationOperations(operation.operations),
307
- };
308
- }).filter(operation => {
309
- if (operation.kind !== 'ModifyColumnDefault') {
310
- return true;
311
- }
312
- return !operations.some(candidate => candidate.kind === 'ModifyColumnType' &&
313
- candidate.tableName === operation.tableName &&
314
- candidate.columnName === operation.columnName);
315
- });
316
- }
317
- function normalizeTableMutationOperations(operations) {
318
- return operations.filter(operation => {
319
- if (operation.kind !== 'ModifyColumnDefault') {
320
- return true;
321
- }
322
- return !operations.some(candidate => candidate.kind === 'ModifyColumnType' &&
323
- candidate.tableName === operation.tableName &&
324
- candidate.columnName === operation.columnName);
325
- });
326
- }
327
- function assertNoUnsupportedChanges(diff) {
328
- if (diff.unsupportedChanges.length === 0) {
329
- return;
330
- }
331
- throw new Error('Cannot render migration with unsupported changes:\n' +
332
- diff.unsupportedChanges.map(change => `- ${change.message}`).join('\n') +
333
- '\n\nUse a custom SQL migration for this change, or split the schema evolution into supported steps.');
334
- }