@intentius/chant-lexicon-sql 0.124.19 → 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/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/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/topology.d.ts.map +1 -1
- package/dist/clickhouse.d.ts +1 -1
- package/dist/clickhouse.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/coverage/clickhouse.json +8 -8
- package/dist/coverage/postgres.json +6 -6
- package/dist/files/clickhouse.d.ts +2 -1
- package/dist/files/clickhouse.d.ts.map +1 -1
- package/dist/files/postgres.d.ts +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/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 +15 -11
- package/dist/postgres/live/catalog.d.ts.map +1 -1
- package/dist/postgres/live/describe-resources.d.ts.map +1 -1
- 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/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/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 +5 -4
- 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/topology.ts +4 -2
- package/src/clickhouse.ts +6 -0
- package/src/codegen/postgres-classifier-page.ts +1 -1
- package/src/codegen/registry.ts +8 -0
- package/src/core/undeclarable.test.ts +22 -19
- package/src/coverage/clickhouse.json +8 -8
- package/src/coverage/postgres.json +6 -6
- package/src/files/clickhouse.ts +14 -6
- package/src/files/postgres.ts +19 -5
- package/src/generated/lexicon-sql.json +40 -0
- 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 +7 -1
- 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/kinds.test.ts +140 -0
- package/src/postgres/live/catalog-kinds.ts +312 -0
- package/src/postgres/live/catalog.ts +30 -12
- 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 +15 -13
- 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/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
package/src/mcp/postgres.ts
CHANGED
|
@@ -81,7 +81,7 @@ export function postgresSearch(params: Record<string, unknown>): unknown {
|
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
const TAGS = { schema: pg.schema, table: pg.table, index: pg.index, view: pg.view, sequence: pg.sequence, type: pg.type, domain: pg.domain, extension: pg.extension, func: pg.func, procedure: pg.procedure, trigger: pg.trigger, policy: pg.policy, role: pg.role, grant: pg.grant } as const;
|
|
84
|
+
const TAGS = { schema: pg.schema, table: pg.table, index: pg.index, view: pg.view, sequence: pg.sequence, type: pg.type, domain: pg.domain, extension: pg.extension, func: pg.func, procedure: pg.procedure, aggregate: pg.aggregate, trigger: pg.trigger, eventTrigger: pg.eventTrigger, collation: pg.collation, cast: pg.cast, policy: pg.policy, role: pg.role, grant: pg.grant } as const;
|
|
85
85
|
export const POSTGRES_TAGS = Object.keys(TAGS);
|
|
86
86
|
|
|
87
87
|
/** Parse one statement with the Postgres tag; an error comes back as SQLPG001 with its line and column. */
|
package/src/plugin.ts
CHANGED
|
@@ -99,15 +99,21 @@ export const sqlPlugin: LexiconPlugin = {
|
|
|
99
99
|
},
|
|
100
100
|
{ name: "dictionary", isTag: true, description: "A ClickHouse CREATE DICTIONARY, parsed into a dictionary entity with its attributes, key, source and layout" },
|
|
101
101
|
{ name: "user", isTag: true, description: "A ClickHouse CREATE USER, parsed into a user entity; its password is the environment's" },
|
|
102
|
+
{ name: "quota", isTag: true, description: "A ClickHouse CREATE QUOTA, parsed into a quota entity with its key, its intervals' limits and whom it applies to" },
|
|
103
|
+
{ name: "settingsProfile", isTag: true, description: "A ClickHouse CREATE SETTINGS PROFILE, parsed into a settings profile entity with its settings, constraints and inherited profiles" },
|
|
102
104
|
{ name: "schema", isTag: true, description: "A Postgres CREATE SCHEMA, parsed into a schema entity" },
|
|
103
105
|
{ name: "index", isTag: true, description: "A Postgres CREATE INDEX, parsed into an index entity" },
|
|
104
106
|
{ name: "sequence", isTag: true, description: "A Postgres CREATE SEQUENCE, parsed into a sequence entity" },
|
|
105
|
-
{ name: "type", isTag: true, description: "A Postgres CREATE TYPE ... AS ENUM, parsed into an enum entity" },
|
|
107
|
+
{ name: "type", isTag: true, description: "A Postgres CREATE TYPE ... AS ENUM, AS (...) or AS RANGE, parsed into an enum, composite or range type entity" },
|
|
106
108
|
{ name: "domain", isTag: true, description: "A Postgres CREATE DOMAIN, parsed into a domain entity" },
|
|
107
109
|
{ name: "extension", isTag: true, description: "A Postgres CREATE EXTENSION, parsed into an extension entity" },
|
|
108
110
|
{ name: "func", isTag: true, description: "A Postgres CREATE FUNCTION, parsed into a function entity with its body kept verbatim, or a ClickHouse CREATE FUNCTION (a named lambda)" },
|
|
109
111
|
{ name: "procedure", isTag: true, description: "A Postgres CREATE PROCEDURE, parsed into a procedure entity with its body kept verbatim" },
|
|
112
|
+
{ name: "aggregate", isTag: true, description: "A Postgres CREATE AGGREGATE, parsed into an aggregate entity identified by its argument types" },
|
|
110
113
|
{ name: "trigger", isTag: true, description: "A Postgres CREATE TRIGGER, parsed into a trigger entity on its table" },
|
|
114
|
+
{ name: "eventTrigger", isTag: true, description: "A Postgres CREATE EVENT TRIGGER, parsed into the database's event trigger entity" },
|
|
115
|
+
{ name: "collation", isTag: true, description: "A Postgres CREATE COLLATION, parsed into a collation entity" },
|
|
116
|
+
{ name: "cast", isTag: true, description: "A Postgres CREATE CAST, parsed into a cast entity named by its two types" },
|
|
111
117
|
{ name: "policy", isTag: true, description: "A Postgres CREATE POLICY, parsed into a row-level security policy on its table, or a ClickHouse CREATE ROW POLICY" },
|
|
112
118
|
{ name: "role", isTag: true, description: "A Postgres CREATE ROLE without a password or memberships, parsed into a role entity, or a ClickHouse CREATE ROLE" },
|
|
113
119
|
{ name: "grant", isTag: true, description: "A Postgres GRANT, REVOKE or ALTER DEFAULT PRIVILEGES, parsed into the privileges it declares, or a ClickHouse GRANT of privileges or roles" },
|
|
@@ -151,7 +151,7 @@ export const refName = (o: { kind: CanonicalKind; schema?: string; name: string;
|
|
|
151
151
|
? `${o.name}${o.signature ?? ""}`
|
|
152
152
|
: o.kind === "schema" || o.kind === "extension" || o.kind === "role" || o.schema === undefined
|
|
153
153
|
? o.name
|
|
154
|
-
: `${o.schema}.${o.name}${o.kind === "function" || o.kind === "procedure" ? (o.signature ?? "") : ""}`;
|
|
154
|
+
: `${o.schema}.${o.name}${o.kind === "function" || o.kind === "procedure" || o.kind === "aggregate" ? (o.signature ?? "") : ""}`;
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
157
|
* The objects a Postgres `chant build` output declares, in creation order,
|
|
@@ -564,7 +564,13 @@ function liveCanonicalAddress(o: LivePgObject): { kind: CanonicalKind; schema?:
|
|
|
564
564
|
"Postgres::MaterializedView": "materializedView",
|
|
565
565
|
"Postgres::Sequence": "sequence",
|
|
566
566
|
"Postgres::Enum": "enum",
|
|
567
|
+
"Postgres::CompositeType": "composite",
|
|
568
|
+
"Postgres::RangeType": "range",
|
|
567
569
|
"Postgres::Domain": "domain",
|
|
570
|
+
"Postgres::Aggregate": "aggregate",
|
|
571
|
+
"Postgres::Collation": "collation",
|
|
572
|
+
"Postgres::Cast": "cast",
|
|
573
|
+
"Postgres::EventTrigger": "eventTrigger",
|
|
568
574
|
"Postgres::Extension": "extension",
|
|
569
575
|
"Postgres::Function": "function",
|
|
570
576
|
"Postgres::Procedure": "procedure",
|
|
@@ -577,7 +583,7 @@ function liveCanonicalAddress(o: LivePgObject): { kind: CanonicalKind; schema?:
|
|
|
577
583
|
)[o.type];
|
|
578
584
|
return {
|
|
579
585
|
kind,
|
|
580
|
-
...(o.schema !== undefined && kind !== "schema" && kind !== "extension" && kind !== "role" ? { schema: o.schema } : {}),
|
|
586
|
+
...(o.schema !== undefined && kind !== "schema" && kind !== "extension" && kind !== "role" && kind !== "cast" && kind !== "eventTrigger" ? { schema: o.schema } : {}),
|
|
581
587
|
name: o.name,
|
|
582
588
|
...(o.signature !== undefined ? { signature: o.signature } : {}),
|
|
583
589
|
};
|
|
@@ -100,12 +100,15 @@ export const pgString = (value: string): string => `'${value.replace(/'/g, "''")
|
|
|
100
100
|
export const pgQualified = (schema: string | undefined, name: string): string => (schema ? `${quoteIdent(schema)}.${quoteIdent(name)}` : quoteIdent(name));
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* An object's name in a statement. A schema
|
|
104
|
-
* a routine is named with its
|
|
105
|
-
*
|
|
103
|
+
* An object's name in a statement. A schema, an extension and an event
|
|
104
|
+
* trigger have no schema; a routine or an aggregate is named with its
|
|
105
|
+
* parameter types (`app.f(integer,text)`), a trigger with its table
|
|
106
|
+
* (`touch ON app.users`), a cast by its types (`(app.money AS numeric)`).
|
|
106
107
|
*/
|
|
107
108
|
export const objectIdent = (o: { kind: CanonicalKind; schema?: string; name: string; signature?: string }): string =>
|
|
108
|
-
o.kind === "
|
|
109
|
+
o.kind === "cast"
|
|
110
|
+
? o.name
|
|
111
|
+
: o.kind === "schema" || o.kind === "extension" || o.kind === "role" || o.kind === "eventTrigger"
|
|
109
112
|
? quoteIdent(o.name)
|
|
110
113
|
: o.kind === "trigger" || o.kind === "policy"
|
|
111
114
|
? `${quoteIdent(o.name)}${o.signature ?? ""}`
|
|
@@ -120,10 +123,16 @@ export const KIND_WORDS: Readonly<Record<CanonicalKind, string>> = {
|
|
|
120
123
|
materializedView: "MATERIALIZED VIEW",
|
|
121
124
|
sequence: "SEQUENCE",
|
|
122
125
|
enum: "TYPE",
|
|
126
|
+
composite: "TYPE",
|
|
127
|
+
range: "TYPE",
|
|
123
128
|
domain: "DOMAIN",
|
|
124
129
|
extension: "EXTENSION",
|
|
125
130
|
function: "FUNCTION",
|
|
126
131
|
procedure: "PROCEDURE",
|
|
132
|
+
aggregate: "AGGREGATE",
|
|
133
|
+
collation: "COLLATION",
|
|
134
|
+
cast: "CAST",
|
|
135
|
+
eventTrigger: "EVENT TRIGGER",
|
|
127
136
|
trigger: "TRIGGER",
|
|
128
137
|
policy: "POLICY",
|
|
129
138
|
role: "ROLE",
|
|
@@ -254,7 +263,12 @@ export function createSteps(
|
|
|
254
263
|
// A table's row-level security is access, which only a profile that manages access applies.
|
|
255
264
|
if (i > 0 && opts.access === false && firstNode(s)?.statement === "rowSecurity") return;
|
|
256
265
|
let sql = s.text;
|
|
257
|
-
const replaceable =
|
|
266
|
+
const replaceable =
|
|
267
|
+
obj.canonical.kind === "view" ||
|
|
268
|
+
obj.canonical.kind === "function" ||
|
|
269
|
+
obj.canonical.kind === "procedure" ||
|
|
270
|
+
obj.canonical.kind === "aggregate" ||
|
|
271
|
+
(obj.canonical.kind === "trigger" && obj.canonical.fields.constraint !== true);
|
|
258
272
|
if (i === 0 && opts.orReplace && replaceable && !/^\s*CREATE\s+OR\s+REPLACE\b/i.test(sql)) sql = sql.replace(/\bCREATE\s+/i, "CREATE OR REPLACE ");
|
|
259
273
|
const concurrently = i === 0 && obj.canonical.kind === "index" && obj.props.concurrently === true;
|
|
260
274
|
out.push({ ...step(sql, cls, opts.rule, !concurrently), ...(concurrently ? { buildsIndex: objectIdent(obj.canonical) } : {}) });
|
|
@@ -528,7 +542,7 @@ export const isRefused = (c: PgChange): boolean => c.class === "expand";
|
|
|
528
542
|
export const isDestructive = (c: PgChange): boolean => c.rule === "SQLPG204";
|
|
529
543
|
|
|
530
544
|
/** Changes that replace the object: drop it and create it again from its declaration. */
|
|
531
|
-
export const isRecreate = (c: PgChange): boolean => c.rule === "SQLPG252" || c.rule === "SQLPG243" || c.rule === "SQLPG281";
|
|
545
|
+
export const isRecreate = (c: PgChange): boolean => c.rule === "SQLPG252" || c.rule === "SQLPG243" || c.rule === "SQLPG281" || c.rule === "SQLPG300";
|
|
532
546
|
|
|
533
547
|
/**
|
|
534
548
|
* SET NOT NULL on a table that exists, without reading the table under
|
|
@@ -692,6 +706,7 @@ export function alterSteps(
|
|
|
692
706
|
break;
|
|
693
707
|
case "SQLPG250":
|
|
694
708
|
case "SQLPG280":
|
|
709
|
+
case "SQLPG302":
|
|
695
710
|
steps.push(...createSteps(obj, opts.marker, { orReplace: true, cls: c.class, rule: c.rule }).slice(0, 1));
|
|
696
711
|
break;
|
|
697
712
|
case "SQLPG291": {
|
|
@@ -872,11 +887,19 @@ const DROP_ORDER: Record<CanonicalKind, number> = {
|
|
|
872
887
|
index: 3,
|
|
873
888
|
table: 4,
|
|
874
889
|
sequence: 5,
|
|
890
|
+
// An event trigger and a cast before the function they call; an aggregate before its functions.
|
|
891
|
+
eventTrigger: 5.5,
|
|
892
|
+
cast: 5.5,
|
|
893
|
+
aggregate: 5.5,
|
|
875
894
|
// A routine after what calls it (a view, a trigger, a default), before the types its parameters use.
|
|
876
895
|
function: 6,
|
|
877
896
|
procedure: 6,
|
|
878
897
|
domain: 7,
|
|
898
|
+
composite: 7.5,
|
|
899
|
+
range: 7.5,
|
|
879
900
|
enum: 8,
|
|
901
|
+
// A collation after the types and columns that use it.
|
|
902
|
+
collation: 8.5,
|
|
880
903
|
extension: 9,
|
|
881
904
|
schema: 10,
|
|
882
905
|
// A role is the cluster's: never dropped by a prune (`../live/catalog.ts` reads only the declared ones).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, test } from "vitest";
|
|
2
2
|
import { isDeclarable } from "@intentius/chant/declarable";
|
|
3
3
|
import { getInterpolationFields } from "@intentius/chant/provenance";
|
|
4
|
-
import { domain, extension, index, isColumnRef, literal, schema, sequence, SqlTemplateError, table, type, view } from "./entities";
|
|
4
|
+
import { domain, extension, index, isColumnRef, literal, schema, sequence, SqlTemplateError, table, type, view, type EnumProps } from "./entities";
|
|
5
5
|
|
|
6
6
|
const app = schema`CREATE SCHEMA app`;
|
|
7
7
|
const orderStatus = type`CREATE TYPE ${app}.order_status AS ENUM ('placed', 'paid')`;
|
|
@@ -121,7 +121,7 @@ describe("indexes, views and the rest", () => {
|
|
|
121
121
|
const e = extension`CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA ${app} VERSION '1.6'`;
|
|
122
122
|
expect(e.props).toMatchObject({ name: "citext", schema: "app", version: "1.6", ifNotExists: true });
|
|
123
123
|
expect(e.dependsOn).toEqual([app]);
|
|
124
|
-
expect(orderStatus.props.labels).toEqual(["placed", "paid"]);
|
|
124
|
+
expect((orderStatus.props as EnumProps).labels).toEqual(["placed", "paid"]);
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
127
|
|
package/src/postgres/entities.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Postgres entities: `schema`, `table`, `index`, `view`, `sequence`,
|
|
3
|
-
* `type
|
|
4
|
-
* `
|
|
5
|
-
*
|
|
3
|
+
* `type` (enum, composite and range), `domain`, `extension`, `func`,
|
|
4
|
+
* `procedure`, `aggregate`, `trigger`, `eventTrigger`, `collation`, `cast`,
|
|
5
|
+
* `policy`, `role` and `grant` tagged templates that parse their DDL at fold
|
|
6
|
+
* time into one Declarable each (chant #3278, #3279, #3680, #3681, #3911).
|
|
6
7
|
*
|
|
7
8
|
* ```ts
|
|
8
9
|
* import { schema, table, index } from "@intentius/chant-lexicon-sql/postgres";
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
import type { AttrRef } from "@intentius/chant/attrref";
|
|
57
58
|
import { setInterpolationFields } from "@intentius/chant/provenance";
|
|
58
59
|
import { isTrivia, POSTGRES_LEXICAL, SqlSyntaxError, untokenize, type Token } from "./tokens";
|
|
59
|
-
import { identValue, parseStatements, type ColumnNode, type CommentNode, type ConstraintNode, type GrantNode, type NameNode, type RowSecurityNode, type Span, type StatementNode } from "./parser";
|
|
60
|
+
import { identValue, parseStatements, type ColumnNode, type CommentNode, type ConstraintNode, type DefElem, type GrantNode, type NameNode, type RowSecurityNode, type Span, type StatementNode } from "./parser";
|
|
60
61
|
import { keywordCategory, quoteIdent } from "./keywords";
|
|
61
62
|
import { feed, lineage, spanText as text, splice as spliceWith, templateSyntaxError, unparsedClauses, type TemplateCtx, type TemplateDialect, type UnparsedClause } from "../core/interpolation";
|
|
62
63
|
import { SqlObject, isColumnRefOf, isSqlObjectOf, makeSqlEntity } from "../core/entity";
|
|
@@ -260,6 +261,86 @@ export interface EnumProps extends CommonProps {
|
|
|
260
261
|
labels: string[];
|
|
261
262
|
}
|
|
262
263
|
|
|
264
|
+
/** A composite type's attribute, as written. */
|
|
265
|
+
export interface CompositeAttributeDef {
|
|
266
|
+
name: string;
|
|
267
|
+
type: string;
|
|
268
|
+
collate?: string;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export interface CompositeTypeProps extends CommonProps {
|
|
272
|
+
attributes: CompositeAttributeDef[];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export interface RangeTypeProps extends CommonProps {
|
|
276
|
+
/** `SUBTYPE`: the element type. */
|
|
277
|
+
subtype: string;
|
|
278
|
+
subtypeOpclass?: string;
|
|
279
|
+
collation?: string;
|
|
280
|
+
/** `CANONICAL`: the function that canonicalizes a value (a C function). */
|
|
281
|
+
canonical?: string;
|
|
282
|
+
subtypeDiff?: string;
|
|
283
|
+
/** `MULTIRANGE_TYPE_NAME`: the multirange type's name, when it is not the one Postgres derives. */
|
|
284
|
+
multirangeTypeName?: string;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** One argument of an aggregate, as written. */
|
|
288
|
+
export interface AggregateArgDef {
|
|
289
|
+
/** `in` when not written. */
|
|
290
|
+
mode: "in" | "variadic";
|
|
291
|
+
name?: string;
|
|
292
|
+
type: string;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export interface AggregateProps extends CommonProps {
|
|
296
|
+
orReplace?: boolean;
|
|
297
|
+
/** The arguments; empty for `(*)`. An ordered-set aggregate's direct arguments. */
|
|
298
|
+
args: AggregateArgDef[];
|
|
299
|
+
/** An ordered-set aggregate's aggregated arguments (`ORDER BY ...`). */
|
|
300
|
+
orderBy?: AggregateArgDef[];
|
|
301
|
+
/**
|
|
302
|
+
* The definition: each option by its name, folded (`sfunc`, `stype`,
|
|
303
|
+
* `initcond`), to its value as written; an option given without a value
|
|
304
|
+
* (`HYPOTHETICAL`, `FINALFUNC_EXTRA`) to `true`.
|
|
305
|
+
*/
|
|
306
|
+
options: Record<string, string>;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export interface CollationProps extends CommonProps {
|
|
310
|
+
ifNotExists?: boolean;
|
|
311
|
+
/** Each option by its name, folded (`provider`, `locale`, `deterministic`), to its value as written. */
|
|
312
|
+
options: Record<string, string>;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface CastProps extends Omit<CommonProps, "schema"> {
|
|
316
|
+
/** `(source AS target)`: a cast is named by its two types and lives in no schema. */
|
|
317
|
+
name: string;
|
|
318
|
+
/** The source type as written. */
|
|
319
|
+
sourceType: string;
|
|
320
|
+
/** The target type as written. */
|
|
321
|
+
targetType: string;
|
|
322
|
+
/** `WITH FUNCTION` (`function`), `WITHOUT FUNCTION` (`binary`) or `WITH INOUT` (`inout`). */
|
|
323
|
+
method: "function" | "binary" | "inout";
|
|
324
|
+
/** The cast function: the entity when interpolated, else its name. */
|
|
325
|
+
function?: PostgresObject | string;
|
|
326
|
+
/** The cast function's SQL name. */
|
|
327
|
+
functionName?: string;
|
|
328
|
+
/** The cast function's parameter types, when written. */
|
|
329
|
+
functionArgs?: string;
|
|
330
|
+
/** `explicit` (the default), `AS ASSIGNMENT` or `AS IMPLICIT`. */
|
|
331
|
+
context: "explicit" | "assignment" | "implicit";
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export interface EventTriggerProps extends Omit<CommonProps, "schema"> {
|
|
335
|
+
/** `ddl_command_start`, `ddl_command_end`, `sql_drop`, `table_rewrite` or `login`. */
|
|
336
|
+
event: string;
|
|
337
|
+
/** `WHEN TAG IN (...)`: the command tags it fires for; every one when absent. */
|
|
338
|
+
tags?: string[];
|
|
339
|
+
/** The function it executes: the entity when interpolated, else its name. */
|
|
340
|
+
function: PostgresObject | string;
|
|
341
|
+
functionName: string;
|
|
342
|
+
}
|
|
343
|
+
|
|
263
344
|
export interface DomainProps extends CommonProps {
|
|
264
345
|
/** The underlying data type. */
|
|
265
346
|
dataType: string;
|
|
@@ -488,11 +569,44 @@ export interface PostgresEnum extends PostgresObject {
|
|
|
488
569
|
readonly props: EnumProps;
|
|
489
570
|
}
|
|
490
571
|
|
|
572
|
+
export interface PostgresCompositeType extends PostgresObject {
|
|
573
|
+
readonly entityType: "Postgres::CompositeType";
|
|
574
|
+
readonly props: CompositeTypeProps;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export interface PostgresRangeType extends PostgresObject {
|
|
578
|
+
readonly entityType: "Postgres::RangeType";
|
|
579
|
+
readonly props: RangeTypeProps;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/** What the `type` tag declares: an enum, a composite or a range type. */
|
|
583
|
+
export type PostgresType = PostgresEnum | PostgresCompositeType | PostgresRangeType;
|
|
584
|
+
|
|
491
585
|
export interface PostgresDomain extends PostgresObject {
|
|
492
586
|
readonly entityType: "Postgres::Domain";
|
|
493
587
|
readonly props: DomainProps;
|
|
494
588
|
}
|
|
495
589
|
|
|
590
|
+
export interface PostgresAggregate extends PostgresObject {
|
|
591
|
+
readonly entityType: "Postgres::Aggregate";
|
|
592
|
+
readonly props: AggregateProps;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
export interface PostgresCollation extends PostgresObject {
|
|
596
|
+
readonly entityType: "Postgres::Collation";
|
|
597
|
+
readonly props: CollationProps;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
export interface PostgresCast extends PostgresObject {
|
|
601
|
+
readonly entityType: "Postgres::Cast";
|
|
602
|
+
readonly props: CastProps;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export interface PostgresEventTrigger extends PostgresObject {
|
|
606
|
+
readonly entityType: "Postgres::EventTrigger";
|
|
607
|
+
readonly props: EventTriggerProps;
|
|
608
|
+
}
|
|
609
|
+
|
|
496
610
|
export interface PostgresExtension extends PostgresObject {
|
|
497
611
|
readonly entityType: "Postgres::Extension";
|
|
498
612
|
readonly props: ExtensionProps;
|
|
@@ -637,23 +751,46 @@ export const POSTGRES_TEMPLATES: TemplateDialect = {
|
|
|
637
751
|
|
|
638
752
|
type Ctx = TemplateCtx;
|
|
639
753
|
|
|
640
|
-
export type PostgresTag =
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
754
|
+
export type PostgresTag =
|
|
755
|
+
| "schema"
|
|
756
|
+
| "table"
|
|
757
|
+
| "index"
|
|
758
|
+
| "view"
|
|
759
|
+
| "sequence"
|
|
760
|
+
| "type"
|
|
761
|
+
| "domain"
|
|
762
|
+
| "extension"
|
|
763
|
+
| "func"
|
|
764
|
+
| "procedure"
|
|
765
|
+
| "aggregate"
|
|
766
|
+
| "trigger"
|
|
767
|
+
| "eventTrigger"
|
|
768
|
+
| "collation"
|
|
769
|
+
| "cast"
|
|
770
|
+
| "policy"
|
|
771
|
+
| "role"
|
|
772
|
+
| "grant";
|
|
773
|
+
|
|
774
|
+
/** The statements each tag holds. */
|
|
775
|
+
export const STATEMENTS_OF: Record<PostgresTag, readonly StatementNode["statement"][]> = {
|
|
776
|
+
schema: ["schema"],
|
|
777
|
+
table: ["table"],
|
|
778
|
+
index: ["index"],
|
|
779
|
+
view: ["view"],
|
|
780
|
+
sequence: ["sequence"],
|
|
781
|
+
type: ["enum", "composite", "range"],
|
|
782
|
+
domain: ["domain"],
|
|
783
|
+
extension: ["extension"],
|
|
784
|
+
func: ["function"],
|
|
785
|
+
procedure: ["procedure"],
|
|
786
|
+
aggregate: ["aggregate"],
|
|
787
|
+
trigger: ["trigger"],
|
|
788
|
+
eventTrigger: ["eventTrigger"],
|
|
789
|
+
collation: ["collation"],
|
|
790
|
+
cast: ["cast"],
|
|
791
|
+
policy: ["policy"],
|
|
792
|
+
role: ["role"],
|
|
793
|
+
grant: ["grant"],
|
|
657
794
|
};
|
|
658
795
|
|
|
659
796
|
const TAG_OF: Record<StatementNode["statement"], PostgresTag | undefined> = {
|
|
@@ -663,11 +800,17 @@ const TAG_OF: Record<StatementNode["statement"], PostgresTag | undefined> = {
|
|
|
663
800
|
view: "view",
|
|
664
801
|
sequence: "sequence",
|
|
665
802
|
enum: "type",
|
|
803
|
+
composite: "type",
|
|
804
|
+
range: "type",
|
|
666
805
|
domain: "domain",
|
|
667
806
|
extension: "extension",
|
|
668
807
|
function: "func",
|
|
669
808
|
procedure: "procedure",
|
|
809
|
+
aggregate: "aggregate",
|
|
670
810
|
trigger: "trigger",
|
|
811
|
+
eventTrigger: "eventTrigger",
|
|
812
|
+
collation: "collation",
|
|
813
|
+
cast: "cast",
|
|
671
814
|
policy: "policy",
|
|
672
815
|
role: "role",
|
|
673
816
|
grant: "grant",
|
|
@@ -683,11 +826,17 @@ export const STATEMENT_NAMES: Record<StatementNode["statement"], string> = {
|
|
|
683
826
|
view: "CREATE VIEW",
|
|
684
827
|
sequence: "CREATE SEQUENCE",
|
|
685
828
|
enum: "CREATE TYPE",
|
|
829
|
+
composite: "CREATE TYPE",
|
|
830
|
+
range: "CREATE TYPE",
|
|
686
831
|
domain: "CREATE DOMAIN",
|
|
687
832
|
extension: "CREATE EXTENSION",
|
|
688
833
|
function: "CREATE FUNCTION",
|
|
689
834
|
procedure: "CREATE PROCEDURE",
|
|
835
|
+
aggregate: "CREATE AGGREGATE",
|
|
690
836
|
trigger: "CREATE TRIGGER",
|
|
837
|
+
eventTrigger: "CREATE EVENT TRIGGER",
|
|
838
|
+
collation: "CREATE COLLATION",
|
|
839
|
+
cast: "CREATE CAST",
|
|
691
840
|
policy: "CREATE POLICY",
|
|
692
841
|
role: "CREATE ROLE",
|
|
693
842
|
grant: "GRANT",
|
|
@@ -715,6 +864,13 @@ export function stringValue(s: string | undefined): string | undefined {
|
|
|
715
864
|
return s;
|
|
716
865
|
}
|
|
717
866
|
|
|
867
|
+
/** A definition list's values, by option name: each value as written, interpolations rendered; an option with no value is `true`. */
|
|
868
|
+
function definitionValues(ctx: Ctx, elems: readonly DefElem[], path: string): Record<string, string> {
|
|
869
|
+
const out: Record<string, string> = {};
|
|
870
|
+
for (const e of elems) out[e.name] = e.value ? req(text(ctx, e.value, path)) : "true";
|
|
871
|
+
return out;
|
|
872
|
+
}
|
|
873
|
+
|
|
718
874
|
/** A qualified name's schema and name. An interpolated schema names the schema; an interpolated object gives both. */
|
|
719
875
|
function qualified(ctx: Ctx, n: NameNode): { schema?: string; name: string } {
|
|
720
876
|
const pieces: string[] = [];
|
|
@@ -926,7 +1082,12 @@ function applyComments(
|
|
|
926
1082
|
if (value !== undefined) constraint!.comment = value;
|
|
927
1083
|
} else {
|
|
928
1084
|
if (!objectTypes.includes(c.objectType)) refuse(c, `does not comment on the ${tag} this template declares`);
|
|
929
|
-
if (c.objectType === "
|
|
1085
|
+
if (c.objectType === "CAST") {
|
|
1086
|
+
// `COMMENT ON CAST (source AS target)`: the two types, as the CREATE CAST writes them.
|
|
1087
|
+
const loose = (x: string) => x.toLowerCase().replace(/\s+/g, " ").replace(/\s*([(),.])\s*/g, "$1");
|
|
1088
|
+
const named = `(${req(text(ctx, c.cast!.source))} AS ${req(text(ctx, c.cast!.target))})`;
|
|
1089
|
+
if (loose(named) !== loose(self.name)) refuse(c, `names another cast than ${self.name}`);
|
|
1090
|
+
} else if (c.objectType === "TRIGGER" || c.objectType === "POLICY") {
|
|
930
1091
|
// `COMMENT ON TRIGGER name ON table`: the name is the trigger's, the table its own.
|
|
931
1092
|
if (qualified(ctx, c.target).name !== self.name || !c.on || !isSelf({ ...qualified(ctx, c.on), name: self.name })) refuse(c, `names another ${c.objectType.toLowerCase()} than ${self.name}`);
|
|
932
1093
|
} else if (!isSelf(qualified(ctx, c.target))) refuse(c, `names another object than ${sqlNameOf(self)}`);
|
|
@@ -1152,7 +1313,7 @@ function build(tag: PostgresTag, strings: TemplateStringsArray | readonly string
|
|
|
1152
1313
|
throw templateSyntaxError(tag, parts, err);
|
|
1153
1314
|
}
|
|
1154
1315
|
const [node, ...rest] = nodes as [StatementNode, ...StatementNode[]];
|
|
1155
|
-
if (node.statement
|
|
1316
|
+
if (!STATEMENTS_OF[tag].includes(node.statement)) {
|
|
1156
1317
|
const holds = STATEMENT_NAMES[node.statement];
|
|
1157
1318
|
const use = TAG_OF[node.statement];
|
|
1158
1319
|
throw new SqlTemplateError(
|
|
@@ -1194,9 +1355,9 @@ function build(tag: PostgresTag, strings: TemplateStringsArray | readonly string
|
|
|
1194
1355
|
const dependsOn = [...new Set([...values, ...(joined?.refs ?? [])].filter((v) => isPostgresObject(v) || isColumnRef(v)))];
|
|
1195
1356
|
const slots: TypedSlot[] = [];
|
|
1196
1357
|
const unparsed = unparsedClauses(ctx, nodes.flatMap((n) => ("unknown" in n && n.unknown ? n.unknown : [])));
|
|
1197
|
-
const make = <T extends PostgresObject>(type: PostgresEntityType, q: { schema?: string; name: string }, props: object, columnNames?: readonly string[]): T => {
|
|
1358
|
+
const make = <T extends PostgresObject>(type: PostgresEntityType, q: { schema?: string; name: string }, props: object, columnNames?: readonly string[], sqlName = sqlNameOf(q)): T => {
|
|
1198
1359
|
if (unparsed) (props as { unparsed?: UnparsedClause[] }).unparsed = unparsed;
|
|
1199
|
-
const entity = makeSqlEntity(PostgresObject.prototype as PostgresObject, type,
|
|
1360
|
+
const entity = makeSqlEntity(PostgresObject.prototype as PostgresObject, type, sqlName, props, columnNames, dependsOn) as T;
|
|
1200
1361
|
const fed = ctx.fed.map((paths) => [...paths].sort());
|
|
1201
1362
|
if (!joined) setInterpolationFields(entity, fed);
|
|
1202
1363
|
else {
|
|
@@ -1239,6 +1400,99 @@ function build(tag: PostgresTag, strings: TemplateStringsArray | readonly string
|
|
|
1239
1400
|
const props: EnumProps = stripUnset({ ...q, labels: node.labels.map((l) => req(stringValue(text(ctx, l, "labels")))), comment, ddl, source });
|
|
1240
1401
|
return make(POSTGRES_ENTITY_TYPES.enum, q, props);
|
|
1241
1402
|
}
|
|
1403
|
+
case "composite": {
|
|
1404
|
+
const q = qualified(ctx, node.name);
|
|
1405
|
+
const comment = applyComments(tag, ctx, comments, q, ["TYPE"]);
|
|
1406
|
+
const attributes = node.attributes.map((a) => {
|
|
1407
|
+
feed(ctx, a.nameSpan, "attributes");
|
|
1408
|
+
return stripUnset({ name: columnName(ctx, { name: a.name, span: a.nameSpan }), type: req(text(ctx, a.type, "attributes")), collate: text(ctx, a.collate, "attributes") }) as CompositeAttributeDef;
|
|
1409
|
+
});
|
|
1410
|
+
const props: CompositeTypeProps = strip({ ...q, attributes, comment, ddl, source }, ["attributes"]);
|
|
1411
|
+
return make(POSTGRES_ENTITY_TYPES.composite, q, props);
|
|
1412
|
+
}
|
|
1413
|
+
case "range": {
|
|
1414
|
+
const q = qualified(ctx, node.name);
|
|
1415
|
+
const comment = applyComments(tag, ctx, comments, q, ["TYPE"]);
|
|
1416
|
+
const opt = definitionValues(ctx, node.options, "options");
|
|
1417
|
+
const props: RangeTypeProps = stripUnset({
|
|
1418
|
+
...q,
|
|
1419
|
+
subtype: req(opt.subtype),
|
|
1420
|
+
subtypeOpclass: opt.subtype_opclass,
|
|
1421
|
+
collation: opt.collation,
|
|
1422
|
+
canonical: opt.canonical,
|
|
1423
|
+
subtypeDiff: opt.subtype_diff,
|
|
1424
|
+
multirangeTypeName: opt.multirange_type_name,
|
|
1425
|
+
comment,
|
|
1426
|
+
ddl,
|
|
1427
|
+
source,
|
|
1428
|
+
});
|
|
1429
|
+
return make(POSTGRES_ENTITY_TYPES.range, q, props);
|
|
1430
|
+
}
|
|
1431
|
+
case "aggregate": {
|
|
1432
|
+
const q = qualified(ctx, node.name);
|
|
1433
|
+
const comment = applyComments(tag, ctx, comments, q, ["AGGREGATE"]);
|
|
1434
|
+
const arg = (a: (typeof node.args)[number]): AggregateArgDef => stripUnset({ mode: (a.mode?.toLowerCase() ?? "in") as AggregateArgDef["mode"], name: a.name, type: req(text(ctx, a.type, "args")) });
|
|
1435
|
+
const props: AggregateProps = strip(
|
|
1436
|
+
{
|
|
1437
|
+
...q,
|
|
1438
|
+
orReplace: node.orReplace || undefined,
|
|
1439
|
+
args: node.args.map(arg),
|
|
1440
|
+
orderBy: node.orderBy?.map(arg),
|
|
1441
|
+
options: definitionValues(ctx, node.options, "options"),
|
|
1442
|
+
comment,
|
|
1443
|
+
ddl,
|
|
1444
|
+
source,
|
|
1445
|
+
},
|
|
1446
|
+
["args"],
|
|
1447
|
+
);
|
|
1448
|
+
return make(POSTGRES_ENTITY_TYPES.aggregate, q, props);
|
|
1449
|
+
}
|
|
1450
|
+
case "collation": {
|
|
1451
|
+
const q = qualified(ctx, node.name);
|
|
1452
|
+
const comment = applyComments(tag, ctx, comments, q, ["COLLATION"]);
|
|
1453
|
+
const props: CollationProps = stripUnset({ ...q, ifNotExists: node.ifNotExists || undefined, options: definitionValues(ctx, node.options, "options"), comment, ddl, source });
|
|
1454
|
+
return make(POSTGRES_ENTITY_TYPES.collation, q, props);
|
|
1455
|
+
}
|
|
1456
|
+
case "cast": {
|
|
1457
|
+
const sourceType = req(text(ctx, node.source, "sourceType"));
|
|
1458
|
+
const targetType = req(text(ctx, node.target, "targetType"));
|
|
1459
|
+
const name = `(${sourceType} AS ${targetType})`;
|
|
1460
|
+
const comment = applyComments(tag, ctx, comments, { name }, ["CAST"]);
|
|
1461
|
+
const props: CastProps = stripUnset({
|
|
1462
|
+
name,
|
|
1463
|
+
sourceType,
|
|
1464
|
+
targetType,
|
|
1465
|
+
method: node.method,
|
|
1466
|
+
function: node.function ? target(ctx, node.function) : undefined,
|
|
1467
|
+
functionName: node.function ? targetName(ctx, node.function) : undefined,
|
|
1468
|
+
functionArgs: node.functionArgs ? text(ctx, node.functionArgs, "functionArgs") : undefined,
|
|
1469
|
+
context: node.context,
|
|
1470
|
+
comment,
|
|
1471
|
+
ddl,
|
|
1472
|
+
source,
|
|
1473
|
+
});
|
|
1474
|
+
return make(POSTGRES_ENTITY_TYPES.cast, { name }, props, undefined, name);
|
|
1475
|
+
}
|
|
1476
|
+
case "eventTrigger": {
|
|
1477
|
+
const name = node.name.pieces[0] || identValue(req(text(ctx, node.name.span)));
|
|
1478
|
+
feed(ctx, node.name.span, "name");
|
|
1479
|
+
const comment = applyComments(tag, ctx, comments, { name }, ["EVENT TRIGGER"]);
|
|
1480
|
+
const tags = node.filters.flatMap((f) => f.values.map((v) => req(stringValue(text(ctx, v, "tags")))));
|
|
1481
|
+
const props: EventTriggerProps = strip(
|
|
1482
|
+
{
|
|
1483
|
+
name,
|
|
1484
|
+
event: node.event.name || identValue(req(text(ctx, node.event.span, "event"))),
|
|
1485
|
+
tags: tags.length > 0 ? tags : undefined,
|
|
1486
|
+
function: target(ctx, node.function),
|
|
1487
|
+
functionName: targetName(ctx, node.function),
|
|
1488
|
+
comment,
|
|
1489
|
+
ddl,
|
|
1490
|
+
source,
|
|
1491
|
+
},
|
|
1492
|
+
[],
|
|
1493
|
+
);
|
|
1494
|
+
return make(POSTGRES_ENTITY_TYPES.eventTrigger, { name }, props);
|
|
1495
|
+
}
|
|
1242
1496
|
case "domain": {
|
|
1243
1497
|
const q = qualified(ctx, node.name);
|
|
1244
1498
|
const checks = node.checks.map((c) => stripUnset({ name: c.name, expr: req(text(ctx, c.expr, "checks")), notValid: c.notValid }) as CheckDef);
|
|
@@ -1644,9 +1898,13 @@ export function sequence(strings: TemplateStringsArray, ...values: unknown[]): P
|
|
|
1644
1898
|
return build("sequence", strings, values) as PostgresSequence;
|
|
1645
1899
|
}
|
|
1646
1900
|
|
|
1647
|
-
/**
|
|
1648
|
-
|
|
1649
|
-
|
|
1901
|
+
/**
|
|
1902
|
+
* `` type`CREATE TYPE name AS ENUM (...)` ``: one enum type; `AS (attribute
|
|
1903
|
+
* type, ...)` a composite type, `AS RANGE (SUBTYPE = ...)` a range type (and
|
|
1904
|
+
* its multirange type, which Postgres creates with it).
|
|
1905
|
+
*/
|
|
1906
|
+
export function type(strings: TemplateStringsArray, ...values: unknown[]): PostgresType {
|
|
1907
|
+
return build("type", strings, values) as PostgresType;
|
|
1650
1908
|
}
|
|
1651
1909
|
|
|
1652
1910
|
/** `` domain`CREATE DOMAIN ...` ``: one domain. */
|
|
@@ -1673,6 +1931,36 @@ export function procedure(strings: TemplateStringsArray, ...values: unknown[]):
|
|
|
1673
1931
|
return build("procedure", strings, values) as PostgresProcedure;
|
|
1674
1932
|
}
|
|
1675
1933
|
|
|
1934
|
+
/**
|
|
1935
|
+
* `` aggregate`CREATE [OR REPLACE] AGGREGATE name(argtype, ...) (SFUNC = ..., STYPE = ...)` ``:
|
|
1936
|
+
* one aggregate, identified, as a function is, by its argument types.
|
|
1937
|
+
*/
|
|
1938
|
+
export function aggregate(strings: TemplateStringsArray, ...values: unknown[]): PostgresAggregate {
|
|
1939
|
+
return build("aggregate", strings, values) as PostgresAggregate;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
/** `` collation`CREATE COLLATION name (provider = icu, locale = '...')` ``: one collation. */
|
|
1943
|
+
export function collation(strings: TemplateStringsArray, ...values: unknown[]): PostgresCollation {
|
|
1944
|
+
return build("collation", strings, values) as PostgresCollation;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
/**
|
|
1948
|
+
* `` cast`CREATE CAST (source AS target) WITH FUNCTION ${fn}(source) [AS ASSIGNMENT | AS IMPLICIT]` ``:
|
|
1949
|
+
* one cast, named by its two types. Creating one takes owning the source or
|
|
1950
|
+
* the target type.
|
|
1951
|
+
*/
|
|
1952
|
+
export function cast(strings: TemplateStringsArray, ...values: unknown[]): PostgresCast {
|
|
1953
|
+
return build("cast", strings, values) as PostgresCast;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
/**
|
|
1957
|
+
* `` eventTrigger`CREATE EVENT TRIGGER name ON ddl_command_end WHEN TAG IN ('CREATE TABLE') EXECUTE FUNCTION ${fn}()` ``:
|
|
1958
|
+
* one event trigger, the database's (no schema). Creating one takes a superuser.
|
|
1959
|
+
*/
|
|
1960
|
+
export function eventTrigger(strings: TemplateStringsArray, ...values: unknown[]): PostgresEventTrigger {
|
|
1961
|
+
return build("eventTrigger", strings, values) as PostgresEventTrigger;
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1676
1964
|
/** `` trigger`CREATE [OR REPLACE] [CONSTRAINT] TRIGGER name ... ON ${table} ... EXECUTE FUNCTION ${fn}()` ``: one trigger on its table. */
|
|
1677
1965
|
export function trigger(strings: TemplateStringsArray, ...values: unknown[]): PostgresTrigger {
|
|
1678
1966
|
return build("trigger", strings, values) as PostgresTrigger;
|
|
@@ -11,7 +11,13 @@ export const POSTGRES_ENTITY_TYPES = {
|
|
|
11
11
|
materializedView: "Postgres::MaterializedView",
|
|
12
12
|
sequence: "Postgres::Sequence",
|
|
13
13
|
enum: "Postgres::Enum",
|
|
14
|
+
composite: "Postgres::CompositeType",
|
|
15
|
+
range: "Postgres::RangeType",
|
|
14
16
|
domain: "Postgres::Domain",
|
|
17
|
+
aggregate: "Postgres::Aggregate",
|
|
18
|
+
collation: "Postgres::Collation",
|
|
19
|
+
cast: "Postgres::Cast",
|
|
20
|
+
eventTrigger: "Postgres::EventTrigger",
|
|
15
21
|
extension: "Postgres::Extension",
|
|
16
22
|
function: "Postgres::Function",
|
|
17
23
|
procedure: "Postgres::Procedure",
|