From 56a69b42a7fc5fa63a22119e70a2f9aa50bbce70 Mon Sep 17 00:00:00 2001 From: Rene Saarsoo Date: Sun, 11 Feb 2024 20:17:14 +0200 Subject: [PATCH] BREAKING! Replace CreateTriggerStmt.eachKw and .when fields with .clauses --- src/cst/CreateTable.ts | 5 +++-- src/cst/Trigger.ts | 15 ++++++++++++--- src/parser.pegjs | 31 +++++++++++++++++++++++++------ src/showNode/trigger.ts | 6 +++--- test/ddl/trigger.test.ts | 5 +++++ 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/cst/CreateTable.ts b/src/cst/CreateTable.ts index 5247b92d..6c0efef1 100644 --- a/src/cst/CreateTable.ts +++ b/src/cst/CreateTable.ts @@ -83,7 +83,7 @@ export interface CreateTableStmt extends BaseNode { export interface RelationKind extends BaseNode { type: "relation_kind"; kindKw: - | Keyword<"TEMP" | "TEMPORARY"> // for TABLE, VIEW, SEQUENCE + | Keyword<"TEMP" | "TEMPORARY"> // for TABLE, VIEW, SEQUENCE, TRIGGER // PostgreSQL deprecated syntax which has the same effect as just TEMPORARY | [Keyword<"GLOBAL" | "LOCAL">, Keyword<"TEMPORARY" | "TEMP">] | Keyword<"UNLOGGED"> // PostgreSQL (TABLE, SEQUENCE) @@ -92,7 +92,8 @@ export interface RelationKind extends BaseNode { | Keyword<"SNAPSHOT"> // BigQuery | Keyword<"VIRTUAL"> // SQLite | Keyword<"MATERIALIZED"> // PostgreSQL (VIEW) - | Keyword<"RECURSIVE">; // PostgreSQL (VIEW) + | Keyword<"RECURSIVE"> // PostgreSQL (VIEW) + | Keyword<"CONSTRAINT">; // PostgreSQL (TRIGGER) } export interface ColumnDefinition extends BaseNode { diff --git a/src/cst/Trigger.ts b/src/cst/Trigger.ts index c64da3f8..956f250f 100644 --- a/src/cst/Trigger.ts +++ b/src/cst/Trigger.ts @@ -1,10 +1,12 @@ import { BaseNode, Keyword } from "./Base"; +import { RelationKind } from "./CreateTable"; import { Expr, Identifier, ListExpr, EntityName, ParenExpr } from "./Expr"; import { BlockStmt } from "./ProceduralLanguage"; export type AllTriggerNodes = | AllTriggerStatements | TriggerEvent + | ForEachClause | TriggerCondition | ExecuteClause; @@ -15,13 +17,12 @@ export interface CreateTriggerStmt extends BaseNode { type: "create_trigger_stmt"; createKw: Keyword<"CREATE">; orReplaceKw?: [Keyword<"OR">, Keyword<"REPLACE">]; - temporaryKw?: Keyword<"TEMP" | "TEMPORARY">; + kind?: RelationKind; triggerKw: Keyword<"TRIGGER">; ifNotExistsKw?: [Keyword<"IF">, Keyword<"NOT">, Keyword<"EXISTS">]; name: EntityName; event: TriggerEvent; - forEachRowKw?: [Keyword<"FOR">, Keyword<"EACH">, Keyword<"ROW">]; - condition?: TriggerCondition; + clauses: TriggerClause[]; body: BlockStmt | ExecuteClause; } @@ -35,6 +36,14 @@ export interface TriggerEvent extends BaseNode { table: EntityName; } +type TriggerClause = ForEachClause | TriggerCondition; + +export interface ForEachClause extends BaseNode { + type: "for_each_clause"; + forEachKw: [Keyword<"FOR">, Keyword<"EACH">]; + itemKw: Keyword<"ROW">; +} + export interface TriggerCondition extends BaseNode { type: "trigger_condition"; whenKw?: Keyword<"WHEN">; diff --git a/src/parser.pegjs b/src/parser.pegjs index b4dd6221..edf35ab7 100644 --- a/src/parser.pegjs +++ b/src/parser.pegjs @@ -3278,30 +3278,36 @@ rename_action create_trigger_stmt = kw:(CREATE __) orReplaceKw:(OR __ REPLACE __)? - tmpKw:((TEMPORARY / TEMP) __)? + kind:(trigger_kind __)? trigKw:(TRIGGER __) ifKw:(if_not_exists __)? name:(entity_name __) event:(trigger_event __) - eachKw:(FOR __ EACH __ ROW __)? - when:(trigger_condition __)? + clauses:(trigger_clause __)* body:trigger_body { return loc({ type: "create_trigger_stmt", createKw: read(kw), orReplaceKw: read(orReplaceKw), - temporaryKw: read(tmpKw), + kind: read(kind), triggerKw: read(trigKw), ifNotExistsKw: read(ifKw), name: read(name), event: read(event), - forEachRowKw: read(eachKw), - condition: read(when), + clauses: clauses.map(read), body, }); } +trigger_kind + = &sqlite kw:(TEMPORARY / TEMP) { + return loc({ type: "relation_kind", kindKw: kw }); + } + / &postgres kw:CONSTRAINT { + return loc({ type: "relation_kind", kindKw: kw }); + } + trigger_event = timeKw:(trigger_time_kw __)? eventKw:(UPDATE __) ofKw:(OF __) cols:(list$column __) onKw:(ON __) table:entity_name { return loc({ @@ -3326,6 +3332,19 @@ trigger_event trigger_time_kw = kw:(BEFORE / AFTER / INSTEAD __ OF) { return read(kw); } +trigger_clause + = for_each_clause + / trigger_condition + +for_each_clause + = kw:(FOR __ EACH __) itemKw:(ROW) { + return loc({ + type: "for_each_clause", + forEachKw: read(kw), + itemKw: read(itemKw), + }); + } + trigger_condition = kw:(WHEN __) e:expr { return loc({ diff --git a/src/showNode/trigger.ts b/src/showNode/trigger.ts index 8f84c7b9..a2c35b0b 100644 --- a/src/showNode/trigger.ts +++ b/src/showNode/trigger.ts @@ -7,13 +7,12 @@ export const triggerMap: FullTransformMap = { show([ node.createKw, node.orReplaceKw, - node.temporaryKw, + node.kind, node.triggerKw, node.ifNotExistsKw, node.name, node.event, - node.forEachRowKw, - node.condition, + node.clauses, node.body, ]), trigger_event: (node) => @@ -25,6 +24,7 @@ export const triggerMap: FullTransformMap = { node.onKw, node.table, ]), + for_each_clause: (node) => show([node.forEachKw, node.itemKw]), trigger_condition: (node) => show([node.whenKw, node.expr]), execute_clause: (node) => show([node.executeKw, node.functionKw, node.name, node.args]), diff --git a/test/ddl/trigger.test.ts b/test/ddl/trigger.test.ts index fd9b5dca..e957e3b7 100644 --- a/test/ddl/trigger.test.ts +++ b/test/ddl/trigger.test.ts @@ -21,6 +21,7 @@ describe("trigger", () => { dialect("sqlite", () => { it("supports TEMPORARY trigger", () => { testWc("CREATE TEMPORARY TRIGGER my_trig DELETE ON my_tbl BEGIN SELECT 1; END"); + testWc("CREATE TEMP TRIGGER my_trig DELETE ON my_tbl BEGIN SELECT 1; END"); }); }); @@ -98,6 +99,10 @@ describe("trigger", () => { it("supports TRUNCATE", () => { testWc(`CREATE TRIGGER my_trig AFTER TRUNCATE ON my_tbl ${body}`); }); + + it("supports CONSTRAINT TRIGGER", () => { + testWc(`CREATE CONSTRAINT TRIGGER my_trig AFTER INSERT ON my_tbl ${body}`); + }); }); });