@intentius/chant-lexicon-sql 0.124.12 → 0.124.14

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 (148) hide show
  1. package/dist/clickhouse/apply/statements.d.ts.map +1 -1
  2. package/dist/clickhouse/entities.d.ts +7 -1
  3. package/dist/clickhouse/entities.d.ts.map +1 -1
  4. package/dist/clickhouse/expressions.d.ts +27 -0
  5. package/dist/clickhouse/expressions.d.ts.map +1 -0
  6. package/dist/clickhouse/parser.d.ts +12 -2
  7. package/dist/clickhouse/parser.d.ts.map +1 -1
  8. package/dist/clickhouse/plan/diff.d.ts.map +1 -1
  9. package/dist/clickhouse/plan/normalize.d.ts +11 -1
  10. package/dist/clickhouse/plan/normalize.d.ts.map +1 -1
  11. package/dist/clickhouse/plan/rebuild-handoff.d.ts.map +1 -1
  12. package/dist/clickhouse/plan/rules.d.ts +1 -0
  13. package/dist/clickhouse/plan/rules.d.ts.map +1 -1
  14. package/dist/clickhouse.d.ts +1 -0
  15. package/dist/clickhouse.d.ts.map +1 -1
  16. package/dist/codegen/classifier-page.d.ts.map +1 -1
  17. package/dist/codegen/postgres-classifier-page.d.ts.map +1 -1
  18. package/dist/core/cursor.d.ts +41 -0
  19. package/dist/core/cursor.d.ts.map +1 -1
  20. package/dist/core/interpolation.d.ts +18 -1
  21. package/dist/core/interpolation.d.ts.map +1 -1
  22. package/dist/files/clickhouse.d.ts +2 -2
  23. package/dist/files/clickhouse.d.ts.map +1 -1
  24. package/dist/files/common.d.ts +16 -0
  25. package/dist/files/common.d.ts.map +1 -1
  26. package/dist/files/postgres.d.ts +2 -2
  27. package/dist/files/postgres.d.ts.map +1 -1
  28. package/dist/import-parser.d.ts +2 -1
  29. package/dist/import-parser.d.ts.map +1 -1
  30. package/dist/integrity.json +19 -19
  31. package/dist/lint/post-synth/clickhouse-helpers.d.ts +6 -19
  32. package/dist/lint/post-synth/clickhouse-helpers.d.ts.map +1 -1
  33. package/dist/lint/post-synth/postgres-helpers.d.ts +15 -55
  34. package/dist/lint/post-synth/postgres-helpers.d.ts.map +1 -1
  35. package/dist/lint/post-synth/postgres-names.d.ts +2 -2
  36. package/dist/lint/post-synth/postgres-names.d.ts.map +1 -1
  37. package/dist/lint/post-synth/sql-helpers.d.ts +5 -6
  38. package/dist/lint/post-synth/sql-helpers.d.ts.map +1 -1
  39. package/dist/lint/post-synth/sqlch102.d.ts.map +1 -1
  40. package/dist/lint/post-synth/sqlch103.d.ts.map +1 -1
  41. package/dist/lint/post-synth/sqlch104.d.ts.map +1 -1
  42. package/dist/lint/post-synth/sqlch105.d.ts.map +1 -1
  43. package/dist/lint/post-synth/sqlch106.d.ts.map +1 -1
  44. package/dist/lint/post-synth/sqlch107.d.ts.map +1 -1
  45. package/dist/lint/post-synth/sqlch111.d.ts.map +1 -1
  46. package/dist/lint/post-synth/sqlch112.d.ts.map +1 -1
  47. package/dist/lint/post-synth/sqlch113.d.ts.map +1 -1
  48. package/dist/lint/post-synth/sqlch114.d.ts.map +1 -1
  49. package/dist/lint/post-synth/sqlch115.d.ts.map +1 -1
  50. package/dist/lint/post-synth/sqlch120.d.ts.map +1 -1
  51. package/dist/lint/post-synth/sqlch125.d.ts.map +1 -1
  52. package/dist/manifest.json +1 -1
  53. package/dist/postgres/apply/statements.d.ts.map +1 -1
  54. package/dist/postgres/entities.d.ts +7 -1
  55. package/dist/postgres/entities.d.ts.map +1 -1
  56. package/dist/postgres/parser.d.ts +10 -2
  57. package/dist/postgres/parser.d.ts.map +1 -1
  58. package/dist/postgres/plan/diff.d.ts.map +1 -1
  59. package/dist/postgres/plan/normalize.d.ts.map +1 -1
  60. package/dist/postgres/plan/rules.d.ts +1 -0
  61. package/dist/postgres/plan/rules.d.ts.map +1 -1
  62. package/dist/postgres.d.ts +1 -0
  63. package/dist/postgres.d.ts.map +1 -1
  64. package/dist/read/clickhouse.d.ts +66 -0
  65. package/dist/read/clickhouse.d.ts.map +1 -0
  66. package/dist/read/objects.d.ts +99 -0
  67. package/dist/read/objects.d.ts.map +1 -0
  68. package/dist/read/postgres.d.ts +83 -0
  69. package/dist/read/postgres.d.ts.map +1 -0
  70. package/dist/read.d.ts +49 -0
  71. package/dist/read.d.ts.map +1 -0
  72. package/dist/rules/clickhouse-helpers.ts +20 -97
  73. package/dist/rules/postgres-helpers.ts +18 -53
  74. package/dist/rules/postgres-names.ts +6 -6
  75. package/dist/rules/sql-helpers.ts +8 -28
  76. package/dist/rules/sqlch102.ts +2 -3
  77. package/dist/rules/sqlch103.ts +2 -3
  78. package/dist/rules/sqlch104.ts +2 -3
  79. package/dist/rules/sqlch105.ts +2 -3
  80. package/dist/rules/sqlch106.ts +2 -3
  81. package/dist/rules/sqlch107.ts +2 -3
  82. package/dist/rules/sqlch111.ts +2 -3
  83. package/dist/rules/sqlch112.ts +2 -3
  84. package/dist/rules/sqlch113.ts +2 -3
  85. package/dist/rules/sqlch114.ts +2 -3
  86. package/dist/rules/sqlch115.ts +2 -3
  87. package/dist/rules/sqlch120.ts +2 -3
  88. package/dist/rules/sqlch125.ts +2 -3
  89. package/dist/serializer.d.ts +11 -1
  90. package/dist/serializer.d.ts.map +1 -1
  91. package/dist/sql-files.d.ts +17 -1
  92. package/dist/sql-files.d.ts.map +1 -1
  93. package/dist/sql-types.d.ts +3 -0
  94. package/dist/sql-types.d.ts.map +1 -1
  95. package/package.json +2 -2
  96. package/src/clickhouse/apply/statements.ts +2 -0
  97. package/src/clickhouse/entities.ts +8 -1
  98. package/src/clickhouse/expressions.ts +108 -0
  99. package/src/clickhouse/parser.ts +113 -31
  100. package/src/clickhouse/plan/diff.ts +19 -0
  101. package/src/clickhouse/plan/normalize.ts +27 -2
  102. package/src/clickhouse/plan/rebuild-handoff.ts +2 -1
  103. package/src/clickhouse/plan/rules.ts +7 -0
  104. package/src/clickhouse/testdata/server-ddl-baseline.json +67 -0
  105. package/src/clickhouse.ts +10 -0
  106. package/src/codegen/classifier-page.ts +2 -0
  107. package/src/codegen/postgres-classifier-page.ts +2 -0
  108. package/src/core/cursor.ts +96 -0
  109. package/src/core/interpolation.ts +32 -1
  110. package/src/files/clickhouse.ts +7 -5
  111. package/src/files/common.ts +23 -0
  112. package/src/files/postgres.ts +12 -8
  113. package/src/import-parser.ts +2 -1
  114. package/src/lint/post-synth/clickhouse-helpers.ts +20 -97
  115. package/src/lint/post-synth/postgres-helpers.ts +18 -53
  116. package/src/lint/post-synth/postgres-names.ts +6 -6
  117. package/src/lint/post-synth/sql-helpers.ts +8 -28
  118. package/src/lint/post-synth/sqlch102.ts +2 -3
  119. package/src/lint/post-synth/sqlch103.ts +2 -3
  120. package/src/lint/post-synth/sqlch104.ts +2 -3
  121. package/src/lint/post-synth/sqlch105.ts +2 -3
  122. package/src/lint/post-synth/sqlch106.ts +2 -3
  123. package/src/lint/post-synth/sqlch107.ts +2 -3
  124. package/src/lint/post-synth/sqlch111.ts +2 -3
  125. package/src/lint/post-synth/sqlch112.ts +2 -3
  126. package/src/lint/post-synth/sqlch113.ts +2 -3
  127. package/src/lint/post-synth/sqlch114.ts +2 -3
  128. package/src/lint/post-synth/sqlch115.ts +2 -3
  129. package/src/lint/post-synth/sqlch120.ts +2 -3
  130. package/src/lint/post-synth/sqlch125.ts +2 -3
  131. package/src/postgres/apply/statements.ts +2 -0
  132. package/src/postgres/entities.ts +9 -1
  133. package/src/postgres/parser.ts +31 -8
  134. package/src/postgres/plan/diff.ts +18 -0
  135. package/src/postgres/plan/normalize.ts +12 -0
  136. package/src/postgres/plan/rules.ts +7 -0
  137. package/src/postgres/testdata/server-ddl-baseline.json +38 -0
  138. package/src/postgres.ts +12 -0
  139. package/src/read/clickhouse.ts +137 -0
  140. package/src/read/objects.ts +137 -0
  141. package/src/read/postgres.ts +180 -0
  142. package/src/read-policies.e2e.test.ts +144 -0
  143. package/src/read.test.ts +143 -0
  144. package/src/read.ts +69 -0
  145. package/src/serializer.ts +37 -1
  146. package/src/sql-files.ts +27 -6
  147. package/src/sql-types.ts +19 -2
  148. package/src/unknown-clauses.test.ts +227 -0
@@ -8,54 +8,26 @@
8
8
  import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
9
9
  import { POSTGRES_MAJORS, VERSION_RANGES } from "../../generated/postgres";
10
10
  import type { VersionRange } from "../../postgres/catalog-types";
11
- import type { ColumnDef, KeyDef } from "../../postgres/entities";
12
- import { postgresMajorOf, postgresObjects, type OutputObject } from "./sql-helpers";
11
+ import { readPostgres, type PostgresIndexInfo, type PostgresTableInfo, type PostgresViewInfo } from "../../read/postgres";
12
+ import type { PostgresIndexJson, PostgresTableJson, PostgresViewJson } from "../../read/objects";
13
+ import { postgresMajorOf, type OutputObject } from "./sql-helpers";
13
14
 
14
- export interface PgTable extends OutputObject {
15
- sqlName: string;
16
- like: string[];
17
- schema?: string;
18
- comment?: string;
19
- columns: Array<ColumnDef & { comment?: string }>;
20
- primaryKey?: KeyDef;
21
- uniques: KeyDef[];
22
- checks: Array<{ name?: string; expr: string; notEnforced?: boolean }>;
23
- foreignKeys: Array<{ name?: string; columns: string[]; refTable: string; refColumns: string[] }>;
24
- exclusions: unknown[];
25
- inherits: unknown[];
26
- partitionOf?: unknown;
27
- ofType?: unknown;
28
- persistence?: string;
29
- with?: string;
30
- }
31
-
32
- export interface PgIndex extends OutputObject {
33
- sqlName: string;
34
- schema?: string;
35
- table: string;
36
- tableName: string;
37
- unique?: boolean;
38
- method?: string;
39
- elements: Array<{ expr: string; column?: string }>;
40
- include?: string;
41
- where?: string;
42
- with?: string;
43
- }
44
-
45
- export interface PgView extends OutputObject {
46
- sqlName: string;
47
- schema?: string;
48
- query: string;
49
- with?: string;
50
- }
15
+ /**
16
+ * The objects as the public read API types them (`../../read/postgres.ts`,
17
+ * `@intentius/chant-lexicon-sql/read`): the checks and a project's own
18
+ * `lint.policies` read the same values.
19
+ */
20
+ export type PgTable = PostgresTableInfo;
21
+ export type PgIndex = PostgresIndexInfo;
22
+ export type PgView = PostgresViewInfo;
51
23
 
52
- export const isTable = (o: OutputObject): o is PgTable => o.type === "Postgres::Table";
53
- export const isIndex = (o: OutputObject): o is PgIndex => o.type === "Postgres::Index";
54
- export const isView = (o: OutputObject): o is PgView => o.type === "Postgres::View";
55
- export const isMaterializedView = (o: OutputObject): o is PgView => o.type === "Postgres::MaterializedView";
24
+ export const isTable = (o: OutputObject): o is OutputObject & PostgresTableJson => o.type === "Postgres::Table";
25
+ export const isIndex = (o: OutputObject): o is OutputObject & PostgresIndexJson => o.type === "Postgres::Index";
26
+ export const isView = (o: OutputObject): o is OutputObject & PostgresViewJson => o.type === "Postgres::View";
27
+ export const isMaterializedView = (o: OutputObject): o is OutputObject & PostgresViewJson => o.type === "Postgres::MaterializedView";
56
28
 
57
- export const tablesOf = (ctx: PostSynthContext): PgTable[] => postgresObjects(ctx).filter(isTable);
58
- export const indexesOf = (ctx: PostSynthContext): PgIndex[] => postgresObjects(ctx).filter(isIndex);
29
+ export const tablesOf = (ctx: PostSynthContext): PgTable[] => readPostgres(ctx).tables;
30
+ export const indexesOf = (ctx: PostSynthContext): PgIndex[] => readPostgres(ctx).indexes;
59
31
 
60
32
  /** The major the build targets (`postgresMajor` in the output), else the newest pinned. */
61
33
  export const targetMajor = (ctx: PostSynthContext): number => postgresMajorOf(ctx, PINNED_MAJOR);
@@ -87,14 +59,7 @@ export function storageParams(text: string | undefined): Map<string, string> {
87
59
  }
88
60
 
89
61
  /** The leading bare-column elements of an index, in order; stops at the first expression. */
90
- export function leadingColumns(index: PgIndex): string[] {
91
- const out: string[] = [];
92
- for (const e of index.elements) {
93
- if (!e.column) break;
94
- out.push(e.column);
95
- }
96
- return out;
97
- }
62
+ export const leadingColumns = (index: PgIndex): string[] => index.columns;
98
63
 
99
64
  /** A check over the build's Postgres objects, so each check file holds its rule. */
100
65
  export function checkOf(
@@ -12,13 +12,13 @@
12
12
  */
13
13
 
14
14
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
15
- import { COLUMN_TYPES, FUNCTIONS, INDEX_ACCESS_METHODS, KEYWORDS, OPERATOR_CLASSES } from "../../generated/postgres";
15
+ import { COLUMN_TYPES, FUNCTIONS, INDEX_ACCESS_METHODS, KEYWORDS, OPERATOR_CLASSES, POSTGRES_MAJORS } from "../../generated/postgres";
16
16
  import { EXTENSION_OBJECTS } from "../../postgres/overlays/extension-objects";
17
17
  import { GRAMMAR_TYPE_SPELLINGS, SERIAL_TYPES, SERIAL_WIDTH_SPELLINGS, TYPE_SPELLINGS } from "../../postgres/overlays/types";
18
18
  import { isTrivia, tokenizeText, type Token } from "../../postgres/tokens";
19
19
  import type { ColumnTypeSpec } from "../../postgres/catalog-types";
20
- import { targetMajor, type PgTable } from "./postgres-helpers";
21
- import { postgresObjects, type OutputObject } from "./sql-helpers";
20
+ import { dialectObjects, recordedPostgresMajor, type PostgresTableJson as PgTable } from "../../read/objects";
21
+ import type { OutputObject } from "./sql-helpers";
22
22
 
23
23
  // ── Catalog lookups ────────────────────────────────────────────────────
24
24
 
@@ -120,7 +120,7 @@ export interface PgProject {
120
120
  }
121
121
 
122
122
  export function projectOf(ctx: PostSynthContext): PgProject {
123
- return projectFromObjects(postgresObjects(ctx), targetMajor(ctx));
123
+ return projectFromObjects(dialectObjects(ctx, "postgres"), recordedPostgresMajor(ctx, POSTGRES_MAJORS[POSTGRES_MAJORS.length - 1]!));
124
124
  }
125
125
 
126
126
  /** The project a set of output objects declares, at `major`: for a reader that holds the build output itself (`chant sql types`). */
@@ -386,7 +386,7 @@ function providesFunction(e: (typeof EXTENSION_OBJECTS)[string], name: string):
386
386
  export function expressionsOf(o: OutputObject): Array<{ where: string; expr: string }> {
387
387
  const out: Array<{ where: string; expr: string }> = [];
388
388
  if (o.type === "Postgres::Table") {
389
- const t = o as PgTable;
389
+ const t = o as unknown as PgTable;
390
390
  for (const c of t.columns) {
391
391
  if (c.default) out.push({ where: `column ${c.name}'s DEFAULT`, expr: c.default });
392
392
  if (c.generated?.expr) out.push({ where: `generated column ${c.name}`, expr: c.generated.expr });
@@ -483,7 +483,7 @@ export function interpolatedTable(p: PgProject, ref: unknown, sqlName: string |
483
483
  const o = p.byExport.get(ref);
484
484
  if (!o || o.type !== "Postgres::Table") return undefined;
485
485
  if (sqlName !== undefined && o.sqlName !== sqlName) return undefined;
486
- return o as PgTable;
486
+ return o as unknown as PgTable;
487
487
  }
488
488
 
489
489
  /**
@@ -1,41 +1,26 @@
1
1
  /**
2
2
  * Reading the sql lexicon's build output in a post-synth check: the JSON
3
- * document the serializer writes (`dialect`, `applyOrder`, `objects`).
3
+ * document the serializer writes (`dialect`, `applyOrder`, `objects`). The
4
+ * documents are found by `../../read/objects.ts`, the same path the public
5
+ * read API (`@intentius/chant-lexicon-sql/read`) takes.
4
6
  */
5
7
 
6
8
  import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
9
+ import { dialectObjects, recordedPostgresMajor, type SqlObjectJson } from "../../read/objects";
7
10
 
8
- export interface OutputObject {
9
- export: string;
10
- type: string;
11
- name: string;
11
+ export interface OutputObject extends SqlObjectJson {
12
12
  database?: string;
13
13
  engine?: { name: string; args?: string[] };
14
- [key: string]: unknown;
15
14
  }
16
15
 
17
16
  /** Every schema object in the build's sql output, ClickHouse dialect. */
18
17
  export function clickhouseObjects(ctx: PostSynthContext): OutputObject[] {
19
- const out: OutputObject[] = [];
20
- for (const doc of ctx.docs ?? []) {
21
- if (doc.error || doc.lexicon !== "sql" || doc.format !== "json") continue;
22
- const value = doc.value as { dialect?: unknown; objects?: unknown };
23
- if (value?.dialect !== "clickhouse" || !Array.isArray(value.objects)) continue;
24
- out.push(...(value.objects as OutputObject[]));
25
- }
26
- return out;
18
+ return dialectObjects(ctx, "clickhouse") as OutputObject[];
27
19
  }
28
20
 
29
21
  /** Every schema object in the build's sql output, Postgres dialect. */
30
22
  export function postgresObjects(ctx: PostSynthContext): OutputObject[] {
31
- const out: OutputObject[] = [];
32
- for (const doc of ctx.docs ?? []) {
33
- if (doc.error || doc.lexicon !== "sql" || doc.format !== "json") continue;
34
- const value = doc.value as { dialect?: unknown; objects?: unknown };
35
- if (value?.dialect !== "postgres" || !Array.isArray(value.objects)) continue;
36
- out.push(...(value.objects as OutputObject[]));
37
- }
38
- return out;
23
+ return dialectObjects(ctx, "postgres") as OutputObject[];
39
24
  }
40
25
 
41
26
  /**
@@ -44,10 +29,5 @@ export function postgresObjects(ctx: PostSynthContext): OutputObject[] {
44
29
  * output that carries none.
45
30
  */
46
31
  export function postgresMajorOf(ctx: PostSynthContext, fallback: number): number {
47
- for (const doc of ctx.docs ?? []) {
48
- if (doc.error || doc.lexicon !== "sql" || doc.format !== "json") continue;
49
- const value = doc.value as { dialect?: unknown; postgresMajor?: unknown };
50
- if (value?.dialect === "postgres" && typeof value.postgresMajor === "number") return value.postgresMajor;
51
- }
52
- return fallback;
32
+ return recordedPostgresMajor(ctx, fallback);
53
33
  }
@@ -1,5 +1,4 @@
1
- import { checkOf, isTable, keyElements } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { checkOf, keyElements, tablesOf } from "./clickhouse-helpers";
3
2
 
4
3
  /**
5
4
  * SQLCH102: a PRIMARY KEY that is not a prefix of ORDER BY.
@@ -9,7 +8,7 @@ import { clickhouseObjects } from "./sql-helpers";
9
8
  * the table at CREATE.
10
9
  */
11
10
  export const sqlch102 = checkOf({ id: "SQLCH102", description: "A PRIMARY KEY is not a prefix of ORDER BY" }, (ctx, report) => {
12
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
11
+ for (const t of tablesOf(ctx)) {
13
12
  if (!t.primaryKey || !t.orderBy) continue;
14
13
  const pk = keyElements(t.primaryKey).map((e) => e.replace(/\s+/g, ""));
15
14
  const ob = keyElements(t.orderBy).map((e) => e.replace(/\s+/g, ""));
@@ -1,5 +1,4 @@
1
- import { baseEngineName, checkOf, columnByName, engineArguments, isNullableType, isTable, typeFamily } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { baseEngineName, checkOf, columnByName, engineArguments, isNullableType, tablesOf, typeFamily } from "./clickhouse-helpers";
3
2
 
4
3
  const VERSION_TYPES = new Set(["UInt8", "UInt16", "UInt32", "UInt64", "UInt128", "UInt256", "Date", "DateTime", "DateTime64"]);
5
4
 
@@ -25,7 +24,7 @@ const SPECIAL: Record<string, Array<{ role: string; index: number; accepts: (fam
25
24
  * .../collapsingmergetree, .../versionedcollapsingmergetree (sign: Int8).
26
25
  */
27
26
  export const sqlch103 = checkOf({ id: "SQLCH103", description: "An engine's version, sign or is_deleted column has an unsupported type" }, (ctx, report) => {
28
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
27
+ for (const t of tablesOf(ctx)) {
29
28
  if (!t.engine) continue;
30
29
  const roles = SPECIAL[baseEngineName(t.engine)];
31
30
  if (!roles) continue;
@@ -1,5 +1,4 @@
1
- import { baseEngineName, checkOf, engineArguments, isTable, splitTop } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { baseEngineName, checkOf, engineArguments, splitTop, tablesOf } from "./clickhouse-helpers";
3
2
 
4
3
  /** The engine arguments that name columns, by base engine. */
5
4
  function columnArguments(engine: string, args: string[]): string[] {
@@ -26,7 +25,7 @@ function columnArguments(engine: string, args: string[]): string[] {
26
25
  * sign, version, is_deleted and summed columns are columns of the table).
27
26
  */
28
27
  export const sqlch104 = checkOf({ id: "SQLCH104", description: "A MergeTree engine argument names a column the table does not declare" }, (ctx, report) => {
29
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
28
+ for (const t of tablesOf(ctx)) {
30
29
  if (!t.engine || t.columns.length === 0) continue;
31
30
  const declared = new Set(t.columns.map((c) => c.name));
32
31
  for (const arg of columnArguments(baseEngineName(t.engine), engineArguments(t.engine))) {
@@ -1,5 +1,4 @@
1
- import { bareName, checkOf, isTable, keyElements } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { bareName, checkOf, keyElements, tablesOf } from "./clickhouse-helpers";
3
2
 
4
3
  /**
5
4
  * SQLCH105: ORDER BY, PRIMARY KEY, PARTITION BY or SAMPLE BY lists a bare
@@ -10,7 +9,7 @@ import { clickhouseObjects } from "./sql-helpers";
10
9
  * judged; an expression is left to the server.
11
10
  */
12
11
  export const sqlch105 = checkOf({ id: "SQLCH105", description: "A table key clause names a column the table does not declare" }, (ctx, report) => {
13
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
12
+ for (const t of tablesOf(ctx)) {
14
13
  if (t.columns.length === 0) continue;
15
14
  const declared = new Set(t.columns.map((c) => c.name));
16
15
  const clauses: Array<[string, string | undefined]> = [
@@ -1,5 +1,4 @@
1
- import { checkOf, isTable, mentionedNames } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { checkOf, mentionedNames, tablesOf } from "./clickhouse-helpers";
3
2
 
4
3
  /**
5
4
  * SQLCH106: a data skipping index expression mentions a column the table does
@@ -11,7 +10,7 @@ import { clickhouseObjects } from "./sql-helpers";
11
10
  * SQL parser would guess.
12
11
  */
13
12
  export const sqlch106 = checkOf({ id: "SQLCH106", description: "A skip index expression names a column the table does not declare" }, (ctx, report) => {
14
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
13
+ for (const t of tablesOf(ctx)) {
15
14
  if (t.columns.length === 0) continue;
16
15
  const declared = new Set(t.columns.map((c) => c.name));
17
16
  for (const index of t.indexes ?? []) {
@@ -1,5 +1,4 @@
1
- import { bareName, checkOf, isTable, splitTop, typeFamily } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { bareName, checkOf, splitTop, tablesOf, typeFamily } from "./clickhouse-helpers";
3
2
 
4
3
  const DATE_TYPES = new Set(["Date", "Date32", "DateTime", "DateTime64"]);
5
4
  const TTL_ACTION = /\s+(DELETE|TO\s+DISK|TO\s+VOLUME|RECOMPRESS|GROUP\s+BY|WHERE)\b[\s\S]*$/i;
@@ -13,7 +12,7 @@ const TTL_ACTION = /\s+(DELETE|TO\s+DISK|TO\s+VOLUME|RECOMPRESS|GROUP\s+BY|WHERE
13
12
  * a function call is left to the server.
14
13
  */
15
14
  export const sqlch107 = checkOf({ id: "SQLCH107", description: "A TTL expression is built on a column that is not a Date or DateTime" }, (ctx, report) => {
16
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
15
+ for (const t of tablesOf(ctx)) {
17
16
  const ttls: Array<{ where: string; expr: string }> = [];
18
17
  if (t.ttl) for (const clause of splitTop(t.ttl)) ttls.push({ where: "table TTL", expr: clause.replace(TTL_ACTION, "") });
19
18
  for (const c of t.columns) if (c.ttl) ttls.push({ where: `column ${c.name} TTL`, expr: c.ttl.replace(TTL_ACTION, "") });
@@ -1,5 +1,4 @@
1
- import { checkOf, isTable, splitTop } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { checkOf, splitTop, tablesOf } from "./clickhouse-helpers";
3
2
 
4
3
  const MAX_VALUES = 100;
5
4
 
@@ -23,7 +22,7 @@ function allowedValues(expr: string): { column: string; count: number } | undefi
23
22
  * https://clickhouse.com/docs/best-practices/select-data-types.
24
23
  */
25
24
  export const sqlch111 = checkOf({ id: "SQLCH111", description: "A String column limited to a few values is not LowCardinality" }, (ctx, report) => {
26
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
25
+ for (const t of tablesOf(ctx)) {
27
26
  for (const c of t.constraints ?? []) {
28
27
  if (c.kind !== "CHECK") continue;
29
28
  const found = allowedValues(c.expr);
@@ -1,5 +1,4 @@
1
- import { checkOf, isTable, typeFamily } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { checkOf, tablesOf, typeFamily } from "./clickhouse-helpers";
3
2
 
4
3
  const FINE_FUNCTIONS =
5
4
  /\b(toStartOfSecond|toStartOfMinute|toStartOfFiveMinutes?|toStartOfTenMinutes|toStartOfFifteenMinutes|toStartOfHour|toRelativeSecondNum|toRelativeMinuteNum|toRelativeHourNum|toUnixTimestamp|toYYYYMMDDhhmmss|toStartOfInterval)\s*\(/;
@@ -15,7 +14,7 @@ const FINE_FUNCTIONS =
15
14
  * the sub-day truncation functions.
16
15
  */
17
16
  export const sqlch112 = checkOf({ id: "SQLCH112", description: "A PARTITION BY expression is finer than a day" }, (ctx, report) => {
18
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
17
+ for (const t of tablesOf(ctx)) {
19
18
  const expr = t.partitionBy?.trim();
20
19
  if (!expr) continue;
21
20
  const col = t.columns.find((c) => c.name === expr.replace(/^\(|\)$/g, "").trim());
@@ -1,5 +1,4 @@
1
- import { checkOf, isMergeTree, isTable } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { checkOf, isMergeTree, tablesOf } from "./clickhouse-helpers";
3
2
 
4
3
  /**
5
4
  * SQLCH113: a MergeTree table with neither ORDER BY nor PRIMARY KEY.
@@ -9,7 +8,7 @@ import { clickhouseObjects } from "./sql-helpers";
9
8
  * `ORDER BY tuple()` to have none). The server refuses the CREATE.
10
9
  */
11
10
  export const sqlch113 = checkOf({ id: "SQLCH113", description: "A MergeTree table declares no sort key" }, (ctx, report) => {
12
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
11
+ for (const t of tablesOf(ctx)) {
13
12
  if (!isMergeTree(t.engine) || t.orderBy || t.primaryKey) continue;
14
13
  report({
15
14
  severity: "error",
@@ -1,6 +1,5 @@
1
1
  import { CODECS } from "../../generated/clickhouse";
2
- import { checkOf, codecNames, isTable } from "./clickhouse-helpers";
3
- import { clickhouseObjects } from "./sql-helpers";
2
+ import { checkOf, codecNames, tablesOf } from "./clickhouse-helpers";
4
3
 
5
4
  /**
6
5
  * SQLCH114: a column CODEC names a codec the pinned server does not have.
@@ -10,7 +9,7 @@ import { clickhouseObjects } from "./sql-helpers";
10
9
  */
11
10
  export const sqlch114 = checkOf({ id: "SQLCH114", description: "A column codec is not one the pinned server has" }, (ctx, report) => {
12
11
  const known = new Set(Object.keys(CODECS).map((n) => n.toLowerCase()));
13
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
12
+ for (const t of tablesOf(ctx)) {
14
13
  for (const c of t.columns) {
15
14
  if (!c.codec) continue;
16
15
  for (const name of codecNames(c.codec)) {
@@ -1,6 +1,5 @@
1
1
  import { CODECS } from "../../generated/clickhouse";
2
- import { checkOf, codecNames, isTable } from "./clickhouse-helpers";
3
- import { clickhouseObjects } from "./sql-helpers";
2
+ import { checkOf, codecNames, tablesOf } from "./clickhouse-helpers";
4
3
 
5
4
  const SENSITIVE = /(^|_)(password|passwd|pwd|secret|api_?key|access_?key|private_?key|token|ssn|social_?security|credit_?card|card_?number|iban)(_|$)/i;
6
5
 
@@ -17,7 +16,7 @@ const SENSITIVE = /(^|_)(password|passwd|pwd|secret|api_?key|access_?key|private
17
16
  */
18
17
  export const sqlch115 = checkOf({ id: "SQLCH115", description: "A secret- or PII-named column carries no comment, TTL or encryption" }, (ctx, report) => {
19
18
  const encryption = new Set(Object.entries(CODECS).filter(([, s]) => s.encryption).map(([n]) => n.toLowerCase()));
20
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
19
+ for (const t of tablesOf(ctx)) {
21
20
  for (const c of t.columns) {
22
21
  if (!SENSITIVE.test(c.name) || c.comment || c.ttl || t.ttl) continue;
23
22
  if (c.codec && codecNames(c.codec).some((n) => encryption.has(n.toLowerCase()))) continue;
@@ -1,5 +1,4 @@
1
- import { checkOf, isTable } from "./clickhouse-helpers";
2
- import { clickhouseObjects } from "./sql-helpers";
1
+ import { checkOf, tablesOf } from "./clickhouse-helpers";
3
2
 
4
3
  /**
5
4
  * SQLCH120: a MergeTree engine written with the legacy positional arguments.
@@ -10,7 +9,7 @@ import { clickhouseObjects } from "./sql-helpers";
10
9
  * syntax is a bare `MergeTree` with ORDER BY, PARTITION BY and SETTINGS.
11
10
  */
12
11
  export const sqlch120 = checkOf({ id: "SQLCH120", description: "A MergeTree engine uses the deprecated positional arguments" }, (ctx, report) => {
13
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
12
+ for (const t of tablesOf(ctx)) {
14
13
  if (t.engine?.name !== "MergeTree" || (t.engine.args ?? []).length === 0) continue;
15
14
  report({
16
15
  severity: "warning",
@@ -1,6 +1,5 @@
1
1
  import { CODECS, CLICKHOUSE_VERSION } from "../../generated/clickhouse";
2
- import { checkOf, isTable, splitTop } from "./clickhouse-helpers";
3
- import { clickhouseObjects } from "./sql-helpers";
2
+ import { checkOf, splitTop, tablesOf } from "./clickhouse-helpers";
4
3
 
5
4
  type Param = { name: string; kind: string; optional?: boolean; range?: readonly [number, number]; values?: readonly string[] };
6
5
 
@@ -17,7 +16,7 @@ const NUMBER = /^-?\d+(\.\d+)?$/;
17
16
  */
18
17
  export const sqlch125 = checkOf({ id: "SQLCH125", description: "A codec parameter is outside what the codec takes" }, (ctx, report) => {
19
18
  const codecs = CODECS as Record<string, { parameters: readonly Param[] | "unknown" } | undefined>;
20
- for (const t of clickhouseObjects(ctx).filter(isTable)) {
19
+ for (const t of tablesOf(ctx)) {
21
20
  for (const c of t.columns) {
22
21
  if (!c.codec) continue;
23
22
  for (const part of splitTop(c.codec)) {
@@ -25,11 +25,21 @@
25
25
  * targets (`sql.postgresMajor`, else the newest pinned major). Post-synth
26
26
  * checks and the lock classifier read it; ClickHouse output has no such field.
27
27
  *
28
+ * A clause chant's parser does not know (#3872) is kept in the statement as
29
+ * written and named in a build warning ({@link unparsedWarnings}).
30
+ *
28
31
  * Rule ids: `SQL` for rules that hold in every dialect, `SQLCH` for the
29
32
  * ClickHouse dialect's (#3199), `SQLPG` for Postgres's (#3289).
30
33
  */
31
- import type { Serializer } from "@intentius/chant";
34
+ import type { Declarable, Serializer } from "@intentius/chant";
32
35
  export { applyOrder } from "./core/references.js";
36
+ /**
37
+ * A warning for each clause chant's parser does not know (#3872): where it
38
+ * is (the `.sql` file and line, or the template's file and the line in its
39
+ * statement), which object, and what follows from it. The statement is sent
40
+ * as written; the server decides.
41
+ */
42
+ export declare function unparsedWarnings(objects: ReadonlyMap<string, Declarable>): string[];
33
43
  /** The file the statements are written to, beside the primary output. */
34
44
  export declare const CLICKHOUSE_DDL_FILE = "clickhouse.sql";
35
45
  /** The Postgres statements' file, beside the primary output. */
@@ -1 +1 @@
1
- {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAc,UAAU,EAAoB,MAAM,kBAAkB,CAAC;AASjF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD,gEAAgE;AAChE,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAmEhD,eAAO,MAAM,aAAa,EAAE,UAuC3B,CAAC"}
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAoB,MAAM,kBAAkB,CAAC;AAYjF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,MAAM,EAAE,CAkBnF;AAED,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD,gEAAgE;AAChE,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAqEhD,eAAO,MAAM,aAAa,EAAE,UAyC3B,CAAC"}
@@ -18,7 +18,9 @@
18
18
  * `MATERIALIZED VIEW`, `DICTIONARY`, `FUNCTION`, `USER`, `ROLE` and `ROW
19
19
  * POLICY`, and `GRANT` (#3711). Any other statement, and any
20
20
  * statement that does not parse, throws a {@link SqlFileError} naming every
21
- * such statement: none is left out.
21
+ * such statement: none is left out. A statement that parses except for a
22
+ * clause the parser does not know (#3872) is read, kept as written, and the
23
+ * clause listed in its object's `unparsed` with the line it is on.
22
24
  *
23
25
  * A name is a reference where it is qualified (`app.users`), or bare where an
24
26
  * object is named (`REFERENCES users`, `FROM users`, an index's table, a
@@ -41,6 +43,18 @@ export interface SqlFileObject {
41
43
  ddl: string;
42
44
  /** The file it came from, the `origin` it was read under. */
43
45
  origin: string;
46
+ /** The line its statement starts on in the file, from 1. */
47
+ line?: number;
48
+ /**
49
+ * Clauses in it chant's parser does not know (#3872), each with the line
50
+ * it starts on: kept in `ddl` as written, for the server to check. Absent
51
+ * when there are none.
52
+ */
53
+ unparsed?: Array<{
54
+ clause: string;
55
+ line: number;
56
+ column?: string;
57
+ }>;
44
58
  }
45
59
  /** A file to read: its DDL and the name errors give it. */
46
60
  export interface SqlFileSource extends ReadOptions {
@@ -60,6 +74,8 @@ export declare function sqlFileDeclarations(dialect: SqlDialect, ddl: string, op
60
74
  };
61
75
  /** Where an entity read from a `.sql` file came from: its `origin`. Undefined for any other entity. */
62
76
  export declare function sqlFileOf(entity: unknown): string | undefined;
77
+ /** The line an entity read from a `.sql` file starts on in it. Undefined for any other entity. */
78
+ export declare function sqlFileLineOf(entity: unknown): number | undefined;
63
79
  /**
64
80
  * The declarations the files make, by export name. `known` holds the
65
81
  * entities declared elsewhere (the project's tagged templates): a file's
@@ -1 +1 @@
1
- {"version":3,"file":"sql-files.d.ts","sourceRoot":"","sources":["../src/sql-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAUhE,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,WAAW,IAAI,cAAc,EAAE,CAAC;AAE9C,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,+GAA+G;IAC/G,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,GAAG,EAAE,MAAM,CAAC;CACb;AAuBD,8GAA8G;AAC9G,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAInG;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,CAW/J;AAED,uGAAuG;AACvG,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE7D;AA4BD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,aAAa,EAAE,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CAAO,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAqD1K;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAatH"}
1
+ {"version":3,"file":"sql-files.d.ts","sourceRoot":"","sources":["../src/sql-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAiB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAU/E,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,WAAW,IAAI,cAAc,EAAE,CAAC;AAE9C,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,+GAA+G;IAC/G,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrE;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,GAAG,EAAE,MAAM,CAAC;CACb;AA0BD,8GAA8G;AAC9G,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAInG;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,CAW/J;AAED,uGAAuG;AACvG,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE7D;AAED,kGAAkG;AAClG,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEjE;AA6BD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,aAAa,EAAE,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CAAO,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAuD1K;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAatH"}
@@ -22,6 +22,9 @@
22
22
  * (`./lint/post-synth/postgres-names.ts`'s `typeIdentity`), the type
23
23
  * family in ClickHouse; `never` when it cannot be told.
24
24
  *
25
+ * A column that carries a clause chant does not read (#3872) keeps the type
26
+ * that was read, with `nullable` and `cmp` `never`.
27
+ *
25
28
  * A view's column that is one column reference (`${t.columns.c}`, `o.${t.columns.c}`)
26
29
  * is that column's type; any other expression is `unknown`.
27
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"sql-types.d.ts","sourceRoot":"","sources":["../src/sql-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAW9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7C,4EAA4E;AAC5E,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAGpG;AAED,kGAAkG;AAClG,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EACzC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,qBAA0B,GAC/B,SAAS,GAAG,OAAO,GAAG,SAAS,CASjC;AAED,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAGjE,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,yGAAyG;IACzG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yGAAyG;IACzG,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAiOD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,IAAI,GAAE,qBAA0B,GAAG,MAAM,CAiClH"}
1
+ {"version":3,"file":"sql-types.d.ts","sourceRoot":"","sources":["../src/sql-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAW9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7C,4EAA4E;AAC5E,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAGpG;AAED,kGAAkG;AAClG,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EACzC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,qBAA0B,GAC/B,SAAS,GAAG,OAAO,GAAG,SAAS,CASjC;AAED,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAGjE,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,yGAAyG;IACzG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yGAAyG;IACzG,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AA+OD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,IAAI,GAAE,qBAA0B,GAAG,MAAM,CAiClH"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-sql",
3
- "version": "0.124.12",
3
+ "version": "0.124.14",
4
4
  "description": "SQL lexicon for chant — database schema as typed declarations, one dialect at a time; ClickHouse first, with types read from a pinned server's catalog",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -70,6 +70,6 @@
70
70
  "typescript": "^5.9.3"
71
71
  },
72
72
  "peerDependencies": {
73
- "@intentius/chant": "^0.124.12"
73
+ "@intentius/chant": "^0.124.14"
74
74
  }
75
75
  }
@@ -187,6 +187,8 @@ export function refusalDetail(changes: readonly Change[], key?: string, type?: s
187
187
  type === undefined || type === CLICKHOUSE_ENTITY_TYPES.table
188
188
  ? `Run it as the rebuild migration Op: ClickHouseRebuildOp({ table: ${JSON.stringify(key ?? "<database.table>")}, ... }) from @intentius/chant-lexicon-sql/clickhouse`
189
189
  : "The rebuild migration Op rebuilds tables only; drop and create this object instead";
190
+ // A clause chant does not read (#3872) is refused for review: whether ALTER can make it is not known.
191
+ if (changes.every((c) => c.rule === "SQLCH290")) return `needs review, since chant does not read the clause: ${parts.join("; ")}`;
190
192
  return `needs a rebuild, which ALTER cannot make: ${parts.join("; ")}. ${instead}`;
191
193
  }
192
194
 
@@ -42,7 +42,7 @@ import { setInterpolationFields } from "@intentius/chant/provenance";
42
42
  import { CLICKHOUSE_LEXICAL, isTrivia, SqlSyntaxError, untokenize } from "./tokens";
43
43
  import { parseCreate, unquote, type ColumnNode, type CreateNode, type Span, type StorageNode } from "./parser";
44
44
  import { parseAccess, type AccessNode } from "./access";
45
- import { feed, lineage, spanText as text, splice as spliceWith, templateSyntaxError, type TemplateCtx, type TemplateDialect } from "../core/interpolation";
45
+ import { feed, lineage, spanText as text, splice as spliceWith, templateSyntaxError, unparsedClauses, type TemplateCtx, type TemplateDialect, type UnparsedClause } from "../core/interpolation";
46
46
  import { SQL_LEXICON, SqlObject, isColumnRefOf, isSqlObjectOf, makeSqlEntity } from "../core/entity";
47
47
  import type { LineageEdge } from "../core/references";
48
48
  import { SqlLiteral, SqlTemplateError, describeValue as describe, stripUnset as strip, templateParts } from "../core/template";
@@ -50,6 +50,7 @@ import { setTypedSlots, type ColumnsIn, type Named, type RowIn, type SlotsIn, ty
50
50
 
51
51
  export { SQL_LEXICON } from "../core/entity";
52
52
  export type { LineageEdge } from "../core/references";
53
+ export type { UnparsedClause } from "../core/interpolation";
53
54
  export { SqlLiteral, SqlTemplateError, templateParts, unescapeTemplateDelimiters } from "../core/template";
54
55
  export type { AnyColumn, Column, ColumnTraits, KeyColumn, Named, NotNullColumn, UncheckedColumn, Unnamed } from "../core/typed";
55
56
 
@@ -110,6 +111,11 @@ interface CommonProps {
110
111
  ddl: string;
111
112
  /** The template's raw parts, as written, for a source round trip. */
112
113
  source: { strings: string[] };
114
+ /**
115
+ * Clauses chant's parser does not know (#3872), kept in `ddl` as written
116
+ * and left to the catalog checks and the server. Absent when there are none.
117
+ */
118
+ unparsed?: UnparsedClause[];
113
119
  }
114
120
 
115
121
  export interface DatabaseProps extends CommonProps {
@@ -540,6 +546,7 @@ function build(tag: Expect, strings: TemplateStringsArray | readonly string[], v
540
546
  database,
541
547
  onCluster: text(ctx, node.onCluster, "onCluster"),
542
548
  comment: stringValue(text(ctx, node.comment, "comment")),
549
+ unparsed: unparsedClauses(ctx, node.unknown),
543
550
  };
544
551
  const done = <T extends ClickHouseObject>(entity: T): T => {
545
552
  setInterpolationFields(entity, ctx.fed.map((paths) => [...paths].sort()));