From df55e42b58b96468e2ff375256ef3a06552f300c Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sun, 17 May 2026 13:15:35 -0400 Subject: [PATCH] parser: validation for func option list, rule statement semicolons also - document symbol for create rule - fix grammar for rule stmt list --- crates/squawk_ide/src/document_symbols.rs | 54 ++++++ .../src/handlers/document_symbol.rs | 1 + crates/squawk_syntax/src/postgresql.ungram | 2 +- ...__test__begin_atomic_stmts_validation.snap | 168 ++++++++++++++++++ ...yntax__test__rule_stmts_ok_validation.snap | 154 ++++++++++++++++ ...k_syntax__test__rule_stmts_validation.snap | 84 +++++++++ crates/squawk_syntax/src/validation.rs | 42 +++++ .../validation/begin_atomic_stmts.sql | 15 ++ .../test_data/validation/rule_stmts.sql | 4 + .../test_data/validation/rule_stmts_ok.sql | 9 + crates/squawk_wasm/src/lib.rs | 1 + 11 files changed, 533 insertions(+), 1 deletion(-) create mode 100644 crates/squawk_syntax/src/snapshots/squawk_syntax__test__begin_atomic_stmts_validation.snap create mode 100644 crates/squawk_syntax/src/snapshots/squawk_syntax__test__rule_stmts_ok_validation.snap create mode 100644 crates/squawk_syntax/src/snapshots/squawk_syntax__test__rule_stmts_validation.snap create mode 100644 crates/squawk_syntax/test_data/validation/begin_atomic_stmts.sql create mode 100644 crates/squawk_syntax/test_data/validation/rule_stmts.sql create mode 100644 crates/squawk_syntax/test_data/validation/rule_stmts_ok.sql diff --git a/crates/squawk_ide/src/document_symbols.rs b/crates/squawk_ide/src/document_symbols.rs index 659ad73a..9ae4c08e 100644 --- a/crates/squawk_ide/src/document_symbols.rs +++ b/crates/squawk_ide/src/document_symbols.rs @@ -21,6 +21,7 @@ pub enum DocumentSymbolKind { Procedure, EventTrigger, Role, + Rule, Policy, PropertyGraph, Type, @@ -153,6 +154,11 @@ pub fn document_symbols(db: &dyn Db, file: File) -> Vec { symbols.push(symbol); } } + ast::Stmt::CreateRule(create_rule) => { + if let Some(symbol) = create_rule_symbol(create_rule) { + symbols.push(symbol); + } + } ast::Stmt::CreatePolicy(create_policy) => { if let Some(symbol) = create_policy_symbol(create_policy) { symbols.push(symbol); @@ -675,6 +681,23 @@ fn create_role_symbol(create_role: ast::CreateRole) -> Option { }) } +fn create_rule_symbol(create_rule: ast::CreateRule) -> Option { + let name_node = create_rule.name()?; + let name = name_node.syntax().text().to_string(); + + let full_range = create_rule.syntax().text_range(); + let focus_range = name_node.syntax().text_range(); + + Some(DocumentSymbol { + name, + detail: None, + kind: DocumentSymbolKind::Rule, + full_range, + focus_range, + children: vec![], + }) +} + fn create_policy_symbol(create_policy: ast::CreatePolicy) -> Option { let name_node = create_policy.name()?; let name = name_node.syntax().text().to_string(); @@ -924,6 +947,7 @@ mod tests { DocumentSymbolKind::Procedure => "procedure", DocumentSymbolKind::EventTrigger => "event trigger", DocumentSymbolKind::Role => "role", + DocumentSymbolKind::Rule => "rule", DocumentSymbolKind::Policy => "policy", DocumentSymbolKind::PropertyGraph => "property graph", DocumentSymbolKind::Type => "type", @@ -1337,6 +1361,36 @@ create role reader; "); } + #[test] + fn create_rule() { + assert_snapshot!(symbols(" +create rule r as on select to t do nothing; +"), @" + info: rule: r + ╭▸ + 2 │ create rule r as on select to t do nothing; + │ ┬───────────┯────────────────────────────── + │ │ │ + │ │ focus range + ╰╴full range + "); + } + + #[test] + fn create_rule_or_replace() { + assert_snapshot!(symbols(" +create or replace rule notify_me as on update to mytable do also notify mytable; +"), @" + info: rule: notify_me + ╭▸ + 2 │ create or replace rule notify_me as on update to mytable do also notify mytable; + │ ┬──────────────────────┯━━━━━━━━──────────────────────────────────────────────── + │ │ │ + │ │ focus range + ╰╴full range + "); + } + #[test] fn create_policy() { assert_snapshot!(symbols(" diff --git a/crates/squawk_server/src/handlers/document_symbol.rs b/crates/squawk_server/src/handlers/document_symbol.rs index a74050e0..b92f55bc 100644 --- a/crates/squawk_server/src/handlers/document_symbol.rs +++ b/crates/squawk_server/src/handlers/document_symbol.rs @@ -62,6 +62,7 @@ pub(crate) fn handle_document_symbol( DocumentSymbolKind::Channel => SymbolKind::EVENT, DocumentSymbolKind::EventTrigger => SymbolKind::EVENT, DocumentSymbolKind::Role => SymbolKind::CLASS, + DocumentSymbolKind::Rule => SymbolKind::EVENT, DocumentSymbolKind::Policy => SymbolKind::VARIABLE, DocumentSymbolKind::PropertyGraph => SymbolKind::STRUCT, }, diff --git a/crates/squawk_syntax/src/postgresql.ungram b/crates/squawk_syntax/src/postgresql.ungram index 8cf6741b..0cf2f0cb 100644 --- a/crates/squawk_syntax/src/postgresql.ungram +++ b/crates/squawk_syntax/src/postgresql.ungram @@ -2639,7 +2639,7 @@ RuleAction = | RuleStmt RuleStmtList = - '(' (RuleStmt (',' RuleStmt)*) ')' + '(' (RuleStmt (';' RuleStmt)*) ')' RuleStmt = SelectVariant diff --git a/crates/squawk_syntax/src/snapshots/squawk_syntax__test__begin_atomic_stmts_validation.snap b/crates/squawk_syntax/src/snapshots/squawk_syntax__test__begin_atomic_stmts_validation.snap new file mode 100644 index 00000000..a3b72a1b --- /dev/null +++ b/crates/squawk_syntax/src/snapshots/squawk_syntax__test__begin_atomic_stmts_validation.snap @@ -0,0 +1,168 @@ +--- +source: crates/squawk_syntax/src/test.rs +input_file: crates/squawk_syntax/test_data/validation/begin_atomic_stmts.sql +--- +SOURCE_FILE@0..239 + CREATE_FUNCTION@0..118 + CREATE_KW@0..6 "create" + WHITESPACE@6..7 " " + FUNCTION_KW@7..15 "function" + WHITESPACE@15..16 " " + PATH@16..17 + PATH_SEGMENT@16..17 + NAME@16..17 + IDENT@16..17 "f" + PARAM_LIST@17..19 + L_PAREN@17..18 "(" + R_PAREN@18..19 ")" + WHITESPACE@19..20 "\n" + RET_TYPE@20..32 + RETURNS_KW@20..27 "returns" + WHITESPACE@27..28 " " + PATH_TYPE@28..32 + PATH@28..32 + PATH_SEGMENT@28..32 + NAME_REF@28..32 + IDENT@28..32 "void" + WHITESPACE@32..33 "\n" + FUNC_OPTION_LIST@33..117 + LANGUAGE_FUNC_OPTION@33..45 + LANGUAGE_KW@33..41 "language" + WHITESPACE@41..42 " " + SQL_KW@42..45 "sql" + WHITESPACE@45..46 "\n" + BEGIN_FUNC_OPTION_LIST@46..117 + BEGIN_KW@46..51 "begin" + WHITESPACE@51..52 " " + ATOMIC_KW@52..58 "atomic" + WHITESPACE@58..61 "\n " + INSERT@61..86 + INSERT_KW@61..67 "insert" + WHITESPACE@67..68 " " + INTO_KW@68..72 "into" + WHITESPACE@72..73 " " + PATH@73..74 + PATH_SEGMENT@73..74 + NAME_REF@73..74 + IDENT@73..74 "t" + WHITESPACE@74..75 " " + VALUES@75..85 + VALUES_KW@75..81 "values" + WHITESPACE@81..82 " " + ROW_LIST@82..85 + ROW@82..85 + L_PAREN@82..83 "(" + LITERAL@83..84 + INT_NUMBER@83..84 "1" + R_PAREN@84..85 ")" + SEMICOLON@85..86 ";" + WHITESPACE@86..89 "\n " + INSERT@89..113 + INSERT_KW@89..95 "insert" + WHITESPACE@95..96 " " + INTO_KW@96..100 "into" + WHITESPACE@100..101 " " + PATH@101..102 + PATH_SEGMENT@101..102 + NAME_REF@101..102 + IDENT@101..102 "t" + WHITESPACE@102..103 " " + VALUES@103..113 + VALUES_KW@103..109 "values" + WHITESPACE@109..110 " " + ROW_LIST@110..113 + ROW@110..113 + L_PAREN@110..111 "(" + LITERAL@111..112 + INT_NUMBER@111..112 "2" + R_PAREN@112..113 ")" + WHITESPACE@113..114 "\n" + END_KW@114..117 "end" + SEMICOLON@117..118 ";" + WHITESPACE@118..120 "\n\n" + CREATE_FUNCTION@120..238 + CREATE_KW@120..126 "create" + WHITESPACE@126..127 " " + FUNCTION_KW@127..135 "function" + WHITESPACE@135..136 " " + PATH@136..137 + PATH_SEGMENT@136..137 + NAME@136..137 + IDENT@136..137 "g" + PARAM_LIST@137..139 + L_PAREN@137..138 "(" + R_PAREN@138..139 ")" + WHITESPACE@139..140 "\n" + RET_TYPE@140..152 + RETURNS_KW@140..147 "returns" + WHITESPACE@147..148 " " + PATH_TYPE@148..152 + PATH@148..152 + PATH_SEGMENT@148..152 + NAME_REF@148..152 + IDENT@148..152 "void" + WHITESPACE@152..153 "\n" + FUNC_OPTION_LIST@153..237 + LANGUAGE_FUNC_OPTION@153..165 + LANGUAGE_KW@153..161 "language" + WHITESPACE@161..162 " " + SQL_KW@162..165 "sql" + WHITESPACE@165..166 "\n" + BEGIN_FUNC_OPTION_LIST@166..237 + BEGIN_KW@166..171 "begin" + WHITESPACE@171..172 " " + ATOMIC_KW@172..178 "atomic" + WHITESPACE@178..181 "\n " + INSERT@181..205 + INSERT_KW@181..187 "insert" + WHITESPACE@187..188 " " + INTO_KW@188..192 "into" + WHITESPACE@192..193 " " + PATH@193..194 + PATH_SEGMENT@193..194 + NAME_REF@193..194 + IDENT@193..194 "t" + WHITESPACE@194..195 " " + VALUES@195..205 + VALUES_KW@195..201 "values" + WHITESPACE@201..202 " " + ROW_LIST@202..205 + ROW@202..205 + L_PAREN@202..203 "(" + LITERAL@203..204 + INT_NUMBER@203..204 "1" + R_PAREN@204..205 ")" + WHITESPACE@205..208 "\n " + INSERT@208..233 + INSERT_KW@208..214 "insert" + WHITESPACE@214..215 " " + INTO_KW@215..219 "into" + WHITESPACE@219..220 " " + PATH@220..221 + PATH_SEGMENT@220..221 + NAME_REF@220..221 + IDENT@220..221 "t" + WHITESPACE@221..222 " " + VALUES@222..232 + VALUES_KW@222..228 "values" + WHITESPACE@228..229 " " + ROW_LIST@229..232 + ROW@229..232 + L_PAREN@229..230 "(" + LITERAL@230..231 + INT_NUMBER@230..231 "2" + R_PAREN@231..232 ")" + SEMICOLON@232..233 ";" + WHITESPACE@233..234 "\n" + END_KW@234..237 "end" + SEMICOLON@237..238 ";" + WHITESPACE@238..239 "\n" + +error[syntax-error]: Missing semicolon after statement + ╭▸ +6 │ insert into t values (2) + ╰╴ ━ +error[syntax-error]: Missing semicolon after statement + ╭▸ +13 │ insert into t values (1) + ╰╴ ━ diff --git a/crates/squawk_syntax/src/snapshots/squawk_syntax__test__rule_stmts_ok_validation.snap b/crates/squawk_syntax/src/snapshots/squawk_syntax__test__rule_stmts_ok_validation.snap new file mode 100644 index 00000000..ae361d56 --- /dev/null +++ b/crates/squawk_syntax/src/snapshots/squawk_syntax__test__rule_stmts_ok_validation.snap @@ -0,0 +1,154 @@ +--- +source: crates/squawk_syntax/src/test.rs +input_file: crates/squawk_syntax/test_data/validation/rule_stmts_ok.sql +--- +SOURCE_FILE@0..209 + CREATE_RULE@0..102 + CREATE_KW@0..6 "create" + WHITESPACE@6..7 " " + RULE_KW@7..11 "rule" + WHITESPACE@11..12 " " + NAME@12..13 + IDENT@12..13 "r" + WHITESPACE@13..14 " " + AS_KW@14..16 "as" + WHITESPACE@16..17 " " + RULE_ON@17..31 + ON_KW@17..19 "on" + WHITESPACE@19..20 " " + UPDATE_KW@20..26 "update" + WHITESPACE@26..27 " " + TO_KW@27..29 "to" + WHITESPACE@29..30 " " + PATH@30..31 + PATH_SEGMENT@30..31 + NAME_REF@30..31 + IDENT@30..31 "t" + WHITESPACE@31..32 " " + RULE_DO@32..101 + DO_KW@32..34 "do" + WHITESPACE@34..35 " " + INSTEAD_KW@35..42 "instead" + WHITESPACE@42..43 " " + RULE_STMT_LIST@43..101 + L_PAREN@43..44 "(" + WHITESPACE@44..47 "\n " + INSERT@47..72 + INSERT_KW@47..53 "insert" + WHITESPACE@53..54 " " + INTO_KW@54..58 "into" + WHITESPACE@58..59 " " + PATH@59..60 + PATH_SEGMENT@59..60 + NAME_REF@59..60 + IDENT@59..60 "t" + WHITESPACE@60..61 " " + VALUES@61..71 + VALUES_KW@61..67 "values" + WHITESPACE@67..68 " " + ROW_LIST@68..71 + ROW@68..71 + L_PAREN@68..69 "(" + LITERAL@69..70 + INT_NUMBER@69..70 "1" + R_PAREN@70..71 ")" + SEMICOLON@71..72 ";" + WHITESPACE@72..75 "\n " + INSERT@75..99 + INSERT_KW@75..81 "insert" + WHITESPACE@81..82 " " + INTO_KW@82..86 "into" + WHITESPACE@86..87 " " + PATH@87..88 + PATH_SEGMENT@87..88 + NAME_REF@87..88 + IDENT@87..88 "t" + WHITESPACE@88..89 " " + VALUES@89..99 + VALUES_KW@89..95 "values" + WHITESPACE@95..96 " " + ROW_LIST@96..99 + ROW@96..99 + L_PAREN@96..97 "(" + LITERAL@97..98 + INT_NUMBER@97..98 "2" + R_PAREN@98..99 ")" + WHITESPACE@99..100 "\n" + R_PAREN@100..101 ")" + SEMICOLON@101..102 ";" + WHITESPACE@102..104 "\n\n" + CREATE_RULE@104..208 + CREATE_KW@104..110 "create" + WHITESPACE@110..111 " " + RULE_KW@111..115 "rule" + WHITESPACE@115..116 " " + NAME@116..118 + IDENT@116..118 "r2" + WHITESPACE@118..119 " " + AS_KW@119..121 "as" + WHITESPACE@121..122 " " + RULE_ON@122..136 + ON_KW@122..124 "on" + WHITESPACE@124..125 " " + UPDATE_KW@125..131 "update" + WHITESPACE@131..132 " " + TO_KW@132..134 "to" + WHITESPACE@134..135 " " + PATH@135..136 + PATH_SEGMENT@135..136 + NAME_REF@135..136 + IDENT@135..136 "t" + WHITESPACE@136..137 " " + RULE_DO@137..207 + DO_KW@137..139 "do" + WHITESPACE@139..140 " " + INSTEAD_KW@140..147 "instead" + WHITESPACE@147..148 " " + RULE_STMT_LIST@148..207 + L_PAREN@148..149 "(" + WHITESPACE@149..152 "\n " + INSERT@152..177 + INSERT_KW@152..158 "insert" + WHITESPACE@158..159 " " + INTO_KW@159..163 "into" + WHITESPACE@163..164 " " + PATH@164..165 + PATH_SEGMENT@164..165 + NAME_REF@164..165 + IDENT@164..165 "t" + WHITESPACE@165..166 " " + VALUES@166..176 + VALUES_KW@166..172 "values" + WHITESPACE@172..173 " " + ROW_LIST@173..176 + ROW@173..176 + L_PAREN@173..174 "(" + LITERAL@174..175 + INT_NUMBER@174..175 "1" + R_PAREN@175..176 ")" + SEMICOLON@176..177 ";" + WHITESPACE@177..180 "\n " + INSERT@180..205 + INSERT_KW@180..186 "insert" + WHITESPACE@186..187 " " + INTO_KW@187..191 "into" + WHITESPACE@191..192 " " + PATH@192..193 + PATH_SEGMENT@192..193 + NAME_REF@192..193 + IDENT@192..193 "t" + WHITESPACE@193..194 " " + VALUES@194..204 + VALUES_KW@194..200 "values" + WHITESPACE@200..201 " " + ROW_LIST@201..204 + ROW@201..204 + L_PAREN@201..202 "(" + LITERAL@202..203 + INT_NUMBER@202..203 "2" + R_PAREN@203..204 ")" + SEMICOLON@204..205 ";" + WHITESPACE@205..206 "\n" + R_PAREN@206..207 ")" + SEMICOLON@207..208 ";" + WHITESPACE@208..209 "\n" diff --git a/crates/squawk_syntax/src/snapshots/squawk_syntax__test__rule_stmts_validation.snap b/crates/squawk_syntax/src/snapshots/squawk_syntax__test__rule_stmts_validation.snap new file mode 100644 index 00000000..61aa2a87 --- /dev/null +++ b/crates/squawk_syntax/src/snapshots/squawk_syntax__test__rule_stmts_validation.snap @@ -0,0 +1,84 @@ +--- +source: crates/squawk_syntax/src/test.rs +input_file: crates/squawk_syntax/test_data/validation/rule_stmts.sql +--- +SOURCE_FILE@0..103 + CREATE_RULE@0..102 + CREATE_KW@0..6 "create" + WHITESPACE@6..7 " " + RULE_KW@7..11 "rule" + WHITESPACE@11..12 " " + NAME@12..13 + IDENT@12..13 "r" + WHITESPACE@13..14 " " + AS_KW@14..16 "as" + WHITESPACE@16..17 " " + RULE_ON@17..31 + ON_KW@17..19 "on" + WHITESPACE@19..20 " " + UPDATE_KW@20..26 "update" + WHITESPACE@26..27 " " + TO_KW@27..29 "to" + WHITESPACE@29..30 " " + PATH@30..31 + PATH_SEGMENT@30..31 + NAME_REF@30..31 + IDENT@30..31 "t" + WHITESPACE@31..32 " " + RULE_DO@32..101 + DO_KW@32..34 "do" + WHITESPACE@34..35 " " + INSTEAD_KW@35..42 "instead" + WHITESPACE@42..43 " " + RULE_STMT_LIST@43..101 + L_PAREN@43..44 "(" + WHITESPACE@44..47 "\n " + INSERT@47..71 + INSERT_KW@47..53 "insert" + WHITESPACE@53..54 " " + INTO_KW@54..58 "into" + WHITESPACE@58..59 " " + PATH@59..60 + PATH_SEGMENT@59..60 + NAME_REF@59..60 + IDENT@59..60 "t" + WHITESPACE@60..61 " " + VALUES@61..71 + VALUES_KW@61..67 "values" + WHITESPACE@67..68 " " + ROW_LIST@68..71 + ROW@68..71 + L_PAREN@68..69 "(" + LITERAL@69..70 + INT_NUMBER@69..70 "1" + R_PAREN@70..71 ")" + WHITESPACE@71..74 "\n " + INSERT@74..99 + INSERT_KW@74..80 "insert" + WHITESPACE@80..81 " " + INTO_KW@81..85 "into" + WHITESPACE@85..86 " " + PATH@86..87 + PATH_SEGMENT@86..87 + NAME_REF@86..87 + IDENT@86..87 "t" + WHITESPACE@87..88 " " + VALUES@88..98 + VALUES_KW@88..94 "values" + WHITESPACE@94..95 " " + ROW_LIST@95..98 + ROW@95..98 + L_PAREN@95..96 "(" + LITERAL@96..97 + INT_NUMBER@96..97 "2" + R_PAREN@97..98 ")" + SEMICOLON@98..99 ";" + WHITESPACE@99..100 "\n" + R_PAREN@100..101 ")" + SEMICOLON@101..102 ";" + WHITESPACE@102..103 "\n" + +error[syntax-error]: Missing semicolon between statements + ╭▸ +2 │ insert into t values (1) + ╰╴ ━ diff --git a/crates/squawk_syntax/src/validation.rs b/crates/squawk_syntax/src/validation.rs index 56db56f3..4481c247 100644 --- a/crates/squawk_syntax/src/validation.rs +++ b/crates/squawk_syntax/src/validation.rs @@ -16,6 +16,7 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec) { match_ast! { match node { ast::AlterAggregate(it) => validate_aggregate_params(it.aggregate().and_then(|x| x.param_list()), errors), + ast::BeginFuncOptionList(it) => validate_begin_func_option_list(it, errors), ast::CreateAggregate(it) => validate_aggregate_params(it.param_list(), errors), ast::CreateTable(it) => validate_create_table(it, errors), ast::PrefixExpr(it) => validate_prefix_expr(it, errors), @@ -24,6 +25,7 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec) { ast::JoinExpr(it) => validate_join_expr(it, errors), ast::Literal(it) => validate_literal(it, errors), ast::NonStandardParam(it) => validate_non_standard_param(it, errors), + ast::RuleStmtList(it) => validate_rule_stmt_list(it, errors), ast::Select(it) => validate_select(it, errors), ast::SelectInto(it) => validate_select_into(it, errors), ast::SourceFile(it) => validate_source_file(it, errors), @@ -40,6 +42,46 @@ pub(crate) fn validate(root: &SyntaxNode, errors: &mut Vec) { } } +fn validate_begin_func_option_list(it: ast::BeginFuncOptionList, acc: &mut Vec) { + for option in it.begin_func_options() { + let ast::BeginFuncOption::Stmt(stmt) = option else { + continue; + }; + let syntax = stmt.syntax(); + if syntax.kind() == EMPTY_STMT { + continue; + } + let ends_with_semi = syntax.last_token().is_some_and(|t| t.kind() == SEMICOLON); + if ends_with_semi { + continue; + } + let end = syntax.text_range().end(); + acc.push(SyntaxError::new( + "Missing semicolon after statement", + TextRange::empty(end), + )); + } +} + +fn validate_rule_stmt_list(it: ast::RuleStmtList, acc: &mut Vec) { + let mut stmts = it.rule_stmts().peekable(); + while let Some(stmt) = stmts.next() { + let syntax = stmt.syntax(); + if stmts.peek().is_none() { + continue; + } + let ends_with_semi = syntax.last_token().is_some_and(|t| t.kind() == SEMICOLON); + if ends_with_semi { + continue; + } + let end = syntax.text_range().end(); + acc.push(SyntaxError::new( + "Missing semicolon between statements", + TextRange::empty(end), + )); + } +} + fn validate_source_file(it: ast::SourceFile, acc: &mut Vec) { let mut stmts = it.stmts().peekable(); while let Some(stmt) = stmts.next() { diff --git a/crates/squawk_syntax/test_data/validation/begin_atomic_stmts.sql b/crates/squawk_syntax/test_data/validation/begin_atomic_stmts.sql new file mode 100644 index 00000000..1a6f86fd --- /dev/null +++ b/crates/squawk_syntax/test_data/validation/begin_atomic_stmts.sql @@ -0,0 +1,15 @@ +create function f() +returns void +language sql +begin atomic + insert into t values (1); + insert into t values (2) +end; + +create function g() +returns void +language sql +begin atomic + insert into t values (1) + insert into t values (2); +end; diff --git a/crates/squawk_syntax/test_data/validation/rule_stmts.sql b/crates/squawk_syntax/test_data/validation/rule_stmts.sql new file mode 100644 index 00000000..91fdb06f --- /dev/null +++ b/crates/squawk_syntax/test_data/validation/rule_stmts.sql @@ -0,0 +1,4 @@ +create rule r as on update to t do instead ( + insert into t values (1) + insert into t values (2); +); diff --git a/crates/squawk_syntax/test_data/validation/rule_stmts_ok.sql b/crates/squawk_syntax/test_data/validation/rule_stmts_ok.sql new file mode 100644 index 00000000..de648c0b --- /dev/null +++ b/crates/squawk_syntax/test_data/validation/rule_stmts_ok.sql @@ -0,0 +1,9 @@ +create rule r as on update to t do instead ( + insert into t values (1); + insert into t values (2) +); + +create rule r2 as on update to t do instead ( + insert into t values (1); + insert into t values (2); +); diff --git a/crates/squawk_wasm/src/lib.rs b/crates/squawk_wasm/src/lib.rs index 5d9d5d25..4ec3e528 100644 --- a/crates/squawk_wasm/src/lib.rs +++ b/crates/squawk_wasm/src/lib.rs @@ -677,6 +677,7 @@ fn convert_document_symbol( squawk_ide::document_symbols::DocumentSymbolKind::Procedure => "procedure", squawk_ide::document_symbols::DocumentSymbolKind::EventTrigger => "event_trigger", squawk_ide::document_symbols::DocumentSymbolKind::Role => "role", + squawk_ide::document_symbols::DocumentSymbolKind::Rule => "rule", squawk_ide::document_symbols::DocumentSymbolKind::Policy => "policy", squawk_ide::document_symbols::DocumentSymbolKind::PropertyGraph => "property_graph", squawk_ide::document_symbols::DocumentSymbolKind::Type => "type",