diff --git a/crates/squawk_ide/src/document_symbols.rs b/crates/squawk_ide/src/document_symbols.rs index 033747a7..6ef6b45b 100644 --- a/crates/squawk_ide/src/document_symbols.rs +++ b/crates/squawk_ide/src/document_symbols.rs @@ -2,13 +2,17 @@ use rowan::TextRange; use squawk_syntax::ast::{self, AstNode}; use crate::binder::{self, extract_string_literal}; -use crate::resolve::{resolve_function_info, resolve_table_info, resolve_type_info}; +use crate::resolve::{ + resolve_function_info, resolve_table_info, resolve_type_info, resolve_view_info, +}; #[derive(Debug)] pub enum DocumentSymbolKind { Table, + View, Function, Type, + Enum, Column, Variant, } @@ -47,6 +51,11 @@ pub fn document_symbols(file: &ast::SourceFile) -> Vec { symbols.push(symbol); } } + ast::Stmt::CreateView(create_view) => { + if let Some(symbol) = create_view_symbol(&binder, create_view) { + symbols.push(symbol); + } + } ast::Stmt::Select(select) => { symbols.extend(cte_table_symbols(select)); } @@ -142,6 +151,39 @@ fn create_table_symbol( }) } +fn create_view_symbol( + binder: &binder::Binder, + create_view: ast::CreateView, +) -> Option { + let path = create_view.path()?; + let segment = path.segment()?; + let name_node = segment.name()?; + + let (schema, view_name) = resolve_view_info(binder, &path)?; + let name = format!("{}.{}", schema.0, view_name); + + let full_range = create_view.syntax().text_range(); + let focus_range = name_node.syntax().text_range(); + + let mut children = vec![]; + if let Some(column_list) = create_view.column_list() { + for column in column_list.columns() { + if let Some(column_symbol) = create_column_symbol(column) { + children.push(column_symbol); + } + } + } + + Some(DocumentSymbol { + name, + detail: None, + kind: DocumentSymbolKind::View, + full_range, + focus_range, + children, + }) +} + fn create_function_symbol( binder: &binder::Binder, create_function: ast::CreateFunction, @@ -198,7 +240,11 @@ fn create_type_symbol( Some(DocumentSymbol { name, detail: None, - kind: DocumentSymbolKind::Type, + kind: if create_type.variant_list().is_some() { + DocumentSymbolKind::Enum + } else { + DocumentSymbolKind::Type + }, full_range, focus_range, children, @@ -280,8 +326,10 @@ mod tests { fn symbol_to_group<'a>(symbol: &DocumentSymbol, sql: &'a str) -> Group<'a> { let kind = match symbol.kind { DocumentSymbolKind::Table => "table", + DocumentSymbolKind::View => "view", DocumentSymbolKind::Function => "function", DocumentSymbolKind::Type => "type", + DocumentSymbolKind::Enum => "enum", DocumentSymbolKind::Column => "column", DocumentSymbolKind::Variant => "variant", }; @@ -477,7 +525,7 @@ create function my_schema.hello() returns void as $$ select 1; $$ language sql; assert_snapshot!( symbols("create type status as enum ('active', 'inactive');"), @r" - info: type: public.status + info: enum: public.status ╭▸ 1 │ create type status as enum ('active', 'inactive'); │ ┬───────────┯━━━━━─────────────────────────────── @@ -554,7 +602,7 @@ create function my_schema.hello() returns void as $$ select 1; $$ language sql; assert_snapshot!( symbols("create type myschema.status as enum ('active', 'inactive');"), @r" - info: type: myschema.status + info: enum: myschema.status ╭▸ 1 │ create type myschema.status as enum ('active', 'inactive'); │ ┬────────────────────┯━━━━━─────────────────────────────── @@ -579,7 +627,7 @@ create function my_schema.hello() returns void as $$ select 1; $$ language sql; assert_snapshot!( symbols("create type priority as enum ('low', 'medium', 'high', 'urgent');"), @r" - info: type: public.priority + info: enum: public.priority ╭▸ 1 │ create type priority as enum ('low', 'medium', 'high', 'urgent'); │ ┬───────────┯━━━━━━━──────────────────────────────────────────── diff --git a/crates/squawk_ide/src/resolve.rs b/crates/squawk_ide/src/resolve.rs index 12d9b029..f9187ac7 100644 --- a/crates/squawk_ide/src/resolve.rs +++ b/crates/squawk_ide/src/resolve.rs @@ -1511,6 +1511,10 @@ pub(crate) fn resolve_type_info(binder: &Binder, path: &ast::Path) -> Option<(Sc resolve_symbol_info(binder, path, SymbolKind::Type) } +pub(crate) fn resolve_view_info(binder: &Binder, path: &ast::Path) -> Option<(Schema, String)> { + resolve_symbol_info(binder, path, SymbolKind::View) +} + fn resolve_symbol_info( binder: &Binder, path: &ast::Path, diff --git a/crates/squawk_server/src/lib.rs b/crates/squawk_server/src/lib.rs index 24cc88bb..1f459fa5 100644 --- a/crates/squawk_server/src/lib.rs +++ b/crates/squawk_server/src/lib.rs @@ -336,8 +336,10 @@ fn handle_document_symbol( detail: sym.detail, kind: match sym.kind { DocumentSymbolKind::Table => SymbolKind::STRUCT, + DocumentSymbolKind::View => SymbolKind::STRUCT, DocumentSymbolKind::Function => SymbolKind::FUNCTION, DocumentSymbolKind::Type => SymbolKind::CLASS, + DocumentSymbolKind::Enum => SymbolKind::ENUM, DocumentSymbolKind::Column => SymbolKind::FIELD, DocumentSymbolKind::Variant => SymbolKind::ENUM_MEMBER, }, diff --git a/crates/squawk_wasm/src/lib.rs b/crates/squawk_wasm/src/lib.rs index ba85ef98..984677c3 100644 --- a/crates/squawk_wasm/src/lib.rs +++ b/crates/squawk_wasm/src/lib.rs @@ -393,8 +393,10 @@ fn convert_document_symbol( detail: symbol.detail, kind: match symbol.kind { squawk_ide::document_symbols::DocumentSymbolKind::Table => "table", + squawk_ide::document_symbols::DocumentSymbolKind::View => "view", squawk_ide::document_symbols::DocumentSymbolKind::Function => "function", squawk_ide::document_symbols::DocumentSymbolKind::Type => "type", + squawk_ide::document_symbols::DocumentSymbolKind::Enum => "enum", squawk_ide::document_symbols::DocumentSymbolKind::Column => "column", squawk_ide::document_symbols::DocumentSymbolKind::Variant => "variant", }