diff --git a/crates/squawk_ide/src/binder.rs b/crates/squawk_ide/src/binder.rs index c090e122..eec340b1 100644 --- a/crates/squawk_ide/src/binder.rs +++ b/crates/squawk_ide/src/binder.rs @@ -215,6 +215,9 @@ fn bind_stmt(b: &mut Binder, stmt: ast::Stmt) { } ast::Stmt::CreateSequence(create_sequence) => bind_create_sequence(b, create_sequence), ast::Stmt::CreateTrigger(create_trigger) => bind_create_trigger(b, create_trigger), + ast::Stmt::CreateEventTrigger(create_event_trigger) => { + bind_create_event_trigger(b, create_event_trigger) + } ast::Stmt::CreateTablespace(create_tablespace) => { bind_create_tablespace(b, create_tablespace) } @@ -547,6 +550,26 @@ fn bind_create_trigger(b: &mut Binder, create_trigger: ast::CreateTrigger) { b.scopes[root].insert(trigger_name, trigger_id); } +fn bind_create_event_trigger(b: &mut Binder, create_event_trigger: ast::CreateEventTrigger) { + let Some(name) = create_event_trigger.name() else { + return; + }; + + let event_trigger_name = Name::from_node(&name); + let name_ptr = SyntaxNodePtr::new(name.syntax()); + + let event_trigger_id = b.symbols.alloc(Symbol { + kind: SymbolKind::EventTrigger, + ptr: name_ptr, + schema: None, + params: None, + table: None, + }); + + let root = b.root_scope(); + b.scopes[root].insert(event_trigger_name, event_trigger_id); +} + fn bind_create_tablespace(b: &mut Binder, create_tablespace: ast::CreateTablespace) { let Some(name) = create_tablespace.name() else { return; diff --git a/crates/squawk_ide/src/classify.rs b/crates/squawk_ide/src/classify.rs index 92b92af8..93ba2200 100644 --- a/crates/squawk_ide/src/classify.rs +++ b/crates/squawk_ide/src/classify.rs @@ -14,6 +14,7 @@ pub(crate) enum NameRefClass { DropMaterializedView, DropSequence, DropTrigger, + DropEventTrigger, SequenceOwnedByColumn, Tablespace, DropDatabase, @@ -100,6 +101,7 @@ pub(crate) enum NameRefClass { UnlistenChannel, TriggerFunctionCall, TriggerProcedureCall, + AlterEventTrigger, } fn is_special_fn(kind: SyntaxKind) -> bool { @@ -449,6 +451,9 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option if ast::DropTrigger::can_cast(ancestor.kind()) { return Some(NameRefClass::DropTrigger); } + if ast::DropEventTrigger::can_cast(ancestor.kind()) { + return Some(NameRefClass::DropEventTrigger); + } if ast::DropDatabase::can_cast(ancestor.kind()) { return Some(NameRefClass::DropDatabase); } @@ -458,6 +463,9 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option if ast::AlterServer::can_cast(ancestor.kind()) { return Some(NameRefClass::AlterServer); } + if ast::AlterEventTrigger::can_cast(ancestor.kind()) { + return Some(NameRefClass::AlterEventTrigger); + } if ast::CreateServer::can_cast(ancestor.kind()) { return Some(NameRefClass::CreateServer); } @@ -603,6 +611,15 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option } return Some(NameRefClass::TriggerFunctionCall); } + if let Some(create_event_trigger) = ast::CreateEventTrigger::cast(ancestor.clone()) + && in_call_expr + && !in_arg_list + { + if create_event_trigger.procedure_token().is_some() { + return Some(NameRefClass::TriggerProcedureCall); + } + return Some(NameRefClass::TriggerFunctionCall); + } if in_partition_item && ast::CreateTableLike::can_cast(ancestor.kind()) { return Some(NameRefClass::PartitionByColumn); } @@ -744,6 +761,7 @@ pub(crate) enum NameClass { CreateIndex(ast::CreateIndex), CreateSequence(ast::CreateSequence), CreateTrigger(ast::CreateTrigger), + CreateEventTrigger(ast::CreateEventTrigger), CreateTablespace(ast::CreateTablespace), CreateDatabase(ast::CreateDatabase), CreateServer(ast::CreateServer), @@ -791,6 +809,9 @@ pub(crate) fn classify_name(name: &ast::Name) -> Option { if let Some(create_trigger) = ast::CreateTrigger::cast(ancestor.clone()) { return Some(NameClass::CreateTrigger(create_trigger)); } + if let Some(create_event_trigger) = ast::CreateEventTrigger::cast(ancestor.clone()) { + return Some(NameClass::CreateEventTrigger(create_event_trigger)); + } if let Some(create_tablespace) = ast::CreateTablespace::cast(ancestor.clone()) { return Some(NameClass::CreateTablespace(create_tablespace)); } diff --git a/crates/squawk_ide/src/document_symbols.rs b/crates/squawk_ide/src/document_symbols.rs index f8eb58d0..d13c4033 100644 --- a/crates/squawk_ide/src/document_symbols.rs +++ b/crates/squawk_ide/src/document_symbols.rs @@ -16,6 +16,7 @@ pub enum DocumentSymbolKind { Function, Aggregate, Procedure, + EventTrigger, Type, Enum, Column, @@ -69,6 +70,11 @@ pub fn document_symbols(file: &ast::SourceFile) -> Vec { symbols.push(symbol); } } + ast::Stmt::CreateEventTrigger(create_event_trigger) => { + if let Some(symbol) = create_event_trigger_symbol(create_event_trigger) { + symbols.push(symbol); + } + } ast::Stmt::CreateType(create_type) => { if let Some(symbol) = create_type_symbol(&binder, create_type) { symbols.push(symbol); @@ -370,6 +376,25 @@ fn create_procedure_symbol( }) } +fn create_event_trigger_symbol( + create_event_trigger: ast::CreateEventTrigger, +) -> Option { + let name_node = create_event_trigger.name()?; + let name = name_node.syntax().text().to_string(); + + let full_range = create_event_trigger.syntax().text_range(); + let focus_range = name_node.syntax().text_range(); + + Some(DocumentSymbol { + name, + detail: None, + kind: DocumentSymbolKind::EventTrigger, + full_range, + focus_range, + children: vec![], + }) +} + fn create_type_symbol( binder: &binder::Binder, create_type: ast::CreateType, @@ -579,6 +604,7 @@ mod tests { DocumentSymbolKind::Function => "function", DocumentSymbolKind::Aggregate => "aggregate", DocumentSymbolKind::Procedure => "procedure", + DocumentSymbolKind::EventTrigger => "event trigger", DocumentSymbolKind::Type => "type", DocumentSymbolKind::Enum => "enum", DocumentSymbolKind::Column => "column", @@ -808,6 +834,22 @@ unlisten *; ); } + #[test] + fn create_event_trigger() { + assert_snapshot!( + symbols("create event trigger et on ddl_command_start execute function f();"), + @r" + info: event trigger: et + ╭▸ + 1 │ create event trigger et on ddl_command_start execute function f(); + │ ┬────────────────────┯━────────────────────────────────────────── + │ │ │ + │ │ focus range + ╰╴full range + " + ); + } + #[test] fn multiple_symbols() { assert_snapshot!(symbols(" diff --git a/crates/squawk_ide/src/goto_definition.rs b/crates/squawk_ide/src/goto_definition.rs index f81ea53f..ce12fe07 100644 --- a/crates/squawk_ide/src/goto_definition.rs +++ b/crates/squawk_ide/src/goto_definition.rs @@ -484,6 +484,65 @@ drop trigger tr$0 on t; "); } + #[test] + fn goto_drop_event_trigger() { + assert_snapshot!(goto(" +create event trigger et on ddl_command_start execute function f(); +drop event trigger et$0; +"), @r" + ╭▸ + 2 │ create event trigger et on ddl_command_start execute function f(); + │ ── 2. destination + 3 │ drop event trigger et; + ╰╴ ─ 1. source + "); + } + + #[test] + fn goto_alter_event_trigger() { + assert_snapshot!(goto(" +create event trigger et on ddl_command_start execute function f(); +alter event trigger et$0 disable; +"), @r" + ╭▸ + 2 │ create event trigger et on ddl_command_start execute function f(); + │ ── 2. destination + 3 │ alter event trigger et disable; + ╰╴ ─ 1. source + "); + } + + #[test] + fn goto_create_event_trigger_function() { + assert_snapshot!(goto(" +create function f() returns event_trigger as 'select 1' language sql; +create event trigger et on ddl_command_start execute function f$0(); +"), @r" + ╭▸ + 2 │ create function f() returns event_trigger as 'select 1' language sql; + │ ─ 2. destination + 3 │ create event trigger et on ddl_command_start execute function f(); + ╰╴ ─ 1. source + "); + } + + #[test] + fn goto_create_event_trigger_procedure() { + assert_snapshot!(goto(" +create procedure p() language sql as 'select 1'; +create event trigger tr + on ddl_command_end + execute procedure p$0(); +"), @r" + ╭▸ + 2 │ create procedure p() language sql as 'select 1'; + │ ─ 2. destination + ‡ + 5 │ execute procedure p(); + ╰╴ ─ 1. source + "); + } + #[test] fn goto_create_trigger_function() { assert_snapshot!(goto(" diff --git a/crates/squawk_ide/src/hover.rs b/crates/squawk_ide/src/hover.rs index fd46489b..f3fd4b35 100644 --- a/crates/squawk_ide/src/hover.rs +++ b/crates/squawk_ide/src/hover.rs @@ -127,6 +127,9 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option { } NameRefClass::DropSequence => return hover_sequence(root, &name_ref, &binder), NameRefClass::DropTrigger => return hover_trigger(root, &name_ref, &binder), + NameRefClass::DropEventTrigger | NameRefClass::AlterEventTrigger => { + return hover_event_trigger(root, &name_ref, &binder); + } NameRefClass::DropDatabase | NameRefClass::ReindexDatabase | NameRefClass::ReindexSystem => return hover_database(root, &name_ref, &binder), @@ -204,6 +207,9 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option { NameClass::CreateTrigger(create_trigger) => { return format_create_trigger(&create_trigger, &binder); } + NameClass::CreateEventTrigger(create_event_trigger) => { + return format_create_event_trigger(&create_event_trigger); + } NameClass::CreateTablespace(create_tablespace) => { return format_create_tablespace(&create_tablespace); } @@ -772,6 +778,24 @@ fn hover_trigger( format_create_trigger(&create_trigger, binder) } +fn hover_event_trigger( + root: &SyntaxNode, + name_ref: &ast::NameRef, + binder: &binder::Binder, +) -> Option { + let event_trigger_ptr = resolve::resolve_name_ref(binder, root, name_ref)? + .into_iter() + .next()?; + + let event_trigger_name_node = event_trigger_ptr.to_node(root); + + let create_event_trigger = event_trigger_name_node + .ancestors() + .find_map(ast::CreateEventTrigger::cast)?; + + format_create_event_trigger(&create_event_trigger) +} + fn hover_tablespace( root: &SyntaxNode, name_ref: &ast::NameRef, @@ -1025,6 +1049,11 @@ fn format_create_trigger( )) } +fn format_create_event_trigger(create_event_trigger: &ast::CreateEventTrigger) -> Option { + let name = create_event_trigger.name()?.syntax().text().to_string(); + Some(format!("event trigger {}", name)) +} + fn format_create_tablespace(create_tablespace: &ast::CreateTablespace) -> Option { let name = create_tablespace.name()?.syntax().text().to_string(); Some(format!("tablespace {}", name)) diff --git a/crates/squawk_ide/src/resolve.rs b/crates/squawk_ide/src/resolve.rs index 5069efc6..062f80a9 100644 --- a/crates/squawk_ide/src/resolve.rs +++ b/crates/squawk_ide/src/resolve.rs @@ -172,6 +172,10 @@ pub(crate) fn resolve_name_ref( resolve_trigger_name_ptr(binder, &trigger_name, &schema, position, Some(table_name)) .map(|ptr| smallvec![ptr]) } + NameRefClass::DropEventTrigger | NameRefClass::AlterEventTrigger => { + let event_trigger_name = Name::from_node(name_ref); + resolve_event_trigger_name_ptr(binder, &event_trigger_name).map(|ptr| smallvec![ptr]) + } NameRefClass::ReindexDatabase | NameRefClass::ReindexSystem | NameRefClass::DropDatabase => { @@ -542,6 +546,13 @@ fn resolve_trigger_name_ptr( binder.lookup_with_table(trigger_name, SymbolKind::Trigger, position, schema, &table) } +fn resolve_event_trigger_name_ptr( + binder: &Binder, + event_trigger_name: &Name, +) -> Option { + binder.lookup(event_trigger_name, SymbolKind::EventTrigger) +} + fn resolve_tablespace_name_ptr(binder: &Binder, tablespace_name: &Name) -> Option { binder.lookup(tablespace_name, SymbolKind::Tablespace) } diff --git a/crates/squawk_ide/src/symbols.rs b/crates/squawk_ide/src/symbols.rs index 38e4adad..5a3482f9 100644 --- a/crates/squawk_ide/src/symbols.rs +++ b/crates/squawk_ide/src/symbols.rs @@ -61,6 +61,7 @@ pub(crate) enum SymbolKind { Server, Extension, Trigger, + EventTrigger, } #[derive(Clone, Debug)] diff --git a/crates/squawk_server/src/lib.rs b/crates/squawk_server/src/lib.rs index b97d2bc0..4efde1c3 100644 --- a/crates/squawk_server/src/lib.rs +++ b/crates/squawk_server/src/lib.rs @@ -380,6 +380,7 @@ fn handle_document_symbol( DocumentSymbolKind::Cursor => SymbolKind::VARIABLE, DocumentSymbolKind::PreparedStatement => SymbolKind::VARIABLE, DocumentSymbolKind::Channel => SymbolKind::EVENT, + DocumentSymbolKind::EventTrigger => SymbolKind::EVENT, }, tags: None, range, diff --git a/crates/squawk_wasm/src/lib.rs b/crates/squawk_wasm/src/lib.rs index d327d7ea..2b4466b7 100644 --- a/crates/squawk_wasm/src/lib.rs +++ b/crates/squawk_wasm/src/lib.rs @@ -406,6 +406,7 @@ fn convert_document_symbol( squawk_ide::document_symbols::DocumentSymbolKind::Function => "function", squawk_ide::document_symbols::DocumentSymbolKind::Aggregate => "aggregate", squawk_ide::document_symbols::DocumentSymbolKind::Procedure => "procedure", + squawk_ide::document_symbols::DocumentSymbolKind::EventTrigger => "event_trigger", squawk_ide::document_symbols::DocumentSymbolKind::Type => "type", squawk_ide::document_symbols::DocumentSymbolKind::Enum => "enum", squawk_ide::document_symbols::DocumentSymbolKind::Column => "column",