diff --git a/crates/squawk_ide/src/completion.rs b/crates/squawk_ide/src/completion.rs index 5290651e..2b5273c9 100644 --- a/crates/squawk_ide/src/completion.rs +++ b/crates/squawk_ide/src/completion.rs @@ -393,6 +393,22 @@ fn column_completions_from_clause( sort_text: None, })); } + Some(resolve::TableSource::Alias(alias)) => { + if let Some(column_list) = alias.column_list() { + completions.extend(column_list.columns().filter_map(|column| { + let name = column.name()?; + Some(CompletionItem { + label: Name::from_node(&name).to_string(), + kind: CompletionItemKind::Column, + detail: None, + insert_text: None, + insert_text_format: None, + trigger_completion_after_insert: false, + sort_text: None, + }) + })); + } + } Some(resolve::TableSource::ParenSelect(paren_select)) => { let columns = resolve::collect_paren_select_columns_with_types( binder, diff --git a/crates/squawk_ide/src/hover.rs b/crates/squawk_ide/src/hover.rs index 092b3cfc..a4119800 100644 --- a/crates/squawk_ide/src/hover.rs +++ b/crates/squawk_ide/src/hover.rs @@ -428,6 +428,7 @@ fn hover_column_definition( // salsa to lookup the the correct binder. fn format_table_source(source: resolve::TableSource, binder: &binder::Binder) -> Option { match source { + resolve::TableSource::Alias(alias) => format_alias_with_column_list(&alias), resolve::TableSource::WithTable(with_table) => format_with_table(&with_table), resolve::TableSource::CreateView(create_view) => format_create_view(&create_view, binder), resolve::TableSource::CreateMaterializedView(create_materialized_view) => { @@ -452,6 +453,14 @@ fn hover_table(binder: &binder::Binder, def_node: &SyntaxNode) -> Option None } +fn format_alias_with_column_list(alias: &ast::Alias) -> Option { + let alias_name = alias.name()?; + let column_list = alias.column_list()?; + let name = Name::from_node(&alias_name).to_string(); + let columns = column_list.syntax().text().to_string(); + Some(format!("table {}{}", name, columns)) +} + fn hover_qualified_star( root: &SyntaxNode, field_expr: &ast::FieldExpr, @@ -527,6 +536,7 @@ fn hover_qualified_star_columns( } match resolve::find_table_source(&table_name_node)? { + resolve::TableSource::Alias(alias) => hover_qualified_star_columns_from_alias(&alias), resolve::TableSource::WithTable(with_table) => { hover_qualified_star_columns_from_cte(&with_table) } @@ -545,6 +555,25 @@ fn hover_qualified_star_columns( } } +fn hover_qualified_star_columns_from_alias(alias: &ast::Alias) -> Option { + let alias_name = Name::from_node(&alias.name()?); + let columns = alias.column_list()?.columns(); + let results: Vec = columns + .filter_map(|column| { + let column_name = Name::from_node(&column.name()?); + Some(ColumnHover::table_column( + &alias_name.to_string(), + &column_name.to_string(), + )) + }) + .collect(); + + if results.is_empty() { + return None; + } + + Some(results.join("\n")) +} fn hover_qualified_star_columns_from_table( root: &SyntaxNode, create_table: &impl ast::HasCreateTable, @@ -3006,6 +3035,19 @@ select t.*$0 from t; "); } + #[test] + fn hover_on_cte_table_alias_with_column_list() { + assert_snapshot!(check_hover(" +with t as (select 1 a, 2 b) +select u$0.x, u.y from t as u(x, y); +"), @" + hover: table u(x, y) + ╭▸ + 3 │ select u.x, u.y from t as u(x, y); + ╰╴ ─ hover + "); + } + #[test] fn hover_on_star_with_subquery_from_cte() { assert_snapshot!(check_hover(" diff --git a/crates/squawk_ide/src/resolve.rs b/crates/squawk_ide/src/resolve.rs index 96a803a6..29e95214 100644 --- a/crates/squawk_ide/src/resolve.rs +++ b/crates/squawk_ide/src/resolve.rs @@ -2729,11 +2729,12 @@ fn collect_tables_from_item( } pub(crate) enum TableSource { - WithTable(ast::WithTable), - CreateView(ast::CreateView), + Alias(ast::Alias), CreateMaterializedView(ast::CreateMaterializedView), CreateTable(ast::CreateTableLike), + CreateView(ast::CreateView), ParenSelect(ast::ParenSelect), + WithTable(ast::WithTable), } pub(crate) fn find_table_source(node: &SyntaxNode) -> Option { @@ -2742,6 +2743,12 @@ pub(crate) fn find_table_source(node: &SyntaxNode) -> Option { } for ancestor in node.ancestors() { + if let Some(alias) = ast::Alias::cast(ancestor.clone()) + && alias.column_list().is_some() + { + return Some(TableSource::Alias(alias)); + } + if let Some(with_table) = ast::WithTable::cast(ancestor.clone()) { return Some(TableSource::WithTable(with_table)); }