supaschema 0.1.0-rc.1
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/.agents/skills/supaschema/SKILL.md +61 -0
- package/.claude/hooks/block-generated-migration-edits.mjs +32 -0
- package/.claude/rules/supaschema.md +22 -0
- package/.claude/settings.json +16 -0
- package/.claude/skills/supaschema/SKILL.md +61 -0
- package/.codex/hooks/supaschema-tool-gate.mjs +73 -0
- package/.codex/hooks.json +16 -0
- package/.codex/rules/supaschema.rules +22 -0
- package/AGENTS.md +40 -0
- package/LICENSE +661 -0
- package/LICENSE-COMMERCIAL.md +35 -0
- package/README.md +249 -0
- package/benchmarks/README.md +104 -0
- package/benchmarks/compare.js +489 -0
- package/benchmarks/fixtures/additive/from.sql +8 -0
- package/benchmarks/fixtures/additive/manifest.json +1 -0
- package/benchmarks/fixtures/additive/to.sql +9 -0
- package/benchmarks/fixtures/functions-policies/from.sql +24 -0
- package/benchmarks/fixtures/functions-policies/manifest.json +5 -0
- package/benchmarks/fixtures/functions-policies/to.sql +24 -0
- package/benchmarks/plot-lib.js +234 -0
- package/benchmarks/plot-svg.js +339 -0
- package/benchmarks/plot.js +154 -0
- package/benchmarks/tools/bench-all.sh +49 -0
- package/benchmarks/tools/build-project-fixture.mjs +245 -0
- package/benchmarks/tools/compare-db.mjs +101 -0
- package/benchmarks/tools/compare-fixtures.mjs +84 -0
- package/benchmarks/tools/compare-report.mjs +90 -0
- package/benchmarks/tools/compare-supabase.mjs +67 -0
- package/benchmarks/tools/registry.js +266 -0
- package/benchmarks/tools/run-workflow.mjs +77 -0
- package/bin/postinstall.mjs +26 -0
- package/bin/supaschema +2 -0
- package/config-schema.json +208 -0
- package/corpus/supabase-style/corpus.json +6 -0
- package/corpus/supabase-style/migrations/20260101000000_init.sql +28 -0
- package/corpus/supabase-style/migrations/20260102000000_noise.sql +13 -0
- package/corpus/supabase-style/migrations/20260103000000_churn.sql +4 -0
- package/corpus/supabase-style/migrations/20260104000000_triggers.sql +17 -0
- package/corpus/supabase-style/roles.sql +13 -0
- package/corpus/supabase-style/tree/functions.sql +26 -0
- package/corpus/supabase-style/tree/policies.sql +4 -0
- package/corpus/supabase-style/tree/schema.sql +4 -0
- package/corpus/supabase-style/tree/tables.sql +20 -0
- package/corpus/supabase-style/tree/triggers.sql +3 -0
- package/corpus/supabase-style/tree/types.sql +2 -0
- package/corpus/supabase-style/tree/views.sql +6 -0
- package/dist/audit.d.ts +20 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +68 -0
- package/dist/benchmark-db.d.ts +5 -0
- package/dist/benchmark-db.d.ts.map +1 -0
- package/dist/benchmark-db.js +71 -0
- package/dist/benchmark-fixtures.d.ts +10 -0
- package/dist/benchmark-fixtures.d.ts.map +1 -0
- package/dist/benchmark-fixtures.js +201 -0
- package/dist/benchmark.d.ts +2 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +308 -0
- package/dist/catalog-comments.d.ts +9 -0
- package/dist/catalog-comments.d.ts.map +1 -0
- package/dist/catalog-comments.js +194 -0
- package/dist/catalog-extras.d.ts +12 -0
- package/dist/catalog-extras.d.ts.map +1 -0
- package/dist/catalog-extras.js +408 -0
- package/dist/catalog-foreign.d.ts +15 -0
- package/dist/catalog-foreign.d.ts.map +1 -0
- package/dist/catalog-foreign.js +114 -0
- package/dist/catalog-tables.d.ts +9 -0
- package/dist/catalog-tables.d.ts.map +1 -0
- package/dist/catalog-tables.js +114 -0
- package/dist/catalog.d.ts +8 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +351 -0
- package/dist/check-hazards.d.ts +7 -0
- package/dist/check-hazards.d.ts.map +1 -0
- package/dist/check-hazards.js +83 -0
- package/dist/check-reporters.d.ts +8 -0
- package/dist/check-reporters.d.ts.map +1 -0
- package/dist/check-reporters.js +76 -0
- package/dist/check.d.ts +3 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +229 -0
- package/dist/cli-defaults.d.ts +24 -0
- package/dist/cli-defaults.d.ts.map +1 -0
- package/dist/cli-defaults.js +65 -0
- package/dist/cli-diff.d.ts +13 -0
- package/dist/cli-diff.d.ts.map +1 -0
- package/dist/cli-diff.js +348 -0
- package/dist/cli-reports.d.ts +9 -0
- package/dist/cli-reports.d.ts.map +1 -0
- package/dist/cli-reports.js +90 -0
- package/dist/cli-tools.d.ts +17 -0
- package/dist/cli-tools.d.ts.map +1 -0
- package/dist/cli-tools.js +136 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +239 -0
- package/dist/config-schema-gen.d.ts +2 -0
- package/dist/config-schema-gen.d.ts.map +1 -0
- package/dist/config-schema-gen.js +11 -0
- package/dist/config.d.ts +58 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +132 -0
- package/dist/core.d.ts +115 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +1 -0
- package/dist/corpus.d.ts +26 -0
- package/dist/corpus.d.ts.map +1 -0
- package/dist/corpus.js +112 -0
- package/dist/database-url.d.ts +8 -0
- package/dist/database-url.d.ts.map +1 -0
- package/dist/database-url.js +74 -0
- package/dist/db-admin.d.ts +23 -0
- package/dist/db-admin.d.ts.map +1 -0
- package/dist/db-admin.js +147 -0
- package/dist/diagnostics.d.ts +16 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +155 -0
- package/dist/diff-score.d.ts +12 -0
- package/dist/diff-score.d.ts.map +1 -0
- package/dist/diff-score.js +339 -0
- package/dist/doctor.d.ts +17 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +110 -0
- package/dist/hash.d.ts +7 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +34 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/lineage.d.ts +23 -0
- package/dist/lineage.d.ts.map +1 -0
- package/dist/lineage.js +61 -0
- package/dist/migrations-status.d.ts +35 -0
- package/dist/migrations-status.d.ts.map +1 -0
- package/dist/migrations-status.js +131 -0
- package/dist/plan-order.d.ts +4 -0
- package/dist/plan-order.d.ts.map +1 -0
- package/dist/plan-order.js +178 -0
- package/dist/planner-replace.d.ts +4 -0
- package/dist/planner-replace.d.ts.map +1 -0
- package/dist/planner-replace.js +76 -0
- package/dist/planner-table.d.ts +3 -0
- package/dist/planner-table.d.ts.map +1 -0
- package/dist/planner-table.js +165 -0
- package/dist/planner.d.ts +5 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +385 -0
- package/dist/render-guards.d.ts +12 -0
- package/dist/render-guards.d.ts.map +1 -0
- package/dist/render-guards.js +159 -0
- package/dist/render.d.ts +7 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +325 -0
- package/dist/selfcheck.d.ts +11 -0
- package/dist/selfcheck.d.ts.map +1 -0
- package/dist/selfcheck.js +43 -0
- package/dist/source-normalize.d.ts +14 -0
- package/dist/source-normalize.d.ts.map +1 -0
- package/dist/source-normalize.js +420 -0
- package/dist/source.d.ts +4 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +233 -0
- package/dist/sql/ast.d.ts +42 -0
- package/dist/sql/ast.d.ts.map +1 -0
- package/dist/sql/ast.js +241 -0
- package/dist/sql/canonical-nodes.d.ts +5 -0
- package/dist/sql/canonical-nodes.d.ts.map +1 -0
- package/dist/sql/canonical-nodes.js +101 -0
- package/dist/sql/extract-helpers.d.ts +18 -0
- package/dist/sql/extract-helpers.d.ts.map +1 -0
- package/dist/sql/extract-helpers.js +127 -0
- package/dist/sql/extract.d.ts +13 -0
- package/dist/sql/extract.d.ts.map +1 -0
- package/dist/sql/extract.js +323 -0
- package/dist/sql/facts.d.ts +34 -0
- package/dist/sql/facts.d.ts.map +1 -0
- package/dist/sql/facts.js +392 -0
- package/dist/sql/identifiers.d.ts +13 -0
- package/dist/sql/identifiers.d.ts.map +1 -0
- package/dist/sql/identifiers.js +83 -0
- package/dist/sql/normalize-deparse.d.ts +25 -0
- package/dist/sql/normalize-deparse.d.ts.map +1 -0
- package/dist/sql/normalize-deparse.js +96 -0
- package/dist/sql/object-hash.d.ts +5 -0
- package/dist/sql/object-hash.d.ts.map +1 -0
- package/dist/sql/object-hash.js +24 -0
- package/dist/sql/parser.d.ts +8 -0
- package/dist/sql/parser.d.ts.map +1 -0
- package/dist/sql/parser.js +89 -0
- package/dist/sql/privileges.d.ts +33 -0
- package/dist/sql/privileges.d.ts.map +1 -0
- package/dist/sql/privileges.js +379 -0
- package/dist/sql/split.d.ts +3 -0
- package/dist/sql/split.d.ts.map +1 -0
- package/dist/sql/split.js +182 -0
- package/dist/sql/statements.d.ts +17 -0
- package/dist/sql/statements.d.ts.map +1 -0
- package/dist/sql/statements.js +284 -0
- package/dist/sql/table-constraints.d.ts +15 -0
- package/dist/sql/table-constraints.d.ts.map +1 -0
- package/dist/sql/table-constraints.js +304 -0
- package/dist/sql/table-shape.d.ts +38 -0
- package/dist/sql/table-shape.d.ts.map +1 -0
- package/dist/sql/table-shape.js +287 -0
- package/dist/sync.d.ts +27 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +86 -0
- package/dist/typegen-model.d.ts +78 -0
- package/dist/typegen-model.d.ts.map +1 -0
- package/dist/typegen-model.js +338 -0
- package/dist/typegen-views.d.ts +7 -0
- package/dist/typegen-views.d.ts.map +1 -0
- package/dist/typegen-views.js +92 -0
- package/dist/typegen-zod.d.ts +3 -0
- package/dist/typegen-zod.d.ts.map +1 -0
- package/dist/typegen-zod.js +149 -0
- package/dist/typegen.d.ts +4 -0
- package/dist/typegen.d.ts.map +1 -0
- package/dist/typegen.js +184 -0
- package/dist/validators.d.ts +3 -0
- package/dist/validators.d.ts.map +1 -0
- package/dist/validators.js +104 -0
- package/dist/verify-environment.d.ts +5 -0
- package/dist/verify-environment.d.ts.map +1 -0
- package/dist/verify-environment.js +92 -0
- package/dist/verify.d.ts +3 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +261 -0
- package/docs/benchmarks/additive-correctness.svg +86 -0
- package/docs/benchmarks/additive-latency.svg +60 -0
- package/docs/benchmarks/functions-policies-correctness.svg +86 -0
- package/docs/benchmarks/functions-policies-latency.svg +60 -0
- package/docs/benchmarks/realistic-correctness.svg +86 -0
- package/docs/benchmarks/realistic-latency.svg +60 -0
- package/docs/benchmarks/scaling-latency.svg +106 -0
- package/docs/benchmarks/workflow-latency.svg +98 -0
- package/docs/benchmarks/xl-correctness.svg +86 -0
- package/docs/benchmarks/xl-latency.svg +60 -0
- package/docs/benchmarks/xxl-correctness.svg +86 -0
- package/docs/benchmarks/xxl-latency.svg +66 -0
- package/docs/case-study-anilize.md +51 -0
- package/docs/ci-gate.md +44 -0
- package/docs/ci.md +68 -0
- package/docs/commands.md +35 -0
- package/docs/config.md +72 -0
- package/docs/corpus.md +33 -0
- package/docs/diagnostics.md +77 -0
- package/docs/hints.md +92 -0
- package/docs/release.md +19 -0
- package/docs/support-matrix.md +57 -0
- package/examples/postgres/schemas/001_app.sql +17 -0
- package/examples/supabase/schemas/001_app.sql +13 -0
- package/examples/supabase/schemas-next/001_app.sql +21 -0
- package/examples/supabase/supaschema.config.json +15 -0
- package/package.json +99 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type AstNode = Record<string, unknown>;
|
|
2
|
+
export interface QualifiedName {
|
|
3
|
+
name: string;
|
|
4
|
+
schema: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AstStatement {
|
|
7
|
+
byteStart: number;
|
|
8
|
+
node: AstNode;
|
|
9
|
+
tag: string;
|
|
10
|
+
text: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function asRecord(value: unknown): AstNode | undefined;
|
|
13
|
+
export declare function readArray(value: unknown): unknown[];
|
|
14
|
+
export declare function readString(value: unknown): string | undefined;
|
|
15
|
+
export declare function readBoolean(value: unknown): boolean;
|
|
16
|
+
export declare function readNumber(value: unknown): number | undefined;
|
|
17
|
+
export declare function stringValue(value: unknown): string | undefined;
|
|
18
|
+
export declare function listItems(value: unknown): unknown[];
|
|
19
|
+
export declare function stringList(value: unknown): string[];
|
|
20
|
+
export declare function astStatements(ast: unknown, sql: string): AstStatement[];
|
|
21
|
+
export declare function rangeVarName(value: unknown): QualifiedName | undefined;
|
|
22
|
+
export declare function qualifiedName(value: unknown): QualifiedName | undefined;
|
|
23
|
+
export declare function typeNameToSql(value: unknown): string;
|
|
24
|
+
export declare function roleSpecName(value: unknown): string | undefined;
|
|
25
|
+
export interface FunctionIdentity extends QualifiedName {
|
|
26
|
+
signature: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function functionIdentity(funcname: unknown, parameters: unknown): FunctionIdentity | undefined;
|
|
29
|
+
export declare function objectWithArgsIdentity(value: unknown): FunctionIdentity | undefined;
|
|
30
|
+
export interface ColumnFacts {
|
|
31
|
+
name: string;
|
|
32
|
+
notNull: boolean;
|
|
33
|
+
hasDefault: boolean;
|
|
34
|
+
identity: boolean;
|
|
35
|
+
generated: boolean;
|
|
36
|
+
hasInlineConstraint: boolean;
|
|
37
|
+
type: string;
|
|
38
|
+
location: number;
|
|
39
|
+
}
|
|
40
|
+
export declare function collectReferences(value: unknown, into?: Set<string>): Set<string>;
|
|
41
|
+
export declare function columnFacts(value: unknown): ColumnFacts | undefined;
|
|
42
|
+
//# sourceMappingURL=ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/sql/ast.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAE5D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAEnD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE7D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMnD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE7D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE9D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAMnD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAInD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,EAAE,CA0BvE;AAID,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAUtE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAYvE;AAoBD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMpD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAO/D;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,OAAO,GAClB,gBAAgB,GAAG,SAAS,CAmB9B;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAQnF;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,GAAG,CAAC,MAAM,CAAC,CAsC5F;AAaD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,SAAS,CA8CnE"}
|
package/dist/sql/ast.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
export function asRecord(value) {
|
|
2
|
+
return value && typeof value === "object" ? value : undefined;
|
|
3
|
+
}
|
|
4
|
+
export function readArray(value) {
|
|
5
|
+
return Array.isArray(value) ? value : [];
|
|
6
|
+
}
|
|
7
|
+
export function readString(value) {
|
|
8
|
+
return typeof value === "string" ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
export function readBoolean(value) {
|
|
11
|
+
if (value === true) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
const booleanNode = asRecord(asRecord(value)?.Boolean);
|
|
15
|
+
return booleanNode?.boolval === true;
|
|
16
|
+
}
|
|
17
|
+
export function readNumber(value) {
|
|
18
|
+
return typeof value === "number" ? value : undefined;
|
|
19
|
+
}
|
|
20
|
+
export function stringValue(value) {
|
|
21
|
+
return readString(asRecord(asRecord(value)?.String)?.sval);
|
|
22
|
+
}
|
|
23
|
+
export function listItems(value) {
|
|
24
|
+
const direct = readArray(value);
|
|
25
|
+
if (direct.length > 0) {
|
|
26
|
+
return direct;
|
|
27
|
+
}
|
|
28
|
+
return readArray(asRecord(asRecord(value)?.List)?.items);
|
|
29
|
+
}
|
|
30
|
+
export function stringList(value) {
|
|
31
|
+
return listItems(value)
|
|
32
|
+
.map((item) => stringValue(item))
|
|
33
|
+
.filter((item) => item !== undefined);
|
|
34
|
+
}
|
|
35
|
+
export function astStatements(ast, sql) {
|
|
36
|
+
const statements = [];
|
|
37
|
+
const bytes = Buffer.from(sql, "utf8");
|
|
38
|
+
for (const raw of readArray(asRecord(ast)?.stmts)) {
|
|
39
|
+
const record = asRecord(raw);
|
|
40
|
+
const node = asRecord(record?.stmt);
|
|
41
|
+
if (!node) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const tag = Object.keys(node)[0] ?? "";
|
|
45
|
+
const location = readNumber(record?.stmt_location) ?? 0;
|
|
46
|
+
const length = readNumber(record?.stmt_len);
|
|
47
|
+
const end = length === undefined ? bytes.length : location + length;
|
|
48
|
+
let byteStart = location;
|
|
49
|
+
while (byteStart < end && asciiWhitespace.has(bytes[byteStart] ?? -1)) {
|
|
50
|
+
byteStart += 1;
|
|
51
|
+
}
|
|
52
|
+
statements.push({
|
|
53
|
+
byteStart,
|
|
54
|
+
node,
|
|
55
|
+
tag,
|
|
56
|
+
text: bytes.subarray(byteStart, end).toString("utf8").trimEnd(),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return statements;
|
|
60
|
+
}
|
|
61
|
+
const asciiWhitespace = new Set([0x20, 0x09, 0x0a, 0x0d, 0x0c, 0x0b]);
|
|
62
|
+
export function rangeVarName(value) {
|
|
63
|
+
const relation = asRecord(asRecord(value)?.RangeVar) ?? asRecord(value);
|
|
64
|
+
const relname = readString(relation?.relname);
|
|
65
|
+
if (!relname) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
name: relname,
|
|
70
|
+
schema: readString(relation?.schemaname) ?? "public",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function qualifiedName(value) {
|
|
74
|
+
const parts = stringList(value);
|
|
75
|
+
if (parts.length === 0) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
if (parts.length === 1) {
|
|
79
|
+
return { name: parts[0] ?? "", schema: "public" };
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
name: parts.at(-1) ?? "",
|
|
83
|
+
schema: parts.at(-2) ?? "public",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const internalTypeNames = new Map([
|
|
87
|
+
["bool", "boolean"],
|
|
88
|
+
["bpchar", "character"],
|
|
89
|
+
["char", '"char"'],
|
|
90
|
+
["float4", "real"],
|
|
91
|
+
["float8", "double precision"],
|
|
92
|
+
["int2", "smallint"],
|
|
93
|
+
["int4", "integer"],
|
|
94
|
+
["int8", "bigint"],
|
|
95
|
+
["time", "time without time zone"],
|
|
96
|
+
["varbit", "bit varying"],
|
|
97
|
+
["timestamp", "timestamp without time zone"],
|
|
98
|
+
["timestamptz", "timestamp with time zone"],
|
|
99
|
+
["timetz", "time with time zone"],
|
|
100
|
+
["varchar", "character varying"],
|
|
101
|
+
]);
|
|
102
|
+
export function typeNameToSql(value) {
|
|
103
|
+
const typeName = asRecord(asRecord(value)?.TypeName) ?? asRecord(value);
|
|
104
|
+
const names = stringList(typeName?.names).filter((name) => name !== "pg_catalog");
|
|
105
|
+
const base = names.map((name) => internalTypeNames.get(name) ?? name).join(".");
|
|
106
|
+
const arraySuffix = "[]".repeat(readArray(typeName?.arrayBounds).length);
|
|
107
|
+
return `${base}${arraySuffix}`;
|
|
108
|
+
}
|
|
109
|
+
export function roleSpecName(value) {
|
|
110
|
+
const role = asRecord(asRecord(value)?.RoleSpec) ?? asRecord(value);
|
|
111
|
+
const roletype = readString(role?.roletype);
|
|
112
|
+
if (roletype === "ROLESPEC_PUBLIC") {
|
|
113
|
+
return "PUBLIC";
|
|
114
|
+
}
|
|
115
|
+
return readString(role?.rolename);
|
|
116
|
+
}
|
|
117
|
+
export function functionIdentity(funcname, parameters) {
|
|
118
|
+
const name = qualifiedName(funcname);
|
|
119
|
+
if (!name) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const args = [];
|
|
123
|
+
for (const item of readArray(parameters)) {
|
|
124
|
+
const parameter = asRecord(asRecord(item)?.FunctionParameter);
|
|
125
|
+
if (!parameter) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const mode = readString(parameter.mode) ?? "FUNC_PARAM_DEFAULT";
|
|
129
|
+
if (mode === "FUNC_PARAM_OUT" || mode === "FUNC_PARAM_TABLE") {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const prefix = mode === "FUNC_PARAM_VARIADIC" ? "VARIADIC " : "";
|
|
133
|
+
args.push(`${prefix}${typeNameToSql(parameter.argType)}`);
|
|
134
|
+
}
|
|
135
|
+
return { ...name, signature: args.join(", ") };
|
|
136
|
+
}
|
|
137
|
+
export function objectWithArgsIdentity(value) {
|
|
138
|
+
const object = asRecord(asRecord(value)?.ObjectWithArgs) ?? asRecord(value);
|
|
139
|
+
const name = qualifiedName(object?.objname);
|
|
140
|
+
if (!name) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const args = readArray(object?.objargs).map((item) => typeNameToSql(item));
|
|
144
|
+
return { ...name, signature: args.join(", ") };
|
|
145
|
+
}
|
|
146
|
+
export function collectReferences(value, into = new Set()) {
|
|
147
|
+
if (Array.isArray(value)) {
|
|
148
|
+
for (const item of value) {
|
|
149
|
+
collectReferences(item, into);
|
|
150
|
+
}
|
|
151
|
+
return into;
|
|
152
|
+
}
|
|
153
|
+
const record = asRecord(value);
|
|
154
|
+
if (!record) {
|
|
155
|
+
return into;
|
|
156
|
+
}
|
|
157
|
+
const rangeVar = asRecord(record.RangeVar);
|
|
158
|
+
if (rangeVar) {
|
|
159
|
+
const name = rangeVarName(rangeVar);
|
|
160
|
+
if (name) {
|
|
161
|
+
into.add(`${name.schema}.${name.name}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const funcCall = asRecord(record.FuncCall);
|
|
165
|
+
if (funcCall) {
|
|
166
|
+
const name = qualifiedNameWhenQualified(funcCall.funcname);
|
|
167
|
+
if (name) {
|
|
168
|
+
into.add(`${name.schema}.${name.name}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const typeName = asRecord(record.TypeName);
|
|
172
|
+
if (typeName) {
|
|
173
|
+
const name = qualifiedNameWhenQualified(typeName.names);
|
|
174
|
+
if (name && name.schema !== "pg_catalog") {
|
|
175
|
+
into.add(`${name.schema}.${name.name}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
for (const child of Object.values(record)) {
|
|
179
|
+
if (child && typeof child === "object") {
|
|
180
|
+
collectReferences(child, into);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return into;
|
|
184
|
+
}
|
|
185
|
+
function qualifiedNameWhenQualified(value) {
|
|
186
|
+
const parts = stringList(value);
|
|
187
|
+
if (parts.length < 2) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
name: parts.at(-1) ?? "",
|
|
192
|
+
schema: parts.at(-2) ?? "",
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
export function columnFacts(value) {
|
|
196
|
+
const column = asRecord(asRecord(value)?.ColumnDef);
|
|
197
|
+
const name = readString(column?.colname);
|
|
198
|
+
if (!column || !name) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
let notNull = false;
|
|
202
|
+
let hasDefault = false;
|
|
203
|
+
let identity = false;
|
|
204
|
+
let generated = false;
|
|
205
|
+
let hasInlineConstraint = false;
|
|
206
|
+
for (const item of readArray(column.constraints)) {
|
|
207
|
+
const constraint = asRecord(asRecord(item)?.Constraint);
|
|
208
|
+
const contype = readString(constraint?.contype);
|
|
209
|
+
switch (contype) {
|
|
210
|
+
case "CONSTR_NOTNULL":
|
|
211
|
+
notNull = true;
|
|
212
|
+
break;
|
|
213
|
+
case "CONSTR_DEFAULT":
|
|
214
|
+
hasDefault = true;
|
|
215
|
+
break;
|
|
216
|
+
case "CONSTR_IDENTITY":
|
|
217
|
+
identity = true;
|
|
218
|
+
break;
|
|
219
|
+
case "CONSTR_GENERATED":
|
|
220
|
+
generated = true;
|
|
221
|
+
break;
|
|
222
|
+
case "CONSTR_NULL":
|
|
223
|
+
break;
|
|
224
|
+
default:
|
|
225
|
+
if (contype !== undefined) {
|
|
226
|
+
hasInlineConstraint = true;
|
|
227
|
+
}
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
generated,
|
|
233
|
+
hasDefault,
|
|
234
|
+
hasInlineConstraint,
|
|
235
|
+
identity,
|
|
236
|
+
location: readNumber(column.location) ?? -1,
|
|
237
|
+
name,
|
|
238
|
+
notNull,
|
|
239
|
+
type: typeNameToSql(column.typeName),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical-nodes.d.ts","sourceRoot":"","sources":["../../src/sql/canonical-nodes.ts"],"names":[],"mappings":"AAEA,KAAK,KAAK,GAAG,MAAM,GAAG,IAAI,CAAC;AAE3B,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,GAAE,KAAK,EAAO,GAAG,OAAO,CA0ChF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAkBzE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { asRecord } from "./ast.js";
|
|
2
|
+
export function canonicalPolicyNode(node, scopes = []) {
|
|
3
|
+
if (Array.isArray(node)) {
|
|
4
|
+
return node.map((item) => canonicalPolicyNode(item, scopes));
|
|
5
|
+
}
|
|
6
|
+
if (typeof node !== "object" || node === null) {
|
|
7
|
+
return node;
|
|
8
|
+
}
|
|
9
|
+
const record = node;
|
|
10
|
+
const typeCast = asRecord(record.TypeCast);
|
|
11
|
+
if (typeCast && asRecord(typeCast.arg)?.A_Const !== undefined) {
|
|
12
|
+
return canonicalPolicyNode(typeCast.arg, scopes);
|
|
13
|
+
}
|
|
14
|
+
// A subquery inside a policy expression is its own SELECT scope. pg_get_expr
|
|
15
|
+
// qualifies that subquery's columns with its relation (`members.item_id`)
|
|
16
|
+
// where the declarative source writes them bare (`item_id`); stripping the
|
|
17
|
+
// sole-from-relation qualifier of the innermost scope converges both lanes,
|
|
18
|
+
// exactly as canonicalViewNode does. Correlated refs to an outer scope keep
|
|
19
|
+
// their written qualification (the conservative stance that never masks a
|
|
20
|
+
// real change).
|
|
21
|
+
const selectStmt = asRecord(record.SelectStmt);
|
|
22
|
+
if (selectStmt) {
|
|
23
|
+
const next = [...scopes, soleFromRelation(selectStmt)];
|
|
24
|
+
const inner = {};
|
|
25
|
+
for (const [key, value] of Object.entries(selectStmt)) {
|
|
26
|
+
inner[key] = canonicalPolicyNode(value, next);
|
|
27
|
+
}
|
|
28
|
+
return { ...record, SelectStmt: inner };
|
|
29
|
+
}
|
|
30
|
+
const columnRef = asRecord(record.ColumnRef);
|
|
31
|
+
if (columnRef) {
|
|
32
|
+
return { ...record, ColumnRef: canonicalColumnRef(columnRef, scopes) };
|
|
33
|
+
}
|
|
34
|
+
const result = {};
|
|
35
|
+
for (const [key, value] of Object.entries(record)) {
|
|
36
|
+
if (key === "ResTarget" && typeof value === "object" && value !== null) {
|
|
37
|
+
const { name: _alias, ...rest } = value;
|
|
38
|
+
result[key] = canonicalPolicyNode(rest, scopes);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
result[key] = canonicalPolicyNode(value, scopes);
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
export function canonicalViewNode(node, scopes) {
|
|
46
|
+
if (Array.isArray(node)) {
|
|
47
|
+
return node.map((item) => canonicalViewNode(item, scopes));
|
|
48
|
+
}
|
|
49
|
+
if (typeof node !== "object" || node === null) {
|
|
50
|
+
return node;
|
|
51
|
+
}
|
|
52
|
+
const record = node;
|
|
53
|
+
const selectStmt = asRecord(record.SelectStmt);
|
|
54
|
+
if (selectStmt) {
|
|
55
|
+
const next = [...scopes, soleFromRelation(selectStmt)];
|
|
56
|
+
return { ...record, SelectStmt: canonicalChildren(selectStmt, next) };
|
|
57
|
+
}
|
|
58
|
+
const columnRef = asRecord(record.ColumnRef);
|
|
59
|
+
if (columnRef) {
|
|
60
|
+
return { ...record, ColumnRef: canonicalColumnRef(columnRef, scopes) };
|
|
61
|
+
}
|
|
62
|
+
return canonicalChildren(record, scopes);
|
|
63
|
+
}
|
|
64
|
+
function canonicalColumnRef(columnRef, scopes) {
|
|
65
|
+
const fields = columnRef.fields;
|
|
66
|
+
if (!Array.isArray(fields) || fields.length !== 2) {
|
|
67
|
+
return columnRef;
|
|
68
|
+
}
|
|
69
|
+
const qualifier = stringField(fields[0]);
|
|
70
|
+
const innermost = scopes.at(-1);
|
|
71
|
+
if (qualifier === undefined || innermost === null || qualifier !== innermost) {
|
|
72
|
+
return columnRef;
|
|
73
|
+
}
|
|
74
|
+
return { ...columnRef, fields: [fields[1]] };
|
|
75
|
+
}
|
|
76
|
+
function soleFromRelation(selectStmt) {
|
|
77
|
+
const fromClause = selectStmt.fromClause;
|
|
78
|
+
if (!Array.isArray(fromClause) || fromClause.length !== 1) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const rangeVar = asRecord(asRecord(fromClause[0])?.RangeVar);
|
|
82
|
+
if (!rangeVar) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const aliasName = asRecord(rangeVar.alias)?.aliasname;
|
|
86
|
+
if (typeof aliasName === "string") {
|
|
87
|
+
return aliasName;
|
|
88
|
+
}
|
|
89
|
+
return typeof rangeVar.relname === "string" ? rangeVar.relname : null;
|
|
90
|
+
}
|
|
91
|
+
function canonicalChildren(record, scopes) {
|
|
92
|
+
const result = {};
|
|
93
|
+
for (const [key, child] of Object.entries(record)) {
|
|
94
|
+
result[key] = canonicalViewNode(child, scopes);
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
function stringField(field) {
|
|
99
|
+
const sval = asRecord(asRecord(field)?.String)?.sval;
|
|
100
|
+
return typeof sval === "string" ? sval : undefined;
|
|
101
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Diagnostic, SchemaObject, SupaschemaConfig } from "../core.js";
|
|
2
|
+
import type { AstNode } from "./ast.js";
|
|
3
|
+
export type ParseStatementResult = {
|
|
4
|
+
diagnostics: Diagnostic[];
|
|
5
|
+
objects: SchemaObject[];
|
|
6
|
+
};
|
|
7
|
+
export declare function alterTableObjects(node: AstNode, statement: string, ordinal: number, file: string | undefined): SchemaObject[] | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Reads the OWNED BY target from ALTER SEQUENCE options: `null` for
|
|
10
|
+
* OWNED BY NONE, the dotted column path otherwise, `undefined` when the
|
|
11
|
+
* statement carries no owned_by option (other ALTER SEQUENCE forms stay
|
|
12
|
+
* unsupported).
|
|
13
|
+
*/
|
|
14
|
+
export declare function sequenceOwnedByOption(options: unknown): string | null | undefined;
|
|
15
|
+
export declare function extensionSchemaOption(options: unknown): string | undefined;
|
|
16
|
+
export declare function withManagedSchemaDiagnostics(objects: SchemaObject[], statement: string, config: SupaschemaConfig, file: string | undefined): ParseStatementResult;
|
|
17
|
+
export declare function supabaseViewSecurityDiagnostics(objects: SchemaObject[], config: SupaschemaConfig): Diagnostic[];
|
|
18
|
+
//# sourceMappingURL=extract-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-helpers.d.ts","sourceRoot":"","sources":["../../src/sql/extract-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAIxC,MAAM,MAAM,oBAAoB,GAAG;IACjC,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,YAAY,EAAE,GAAG,SAAS,CAgE5B;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAajF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAY1E;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,YAAY,EAAE,EACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,oBAAoB,CAMtB;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,YAAY,EAAE,EACvB,MAAM,EAAE,gBAAgB,GACvB,UAAU,EAAE,CA0Bd"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { diagnostic } from "../diagnostics.js";
|
|
2
|
+
import { asRecord, rangeVarName, readArray, readString, stringList } from "./ast.js";
|
|
3
|
+
import { makeObject } from "./statements.js";
|
|
4
|
+
export function alterTableObjects(node, statement, ordinal, file) {
|
|
5
|
+
const table = rangeVarName(node.relation);
|
|
6
|
+
if (!table) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const command = readArray(node.cmds)
|
|
10
|
+
.map((item) => asRecord(asRecord(item)?.AlterTableCmd))
|
|
11
|
+
.find((item) => item !== undefined);
|
|
12
|
+
const subtype = readString(command?.subtype);
|
|
13
|
+
if (subtype === "AT_AddConstraint") {
|
|
14
|
+
const constraint = asRecord(asRecord(command?.def)?.Constraint);
|
|
15
|
+
const name = readString(constraint?.conname);
|
|
16
|
+
if (!name) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return [
|
|
20
|
+
makeObject({
|
|
21
|
+
kind: "constraint",
|
|
22
|
+
name,
|
|
23
|
+
schema: table.schema,
|
|
24
|
+
table: table.name,
|
|
25
|
+
}, statement, ordinal, file),
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
if (subtype === "AT_EnableRowSecurity" ||
|
|
29
|
+
subtype === "AT_DisableRowSecurity" ||
|
|
30
|
+
subtype === "AT_ForceRowSecurity" ||
|
|
31
|
+
subtype === "AT_NoForceRowSecurity") {
|
|
32
|
+
return [
|
|
33
|
+
makeObject({ kind: "rls", name: table.name, schema: table.schema, table: table.name }, statement, ordinal, file, { rlsSubtype: subtype }),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
if (subtype === "AT_ColumnDefault") {
|
|
37
|
+
const column = readString(command?.name);
|
|
38
|
+
if (!column) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return [
|
|
42
|
+
makeObject({ kind: "table", name: table.name, schema: table.schema }, statement, ordinal, file, {
|
|
43
|
+
columnDefaultAmendment: { column, expression: command?.def ?? null },
|
|
44
|
+
}),
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Reads the OWNED BY target from ALTER SEQUENCE options: `null` for
|
|
51
|
+
* OWNED BY NONE, the dotted column path otherwise, `undefined` when the
|
|
52
|
+
* statement carries no owned_by option (other ALTER SEQUENCE forms stay
|
|
53
|
+
* unsupported).
|
|
54
|
+
*/
|
|
55
|
+
export function sequenceOwnedByOption(options) {
|
|
56
|
+
for (const item of readArray(options)) {
|
|
57
|
+
const defElem = asRecord(asRecord(item)?.DefElem);
|
|
58
|
+
if (readString(defElem?.defname) !== "owned_by") {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const parts = stringList(defElem?.arg);
|
|
62
|
+
if (parts.length === 0) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return parts.at(-1) === "none" ? null : parts.join(".");
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
export function extensionSchemaOption(options) {
|
|
70
|
+
for (const item of readArray(options)) {
|
|
71
|
+
const defElem = asRecord(asRecord(item)?.DefElem);
|
|
72
|
+
if (readString(defElem?.defname) !== "schema") {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const value = readString(asRecord(asRecord(defElem?.arg)?.String)?.sval);
|
|
76
|
+
if (value) {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
export function withManagedSchemaDiagnostics(objects, statement, config, file) {
|
|
83
|
+
const diagnostics = [];
|
|
84
|
+
for (const object of objects) {
|
|
85
|
+
diagnostics.push(...managedSchemaDiagnostics(object, statement, config, file));
|
|
86
|
+
}
|
|
87
|
+
return { diagnostics, objects };
|
|
88
|
+
}
|
|
89
|
+
export function supabaseViewSecurityDiagnostics(objects, config) {
|
|
90
|
+
if (config.adapter !== "supabase-auto") {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
const diagnostics = [];
|
|
94
|
+
for (const object of objects) {
|
|
95
|
+
if (object.ref.kind !== "view" || (object.ref.schema ?? "public") !== "public") {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (object.metadata.securityInvoker === true) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
diagnostics.push(diagnostic("SUPA_SUPABASE_VIEW_SECURITY_INVOKER", "warning", `view "public"."${object.ref.name}" in an exposed schema does not set security_invoker`, {
|
|
102
|
+
file: object.file,
|
|
103
|
+
hint: "Add WITH (security_invoker = true) so row level security applies to the querying role.",
|
|
104
|
+
ref: object.ref,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
return diagnostics;
|
|
108
|
+
}
|
|
109
|
+
function managedSchemaDiagnostics(object, statement, config, file) {
|
|
110
|
+
if (config.adapter !== "supabase-auto") {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
const refSchema = object.ref.kind === "schema" ? object.ref.name : object.ref.schema;
|
|
114
|
+
const metadataSchema = typeof object.metadata.schema === "string" ? object.metadata.schema : undefined;
|
|
115
|
+
const schema = [refSchema, metadataSchema].find((candidate) => candidate !== undefined && config.managedSchemas.includes(candidate));
|
|
116
|
+
if (!schema) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
return [
|
|
120
|
+
diagnostic("SUPA_SUPABASE_MANAGED_SCHEMA", "error", `schema "${schema}" is managed by Supabase and is not a declarative source owner`, {
|
|
121
|
+
file,
|
|
122
|
+
hint: `Move this statement out of the declarative tree, or exclude the schema with config schemas.exclude: ["${schema}"].`,
|
|
123
|
+
ref: object.ref,
|
|
124
|
+
statement,
|
|
125
|
+
}),
|
|
126
|
+
];
|
|
127
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Diagnostic, ExtractOptions, SchemaObject } from "../core.js";
|
|
2
|
+
type ExtractObjectsOptions = ExtractOptions & {
|
|
3
|
+
file?: string;
|
|
4
|
+
startOrdinal?: number;
|
|
5
|
+
};
|
|
6
|
+
type ExtractObjectsResult = {
|
|
7
|
+
diagnostics: Diagnostic[];
|
|
8
|
+
nextOrdinal: number;
|
|
9
|
+
objects: SchemaObject[];
|
|
10
|
+
};
|
|
11
|
+
export declare function extractObjectsFromSql(sql: string, options?: ExtractObjectsOptions): Promise<ExtractObjectsResult>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=extract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/sql/extract.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EAGd,YAAY,EAEb,MAAM,YAAY,CAAC;AAiCpB,KAAK,qBAAqB,GAAG,cAAc,GAAG;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAcF,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,oBAAoB,CAAC,CA6C/B"}
|