@intentius/chant-lexicon-sql 0.124.31 → 0.124.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/change-set.js +250 -0
- package/dist/clickhouse/access.js +722 -0
- package/dist/clickhouse/apply/apply.js +243 -0
- package/dist/clickhouse/apply/mutations.js +66 -0
- package/dist/clickhouse/apply/statements.js +545 -0
- package/dist/clickhouse/catalog-types.js +7 -0
- package/dist/clickhouse/container.js +152 -0
- package/dist/clickhouse/engine-syntax.js +159 -0
- package/dist/clickhouse/entities.js +593 -0
- package/dist/clickhouse/expressions.js +107 -0
- package/dist/clickhouse/http.js +55 -0
- package/dist/clickhouse/import/generator.js +192 -0
- package/dist/clickhouse/import/inlined.js +207 -0
- package/dist/clickhouse/import/ir.js +160 -0
- package/dist/clickhouse/import/live-export.js +131 -0
- package/dist/clickhouse/import/parser.js +17 -0
- package/dist/clickhouse/live/bind.js +116 -0
- package/dist/clickhouse/live/catalog.js +223 -0
- package/dist/clickhouse/live/describe-resources.js +91 -0
- package/dist/clickhouse/live/undeclarable.js +59 -0
- package/dist/clickhouse/overlays/codecs.js +57 -0
- package/dist/clickhouse/overlays/engines.js +101 -0
- package/dist/clickhouse/overlays/kinds.js +1 -0
- package/dist/clickhouse/overlays/projections.js +26 -0
- package/dist/clickhouse/overlays/skip-indexes.js +40 -0
- package/dist/clickhouse/overlays/ttl.js +34 -0
- package/dist/clickhouse/overlays/types.js +59 -0
- package/dist/clickhouse/ownership.js +83 -0
- package/dist/clickhouse/parser.js +674 -0
- package/dist/clickhouse/plan/commands.js +159 -0
- package/dist/clickhouse/plan/deep.js +345 -0
- package/dist/clickhouse/plan/diff.js +312 -0
- package/dist/clickhouse/plan/disruption.js +73 -0
- package/dist/clickhouse/plan/normalize.js +545 -0
- package/dist/clickhouse/plan/rebuild-handoff.js +57 -0
- package/dist/clickhouse/plan/report.js +26 -0
- package/dist/clickhouse/plan/rules.js +72 -0
- package/dist/clickhouse/plan/schema.js +67 -0
- package/dist/clickhouse/plan/server-format.js +35 -0
- package/dist/clickhouse/rebuild/backfill.js +265 -0
- package/dist/clickhouse/rebuild/engines.js +146 -0
- package/dist/clickhouse/rebuild/observe.js +260 -0
- package/dist/clickhouse/rebuild/op.js +152 -0
- package/dist/clickhouse/rebuild/partitions.js +65 -0
- package/dist/clickhouse/rebuild/receipts.js +120 -0
- package/dist/clickhouse/rebuild/replicas.js +121 -0
- package/dist/clickhouse/rebuild/shards.js +76 -0
- package/dist/clickhouse/rebuild/steps.js +383 -0
- package/dist/clickhouse/rebuild/verify.js +279 -0
- package/dist/clickhouse/row-types.js +151 -0
- package/dist/clickhouse/testing/fake-server.js +47 -0
- package/dist/clickhouse/testing/roundtrip-schema.js +25 -0
- package/dist/clickhouse/testing/writable-server.js +123 -0
- package/dist/clickhouse/tokens.js +23 -0
- package/dist/clickhouse/topology.js +463 -0
- package/dist/clickhouse/type-syntax.js +73 -0
- package/dist/clickhouse.js +25 -0
- package/dist/codegen/classifier-page.js +93 -0
- package/dist/codegen/clickhouse-module.js +249 -0
- package/dist/codegen/coverage-page.js +70 -0
- package/dist/codegen/docs-cli.js +3 -0
- package/dist/codegen/docs.js +222 -0
- package/dist/codegen/generate-cli.js +13 -0
- package/dist/codegen/generate.js +97 -0
- package/dist/codegen/package.js +28 -0
- package/dist/codegen/postgres-classifier-page.js +95 -0
- package/dist/codegen/postgres-module.js +418 -0
- package/dist/codegen/registry.js +52 -0
- package/dist/composites/audit-log-table.js +35 -0
- package/dist/composites/catalog.js +524 -0
- package/dist/composites/cdc-mirror.js +32 -0
- package/dist/composites/clickhouse.js +6 -0
- package/dist/composites/events-table.js +26 -0
- package/dist/composites/index.js +8 -0
- package/dist/composites/join-table.js +25 -0
- package/dist/composites/postgres.js +6 -0
- package/dist/composites/refreshed-view.js +24 -0
- package/dist/composites/replacing-table.js +28 -0
- package/dist/composites/rollup-view.js +29 -0
- package/dist/composites/sharded-table.js +27 -0
- package/dist/composites/soft-delete-table.js +34 -0
- package/dist/composites/tenant-table.js +26 -0
- package/dist/composites/typed.js +8 -0
- package/dist/config.js +206 -0
- package/dist/core/apply.js +93 -0
- package/dist/core/classifier.js +115 -0
- package/dist/core/container.js +69 -0
- package/dist/core/cursor.js +261 -0
- package/dist/core/diff.js +48 -0
- package/dist/core/entity.js +58 -0
- package/dist/core/find-templates.js +118 -0
- package/dist/core/foreign-tables.js +27 -0
- package/dist/core/handoff.js +32 -0
- package/dist/core/index.js +64 -0
- package/dist/core/interpolation.js +191 -0
- package/dist/core/normalize.js +43 -0
- package/dist/core/ownership.js +119 -0
- package/dist/core/receipts.js +22 -0
- package/dist/core/references.js +61 -0
- package/dist/core/statements.js +42 -0
- package/dist/core/template.js +79 -0
- package/dist/core/testing/http-stub.js +21 -0
- package/dist/core/tokens.js +202 -0
- package/dist/core/typed.js +40 -0
- package/dist/core/undeclarable.js +46 -0
- package/dist/coverage.js +161 -0
- package/dist/detect.js +32 -0
- package/dist/dialects.js +18 -0
- package/dist/files/build-root.js +72 -0
- package/dist/files/clickhouse.js +138 -0
- package/dist/files/common.js +58 -0
- package/dist/files/postgres.js +389 -0
- package/dist/generated/clickhouse-types.js +5 -0
- package/dist/generated/clickhouse.js +4361 -0
- package/dist/generated/postgres-types.js +227 -0
- package/dist/generated/postgres.js +3667 -0
- package/dist/import-generator.js +14 -0
- package/dist/import-parser.js +71 -0
- package/dist/index.js +24 -0
- package/dist/init-templates.js +290 -0
- package/dist/integrity.json +2 -2
- package/dist/lint/audit-catalog.js +31 -0
- package/dist/lint/audit-lineage.js +22 -0
- package/dist/lint/post-synth/audit-entries.js +34 -0
- package/dist/lint/post-synth/clickhouse-helpers.js +79 -0
- package/dist/lint/post-synth/clickhouse-type-check.js +162 -0
- package/dist/lint/post-synth/index.js +112 -0
- package/dist/lint/post-synth/postgres-audit-entries.js +35 -0
- package/dist/lint/post-synth/postgres-helpers.js +65 -0
- package/dist/lint/post-synth/postgres-names.js +507 -0
- package/dist/lint/post-synth/sql-helpers.js +23 -0
- package/dist/lint/post-synth/sql101.js +59 -0
- package/dist/lint/post-synth/sql102.js +34 -0
- package/dist/lint/post-synth/sqlch101.js +34 -0
- package/dist/lint/post-synth/sqlch102.js +23 -0
- package/dist/lint/post-synth/sqlch103.js +45 -0
- package/dist/lint/post-synth/sqlch104.js +41 -0
- package/dist/lint/post-synth/sqlch105.js +36 -0
- package/dist/lint/post-synth/sqlch106.js +27 -0
- package/dist/lint/post-synth/sqlch107.js +39 -0
- package/dist/lint/post-synth/sqlch108.js +28 -0
- package/dist/lint/post-synth/sqlch109.js +21 -0
- package/dist/lint/post-synth/sqlch110.js +31 -0
- package/dist/lint/post-synth/sqlch111.js +41 -0
- package/dist/lint/post-synth/sqlch112.js +28 -0
- package/dist/lint/post-synth/sqlch113.js +19 -0
- package/dist/lint/post-synth/sqlch114.js +26 -0
- package/dist/lint/post-synth/sqlch115.js +30 -0
- package/dist/lint/post-synth/sqlch116.js +22 -0
- package/dist/lint/post-synth/sqlch117.js +26 -0
- package/dist/lint/post-synth/sqlch118.js +27 -0
- package/dist/lint/post-synth/sqlch119.js +32 -0
- package/dist/lint/post-synth/sqlch120.js +20 -0
- package/dist/lint/post-synth/sqlch121.js +11 -0
- package/dist/lint/post-synth/sqlch122.js +11 -0
- package/dist/lint/post-synth/sqlch123.js +10 -0
- package/dist/lint/post-synth/sqlch124.js +21 -0
- package/dist/lint/post-synth/sqlch125.js +55 -0
- package/dist/lint/post-synth/sqlch126.js +62 -0
- package/dist/lint/post-synth/sqlch127.js +132 -0
- package/dist/lint/post-synth/sqlpg101.js +25 -0
- package/dist/lint/post-synth/sqlpg102.js +35 -0
- package/dist/lint/post-synth/sqlpg103.js +23 -0
- package/dist/lint/post-synth/sqlpg104.js +23 -0
- package/dist/lint/post-synth/sqlpg105.js +22 -0
- package/dist/lint/post-synth/sqlpg106.js +22 -0
- package/dist/lint/post-synth/sqlpg107.js +22 -0
- package/dist/lint/post-synth/sqlpg108.js +28 -0
- package/dist/lint/post-synth/sqlpg109.js +39 -0
- package/dist/lint/post-synth/sqlpg110.js +38 -0
- package/dist/lint/post-synth/sqlpg111.js +23 -0
- package/dist/lint/post-synth/sqlpg112.js +25 -0
- package/dist/lint/post-synth/sqlpg113.js +29 -0
- package/dist/lint/post-synth/sqlpg114.js +39 -0
- package/dist/lint/post-synth/sqlpg115.js +48 -0
- package/dist/lint/post-synth/sqlpg116.js +26 -0
- package/dist/lint/post-synth/sqlpg117.js +24 -0
- package/dist/lint/post-synth/sqlpg118.js +22 -0
- package/dist/lint/post-synth/sqlpg119.js +41 -0
- package/dist/lint/post-synth/sqlpg120.js +83 -0
- package/dist/lint/post-synth/sqlpg121.js +33 -0
- package/dist/lint/post-synth/sqlpg122.js +27 -0
- package/dist/lint/post-synth/sqlpg123.js +69 -0
- package/dist/lint/post-synth/sqlpg124.js +50 -0
- package/dist/lint/post-synth/sqlpg125.js +41 -0
- package/dist/lint/post-synth/sqlpg126.js +38 -0
- package/dist/lint/rules/index.js +12 -0
- package/dist/lint/rules/postgres-templates.js +27 -0
- package/dist/lint/rules/sqlch001.js +79 -0
- package/dist/lint/rules/sqlch002.js +124 -0
- package/dist/lint/rules/sqlch003.js +69 -0
- package/dist/lint/rules/sqlch004.js +83 -0
- package/dist/lint/rules/sqlpg001.js +68 -0
- package/dist/lint/rules/sqlpg002.js +69 -0
- package/dist/lint/rules/sqlpg003.js +58 -0
- package/dist/lint/rules/sqlpg004.js +77 -0
- package/dist/lint/rules/sqlpg005.js +86 -0
- package/dist/lint/rules/templates.js +25 -0
- package/dist/lint/rules/typed-names.js +132 -0
- package/dist/live-dialect.js +32 -0
- package/dist/lsp/catalog.js +44 -0
- package/dist/lsp/completions.js +136 -0
- package/dist/lsp/hover.js +115 -0
- package/dist/lsp/postgres-catalog.js +176 -0
- package/dist/lsp/postgres-template.js +171 -0
- package/dist/lsp/postgres.js +266 -0
- package/dist/lsp/refs.js +60 -0
- package/dist/lsp/registry.d.ts.map +1 -1
- package/dist/lsp/registry.js +19 -0
- package/dist/lsp/template.js +143 -0
- package/dist/manifest.json +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +293 -0
- package/dist/mcp/postgres.js +117 -0
- package/dist/migration-statements.js +243 -0
- package/dist/op/activities/clickhouse-apply.js +83 -0
- package/dist/op/activities/clickhouse-emulator.js +53 -0
- package/dist/op/activities/clickhouse-rebuild.js +119 -0
- package/dist/op/activities/index.js +26 -0
- package/dist/op/activities/postgres-apply.js +126 -0
- package/dist/op/activities/postgres-emulator.js +70 -0
- package/dist/op/activities/postgres-migration.js +156 -0
- package/dist/op/activities/sql-exec.js +57 -0
- package/dist/op/activity-contracts.js +103 -0
- package/dist/package-cli.js +14 -0
- package/dist/plugin.js +259 -0
- package/dist/postgres/access/acl.js +344 -0
- package/dist/postgres/access/changes.js +30 -0
- package/dist/postgres/access/import.js +61 -0
- package/dist/postgres/access/live.js +96 -0
- package/dist/postgres/apply/apply.js +557 -0
- package/dist/postgres/apply/statements.js +882 -0
- package/dist/postgres/catalog-types.js +18 -0
- package/dist/postgres/container.js +58 -0
- package/dist/postgres/entities.js +1390 -0
- package/dist/postgres/entity-types.js +28 -0
- package/dist/postgres/import/generator.js +283 -0
- package/dist/postgres/import/ir.js +53 -0
- package/dist/postgres/import/live-export.js +83 -0
- package/dist/postgres/keywords.js +32 -0
- package/dist/postgres/live/bind.js +130 -0
- package/dist/postgres/live/catalog-kinds.js +301 -0
- package/dist/postgres/live/catalog.js +644 -0
- package/dist/postgres/live/client.js +151 -0
- package/dist/postgres/live/describe-resources.js +135 -0
- package/dist/postgres/live/undeclarable.js +111 -0
- package/dist/postgres/migrate/backfill.js +170 -0
- package/dist/postgres/migrate/batches.js +122 -0
- package/dist/postgres/migrate/carry.js +518 -0
- package/dist/postgres/migrate/handoff.js +59 -0
- package/dist/postgres/migrate/names.js +61 -0
- package/dist/postgres/migrate/observe.js +360 -0
- package/dist/postgres/migrate/op.js +178 -0
- package/dist/postgres/migrate/receipts.js +117 -0
- package/dist/postgres/migrate/replication.js +106 -0
- package/dist/postgres/migrate/steps.js +514 -0
- package/dist/postgres/overlays/columns.js +31 -0
- package/dist/postgres/overlays/constraints.js +52 -0
- package/dist/postgres/overlays/extension-objects.js +88 -0
- package/dist/postgres/overlays/indexes.js +25 -0
- package/dist/postgres/overlays/kinds.js +2 -0
- package/dist/postgres/overlays/partitioning.js +23 -0
- package/dist/postgres/overlays/relations.js +25 -0
- package/dist/postgres/overlays/storage.js +65 -0
- package/dist/postgres/overlays/type-ddl.js +36 -0
- package/dist/postgres/overlays/types.js +74 -0
- package/dist/postgres/parser.js +1824 -0
- package/dist/postgres/plan/commands.js +137 -0
- package/dist/postgres/plan/deep.js +324 -0
- package/dist/postgres/plan/diff.js +499 -0
- package/dist/postgres/plan/disruption.js +64 -0
- package/dist/postgres/plan/normalize.js +889 -0
- package/dist/postgres/plan/report.js +21 -0
- package/dist/postgres/plan/rules.js +115 -0
- package/dist/postgres/plan/schema.js +105 -0
- package/dist/postgres/plan/server-normalize.js +166 -0
- package/dist/postgres/providers/aurora.js +44 -0
- package/dist/postgres/providers/azure.js +53 -0
- package/dist/postgres/providers/cloud-sql.js +41 -0
- package/dist/postgres/providers/index.js +73 -0
- package/dist/postgres/providers/neon.js +44 -0
- package/dist/postgres/providers/rds.js +47 -0
- package/dist/postgres/providers/supabase.js +45 -0
- package/dist/postgres/providers/types.js +21 -0
- package/dist/postgres/row-types.js +107 -0
- package/dist/postgres/testing/fake-client.js +34 -0
- package/dist/postgres/testing/migration.js +48 -0
- package/dist/postgres/testing/roundtrip-schema.js +64 -0
- package/dist/postgres/testing/server.js +47 -0
- package/dist/postgres/testing/writable-server.js +160 -0
- package/dist/postgres/tokens.js +41 -0
- package/dist/postgres.js +15 -0
- package/dist/read/clickhouse.js +82 -0
- package/dist/read/objects.js +44 -0
- package/dist/read/postgres.js +104 -0
- package/dist/read.js +52 -0
- package/dist/receipts.js +207 -0
- package/dist/serializer.js +172 -0
- package/dist/skill-defs.js +93 -0
- package/dist/spec/catalog.js +191 -0
- package/dist/spec/fetch.d.ts.map +1 -1
- package/dist/spec/fetch.js +90 -0
- package/dist/spec/pin.js +42 -0
- package/dist/spec/postgres-catalog.js +171 -0
- package/dist/spec/postgres-fetch.js +91 -0
- package/dist/spec/postgres-pin.js +82 -0
- package/dist/sql-files.js +206 -0
- package/dist/sql-types-command.js +97 -0
- package/dist/sql-types.js +323 -0
- package/dist/token-source.js +156 -0
- package/dist/validate-cli.js +5 -0
- package/dist/validate.js +151 -0
- package/dist/workspace-outputs.js +191 -0
- package/package.json +7 -7
- package/src/codegen/package.ts +2 -2
- package/src/lint/rules/typescript-7.test.ts +2 -1
- package/src/lsp/catalog.ts +2 -2
- package/src/lsp/postgres-catalog.ts +2 -2
- package/src/lsp/registry.ts +2 -1
- package/src/mcp/index.ts +4 -2
- package/src/spec/fetch.ts +2 -2
- package/src/spec/postgres-fetch.ts +2 -2
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dialect-neutral half of a hand-written CREATE parser (chant #3196,
|
|
3
|
+
* #3278): a cursor over a statement's significant tokens, keyword and
|
|
4
|
+
* punctuation tests, spans, and expressions kept as balanced token spans.
|
|
5
|
+
*
|
|
6
|
+
* Statement structure is a dialect's to parse; expressions are not parsed. An
|
|
7
|
+
* expression (a default, a key, a view's SELECT) is a span of tokens: its
|
|
8
|
+
* source text, verbatim, and the interpolations inside it. A dialect parser
|
|
9
|
+
* extends {@link SqlCursor} with its statements, and says where an expression
|
|
10
|
+
* stops ({@link SqlCursor.stopsAt}) and how a token nests
|
|
11
|
+
* ({@link SqlCursor.depthChange}).
|
|
12
|
+
*/
|
|
13
|
+
import { isTrivia, SqlSyntaxError } from "./tokens.js";
|
|
14
|
+
/** Whether `t` is a bare word, any of `words`, case-insensitively. */
|
|
15
|
+
export const kw = (t, ...words) => t !== undefined && t.kind === "ident" && words.includes(t.text.toUpperCase());
|
|
16
|
+
/** `name` with its identifier quotes taken off and doubled quotes undone; `quotes` are the dialect's identifier quotes. */
|
|
17
|
+
export const unquoteWith = (text, quotes) => {
|
|
18
|
+
if (text.length < 2 || !quotes.includes(text[0]) || !quotes.includes(text[text.length - 1]))
|
|
19
|
+
return text;
|
|
20
|
+
let inner = text.slice(1, -1);
|
|
21
|
+
for (const q of quotes)
|
|
22
|
+
inner = inner.split(q + q).join(q);
|
|
23
|
+
return inner;
|
|
24
|
+
};
|
|
25
|
+
/** Edit distance with a swap of two neighbours as one edit, for telling a misspelt clause from a new one. */
|
|
26
|
+
function distance(a, b) {
|
|
27
|
+
const d = Array.from({ length: a.length + 1 }, (_, i) => Array.from({ length: b.length + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)));
|
|
28
|
+
for (let i = 1; i <= a.length; i++) {
|
|
29
|
+
for (let j = 1; j <= b.length; j++) {
|
|
30
|
+
const row = d[i];
|
|
31
|
+
row[j] = Math.min(d[i - 1][j] + 1, row[j - 1] + 1, d[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
32
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1])
|
|
33
|
+
row[j] = Math.min(row[j], d[i - 2][j - 2] + 1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return d[a.length][b.length];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The known clause word `word` is a misspelling of, if any: one edit from a
|
|
40
|
+
* known word of four letters or more (two neighbouring letters swapped is
|
|
41
|
+
* one), two from one of seven or more. A word
|
|
42
|
+
* that close is taken as a typo, which fails, not as a new clause, which warns.
|
|
43
|
+
*/
|
|
44
|
+
export function misspelling(word, known) {
|
|
45
|
+
const w = word.toUpperCase();
|
|
46
|
+
for (const k of known) {
|
|
47
|
+
if (k.length < 4 || k === w)
|
|
48
|
+
continue;
|
|
49
|
+
const d = distance(w, k);
|
|
50
|
+
if (d === 1 || (d === 2 && k.length >= 7 && w.length >= 7))
|
|
51
|
+
return k;
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
export class SqlCursor {
|
|
56
|
+
constructor(tokens) {
|
|
57
|
+
this.tokens = tokens;
|
|
58
|
+
this.p = 0;
|
|
59
|
+
/** The clauses read so far that the parser does not know (#3872), in order. */
|
|
60
|
+
this.unknownClauses = [];
|
|
61
|
+
this.sig = tokens.map((t, i) => (isTrivia(t) ? -1 : i)).filter((i) => i >= 0);
|
|
62
|
+
}
|
|
63
|
+
peek(n = 0) {
|
|
64
|
+
const idx = this.sig[this.p + n];
|
|
65
|
+
return idx === undefined ? undefined : this.tokens[idx];
|
|
66
|
+
}
|
|
67
|
+
/** Token-list index of the significant token `n` ahead. */
|
|
68
|
+
idx(n = 0) {
|
|
69
|
+
return this.sig[this.p + n] ?? this.tokens.length;
|
|
70
|
+
}
|
|
71
|
+
next() {
|
|
72
|
+
const t = this.peek();
|
|
73
|
+
if (!t)
|
|
74
|
+
this.fail("unexpected end of statement");
|
|
75
|
+
this.p++;
|
|
76
|
+
return t;
|
|
77
|
+
}
|
|
78
|
+
fail(message, t = this.peek()) {
|
|
79
|
+
const at = t ?? this.lastToken();
|
|
80
|
+
const shown = t ? ` at '${t.kind === "ref" ? "${...}" : t.text}'` : "";
|
|
81
|
+
throw new SqlSyntaxError(`${message}${shown}`, at?.part ?? 0, t ? at.start : (at?.end ?? 0), at);
|
|
82
|
+
}
|
|
83
|
+
lastToken() {
|
|
84
|
+
const last = this.sig[this.sig.length - 1];
|
|
85
|
+
return last === undefined ? undefined : this.tokens[last];
|
|
86
|
+
}
|
|
87
|
+
accept(...words) {
|
|
88
|
+
if (kw(this.peek(), ...words)) {
|
|
89
|
+
this.p++;
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
expect(...words) {
|
|
95
|
+
if (!this.accept(...words))
|
|
96
|
+
this.fail(`expected ${words.join(" or ")}`);
|
|
97
|
+
}
|
|
98
|
+
/** Whether the next significant tokens are the bare words `words`, in order. */
|
|
99
|
+
is(...words) {
|
|
100
|
+
return words.every((w, n) => kw(this.peek(n), w));
|
|
101
|
+
}
|
|
102
|
+
/** Accept a sequence of bare words, all of them or none. */
|
|
103
|
+
acceptSeq(...words) {
|
|
104
|
+
if (!this.is(...words))
|
|
105
|
+
return false;
|
|
106
|
+
this.p += words.length;
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
isPunct(c, n = 0) {
|
|
110
|
+
const t = this.peek(n);
|
|
111
|
+
return t !== undefined && t.kind === "punct" && t.text === c;
|
|
112
|
+
}
|
|
113
|
+
acceptPunct(c) {
|
|
114
|
+
if (this.isPunct(c)) {
|
|
115
|
+
this.p++;
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
expectPunct(c) {
|
|
121
|
+
if (!this.acceptPunct(c))
|
|
122
|
+
this.fail(`expected '${c}'`);
|
|
123
|
+
}
|
|
124
|
+
atEnd() {
|
|
125
|
+
return this.peek() === undefined || this.isPunct(";");
|
|
126
|
+
}
|
|
127
|
+
span(from, refs) {
|
|
128
|
+
return { from, to: this.idx(-1) + 1, refs };
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Whether the expression being read stops at the current token, a top-level
|
|
132
|
+
* bare word: by default when it is one of `stop`. A dialect overrides this
|
|
133
|
+
* for its multi-word stops (ClickHouse stops at `ORDER` only before `BY`).
|
|
134
|
+
*/
|
|
135
|
+
stopsAt(stop) {
|
|
136
|
+
const t = this.peek();
|
|
137
|
+
return t !== undefined && t.kind === "ident" && stop.includes(t.text.toUpperCase());
|
|
138
|
+
}
|
|
139
|
+
/** How `t` changes the nesting depth of an expression: `(` opens and `)` closes. */
|
|
140
|
+
depthChange(t) {
|
|
141
|
+
if (t.kind === "punct" && t.text === "(")
|
|
142
|
+
return 1;
|
|
143
|
+
if (t.kind === "punct" && t.text === ")")
|
|
144
|
+
return -1;
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* An expression as a token span: everything up to a top-level `,` (unless
|
|
149
|
+
* `stopAtComma` is false), `)` or `;`, or a top-level stop word. Nesting is
|
|
150
|
+
* balanced, not parsed.
|
|
151
|
+
*/
|
|
152
|
+
expr(stop = [], stopAtComma = true) {
|
|
153
|
+
const from = this.idx();
|
|
154
|
+
const refs = [];
|
|
155
|
+
let depth = 0;
|
|
156
|
+
const startP = this.p;
|
|
157
|
+
for (;;) {
|
|
158
|
+
const t = this.peek();
|
|
159
|
+
if (t === undefined)
|
|
160
|
+
break;
|
|
161
|
+
if (depth === 0) {
|
|
162
|
+
if (t.kind === "punct" && (t.text === ")" || t.text === ";" || (stopAtComma && t.text === ",")))
|
|
163
|
+
break;
|
|
164
|
+
if (this.stopsAt(stop))
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
depth += this.depthChange(t);
|
|
168
|
+
if (t.kind === "ref")
|
|
169
|
+
refs.push(t.part);
|
|
170
|
+
this.p++;
|
|
171
|
+
}
|
|
172
|
+
if (this.p === startP)
|
|
173
|
+
this.fail("expected an expression");
|
|
174
|
+
return this.span(from, refs);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* At a clause boundary, a clause this parser does not know (#3872): a bare
|
|
178
|
+
* word that is not one of `known`, read up to the next top-level word of
|
|
179
|
+
* `known`, the statement's end, or (with `inList`, inside a column list) the
|
|
180
|
+
* element's `,` or `)`, its parentheses balanced. Recorded and returned.
|
|
181
|
+
*
|
|
182
|
+
* Undefined when the next token cannot start one: the end, punctuation, a
|
|
183
|
+
* string, a number, a quoted name or an interpolation, a word shorter than
|
|
184
|
+
* three letters or with a digit in it, or a word of `known`
|
|
185
|
+
* (a clause the parser knows, out of place). A word one letter from a known
|
|
186
|
+
* one fails here as a misspelling, and a run holding a top-level `SELECT`,
|
|
187
|
+
* `CREATE` or `INSERT` as a query or a second statement: genuinely
|
|
188
|
+
* malformed SQL stays an error.
|
|
189
|
+
*/
|
|
190
|
+
unknownClause(known, options = {}) {
|
|
191
|
+
const t = this.peek();
|
|
192
|
+
// A clause starts with a key word: three letters or more, no digits.
|
|
193
|
+
if (t === undefined || t.kind !== "ident" || !/^[A-Za-z_]{3,}$/.test(t.text))
|
|
194
|
+
return undefined;
|
|
195
|
+
const word = t.text.toUpperCase();
|
|
196
|
+
if (known.includes(word))
|
|
197
|
+
return undefined;
|
|
198
|
+
const near = misspelling(word, known);
|
|
199
|
+
if (near !== undefined)
|
|
200
|
+
this.fail(`expected a clause ('${t.text}' is not one chant reads, and is one letter from ${near}: is it misspelt?)`, t);
|
|
201
|
+
const from = this.idx();
|
|
202
|
+
const startP = this.p;
|
|
203
|
+
// Its name: the first word, and when that is written in upper case, the upper-case words after it (`SQL SECURITY`), not a name it takes.
|
|
204
|
+
const words = [word];
|
|
205
|
+
const upper = (u) => u?.kind === "ident" && /^[A-Z_]+$/.test(u.text) && !known.includes(u.text);
|
|
206
|
+
if (upper(t))
|
|
207
|
+
for (let n = 1; n < 3 && upper(this.peek(n)); n++)
|
|
208
|
+
words.push(this.peek(n).text);
|
|
209
|
+
const refs = [];
|
|
210
|
+
let depth = 0;
|
|
211
|
+
for (;;) {
|
|
212
|
+
const u = this.peek();
|
|
213
|
+
if (u === undefined)
|
|
214
|
+
break;
|
|
215
|
+
if (depth === 0) {
|
|
216
|
+
if (u.kind === "punct" && (u.text === ";" || u.text === ")" || (options.inList === true && u.text === ",")))
|
|
217
|
+
break;
|
|
218
|
+
if (this.p > startP && u.kind === "ident" && known.includes(u.text.toUpperCase()))
|
|
219
|
+
break;
|
|
220
|
+
// A query or a second statement is not a clause: `CREATE TABLE ... AS SELECT`, `... PARALLEL WITH CREATE ...`.
|
|
221
|
+
if (kw(u, "SELECT", "CREATE", "INSERT"))
|
|
222
|
+
this.fail(`expected a clause (${u.text.toUpperCase()} starts a query or a statement, which is not declared here)`, u);
|
|
223
|
+
}
|
|
224
|
+
depth += this.depthChange(u);
|
|
225
|
+
if (depth < 0)
|
|
226
|
+
break;
|
|
227
|
+
if (u.kind === "ref")
|
|
228
|
+
refs.push(u.part);
|
|
229
|
+
this.p++;
|
|
230
|
+
}
|
|
231
|
+
if (depth !== 0)
|
|
232
|
+
this.fail(`unbalanced parentheses in the ${words.join(" ")} clause`, t);
|
|
233
|
+
const clause = { clause: words.join(" "), span: this.span(from, refs), ...(options.column !== undefined ? { column: options.column } : {}) };
|
|
234
|
+
this.unknownClauses.push(clause);
|
|
235
|
+
return clause;
|
|
236
|
+
}
|
|
237
|
+
/** `( ... )` balanced: the span between the parentheses. */
|
|
238
|
+
parenthesized() {
|
|
239
|
+
this.expectPunct("(");
|
|
240
|
+
if (this.isPunct(")")) {
|
|
241
|
+
const at = this.idx();
|
|
242
|
+
this.p++;
|
|
243
|
+
return { from: at, to: at, refs: [] };
|
|
244
|
+
}
|
|
245
|
+
const inner = this.exprList();
|
|
246
|
+
this.expectPunct(")");
|
|
247
|
+
return inner;
|
|
248
|
+
}
|
|
249
|
+
/** A comma-separated expression list as one span. */
|
|
250
|
+
exprList(stop = []) {
|
|
251
|
+
const first = this.expr(stop);
|
|
252
|
+
let last = first;
|
|
253
|
+
const refs = [...first.refs];
|
|
254
|
+
while (this.isPunct(",")) {
|
|
255
|
+
this.p++;
|
|
256
|
+
last = this.expr(stop);
|
|
257
|
+
refs.push(...last.refs);
|
|
258
|
+
}
|
|
259
|
+
return { from: first.from, to: last.to, refs };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity and renames between two schemas, the same in every dialect
|
|
3
|
+
* (#3047 question 3).
|
|
4
|
+
*
|
|
5
|
+
* An object is identified by its key: its export name between two revisions
|
|
6
|
+
* of the declarations, its qualified name against a live server, which has no
|
|
7
|
+
* export names. An `after` object whose key is new but whose `previously` hint
|
|
8
|
+
* (`-- previously: <old name>`) names a `before` object with no `after`
|
|
9
|
+
* counterpart is that object, renamed. What changed inside a matched pair,
|
|
10
|
+
* and how each change is classed, is the dialect's.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Match `after` to `before` by key, then by rename hint. Returns every `after`
|
|
14
|
+
* object in order, created or matched, then every `before` object no `after`
|
|
15
|
+
* object matched, dropped.
|
|
16
|
+
*/
|
|
17
|
+
export function matchByIdentity(before, after, rules) {
|
|
18
|
+
const out = [];
|
|
19
|
+
const byKey = new Map(before.map((o) => [o.key, o]));
|
|
20
|
+
const byQualified = new Map(before.map((o) => [rules.qualified(o.canonical), o]));
|
|
21
|
+
const afterKeys = new Set(after.map((o) => o.key));
|
|
22
|
+
const matched = new Set();
|
|
23
|
+
for (const a of after) {
|
|
24
|
+
let b = byKey.get(a.key);
|
|
25
|
+
const prev = rules.previously(a.canonical);
|
|
26
|
+
if (!b && prev) {
|
|
27
|
+
let candidate = byKey.get(prev);
|
|
28
|
+
for (const name of rules.previousNames(a.canonical, prev))
|
|
29
|
+
candidate ?? (candidate = byQualified.get(name));
|
|
30
|
+
if (candidate && !afterKeys.has(candidate.key))
|
|
31
|
+
b = candidate;
|
|
32
|
+
}
|
|
33
|
+
if (!b) {
|
|
34
|
+
out.push({ kind: "created", after: a });
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
matched.add(b.key);
|
|
38
|
+
out.push({ kind: "matched", before: b, after: a });
|
|
39
|
+
}
|
|
40
|
+
for (const b of before)
|
|
41
|
+
if (!matched.has(b.key))
|
|
42
|
+
out.push({ kind: "dropped", before: b });
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
/** The names whose values differ between two records, sorted. */
|
|
46
|
+
export function changedEntries(before, after) {
|
|
47
|
+
return [...new Set([...Object.keys(before), ...Object.keys(after)])].sort().filter((name) => before[name] !== after[name]);
|
|
48
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The entity base every dialect's objects share: the Declarable fields core
|
|
3
|
+
* reads, the hidden-property construction that keeps them out of a build's
|
|
4
|
+
* props, and the column references (`${t.columns.x}`) a relation hands out.
|
|
5
|
+
*
|
|
6
|
+
* A dialect subclasses {@link SqlObject} with its own entity types
|
|
7
|
+
* (`ClickHouse::Table`), builds its entities with {@link makeSqlEntity} on its
|
|
8
|
+
* subclass's prototype, and recognizes its own objects by their type prefix.
|
|
9
|
+
*/
|
|
10
|
+
import { DECLARABLE_MARKER } from "@intentius/chant/declarable";
|
|
11
|
+
import { AttrRef } from "@intentius/chant/attrref";
|
|
12
|
+
/** The lexicon every dialect's entities belong to. */
|
|
13
|
+
export const SQL_LEXICON = "sql";
|
|
14
|
+
/** The members a schema object has besides its props, in every dialect. */
|
|
15
|
+
export class SqlObject {
|
|
16
|
+
}
|
|
17
|
+
const hidden = (target, key, value) => Object.defineProperty(target, key, { value, enumerable: false, writable: false, configurable: false });
|
|
18
|
+
/**
|
|
19
|
+
* One entity on `prototype` (a dialect's {@link SqlObject} subclass). Every
|
|
20
|
+
* field but `dependsOn` is hidden, so a build's props are the parsed
|
|
21
|
+
* definition alone. With `columnNames`, the entity gets a frozen `columns`
|
|
22
|
+
* record holding one {@link AttrRef} per column.
|
|
23
|
+
*/
|
|
24
|
+
export function makeSqlEntity(prototype, entityType, sqlName, props, columnNames, dependsOn) {
|
|
25
|
+
const entity = Object.create(prototype);
|
|
26
|
+
hidden(entity, DECLARABLE_MARKER, true);
|
|
27
|
+
hidden(entity, "lexicon", SQL_LEXICON);
|
|
28
|
+
hidden(entity, "entityType", entityType);
|
|
29
|
+
hidden(entity, "kind", "resource");
|
|
30
|
+
hidden(entity, "props", props);
|
|
31
|
+
hidden(entity, "sqlName", sqlName);
|
|
32
|
+
if (columnNames) {
|
|
33
|
+
const columns = {};
|
|
34
|
+
for (const name of columnNames)
|
|
35
|
+
columns[name] = new AttrRef(entity, name);
|
|
36
|
+
hidden(entity, "columns", Object.freeze(columns));
|
|
37
|
+
}
|
|
38
|
+
Object.defineProperty(entity, "dependsOn", { value: dependsOn, enumerable: true });
|
|
39
|
+
return entity;
|
|
40
|
+
}
|
|
41
|
+
/** Whether `value` is a sql lexicon entity whose type starts with `typePrefix` (`ClickHouse::`). */
|
|
42
|
+
export function isSqlObjectOf(value, typePrefix) {
|
|
43
|
+
return (typeof value === "object" &&
|
|
44
|
+
value !== null &&
|
|
45
|
+
value.lexicon === SQL_LEXICON &&
|
|
46
|
+
typeof value.sqlName === "string" &&
|
|
47
|
+
typeof value.entityType === "string" &&
|
|
48
|
+
value.entityType.startsWith(typePrefix));
|
|
49
|
+
}
|
|
50
|
+
/** A column reference: an AttrRef whose parent `isOwner` accepts. */
|
|
51
|
+
export function isColumnRefOf(value, isOwner) {
|
|
52
|
+
if (typeof value !== "object" || value === null)
|
|
53
|
+
return false;
|
|
54
|
+
const v = value;
|
|
55
|
+
if (typeof v.attribute !== "string" || typeof v.parent?.deref !== "function")
|
|
56
|
+
return false;
|
|
57
|
+
return isOwner(v.parent.deref());
|
|
58
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finding a dialect's tags in a source file, for source-level lint rules and
|
|
3
|
+
* the editor (chant #3278). A rule reads a template's raw parts straight from
|
|
4
|
+
* the TypeScript AST and parses them the way the tag does, with every
|
|
5
|
+
* interpolation left a reference: lint cannot know the values.
|
|
6
|
+
*
|
|
7
|
+
* Every dialect exports tags with the same names (`table`, `view`), so a tag
|
|
8
|
+
* is a dialect's by the module it is imported from, never by its name.
|
|
9
|
+
*/
|
|
10
|
+
import { ts } from "@intentius/chant/lint/typescript";
|
|
11
|
+
import { unescapeTemplateDelimiters } from "./template.js";
|
|
12
|
+
/** Local names bound to the dialects' tags by this file's imports: `{ table as t }` maps `t` to `table`. */
|
|
13
|
+
function tagBindings(source, sources) {
|
|
14
|
+
const out = new Map();
|
|
15
|
+
for (const stmt of source.statements) {
|
|
16
|
+
if (!ts.isImportDeclaration(stmt) || !ts.isStringLiteral(stmt.moduleSpecifier))
|
|
17
|
+
continue;
|
|
18
|
+
// A module may export several dialects' tags (the package root does): a tag is the first source's that names it.
|
|
19
|
+
const from = sources.filter((s) => s.modules.includes(stmt.moduleSpecifier.text));
|
|
20
|
+
if (from.length === 0)
|
|
21
|
+
continue;
|
|
22
|
+
const named = stmt.importClause?.namedBindings;
|
|
23
|
+
if (!named || !ts.isNamedImports(named))
|
|
24
|
+
continue;
|
|
25
|
+
for (const el of named.elements) {
|
|
26
|
+
const imported = (el.propertyName ?? el.name).text;
|
|
27
|
+
const source = from.find((s) => s.tags.includes(imported));
|
|
28
|
+
if (source)
|
|
29
|
+
out.set(el.name.text, { dialect: source.dialect, tag: imported });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
/** Every template in `source` whose tag is imported from one of `sources`' modules, in source order. */
|
|
35
|
+
export function findSqlTemplates(source, sources) {
|
|
36
|
+
const bindings = tagBindings(source, sources);
|
|
37
|
+
if (bindings.size === 0)
|
|
38
|
+
return [];
|
|
39
|
+
const found = [];
|
|
40
|
+
const visit = (node) => {
|
|
41
|
+
if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && bindings.has(node.tag.text)) {
|
|
42
|
+
const t = node.template;
|
|
43
|
+
// As the tag reads them: raw, with `\`` and `\${` undone. An offset after one of those is off by one.
|
|
44
|
+
const parts = (ts.isNoSubstitutionTemplateLiteral(t)
|
|
45
|
+
? [t.rawText ?? t.text]
|
|
46
|
+
: [t.head.rawText ?? t.head.text, ...t.templateSpans.map((s) => s.literal.rawText ?? s.literal.text)]).map(unescapeTemplateDelimiters);
|
|
47
|
+
// A part's text begins one character after its opening delimiter (` or }).
|
|
48
|
+
const starts = ts.isNoSubstitutionTemplateLiteral(t)
|
|
49
|
+
? [t.getStart(source) + 1]
|
|
50
|
+
: [t.head.getStart(source) + 1, ...t.templateSpans.map((s) => s.literal.getStart(source) + 1)];
|
|
51
|
+
const expressions = ts.isNoSubstitutionTemplateLiteral(t) ? [] : t.templateSpans.map((s) => s.expression);
|
|
52
|
+
const { dialect, tag } = bindings.get(node.tag.text);
|
|
53
|
+
found.push({ node, dialect, tag, parts, starts, expressions });
|
|
54
|
+
}
|
|
55
|
+
ts.forEachChild(node, visit);
|
|
56
|
+
};
|
|
57
|
+
visit(source);
|
|
58
|
+
return found;
|
|
59
|
+
}
|
|
60
|
+
/** 1-based line and column of a template offset. */
|
|
61
|
+
export function templatePosition(source, found, part, offset) {
|
|
62
|
+
const pos = (found.starts[part] ?? found.node.getStart(source)) + offset;
|
|
63
|
+
const { line, character } = source.getLineAndCharacterOfPosition(pos);
|
|
64
|
+
return { line: line + 1, column: character + 1 };
|
|
65
|
+
}
|
|
66
|
+
/** A token's position; an interpolation's is its expression's. */
|
|
67
|
+
export function tokenPosition(source, found, token) {
|
|
68
|
+
if (token.kind === "ref") {
|
|
69
|
+
const expr = found.expressions[token.part];
|
|
70
|
+
if (expr) {
|
|
71
|
+
const { line, character } = source.getLineAndCharacterOfPosition(expr.getStart(source));
|
|
72
|
+
return { line: line + 1, column: character + 1 };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return templatePosition(source, found, token.part, token.start);
|
|
76
|
+
}
|
|
77
|
+
// ── The editor ─────────────────────────────────────────────────────────
|
|
78
|
+
/** The offset of an LSP position (0-based line and character) in `content`. */
|
|
79
|
+
export function offsetAt(content, pos) {
|
|
80
|
+
let offset = 0;
|
|
81
|
+
for (let line = 0; line < pos.line; line++) {
|
|
82
|
+
const next = content.indexOf("\n", offset);
|
|
83
|
+
if (next < 0)
|
|
84
|
+
return content.length;
|
|
85
|
+
offset = next + 1;
|
|
86
|
+
}
|
|
87
|
+
return Math.min(offset + pos.character, content.length);
|
|
88
|
+
}
|
|
89
|
+
/** The template the source offset `at` is inside, and where in it. */
|
|
90
|
+
export function locateIn(content, at, sources, fileName = "file.ts") {
|
|
91
|
+
const source = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true);
|
|
92
|
+
for (const found of findSqlTemplates(source, sources)) {
|
|
93
|
+
const start = found.node.template.getStart(source);
|
|
94
|
+
const end = found.node.template.getEnd();
|
|
95
|
+
if (at <= start || at >= end)
|
|
96
|
+
continue;
|
|
97
|
+
for (let i = 0; i < found.parts.length; i++) {
|
|
98
|
+
const from = found.starts[i];
|
|
99
|
+
if (at >= from && at <= from + found.parts[i].length) {
|
|
100
|
+
return { source, found, part: i, offset: at - from, expression: -1, at };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const expression = found.expressions.findIndex((e) => at >= e.getStart(source) && at <= e.getEnd());
|
|
104
|
+
return { source, found, part: -1, offset: 0, expression, at };
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
const WORD = /[A-Za-z0-9_]/;
|
|
109
|
+
/** The identifier characters around an offset in a part. */
|
|
110
|
+
export function wordAround(text, offset) {
|
|
111
|
+
let start = offset;
|
|
112
|
+
while (start > 0 && WORD.test(text[start - 1]))
|
|
113
|
+
start--;
|
|
114
|
+
let end = offset;
|
|
115
|
+
while (end < text.length && WORD.test(text[end]))
|
|
116
|
+
end++;
|
|
117
|
+
return { start, end };
|
|
118
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tables another tool keeps its migration history in, by name, with the tool.
|
|
3
|
+
*
|
|
4
|
+
* Both dialects' catalog readers mark a table by one of these names as
|
|
5
|
+
* foreign: import leaves it out with a warning, and a plan names it in a hint
|
|
6
|
+
* instead of proposing a drop, since chant changing it would change what that
|
|
7
|
+
* tool owns (#3047 question 10, #3676). golang-migrate, dbmate, goose and
|
|
8
|
+
* Flyway keep the same tables on ClickHouse as on Postgres.
|
|
9
|
+
*/
|
|
10
|
+
export const FOREIGN_TABLES = {
|
|
11
|
+
_prisma_migrations: "Prisma Migrate",
|
|
12
|
+
schema_migrations: "a migration runner (Rails, golang-migrate, dbmate)",
|
|
13
|
+
ar_internal_metadata: "Rails",
|
|
14
|
+
django_migrations: "Django",
|
|
15
|
+
alembic_version: "Alembic",
|
|
16
|
+
__drizzle_migrations: "drizzle-kit",
|
|
17
|
+
flyway_schema_history: "Flyway",
|
|
18
|
+
goose_db_version: "goose",
|
|
19
|
+
knex_migrations: "Knex",
|
|
20
|
+
knex_migrations_lock: "Knex",
|
|
21
|
+
SequelizeMeta: "Sequelize",
|
|
22
|
+
pgmigrations: "node-pg-migrate",
|
|
23
|
+
};
|
|
24
|
+
/** The tool that keeps a table by this name, or undefined when none does. */
|
|
25
|
+
export function foreignTool(name) {
|
|
26
|
+
return Object.prototype.hasOwnProperty.call(FOREIGN_TABLES, name) ? FOREIGN_TABLES[name] : undefined;
|
|
27
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a plan hands a change it refuses to make in place to a migration Op,
|
|
3
|
+
* the same in every dialect.
|
|
4
|
+
*
|
|
5
|
+
* `chant sql plan`, `chant sql diff` and the applier refuse a change the
|
|
6
|
+
* dialect cannot make in place (a ClickHouse sorting-key change, which needs
|
|
7
|
+
* a rebuild). What they hand on is the Op to run instead, one per object: a
|
|
8
|
+
* declaration ready to put in an `*.op.ts` file, reviewed in the pull request
|
|
9
|
+
* like the schema change it carries out. Nothing is written for the user. The
|
|
10
|
+
* Op's own Plan phase classifies the change again against the server.
|
|
11
|
+
*
|
|
12
|
+
* Which Op, and the options a dialect suggests for it (ClickHouse's dual-write
|
|
13
|
+
* mode), are the dialect's.
|
|
14
|
+
*/
|
|
15
|
+
/** An Op name for a migration of `table`: `<kind>-<table>`, lower case, runs of other characters as `-`. */
|
|
16
|
+
export function migrationOpName(kind, table) {
|
|
17
|
+
return `${kind}-${table.replace(/[^A-Za-z0-9]+/g, "-").toLowerCase()}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The suggestions as report lines: what the Op is, the import it comes from,
|
|
21
|
+
* then one declaration per line.
|
|
22
|
+
*/
|
|
23
|
+
export function renderMigrationOps(ops, op) {
|
|
24
|
+
if (ops.length === 0)
|
|
25
|
+
return [];
|
|
26
|
+
return [
|
|
27
|
+
"",
|
|
28
|
+
`Run ${ops.length === 1 ? "it" : "each"} as ${op.what}, declared in an *.op.ts file ` +
|
|
29
|
+
`(import { ${op.exportName} } from "${op.importPath}"), then \`chant run <name>\` until it is done:`,
|
|
30
|
+
...ops.map((o) => ` ${o.declaration}`),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sql lexicon's shared core: what every dialect (`../clickhouse/`, and
|
|
3
|
+
* Postgres next, #3289) builds on, with no database's grammar in it (#3275
|
|
4
|
+
* question 7, #3047 question 1).
|
|
5
|
+
*
|
|
6
|
+
* Belongs here:
|
|
7
|
+
*
|
|
8
|
+
* - the entity base and Declarable plumbing, and column references
|
|
9
|
+
* (`entity.ts`);
|
|
10
|
+
* - the lossless tokenizer, with each dialect's character-level rules as a
|
|
11
|
+
* table (`tokens.ts`), and the parser base: a cursor over significant
|
|
12
|
+
* tokens with expressions kept as token spans (`cursor.ts`);
|
|
13
|
+
* - the tagged-template plumbing: raw parts, what a plain interpolation
|
|
14
|
+
* splices in, `SqlLiteral`, the tag's error (`template.ts`), and splicing,
|
|
15
|
+
* span text, what each spliced value fed, and a view's column lineage
|
|
16
|
+
* (`interpolation.ts`);
|
|
17
|
+
* - finding a dialect's templates in a source file by the module its tags
|
|
18
|
+
* are imported from, for lint and the editor (`find-templates.ts`);
|
|
19
|
+
* - references between objects, column lineage, and the creation order
|
|
20
|
+
* (`references.ts`);
|
|
21
|
+
* - identity and renames between two schemas, and the change-set model
|
|
22
|
+
* (`diff.ts`);
|
|
23
|
+
* - the classifier framework: the rule shape, classes as data per dialect,
|
|
24
|
+
* `classifyDisruption()` over a dialect's rules, the text report
|
|
25
|
+
* (`classifier.ts`);
|
|
26
|
+
* - normalization helpers that are not a database's grammar, such as the
|
|
27
|
+
* `-- previously:` hint (`normalize.ts`);
|
|
28
|
+
* - typed columns: the brands, `ColumnsIn`, `SlotsIn` and `RowIn` each
|
|
29
|
+
* dialect's `SqlSchema` is read through, and the slot record a tag leaves
|
|
30
|
+
* for `chant sql types` (`typed.ts`);
|
|
31
|
+
* - the ownership trailer on an object's comment (`ownership.ts`);
|
|
32
|
+
* - receipts kept on the server (`receipts.ts`);
|
|
33
|
+
* - the applier's tri-state outcome, its envelope projection and the build
|
|
34
|
+
* output reader (`apply.ts`);
|
|
35
|
+
* - the hand-off from a refused change to a migration Op (`handoff.ts`);
|
|
36
|
+
* - a throwaway server in a container, and test helpers that are not one
|
|
37
|
+
* database's (`container.ts`, `testing/`).
|
|
38
|
+
*
|
|
39
|
+
* Stays in a dialect: its lexical rules and statement grammar, its key words
|
|
40
|
+
* and identifier quoting, `literal()`'s escaping, its entity types and props,
|
|
41
|
+
* its generated types and overlays, its normalization rules, its rule ids
|
|
42
|
+
* and classes and the documentation they cite, the statements its applier
|
|
43
|
+
* sends and how it waits on the server, its client and binding, import and
|
|
44
|
+
* observation over its catalog, and its migration Op.
|
|
45
|
+
*
|
|
46
|
+
* Nothing here is exported from the package root or a dialect subpath on its
|
|
47
|
+
* own: each dialect re-exports what its public surface names.
|
|
48
|
+
*/
|
|
49
|
+
export * from "./entity.js";
|
|
50
|
+
export * from "./tokens.js";
|
|
51
|
+
export * from "./cursor.js";
|
|
52
|
+
export * from "./template.js";
|
|
53
|
+
export * from "./interpolation.js";
|
|
54
|
+
export * from "./find-templates.js";
|
|
55
|
+
export * from "./references.js";
|
|
56
|
+
export * from "./diff.js";
|
|
57
|
+
export * from "./classifier.js";
|
|
58
|
+
export * from "./normalize.js";
|
|
59
|
+
export * from "./typed.js";
|
|
60
|
+
export * from "./ownership.js";
|
|
61
|
+
export * from "./receipts.js";
|
|
62
|
+
export * from "./apply.js";
|
|
63
|
+
export * from "./handoff.js";
|
|
64
|
+
export * from "./container.js";
|