@intentius/chant-lexicon-sql 0.124.18 → 0.124.21
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/clickhouse/access.d.ts +36 -7
- package/dist/clickhouse/access.d.ts.map +1 -1
- package/dist/clickhouse/apply/statements.d.ts.map +1 -1
- package/dist/clickhouse/entities.d.ts +60 -0
- package/dist/clickhouse/entities.d.ts.map +1 -1
- package/dist/clickhouse/import/generator.d.ts +1 -7
- package/dist/clickhouse/import/generator.d.ts.map +1 -1
- package/dist/clickhouse/import/live-export.d.ts +8 -0
- package/dist/clickhouse/import/live-export.d.ts.map +1 -1
- package/dist/clickhouse/live/catalog.d.ts +6 -5
- package/dist/clickhouse/live/catalog.d.ts.map +1 -1
- package/dist/clickhouse/live/describe-resources.d.ts.map +1 -1
- package/dist/clickhouse/live/undeclarable.d.ts +32 -0
- package/dist/clickhouse/live/undeclarable.d.ts.map +1 -0
- package/dist/clickhouse/parser.d.ts +16 -0
- package/dist/clickhouse/parser.d.ts.map +1 -1
- package/dist/clickhouse/plan/deep.d.ts.map +1 -1
- package/dist/clickhouse/plan/diff.d.ts.map +1 -1
- package/dist/clickhouse/plan/normalize.d.ts +6 -3
- package/dist/clickhouse/plan/normalize.d.ts.map +1 -1
- package/dist/clickhouse/plan/rules.d.ts +3 -0
- package/dist/clickhouse/plan/rules.d.ts.map +1 -1
- package/dist/clickhouse/testing/fake-server.d.ts +6 -0
- package/dist/clickhouse/testing/fake-server.d.ts.map +1 -1
- package/dist/clickhouse/topology.d.ts.map +1 -1
- package/dist/clickhouse.d.ts +1 -1
- package/dist/clickhouse.d.ts.map +1 -1
- package/dist/codegen/coverage-page.d.ts +7 -0
- package/dist/codegen/coverage-page.d.ts.map +1 -0
- package/dist/codegen/docs.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/core/undeclarable.d.ts +38 -0
- package/dist/core/undeclarable.d.ts.map +1 -0
- package/dist/coverage/clickhouse-commands.json +24 -0
- package/dist/coverage/clickhouse.json +25 -0
- package/dist/coverage/postgres-commands.json +245 -0
- package/dist/coverage/postgres.json +51 -0
- package/dist/coverage.d.ts +68 -0
- package/dist/coverage.d.ts.map +1 -1
- package/dist/files/clickhouse.d.ts +2 -1
- package/dist/files/clickhouse.d.ts.map +1 -1
- package/dist/files/common.d.ts +12 -0
- package/dist/files/common.d.ts.map +1 -1
- package/dist/files/postgres.d.ts +1 -1
- package/dist/files/postgres.d.ts.map +1 -1
- package/dist/import-parser.d.ts +7 -2
- package/dist/import-parser.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +10 -10
- package/dist/lint/post-synth/postgres-names.d.ts.map +1 -1
- package/dist/lint/post-synth/sql101.d.ts.map +1 -1
- package/dist/lint/rules/sqlch001.d.ts +1 -1
- package/dist/lint/rules/sqlch001.d.ts.map +1 -1
- package/dist/lint/rules/sqlpg001.d.ts.map +1 -1
- package/dist/lint/rules/templates.d.ts +1 -1
- package/dist/lint/rules/templates.d.ts.map +1 -1
- package/dist/lsp/postgres-template.d.ts.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/meta.json +40 -0
- package/dist/okf/index.md +9 -1
- package/dist/okf/rules/SQL101.md +1 -0
- package/dist/okf/rules/SQLCH001.md +2 -2
- package/dist/okf/rules/SQLPG113.md +2 -0
- package/dist/okf/types/PostgresAggregate.md +13 -0
- package/dist/okf/types/PostgresCast.md +9 -0
- package/dist/okf/types/PostgresCollation.md +9 -0
- package/dist/okf/types/PostgresCompositeType.md +13 -0
- package/dist/okf/types/PostgresEventTrigger.md +9 -0
- package/dist/okf/types/PostgresRangeType.md +13 -0
- package/dist/okf/types/Quota.md +9 -0
- package/dist/okf/types/SettingsProfile.md +9 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/postgres/apply/apply.d.ts.map +1 -1
- package/dist/postgres/apply/statements.d.ts +4 -3
- package/dist/postgres/apply/statements.d.ts.map +1 -1
- package/dist/postgres/entities.d.ts +129 -6
- package/dist/postgres/entities.d.ts.map +1 -1
- package/dist/postgres/entity-types.d.ts +6 -0
- package/dist/postgres/entity-types.d.ts.map +1 -1
- package/dist/postgres/import/generator.d.ts +3 -2
- package/dist/postgres/import/generator.d.ts.map +1 -1
- package/dist/postgres/import/live-export.d.ts +8 -0
- package/dist/postgres/import/live-export.d.ts.map +1 -1
- package/dist/postgres/live/catalog-kinds.d.ts +28 -0
- package/dist/postgres/live/catalog-kinds.d.ts.map +1 -0
- package/dist/postgres/live/catalog.d.ts +23 -8
- package/dist/postgres/live/catalog.d.ts.map +1 -1
- package/dist/postgres/live/describe-resources.d.ts.map +1 -1
- package/dist/postgres/live/undeclarable.d.ts +42 -0
- package/dist/postgres/live/undeclarable.d.ts.map +1 -0
- package/dist/postgres/parser.d.ts +88 -5
- package/dist/postgres/parser.d.ts.map +1 -1
- package/dist/postgres/plan/deep.d.ts.map +1 -1
- package/dist/postgres/plan/diff.d.ts.map +1 -1
- package/dist/postgres/plan/normalize.d.ts +17 -2
- package/dist/postgres/plan/normalize.d.ts.map +1 -1
- package/dist/postgres/plan/rules.d.ts +3 -0
- package/dist/postgres/plan/rules.d.ts.map +1 -1
- package/dist/postgres/plan/schema.d.ts +3 -2
- package/dist/postgres/plan/schema.d.ts.map +1 -1
- package/dist/postgres/testing/fake-client.d.ts +6 -0
- package/dist/postgres/testing/fake-client.d.ts.map +1 -1
- package/dist/postgres/testing/roundtrip-schema.d.ts +4 -2
- package/dist/postgres/testing/roundtrip-schema.d.ts.map +1 -1
- package/dist/postgres.d.ts +1 -1
- package/dist/postgres.d.ts.map +1 -1
- package/dist/rules/postgres-names.ts +15 -2
- package/dist/rules/postgres-templates.ts +2 -2
- package/dist/rules/sql101.ts +1 -0
- package/dist/rules/sqlch001.ts +10 -3
- package/dist/rules/sqlpg001.ts +6 -21
- package/dist/rules/sqlpg113.ts +1 -1
- package/dist/rules/templates.ts +2 -2
- package/dist/validate.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/clickhouse/access.ts +197 -22
- package/src/clickhouse/apply/statements.ts +17 -5
- package/src/clickhouse/entities.ts +78 -2
- package/src/clickhouse/import/generator.ts +16 -3
- package/src/clickhouse/import/live-export.ts +17 -2
- package/src/clickhouse/live/catalog.ts +57 -10
- package/src/clickhouse/live/describe-resources.ts +3 -1
- package/src/clickhouse/live/kinds.e2e.test.ts +179 -0
- package/src/clickhouse/live/undeclarable.e2e.test.ts +65 -0
- package/src/clickhouse/live/undeclarable.ts +66 -0
- package/src/clickhouse/parser.test.ts +45 -2
- package/src/clickhouse/parser.ts +111 -3
- package/src/clickhouse/plan/deep.ts +25 -6
- package/src/clickhouse/plan/diff.ts +41 -1
- package/src/clickhouse/plan/normalize.ts +12 -4
- package/src/clickhouse/plan/rules.ts +22 -1
- package/src/clickhouse/quota-profile.test.ts +186 -0
- package/src/clickhouse/table-function.test.ts +54 -0
- package/src/clickhouse/testdata/server-ddl-baseline.json +17 -14
- package/src/clickhouse/testing/fake-server.ts +5 -0
- package/src/clickhouse/topology.ts +4 -2
- package/src/clickhouse.ts +6 -0
- package/src/codegen/classifier-page.test.ts +6 -0
- package/src/codegen/coverage-page.ts +77 -0
- package/src/codegen/docs.ts +5 -0
- package/src/codegen/postgres-classifier-page.ts +1 -1
- package/src/codegen/registry.ts +8 -0
- package/src/core/undeclarable.test.ts +141 -0
- package/src/core/undeclarable.ts +66 -0
- package/src/coverage/clickhouse-commands.json +24 -0
- package/src/coverage/clickhouse.json +25 -0
- package/src/coverage/postgres-commands.json +245 -0
- package/src/coverage/postgres.json +51 -0
- package/src/coverage.test.ts +78 -0
- package/src/coverage.ts +142 -0
- package/src/files/clickhouse.ts +20 -7
- package/src/files/common.ts +18 -0
- package/src/files/postgres.ts +25 -6
- package/src/generated/lexicon-sql.json +40 -0
- package/src/import-parser.ts +12 -4
- package/src/index.ts +2 -2
- package/src/lint/post-synth/postgres-names.ts +15 -2
- package/src/lint/post-synth/sql101.ts +1 -0
- package/src/lint/post-synth/sqlpg113.ts +1 -1
- package/src/lint/rules/postgres-templates.ts +2 -2
- package/src/lint/rules/sqlch001.ts +10 -3
- package/src/lint/rules/sqlpg001.ts +6 -21
- package/src/lint/rules/templates.ts +2 -2
- package/src/lsp/postgres-template.ts +14 -0
- package/src/mcp/index.ts +5 -5
- package/src/mcp/postgres.ts +1 -1
- package/src/plugin.ts +13 -2
- package/src/postgres/apply/apply.ts +8 -2
- package/src/postgres/apply/statements.ts +29 -6
- package/src/postgres/entities.test.ts +2 -2
- package/src/postgres/entities.ts +316 -28
- package/src/postgres/entity-types.ts +6 -0
- package/src/postgres/import/generator.ts +31 -4
- package/src/postgres/import/live-export.ts +25 -2
- package/src/postgres/kinds.test.ts +140 -0
- package/src/postgres/live/catalog-kinds.ts +312 -0
- package/src/postgres/live/catalog.ts +33 -11
- package/src/postgres/live/describe-resources.ts +14 -5
- package/src/postgres/live/kinds.e2e.test.ts +182 -0
- package/src/postgres/live/roundtrip.e2e.test.ts +9 -3
- package/src/postgres/live/undeclarable.e2e.test.ts +83 -0
- package/src/postgres/live/undeclarable.ts +141 -0
- package/src/postgres/parser.test.ts +2 -1
- package/src/postgres/parser.ts +307 -17
- package/src/postgres/plan/deep.ts +33 -0
- package/src/postgres/plan/diff.ts +45 -0
- package/src/postgres/plan/normalize.ts +153 -2
- package/src/postgres/plan/rules.ts +21 -0
- package/src/postgres/plan/schema.ts +6 -4
- package/src/postgres/testing/fake-client.ts +5 -0
- package/src/postgres/testing/roundtrip-schema.ts +19 -1
- package/src/postgres.ts +19 -0
- package/src/skill-defs.ts +1 -1
- package/src/skills/chant-sql-postgres.md +7 -3
- package/src/skills/chant-sql.md +3 -1
- package/src/unknown-clauses.test.ts +2 -1
- package/src/validate.ts +8 -0
|
@@ -46,13 +46,20 @@
|
|
|
46
46
|
import { isTrivia, tokenizeText, type Token } from "../tokens";
|
|
47
47
|
import { identValue } from "../parser";
|
|
48
48
|
import { quoteIdent } from "../keywords";
|
|
49
|
-
import { COLUMN_TYPES } from "../../generated/postgres";
|
|
49
|
+
import { COLUMN_TYPES, FUNCTIONS } from "../../generated/postgres";
|
|
50
50
|
import { stripMarker } from "../../core/ownership";
|
|
51
51
|
import { sequenceDefaults } from "../live/catalog";
|
|
52
52
|
import type {
|
|
53
|
+
AggregateArgDef,
|
|
54
|
+
AggregateProps,
|
|
55
|
+
CastProps,
|
|
53
56
|
CheckDef,
|
|
57
|
+
CollationProps,
|
|
54
58
|
ColumnDef,
|
|
59
|
+
CompositeTypeProps,
|
|
55
60
|
DomainProps,
|
|
61
|
+
EventTriggerProps,
|
|
62
|
+
RangeTypeProps,
|
|
56
63
|
EnumProps,
|
|
57
64
|
ExclusionDef,
|
|
58
65
|
ExtensionProps,
|
|
@@ -333,8 +340,14 @@ export type CanonicalKind =
|
|
|
333
340
|
| "materializedView"
|
|
334
341
|
| "sequence"
|
|
335
342
|
| "enum"
|
|
343
|
+
| "composite"
|
|
344
|
+
| "range"
|
|
336
345
|
| "domain"
|
|
337
346
|
| "extension"
|
|
347
|
+
| "aggregate"
|
|
348
|
+
| "collation"
|
|
349
|
+
| "cast"
|
|
350
|
+
| "eventTrigger"
|
|
338
351
|
| "function"
|
|
339
352
|
| "procedure"
|
|
340
353
|
| "trigger"
|
|
@@ -373,7 +386,13 @@ const kindOf: Record<string, CanonicalKind> = {
|
|
|
373
386
|
"Postgres::MaterializedView": "materializedView",
|
|
374
387
|
"Postgres::Sequence": "sequence",
|
|
375
388
|
"Postgres::Enum": "enum",
|
|
389
|
+
"Postgres::CompositeType": "composite",
|
|
390
|
+
"Postgres::RangeType": "range",
|
|
376
391
|
"Postgres::Domain": "domain",
|
|
392
|
+
"Postgres::Aggregate": "aggregate",
|
|
393
|
+
"Postgres::Collation": "collation",
|
|
394
|
+
"Postgres::Cast": "cast",
|
|
395
|
+
"Postgres::EventTrigger": "eventTrigger",
|
|
377
396
|
"Postgres::Extension": "extension",
|
|
378
397
|
"Postgres::Function": "function",
|
|
379
398
|
"Postgres::Procedure": "procedure",
|
|
@@ -595,6 +614,96 @@ function triggerFields(p: TriggerProps, defaultSchema: string, fields: Record<st
|
|
|
595
614
|
: undefined;
|
|
596
615
|
}
|
|
597
616
|
|
|
617
|
+
// ── Types, aggregates, collations, casts, event triggers (#3911) ──────
|
|
618
|
+
|
|
619
|
+
/** The kinds that live in no schema. */
|
|
620
|
+
const UNPLACED: ReadonlySet<CanonicalKind> = new Set(["schema", "extension", "role", "cast", "eventTrigger"]);
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* A function named where an object calls it (an aggregate's SFUNC, a cast's
|
|
624
|
+
* or an event trigger's function), as the catalog's `regproc` prints it with
|
|
625
|
+
* an empty search_path: a `pg_catalog` function bare, any other qualified. A
|
|
626
|
+
* bare name that is no built-in function's is in the default schema.
|
|
627
|
+
*/
|
|
628
|
+
export function canonicalFunctionName(text: string, defaultSchema: string): string {
|
|
629
|
+
const pieces = canonicalName(text).split(/\.(?=(?:[^"]*"[^"]*")*[^"]*$)/);
|
|
630
|
+
if (pieces.length >= 2) return pieces[0] === "pg_catalog" ? pieces.slice(1).join(".") : pieces.join(".");
|
|
631
|
+
const bare = identValue(pieces[0]!);
|
|
632
|
+
return FUNCTIONS[bare] !== undefined ? pieces[0]! : `${quoteIdent(defaultSchema)}.${pieces[0]}`;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/** A collation named in a type or an attribute: canonical, a `pg_catalog` one bare (`"C"`), as the catalog prints it. */
|
|
636
|
+
export const canonicalCollation = (text: string): string => canonicalName(text).replace(/^pg_catalog\./, "");
|
|
637
|
+
|
|
638
|
+
/** A definition list's value as compared: a string constant's value, a word folded, other text canonical. */
|
|
639
|
+
function defValue(v: string): string {
|
|
640
|
+
const t = v.trim();
|
|
641
|
+
if (/^([Ee]?'|\$)/.test(t)) return stringValue(t) ?? t;
|
|
642
|
+
if (/^"/.test(t)) return identValue(t);
|
|
643
|
+
if (/^[A-Za-z_][A-Za-z0-9_$]*$/.test(t)) return t.toLowerCase();
|
|
644
|
+
return canonicalExpr(t) ?? t;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/** A Postgres boolean option's value (`true`, `on`, `1`, `yes`), as written or given with no value. */
|
|
648
|
+
const isTrue = (v: string | undefined): boolean => v !== undefined && /^(true|on|1|yes|t|y)$/i.test(defValue(v));
|
|
649
|
+
|
|
650
|
+
/** The name Postgres gives a range type's multirange type when none is written: `range` in its name becomes `multirange`, else `_multirange` is added. */
|
|
651
|
+
export function defaultMultirangeName(range: string): string {
|
|
652
|
+
const at = range.indexOf("range");
|
|
653
|
+
return at >= 0 ? `${range.slice(0, at)}multi${range.slice(at)}` : `${range}_multirange`;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/** An aggregate's identity among its overloads: `(integer)`, `(*)`, `(text ORDER BY integer)`. */
|
|
657
|
+
export function aggregateSignature(p: Pick<AggregateProps, "args" | "orderBy">, defaultSchema: string): string {
|
|
658
|
+
const types = (l: readonly AggregateArgDef[]) => l.map((a) => canonicalArgType(a.type, defaultSchema)).join(",");
|
|
659
|
+
if (p.orderBy) return `(${p.args.length > 0 ? `${types(p.args)} ` : ""}ORDER BY ${types(p.orderBy)})`;
|
|
660
|
+
return p.args.length === 0 ? "(*)" : `(${types(p.args)})`;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const AGGREGATE_FUNCTIONS = new Set(["sfunc", "finalfunc", "combinefunc", "serialfunc", "deserialfunc", "msfunc", "minvfunc", "mfinalfunc"]);
|
|
664
|
+
const AGGREGATE_TYPES = new Set(["stype", "mstype"]);
|
|
665
|
+
const AGGREGATE_FLAGS = new Set(["finalfunc_extra", "mfinalfunc_extra", "hypothetical"]);
|
|
666
|
+
|
|
667
|
+
/** An aggregate's definition as compared: each option canonical, the ones at their defaults left out. */
|
|
668
|
+
function aggregateOptions(p: AggregateProps, defaultSchema: string): Record<string, string> {
|
|
669
|
+
const out: Record<string, string> = {};
|
|
670
|
+
// A FINALFUNC_MODIFY not written is READ_ONLY for a plain aggregate, READ_WRITE for an ordered-set one.
|
|
671
|
+
const modifyDefault = p.orderBy ? "read_write" : "read_only";
|
|
672
|
+
for (const [k, v] of Object.entries(p.options)) {
|
|
673
|
+
if (AGGREGATE_FUNCTIONS.has(k)) out[k] = canonicalFunctionName(v, defaultSchema);
|
|
674
|
+
else if (AGGREGATE_TYPES.has(k)) out[k] = canonicalType(v, defaultSchema)!;
|
|
675
|
+
else if (AGGREGATE_FLAGS.has(k)) {
|
|
676
|
+
if (isTrue(v)) out[k] = "true";
|
|
677
|
+
} else if (k === "sspace" || k === "msspace") {
|
|
678
|
+
if (Number(defValue(v)) !== 0) out[k] = String(Number(defValue(v)));
|
|
679
|
+
} else if (k === "finalfunc_modify" || k === "mfinalfunc_modify") {
|
|
680
|
+
if (defValue(v) !== modifyDefault) out[k] = defValue(v);
|
|
681
|
+
} else if (k === "sortop") {
|
|
682
|
+
out[k] = v.trim().replace(/^OPERATOR\s*\(\s*(.*?)\s*\)$/is, "$1").replace(/^pg_catalog\s*\.\s*/i, "");
|
|
683
|
+
} else if (k === "parallel") {
|
|
684
|
+
if (defValue(v) !== "unsafe") out[k] = defValue(v);
|
|
685
|
+
} else out[k] = defValue(v);
|
|
686
|
+
}
|
|
687
|
+
return Object.fromEntries(Object.entries(out).sort(([a], [b]) => (a < b ? -1 : 1)));
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/** A collation's definition as compared: its provider (`libc` unless written) and locales, `deterministic` only when false. VERSION is the provider's, and is not compared. */
|
|
691
|
+
function collationFields(p: CollationProps, fields: Record<string, unknown>): void {
|
|
692
|
+
const o = Object.fromEntries(Object.entries(p.options).map(([k, v]) => [k, defValue(v)]));
|
|
693
|
+
const provider = o.provider ?? "libc";
|
|
694
|
+
fields.provider = provider;
|
|
695
|
+
if (provider === "libc") {
|
|
696
|
+
fields.lcCollate = o.lc_collate ?? o.locale;
|
|
697
|
+
fields.lcCtype = o.lc_ctype ?? o.locale;
|
|
698
|
+
} else fields.locale = o.locale ?? o.lc_collate;
|
|
699
|
+
fields.nondeterministic = p.options.deterministic !== undefined && !isTrue(p.options.deterministic);
|
|
700
|
+
fields.rules = o.rules;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/** A cast's name, `(source AS target)`, its types canonical. */
|
|
704
|
+
export const castName = (p: Pick<CastProps, "sourceType" | "targetType">, defaultSchema: string): string =>
|
|
705
|
+
`(${canonicalType(p.sourceType, defaultSchema)} AS ${canonicalType(p.targetType, defaultSchema)})`;
|
|
706
|
+
|
|
598
707
|
/**
|
|
599
708
|
* A definition in canonical form. `props` is an entity's props, declared or
|
|
600
709
|
* parsed from what the server printed; `defaultSchema` qualifies a bare name.
|
|
@@ -602,7 +711,7 @@ function triggerFields(p: TriggerProps, defaultSchema: string, fields: Record<st
|
|
|
602
711
|
export function canonicalPgObject(entityType: string, props: Record<string, unknown>, defaultSchema = "public"): CanonicalPgObject {
|
|
603
712
|
const kind = kindOf[entityType];
|
|
604
713
|
if (!kind) throw new Error(`not a Postgres entity type: ${entityType}`);
|
|
605
|
-
const schemaOf = (p: { schema?: string }) => (kind
|
|
714
|
+
const schemaOf = (p: { schema?: string }) => (UNPLACED.has(kind) || ACCESS_KINDS.has(kind) ? undefined : (p.schema ?? defaultSchema));
|
|
606
715
|
const base: Pick<CanonicalPgObject, "kind" | "schema" | "name" | "signature"> = { kind, schema: schemaOf(props as { schema?: string }), name: String(props.name) };
|
|
607
716
|
const fields: Record<string, unknown> = { comment: comment(props.comment as string | undefined) };
|
|
608
717
|
const columns: CanonicalColumn[] = [];
|
|
@@ -623,6 +732,48 @@ export function canonicalPgObject(entityType: string, props: Record<string, unkn
|
|
|
623
732
|
case "enum":
|
|
624
733
|
fields.labels = (props as unknown as EnumProps).labels;
|
|
625
734
|
break;
|
|
735
|
+
case "composite": {
|
|
736
|
+
const p = props as unknown as CompositeTypeProps;
|
|
737
|
+
fields.attributeDefs = p.attributes.map((a) => `${quoteIdent(a.name)} ${canonicalType(a.type, defaultSchema)}${a.collate ? ` collate ${canonicalCollation(a.collate)}` : ""}`);
|
|
738
|
+
break;
|
|
739
|
+
}
|
|
740
|
+
case "range": {
|
|
741
|
+
const p = props as unknown as RangeTypeProps;
|
|
742
|
+
fields.subtype = canonicalType(p.subtype, defaultSchema);
|
|
743
|
+
fields.subtypeOpclass = p.subtypeOpclass ? canonicalName(p.subtypeOpclass).replace(/^pg_catalog\./, "") : undefined;
|
|
744
|
+
fields.collation = p.collation ? canonicalCollation(p.collation) : undefined;
|
|
745
|
+
fields.canonical = p.canonical ? canonicalFunctionName(p.canonical, defaultSchema) : undefined;
|
|
746
|
+
fields.subtypeDiff = p.subtypeDiff ? canonicalFunctionName(p.subtypeDiff, defaultSchema) : undefined;
|
|
747
|
+
// The multirange type is always named: as written, else as Postgres derives it, in the range's schema.
|
|
748
|
+
fields.multirange = p.multirangeTypeName
|
|
749
|
+
? canonicalName(p.multirangeTypeName, base.schema)
|
|
750
|
+
: canonicalName(quoteIdent(defaultMultirangeName(base.name)), base.schema);
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
case "aggregate": {
|
|
754
|
+
const p = props as unknown as AggregateProps;
|
|
755
|
+
base.signature = aggregateSignature(p, defaultSchema);
|
|
756
|
+
fields.definition = aggregateOptions(p, defaultSchema);
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
759
|
+
case "collation":
|
|
760
|
+
collationFields(props as unknown as CollationProps, fields);
|
|
761
|
+
break;
|
|
762
|
+
case "cast": {
|
|
763
|
+
const p = props as unknown as CastProps;
|
|
764
|
+
base.name = castName(p, defaultSchema);
|
|
765
|
+
fields.castMethod = p.method;
|
|
766
|
+
fields.function = p.functionName ? canonicalFunctionName(p.functionName, defaultSchema) : undefined;
|
|
767
|
+
fields.context = p.context === "explicit" ? undefined : p.context;
|
|
768
|
+
break;
|
|
769
|
+
}
|
|
770
|
+
case "eventTrigger": {
|
|
771
|
+
const p = props as unknown as EventTriggerProps;
|
|
772
|
+
fields.event = p.event.toLowerCase();
|
|
773
|
+
fields.tags = p.tags && p.tags.length > 0 ? [...new Set(p.tags.map((t) => t.toUpperCase().replace(/\s+/g, " ").trim()))].sort() : undefined;
|
|
774
|
+
fields.function = canonicalFunctionName(p.functionName, defaultSchema);
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
626
777
|
case "function":
|
|
627
778
|
case "procedure": {
|
|
628
779
|
const p = props as unknown as RoutineProps;
|
|
@@ -357,6 +357,27 @@ export const PG_CLASSIFIER_RULES = {
|
|
|
357
357
|
"chant's parser does not know this clause, so it cannot tell which lock the change takes or whether an in-place statement makes it; the plan refuses it rather than guess. Review it: make it by hand with the ALTER the server documents for the clause, or as expand and contract.",
|
|
358
358
|
`${DOCS}/sql-altertable.html`,
|
|
359
359
|
),
|
|
360
|
+
SQLPG300: rule(
|
|
361
|
+
"SQLPG300",
|
|
362
|
+
"metadata",
|
|
363
|
+
"Drop and create a type, aggregate, collation, cast or event trigger",
|
|
364
|
+
"A composite or range type's definition, a collation's, a cast's and an event trigger's have no ALTER, and an aggregate's argument types, state type and final function cannot be replaced: the object is dropped and created in one transaction. Nothing on the server depends on it (a column, a view, a function or a cast would make the DROP fail); the locks are on its catalog rows only.",
|
|
365
|
+
`${DOCS}/sql-createtype.html`,
|
|
366
|
+
),
|
|
367
|
+
SQLPG301: rule(
|
|
368
|
+
"SQLPG301",
|
|
369
|
+
"expand",
|
|
370
|
+
"Change a type, aggregate, collation or cast that other objects depend on",
|
|
371
|
+
"No ALTER makes the change, and DROP refuses while a column, a view, a function or another object depends on the object. Create the new definition under another name, move what depends on it, then drop the old.",
|
|
372
|
+
`${DOCS}/sql-droptype.html`,
|
|
373
|
+
),
|
|
374
|
+
SQLPG302: rule(
|
|
375
|
+
"SQLPG302",
|
|
376
|
+
"metadata",
|
|
377
|
+
"Replace an aggregate's definition",
|
|
378
|
+
"CREATE OR REPLACE AGGREGATE (14 and later) replaces the aggregate's functions and options in the catalog; no table is locked. Its argument types, its result and its kind (plain, ordered-set, hypothetical-set) have to stay the same, so a change of the state type or the final function is dropped and created instead (SQLPG300).",
|
|
379
|
+
`${DOCS}/sql-createaggregate.html`,
|
|
380
|
+
),
|
|
360
381
|
SQLPG270: rule("SQLPG270", "drop", "Drop an object", "The object and, for a table, a materialized view or a sequence, its data are gone.", `${DOCS}/sql-droptable.html`),
|
|
361
382
|
} as const satisfies Record<string, PgClassifierRule>;
|
|
362
383
|
|
|
@@ -28,7 +28,7 @@ export interface PgDiffObject extends CanonicalPgObject {
|
|
|
28
28
|
foreign?: string;
|
|
29
29
|
/** The export name, against a server. */
|
|
30
30
|
exportName?: string;
|
|
31
|
-
/** What depends on a routine on the server (a view, a trigger, a
|
|
31
|
+
/** What depends on a routine, type, aggregate, collation or cast on the server (a view, a trigger, a column), which a DROP would refuse. */
|
|
32
32
|
dependents?: string[];
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -99,15 +99,17 @@ export function pgSchemaFromBuildFile(path: string, defaultSchema = "public"): P
|
|
|
99
99
|
/**
|
|
100
100
|
* The namespace an object's name is unique in: relations (tables, views,
|
|
101
101
|
* sequences, indexes) share one per schema, types and domains another,
|
|
102
|
-
* functions and
|
|
102
|
+
* functions, procedures and aggregates a third (told apart by their
|
|
103
|
+
* parameter types), collations a fourth; a cast is named by its two types,
|
|
103
104
|
* a trigger's or a policy's name is unique on its table, and a role's in the
|
|
104
105
|
* cluster.
|
|
105
106
|
*/
|
|
106
107
|
export function pgNamespace(kind: string): string {
|
|
107
108
|
if (kind === "schema" || kind === "extension" || kind === "trigger" || kind === "policy" || kind === "role") return kind;
|
|
109
|
+
if (kind === "collation" || kind === "cast" || kind === "eventTrigger") return kind;
|
|
108
110
|
if (kind === "grant" || kind === "defaultPrivileges") return "grant";
|
|
109
|
-
if (kind === "enum" || kind === "domain") return "type";
|
|
110
|
-
if (kind === "function" || kind === "procedure") return "routine";
|
|
111
|
+
if (kind === "enum" || kind === "domain" || kind === "composite" || kind === "range") return "type";
|
|
112
|
+
if (kind === "function" || kind === "procedure" || kind === "aggregate") return "routine";
|
|
111
113
|
return "relation";
|
|
112
114
|
}
|
|
113
115
|
|
|
@@ -11,6 +11,8 @@ export interface FakeCatalog {
|
|
|
11
11
|
tables?: Array<{ schema: string; name: string; comment?: string; columns?: Array<{ name: string; type: string; notnull?: boolean; dflt?: string }> }>;
|
|
12
12
|
views?: Array<{ schema: string; name: string; def: string; materialized?: boolean; comment?: string }>;
|
|
13
13
|
indexes?: Array<{ schema: string; name: string; table: string; def: string }>;
|
|
14
|
+
/** What the undeclarable-kind probes (`../live/undeclarable.ts`) find, by the coverage table's kind. Default: nothing. */
|
|
15
|
+
undeclarable?: Array<{ kind: string; schema?: string; name: string }>;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export function fakeClient(catalog: FakeCatalog, log: string[] = []): PostgresClient {
|
|
@@ -20,6 +22,9 @@ export function fakeClient(catalog: FakeCatalog, log: string[] = []): PostgresCl
|
|
|
20
22
|
async query<T>(sql: string): Promise<T[]> {
|
|
21
23
|
log.push(sql);
|
|
22
24
|
const rows = (r: unknown[]) => r as T[];
|
|
25
|
+
// A probe for one undeclarable kind (`../live/undeclarable.ts`), which its comment names.
|
|
26
|
+
const probe = /^\/\* chant undeclarable: (.+?) \*\//.exec(sql);
|
|
27
|
+
if (probe) return rows((catalog.undeclarable ?? []).filter((u) => u.kind === probe[1]).map((u) => ({ schema: u.schema ?? null, name: u.name, owner: null })));
|
|
23
28
|
if (sql.includes("FROM pg_catalog.pg_namespace n WHERE")) return rows((catalog.schemas ?? []).map((s, i) => ({ oid: String(100 + i), name: s.name, comment: s.comment ?? null })));
|
|
24
29
|
if (sql.includes("c.relkind IN ('r', 'p')")) {
|
|
25
30
|
return rows(tables.map((t) => ({ oid: t.oid, schema: t.schema, name: t.name, kind: "r", persistence: "p", ispartition: false, typed: false, partkey: null, bound: null, parents: [], reloptions: null, am: "heap", tablespace: null, comment: t.comment ?? null })));
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* kind the dialect declares, with what the catalog's printers rewrite most
|
|
4
4
|
* (type aliases, literal casts, `IN` lists, unnamed constraints, identity and
|
|
5
5
|
* sequence options, storage parameters, comments), an extension and the
|
|
6
|
-
* domain over its type, a
|
|
6
|
+
* domain over its type, a collation, composite and range types (and a
|
|
7
|
+
* multirange column), plain and ordered-set aggregates, a cast and an event
|
|
8
|
+
* trigger (#3911), a partitioned table and a partition, an ORM's
|
|
7
9
|
* revision table that import leaves out, and an object carrying chant's
|
|
8
10
|
* ownership trailer.
|
|
9
11
|
*/
|
|
@@ -42,5 +44,21 @@ CREATE VIEW app.order_totals AS
|
|
|
42
44
|
FROM app.users u LEFT JOIN app.orders o ON o.user_id = u.id
|
|
43
45
|
GROUP BY u.id, u.email;
|
|
44
46
|
CREATE MATERIALIZED VIEW app.daily AS SELECT placed_at::date AS day, count(*) AS n FROM app.orders GROUP BY 1 WITH NO DATA;
|
|
47
|
+
CREATE COLLATION app.ci (provider = icu, locale = 'und-u-ks-level2', deterministic = false);
|
|
48
|
+
COMMENT ON COLLATION app.ci IS 'Case-insensitive';
|
|
49
|
+
CREATE TYPE app.pair AS (a integer, b text COLLATE "C");
|
|
50
|
+
COMMENT ON TYPE app.pair IS 'Two values';
|
|
51
|
+
CREATE TYPE app.floatrange AS RANGE (SUBTYPE = float8, SUBTYPE_DIFF = float8mi);
|
|
52
|
+
CREATE TABLE app.people (id integer PRIMARY KEY, nick text COLLATE app.ci, span app.floatrange, tags app.floatmultirange);
|
|
53
|
+
CREATE FUNCTION app.add2(a integer, b integer) RETURNS integer LANGUAGE sql IMMUTABLE AS $$ SELECT a + b $$;
|
|
54
|
+
CREATE AGGREGATE app.total(integer) (SFUNC = app.add2, STYPE = integer, INITCOND = '0', PARALLEL = SAFE);
|
|
55
|
+
COMMENT ON AGGREGATE app.total(integer) IS 'A sum';
|
|
56
|
+
CREATE FUNCTION app.middle(v double precision[]) RETURNS double precision LANGUAGE sql IMMUTABLE AS $$ SELECT v[(array_length(v, 1) + 1) / 2] $$;
|
|
57
|
+
CREATE AGGREGATE app.median_of(ORDER BY double precision) (SFUNC = pg_catalog.array_append, STYPE = double precision[], FINALFUNC = app.middle);
|
|
58
|
+
CREATE FUNCTION app.pair_text(p app.pair) RETURNS text LANGUAGE sql IMMUTABLE AS $$ SELECT p.a || ':' || p.b $$;
|
|
59
|
+
CREATE CAST (app.pair AS text) WITH FUNCTION app.pair_text(app.pair) AS ASSIGNMENT;
|
|
60
|
+
COMMENT ON CAST (app.pair AS text) IS 'a:b';
|
|
61
|
+
CREATE FUNCTION app.audit() RETURNS event_trigger LANGUAGE plpgsql AS $$ BEGIN END $$;
|
|
62
|
+
CREATE EVENT TRIGGER app_audit ON ddl_command_end WHEN TAG IN ('CREATE TABLE') EXECUTE FUNCTION app.audit();
|
|
45
63
|
CREATE TABLE public._prisma_migrations (id varchar(36) PRIMARY KEY, checksum varchar(64) NOT NULL);
|
|
46
64
|
`;
|
package/src/postgres.ts
CHANGED
|
@@ -17,7 +17,11 @@ export {
|
|
|
17
17
|
extension,
|
|
18
18
|
func,
|
|
19
19
|
procedure,
|
|
20
|
+
aggregate,
|
|
20
21
|
trigger,
|
|
22
|
+
eventTrigger,
|
|
23
|
+
collation,
|
|
24
|
+
cast,
|
|
21
25
|
policy,
|
|
22
26
|
role,
|
|
23
27
|
grant,
|
|
@@ -37,7 +41,14 @@ export {
|
|
|
37
41
|
type PostgresIndex,
|
|
38
42
|
type PostgresSequence,
|
|
39
43
|
type PostgresEnum,
|
|
44
|
+
type PostgresCompositeType,
|
|
45
|
+
type PostgresRangeType,
|
|
46
|
+
type PostgresType,
|
|
40
47
|
type PostgresDomain,
|
|
48
|
+
type PostgresAggregate,
|
|
49
|
+
type PostgresCollation,
|
|
50
|
+
type PostgresCast,
|
|
51
|
+
type PostgresEventTrigger,
|
|
41
52
|
type PostgresExtension,
|
|
42
53
|
type PostgresFunction,
|
|
43
54
|
type PostgresProcedure,
|
|
@@ -56,6 +67,14 @@ export {
|
|
|
56
67
|
type ViewProps,
|
|
57
68
|
type SequenceProps,
|
|
58
69
|
type EnumProps,
|
|
70
|
+
type CompositeTypeProps,
|
|
71
|
+
type CompositeAttributeDef,
|
|
72
|
+
type RangeTypeProps,
|
|
73
|
+
type AggregateProps,
|
|
74
|
+
type AggregateArgDef,
|
|
75
|
+
type CollationProps,
|
|
76
|
+
type CastProps,
|
|
77
|
+
type EventTriggerProps,
|
|
59
78
|
type DomainProps,
|
|
60
79
|
type ExtensionProps,
|
|
61
80
|
type RoutineProps,
|
package/src/skill-defs.ts
CHANGED
|
@@ -54,7 +54,7 @@ export const sqlSkills = createSkillsLoader(import.meta.url, [
|
|
|
54
54
|
file: "chant-sql-postgres.md",
|
|
55
55
|
name: "chant-sql-postgres",
|
|
56
56
|
description:
|
|
57
|
-
"Declare Postgres schemas, tables, constraints, indexes, views, sequences, enum and domain types, extensions, functions, procedures, triggers, policies, roles and grants as SQL-shaped tagged templates, with references, lineage and the SQLPG lint rules",
|
|
57
|
+
"Declare Postgres schemas, tables, constraints, indexes, views, sequences, enum, composite, range and domain types, collations, casts, aggregates, event triggers, extensions, functions, procedures, triggers, policies, roles and grants as SQL-shaped tagged templates, with references, lineage and the SQLPG lint rules",
|
|
58
58
|
triggers: [
|
|
59
59
|
{ type: "context" as const, value: "postgres" },
|
|
60
60
|
{ type: "context" as const, value: "postgres schema" },
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
skill: chant-sql-postgres
|
|
3
|
-
description: Declare Postgres schemas, tables, constraints, indexes, views, sequences, enum and domain types, extensions, functions, procedures, triggers, policies, roles and grants as SQL-shaped tagged templates, with references, lineage and the SQLPG lint rules
|
|
3
|
+
description: Declare Postgres schemas, tables, constraints, indexes, views, sequences, enum, composite, range and domain types, collations, casts, aggregates, event triggers, extensions, functions, procedures, triggers, policies, roles and grants as SQL-shaped tagged templates, with references, lineage and the SQLPG lint rules
|
|
4
4
|
user-invocable: true
|
|
5
5
|
---
|
|
6
6
|
# Declaring a Postgres schema with chant
|
|
@@ -34,12 +34,16 @@ The export name (`users`) is the object's identity in chant. The name in the SQL
|
|
|
34
34
|
| `index` | `CREATE INDEX` | `Postgres::Index` |
|
|
35
35
|
| `view` | `CREATE VIEW`, `CREATE MATERIALIZED VIEW` | `Postgres::View`, `Postgres::MaterializedView` |
|
|
36
36
|
| `sequence` | `CREATE SEQUENCE` | `Postgres::Sequence` |
|
|
37
|
-
| `type` | `CREATE TYPE ... AS ENUM` | `Postgres::Enum` |
|
|
37
|
+
| `type` | `CREATE TYPE ... AS ENUM`, `AS (...)`, `AS RANGE` | `Postgres::Enum`, `Postgres::CompositeType`, `Postgres::RangeType` |
|
|
38
38
|
| `domain` | `CREATE DOMAIN` | `Postgres::Domain` |
|
|
39
39
|
| `extension` | `CREATE EXTENSION` | `Postgres::Extension` |
|
|
40
40
|
| `func` | `CREATE FUNCTION` | `Postgres::Function` |
|
|
41
41
|
| `procedure` | `CREATE PROCEDURE` | `Postgres::Procedure` |
|
|
42
|
+
| `aggregate` | `CREATE AGGREGATE` | `Postgres::Aggregate` |
|
|
42
43
|
| `trigger` | `CREATE TRIGGER` | `Postgres::Trigger` |
|
|
44
|
+
| `eventTrigger` | `CREATE EVENT TRIGGER` | `Postgres::EventTrigger` |
|
|
45
|
+
| `collation` | `CREATE COLLATION` | `Postgres::Collation` |
|
|
46
|
+
| `cast` | `CREATE CAST` | `Postgres::Cast` |
|
|
43
47
|
| `policy` | `CREATE POLICY` | `Postgres::Policy` |
|
|
44
48
|
| `role` | `CREATE ROLE` (no password, no memberships) | `Postgres::Role` |
|
|
45
49
|
| `grant` | `GRANT`, `REVOKE`, `ALTER DEFAULT PRIVILEGES` | `Postgres::Grant`, `Postgres::DefaultPrivileges` |
|
|
@@ -185,4 +189,4 @@ chant build src --lexicon sql -o dist/schema.json
|
|
|
185
189
|
|
|
186
190
|
## Not covered
|
|
187
191
|
|
|
188
|
-
`ALTER` (other than a table's row-level security), role memberships, rules,
|
|
192
|
+
`ALTER` (other than a table's row-level security), role memberships, rules, operators, extended statistics, foreign data objects, publications and subscriptions, text search objects and base types are not declared with the tags. An aggregate is identified by its argument types; a cast is named `(source AS target)` and an event trigger lives in no schema. A definition change to a composite or range type, collation, cast or event trigger is a drop and a create, refused while something depends on it. Planning a schema change (`chant sql diff`, `chant sql plan`, the lock classes) is the `chant-sql-postgres-plan` skill. Apply and the expand-and-contract migration Op have their own skills, which arrive with the code they describe.
|
package/src/skills/chant-sql.md
CHANGED
|
@@ -35,9 +35,11 @@ The export name (`events`) is the object's identity in chant. The name in the SQ
|
|
|
35
35
|
|
|
36
36
|
A dictionary is a `dictionary` template holding `CREATE DICTIONARY`, with its attributes, `PRIMARY KEY`, `SOURCE`, `LAYOUT` and `LIFETIME`. Its attributes are columns (`${ratesDict.columns.rate}`). Any change but its comment is SQLCH245, and the applier replaces it with `CREATE OR REPLACE DICTIONARY`. Keep passwords out of `SOURCE`: name a server-side named collection instead.
|
|
37
37
|
|
|
38
|
+
A table over a table function is a `table` template, `CREATE TABLE t [(cols)] AS numbers(10)`, with no engine; a change is SQLCH219 (`CREATE OR REPLACE TABLE`). `CREATE TABLE ... AS other`, `AS SELECT` and `CLONE AS`, live and window views, named collections (credentials), masking policies, workloads, resources and `CREATE INDEX` are refused with the reason.
|
|
39
|
+
|
|
38
40
|
A SQL user-defined function is a `func` template holding `CREATE FUNCTION name AS (x) -> expr`, with no database in its name. A changed expression is SQLCH260 (`CREATE OR REPLACE FUNCTION`). It carries no ownership marker, so chant never drops one.
|
|
39
41
|
|
|
40
|
-
Users, roles, row policies and grants are `user`, `role`, `policy` and `grant` templates. Never write a password: `IDENTIFIED BY` is refused, a user declared without `IDENTIFIED` is created by the environment with its password, and chant manages the rest of it. Grants are compared per grantee: every `grant` naming a grantee adds up to its complete list, and anything else it holds is revoked (SQLCH274). None of these is ever dropped by chant. They are planned and applied only where the profile sets `access: true` (`sql.profiles.<env>.access`); elsewhere each is reported `filtered`.
|
|
42
|
+
Users, roles, row policies, quotas, settings profiles and grants are `user`, `role`, `policy`, `quota`, `settingsProfile` and `grant` templates; a quota or profile is changed with `ALTER` (SQLCH275, SQLCH276), never replaced. Never write a password: `IDENTIFIED BY` is refused, a user declared without `IDENTIFIED` is created by the environment with its password, and chant manages the rest of it. Grants are compared per grantee: every `grant` naming a grantee adds up to its complete list, and anything else it holds is revoked (SQLCH274). None of these is ever dropped by chant. They are planned and applied only where the profile sets `access: true` (`sql.profiles.<env>.access`); elsewhere each is reported `filtered`.
|
|
41
43
|
|
|
42
44
|
## Interpolations
|
|
43
45
|
|
|
@@ -58,7 +58,8 @@ describe("the ClickHouse parser keeps a clause it does not know", () => {
|
|
|
58
58
|
// Unbalanced parentheses, a word that is not a key word, an unknown statement kind.
|
|
59
59
|
expect(() => ch("CREATE TABLE a.t (x UInt64) ENGINE = Log FUTURE_THING (a")).toThrow(/unbalanced parentheses|expected/);
|
|
60
60
|
expect(() => ch("CREATE TABLE a.t (x UInt64) ENGINE = Log 'stray'")).toThrow(/unexpected token/);
|
|
61
|
-
expect(() => ch("CREATE NAMED COLLECTION c AS a = 1")).toThrow(/
|
|
61
|
+
expect(() => ch("CREATE NAMED COLLECTION c AS a = 1")).toThrow(/NAMED COLLECTION is not declared/);
|
|
62
|
+
expect(() => ch("CREATE SOMETHING c")).toThrow(/expected DATABASE, TABLE/);
|
|
62
63
|
});
|
|
63
64
|
});
|
|
64
65
|
|
package/src/validate.ts
CHANGED
|
@@ -31,6 +31,8 @@ const REQUIRED_ENTITIES = [
|
|
|
31
31
|
"Role",
|
|
32
32
|
"RowPolicy",
|
|
33
33
|
"Grant",
|
|
34
|
+
"Quota",
|
|
35
|
+
"SettingsProfile",
|
|
34
36
|
"PostgresSchema",
|
|
35
37
|
"PostgresTable",
|
|
36
38
|
"PostgresIndex",
|
|
@@ -38,7 +40,13 @@ const REQUIRED_ENTITIES = [
|
|
|
38
40
|
"PostgresMaterializedView",
|
|
39
41
|
"PostgresSequence",
|
|
40
42
|
"PostgresEnum",
|
|
43
|
+
"PostgresCompositeType",
|
|
44
|
+
"PostgresRangeType",
|
|
41
45
|
"PostgresDomain",
|
|
46
|
+
"PostgresAggregate",
|
|
47
|
+
"PostgresCollation",
|
|
48
|
+
"PostgresCast",
|
|
49
|
+
"PostgresEventTrigger",
|
|
42
50
|
"PostgresExtension",
|
|
43
51
|
"PostgresFunction",
|
|
44
52
|
"PostgresProcedure",
|