@intentius/chant-lexicon-sql 0.121.0 → 0.122.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 (150) hide show
  1. package/dist/clickhouse/catalog-types.d.ts +8 -0
  2. package/dist/clickhouse/catalog-types.d.ts.map +1 -1
  3. package/dist/clickhouse/overlays/codecs.d.ts.map +1 -1
  4. package/dist/clickhouse/overlays/kinds.d.ts +1 -1
  5. package/dist/clickhouse/overlays/kinds.d.ts.map +1 -1
  6. package/dist/clickhouse/overlays/types.d.ts.map +1 -1
  7. package/dist/clickhouse/type-syntax.d.ts +33 -0
  8. package/dist/clickhouse/type-syntax.d.ts.map +1 -0
  9. package/dist/codegen/clickhouse-module.d.ts.map +1 -1
  10. package/dist/codegen/postgres-module.d.ts.map +1 -1
  11. package/dist/generated/clickhouse.d.ts +7 -1
  12. package/dist/generated/clickhouse.d.ts.map +1 -1
  13. package/dist/generated/postgres.d.ts +6 -0
  14. package/dist/generated/postgres.d.ts.map +1 -1
  15. package/dist/integrity.json +23 -5
  16. package/dist/lint/audit-catalog.d.ts.map +1 -1
  17. package/dist/lint/post-synth/audit-entries.d.ts.map +1 -1
  18. package/dist/lint/post-synth/clickhouse-type-check.d.ts +37 -0
  19. package/dist/lint/post-synth/clickhouse-type-check.d.ts.map +1 -0
  20. package/dist/lint/post-synth/index.d.ts.map +1 -1
  21. package/dist/lint/post-synth/postgres-audit-entries.d.ts.map +1 -1
  22. package/dist/lint/post-synth/postgres-names.d.ts +149 -0
  23. package/dist/lint/post-synth/postgres-names.d.ts.map +1 -0
  24. package/dist/lint/post-synth/sql101.d.ts +9 -0
  25. package/dist/lint/post-synth/sql101.d.ts.map +1 -0
  26. package/dist/lint/post-synth/sqlch121.d.ts +10 -0
  27. package/dist/lint/post-synth/sqlch121.d.ts.map +1 -0
  28. package/dist/lint/post-synth/sqlch122.d.ts +10 -0
  29. package/dist/lint/post-synth/sqlch122.d.ts.map +1 -0
  30. package/dist/lint/post-synth/sqlch123.d.ts +9 -0
  31. package/dist/lint/post-synth/sqlch123.d.ts.map +1 -0
  32. package/dist/lint/post-synth/sqlch124.d.ts +6 -0
  33. package/dist/lint/post-synth/sqlch124.d.ts.map +1 -0
  34. package/dist/lint/post-synth/sqlch125.d.ts +11 -0
  35. package/dist/lint/post-synth/sqlch125.d.ts.map +1 -0
  36. package/dist/lint/post-synth/sqlch126.d.ts +12 -0
  37. package/dist/lint/post-synth/sqlch126.d.ts.map +1 -0
  38. package/dist/lint/post-synth/sqlch127.d.ts +22 -0
  39. package/dist/lint/post-synth/sqlch127.d.ts.map +1 -0
  40. package/dist/lint/post-synth/sqlpg119.d.ts +18 -0
  41. package/dist/lint/post-synth/sqlpg119.d.ts.map +1 -0
  42. package/dist/lint/post-synth/sqlpg120.d.ts +17 -0
  43. package/dist/lint/post-synth/sqlpg120.d.ts.map +1 -0
  44. package/dist/lint/post-synth/sqlpg121.d.ts +12 -0
  45. package/dist/lint/post-synth/sqlpg121.d.ts.map +1 -0
  46. package/dist/lint/post-synth/sqlpg122.d.ts +12 -0
  47. package/dist/lint/post-synth/sqlpg122.d.ts.map +1 -0
  48. package/dist/lint/post-synth/sqlpg123.d.ts +17 -0
  49. package/dist/lint/post-synth/sqlpg123.d.ts.map +1 -0
  50. package/dist/lint/post-synth/sqlpg124.d.ts +16 -0
  51. package/dist/lint/post-synth/sqlpg124.d.ts.map +1 -0
  52. package/dist/lint/post-synth/sqlpg125.d.ts +17 -0
  53. package/dist/lint/post-synth/sqlpg125.d.ts.map +1 -0
  54. package/dist/lint/post-synth/sqlpg126.d.ts +19 -0
  55. package/dist/lint/post-synth/sqlpg126.d.ts.map +1 -0
  56. package/dist/manifest.json +1 -1
  57. package/dist/okf/index.md +16 -0
  58. package/dist/okf/rules/SQL101.md +23 -0
  59. package/dist/okf/rules/SQLCH121.md +11 -0
  60. package/dist/okf/rules/SQLCH122.md +11 -0
  61. package/dist/okf/rules/SQLCH123.md +11 -0
  62. package/dist/okf/rules/SQLCH124.md +18 -0
  63. package/dist/okf/rules/SQLCH125.md +11 -0
  64. package/dist/okf/rules/SQLCH126.md +15 -0
  65. package/dist/okf/rules/SQLCH127.md +15 -0
  66. package/dist/okf/rules/SQLPG119.md +16 -0
  67. package/dist/okf/rules/SQLPG120.md +16 -0
  68. package/dist/okf/rules/SQLPG121.md +11 -0
  69. package/dist/okf/rules/SQLPG122.md +15 -0
  70. package/dist/okf/rules/SQLPG123.md +16 -0
  71. package/dist/okf/rules/SQLPG124.md +11 -0
  72. package/dist/okf/rules/SQLPG125.md +11 -0
  73. package/dist/okf/rules/SQLPG126.md +11 -0
  74. package/dist/okf/types/Dictionary.md +4 -0
  75. package/dist/okf/types/Function.md +5 -0
  76. package/dist/okf/types/Grant.md +6 -0
  77. package/dist/okf/types/MaterializedView.md +1 -0
  78. package/dist/okf/types/PostgresDefaultPrivileges.md +4 -0
  79. package/dist/okf/types/PostgresDomain.md +2 -0
  80. package/dist/okf/types/PostgresEnum.md +1 -0
  81. package/dist/okf/types/PostgresFunction.md +4 -0
  82. package/dist/okf/types/PostgresGrant.md +5 -0
  83. package/dist/okf/types/PostgresPolicy.md +4 -0
  84. package/dist/okf/types/PostgresProcedure.md +4 -0
  85. package/dist/okf/types/PostgresSequence.md +2 -0
  86. package/dist/okf/types/PostgresTrigger.md +4 -0
  87. package/dist/okf/types/RowPolicy.md +4 -0
  88. package/dist/okf/types/Table.md +1 -0
  89. package/dist/okf/types/View.md +1 -0
  90. package/dist/postgres/overlays/extension-objects.d.ts +28 -0
  91. package/dist/postgres/overlays/extension-objects.d.ts.map +1 -0
  92. package/dist/postgres/overlays/types.d.ts +10 -0
  93. package/dist/postgres/overlays/types.d.ts.map +1 -1
  94. package/dist/rules/audit-entries.ts +7 -0
  95. package/dist/rules/clickhouse-type-check.ts +173 -0
  96. package/dist/rules/postgres-audit-entries.ts +8 -0
  97. package/dist/rules/postgres-names.ts +506 -0
  98. package/dist/rules/sql101.ts +62 -0
  99. package/dist/rules/sqlch121.ts +12 -0
  100. package/dist/rules/sqlch122.ts +12 -0
  101. package/dist/rules/sqlch123.ts +11 -0
  102. package/dist/rules/sqlch124.ts +21 -0
  103. package/dist/rules/sqlch125.ts +56 -0
  104. package/dist/rules/sqlch126.ts +57 -0
  105. package/dist/rules/sqlch127.ts +128 -0
  106. package/dist/rules/sqlpg119.ts +37 -0
  107. package/dist/rules/sqlpg120.ts +70 -0
  108. package/dist/rules/sqlpg121.ts +32 -0
  109. package/dist/rules/sqlpg122.ts +28 -0
  110. package/dist/rules/sqlpg123.ts +63 -0
  111. package/dist/rules/sqlpg124.ts +47 -0
  112. package/dist/rules/sqlpg125.ts +40 -0
  113. package/dist/rules/sqlpg126.ts +37 -0
  114. package/package.json +2 -2
  115. package/src/clickhouse/catalog-types.ts +9 -0
  116. package/src/clickhouse/overlays/codecs.ts +6 -2
  117. package/src/clickhouse/overlays/kinds.ts +1 -1
  118. package/src/clickhouse/overlays/types.ts +20 -3
  119. package/src/clickhouse/type-syntax.ts +82 -0
  120. package/src/codegen/clickhouse-module.ts +15 -1
  121. package/src/codegen/postgres-module.ts +43 -0
  122. package/src/composites/composites.test.ts +7 -6
  123. package/src/generated/clickhouse.ts +1905 -6
  124. package/src/generated/postgres.ts +2639 -0
  125. package/src/lint/audit-catalog.ts +8 -0
  126. package/src/lint/post-synth/audit-entries.ts +7 -0
  127. package/src/lint/post-synth/clickhouse-catalog-checks.test.ts +315 -0
  128. package/src/lint/post-synth/clickhouse-type-check.ts +173 -0
  129. package/src/lint/post-synth/index.ts +32 -0
  130. package/src/lint/post-synth/postgres-audit-entries.ts +8 -0
  131. package/src/lint/post-synth/postgres-checks.test.ts +214 -1
  132. package/src/lint/post-synth/postgres-names.ts +506 -0
  133. package/src/lint/post-synth/sql101.ts +62 -0
  134. package/src/lint/post-synth/sqlch121.ts +12 -0
  135. package/src/lint/post-synth/sqlch122.ts +12 -0
  136. package/src/lint/post-synth/sqlch123.ts +11 -0
  137. package/src/lint/post-synth/sqlch124.ts +21 -0
  138. package/src/lint/post-synth/sqlch125.ts +56 -0
  139. package/src/lint/post-synth/sqlch126.ts +57 -0
  140. package/src/lint/post-synth/sqlch127.ts +128 -0
  141. package/src/lint/post-synth/sqlpg119.ts +37 -0
  142. package/src/lint/post-synth/sqlpg120.ts +70 -0
  143. package/src/lint/post-synth/sqlpg121.ts +32 -0
  144. package/src/lint/post-synth/sqlpg122.ts +28 -0
  145. package/src/lint/post-synth/sqlpg123.ts +63 -0
  146. package/src/lint/post-synth/sqlpg124.ts +47 -0
  147. package/src/lint/post-synth/sqlpg125.ts +40 -0
  148. package/src/lint/post-synth/sqlpg126.ts +37 -0
  149. package/src/postgres/overlays/extension-objects.ts +100 -0
  150. package/src/postgres/overlays/types.ts +25 -0
@@ -29,6 +29,7 @@ const WIDTH: ArgumentOverlay & { name: string } = {
29
29
  name: "bytes",
30
30
  kind: "number",
31
31
  optional: true,
32
+ values: ["1", "2", "4", "8"],
32
33
  note: "1, 2, 4 or 8; the column type's width when omitted.",
33
34
  };
34
35
 
@@ -40,7 +41,10 @@ export const CODEC_OVERLAY: Record<string, CodecOverlay> = {
40
41
  role: "compression",
41
42
  },
42
43
  ZSTD: {
43
- parameters: [{ name: "level", kind: "number", optional: true, range: [1, 22], note: "1 when omitted." }],
44
+ parameters: [
45
+ { name: "level", kind: "number", optional: true, range: [1, 22], note: "1 when omitted." },
46
+ { name: "window_log", kind: "number", optional: true, range: [10, 31], note: "Turns on long-range matching with this window log." },
47
+ ],
44
48
  role: "compression",
45
49
  },
46
50
  Delta: { parameters: [WIDTH], role: "preprocessing" },
@@ -54,7 +58,7 @@ export const CODEC_OVERLAY: Record<string, CodecOverlay> = {
54
58
  FPC: {
55
59
  parameters: [
56
60
  { name: "level", kind: "number", optional: true, range: [1, 28], note: "12 when omitted." },
57
- { name: "float_size", kind: "number", optional: true, note: "4 or 8; the column type's width when omitted." },
61
+ { name: "float_size", kind: "number", optional: true, values: ["4", "8"], note: "4 or 8; the column type's width when omitted." },
58
62
  ],
59
63
  role: "compression",
60
64
  },
@@ -29,7 +29,7 @@ export interface ArgumentOverlay {
29
29
  kind: ArgumentKind;
30
30
  /** Overrides the syntax line's optionality, with `note` saying why. */
31
31
  optional?: boolean;
32
- /** The legal values of a `keyword`. */
32
+ /** The legal values of a `keyword`, or of a `number` limited to a set (a codec's byte width: 1, 2, 4 or 8). */
33
33
  values?: readonly string[];
34
34
  /** The inclusive range of a `number`. */
35
35
  range?: readonly [number, number];
@@ -26,16 +26,33 @@ const P = (name: string, kind: TypeParameter["kind"], extra: Partial<TypeParamet
26
26
 
27
27
  const TZ = P("timezone", "string", { optional: true });
28
28
 
29
+ /**
30
+ * The server takes and ignores a MySQL-style display width on an integer
31
+ * (`INT(11)`, `UInt64(8)`), a precision and scale on a float (`DOUBLE(10, 2)`)
32
+ * and a length on a string (`VARCHAR(255)`), so each is an optional parameter
33
+ * here rather than a mistake.
34
+ */
35
+ const WIDTH = [P("display_width", "number", { optional: true })];
36
+ const FLOAT = [P("precision", "number", { optional: true }), P("scale", "number", { optional: true })];
37
+ const INTEGERS = ["Int8", "Int16", "Int32", "Int64", "Int128", "Int256", "UInt8", "UInt16", "UInt32", "UInt64", "UInt128", "UInt256"];
38
+
29
39
  export const TYPE_PARAMETERS: Record<string, readonly TypeParameter[]> = {
30
- Decimal: [P("precision", "number", { range: [1, 76] }), P("scale", "number", { optional: true })],
40
+ ...Object.fromEntries(INTEGERS.map((name) => [name, WIDTH])),
41
+ Float32: FLOAT,
42
+ Float64: FLOAT,
43
+ BFloat16: FLOAT,
44
+ String: [P("length", "number", { optional: true })],
45
+ /** A bare `Decimal` is `Decimal(10, 0)`. */
46
+ Decimal: [P("precision", "number", { optional: true, range: [1, 76] }), P("scale", "number", { optional: true, range: [0, 76] })],
31
47
  Decimal32: [P("scale", "number", { range: [0, 9] })],
32
48
  Decimal64: [P("scale", "number", { range: [0, 18] })],
33
49
  Decimal128: [P("scale", "number", { range: [0, 38] })],
34
50
  Decimal256: [P("scale", "number", { range: [0, 76] })],
35
51
  DateTime: [TZ],
36
52
  DateTime32: [TZ],
37
- DateTime64: [P("precision", "number", { range: [0, 9] }), TZ],
38
- Time64: [P("precision", "number", { range: [0, 9] })],
53
+ /** A bare `DateTime64` has precision 3. */
54
+ DateTime64: [P("precision", "number", { optional: true, range: [0, 9] }), TZ],
55
+ Time64: [P("precision", "number", { optional: true, range: [0, 9] })],
39
56
  FixedString: [P("length", "number", { range: [1, Number.MAX_SAFE_INTEGER] })],
40
57
  Enum: [P("member", "enum-member", { repeated: true })],
41
58
  Enum8: [P("member", "enum-member", { repeated: true })],
@@ -0,0 +1,82 @@
1
+ /**
2
+ * A column type, read into its family and parameters: `Nullable(String)` is
3
+ * the family `Nullable` with the one parameter `String`;
4
+ * `DateTime64(3, 'UTC')` is `DateTime64` with `3` and `'UTC'`.
5
+ *
6
+ * The reading is lexical, over the same tokenizer the parser uses, so a
7
+ * string literal holding a parenthesis (`Enum8('a(' = 1)`) or a comma does not
8
+ * split a parameter. What a parameter means (a type, a number, a name) is the
9
+ * caller's question, answered from `TYPE_PARAMETERS`.
10
+ */
11
+
12
+ import { isTrivia, tokenizeText, type Token } from "./tokens";
13
+
14
+ export interface TypeParam {
15
+ /** The parameter as written, trimmed. */
16
+ text: string;
17
+ tokens: Token[];
18
+ }
19
+
20
+ export interface TypeSyntax {
21
+ /** The words before the parameters: `UInt64`, `BIGINT UNSIGNED`, or `a String` for a named tuple element. */
22
+ words: Token[];
23
+ /** The parameters, or undefined when the type has no parentheses. */
24
+ params?: TypeParam[];
25
+ }
26
+
27
+ const textOf = (tokens: readonly Token[]): string => tokens.map((t) => t.text).join("").trim();
28
+
29
+ /** The significant tokens of a type, or undefined when it does not tokenize. */
30
+ export function typeTokens(text: string): Token[] | undefined {
31
+ try {
32
+ return tokenizeText(text, 0);
33
+ } catch {
34
+ return undefined;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Read a type into its leading words and its parameters. Undefined when the
40
+ * text is not a type this can read: no leading name, or unbalanced parentheses.
41
+ * Anything after the closing parenthesis (`COLLATE utf8`) is ignored.
42
+ */
43
+ export function readType(tokens: readonly Token[]): TypeSyntax | undefined {
44
+ const sig = tokens.filter((t) => !isTrivia(t));
45
+ const words: Token[] = [];
46
+ let i = 0;
47
+ // `String COLLATE utf8`: COLLATE ends the type's words.
48
+ while (i < sig.length && (sig[i]!.kind === "ident" || sig[i]!.kind === "qident") && sig[i]!.text.toUpperCase() !== "COLLATE") words.push(sig[i++]!);
49
+ if (words.length === 0) return undefined;
50
+ if (i >= sig.length || !(sig[i]!.kind === "punct" && sig[i]!.text === "(")) return { words };
51
+ // Parameters: the tokens up to the matching parenthesis, split at top-level commas.
52
+ const start = tokens.indexOf(sig[i]!);
53
+ const params: TypeParam[] = [];
54
+ let depth = 0;
55
+ let current: Token[] = [];
56
+ for (let j = start; j < tokens.length; j++) {
57
+ const t = tokens[j]!;
58
+ if (t.kind === "punct" && t.text === "(") {
59
+ if (depth++ === 0) continue;
60
+ } else if (t.kind === "punct" && t.text === ")") {
61
+ if (--depth === 0) {
62
+ if (params.length > 0 || current.some((x) => !isTrivia(x))) params.push({ text: textOf(current), tokens: current });
63
+ return { words, params };
64
+ }
65
+ } else if (depth === 1 && t.kind === "punct" && t.text === ",") {
66
+ params.push({ text: textOf(current), tokens: current });
67
+ current = [];
68
+ continue;
69
+ }
70
+ current.push(t);
71
+ }
72
+ return undefined;
73
+ }
74
+
75
+ /** A parameter that is a numeric literal, possibly negative: its value. */
76
+ export function numericParam(param: TypeParam): number | undefined {
77
+ const sig = param.tokens.filter((t) => !isTrivia(t));
78
+ const negative = sig.length === 2 && sig[0]!.kind === "op" && sig[0]!.text === "-";
79
+ const n = negative ? sig[1] : sig.length === 1 ? sig[0] : undefined;
80
+ if (!n || n.kind !== "number" || !/^\d+(\.\d+)?([eE][+-]?\d+)?$/.test(n.text)) return undefined;
81
+ return negative ? -Number(n.text) : Number(n.text);
82
+ }
@@ -219,7 +219,7 @@ export function renderClickHouseModule(catalog: ClickHouseCatalog): RenderedModu
219
219
 
220
220
  const tables = [
221
221
  ...header("The tables lint and the LSP read, typed by ./clickhouse-types."),
222
- `import type { CodecSpec, DatabaseEngineSpec, SettingSpec, SkipIndexSpec, TableEngineSpec, TypeFamilySpec } from "../clickhouse/catalog-types";`,
222
+ `import type { CodecSpec, DatabaseEngineSpec, FunctionSpec, SettingSpec, SkipIndexSpec, TableEngineSpec, TypeFamilySpec } from "../clickhouse/catalog-types";`,
223
223
  `import type { CodecName, ColumnTypeName, DatabaseEngineName, MergeTreeSettings, QuerySettings, SkipIndexType, TableEngineName } from "./clickhouse-types";`,
224
224
  "",
225
225
  `export * from "./clickhouse-types";`,
@@ -255,6 +255,20 @@ export function renderClickHouseModule(catalog: ClickHouseCatalog): RenderedModu
255
255
  }),
256
256
  "};",
257
257
  "",
258
+ `/** Every function the server has (\`system.functions\`, origin System), aliases included. */`,
259
+ `export const FUNCTIONS: Readonly<Record<string, FunctionSpec>> = {`,
260
+ ...catalog.functions.map(
261
+ (f) =>
262
+ ` ${key(f.name)}: ${JSON.stringify({ aggregate: f.aggregate, caseInsensitive: f.caseInsensitive, ...(f.aliasOf ? { aliasOf: f.aliasOf } : {}) })},`,
263
+ ),
264
+ "};",
265
+ "",
266
+ `/** The aggregate function combinators (\`system.aggregate_function_combinators\`): the suffixes of \`countIf\`, \`sumState\`. */`,
267
+ `export const AGGREGATE_COMBINATORS: readonly string[] = ${JSON.stringify(catalog.aggregateCombinators.map((c) => c.name))};`,
268
+ "",
269
+ `/** The table functions (\`system.table_functions\`): \`numbers\`, \`remote\`, \`s3\`. */`,
270
+ `export const TABLE_FUNCTIONS: readonly string[] = ${JSON.stringify(catalog.tableFunctions)};`,
271
+ "",
258
272
  `export const SKIP_INDEX_TYPES: Readonly<Record<SkipIndexType, SkipIndexSpec>> = {`,
259
273
  ...indexLines,
260
274
  "};",
@@ -410,6 +410,43 @@ export function renderPostgresModule(catalogs: readonly PostgresCatalog[]): Rend
410
410
  "};",
411
411
  ];
412
412
 
413
+ // Names lint checks a declaration against, each with the majors that have it
414
+ // (`true`: every supported major). Read straight off the catalogs, internal
415
+ // functions included: a column default may call `pg_current_xact_id()`.
416
+ const presence = (lists: ReadonlyArray<readonly string[]>): Map<string, number[]> => {
417
+ const out = new Map<string, number[]>();
418
+ lists.forEach((names, i) => {
419
+ for (const n of new Set(names)) out.set(n, [...(out.get(n) ?? []), majors[i]!]);
420
+ });
421
+ return out;
422
+ };
423
+ const majorsLiteral = (ms: readonly number[]): string => (ms.length === majors.length ? "true" : JSON.stringify(ms));
424
+ const presenceTable = (m: Map<string, number[]>, indent: string): string[] =>
425
+ sorted(m.keys()).map((n) => `${indent}${JSON.stringify(n)}: ${majorsLiteral(m.get(n)!)},`);
426
+ const functionTable = [
427
+ `/** Every function, aggregate and procedure name in \`pg_proc\`, to the majors that have it (\`true\`: all of them). */`,
428
+ `export const FUNCTIONS: Readonly<Record<string, true | readonly number[]>> = {`,
429
+ ...presenceTable(presence(catalogs.map((c) => c.functions.map((f) => f.name))), " "),
430
+ "};",
431
+ ];
432
+ const methodTable = [
433
+ `/** The index access methods, to the majors that have each (\`true\`: all of them). */`,
434
+ `export const INDEX_ACCESS_METHODS: Readonly<Record<string, true | readonly number[]>> = {`,
435
+ ...presenceTable(presence(catalogs.map((c) => c.accessMethods.filter((a) => a.type === "i").map((a) => a.name))), " "),
436
+ "};",
437
+ ];
438
+ const opclassAms = sorted(catalogs.flatMap((c) => c.opclasses.map((o) => o.am)));
439
+ const opclassTable = [
440
+ `/** The operator classes of each index access method, to the majors that have each (\`true\`: all of them). */`,
441
+ `export const OPERATOR_CLASSES: Readonly<Record<string, Readonly<Record<string, true | readonly number[]>>>> = {`,
442
+ ...opclassAms.flatMap((am) => [
443
+ ` ${key(am)}: {`,
444
+ ...presenceTable(presence(catalogs.map((c) => c.opclasses.filter((o) => o.am === am).map((o) => o.name))), " "),
445
+ " },",
446
+ ]),
447
+ "};",
448
+ ];
449
+
413
450
  const tables = [
414
451
  ...header("The tables lint and the LSP read, typed by ./postgres-types."),
415
452
  `import type { ColumnTypeSpec, SettingSpec, StorageParameterSpec } from "../postgres/catalog-types";`,
@@ -425,6 +462,12 @@ export function renderPostgresModule(catalogs: readonly PostgresCatalog[]): Rend
425
462
  "",
426
463
  ...keywordTable,
427
464
  "",
465
+ ...functionTable,
466
+ "",
467
+ ...methodTable,
468
+ "",
469
+ ...opclassTable,
470
+ "",
428
471
  ].join("\n");
429
472
 
430
473
  notes.push(
@@ -202,7 +202,7 @@ test("a prop that is not valid SQL is refused at the interpolation that carried
202
202
  // ── What the lexicon's own checks say ──────────────────────────────────
203
203
 
204
204
  describe("the composites pass the lexicon's post-synth checks", () => {
205
- test("SQLCH101-120 find nothing in any of them", () => {
205
+ test("SQL101 and SQLCH101-127 find nothing in any of them", () => {
206
206
  const source = events();
207
207
  const instances: Array<[string, CompositeInstance]> = [
208
208
  ["users", ReplacingTable({ name: "users", columns: "id UInt64, email String", orderBy: "id" })],
@@ -230,10 +230,11 @@ describe("the composites pass the lexicon's post-synth checks", () => {
230
230
  expect(doc.applyOrder.indexOf("hitsLocal")).toBeLessThan(doc.applyOrder.indexOf("hitsDistributed"));
231
231
 
232
232
  const ctx = makePostSynthCtx("sql", out.primary, entities);
233
- const clickhouse = postSynthChecks.filter((c) => c.id.startsWith("SQLCH"));
233
+ const clickhouse = postSynthChecks.filter((c) => c.id.startsWith("SQLCH") || c.id === "SQL101");
234
234
  const ids = clickhouse.map((c) => c.id).sort();
235
- expect(ids[0]).toBe("SQLCH101");
236
- expect(ids.at(-1)).toBe("SQLCH120");
235
+ expect(ids[0]).toBe("SQL101");
236
+ expect(ids).toContain("SQLCH101");
237
+ expect(ids.at(-1)).toBe("SQLCH127");
237
238
  expect(clickhouse.flatMap((check) => check.check(ctx))).toEqual([]);
238
239
  });
239
240
  });
@@ -559,7 +560,7 @@ describe("the Postgres composites", () => {
559
560
  expect(() => TenantTable({ name: "notes", columns: "id bigint NOT NULL, (", primaryKey: "id", indexOn: "id" })).toThrow(SqlTemplateError);
560
561
  });
561
562
 
562
- test("SQLPG101 to SQLPG118 find nothing in any of them", () => {
563
+ test("SQLPG101 to SQLPG126 find nothing in any of them", () => {
563
564
  const people = users();
564
565
  const teams = SoftDeleteTable({ name: "teams", schema: "app", columns: "id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name text NOT NULL" });
565
566
  const members = JoinTable({ name: "memberships", schema: "app", left: people.table, leftColumn: "user_id", right: teams.table, rightColumn: "team_id" });
@@ -588,7 +589,7 @@ describe("the Postgres composites", () => {
588
589
 
589
590
  const ctx = makePostSynthCtx("sql", out.primary, entities);
590
591
  const checks = postSynthChecks.filter((c) => c.id.startsWith("SQLPG"));
591
- expect(checks).toHaveLength(18);
592
+ expect(checks).toHaveLength(26);
592
593
  expect(checks.flatMap((check) => check.check(ctx).map((d) => `${check.id} ${d.message}`))).toEqual([]);
593
594
  });
594
595
  });