1use crate::ast_nav;
2use crate::builtins::builtins_file;
3use crate::collect;
4use crate::column_name::ColumnName;
5use crate::comments::preceding_comment;
6use crate::db::{File, bind, parse};
7use crate::infer::infer_type_from_expr;
8use crate::location::{Location, LocationKind};
9use crate::name;
10use crate::offsets::token_from_offset;
11use crate::symbols::{Name, Schema};
12use crate::{goto_definition, resolve};
13use rowan::TextSize;
14use salsa::Database as Db;
15use squawk_syntax::SyntaxNode;
16use squawk_syntax::SyntaxNodePtr;
17use squawk_syntax::{
18 SyntaxKind,
19 ast::{self, AstNode},
20};
21
22#[derive(Clone, Debug, Eq, PartialEq)]
23pub struct Hover {
24 pub snippet: String,
25 pub comment: Option<String>,
26}
27
28impl Hover {
29 fn snippet(snippet: impl Into<String>) -> Hover {
30 Hover {
31 snippet: snippet.into(),
32 comment: None,
33 }
34 }
35
36 fn new(snippet: impl Into<String>, comment: impl Into<String>) -> Hover {
37 Hover {
38 snippet: snippet.into(),
39 comment: Some(comment.into()),
40 }
41 }
42
43 pub fn markdown(&self) -> String {
44 let snippet = &self.snippet;
45 let mut out = format!(
46 "
47```sql
48{snippet}
49```
50"
51 );
52
53 if let Some(comment) = &self.comment {
54 out.push_str(&format!(
55 "---
56{comment}
57"
58 ))
59 }
60
61 out
62 }
63}
64
65fn merge_hovers(hovers: Vec<Hover>) -> Option<Hover> {
66 if hovers.is_empty() {
67 return None;
68 }
69
70 if hovers.len() == 1 {
71 return Some(hovers[0].clone());
72 }
73
74 Some(Hover::snippet(
75 hovers
76 .into_iter()
77 .map(|hover| hover.snippet)
78 .collect::<Vec<_>>()
79 .join("\n"),
80 ))
81}
82
83fn hover_with_preceding_comment(snippet: impl Into<String>, node: &SyntaxNode) -> Hover {
84 let snippet = snippet.into();
85 if let Some(comment) = preceding_comment(node) {
86 return Hover::new(snippet, comment);
87 }
88 Hover::snippet(snippet)
89}
90
91fn hover_column_with_preceding_comment(snippet: impl Into<String>, def_node: &SyntaxNode) -> Hover {
92 let snippet = snippet.into();
93 if let Some(definition_node) = def_node
94 .ancestors()
95 .find_map(|node| ast::Column::cast(node.clone()))
96 {
97 return hover_with_preceding_comment(snippet, definition_node.syntax());
98 }
99 Hover::snippet(snippet)
100}
101
102#[salsa::tracked]
103pub fn hover(db: &dyn Db, file: File, offset: TextSize) -> Option<Hover> {
104 let token = token_from_offset(db, file, offset)?;
105 let parent = token.parent()?;
106
107 if token.kind() == SyntaxKind::STAR {
108 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone())
109 && field_expr.star_token().is_some()
110 && let Some(result) = hover_qualified_star(db, file, field_expr)
111 {
112 return Some(result);
113 }
114
115 if let Some(arg_list) = ast::ArgList::cast(parent.clone())
116 && let Some(result) = hover_unqualified_star_in_arg_list(db, file, arg_list)
117 {
118 return Some(result);
119 }
120
121 if let Some(target) = ast::Target::cast(parent.clone())
122 && target.star_token().is_some()
123 && let Some(result) = hover_unqualified_star(db, file, target)
124 {
125 return Some(result);
126 }
127 return None;
128 }
129
130 if ast::NameRef::can_cast(parent.kind()) {
131 return hover_name_ref(db, file, offset);
132 }
133
134 if let Some(name) = ast::Name::cast(parent) {
135 return hover_name(db, file, name);
136 }
137
138 None
139}
140
141fn hover_name(db: &dyn Db, file: File, name: ast::Name) -> Option<Hover> {
142 let def = Location::from_node(file, name.syntax())?;
143 match def.kind {
144 LocationKind::Aggregate => hover_aggregate(db, def),
145 LocationKind::CaseExpr | LocationKind::CommitBegin | LocationKind::CommitEnd => None,
146 LocationKind::Channel => hover_channel(db, def),
147 LocationKind::Column => hover_name_column(db, def),
148 LocationKind::Cursor => hover_cursor(db, def),
149 LocationKind::Database => hover_database(db, def),
150 LocationKind::EventTrigger => hover_event_trigger(db, def),
151 LocationKind::Extension => hover_extension(db, def),
152 LocationKind::Function => hover_function(db, def),
153 LocationKind::Index => hover_index(db, def),
154 LocationKind::NamedArgParameter => hover_named_arg_parameter(db, def),
155 LocationKind::Policy => hover_policy(db, def),
156 LocationKind::PreparedStatement => hover_prepared_statement(db, def),
157 LocationKind::Procedure => hover_procedure(db, def),
158 LocationKind::PropertyGraph => hover_property_graph(db, def),
159 LocationKind::Role => hover_role(db, def),
160 LocationKind::Schema => hover_schema(db, def),
161 LocationKind::Sequence => hover_sequence(db, def),
162 LocationKind::Server => hover_server(db, def),
163 LocationKind::Table => hover_table(db, def),
164 LocationKind::Tablespace => hover_tablespace(db, def),
165 LocationKind::View => {
166 if let Some(hover) = format_create_view(db, def) {
167 return Some(hover);
168 }
169 hover_table(db, def)
170 }
171 LocationKind::Trigger => hover_trigger(db, def),
172 LocationKind::Type => hover_type(db, def),
173 LocationKind::Window => hover_window(db, def),
174 }
175}
176
177fn hover_name_column(db: &dyn Db, def: Location) -> Option<Hover> {
178 if let Some(result) = hover_composite_type_field(db, def) {
179 return Some(result);
180 }
181
182 let def_node = def.to_node(db)?;
183 if let Some(column) = def_node.parent().and_then(ast::Column::cast)
184 && let Some(create_table) = def_node.ancestors().find_map(ast::CreateTableLike::cast)
185 {
186 return hover_column_definition(db, def.file, create_table, column);
187 }
188
189 if def_node
190 .ancestors()
191 .any(|ancestor| ast::ColumnList::can_cast(ancestor.kind()))
192 && let Some(create_view) = def_node.ancestors().find_map(ast::CreateViewLike::cast)
193 {
194 return format_view_column(db, def.file, &create_view, &def_node);
195 }
196
197 None
198}
199
200fn hover_name_ref(db: &dyn Db, file: File, offset: TextSize) -> Option<Hover> {
201 let definitions = goto_definition::goto_definition(db, file, offset);
206 let def = *definitions.first()?;
207 match def.kind {
208 LocationKind::Aggregate => hover_aggregate(db, def),
209 LocationKind::CaseExpr | LocationKind::CommitBegin | LocationKind::CommitEnd => None,
210 LocationKind::Channel => hover_channel(db, def),
211 LocationKind::Column => {
212 if let Some(result) = hover_composite_type_field(db, def) {
213 return Some(result);
214 }
215 if let Some(result) = hover_column(db, &definitions) {
216 return Some(result);
217 }
218 if let Some(result) = hover_function(db, def) {
220 return Some(result);
221 }
222 hover_table(db, def)
224 }
225 LocationKind::Cursor => hover_cursor(db, def),
226 LocationKind::Database => hover_database(db, def),
227 LocationKind::EventTrigger => hover_event_trigger(db, def),
228 LocationKind::Extension => hover_extension(db, def),
229 LocationKind::Function => {
230 if let Some(result) = hover_function(db, def) {
231 return Some(result);
232 }
233 if let Some(result) = hover_routine(db, def) {
234 return Some(result);
235 }
236 hover_column(db, &definitions)
237 }
238 LocationKind::Index => hover_index(db, def),
239 LocationKind::NamedArgParameter => hover_named_arg_parameter(db, def),
240 LocationKind::Policy => hover_policy(db, def),
241 LocationKind::PreparedStatement => hover_prepared_statement(db, def),
242 LocationKind::Procedure => hover_procedure(db, def),
243 LocationKind::PropertyGraph => hover_property_graph(db, def),
244 LocationKind::Role => hover_role(db, def),
245 LocationKind::Schema => hover_schema(db, def),
246 LocationKind::Sequence => hover_sequence(db, def),
247 LocationKind::Server => hover_server(db, def),
248 LocationKind::Table | LocationKind::View => hover_table(db, def),
249 LocationKind::Tablespace => hover_tablespace(db, def),
250 LocationKind::Trigger => hover_trigger(db, def),
251 LocationKind::Type => hover_type(db, def),
252 LocationKind::Window => hover_window(db, def),
253 }
254}
255
256struct ColumnHover;
257impl ColumnHover {
258 fn table_column(table_name: &str, column_name: &str) -> String {
259 format!("column {table_name}.{column_name}")
260 }
261
262 fn table_column_type(table_name: &str, column_name: &str, ty: &str) -> String {
263 format!("column {table_name}.{column_name} {ty}")
264 }
265
266 fn schema_table_column_type(
267 schema: &str,
268 table_name: &str,
269 column_name: &str,
270 ty: &str,
271 ) -> String {
272 format!("column {schema}.{table_name}.{column_name} {ty}")
273 }
274 fn schema_table_column(schema: &str, table_name: &str, column_name: &str) -> String {
275 format!("column {schema}.{table_name}.{column_name}")
276 }
277
278 fn anon_column(col_name: &str) -> String {
279 format!("column {}", col_name)
280 }
281 fn anon_column_type(col_name: &str, ty: &str) -> String {
282 format!("column {} {}", col_name, ty)
283 }
284}
285
286fn hover_column(db: &dyn Db, definitions: &[Location]) -> Option<Hover> {
287 let results: Vec<Hover> = definitions
288 .iter()
289 .filter_map(|def| format_hover_for_column_ptr(db, *def))
290 .collect();
291
292 merge_hovers(results)
293}
294
295fn format_hover_for_column_ptr(db: &dyn Db, def: Location) -> Option<Hover> {
296 let def_node = &def.to_node(db)?;
297 match ast_nav::parent_source(def_node)? {
298 ast_nav::ParentSouce::WithTable(with_table) => {
299 let cte_name = with_table.name()?;
300 let column_name = collect::column_name_from_node(def_node)?;
301 let table_name = Name::from_node(&cte_name);
302 let ty = collect::with_table_columns_with_types(db, def.file, with_table)
303 .into_iter()
304 .find(|(name, _)| *name == column_name)
305 .and_then(|(_, ty)| ty);
306 return Some(hover_column_with_preceding_comment(
307 match ty {
308 Some(ty) => ColumnHover::table_column_type(
309 &table_name.to_string(),
310 &column_name.to_string(),
311 &ty.to_string(),
312 ),
313 None => {
314 ColumnHover::table_column(&table_name.to_string(), &column_name.to_string())
315 }
316 },
317 def_node,
318 ));
319 }
320 ast_nav::ParentSouce::ParenSelect(paren_select) => {
321 let table_name = subquery_alias_name(&paren_select);
323
324 let column_name = collect::column_name_from_node(def_node)?;
326
327 let ty = collect::paren_select_columns_with_types(db, def.file, &paren_select)
328 .into_iter()
329 .find(|(name, _)| *name == column_name)
330 .and_then(|(_, ty)| ty)?;
331 if let Some(table_name) = table_name {
332 Some(hover_column_with_preceding_comment(
333 ColumnHover::table_column_type(
334 &table_name.to_string(),
335 &column_name.to_string(),
336 &ty.to_string(),
337 ),
338 def_node,
339 ))
340 } else {
341 Some(hover_column_with_preceding_comment(
342 ColumnHover::anon_column_type(&column_name.to_string(), &ty.to_string()),
343 def_node,
344 ))
345 }
346 }
347 ast_nav::ParentSouce::CreateView(create_view) => {
351 let column_name = collect::column_name_from_node(def_node)?;
352 let path = create_view.path()?;
353 let (schema, view_name) = resolve::resolve_view_info(db, def.file, &path)?;
354 let ty = collect::view_like_columns_with_types(db, def.file, &create_view)
355 .into_iter()
356 .find(|(name, _)| *name == column_name)
357 .and_then(|(_, ty)| ty);
358 return Some(hover_column_with_preceding_comment(
359 match ty {
360 Some(ty) => ColumnHover::schema_table_column_type(
361 &schema.to_string(),
362 &view_name,
363 &column_name.to_string(),
364 &ty.to_string(),
365 ),
366 None => ColumnHover::schema_table_column(
367 &schema.to_string(),
368 &view_name,
369 &column_name.to_string(),
370 ),
371 },
372 def_node,
373 ));
374 }
375 ast_nav::ParentSouce::Alias(alias) => {
376 let alias_name = alias.name()?;
377 alias.column_list()?;
378 let from_item = alias.syntax().ancestors().find_map(ast::FromItem::cast)?;
379 let table_name = Name::from_node(&alias_name);
380 let column_name = Name::from_string(def_node.text().to_string());
381 let ty = collect::columns_for_star_from_alias(db, def.file, &from_item, &alias)
382 .into_iter()
383 .find(|(name, _)| *name == column_name)
384 .and_then(|(_, ty)| ty);
385 return Some(hover_column_with_preceding_comment(
386 match ty {
387 Some(ty) => ColumnHover::table_column_type(
388 &table_name.to_string(),
389 &column_name.to_string(),
390 &ty.to_string(),
391 ),
392 None => {
393 ColumnHover::table_column(&table_name.to_string(), &column_name.to_string())
394 }
395 },
396 def_node,
397 ));
398 }
399 ast_nav::ParentSouce::CreateTableAs(create_table_as) => {
400 let column_name = collect::column_name_from_node(def_node)?;
401 let path = create_table_as.path()?;
402 let (schema, table_name) = resolve::resolve_table_info(db, def.file, &path)?;
403 let ty = collect::create_table_as_columns_with_types(db, def.file, &create_table_as)
404 .into_iter()
405 .find(|(name, _)| *name == column_name)
406 .and_then(|(_, ty)| ty);
407 return Some(hover_column_with_preceding_comment(
408 match ty {
409 Some(ty) => ColumnHover::schema_table_column_type(
410 &schema.to_string(),
411 &table_name,
412 &column_name.to_string(),
413 &ty.to_string(),
414 ),
415 None => ColumnHover::schema_table_column(
416 &schema.to_string(),
417 &table_name,
418 &column_name.to_string(),
419 ),
420 },
421 def_node,
422 ));
423 }
424 ast_nav::ParentSouce::CreateTable(create_table) => {
425 let column = def_node.ancestors().find_map(ast::Column::cast)?;
426 let column_name = column.name()?;
427 let ty = column.ty()?;
428 let path = create_table.path()?;
429 let (schema, table_name) = resolve::resolve_table_info(db, def.file, &path)?;
430
431 return Some(hover_column_with_preceding_comment(
432 ColumnHover::schema_table_column_type(
433 &schema.to_string(),
434 &table_name,
435 &Name::from_node(&column_name).to_string(),
436 &ty.syntax().text().to_string(),
437 ),
438 def_node,
439 ));
440 }
441 }
442}
443
444fn hover_composite_type_field(db: &dyn Db, def: Location) -> Option<Hover> {
445 let column = def.to_node(db)?.ancestors().find_map(ast::Column::cast)?;
446 let field_name = column.name()?.syntax().text().to_string();
447 let ty = column.ty()?;
448
449 let create_type = column
450 .syntax()
451 .ancestors()
452 .find_map(ast::CreateType::cast)?;
453 let type_path = create_type.path()?;
454 let (schema, type_name) = resolve::resolve_type_info(db, def.file, &type_path)?;
455
456 Some(hover_with_preceding_comment(
457 format!(
458 "field {}.{}.{} {}",
459 schema,
460 type_name,
461 field_name,
462 ty.syntax().text()
463 ),
464 column.syntax(),
465 ))
466}
467
468fn hover_column_definition(
469 db: &dyn Db,
470 file: File,
471 create_table: impl ast::HasCreateTable,
472 column: ast::Column,
473) -> Option<Hover> {
474 let column_name = column.name()?.syntax().text().to_string();
475 let ty = column.ty()?;
476 let path = create_table.path()?;
477 let (schema, table_name) = resolve::resolve_table_info(db, file, &path)?;
478 let ty = ty.syntax().text().to_string();
479 Some(hover_with_preceding_comment(
480 ColumnHover::schema_table_column_type(&schema.to_string(), &table_name, &column_name, &ty),
481 column.syntax(),
482 ))
483}
484
485fn format_table_source(db: &dyn Db, file: File, source: ast_nav::ParentSouce) -> Option<Hover> {
486 match source {
487 ast_nav::ParentSouce::Alias(alias) => format_alias_with_column_list(db, file, alias),
488 ast_nav::ParentSouce::WithTable(with_table) => format_with_table(with_table),
489 ast_nav::ParentSouce::CreateView(create_view) => {
490 format_create_view_like(db, file, create_view)
491 }
492 ast_nav::ParentSouce::CreateTable(create_table) => {
493 format_create_table(db, file, create_table)
494 }
495 ast_nav::ParentSouce::CreateTableAs(create_table_as) => {
496 format_create_table_as(db, file, create_table_as)
497 }
498 ast_nav::ParentSouce::ParenSelect(paren_select) => format_paren_select(paren_select),
499 }
500}
501
502fn hover_table(db: &dyn Db, def: Location) -> Option<Hover> {
503 let source = ast_nav::parent_source(&def.to_node(db)?)?;
504 format_table_source(db, def.file, source)
505}
506
507fn format_alias_with_column_list(db: &dyn Db, file: File, alias: ast::Alias) -> Option<Hover> {
508 let alias_name = alias.name()?;
509 let name = Name::from_node(&alias_name);
510
511 let Some(column_list) = alias.column_list() else {
512 let name = Name::from_node(&alias.name()?);
513 let from_item = alias.syntax().ancestors().find_map(ast::FromItem::cast)?;
514 let paren_select = from_item.paren_select()?;
515 return format_subquery_table(name, paren_select);
516 };
517
518 let mut columns: Vec<Name> = column_list
519 .columns()
520 .filter_map(|column| {
521 column
522 .name()
523 .map(|column_name| Name::from_node(&column_name))
524 })
525 .collect();
526
527 if let Some(from_item) = alias.syntax().ancestors().find_map(ast::FromItem::cast)
528 && let Some(table_ptr) = resolve::table_ptr_from_from_item(db, file, &from_item)
529 {
530 let base_columns = collect::star_column_names(db, file, &table_ptr);
531 for column in base_columns.iter().skip(columns.len()) {
532 columns.push(column.clone());
533 }
534 }
535
536 let columns = columns
537 .iter()
538 .map(|column| column.to_string())
539 .collect::<Vec<_>>()
540 .join(", ");
541 Some(Hover::snippet(format!("table {}({})", name, columns)))
542}
543
544fn hover_qualified_star(db: &dyn Db, file: File, field_expr: ast::FieldExpr) -> Option<Hover> {
545 let table_ptr = qualified_star_table_ptr(db, file, field_expr)?;
546 hover_qualified_star_columns(db, file, &table_ptr)
547}
548
549fn hover_unqualified_star(db: &dyn Db, file: File, target: ast::Target) -> Option<Hover> {
550 let mut results = vec![];
551 for file in [file, builtins_file(db)] {
552 results = hover_unqualified_star_with_binder(db, file, &target);
553 if results.is_empty() && target_has_schema_qualified_from_item(&target) {
554 continue;
555 } else {
556 break;
557 }
558 }
559 merge_hovers(results)
560}
561
562fn hover_unqualified_star_with_binder(db: &dyn Db, file: File, target: &ast::Target) -> Vec<Hover> {
563 let mut results = vec![];
564
565 if let Some(table_ptrs) = unqualified_star_table_ptrs(db, file, target) {
566 for table_ptr in table_ptrs {
567 if let Some(columns) = hover_qualified_star_columns(db, file, &table_ptr) {
568 results.push(columns);
569 }
570 }
571 }
572
573 results
574}
575
576fn target_has_schema_qualified_from_item(target: &ast::Target) -> bool {
577 let Some(select) = target.syntax().ancestors().find_map(ast::Select::cast) else {
578 return false;
579 };
580 let Some(from_clause) = select.from_clause() else {
581 return false;
582 };
583
584 for from_item in from_clause.from_items() {
585 if from_item.field_expr().is_some() {
586 return true;
587 }
588 }
589
590 false
591}
592
593fn hover_unqualified_star_in_arg_list(
594 db: &dyn Db,
595 file: File,
596 arg_list: ast::ArgList,
597) -> Option<Hover> {
598 let table_ptrs = unqualified_star_in_arg_list_ptrs(db, file, &arg_list)?;
599 let mut results = vec![];
600 for table_ptr in table_ptrs {
601 if let Some(columns) = hover_qualified_star_columns(db, file, &table_ptr) {
602 results.push(columns);
603 }
604 }
605
606 merge_hovers(results)
607}
608
609fn format_subquery_table(name: Name, paren_select: ast::ParenSelect) -> Option<Hover> {
610 let name = name.to_string();
611 let query = paren_select.syntax().text().to_string();
612 Some(Hover::snippet(format!("subquery {} as {}", name, query)))
613}
614
615fn hover_qualified_star_columns(
616 db: &dyn Db,
617 file: File,
618 table_ptr: &squawk_syntax::SyntaxNodePtr,
619) -> Option<Hover> {
620 let source_file = parse(db, file).tree();
621 let root = source_file.syntax();
622 let table_name_node = table_ptr.to_node(root);
623
624 match ast_nav::parent_source(&table_name_node)? {
625 ast_nav::ParentSouce::Alias(alias) => {
626 hover_qualified_star_columns_from_alias(db, file, &alias)
627 }
628 ast_nav::ParentSouce::WithTable(with_table) => {
629 hover_qualified_star_columns_from_cte(db, file, with_table)
630 }
631 ast_nav::ParentSouce::CreateTable(create_table) => {
632 hover_qualified_star_columns_from_table(db, file, create_table)
633 }
634 ast_nav::ParentSouce::CreateTableAs(create_table_as) => {
635 hover_qualified_star_columns_from_table_as(db, file, &create_table_as)
636 }
637 ast_nav::ParentSouce::CreateView(create_view) => {
638 hover_qualified_star_columns_from_view_like(db, file, &create_view)
639 }
640 ast_nav::ParentSouce::ParenSelect(paren_select) => {
641 hover_qualified_star_columns_from_subquery(db, file, &paren_select)
642 }
643 }
644}
645
646fn hover_qualified_star_columns_from_alias(
647 db: &dyn Db,
648 file: File,
649 alias: &ast::Alias,
650) -> Option<Hover> {
651 let alias_name = Name::from_node(&alias.name()?);
652 alias.column_list()?;
653 let from_item = alias.syntax().ancestors().find_map(ast::FromItem::cast)?;
654 let columns = collect::columns_for_star_from_alias(db, file, &from_item, alias);
655
656 if columns.is_empty() {
657 return None;
658 }
659
660 let results: Vec<Hover> = columns
661 .into_iter()
662 .map(|(column_name, ty)| {
663 Hover::snippet(match ty {
664 Some(ty) => ColumnHover::table_column_type(
665 &alias_name.to_string(),
666 &column_name.to_string(),
667 &ty.to_string(),
668 ),
669 None => {
670 ColumnHover::table_column(&alias_name.to_string(), &column_name.to_string())
671 }
672 })
673 })
674 .collect();
675
676 merge_hovers(results)
677}
678
679fn hover_qualified_star_columns_from_table(
680 db: &dyn Db,
681 file: File,
682 create_table: impl ast::HasCreateTable,
683) -> Option<Hover> {
684 let path = create_table.path()?;
685 let (schema, table_name) = resolve::resolve_table_info(db, file, &path)?;
686 let schema = schema.to_string();
687 let results: Vec<Hover> = collect::table_columns(db, file, &create_table)
688 .into_iter()
689 .filter_map(|(column_name, ty)| {
690 let ty = ty?;
691 Some(Hover::snippet(ColumnHover::schema_table_column_type(
692 &schema,
693 &table_name,
694 &column_name.to_string(),
695 &ty.to_string(),
696 )))
697 })
698 .collect();
699
700 merge_hovers(results)
701}
702
703fn hover_qualified_star_columns_from_table_as(
704 db: &dyn Db,
705 file: File,
706 create_table_as: &ast::CreateTableAs,
707) -> Option<Hover> {
708 let path = create_table_as.path()?;
709 let (schema, table_name) = resolve::resolve_table_info(db, file, &path)?;
710 let schema_str = schema.to_string();
711
712 let columns = collect::create_table_as_columns_with_types(db, file, create_table_as);
713 let results: Vec<Hover> = columns
714 .into_iter()
715 .map(|(column_name, ty)| {
716 if let Some(ty) = ty {
717 return Hover::snippet(ColumnHover::schema_table_column_type(
718 &schema_str,
719 &table_name,
720 &column_name.to_string(),
721 &ty.to_string(),
722 ));
723 }
724 Hover::snippet(ColumnHover::schema_table_column(
725 &schema_str,
726 &table_name,
727 &column_name.to_string(),
728 ))
729 })
730 .collect();
731
732 merge_hovers(results)
733}
734
735fn hover_qualified_star_columns_from_cte(
736 db: &dyn Db,
737 file: File,
738 with_table: ast::WithTable,
739) -> Option<Hover> {
740 let cte_name = Name::from_node(&with_table.name()?);
741 let cte_name = cte_name.to_string();
742 let columns = collect::with_table_columns_with_types(db, file, with_table);
743 let results: Vec<Hover> = columns
744 .into_iter()
745 .map(|(column_name, ty)| {
746 let column_name = column_name.to_string();
747 if let Some(ty) = ty {
748 return Hover::snippet(ColumnHover::table_column_type(
749 &cte_name,
750 &column_name,
751 &ty.to_string(),
752 ));
753 }
754
755 Hover::snippet(ColumnHover::table_column(&cte_name, &column_name))
756 })
757 .collect();
758
759 merge_hovers(results)
760}
761
762fn hover_qualified_star_columns_from_view_like(
763 db: &dyn Db,
764 file: File,
765 create_view: &ast::CreateViewLike,
766) -> Option<Hover> {
767 let path = create_view.path()?;
768 let (schema, view_name) = resolve::resolve_view_info(db, file, &path)?;
769
770 let schema_str = schema.to_string();
771 let columns = collect::view_like_columns_with_types(db, file, create_view);
772 let results: Vec<Hover> = columns
773 .into_iter()
774 .map(|(column_name, ty)| {
775 if let Some(ty) = ty {
776 return Hover::snippet(ColumnHover::schema_table_column_type(
777 &schema_str,
778 &view_name,
779 &column_name.to_string(),
780 &ty.to_string(),
781 ));
782 }
783
784 Hover::snippet(ColumnHover::schema_table_column(
785 &schema_str,
786 &view_name,
787 &column_name.to_string(),
788 ))
789 })
790 .collect();
791
792 merge_hovers(results)
793}
794
795fn hover_qualified_star_columns_from_subquery(
796 db: &dyn Db,
797 file: File,
798 paren_select: &ast::ParenSelect,
799) -> Option<Hover> {
800 let select_variant = paren_select.select()?;
801
802 if let Some(select) = ast_nav::select_from_variant(select_variant) {
803 let target_list = select.select_clause()?.target_list()?;
804
805 let mut results = vec![];
806 let subquery_alias = subquery_alias_name(paren_select);
807
808 for target in target_list.targets() {
809 if target.star_token().is_some() {
810 let table_ptrs = unqualified_star_table_ptrs(db, file, &target)?;
811 for table_ptr in table_ptrs {
812 if let Some(columns) = hover_qualified_star_columns(db, file, &table_ptr) {
813 results.push(columns)
814 }
815 }
816 continue;
817 }
818
819 if let Some(result) =
820 hover_subquery_target_column(db, file, &target, subquery_alias.as_ref())
821 {
822 results.push(result);
823 }
824 }
825
826 return merge_hovers(results);
827 }
828
829 let subquery_alias = subquery_alias_name(paren_select);
830 let results: Vec<Hover> = collect::paren_select_columns_with_types(db, file, paren_select)
831 .into_iter()
832 .map(|(column_name, ty)| {
833 if let Some(alias) = &subquery_alias {
834 return Hover::snippet(ColumnHover::table_column(
835 &alias.to_string(),
836 &column_name.to_string(),
837 ));
838 }
839 if let Some(ty) = ty {
840 return Hover::snippet(ColumnHover::anon_column_type(
841 &column_name.to_string(),
842 &ty.to_string(),
843 ));
844 }
845 Hover::snippet(ColumnHover::anon_column(&column_name.to_string()))
846 })
847 .collect();
848
849 merge_hovers(results)
850}
851
852fn subquery_alias_name(paren_select: &ast::ParenSelect) -> Option<Name> {
853 let from_item = paren_select
854 .syntax()
855 .ancestors()
856 .find_map(ast::FromItem::cast)?;
857 let alias_name = from_item.alias()?.name()?;
858 Some(Name::from_node(&alias_name))
859}
860
861fn hover_subquery_target_column(
862 db: &dyn Db,
863 file: File,
864 target: &ast::Target,
865 subquery_alias: Option<&Name>,
866) -> Option<Hover> {
867 if let Some(alias) = subquery_alias
868 && let Some((col_name, _node)) = ColumnName::from_target(target.clone())
869 && let Some(col_name) = col_name.to_string()
870 {
871 let ty = target.expr().and_then(|e| infer_type_from_expr(&e));
872 return Some(Hover::snippet(match ty {
873 Some(ty) => {
874 ColumnHover::table_column_type(&alias.to_string(), &col_name, &ty.to_string())
875 }
876 None => ColumnHover::table_column(&alias.to_string(), &col_name),
877 }));
878 }
879
880 let result = match target.expr()? {
881 ast::Expr::NameRef(name_ref) => hover(db, file, name_ref.syntax().text_range().start()),
882 ast::Expr::FieldExpr(field_expr) => {
883 let field = field_expr.field()?;
884 hover(db, file, field.syntax().text_range().start())
885 }
886 _ => None,
887 };
888
889 if result.is_some() {
890 return result;
891 }
892
893 if let Some((col_name, _node)) = ColumnName::from_target(target.clone())
894 && let Some(col_name) = col_name.to_string()
895 {
896 let ty = target.expr().and_then(|e| infer_type_from_expr(&e));
897 return Some(Hover::snippet(match ty {
898 Some(ty) => ColumnHover::anon_column_type(&col_name, &ty.to_string()),
899 None => ColumnHover::anon_column(&col_name),
900 }));
901 }
902
903 None
904}
905
906fn hover_index(db: &dyn Db, def: Location) -> Option<Hover> {
907 let create_index = def
908 .to_node(db)?
909 .ancestors()
910 .find_map(ast::CreateIndex::cast)?;
911 format_create_index(db, def.file, create_index)
912}
913
914fn hover_sequence(db: &dyn Db, def: Location) -> Option<Hover> {
915 let create_sequence = def
916 .to_node(db)?
917 .ancestors()
918 .find_map(ast::CreateSequence::cast)?;
919 format_create_sequence(db, def.file, create_sequence)
920}
921
922fn hover_trigger(db: &dyn Db, def: Location) -> Option<Hover> {
923 let create_trigger = def
924 .to_node(db)?
925 .ancestors()
926 .find_map(ast::CreateTrigger::cast)?;
927 format_create_trigger(db, def.file, create_trigger)
928}
929
930fn hover_policy(db: &dyn Db, def: Location) -> Option<Hover> {
931 let create_policy = def
932 .to_node(db)?
933 .ancestors()
934 .find_map(ast::CreatePolicy::cast)?;
935 format_create_policy(db, def.file, create_policy)
936}
937
938fn hover_property_graph(db: &dyn Db, def: Location) -> Option<Hover> {
939 let create_property_graph = def
940 .to_node(db)?
941 .ancestors()
942 .find_map(ast::CreatePropertyGraph::cast)?;
943 format_create_property_graph(db, def.file, create_property_graph)
944}
945
946fn hover_event_trigger(db: &dyn Db, def: Location) -> Option<Hover> {
947 let create_event_trigger = def
948 .to_node(db)?
949 .ancestors()
950 .find_map(ast::CreateEventTrigger::cast)?;
951
952 format_create_event_trigger(create_event_trigger)
953}
954
955fn hover_tablespace(db: &dyn Db, def: Location) -> Option<Hover> {
956 let def_node = def.to_node(db)?;
957 if let Some(create_tablespace) = def_node.ancestors().find_map(ast::CreateTablespace::cast) {
958 return format_create_tablespace(create_tablespace);
959 }
960 Some(Hover::snippet(format!("tablespace {}", def_node.text())))
961}
962
963fn hover_database(db: &dyn Db, def: Location) -> Option<Hover> {
964 let def_node = def.to_node(db)?;
965 if let Some(create_database) = def_node.ancestors().find_map(ast::CreateDatabase::cast) {
966 return format_create_database(create_database);
967 }
968 Some(Hover::snippet(format!("database {}", def_node.text())))
969}
970
971fn hover_server(db: &dyn Db, def: Location) -> Option<Hover> {
972 let def_node = def.to_node(db)?;
973 if let Some(create_server) = def_node.ancestors().find_map(ast::CreateServer::cast) {
974 return format_create_server(create_server);
975 }
976 Some(Hover::snippet(format!("server {}", def_node.text())))
977}
978
979fn hover_extension(db: &dyn Db, def: Location) -> Option<Hover> {
980 let def_node = def.to_node(db)?;
981 if let Some(create_extension) = def_node.ancestors().find_map(ast::CreateExtension::cast) {
982 return format_create_extension(create_extension);
983 }
984 Some(Hover::snippet(format!("extension {}", def_node.text())))
985}
986
987fn hover_role(db: &dyn Db, def: Location) -> Option<Hover> {
988 let def_node = def.to_node(db)?;
989 if let Some(create_role) = def_node.ancestors().find_map(ast::CreateRole::cast) {
990 return format_create_role(create_role);
991 }
992 Some(Hover::snippet(format!("role {}", def_node.text())))
993}
994
995fn hover_cursor(db: &dyn Db, def: Location) -> Option<Hover> {
996 let declare = def.to_node(db)?.ancestors().find_map(ast::Declare::cast)?;
997 format_declare_cursor(declare)
998}
999
1000fn hover_prepared_statement(db: &dyn Db, def: Location) -> Option<Hover> {
1001 let prepare = def.to_node(db)?.ancestors().find_map(ast::Prepare::cast)?;
1002 format_prepare(prepare)
1003}
1004
1005fn hover_channel(db: &dyn Db, def: Location) -> Option<Hover> {
1006 let listen = def.to_node(db)?.ancestors().find_map(ast::Listen::cast)?;
1007 format_listen(listen)
1008}
1009
1010fn hover_window(db: &dyn Db, def: Location) -> Option<Hover> {
1011 let window_def = def
1012 .to_node(db)?
1013 .ancestors()
1014 .find_map(ast::WindowDef::cast)?;
1015
1016 Some(Hover::snippet(format!(
1017 "window {}",
1018 window_def.syntax().text()
1019 )))
1020}
1021
1022fn hover_type(db: &dyn Db, def: Location) -> Option<Hover> {
1023 let create_type = def
1024 .to_node(db)?
1025 .ancestors()
1026 .find_map(ast::CreateType::cast)?;
1027 format_create_type(db, def.file, create_type)
1028}
1029
1030fn format_declare_cursor(declare: ast::Declare) -> Option<Hover> {
1031 let name = declare.name()?;
1032 let query = declare.query()?;
1033 Some(Hover::snippet(format!(
1034 "cursor {} for {}",
1035 name.syntax().text(),
1036 query.syntax().text()
1037 )))
1038}
1039
1040fn format_prepare(prepare: ast::Prepare) -> Option<Hover> {
1041 let name = prepare.name()?;
1042 let stmt = prepare.preparable_stmt()?;
1043 Some(Hover::snippet(format!(
1044 "prepare {} as {}",
1045 name.syntax().text(),
1046 stmt.syntax().text()
1047 )))
1048}
1049
1050fn format_listen(listen: ast::Listen) -> Option<Hover> {
1051 let name = listen.name()?;
1052 Some(Hover::snippet(format!("listen {}", name.syntax().text())))
1053}
1054
1055fn format_create_table(
1056 db: &dyn Db,
1057 file: File,
1058 create_table: impl ast::HasCreateTable,
1059) -> Option<Hover> {
1060 let path = create_table.path()?;
1061 let (schema, table_name) = resolve::resolve_table_info(db, file, &path)?;
1062 let schema = schema.to_string();
1063 let args = create_table.table_arg_list()?.syntax().text().to_string();
1064
1065 let foreign = if create_table.syntax().kind() == SyntaxKind::CREATE_FOREIGN_TABLE {
1066 "foreign "
1067 } else {
1068 ""
1069 };
1070
1071 Some(Hover::snippet(format!(
1072 "{foreign}table {schema}.{table_name}{args}"
1073 )))
1074}
1075
1076fn format_create_table_as(
1077 db: &dyn Db,
1078 file: File,
1079 create_table_as: ast::CreateTableAs,
1080) -> Option<Hover> {
1081 let path = create_table_as.path()?;
1082 let (schema, table_name) = resolve::resolve_table_info(db, file, &path)?;
1083 let query = create_table_as.query()?.syntax().text().to_string();
1084 Some(Hover::snippet(format!(
1085 "table {}.{} as {}",
1086 schema, table_name, query
1087 )))
1088}
1089
1090fn format_create_view(db: &dyn Db, def: Location) -> Option<Hover> {
1091 let create_view = ast::CreateViewLike::cast(def.to_node(db)?)?;
1092 format_create_view_like(db, def.file, create_view)
1093}
1094
1095fn format_create_view_like(
1096 db: &dyn Db,
1097 file: File,
1098 create_view: ast::CreateViewLike,
1099) -> Option<Hover> {
1100 let path = create_view.path()?;
1101 let (schema, view_name) = resolve::resolve_view_info(db, file, &path)?;
1104 let schema = schema.to_string();
1105
1106 let column_list = create_view
1107 .column_list()
1108 .map(|cl| cl.syntax().text().to_string())
1109 .unwrap_or_default();
1110
1111 let query = create_view.query()?.syntax().text().to_string();
1112
1113 let view_kind = if create_view.syntax().kind() == SyntaxKind::CREATE_MATERIALIZED_VIEW {
1114 "materialized view"
1115 } else {
1116 "view"
1117 };
1118
1119 Some(Hover::snippet(format!(
1120 "{view_kind} {}.{}{} as {}",
1121 schema, view_name, column_list, query
1122 )))
1123}
1124
1125fn format_view_column(
1126 db: &dyn Db,
1127 file: File,
1128 create_view: &ast::CreateViewLike,
1129 def_node: &SyntaxNode,
1130) -> Option<Hover> {
1131 let path = create_view.path()?;
1132 let (schema, view_name) = resolve::resolve_view_info(db, file, &path)?;
1133 let column_name = Name::from_string(def_node.to_string());
1134 let ty = collect::view_like_columns_with_types(db, file, create_view)
1135 .into_iter()
1136 .find(|(name, _)| *name == column_name)
1137 .and_then(|(_, ty)| ty);
1138 Some(hover_column_with_preceding_comment(
1139 match ty {
1140 Some(ty) => ColumnHover::schema_table_column_type(
1141 &schema.to_string(),
1142 &view_name,
1143 &column_name.to_string(),
1144 &ty.to_string(),
1145 ),
1146 None => ColumnHover::schema_table_column(
1147 &schema.to_string(),
1148 &view_name,
1149 &column_name.to_string(),
1150 ),
1151 },
1152 def_node,
1153 ))
1154}
1155
1156fn format_with_table(with_table: ast::WithTable) -> Option<Hover> {
1157 let name = with_table.name()?.syntax().text().to_string();
1158 let query = with_table.query()?.syntax().text().to_string();
1159 Some(Hover::snippet(format!("with {} as ({})", name, query)))
1160}
1161
1162fn format_paren_select(paren_select: ast::ParenSelect) -> Option<Hover> {
1163 let query = paren_select.select()?.syntax().text().to_string();
1164 Some(Hover::snippet(format!("({})", query)))
1165}
1166
1167fn format_create_index(db: &dyn Db, file: File, create_index: ast::CreateIndex) -> Option<Hover> {
1168 let index_name = create_index.name()?.syntax().text().to_string();
1169
1170 let index_schema = index_schema(db, file, create_index.clone())?;
1171
1172 let path = create_index.relation_name()?.path()?;
1173 let (table_schema, table_name) = resolve::resolve_table_info(db, file, &path)?;
1174
1175 let partition_item_list = create_index.partition_item_list()?;
1176 let columns = partition_item_list.syntax().text().to_string();
1177
1178 Some(Hover::snippet(format!(
1179 "index {}.{} on {}.{}{}",
1180 index_schema, index_name, table_schema, table_name, columns
1181 )))
1182}
1183
1184fn format_create_sequence(
1185 db: &dyn Db,
1186 file: File,
1187 create_sequence: ast::CreateSequence,
1188) -> Option<Hover> {
1189 let path = create_sequence.path()?;
1190 let (schema, sequence_name) = resolve::resolve_sequence_info(db, file, &path)?;
1191
1192 Some(Hover::snippet(format!(
1193 "sequence {}.{}",
1194 schema, sequence_name
1195 )))
1196}
1197
1198fn format_create_trigger(
1199 db: &dyn Db,
1200 file: File,
1201 create_trigger: ast::CreateTrigger,
1202) -> Option<Hover> {
1203 let trigger_name = create_trigger.name()?.syntax().text().to_string();
1204 let on_table_path = create_trigger.on_table()?.path()?;
1205
1206 let (schema, table_name) = resolve::resolve_table_info(db, file, &on_table_path)?;
1207 Some(Hover::snippet(format!(
1208 "trigger {}.{} on {}.{}",
1209 schema, trigger_name, schema, table_name
1210 )))
1211}
1212
1213fn format_create_policy(
1214 db: &dyn Db,
1215 file: File,
1216 create_policy: ast::CreatePolicy,
1217) -> Option<Hover> {
1218 let policy_name = create_policy.name()?.syntax().text().to_string();
1219 let on_table_path = create_policy.on_table()?.path()?;
1220
1221 let (schema, table_name) = resolve::resolve_table_info(db, file, &on_table_path)?;
1222 Some(Hover::snippet(format!(
1223 "policy {}.{} on {}.{}",
1224 schema, policy_name, schema, table_name
1225 )))
1226}
1227
1228fn format_create_property_graph(
1229 db: &dyn Db,
1230 file: File,
1231 create_property_graph: ast::CreatePropertyGraph,
1232) -> Option<Hover> {
1233 let path = create_property_graph.path()?;
1234 let (schema, name) = resolve::resolve_property_graph_info(db, file, &path)?;
1235 Some(Hover::snippet(format!(
1236 "property graph {}.{}",
1237 schema, name
1238 )))
1239}
1240
1241fn format_create_event_trigger(create_event_trigger: ast::CreateEventTrigger) -> Option<Hover> {
1242 let name = create_event_trigger.name()?.syntax().text().to_string();
1243 Some(Hover::snippet(format!("event trigger {}", name)))
1244}
1245
1246fn format_create_tablespace(create_tablespace: ast::CreateTablespace) -> Option<Hover> {
1247 let name = create_tablespace.name()?.syntax().text().to_string();
1248 Some(Hover::snippet(format!("tablespace {}", name)))
1249}
1250
1251fn format_create_database(create_database: ast::CreateDatabase) -> Option<Hover> {
1252 let name = create_database.name()?.syntax().text().to_string();
1253 Some(Hover::snippet(format!("database {}", name)))
1254}
1255
1256fn format_create_server(create_server: ast::CreateServer) -> Option<Hover> {
1257 let name = create_server.name()?.syntax().text().to_string();
1258 Some(Hover::snippet(format!("server {}", name)))
1259}
1260
1261fn format_create_extension(create_extension: ast::CreateExtension) -> Option<Hover> {
1262 let name = create_extension.name()?.syntax().text().to_string();
1263 Some(Hover::snippet(format!("extension {}", name)))
1264}
1265
1266fn format_create_role(create_role: ast::CreateRole) -> Option<Hover> {
1267 let name = create_role.name()?.syntax().text().to_string();
1268 Some(Hover::snippet(format!("role {}", name)))
1269}
1270
1271fn index_schema(db: &dyn Db, file: File, create_index: ast::CreateIndex) -> Option<String> {
1272 let position = create_index.syntax().text_range().start();
1273 bind(db, file)
1274 .search_path_at(position)
1275 .first()
1276 .map(|s| s.to_string())
1277}
1278
1279fn format_create_type(db: &dyn Db, file: File, create_type: ast::CreateType) -> Option<Hover> {
1280 let path = create_type.path()?;
1281 let (schema, type_name) = resolve::resolve_type_info(db, file, &path)?;
1282
1283 let snippet = if let Some(variant_list) = create_type.variant_list() {
1284 let variants = variant_list.syntax().text().to_string();
1285 format!("type {}.{} as enum {}", schema, type_name, variants)
1286 } else if let Some(column_list) = create_type.column_list() {
1287 let columns = column_list.syntax().text().to_string();
1288 format!("type {}.{} as {}", schema, type_name, columns)
1289 } else if let Some(attribute_list) = create_type.attribute_list() {
1290 let attributes = attribute_list.syntax().text().to_string();
1291 format!("type {}.{} {}", schema, type_name, attributes)
1292 } else {
1293 format!("type {}.{}", schema, type_name)
1294 };
1295
1296 Some(hover_with_preceding_comment(snippet, create_type.syntax()))
1297}
1298
1299fn hover_schema(db: &dyn Db, def: Location) -> Option<Hover> {
1300 let create_schema = def
1301 .to_node(db)?
1302 .ancestors()
1303 .find_map(ast::CreateSchema::cast)?;
1304 format_create_schema(create_schema)
1305}
1306
1307fn create_schema_name(create_schema: ast::CreateSchema) -> Option<String> {
1308 if let Some(schema_name) = create_schema.name() {
1309 return Some(schema_name.syntax().text().to_string());
1310 }
1311
1312 create_schema
1313 .role()
1314 .and_then(|r| r.name())
1315 .map(|n| n.syntax().text().to_string())
1316}
1317
1318fn format_create_schema(create_schema: ast::CreateSchema) -> Option<Hover> {
1319 let schema_name = create_schema_name(create_schema)?;
1320 Some(Hover::snippet(format!("schema {}", schema_name)))
1321}
1322
1323fn hover_function(db: &dyn Db, def: Location) -> Option<Hover> {
1324 let create_function = def
1325 .to_node(db)?
1326 .ancestors()
1327 .find_map(ast::CreateFunction::cast)?;
1328 format_create_function(db, def.file, create_function)
1329}
1330
1331fn hover_named_arg_parameter(db: &dyn Db, def: Location) -> Option<Hover> {
1332 let def_node = def.to_node(db)?;
1333 let param = def_node.ancestors().find_map(ast::Param::cast)?;
1334 let param_name = param.name().map(|name| Name::from_node(&name))?;
1335 let param_type = param.ty().map(|ty| ty.syntax().text().to_string());
1336
1337 for ancestor in def_node.ancestors() {
1338 if let Some(create_function) = ast::CreateFunction::cast(ancestor.clone()) {
1339 let path = create_function.path()?;
1340 let (schema, function_name) = resolve::resolve_function_info(db, def.file, &path)?;
1341 return Some(format_param_hover(
1342 schema,
1343 function_name,
1344 param_name,
1345 param_type,
1346 ));
1347 }
1348 if let Some(create_procedure) = ast::CreateProcedure::cast(ancestor.clone()) {
1349 let path = create_procedure.path()?;
1350 let (schema, procedure_name) = resolve::resolve_procedure_info(db, def.file, &path)?;
1351 return Some(format_param_hover(
1352 schema,
1353 procedure_name,
1354 param_name,
1355 param_type,
1356 ));
1357 }
1358 if let Some(create_aggregate) = ast::CreateAggregate::cast(ancestor) {
1359 let path = create_aggregate.path()?;
1360 let (schema, aggregate_name) = resolve::resolve_aggregate_info(db, def.file, &path)?;
1361 return Some(format_param_hover(
1362 schema,
1363 aggregate_name,
1364 param_name,
1365 param_type,
1366 ));
1367 }
1368 }
1369
1370 None
1371}
1372
1373fn format_param_hover(
1374 schema: Schema,
1375 routine_name: String,
1376 param_name: Name,
1377 param_type: Option<String>,
1378) -> Hover {
1379 if let Some(param_type) = param_type {
1380 return Hover::snippet(format!(
1381 "parameter {}.{}.{} {}",
1382 schema, routine_name, param_name, param_type
1383 ));
1384 }
1385
1386 Hover::snippet(format!(
1387 "parameter {}.{}.{}",
1388 schema, routine_name, param_name
1389 ))
1390}
1391
1392fn format_create_function(
1393 db: &dyn Db,
1394 file: File,
1395 create_function: ast::CreateFunction,
1396) -> Option<Hover> {
1397 let path = create_function.path()?;
1398 let (schema, function_name) = resolve::resolve_function_info(db, file, &path)?;
1399
1400 let params = create_function.param_list()?.syntax().text().to_string();
1401 let return_type = create_function.ret_type()?.syntax().text().to_string();
1402 let snippet = format!(
1403 "function {}.{}{} {}",
1404 schema, function_name, params, return_type
1405 );
1406
1407 Some(hover_with_preceding_comment(
1408 snippet,
1409 create_function.syntax(),
1410 ))
1411}
1412
1413fn hover_aggregate(db: &dyn Db, def: Location) -> Option<Hover> {
1414 let create_aggregate = def
1415 .to_node(db)?
1416 .ancestors()
1417 .find_map(ast::CreateAggregate::cast)?;
1418 format_create_aggregate(db, def.file, create_aggregate)
1419}
1420
1421fn format_create_aggregate(
1422 db: &dyn Db,
1423 file: File,
1424 create_aggregate: ast::CreateAggregate,
1425) -> Option<Hover> {
1426 let path = create_aggregate.path()?;
1427 let (schema, aggregate_name) = resolve::resolve_aggregate_info(db, file, &path)?;
1428
1429 let param_list = create_aggregate.param_list()?;
1430 let params = param_list.syntax().text().to_string();
1431
1432 Some(Hover::snippet(format!(
1433 "aggregate {}.{}{}",
1434 schema, aggregate_name, params
1435 )))
1436}
1437
1438fn hover_procedure(db: &dyn Db, def: Location) -> Option<Hover> {
1439 let create_procedure = def
1440 .to_node(db)?
1441 .ancestors()
1442 .find_map(ast::CreateProcedure::cast)?;
1443 format_create_procedure(db, def.file, create_procedure)
1444}
1445
1446fn format_create_procedure(
1447 db: &dyn Db,
1448 file: File,
1449 create_procedure: ast::CreateProcedure,
1450) -> Option<Hover> {
1451 let path = create_procedure.path()?;
1452 let (schema, procedure_name) = resolve::resolve_procedure_info(db, file, &path)?;
1453
1454 let param_list = create_procedure.param_list()?;
1455 let params = param_list.syntax().text().to_string();
1456
1457 Some(Hover::snippet(format!(
1458 "procedure {}.{}{}",
1459 schema, procedure_name, params
1460 )))
1461}
1462
1463fn hover_routine(db: &dyn Db, def: Location) -> Option<Hover> {
1464 for ancestor in def.to_node(db)?.ancestors() {
1465 if let Some(create_function) = ast::CreateFunction::cast(ancestor.clone()) {
1466 return format_create_function(db, def.file, create_function);
1467 }
1468 if let Some(create_aggregate) = ast::CreateAggregate::cast(ancestor.clone()) {
1469 return format_create_aggregate(db, def.file, create_aggregate);
1470 }
1471 if let Some(create_procedure) = ast::CreateProcedure::cast(ancestor) {
1472 return format_create_procedure(db, def.file, create_procedure);
1473 }
1474 }
1475
1476 None
1477}
1478
1479fn qualified_star_table_ptr(
1480 db: &dyn Db,
1481 file: File,
1482 field_expr: ast::FieldExpr,
1483) -> Option<SyntaxNodePtr> {
1484 let table_name = resolve::qualified_star_table_name(&field_expr)?;
1485 let position = field_expr.syntax().text_range().start();
1486 let target = field_expr
1487 .syntax()
1488 .ancestors()
1489 .find_map(ast::Target::cast)?;
1490
1491 let path = match ast_nav::target_parent_query(target)? {
1492 ast_nav::ParentQuery::Select(select) => {
1493 let from_clause = select.from_clause()?;
1494 let from_item = resolve::find_from_item_in_from_clause(&from_clause, &table_name)?;
1495
1496 if let Some(alias) = from_item.alias()
1497 && alias.column_list().is_some()
1498 {
1499 return Some(SyntaxNodePtr::new(alias.syntax()));
1500 }
1501
1502 let (schema, table_name) = name::schema_and_table_from_from_item(&from_item)?;
1503
1504 let name_ref = from_item.name_ref();
1505 if let Some((table_like_ptr, _kind)) = resolve::resolve_table_like(
1506 db,
1507 file,
1508 name_ref.as_ref(),
1509 &table_name,
1510 schema.as_ref(),
1511 position,
1512 ) {
1513 return Some(table_like_ptr);
1514 }
1515
1516 return None;
1517 }
1518 ast_nav::ParentQuery::Update(update) => update.relation_name()?.path()?,
1519 ast_nav::ParentQuery::Delete(delete) => delete.relation_name()?.path()?,
1520 ast_nav::ParentQuery::Insert(insert) => insert.path()?,
1521 ast_nav::ParentQuery::Merge(merge) => merge.relation_name()?.path()?,
1522 };
1523
1524 table_or_view_or_cte_ptrs(db, file, position, &path)?
1525 .into_iter()
1526 .next()
1527}
1528
1529fn table_or_view_or_cte_ptrs(
1530 db: &dyn Db,
1531 file: File,
1532 position: TextSize,
1533 path: &ast::Path,
1534) -> Option<Vec<SyntaxNodePtr>> {
1535 let (schema, table_name) = name::schema_and_name_path(path)?;
1536 let mut results = vec![];
1537 let name_ref = path.segment().and_then(|x| x.name_ref());
1538
1539 if let Some((table_like_ptr, _kind)) = resolve::resolve_table_like(
1540 db,
1541 file,
1542 name_ref.as_ref(),
1543 &table_name,
1544 schema.as_ref(),
1545 position,
1546 ) {
1547 results.push(table_like_ptr);
1548 }
1549
1550 if results.is_empty() {
1551 return None;
1552 }
1553 Some(results)
1554}
1555
1556fn unqualified_star_table_ptrs(
1557 db: &dyn Db,
1558 file: File,
1559 target: &ast::Target,
1560) -> Option<Vec<SyntaxNodePtr>> {
1561 target.star_token()?;
1562
1563 let path = match ast_nav::target_parent_query(target.clone())? {
1564 ast_nav::ParentQuery::Select(select) => {
1565 let from_clause = select.from_clause()?;
1566 let results = resolve::table_ptrs_from_clause(db, file, &from_clause);
1567 if results.is_empty() {
1568 return None;
1569 }
1570 return Some(results);
1571 }
1572 ast_nav::ParentQuery::Update(update) => update.relation_name()?.path(),
1573 ast_nav::ParentQuery::Insert(insert) => insert.path(),
1574 ast_nav::ParentQuery::Delete(delete) => delete.relation_name()?.path(),
1575 ast_nav::ParentQuery::Merge(merge) => merge.relation_name()?.path(),
1576 }?;
1577
1578 let position = target.syntax().text_range().start();
1579 table_or_view_or_cte_ptrs(db, file, position, &path)
1580}
1581
1582fn unqualified_star_in_arg_list_ptrs(
1583 db: &dyn Db,
1584 file: File,
1585 arg_list: &ast::ArgList,
1586) -> Option<Vec<SyntaxNodePtr>> {
1587 let from_clause = arg_list
1588 .syntax()
1589 .ancestors()
1590 .find_map(ast::Select::cast)?
1591 .from_clause()?;
1592 let results = resolve::table_ptrs_from_clause(db, file, &from_clause);
1593
1594 if results.is_empty() {
1595 return None;
1596 }
1597
1598 Some(results)
1599}
1600
1601#[cfg(test)]
1602mod test {
1603 use crate::db::{Database, File};
1604 use crate::hover::hover;
1605 use crate::test_utils::Fixture;
1606 use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet, renderer::DecorStyle};
1607 use insta::assert_snapshot;
1608
1609 #[must_use]
1610 #[track_caller]
1611 fn check_hover(sql: &str) -> String {
1612 check_hover_(sql).expect("should find hover information")
1613 }
1614
1615 #[track_caller]
1616 fn check_hover_(sql: &str) -> Option<String> {
1617 let db = Database::default();
1618 let fixture = Fixture::new(sql);
1619 let marker = fixture.marker();
1620 let offset = marker.offset_before();
1621 let hover_span = marker.range();
1622 let sql = fixture.sql();
1623 let file = File::new(&db, sql.into());
1624 assert_eq!(crate::db::parse(&db, file).errors(), vec![]);
1625
1626 if let Some(type_info) = hover(&db, file, offset) {
1627 let title = format!("hover: {}", type_info.snippet);
1628 let group = Level::INFO.primary_title(&title).element(
1629 Snippet::source(sql)
1630 .fold(true)
1631 .annotation(AnnotationKind::Context.span(hover_span).label("hover")),
1632 );
1633 let renderer = Renderer::plain().decor_style(DecorStyle::Unicode);
1634 return Some(
1635 renderer
1636 .render(&[group])
1637 .to_string()
1638 .replace("info: hover:", "hover:"),
1640 );
1641 }
1642 None
1643 }
1644
1645 #[must_use]
1646 #[track_caller]
1647 fn check_hover_info(sql: &str) -> super::Hover {
1648 let db = Database::default();
1649 let fixture = Fixture::new(sql);
1650 let offset = fixture.marker().offset_before();
1651 let sql = fixture.sql();
1652 let file = File::new(&db, sql.into());
1653 assert_eq!(crate::db::parse(&db, file).errors(), vec![]);
1654
1655 hover(&db, file, offset).expect("should find hover information")
1656 }
1657
1658 #[test]
1659 fn hover_column_in_create_index() {
1660 assert_snapshot!(check_hover("
1661create table users(id int, email text);
1662create index idx_email on users(email$0);
1663"), @r"
1664 hover: column public.users.email text
1665 ╭▸
1666 3 │ create index idx_email on users(email);
1667 ╰╴ ─ hover
1668 ");
1669 }
1670
1671 #[test]
1672 fn hover_column_int_type() {
1673 assert_snapshot!(check_hover("
1674create table users(id int, email text);
1675create index idx_id on users(id$0);
1676"), @r"
1677 hover: column public.users.id int
1678 ╭▸
1679 3 │ create index idx_id on users(id);
1680 ╰╴ ─ hover
1681 ");
1682 }
1683
1684 #[test]
1685 fn hover_column_with_schema() {
1686 assert_snapshot!(check_hover("
1687create table public.users(id int, email text);
1688create index idx_email on public.users(email$0);
1689"), @r"
1690 hover: column public.users.email text
1691 ╭▸
1692 3 │ create index idx_email on public.users(email);
1693 ╰╴ ─ hover
1694 ");
1695 }
1696
1697 #[test]
1698 fn hover_column_temp_table() {
1699 assert_snapshot!(check_hover("
1700create temp table users(id int, email text);
1701create index idx_email on users(email$0);
1702"), @r"
1703 hover: column pg_temp.users.email text
1704 ╭▸
1705 3 │ create index idx_email on users(email);
1706 ╰╴ ─ hover
1707 ");
1708 }
1709
1710 #[test]
1711 fn hover_column_multiple_columns() {
1712 assert_snapshot!(check_hover("
1713create table users(id int, email text, name varchar(100));
1714create index idx_users on users(id, email$0, name);
1715"), @r"
1716 hover: column public.users.email text
1717 ╭▸
1718 3 │ create index idx_users on users(id, email, name);
1719 ╰╴ ─ hover
1720 ");
1721 }
1722
1723 #[test]
1724 fn hover_column_varchar() {
1725 assert_snapshot!(check_hover("
1726create table users(id int, name varchar(100));
1727create index idx_name on users(name$0);
1728"), @r"
1729 hover: column public.users.name varchar(100)
1730 ╭▸
1731 3 │ create index idx_name on users(name);
1732 ╰╴ ─ hover
1733 ");
1734 }
1735
1736 #[test]
1737 fn hover_column_bigint() {
1738 assert_snapshot!(check_hover("
1739create table metrics(value bigint);
1740create index idx_value on metrics(value$0);
1741"), @r"
1742 hover: column public.metrics.value bigint
1743 ╭▸
1744 3 │ create index idx_value on metrics(value);
1745 ╰╴ ─ hover
1746 ");
1747 }
1748
1749 #[test]
1750 fn hover_column_timestamp() {
1751 assert_snapshot!(check_hover("
1752create table events(created_at timestamp with time zone);
1753create index idx_created on events(created_at$0);
1754"), @r"
1755 hover: column public.events.created_at timestamp with time zone
1756 ╭▸
1757 3 │ create index idx_created on events(created_at);
1758 ╰╴ ─ hover
1759 ");
1760 }
1761
1762 #[test]
1763 fn hover_column_with_search_path() {
1764 assert_snapshot!(check_hover(r#"
1765set search_path to myschema;
1766create table myschema.users(id int, email text);
1767create index idx_email on users(email$0);
1768"#), @r"
1769 hover: column myschema.users.email text
1770 ╭▸
1771 4 │ create index idx_email on users(email);
1772 ╰╴ ─ hover
1773 ");
1774 }
1775
1776 #[test]
1777 fn hover_column_explicit_schema_overrides_search_path() {
1778 assert_snapshot!(check_hover(r#"
1779set search_path to myschema;
1780create table public.users(id int, email text);
1781create table myschema.users(value bigint);
1782create index idx_email on public.users(email$0);
1783"#), @r"
1784 hover: column public.users.email text
1785 ╭▸
1786 5 │ create index idx_email on public.users(email);
1787 ╰╴ ─ hover
1788 ");
1789 }
1790
1791 #[test]
1792 fn hover_on_table_name() {
1793 assert_snapshot!(check_hover("
1794create table t(id int);
1795create index idx on t$0(id);
1796"), @r"
1797 hover: table public.t(id int)
1798 ╭▸
1799 3 │ create index idx on t(id);
1800 ╰╴ ─ hover
1801 ");
1802 }
1803
1804 #[test]
1805 fn hover_on_index_name_in_create() {
1806 assert_snapshot!(check_hover("
1807create table users(id int);
1808create index idx$0 on users(id);
1809"), @r"
1810 hover: index public.idx on public.users(id)
1811 ╭▸
1812 3 │ create index idx on users(id);
1813 ╰╴ ─ hover
1814 ");
1815 }
1816
1817 #[test]
1818 fn hover_table_in_create_index() {
1819 assert_snapshot!(check_hover("
1820create table users(id int, email text);
1821create index idx_email on users$0(email);
1822"), @r"
1823 hover: table public.users(id int, email text)
1824 ╭▸
1825 3 │ create index idx_email on users(email);
1826 ╰╴ ─ hover
1827 ");
1828 }
1829
1830 #[test]
1831 fn hover_table_with_schema() {
1832 assert_snapshot!(check_hover("
1833create table public.users(id int, email text);
1834create index idx on public.users$0(id);
1835"), @r"
1836 hover: table public.users(id int, email text)
1837 ╭▸
1838 3 │ create index idx on public.users(id);
1839 ╰╴ ─ hover
1840 ");
1841 }
1842
1843 #[test]
1844 fn hover_table_temp() {
1845 assert_snapshot!(check_hover("
1846create temp table users(id int, email text);
1847create index idx on users$0(id);
1848"), @r"
1849 hover: table pg_temp.users(id int, email text)
1850 ╭▸
1851 3 │ create index idx on users(id);
1852 ╰╴ ─ hover
1853 ");
1854 }
1855
1856 #[test]
1857 fn hover_table_multiline() {
1858 assert_snapshot!(check_hover("
1859create table users(
1860 id int,
1861 email text,
1862 name varchar(100)
1863);
1864create index idx on users$0(id);
1865"), @r"
1866 hover: table public.users(
1867 id int,
1868 email text,
1869 name varchar(100)
1870 )
1871 ╭▸
1872 7 │ create index idx on users(id);
1873 ╰╴ ─ hover
1874 ");
1875 }
1876
1877 #[test]
1878 fn hover_table_with_search_path() {
1879 assert_snapshot!(check_hover(r#"
1880set search_path to myschema;
1881create table users(id int, email text);
1882create index idx on users$0(id);
1883"#), @r"
1884 hover: table myschema.users(id int, email text)
1885 ╭▸
1886 4 │ create index idx on users(id);
1887 ╰╴ ─ hover
1888 ");
1889 }
1890
1891 #[test]
1892 fn hover_table_search_path_at_definition() {
1893 assert_snapshot!(check_hover(r#"
1894set search_path to myschema;
1895create table users(id int, email text);
1896set search_path to myschema, otherschema;
1897create index idx on users$0(id);
1898"#), @r"
1899 hover: table myschema.users(id int, email text)
1900 ╭▸
1901 5 │ create index idx on users(id);
1902 ╰╴ ─ hover
1903 ");
1904 }
1905
1906 #[test]
1907 fn hover_on_create_table_definition() {
1908 assert_snapshot!(check_hover("
1909create table t$0(x bigint);
1910"), @r"
1911 hover: table public.t(x bigint)
1912 ╭▸
1913 2 │ create table t(x bigint);
1914 ╰╴ ─ hover
1915 ");
1916 }
1917
1918 #[test]
1919 fn hover_on_create_table_definition_with_schema() {
1920 assert_snapshot!(check_hover("
1921create table myschema.users$0(id int);
1922"), @r"
1923 hover: table myschema.users(id int)
1924 ╭▸
1925 2 │ create table myschema.users(id int);
1926 ╰╴ ─ hover
1927 ");
1928 }
1929
1930 #[test]
1931 fn hover_on_create_temp_table_definition() {
1932 assert_snapshot!(check_hover("
1933create temp table t$0(x bigint);
1934"), @r"
1935 hover: table pg_temp.t(x bigint)
1936 ╭▸
1937 2 │ create temp table t(x bigint);
1938 ╰╴ ─ hover
1939 ");
1940 }
1941
1942 #[test]
1943 fn hover_on_column_in_create_table() {
1944 assert_snapshot!(check_hover("
1945create table t(id$0 int);
1946"), @r"
1947 hover: column public.t.id int
1948 ╭▸
1949 2 │ create table t(id int);
1950 ╰╴ ─ hover
1951 ");
1952 }
1953
1954 #[test]
1955 fn hover_on_column_in_create_table_with_schema() {
1956 assert_snapshot!(check_hover("
1957create table myschema.users(id$0 int, name text);
1958"), @r"
1959 hover: column myschema.users.id int
1960 ╭▸
1961 2 │ create table myschema.users(id int, name text);
1962 ╰╴ ─ hover
1963 ");
1964 }
1965
1966 #[test]
1967 fn hover_on_column_in_temp_table() {
1968 assert_snapshot!(check_hover("
1969create temp table t(x$0 bigint);
1970"), @r"
1971 hover: column pg_temp.t.x bigint
1972 ╭▸
1973 2 │ create temp table t(x bigint);
1974 ╰╴ ─ hover
1975 ");
1976 }
1977
1978 #[test]
1979 fn hover_on_multiple_columns() {
1980 assert_snapshot!(check_hover("
1981create table t(id int, email$0 text, name varchar(100));
1982"), @r"
1983 hover: column public.t.email text
1984 ╭▸
1985 2 │ create table t(id int, email text, name varchar(100));
1986 ╰╴ ─ hover
1987 ");
1988 }
1989
1990 #[test]
1991 fn hover_on_drop_table() {
1992 assert_snapshot!(check_hover("
1993create table users(id int, email text);
1994drop table users$0;
1995"), @r"
1996 hover: table public.users(id int, email text)
1997 ╭▸
1998 3 │ drop table users;
1999 ╰╴ ─ hover
2000 ");
2001 }
2002
2003 #[test]
2004 fn hover_on_drop_table_with_schema() {
2005 assert_snapshot!(check_hover("
2006create table myschema.users(id int);
2007drop table myschema.users$0;
2008"), @r"
2009 hover: table myschema.users(id int)
2010 ╭▸
2011 3 │ drop table myschema.users;
2012 ╰╴ ─ hover
2013 ");
2014 }
2015
2016 #[test]
2017 fn hover_on_drop_temp_table() {
2018 assert_snapshot!(check_hover("
2019create temp table t(x bigint);
2020drop table t$0;
2021"), @r"
2022 hover: table pg_temp.t(x bigint)
2023 ╭▸
2024 3 │ drop table t;
2025 ╰╴ ─ hover
2026 ");
2027 }
2028
2029 #[test]
2030 fn hover_on_create_index_definition() {
2031 assert_snapshot!(check_hover("
2032create table t(x bigint);
2033create index idx$0 on t(x);
2034"), @r"
2035 hover: index public.idx on public.t(x)
2036 ╭▸
2037 3 │ create index idx on t(x);
2038 ╰╴ ─ hover
2039 ");
2040 }
2041
2042 #[test]
2043 fn hover_on_drop_index() {
2044 assert_snapshot!(check_hover("
2045create table t(x bigint);
2046create index idx_x on t(x);
2047drop index idx_x$0;
2048"), @r"
2049 hover: index public.idx_x on public.t(x)
2050 ╭▸
2051 4 │ drop index idx_x;
2052 ╰╴ ─ hover
2053 ");
2054 }
2055
2056 #[test]
2057 fn hover_on_create_type_definition() {
2058 assert_snapshot!(check_hover("
2059create type status$0 as enum ('active', 'inactive');
2060"), @r"
2061 hover: type public.status as enum ('active', 'inactive')
2062 ╭▸
2063 2 │ create type status as enum ('active', 'inactive');
2064 ╰╴ ─ hover
2065 ");
2066 }
2067
2068 #[test]
2069 fn hover_on_create_type_definition_with_schema() {
2070 assert_snapshot!(check_hover("
2071create type myschema.status$0 as enum ('active', 'inactive');
2072"), @r"
2073 hover: type myschema.status as enum ('active', 'inactive')
2074 ╭▸
2075 2 │ create type myschema.status as enum ('active', 'inactive');
2076 ╰╴ ─ hover
2077 ");
2078 }
2079
2080 #[test]
2081 fn hover_on_drop_type() {
2082 assert_snapshot!(check_hover("
2083create type status as enum ('active', 'inactive');
2084drop type status$0;
2085"), @r"
2086 hover: type public.status as enum ('active', 'inactive')
2087 ╭▸
2088 3 │ drop type status;
2089 ╰╴ ─ hover
2090 ");
2091 }
2092
2093 #[test]
2094 fn hover_on_drop_type_with_schema() {
2095 assert_snapshot!(check_hover("
2096create type myschema.status as enum ('active', 'inactive');
2097drop type myschema.status$0;
2098"), @r"
2099 hover: type myschema.status as enum ('active', 'inactive')
2100 ╭▸
2101 3 │ drop type myschema.status;
2102 ╰╴ ─ hover
2103 ");
2104 }
2105
2106 #[test]
2107 fn hover_on_create_type_composite() {
2108 assert_snapshot!(check_hover("
2109create type person$0 as (name text, age int);
2110"), @r"
2111 hover: type public.person as (name text, age int)
2112 ╭▸
2113 2 │ create type person as (name text, age int);
2114 ╰╴ ─ hover
2115 ");
2116 }
2117
2118 #[test]
2119 fn hover_on_drop_type_composite() {
2120 assert_snapshot!(check_hover("
2121create type person as (name text, age int);
2122drop type person$0;
2123"), @r"
2124 hover: type public.person as (name text, age int)
2125 ╭▸
2126 3 │ drop type person;
2127 ╰╴ ─ hover
2128 ");
2129 }
2130
2131 #[test]
2132 fn hover_on_create_type_range() {
2133 assert_snapshot!(check_hover("
2134create type int4_range$0 as range (subtype = int4);
2135"), @r"
2136 hover: type public.int4_range (subtype = int4)
2137 ╭▸
2138 2 │ create type int4_range as range (subtype = int4);
2139 ╰╴ ─ hover
2140 ");
2141 }
2142
2143 #[test]
2144 fn hover_on_drop_type_range() {
2145 assert_snapshot!(check_hover("
2146create type int4_range as range (subtype = int4);
2147drop type int4_range$0;
2148"), @r"
2149 hover: type public.int4_range (subtype = int4)
2150 ╭▸
2151 3 │ drop type int4_range;
2152 ╰╴ ─ hover
2153 ");
2154 }
2155
2156 #[test]
2157 fn hover_on_cast_operator() {
2158 assert_snapshot!(check_hover("
2159create type foo as enum ('a', 'b');
2160select x::foo$0;
2161"), @r"
2162 hover: type public.foo as enum ('a', 'b')
2163 ╭▸
2164 3 │ select x::foo;
2165 ╰╴ ─ hover
2166 ");
2167 }
2168
2169 #[test]
2170 fn hover_on_cast_function() {
2171 assert_snapshot!(check_hover("
2172create type bar as enum ('x', 'y');
2173select cast(x as bar$0);
2174"), @r"
2175 hover: type public.bar as enum ('x', 'y')
2176 ╭▸
2177 3 │ select cast(x as bar);
2178 ╰╴ ─ hover
2179 ");
2180 }
2181
2182 #[test]
2183 fn hover_on_cast_with_schema() {
2184 assert_snapshot!(check_hover("
2185create type myschema.baz as enum ('m', 'n');
2186select x::myschema.baz$0;
2187"), @r"
2188 hover: type myschema.baz as enum ('m', 'n')
2189 ╭▸
2190 3 │ select x::myschema.baz;
2191 ╰╴ ─ hover
2192 ");
2193 }
2194
2195 #[test]
2196 fn hover_on_drop_function() {
2197 assert_snapshot!(check_hover("
2198create function foo() returns int as $$ select 1 $$ language sql;
2199drop function foo$0();
2200"), @r"
2201 hover: function public.foo() returns int
2202 ╭▸
2203 3 │ drop function foo();
2204 ╰╴ ─ hover
2205 ");
2206 }
2207
2208 #[test]
2209 fn hover_on_drop_function_with_schema() {
2210 assert_snapshot!(check_hover("
2211create function myschema.foo() returns int as $$ select 1 $$ language sql;
2212drop function myschema.foo$0();
2213"), @r"
2214 hover: function myschema.foo() returns int
2215 ╭▸
2216 3 │ drop function myschema.foo();
2217 ╰╴ ─ hover
2218 ");
2219 }
2220
2221 #[test]
2222 fn hover_on_create_function_definition() {
2223 assert_snapshot!(check_hover("
2224create function foo$0() returns int as $$ select 1 $$ language sql;
2225"), @r"
2226 hover: function public.foo() returns int
2227 ╭▸
2228 2 │ create function foo() returns int as $$ select 1 $$ language sql;
2229 ╰╴ ─ hover
2230 ");
2231 }
2232
2233 #[test]
2234 fn hover_on_create_function_with_explicit_schema() {
2235 assert_snapshot!(check_hover("
2236create function myschema.foo$0() returns int as $$ select 1 $$ language sql;
2237"), @r"
2238 hover: function myschema.foo() returns int
2239 ╭▸
2240 2 │ create function myschema.foo() returns int as $$ select 1 $$ language sql;
2241 ╰╴ ─ hover
2242 ");
2243 }
2244
2245 #[test]
2246 fn hover_function_extracts_preceding_comment() {
2247 let hover = check_hover_info(
2248 "
2249-- this is a doc comment
2250-- for foo
2251create function foo() returns int as $$ select 1 $$ language sql;
2252select foo$0();
2253",
2254 );
2255 assert_snapshot!(hover.markdown(), @"
2256 ```sql
2257 function public.foo() returns int
2258 ```
2259 ---
2260 this is a doc comment
2261 for foo
2262 ");
2263 }
2264
2265 #[test]
2266 fn hover_type_extracts_preceding_comment() {
2267 let hover = check_hover_info(
2268 "
2269-- this is a doc comment
2270-- for foo
2271create type foo as enum ('a', 'b');
2272select 1::foo$0;
2273",
2274 );
2275 assert_snapshot!(hover.markdown(), @"
2276 ```sql
2277 type public.foo as enum ('a', 'b')
2278 ```
2279 ---
2280 this is a doc comment
2281 for foo
2282 ");
2283 }
2284
2285 #[test]
2286 fn hover_bigint_extracts_preceding_comment_from_int8_definition() {
2287 let hover = check_hover_info(
2288 "
2289-- 64-bit integer
2290create type pg_catalog.int8;
2291select 1::bigint$0;
2292",
2293 );
2294 assert_snapshot!(hover.markdown(), @"
2295 ```sql
2296 type pg_catalog.int8
2297 ```
2298 ---
2299 64-bit integer
2300 ");
2301 }
2302
2303 #[test]
2304 fn hover_text_type() {
2305 let hover = check_hover_info(
2306 "
2307-- variable-length string, no limit specified
2308--
2309-- size: -1, align: 4
2310create type pg_catalog.text;
2311select '1'::text$0;
2312",
2313 );
2314 assert_snapshot!(hover.markdown(), @"
2315 ```sql
2316 type pg_catalog.text
2317 ```
2318 ---
2319 variable-length string, no limit specified
2320 size: -1, align: 4
2321 ");
2322 }
2323
2324 #[test]
2325 fn hover_column_extracts_preceding_comment() {
2326 let hover = check_hover_info(
2327 "
2328create table users(
2329 -- email address
2330 email text
2331);
2332select email$0 from users;
2333",
2334 );
2335 assert_snapshot!(hover.markdown(), @"
2336 ```sql
2337 column public.users.email text
2338 ```
2339 ---
2340 email address
2341 ");
2342 }
2343
2344 #[test]
2345 fn hover_create_table_column_extracts_preceding_comment() {
2346 let hover = check_hover_info(
2347 "
2348create table users(
2349 -- email address
2350 email$0 text
2351);
2352",
2353 );
2354 assert_snapshot!(hover.markdown(), @"
2355 ```sql
2356 column public.users.email text
2357 ```
2358 ---
2359 email address
2360 ");
2361 }
2362
2363 #[test]
2364 fn hover_on_drop_function_with_search_path() {
2365 assert_snapshot!(check_hover(r#"
2366set search_path to myschema;
2367create function foo() returns int as $$ select 1 $$ language sql;
2368drop function foo$0();
2369"#), @r"
2370 hover: function myschema.foo() returns int
2371 ╭▸
2372 4 │ drop function foo();
2373 ╰╴ ─ hover
2374 ");
2375 }
2376
2377 #[test]
2378 fn hover_on_drop_function_overloaded() {
2379 assert_snapshot!(check_hover("
2380create function add(complex) returns complex as $$ select null $$ language sql;
2381create function add(bigint) returns bigint as $$ select 1 $$ language sql;
2382drop function add$0(complex);
2383"), @r"
2384 hover: function public.add(complex) returns complex
2385 ╭▸
2386 4 │ drop function add(complex);
2387 ╰╴ ─ hover
2388 ");
2389 }
2390
2391 #[test]
2392 fn hover_on_drop_function_second_overload() {
2393 assert_snapshot!(check_hover("
2394create function add(complex) returns complex as $$ select null $$ language sql;
2395create function add(bigint) returns bigint as $$ select 1 $$ language sql;
2396drop function add$0(bigint);
2397"), @r"
2398 hover: function public.add(bigint) returns bigint
2399 ╭▸
2400 4 │ drop function add(bigint);
2401 ╰╴ ─ hover
2402 ");
2403 }
2404
2405 #[test]
2406 fn hover_on_drop_aggregate() {
2407 assert_snapshot!(check_hover("
2408create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2409drop aggregate myavg$0(int);
2410"), @r"
2411 hover: aggregate public.myavg(int)
2412 ╭▸
2413 3 │ drop aggregate myavg(int);
2414 ╰╴ ─ hover
2415 ");
2416 }
2417
2418 #[test]
2419 fn hover_on_drop_aggregate_with_schema() {
2420 assert_snapshot!(check_hover("
2421create aggregate myschema.myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2422drop aggregate myschema.myavg$0(int);
2423"), @r"
2424 hover: aggregate myschema.myavg(int)
2425 ╭▸
2426 3 │ drop aggregate myschema.myavg(int);
2427 ╰╴ ─ hover
2428 ");
2429 }
2430
2431 #[test]
2432 fn hover_on_create_aggregate_definition() {
2433 assert_snapshot!(check_hover("
2434create aggregate myavg$0(int) (sfunc = int4_avg_accum, stype = _int8);
2435"), @r"
2436 hover: aggregate public.myavg(int)
2437 ╭▸
2438 2 │ create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2439 ╰╴ ─ hover
2440 ");
2441 }
2442
2443 #[test]
2444 fn hover_on_drop_aggregate_with_search_path() {
2445 assert_snapshot!(check_hover(r#"
2446set search_path to myschema;
2447create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2448drop aggregate myavg$0(int);
2449"#), @r"
2450 hover: aggregate myschema.myavg(int)
2451 ╭▸
2452 4 │ drop aggregate myavg(int);
2453 ╰╴ ─ hover
2454 ");
2455 }
2456
2457 #[test]
2458 fn hover_on_drop_aggregate_overloaded() {
2459 assert_snapshot!(check_hover("
2460create aggregate sum(complex) (sfunc = complex_add, stype = complex, initcond = '(0,0)');
2461create aggregate sum(bigint) (sfunc = bigint_add, stype = bigint, initcond = '0');
2462drop aggregate sum$0(complex);
2463"), @r"
2464 hover: aggregate public.sum(complex)
2465 ╭▸
2466 4 │ drop aggregate sum(complex);
2467 ╰╴ ─ hover
2468 ");
2469 }
2470
2471 #[test]
2472 fn hover_on_drop_aggregate_second_overload() {
2473 assert_snapshot!(check_hover("
2474create aggregate sum(complex) (sfunc = complex_add, stype = complex, initcond = '(0,0)');
2475create aggregate sum(bigint) (sfunc = bigint_add, stype = bigint, initcond = '0');
2476drop aggregate sum$0(bigint);
2477"), @r"
2478 hover: aggregate public.sum(bigint)
2479 ╭▸
2480 4 │ drop aggregate sum(bigint);
2481 ╰╴ ─ hover
2482 ");
2483 }
2484
2485 #[test]
2486 fn hover_on_select_function_call() {
2487 assert_snapshot!(check_hover("
2488create function foo() returns int as $$ select 1 $$ language sql;
2489select foo$0();
2490"), @r"
2491 hover: function public.foo() returns int
2492 ╭▸
2493 3 │ select foo();
2494 ╰╴ ─ hover
2495 ");
2496 }
2497
2498 #[test]
2499 fn hover_on_select_function_call_with_schema() {
2500 assert_snapshot!(check_hover("
2501create function public.foo() returns int as $$ select 1 $$ language sql;
2502select public.foo$0();
2503"), @r"
2504 hover: function public.foo() returns int
2505 ╭▸
2506 3 │ select public.foo();
2507 ╰╴ ─ hover
2508 ");
2509 }
2510
2511 #[test]
2512 fn hover_on_select_function_call_with_search_path() {
2513 assert_snapshot!(check_hover(r#"
2514set search_path to myschema;
2515create function foo() returns int as $$ select 1 $$ language sql;
2516select foo$0();
2517"#), @r"
2518 hover: function myschema.foo() returns int
2519 ╭▸
2520 4 │ select foo();
2521 ╰╴ ─ hover
2522 ");
2523 }
2524
2525 #[test]
2526 fn hover_on_select_function_call_with_params() {
2527 assert_snapshot!(check_hover("
2528create function add(a int, b int) returns int as $$ select a + b $$ language sql;
2529select add$0(1, 2);
2530"), @r"
2531 hover: function public.add(a int, b int) returns int
2532 ╭▸
2533 3 │ select add(1, 2);
2534 ╰╴ ─ hover
2535 ");
2536 }
2537
2538 #[test]
2539 fn hover_on_builtin_function_call() {
2540 assert_snapshot!(check_hover("
2541select now$0();
2542"), @r"
2543 hover: function pg_catalog.now() returns timestamp with time zone
2544 ╭▸
2545 2 │ select now();
2546 ╰╴ ─ hover
2547 ");
2548 }
2549
2550 #[test]
2551 fn hover_on_named_arg_param() {
2552 assert_snapshot!(check_hover("
2553create function foo(bar_param int) returns int as $$ select 1 $$ language sql;
2554select foo(bar_param$0 := 5);
2555"), @r"
2556 hover: parameter public.foo.bar_param int
2557 ╭▸
2558 3 │ select foo(bar_param := 5);
2559 ╰╴ ─ hover
2560 ");
2561 }
2562
2563 #[test]
2564 fn hover_on_named_arg_param_schema_qualified() {
2565 assert_snapshot!(check_hover("
2566create schema s;
2567create function s.foo(my_param int) returns int as $$ select 1 $$ language sql;
2568select s.foo(my_param$0 := 10);
2569"), @r"
2570 hover: parameter s.foo.my_param int
2571 ╭▸
2572 4 │ select s.foo(my_param := 10);
2573 ╰╴ ─ hover
2574 ");
2575 }
2576
2577 #[test]
2578 fn hover_on_named_arg_param_procedure() {
2579 assert_snapshot!(check_hover("
2580create procedure proc(param_x int) as 'select 1' language sql;
2581call proc(param_x$0 := 42);
2582"), @r"
2583 hover: parameter public.proc.param_x int
2584 ╭▸
2585 3 │ call proc(param_x := 42);
2586 ╰╴ ─ hover
2587 ");
2588 }
2589
2590 #[test]
2591 fn hover_on_function_call_style_column_access() {
2592 assert_snapshot!(check_hover("
2593create table t(a int, b int);
2594select a$0(t) from t;
2595"), @r"
2596 hover: column public.t.a int
2597 ╭▸
2598 3 │ select a(t) from t;
2599 ╰╴ ─ hover
2600 ");
2601 }
2602
2603 #[test]
2604 fn hover_on_function_call_style_column_access_with_function_precedence() {
2605 assert_snapshot!(check_hover("
2606create table t(a int, b int);
2607create function b(t) returns int as 'select 1' LANGUAGE sql;
2608select b$0(t) from t;
2609"), @r"
2610 hover: function public.b(t) returns int
2611 ╭▸
2612 4 │ select b(t) from t;
2613 ╰╴ ─ hover
2614 ");
2615 }
2616
2617 #[test]
2618 fn hover_on_function_call_style_table_arg() {
2619 assert_snapshot!(check_hover("
2620create table t(a int, b int);
2621select a(t$0) from t;
2622"), @r"
2623 hover: table public.t(a int, b int)
2624 ╭▸
2625 3 │ select a(t) from t;
2626 ╰╴ ─ hover
2627 ");
2628 }
2629
2630 #[test]
2631 fn hover_on_function_call_style_table_arg_with_function() {
2632 assert_snapshot!(check_hover("
2633create table t(a int, b int);
2634create function b(t) returns int as 'select 1' LANGUAGE sql;
2635select b(t$0) from t;
2636"), @r"
2637 hover: table public.t(a int, b int)
2638 ╭▸
2639 4 │ select b(t) from t;
2640 ╰╴ ─ hover
2641 ");
2642 }
2643
2644 #[test]
2645 fn hover_on_function_call_style_table_arg_in_where() {
2646 assert_snapshot!(check_hover("
2647create table t(a int);
2648select * from t where a(t$0) > 2;
2649"), @r"
2650 hover: table public.t(a int)
2651 ╭▸
2652 3 │ select * from t where a(t) > 2;
2653 ╰╴ ─ hover
2654 ");
2655 }
2656
2657 #[test]
2658 fn hover_on_qualified_table_ref_in_where() {
2659 assert_snapshot!(check_hover("
2660create table t(a int);
2661create function b(t) returns int as 'select 1' language sql;
2662select * from t where t$0.b > 2;
2663"), @r"
2664 hover: table public.t(a int)
2665 ╭▸
2666 4 │ select * from t where t.b > 2;
2667 ╰╴ ─ hover
2668 ");
2669 }
2670
2671 #[test]
2672 fn hover_on_field_style_function_call() {
2673 assert_snapshot!(check_hover("
2674create table t(a int);
2675create function b(t) returns int as 'select 1' language sql;
2676select t.b$0 from t;
2677"), @r"
2678 hover: function public.b(t) returns int
2679 ╭▸
2680 4 │ select t.b from t;
2681 ╰╴ ─ hover
2682 ");
2683 }
2684
2685 #[test]
2686 fn hover_on_field_style_function_call_column_precedence() {
2687 assert_snapshot!(check_hover("
2688create table t(a int, b int);
2689create function b(t) returns int as 'select 1' language sql;
2690select t.b$0 from t;
2691"), @r"
2692 hover: column public.t.b int
2693 ╭▸
2694 4 │ select t.b from t;
2695 ╰╴ ─ hover
2696 ");
2697 }
2698
2699 #[test]
2700 fn hover_on_field_style_function_call_table_ref() {
2701 assert_snapshot!(check_hover("
2702create table t(a int);
2703create function b(t) returns int as 'select 1' language sql;
2704select t$0.b from t;
2705"), @r"
2706 hover: table public.t(a int)
2707 ╭▸
2708 4 │ select t.b from t;
2709 ╰╴ ─ hover
2710 ");
2711 }
2712
2713 #[test]
2714 fn hover_on_select_from_table() {
2715 assert_snapshot!(check_hover("
2716create table users(id int, email text);
2717select * from users$0;
2718"), @r"
2719 hover: table public.users(id int, email text)
2720 ╭▸
2721 3 │ select * from users;
2722 ╰╴ ─ hover
2723 ");
2724 }
2725
2726 #[test]
2727 fn hover_on_subquery_qualified_table_ref() {
2728 assert_snapshot!(check_hover("
2729select t$0.a from (select 1 a) t;
2730"), @r"
2731 hover: subquery t as (select 1 a)
2732 ╭▸
2733 2 │ select t.a from (select 1 a) t;
2734 ╰╴ ─ hover
2735 ");
2736 }
2737
2738 #[test]
2739 fn hover_on_subquery_qualified_column_ref() {
2740 assert_snapshot!(check_hover("
2741select t.a$0 from (select 1 a) t;
2742"), @"
2743 hover: column t.a integer
2744 ╭▸
2745 2 │ select t.a from (select 1 a) t;
2746 ╰╴ ─ hover
2747 ");
2748 }
2749
2750 #[test]
2751 fn hover_on_subquery_unqualified_column_ref_with_alias() {
2752 assert_snapshot!(check_hover("
2753select a$0 from (select 1 a) t;
2754"), @"
2755 hover: column t.a integer
2756 ╭▸
2757 2 │ select a from (select 1 a) t;
2758 ╰╴ ─ hover
2759 ");
2760 }
2761
2762 #[test]
2763 fn hover_on_select_from_table_with_schema() {
2764 assert_snapshot!(check_hover("
2765create table public.users(id int, email text);
2766select * from public.users$0;
2767"), @r"
2768 hover: table public.users(id int, email text)
2769 ╭▸
2770 3 │ select * from public.users;
2771 ╰╴ ─ hover
2772 ");
2773 }
2774
2775 #[test]
2776 fn hover_on_select_from_table_with_search_path() {
2777 assert_snapshot!(check_hover("
2778set search_path to foo;
2779create table foo.users(id int, email text);
2780select * from users$0;
2781"), @r"
2782 hover: table foo.users(id int, email text)
2783 ╭▸
2784 4 │ select * from users;
2785 ╰╴ ─ hover
2786 ");
2787 }
2788
2789 #[test]
2790 fn hover_on_select_from_temp_table() {
2791 assert_snapshot!(check_hover("
2792create temp table users(id int, email text);
2793select * from users$0;
2794"), @r"
2795 hover: table pg_temp.users(id int, email text)
2796 ╭▸
2797 3 │ select * from users;
2798 ╰╴ ─ hover
2799 ");
2800 }
2801
2802 #[test]
2803 fn hover_on_select_from_multiline_table() {
2804 assert_snapshot!(check_hover("
2805create table users(
2806 id int,
2807 email text,
2808 name varchar(100)
2809);
2810select * from users$0;
2811"), @r"
2812 hover: table public.users(
2813 id int,
2814 email text,
2815 name varchar(100)
2816 )
2817 ╭▸
2818 7 │ select * from users;
2819 ╰╴ ─ hover
2820 ");
2821 }
2822
2823 #[test]
2824 fn hover_on_select_column() {
2825 assert_snapshot!(check_hover("
2826create table users(id int, email text);
2827select id$0 from users;
2828"), @r"
2829 hover: column public.users.id int
2830 ╭▸
2831 3 │ select id from users;
2832 ╰╴ ─ hover
2833 ");
2834 }
2835
2836 #[test]
2837 fn hover_on_select_column_second() {
2838 assert_snapshot!(check_hover("
2839create table users(id int, email text);
2840select id, email$0 from users;
2841"), @r"
2842 hover: column public.users.email text
2843 ╭▸
2844 3 │ select id, email from users;
2845 ╰╴ ─ hover
2846 ");
2847 }
2848
2849 #[test]
2850 fn hover_on_select_column_with_schema() {
2851 assert_snapshot!(check_hover("
2852create table public.users(id int, email text);
2853select email$0 from public.users;
2854"), @r"
2855 hover: column public.users.email text
2856 ╭▸
2857 3 │ select email from public.users;
2858 ╰╴ ─ hover
2859 ");
2860 }
2861
2862 #[test]
2863 fn hover_on_select_column_with_search_path() {
2864 assert_snapshot!(check_hover("
2865set search_path to foo;
2866create table foo.users(id int, email text);
2867select id$0 from users;
2868"), @r"
2869 hover: column foo.users.id int
2870 ╭▸
2871 4 │ select id from users;
2872 ╰╴ ─ hover
2873 ");
2874 }
2875
2876 #[test]
2877 fn hover_on_select_qualified_star() {
2878 assert_snapshot!(check_hover("
2879create table u(id int, b int);
2880select u.*$0 from u;
2881"), @r"
2882 hover: column public.u.id int
2883 column public.u.b int
2884 ╭▸
2885 3 │ select u.* from u;
2886 ╰╴ ─ hover
2887 ");
2888 }
2889
2890 #[test]
2891 fn hover_on_select_unqualified_star() {
2892 assert_snapshot!(check_hover("
2893create table u(id int, b int);
2894select *$0 from u;
2895"), @r"
2896 hover: column public.u.id int
2897 column public.u.b int
2898 ╭▸
2899 3 │ select * from u;
2900 ╰╴ ─ hover
2901 ");
2902 }
2903
2904 #[test]
2905 fn hover_on_select_count_star() {
2906 assert_snapshot!(check_hover("
2907create table u(id int, b int);
2908select count(*$0) from u;
2909"), @r"
2910 hover: column public.u.id int
2911 column public.u.b int
2912 ╭▸
2913 3 │ select count(*) from u;
2914 ╰╴ ─ hover
2915 ");
2916 }
2917
2918 #[test]
2919 fn hover_on_insert_table() {
2920 assert_snapshot!(check_hover("
2921create table users(id int, email text);
2922insert into users$0(id, email) values (1, 'test');
2923"), @r"
2924 hover: table public.users(id int, email text)
2925 ╭▸
2926 3 │ insert into users(id, email) values (1, 'test');
2927 ╰╴ ─ hover
2928 ");
2929 }
2930
2931 #[test]
2932 fn hover_on_insert_table_with_schema() {
2933 assert_snapshot!(check_hover("
2934create table public.users(id int, email text);
2935insert into public.users$0(id, email) values (1, 'test');
2936"), @r"
2937 hover: table public.users(id int, email text)
2938 ╭▸
2939 3 │ insert into public.users(id, email) values (1, 'test');
2940 ╰╴ ─ hover
2941 ");
2942 }
2943
2944 #[test]
2945 fn hover_on_insert_column() {
2946 assert_snapshot!(check_hover("
2947create table users(id int, email text);
2948insert into users(id$0, email) values (1, 'test');
2949"), @r"
2950 hover: column public.users.id int
2951 ╭▸
2952 3 │ insert into users(id, email) values (1, 'test');
2953 ╰╴ ─ hover
2954 ");
2955 }
2956
2957 #[test]
2958 fn hover_on_insert_column_second() {
2959 assert_snapshot!(check_hover("
2960create table users(id int, email text);
2961insert into users(id, email$0) values (1, 'test');
2962"), @r"
2963 hover: column public.users.email text
2964 ╭▸
2965 3 │ insert into users(id, email) values (1, 'test');
2966 ╰╴ ─ hover
2967 ");
2968 }
2969
2970 #[test]
2971 fn hover_on_insert_column_with_schema() {
2972 assert_snapshot!(check_hover("
2973create table public.users(id int, email text);
2974insert into public.users(email$0) values ('test');
2975"), @r"
2976 hover: column public.users.email text
2977 ╭▸
2978 3 │ insert into public.users(email) values ('test');
2979 ╰╴ ─ hover
2980 ");
2981 }
2982
2983 #[test]
2984 fn hover_on_delete_table() {
2985 assert_snapshot!(check_hover("
2986create table users(id int, email text);
2987delete from users$0 where id = 1;
2988"), @r"
2989 hover: table public.users(id int, email text)
2990 ╭▸
2991 3 │ delete from users where id = 1;
2992 ╰╴ ─ hover
2993 ");
2994 }
2995
2996 #[test]
2997 fn hover_on_delete_table_with_schema() {
2998 assert_snapshot!(check_hover("
2999create table public.users(id int, email text);
3000delete from public.users$0 where id = 1;
3001"), @r"
3002 hover: table public.users(id int, email text)
3003 ╭▸
3004 3 │ delete from public.users where id = 1;
3005 ╰╴ ─ hover
3006 ");
3007 }
3008
3009 #[test]
3010 fn hover_on_delete_where_column() {
3011 assert_snapshot!(check_hover("
3012create table users(id int, email text);
3013delete from users where id$0 = 1;
3014"), @r"
3015 hover: column public.users.id int
3016 ╭▸
3017 3 │ delete from users where id = 1;
3018 ╰╴ ─ hover
3019 ");
3020 }
3021
3022 #[test]
3023 fn hover_on_delete_where_column_second() {
3024 assert_snapshot!(check_hover("
3025create table users(id int, email text, active boolean);
3026delete from users where id = 1 and email$0 = 'test';
3027"), @r"
3028 hover: column public.users.email text
3029 ╭▸
3030 3 │ delete from users where id = 1 and email = 'test';
3031 ╰╴ ─ hover
3032 ");
3033 }
3034
3035 #[test]
3036 fn hover_on_delete_where_column_with_schema() {
3037 assert_snapshot!(check_hover("
3038create table public.users(id int, email text);
3039delete from public.users where email$0 = 'test';
3040"), @r"
3041 hover: column public.users.email text
3042 ╭▸
3043 3 │ delete from public.users where email = 'test';
3044 ╰╴ ─ hover
3045 ");
3046 }
3047
3048 #[test]
3049 fn hover_on_select_table_as_column() {
3050 assert_snapshot!(check_hover("
3051create table t(x bigint, y bigint);
3052select t$0 from t;
3053"), @r"
3054 hover: table public.t(x bigint, y bigint)
3055 ╭▸
3056 3 │ select t from t;
3057 ╰╴ ─ hover
3058 ");
3059 }
3060
3061 #[test]
3062 fn hover_on_select_table_as_column_with_schema() {
3063 assert_snapshot!(check_hover("
3064create table public.t(x bigint, y bigint);
3065select t$0 from public.t;
3066"), @r"
3067 hover: table public.t(x bigint, y bigint)
3068 ╭▸
3069 3 │ select t from public.t;
3070 ╰╴ ─ hover
3071 ");
3072 }
3073
3074 #[test]
3075 fn hover_on_select_table_as_column_with_search_path() {
3076 assert_snapshot!(check_hover("
3077set search_path to foo;
3078create table foo.users(id int, email text);
3079select users$0 from users;
3080"), @r"
3081 hover: table foo.users(id int, email text)
3082 ╭▸
3083 4 │ select users from users;
3084 ╰╴ ─ hover
3085 ");
3086 }
3087
3088 #[test]
3089 fn hover_on_select_column_with_same_name_as_table() {
3090 assert_snapshot!(check_hover("
3091create table t(t int);
3092select t$0 from t;
3093"), @r"
3094 hover: column public.t.t int
3095 ╭▸
3096 3 │ select t from t;
3097 ╰╴ ─ hover
3098 ");
3099 }
3100
3101 #[test]
3102 fn hover_on_create_schema() {
3103 assert_snapshot!(check_hover("
3104create schema foo$0;
3105"), @r"
3106 hover: schema foo
3107 ╭▸
3108 2 │ create schema foo;
3109 ╰╴ ─ hover
3110 ");
3111 }
3112
3113 #[test]
3114 fn hover_on_create_schema_authorization() {
3115 assert_snapshot!(check_hover("
3116create schema authorization foo$0;
3117"), @r"
3118 hover: schema foo
3119 ╭▸
3120 2 │ create schema authorization foo;
3121 ╰╴ ─ hover
3122 ");
3123 }
3124
3125 #[test]
3126 fn hover_on_drop_schema_authorization() {
3127 assert_snapshot!(check_hover("
3128create schema authorization foo;
3129drop schema foo$0;
3130"), @r"
3131 hover: schema foo
3132 ╭▸
3133 3 │ drop schema foo;
3134 ╰╴ ─ hover
3135 ");
3136 }
3137
3138 #[test]
3139 fn hover_on_drop_schema() {
3140 assert_snapshot!(check_hover("
3141create schema foo;
3142drop schema foo$0;
3143"), @r"
3144 hover: schema foo
3145 ╭▸
3146 3 │ drop schema foo;
3147 ╰╴ ─ hover
3148 ");
3149 }
3150
3151 #[test]
3152 fn hover_on_schema_after_definition() {
3153 assert_snapshot!(check_hover("
3154drop schema foo$0;
3155create schema foo;
3156"), @r"
3157 hover: schema foo
3158 ╭▸
3159 2 │ drop schema foo;
3160 ╰╴ ─ hover
3161 ");
3162 }
3163
3164 #[test]
3165 fn hover_on_cte_table() {
3166 assert_snapshot!(check_hover("
3167with t as (select 1 a)
3168select a from t$0;
3169"), @r"
3170 hover: with t as (select 1 a)
3171 ╭▸
3172 3 │ select a from t;
3173 ╰╴ ─ hover
3174 ");
3175 }
3176
3177 #[test]
3178 fn hover_on_select_cte_table_as_column() {
3179 assert_snapshot!(check_hover("
3180with t as (select 1 a, 2 b, 3 c)
3181select t$0 from t;
3182"), @r"
3183 hover: with t as (select 1 a, 2 b, 3 c)
3184 ╭▸
3185 3 │ select t from t;
3186 ╰╴ ─ hover
3187 ");
3188 }
3189
3190 #[test]
3191 fn hover_on_cte_column() {
3192 assert_snapshot!(check_hover("
3193with t as (select 1 a)
3194select a$0 from t;
3195"), @"
3196 hover: column t.a integer
3197 ╭▸
3198 3 │ select a from t;
3199 ╰╴ ─ hover
3200 ");
3201 }
3202
3203 #[test]
3204 fn hover_on_cte_with_multiple_columns() {
3205 assert_snapshot!(check_hover("
3206with t as (select 1 a, 2 b)
3207select b$0 from t;
3208"), @"
3209 hover: column t.b integer
3210 ╭▸
3211 3 │ select b from t;
3212 ╰╴ ─ hover
3213 ");
3214 }
3215
3216 #[test]
3217 fn hover_on_cte_with_column_list() {
3218 assert_snapshot!(check_hover("
3219with t(a) as (select 1)
3220select a$0 from t;
3221"), @"
3222 hover: column t.a integer
3223 ╭▸
3224 3 │ select a from t;
3225 ╰╴ ─ hover
3226 ");
3227 }
3228
3229 #[test]
3230 fn hover_on_nested_cte() {
3231 assert_snapshot!(check_hover("
3232with x as (select 1 a),
3233 y as (select a from x)
3234select a$0 from y;
3235"), @"
3236 hover: column y.a integer
3237 ╭▸
3238 4 │ select a from y;
3239 ╰╴ ─ hover
3240 ");
3241 }
3242
3243 #[test]
3244 fn hover_on_cte_shadowing_table_with_star() {
3245 assert_snapshot!(check_hover("
3246create table t(a bigint);
3247with t as (select * from t)
3248select a$0 from t;
3249"), @r"
3250 hover: column public.t.a bigint
3251 ╭▸
3252 4 │ select a from t;
3253 ╰╴ ─ hover
3254 ");
3255 }
3256
3257 #[test]
3258 fn hover_on_cte_definition() {
3259 assert_snapshot!(check_hover("
3260with t$0 as (select 1 a)
3261select a from t;
3262"), @r"
3263 hover: with t as (select 1 a)
3264 ╭▸
3265 2 │ with t as (select 1 a)
3266 ╰╴ ─ hover
3267 ");
3268 }
3269
3270 #[test]
3271 fn hover_on_cte_values_column1() {
3272 assert_snapshot!(check_hover("
3273with t as (
3274 values (1, 2), (3, 4)
3275)
3276select column1$0, column2 from t;
3277"), @"
3278 hover: column t.column1 integer
3279 ╭▸
3280 5 │ select column1, column2 from t;
3281 ╰╴ ─ hover
3282 ");
3283 }
3284
3285 #[test]
3286 fn hover_on_cte_values_column2() {
3287 assert_snapshot!(check_hover("
3288with t as (
3289 values (1, 2), (3, 4)
3290)
3291select column1, column2$0 from t;
3292"), @"
3293 hover: column t.column2 integer
3294 ╭▸
3295 5 │ select column1, column2 from t;
3296 ╰╴ ─ hover
3297 ");
3298 }
3299
3300 #[test]
3301 fn hover_on_cte_values_single_column() {
3302 assert_snapshot!(check_hover("
3303with t as (
3304 values (1), (2), (3)
3305)
3306select column1$0 from t;
3307"), @"
3308 hover: column t.column1 integer
3309 ╭▸
3310 5 │ select column1 from t;
3311 ╰╴ ─ hover
3312 ");
3313 }
3314
3315 #[test]
3316 fn hover_on_cte_values_uppercase_column_names() {
3317 assert_snapshot!(check_hover("
3318with t as (
3319 values (1, 2), (3, 4)
3320)
3321select COLUMN1$0, COLUMN2 from t;
3322"), @"
3323 hover: column t.column1 integer
3324 ╭▸
3325 5 │ select COLUMN1, COLUMN2 from t;
3326 ╰╴ ─ hover
3327 ");
3328 }
3329
3330 #[test]
3331 fn hover_on_subquery_column() {
3332 assert_snapshot!(check_hover("
3333select a$0 from (select 1 a);
3334"), @r"
3335 hover: column a integer
3336 ╭▸
3337 2 │ select a from (select 1 a);
3338 ╰╴ ─ hover
3339 ");
3340 }
3341
3342 #[test]
3343 fn hover_on_subquery_values_column() {
3344 assert_snapshot!(check_hover("
3345select column1$0 from (values (1, 'foo'));
3346"), @r"
3347 hover: column column1 integer
3348 ╭▸
3349 2 │ select column1 from (values (1, 'foo'));
3350 ╰╴ ─ hover
3351 ");
3352 }
3353
3354 #[test]
3355 fn hover_on_cte_qualified_star() {
3356 assert_snapshot!(check_hover("
3357with u as (select 1 id, 2 b)
3358select u.*$0 from u;
3359"), @"
3360 hover: column u.id integer
3361 column u.b integer
3362 ╭▸
3363 3 │ select u.* from u;
3364 ╰╴ ─ hover
3365 ");
3366 }
3367
3368 #[test]
3369 fn hover_on_cte_values_qualified_star() {
3370 assert_snapshot!(check_hover("
3371with t as (values (1, 2), (3, 4))
3372select t.*$0 from t;
3373"), @"
3374 hover: column t.column1 integer
3375 column t.column2 integer
3376 ╭▸
3377 3 │ select t.* from t;
3378 ╰╴ ─ hover
3379 ");
3380 }
3381
3382 #[test]
3383 fn hover_on_cte_table_alias_with_column_list() {
3384 assert_snapshot!(check_hover("
3385with t as (select 1 a, 2 b, 3 c)
3386select u$0.x, u.y from t as u(x, y);
3387"), @"
3388 hover: table u(x, y, c)
3389 ╭▸
3390 3 │ select u.x, u.y from t as u(x, y);
3391 ╰╴ ─ hover
3392 ");
3393 }
3394
3395 #[test]
3396 fn hover_on_cte_table_alias_with_column_list_column_ref() {
3397 assert_snapshot!(check_hover("
3398with t as (select 1 a, 2 b, 3 c)
3399select u.x$0 from t as u(x, y);
3400"), @"
3401 hover: column u.x integer
3402 ╭▸
3403 3 │ select u.x from t as u(x, y);
3404 ╰╴ ─ hover
3405 ");
3406 }
3407
3408 #[test]
3409 fn hover_on_cte_table_alias_with_column_list_table_ref() {
3410 assert_snapshot!(check_hover("
3411with t as (select 1 a, 2 b, 3 c)
3412select u$0 from t as u(x, y);
3413"), @"
3414 hover: table u(x, y, c)
3415 ╭▸
3416 3 │ select u from t as u(x, y);
3417 ╰╴ ─ hover
3418 ");
3419 }
3420
3421 #[test]
3422 fn hover_on_subquery_alias_with_column_list_table_ref() {
3423 assert_snapshot!(check_hover("
3424with t as (select 1 a, 2 b, 3 c)
3425select z$0 from (select * from t) as z(x, y);
3426"), @"
3427 hover: table z(x, y, c)
3428 ╭▸
3429 3 │ select z from (select * from t) as z(x, y);
3430 ╰╴ ─ hover
3431 ");
3432 }
3433
3434 #[test]
3435 fn hover_on_subquery_nested_paren_alias_with_column_list_table_ref() {
3436 assert_snapshot!(check_hover("
3437with t as (select 1 a, 2 b, 3 c)
3438select z$0 from ((select * from t)) as z(x, y);
3439"), @"
3440 hover: table z(x, y, c)
3441 ╭▸
3442 3 │ select z from ((select * from t)) as z(x, y);
3443 ╰╴ ─ hover
3444 ");
3445 }
3446
3447 #[test]
3448 fn hover_on_cte_table_alias_with_partial_column_list_star() {
3449 assert_snapshot!(check_hover("
3450with t as (select 1 a, 2 b, 3 c)
3451select *$0 from t u(x, y);
3452"), @"
3453 hover: column u.x integer
3454 column u.y integer
3455 column u.c integer
3456 ╭▸
3457 3 │ select * from t u(x, y);
3458 ╰╴ ─ hover
3459 ");
3460 }
3461
3462 #[test]
3463 fn hover_on_cte_table_alias_with_partial_column_list_star_from_information_schema() {
3464 assert_snapshot!(check_hover("
3465with t as (select * from information_schema.sql_features)
3466select *$0 from t u(x);
3467"), @"
3468 hover: column u.x character_data
3469 column u.feature_name character_data
3470 column u.sub_feature_id character_data
3471 column u.sub_feature_name character_data
3472 column u.is_supported yes_or_no
3473 column u.is_verified_by character_data
3474 column u.comments character_data
3475 ╭▸
3476 3 │ select * from t u(x);
3477 ╰╴ ─ hover
3478 ");
3479 }
3480
3481 #[test]
3482 fn hover_cte_builtin_information_schema() {
3483 assert_snapshot!(check_hover("
3484with t as (select * from information_schema.sql_features)
3485select *$0 from t;
3486"), @"
3487 hover: column t.feature_id character_data
3488 column t.feature_name character_data
3489 column t.sub_feature_id character_data
3490 column t.sub_feature_name character_data
3491 column t.is_supported yes_or_no
3492 column t.is_verified_by character_data
3493 column t.comments character_data
3494 ╭▸
3495 3 │ select * from t;
3496 ╰╴ ─ hover
3497 ");
3498 }
3499
3500 #[test]
3501 fn hover_on_cte_table_alias_with_partial_column_list_qualified_star() {
3502 assert_snapshot!(check_hover("
3503with t as (select 1 a, 2 b, 3 c)
3504select u.*$0 from t u(x, y);
3505"), @"
3506 hover: column u.x integer
3507 column u.y integer
3508 column u.c integer
3509 ╭▸
3510 3 │ select u.* from t u(x, y);
3511 ╰╴ ─ hover
3512 ");
3513 }
3514
3515 #[test]
3516 fn hover_on_star_from_cte_empty_select() {
3517 assert!(
3518 check_hover_(
3519 "
3520with t as (select)
3521select *$0 from t;
3522",
3523 )
3524 .is_none()
3525 );
3526 }
3527
3528 #[test]
3529 fn hover_on_star_with_subquery_from_cte() {
3530 assert_snapshot!(check_hover("
3531with u as (select 1 id, 2 b)
3532select *$0 from (select *, *, * from u);
3533"), @"
3534 hover: column u.id integer
3535 column u.b integer
3536 column u.id integer
3537 column u.b integer
3538 column u.id integer
3539 column u.b integer
3540 ╭▸
3541 3 │ select * from (select *, *, * from u);
3542 ╰╴ ─ hover
3543 ");
3544 }
3545
3546 #[test]
3547 fn hover_on_star_with_subquery_from_table() {
3548 assert_snapshot!(check_hover("
3549create table t(a int, b int);
3550select *$0 from (select a from t);
3551"), @r"
3552 hover: column public.t.a int
3553 ╭▸
3554 3 │ select * from (select a from t);
3555 ╰╴ ─ hover
3556 ");
3557 }
3558
3559 #[test]
3560 fn hover_on_star_with_subquery_from_table_statement() {
3561 assert_snapshot!(check_hover("
3562with t as (select 1 a, 2 b)
3563select *$0 from (table t);
3564"), @"
3565 hover: column a integer
3566 column b integer
3567 ╭▸
3568 3 │ select * from (table t);
3569 ╰╴ ─ hover
3570 ");
3571 }
3572
3573 #[test]
3574 fn hover_on_star_from_information_schema_table() {
3575 assert_snapshot!(check_hover("
3576select *$0 from information_schema.sql_features;
3577"), @"
3578 hover: column information_schema.sql_features.feature_id character_data
3579 column information_schema.sql_features.feature_name character_data
3580 column information_schema.sql_features.sub_feature_id character_data
3581 column information_schema.sql_features.sub_feature_name character_data
3582 column information_schema.sql_features.is_supported yes_or_no
3583 column information_schema.sql_features.is_verified_by character_data
3584 column information_schema.sql_features.comments character_data
3585 ╭▸
3586 2 │ select * from information_schema.sql_features;
3587 ╰╴ ─ hover
3588 ");
3589 }
3590
3591 #[test]
3592 fn hover_on_star_with_subquery_literal() {
3593 assert_snapshot!(check_hover("
3594select *$0 from (select 1);
3595"), @"
3596 hover: column ?column? integer
3597 ╭▸
3598 2 │ select * from (select 1);
3599 ╰╴ ─ hover
3600 ");
3601 }
3602
3603 #[test]
3604 fn hover_on_star_with_subquery_literal_with_alias() {
3605 assert_snapshot!(check_hover("
3606select *$0 from (select 1) as sub;
3607"), @"
3608 hover: column sub.?column? integer
3609 ╭▸
3610 2 │ select * from (select 1) as sub;
3611 ╰╴ ─ hover
3612 ");
3613 }
3614
3615 #[test]
3616 fn hover_on_view_inferred_column_name() {
3617 assert_snapshot!(check_hover(r#"
3618create view v as select 1;
3619select "?column?"$0 from v;
3620"#), @r#"
3621 hover: column public.v.?column? integer
3622 ╭▸
3623 3 │ select "?column?" from v;
3624 ╰╴ ─ hover
3625 "#);
3626 }
3627
3628 #[test]
3629 fn hover_on_cte_inferred_column_name() {
3630 assert_snapshot!(check_hover(r#"
3631with x as (select 1)
3632select "?column?"$0 from x;
3633"#), @r#"
3634 hover: column x.?column? integer
3635 ╭▸
3636 3 │ select "?column?" from x;
3637 ╰╴ ─ hover
3638 "#);
3639 }
3640
3641 #[test]
3642 fn hover_on_create_table_as_inferred_column_name() {
3643 assert_snapshot!(check_hover(r#"
3644create table t as select 1;
3645select "?column?"$0 from t;
3646"#), @r#"
3647 hover: column public.t.?column? integer
3648 ╭▸
3649 3 │ select "?column?" from t;
3650 ╰╴ ─ hover
3651 "#);
3652 }
3653
3654 #[test]
3655 fn hover_on_paren_select_inferred_column_name() {
3656 assert_snapshot!(check_hover(r#"
3657select "?column?"$0 from (select 1);
3658"#), @r#"
3659 hover: column ?column? integer
3660 ╭▸
3661 2 │ select "?column?" from (select 1);
3662 ╰╴ ─ hover
3663 "#);
3664 }
3665
3666 #[test]
3667 fn hover_on_paren_select_aliased_inferred_column_name() {
3668 assert_snapshot!(check_hover(r#"
3669select sub."?column?"$0 from (select 1) sub;
3670"#), @r#"
3671 hover: column sub.?column? integer
3672 ╭▸
3673 2 │ select sub."?column?" from (select 1) sub;
3674 ╰╴ ─ hover
3675 "#);
3676 }
3677
3678 #[test]
3679 fn hover_on_view_qualified_star() {
3680 assert_snapshot!(check_hover("
3681create view v as select 1 id, 2 b;
3682select v.*$0 from v;
3683"), @"
3684 hover: column public.v.id integer
3685 column public.v.b integer
3686 ╭▸
3687 3 │ select v.* from v;
3688 ╰╴ ─ hover
3689 ");
3690 }
3691
3692 #[test]
3693 fn hover_on_materialized_view_qualified_star() {
3694 assert_snapshot!(check_hover("
3695 create materialized view v as select 1 id, 2 b;
3696 select v.*$0 from v;
3697 "), @"
3698 hover: column public.v.id integer
3699 column public.v.b integer
3700 ╭▸
3701 3 │ select v.* from v;
3702 ╰╴ ─ hover
3703 ");
3704 }
3705
3706 #[test]
3707 fn hover_on_view_qualified_star_with_column_list() {
3708 assert_snapshot!(check_hover("
3709create view v (x, y) as select 1, 2, 3;
3710select v.*$0 from v;
3711"), @"
3712 hover: column public.v.x integer
3713 column public.v.y integer
3714 column public.v.?column? integer
3715 ╭▸
3716 3 │ select v.* from v;
3717 ╰╴ ─ hover
3718 ");
3719 }
3720
3721 #[test]
3722 fn hover_on_materialized_view_qualified_star_with_column_list() {
3723 assert_snapshot!(check_hover("
3724create materialized view mv (x, y) as select 1, 2, 3;
3725select mv.*$0 from mv;
3726"), @"
3727 hover: column public.mv.x integer
3728 column public.mv.y integer
3729 column public.mv.?column? integer
3730 ╭▸
3731 3 │ select mv.* from mv;
3732 ╰╴ ─ hover
3733 ");
3734 }
3735
3736 #[test]
3737 fn hover_on_drop_procedure() {
3738 assert_snapshot!(check_hover("
3739create procedure foo() language sql as $$ select 1 $$;
3740drop procedure foo$0();
3741"), @r"
3742 hover: procedure public.foo()
3743 ╭▸
3744 3 │ drop procedure foo();
3745 ╰╴ ─ hover
3746 ");
3747 }
3748
3749 #[test]
3750 fn hover_on_drop_procedure_with_schema() {
3751 assert_snapshot!(check_hover("
3752create procedure myschema.foo() language sql as $$ select 1 $$;
3753drop procedure myschema.foo$0();
3754"), @r"
3755 hover: procedure myschema.foo()
3756 ╭▸
3757 3 │ drop procedure myschema.foo();
3758 ╰╴ ─ hover
3759 ");
3760 }
3761
3762 #[test]
3763 fn hover_on_create_procedure_definition() {
3764 assert_snapshot!(check_hover("
3765create procedure foo$0() language sql as $$ select 1 $$;
3766"), @r"
3767 hover: procedure public.foo()
3768 ╭▸
3769 2 │ create procedure foo() language sql as $$ select 1 $$;
3770 ╰╴ ─ hover
3771 ");
3772 }
3773
3774 #[test]
3775 fn hover_on_create_procedure_with_explicit_schema() {
3776 assert_snapshot!(check_hover("
3777create procedure myschema.foo$0() language sql as $$ select 1 $$;
3778"), @r"
3779 hover: procedure myschema.foo()
3780 ╭▸
3781 2 │ create procedure myschema.foo() language sql as $$ select 1 $$;
3782 ╰╴ ─ hover
3783 ");
3784 }
3785
3786 #[test]
3787 fn hover_on_drop_procedure_with_search_path() {
3788 assert_snapshot!(check_hover(r#"
3789set search_path to myschema;
3790create procedure foo() language sql as $$ select 1 $$;
3791drop procedure foo$0();
3792"#), @r"
3793 hover: procedure myschema.foo()
3794 ╭▸
3795 4 │ drop procedure foo();
3796 ╰╴ ─ hover
3797 ");
3798 }
3799
3800 #[test]
3801 fn hover_on_drop_procedure_overloaded() {
3802 assert_snapshot!(check_hover("
3803create procedure add(complex) language sql as $$ select null $$;
3804create procedure add(bigint) language sql as $$ select 1 $$;
3805drop procedure add$0(complex);
3806"), @r"
3807 hover: procedure public.add(complex)
3808 ╭▸
3809 4 │ drop procedure add(complex);
3810 ╰╴ ─ hover
3811 ");
3812 }
3813
3814 #[test]
3815 fn hover_on_drop_procedure_second_overload() {
3816 assert_snapshot!(check_hover("
3817create procedure add(complex) language sql as $$ select null $$;
3818create procedure add(bigint) language sql as $$ select 1 $$;
3819drop procedure add$0(bigint);
3820"), @r"
3821 hover: procedure public.add(bigint)
3822 ╭▸
3823 4 │ drop procedure add(bigint);
3824 ╰╴ ─ hover
3825 ");
3826 }
3827
3828 #[test]
3829 fn hover_on_call_procedure() {
3830 assert_snapshot!(check_hover("
3831create procedure foo() language sql as $$ select 1 $$;
3832call foo$0();
3833"), @r"
3834 hover: procedure public.foo()
3835 ╭▸
3836 3 │ call foo();
3837 ╰╴ ─ hover
3838 ");
3839 }
3840
3841 #[test]
3842 fn hover_on_call_procedure_with_schema() {
3843 assert_snapshot!(check_hover("
3844create procedure public.foo() language sql as $$ select 1 $$;
3845call public.foo$0();
3846"), @r"
3847 hover: procedure public.foo()
3848 ╭▸
3849 3 │ call public.foo();
3850 ╰╴ ─ hover
3851 ");
3852 }
3853
3854 #[test]
3855 fn hover_on_call_procedure_with_search_path() {
3856 assert_snapshot!(check_hover(r#"
3857set search_path to myschema;
3858create procedure foo() language sql as $$ select 1 $$;
3859call foo$0();
3860"#), @r"
3861 hover: procedure myschema.foo()
3862 ╭▸
3863 4 │ call foo();
3864 ╰╴ ─ hover
3865 ");
3866 }
3867
3868 #[test]
3869 fn hover_on_call_procedure_with_params() {
3870 assert_snapshot!(check_hover("
3871create procedure add(a int, b int) language sql as $$ select a + b $$;
3872call add$0(1, 2);
3873"), @r"
3874 hover: procedure public.add(a int, b int)
3875 ╭▸
3876 3 │ call add(1, 2);
3877 ╰╴ ─ hover
3878 ");
3879 }
3880
3881 #[test]
3882 fn hover_on_drop_routine_function() {
3883 assert_snapshot!(check_hover("
3884create function foo() returns int as $$ select 1 $$ language sql;
3885drop routine foo$0();
3886"), @r"
3887 hover: function public.foo() returns int
3888 ╭▸
3889 3 │ drop routine foo();
3890 ╰╴ ─ hover
3891 ");
3892 }
3893
3894 #[test]
3895 fn hover_on_drop_routine_aggregate() {
3896 assert_snapshot!(check_hover("
3897create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
3898drop routine myavg$0(int);
3899"), @r"
3900 hover: aggregate public.myavg(int)
3901 ╭▸
3902 3 │ drop routine myavg(int);
3903 ╰╴ ─ hover
3904 ");
3905 }
3906
3907 #[test]
3908 fn hover_on_drop_routine_procedure() {
3909 assert_snapshot!(check_hover("
3910create procedure foo() language sql as $$ select 1 $$;
3911drop routine foo$0();
3912"), @r"
3913 hover: procedure public.foo()
3914 ╭▸
3915 3 │ drop routine foo();
3916 ╰╴ ─ hover
3917 ");
3918 }
3919
3920 #[test]
3921 fn hover_on_drop_routine_with_schema() {
3922 assert_snapshot!(check_hover("
3923set search_path to public;
3924create function foo() returns int as $$ select 1 $$ language sql;
3925drop routine public.foo$0();
3926"), @r"
3927 hover: function public.foo() returns int
3928 ╭▸
3929 4 │ drop routine public.foo();
3930 ╰╴ ─ hover
3931 ");
3932 }
3933
3934 #[test]
3935 fn hover_on_drop_routine_with_search_path() {
3936 assert_snapshot!(check_hover(r#"
3937set search_path to myschema;
3938create function foo() returns int as $$ select 1 $$ language sql;
3939drop routine foo$0();
3940"#), @r"
3941 hover: function myschema.foo() returns int
3942 ╭▸
3943 4 │ drop routine foo();
3944 ╰╴ ─ hover
3945 ");
3946 }
3947
3948 #[test]
3949 fn hover_on_drop_routine_overloaded() {
3950 assert_snapshot!(check_hover("
3951create function add(complex) returns complex as $$ select null $$ language sql;
3952create function add(bigint) returns bigint as $$ select 1 $$ language sql;
3953drop routine add$0(complex);
3954"), @r"
3955 hover: function public.add(complex) returns complex
3956 ╭▸
3957 4 │ drop routine add(complex);
3958 ╰╴ ─ hover
3959 ");
3960 }
3961
3962 #[test]
3963 fn hover_on_drop_routine_prefers_function_over_procedure() {
3964 assert_snapshot!(check_hover("
3965create function foo() returns int as $$ select 1 $$ language sql;
3966create procedure foo() language sql as $$ select 1 $$;
3967drop routine foo$0();
3968"), @r"
3969 hover: function public.foo() returns int
3970 ╭▸
3971 4 │ drop routine foo();
3972 ╰╴ ─ hover
3973 ");
3974 }
3975
3976 #[test]
3977 fn hover_on_drop_routine_prefers_aggregate_over_procedure() {
3978 assert_snapshot!(check_hover("
3979create aggregate foo(int) (sfunc = int4_avg_accum, stype = _int8);
3980create procedure foo(int) language sql as $$ select 1 $$;
3981drop routine foo$0(int);
3982"), @r"
3983 hover: aggregate public.foo(int)
3984 ╭▸
3985 4 │ drop routine foo(int);
3986 ╰╴ ─ hover
3987 ");
3988 }
3989
3990 #[test]
3991 fn hover_on_update_table() {
3992 assert_snapshot!(check_hover("
3993create table users(id int, email text);
3994update users$0 set email = 'new@example.com';
3995"), @r"
3996 hover: table public.users(id int, email text)
3997 ╭▸
3998 3 │ update users set email = 'new@example.com';
3999 ╰╴ ─ hover
4000 ");
4001 }
4002
4003 #[test]
4004 fn hover_on_update_table_with_schema() {
4005 assert_snapshot!(check_hover("
4006create table public.users(id int, email text);
4007update public.users$0 set email = 'new@example.com';
4008"), @r"
4009 hover: table public.users(id int, email text)
4010 ╭▸
4011 3 │ update public.users set email = 'new@example.com';
4012 ╰╴ ─ hover
4013 ");
4014 }
4015
4016 #[test]
4017 fn hover_on_update_set_column() {
4018 assert_snapshot!(check_hover("
4019create table users(id int, email text);
4020update users set email$0 = 'new@example.com' where id = 1;
4021"), @r"
4022 hover: column public.users.email text
4023 ╭▸
4024 3 │ update users set email = 'new@example.com' where id = 1;
4025 ╰╴ ─ hover
4026 ");
4027 }
4028
4029 #[test]
4030 fn hover_on_update_set_column_with_schema() {
4031 assert_snapshot!(check_hover("
4032create table public.users(id int, email text);
4033update public.users set email$0 = 'new@example.com' where id = 1;
4034"), @r"
4035 hover: column public.users.email text
4036 ╭▸
4037 3 │ update public.users set email = 'new@example.com' where id = 1;
4038 ╰╴ ─ hover
4039 ");
4040 }
4041
4042 #[test]
4043 fn hover_on_update_where_column() {
4044 assert_snapshot!(check_hover("
4045create table users(id int, email text);
4046update users set email = 'new@example.com' where id$0 = 1;
4047"), @r"
4048 hover: column public.users.id int
4049 ╭▸
4050 3 │ update users set email = 'new@example.com' where id = 1;
4051 ╰╴ ─ hover
4052 ");
4053 }
4054
4055 #[test]
4056 fn hover_on_update_where_column_with_schema() {
4057 assert_snapshot!(check_hover("
4058create table public.users(id int, email text);
4059update public.users set email = 'new@example.com' where id$0 = 1;
4060"), @r"
4061 hover: column public.users.id int
4062 ╭▸
4063 3 │ update public.users set email = 'new@example.com' where id = 1;
4064 ╰╴ ─ hover
4065 ");
4066 }
4067
4068 #[test]
4069 fn hover_on_update_from_table() {
4070 assert_snapshot!(check_hover("
4071create table users(id int, email text);
4072create table messages(id int, user_id int, email text);
4073update users set email = messages.email from messages$0 where users.id = messages.user_id;
4074"), @r"
4075 hover: table public.messages(id int, user_id int, email text)
4076 ╭▸
4077 4 │ update users set email = messages.email from messages where users.id = messages.user_id;
4078 ╰╴ ─ hover
4079 ");
4080 }
4081
4082 #[test]
4083 fn hover_on_update_from_table_with_schema() {
4084 assert_snapshot!(check_hover("
4085create table users(id int, email text);
4086create table public.messages(id int, user_id int, email text);
4087update users set email = messages.email from public.messages$0 where users.id = messages.user_id;
4088"), @r"
4089 hover: table public.messages(id int, user_id int, email text)
4090 ╭▸
4091 4 │ update users set email = messages.email from public.messages where users.id = messages.user_id;
4092 ╰╴ ─ hover
4093 ");
4094 }
4095
4096 #[test]
4097 fn hover_on_update_with_cte_table() {
4098 assert_snapshot!(check_hover("
4099create table users(id int, email text);
4100with new_data as (
4101 select 1 as id, 'new@example.com' as email
4102)
4103update users set email = new_data.email from new_data$0 where users.id = new_data.id;
4104"), @r"
4105 hover: with new_data as (select 1 as id, 'new@example.com' as email)
4106 ╭▸
4107 6 │ update users set email = new_data.email from new_data where users.id = new_data.id;
4108 ╰╴ ─ hover
4109 ");
4110 }
4111
4112 #[test]
4113 fn hover_on_update_with_cte_column_in_set() {
4114 assert_snapshot!(check_hover("
4115create table users(id int, email text);
4116with new_data as (
4117 select 1 as id, 'new@example.com' as email
4118)
4119update users set email = new_data.email$0 from new_data where users.id = new_data.id;
4120"), @"
4121 hover: column new_data.email text
4122 ╭▸
4123 6 │ update users set email = new_data.email from new_data where users.id = new_data.id;
4124 ╰╴ ─ hover
4125 ");
4126 }
4127
4128 #[test]
4129 fn hover_on_update_with_cte_column_in_where() {
4130 assert_snapshot!(check_hover("
4131create table users(id int, email text);
4132with new_data as (
4133 select 1 as id, 'new@example.com' as email
4134)
4135update users set email = new_data.email from new_data where new_data.id$0 = users.id;
4136"), @"
4137 hover: column new_data.id integer
4138 ╭▸
4139 6 │ update users set email = new_data.email from new_data where new_data.id = users.id;
4140 ╰╴ ─ hover
4141 ");
4142 }
4143
4144 #[test]
4145 fn hover_on_create_view_definition() {
4146 assert_snapshot!(check_hover("
4147create view v$0 as select 1;
4148"), @r"
4149 hover: view public.v as select 1
4150 ╭▸
4151 2 │ create view v as select 1;
4152 ╰╴ ─ hover
4153 ");
4154 }
4155
4156 #[test]
4157 fn hover_on_create_view_definition_with_schema() {
4158 assert_snapshot!(check_hover("
4159create view myschema.v$0 as select 1;
4160"), @r"
4161 hover: view myschema.v as select 1
4162 ╭▸
4163 2 │ create view myschema.v as select 1;
4164 ╰╴ ─ hover
4165 ");
4166 }
4167
4168 #[test]
4169 fn hover_on_create_temp_view_definition() {
4170 assert_snapshot!(check_hover("
4171create temp view v$0 as select 1;
4172"), @r"
4173 hover: view pg_temp.v as select 1
4174 ╭▸
4175 2 │ create temp view v as select 1;
4176 ╰╴ ─ hover
4177 ");
4178 }
4179
4180 #[test]
4181 fn hover_on_create_view_with_column_list() {
4182 assert_snapshot!(check_hover("
4183create view v(col1$0) as select 1;
4184"), @"
4185 hover: column public.v.col1 integer
4186 ╭▸
4187 2 │ create view v(col1) as select 1;
4188 ╰╴ ─ hover
4189 ");
4190 }
4191
4192 #[test]
4193 fn hover_on_create_view_create_table_select_col() {
4194 assert_snapshot!(check_hover("
4195create table t(a bigint);
4196create view v as
4197 select a from t;
4198select a$0 from v;
4199"), @"
4200 hover: column public.v.a bigint
4201 ╭▸
4202 5 │ select a from v;
4203 ╰╴ ─ hover
4204 ");
4205 }
4206
4207 #[test]
4208 fn hover_on_select_from_view() {
4209 assert_snapshot!(check_hover("
4210create view v as select 1;
4211select * from v$0;
4212"), @r"
4213 hover: view public.v as select 1
4214 ╭▸
4215 3 │ select * from v;
4216 ╰╴ ─ hover
4217 ");
4218 }
4219
4220 #[test]
4221 fn hover_on_select_column_from_view_column_list() {
4222 assert_snapshot!(check_hover("
4223create view v(a) as select 1;
4224select a$0 from v;
4225"), @"
4226 hover: column public.v.a integer
4227 ╭▸
4228 3 │ select a from v;
4229 ╰╴ ─ hover
4230 ");
4231 }
4232
4233 #[test]
4234 fn hover_on_select_column_from_view_column_list_overrides_target() {
4235 assert_snapshot!(check_hover("
4236create view v(a) as select 1, 2 b;
4237select a, b$0 from v;
4238"), @"
4239 hover: column public.v.b integer
4240 ╭▸
4241 3 │ select a, b from v;
4242 ╰╴ ─ hover
4243 ");
4244 }
4245
4246 #[test]
4247 fn hover_on_select_column_from_view_target_list() {
4248 assert_snapshot!(check_hover("
4249create view v as select 1 a, 2 b;
4250select a$0, b from v;
4251"), @"
4252 hover: column public.v.a integer
4253 ╭▸
4254 3 │ select a, b from v;
4255 ╰╴ ─ hover
4256 ");
4257 }
4258
4259 #[test]
4260 fn hover_on_create_table_as_column() {
4261 assert_snapshot!(check_hover("
4262create table t as select 1 a;
4263select a$0 from t;
4264"), @"
4265 hover: column public.t.a integer
4266 ╭▸
4267 3 │ select a from t;
4268 ╰╴ ─ hover
4269 ");
4270 }
4271
4272 #[test]
4273 fn hover_on_create_table_as_table() {
4274 assert_snapshot!(check_hover("
4275create table t as select 1 a;
4276select a from t$0;
4277"), @"
4278 hover: table public.t as select 1 a
4279 ╭▸
4280 3 │ select a from t;
4281 ╰╴ ─ hover
4282 ");
4283 }
4284
4285 #[test]
4286 fn hover_on_select_from_view_with_schema() {
4287 assert_snapshot!(check_hover("
4288create view myschema.v as select 1;
4289select * from myschema.v$0;
4290"), @r"
4291 hover: view myschema.v as select 1
4292 ╭▸
4293 3 │ select * from myschema.v;
4294 ╰╴ ─ hover
4295 ");
4296 }
4297
4298 #[test]
4299 fn hover_on_drop_view() {
4300 assert_snapshot!(check_hover("
4301create view v as select 1;
4302drop view v$0;
4303"), @r"
4304 hover: view public.v as select 1
4305 ╭▸
4306 3 │ drop view v;
4307 ╰╴ ─ hover
4308 ");
4309 }
4310
4311 #[test]
4312 fn hover_composite_type_field() {
4313 assert_snapshot!(check_hover("
4314create type person_info as (name varchar(50), age int);
4315with team as (
4316 select 1 as id, ('Alice', 30)::person_info as member
4317)
4318select (member).name$0, (member).age from team;
4319"), @r"
4320 hover: field public.person_info.name varchar(50)
4321 ╭▸
4322 6 │ select (member).name, (member).age from team;
4323 ╰╴ ─ hover
4324 ");
4325 }
4326
4327 #[test]
4328 fn hover_composite_type_field_age() {
4329 assert_snapshot!(check_hover("
4330create type person_info as (name varchar(50), age int);
4331with team as (
4332 select 1 as id, ('Alice', 30)::person_info as member
4333)
4334select (member).name, (member).age$0 from team;
4335"), @r"
4336 hover: field public.person_info.age int
4337 ╭▸
4338 6 │ select (member).name, (member).age from team;
4339 ╰╴ ─ hover
4340 ");
4341 }
4342
4343 #[test]
4344 fn hover_composite_type_field_nested_parens() {
4345 assert_snapshot!(check_hover("
4346create type person_info as (name varchar(50), age int);
4347with team as (
4348 select 1 as id, ('Alice', 30)::person_info as member
4349)
4350select ((((member))).name$0) from team;
4351"), @r"
4352 hover: field public.person_info.name varchar(50)
4353 ╭▸
4354 6 │ select ((((member))).name) from team;
4355 ╰╴ ─ hover
4356 ");
4357 }
4358
4359 #[test]
4360 fn hover_on_join_using_column() {
4361 assert_snapshot!(check_hover("
4362create table t(id int);
4363create table u(id int);
4364select * from t join u using (id$0);
4365"), @r"
4366 hover: column public.t.id int
4367 column public.u.id int
4368 ╭▸
4369 4 │ select * from t join u using (id);
4370 ╰╴ ─ hover
4371 ");
4372 }
4373
4374 #[test]
4375 fn hover_on_truncate_table() {
4376 assert_snapshot!(check_hover("
4377create table users(id int, email text);
4378truncate table users$0;
4379"), @r"
4380 hover: table public.users(id int, email text)
4381 ╭▸
4382 3 │ truncate table users;
4383 ╰╴ ─ hover
4384 ");
4385 }
4386
4387 #[test]
4388 fn hover_on_truncate_table_without_table_keyword() {
4389 assert_snapshot!(check_hover("
4390create table users(id int, email text);
4391truncate users$0;
4392"), @r"
4393 hover: table public.users(id int, email text)
4394 ╭▸
4395 3 │ truncate users;
4396 ╰╴ ─ hover
4397 ");
4398 }
4399
4400 #[test]
4401 fn hover_on_lock_table() {
4402 assert_snapshot!(check_hover("
4403create table users(id int, email text);
4404lock table users$0;
4405"), @r"
4406 hover: table public.users(id int, email text)
4407 ╭▸
4408 3 │ lock table users;
4409 ╰╴ ─ hover
4410 ");
4411 }
4412
4413 #[test]
4414 fn hover_on_lock_table_without_table_keyword() {
4415 assert_snapshot!(check_hover("
4416create table users(id int, email text);
4417lock users$0;
4418"), @r"
4419 hover: table public.users(id int, email text)
4420 ╭▸
4421 3 │ lock users;
4422 ╰╴ ─ hover
4423 ");
4424 }
4425
4426 #[test]
4427 fn hover_on_vacuum_table() {
4428 assert_snapshot!(check_hover("
4429create table users(id int, email text);
4430vacuum users$0;
4431"), @r"
4432 hover: table public.users(id int, email text)
4433 ╭▸
4434 3 │ vacuum users;
4435 ╰╴ ─ hover
4436 ");
4437 }
4438
4439 #[test]
4440 fn hover_on_vacuum_with_analyze() {
4441 assert_snapshot!(check_hover("
4442create table users(id int, email text);
4443vacuum analyze users$0;
4444"), @r"
4445 hover: table public.users(id int, email text)
4446 ╭▸
4447 3 │ vacuum analyze users;
4448 ╰╴ ─ hover
4449 ");
4450 }
4451
4452 #[test]
4453 fn hover_on_alter_table() {
4454 assert_snapshot!(check_hover("
4455create table users(id int, email text);
4456alter table users$0 alter email set not null;
4457"), @r"
4458 hover: table public.users(id int, email text)
4459 ╭▸
4460 3 │ alter table users alter email set not null;
4461 ╰╴ ─ hover
4462 ");
4463 }
4464
4465 #[test]
4466 fn hover_on_alter_table_column() {
4467 assert_snapshot!(check_hover("
4468create table users(id int, email text);
4469alter table users alter email$0 set not null;
4470"), @r"
4471 hover: column public.users.email text
4472 ╭▸
4473 3 │ alter table users alter email set not null;
4474 ╰╴ ─ hover
4475 ");
4476 }
4477
4478 #[test]
4479 fn hover_on_refresh_materialized_view() {
4480 assert_snapshot!(check_hover("
4481create materialized view mv as select 1;
4482refresh materialized view mv$0;
4483"), @r"
4484 hover: materialized view public.mv as select 1
4485 ╭▸
4486 3 │ refresh materialized view mv;
4487 ╰╴ ─ hover
4488 ");
4489 }
4490
4491 #[test]
4492 fn hover_on_reindex_table() {
4493 assert_snapshot!(check_hover("
4494create table users(id int);
4495reindex table users$0;
4496"), @r"
4497 hover: table public.users(id int)
4498 ╭▸
4499 3 │ reindex table users;
4500 ╰╴ ─ hover
4501 ");
4502 }
4503
4504 #[test]
4505 fn hover_on_reindex_index() {
4506 assert_snapshot!(check_hover("
4507create table t(c int);
4508create index idx on t(c);
4509reindex index idx$0;
4510"), @r"
4511 hover: index public.idx on public.t(c)
4512 ╭▸
4513 4 │ reindex index idx;
4514 ╰╴ ─ hover
4515 ");
4516 }
4517
4518 #[test]
4519 fn hover_merge_returning_star_from_cte() {
4520 assert_snapshot!(check_hover("
4521create table t(a int, b int);
4522with u(x, y) as (
4523 select 1, 2
4524),
4525merged as (
4526 merge into t
4527 using u
4528 on t.a = u.x
4529 when matched then
4530 do nothing
4531 when not matched then
4532 do nothing
4533 returning a as x, b as y
4534)
4535select *$0 from merged;
4536"), @r"
4537 hover: column merged.x int
4538 column merged.y int
4539 ╭▸
4540 16 │ select * from merged;
4541 ╰╴ ─ hover
4542 ");
4543 }
4544
4545 #[test]
4546 fn hover_cte_insert_returning_aliased_column() {
4547 assert_snapshot!(check_hover("
4548create table t(a int, b int);
4549with inserted as (
4550 insert into t values (1, 2)
4551 returning a as x, b as y
4552)
4553select x$0 from inserted;
4554"), @r"
4555 hover: column inserted.x int
4556 ╭▸
4557 7 │ select x from inserted;
4558 ╰╴ ─ hover
4559 ");
4560 }
4561
4562 #[test]
4563 fn hover_cte_update_returning_aliased_column() {
4564 assert_snapshot!(check_hover("
4565create table t(a int, b int);
4566with updated as (
4567 update t set a = 42
4568 returning a as x, b as y
4569)
4570select x$0 from updated;
4571"), @r"
4572 hover: column updated.x int
4573 ╭▸
4574 7 │ select x from updated;
4575 ╰╴ ─ hover
4576 ");
4577 }
4578
4579 #[test]
4580 fn hover_cte_delete_returning_aliased_column() {
4581 assert_snapshot!(check_hover("
4582create table t(a int, b int);
4583with deleted as (
4584 delete from t
4585 returning a as x, b as y
4586)
4587select x$0 from deleted;
4588"), @r"
4589 hover: column deleted.x int
4590 ╭▸
4591 7 │ select x from deleted;
4592 ╰╴ ─ hover
4593 ");
4594 }
4595
4596 #[test]
4597 fn hover_update_returning_star() {
4598 assert_snapshot!(check_hover("
4599create table t(a int, b int);
4600update t set a = 1
4601returning *$0;
4602"), @r"
4603 hover: column public.t.a int
4604 column public.t.b int
4605 ╭▸
4606 4 │ returning *;
4607 ╰╴ ─ hover
4608 ");
4609 }
4610
4611 #[test]
4612 fn hover_insert_returning_star() {
4613 assert_snapshot!(check_hover("
4614create table t(a int, b int);
4615insert into t values (1, 2)
4616returning *$0;
4617"), @r"
4618 hover: column public.t.a int
4619 column public.t.b int
4620 ╭▸
4621 4 │ returning *;
4622 ╰╴ ─ hover
4623 ");
4624 }
4625
4626 #[test]
4627 fn hover_delete_returning_star() {
4628 assert_snapshot!(check_hover("
4629create table t(a int, b int);
4630delete from t
4631returning *$0;
4632"), @r"
4633 hover: column public.t.a int
4634 column public.t.b int
4635 ╭▸
4636 4 │ returning *;
4637 ╰╴ ─ hover
4638 ");
4639 }
4640
4641 #[test]
4642 fn hover_merge_returning_star() {
4643 assert_snapshot!(check_hover("
4644create table t(a int, b int);
4645merge into t
4646 using (select 1 as x, 2 as y) u
4647 on t.a = u.x
4648 when matched then
4649 do nothing
4650returning *$0;
4651"), @r"
4652 hover: column public.t.a int
4653 column public.t.b int
4654 ╭▸
4655 8 │ returning *;
4656 ╰╴ ─ hover
4657 ");
4658 }
4659
4660 #[test]
4661 fn hover_merge_returning_qualified_star_old() {
4662 assert_snapshot!(check_hover("
4663create table t(a int, b int);
4664merge into t
4665 using (select 1 as x, 2 as y) u
4666 on t.a = u.x
4667 when matched then
4668 update set a = 99
4669returning old$0.*;
4670"), @r"
4671 hover: table public.t(a int, b int)
4672 ╭▸
4673 8 │ returning old.*;
4674 ╰╴ ─ hover
4675 ");
4676 }
4677
4678 #[test]
4679 fn hover_merge_returning_qualified_star_new() {
4680 assert_snapshot!(check_hover("
4681create table t(a int, b int);
4682merge into t
4683 using (select 1 as x, 2 as y) u
4684 on t.a = u.x
4685 when matched then
4686 update set a = 99
4687returning new$0.*;
4688"), @r"
4689 hover: table public.t(a int, b int)
4690 ╭▸
4691 8 │ returning new.*;
4692 ╰╴ ─ hover
4693 ");
4694 }
4695
4696 #[test]
4697 fn hover_merge_returning_qualified_star_table() {
4698 assert_snapshot!(check_hover("
4699create table t(a int, b int);
4700merge into t
4701 using (select 1 as x, 2 as y) u
4702 on t.a = u.x
4703 when matched then
4704 update set a = 99
4705returning t$0.*;
4706"), @r"
4707 hover: table public.t(a int, b int)
4708 ╭▸
4709 8 │ returning t.*;
4710 ╰╴ ─ hover
4711 ");
4712 }
4713
4714 #[test]
4715 fn hover_merge_returning_qualified_star_old_on_star() {
4716 assert_snapshot!(check_hover("
4717create table t(a int, b int);
4718merge into t
4719 using (select 1 as x, 2 as y) u
4720 on t.a = u.x
4721 when matched then
4722 update set a = 99
4723returning old.*$0;
4724"), @r"
4725 hover: column public.t.a int
4726 column public.t.b int
4727 ╭▸
4728 8 │ returning old.*;
4729 ╰╴ ─ hover
4730 ");
4731 }
4732
4733 #[test]
4734 fn hover_merge_returning_qualified_star_new_on_star() {
4735 assert_snapshot!(check_hover("
4736create table t(a int, b int);
4737merge into t
4738 using (select 1 as x, 2 as y) u
4739 on t.a = u.x
4740 when matched then
4741 update set a = 99
4742returning new.*$0;
4743"), @r"
4744 hover: column public.t.a int
4745 column public.t.b int
4746 ╭▸
4747 8 │ returning new.*;
4748 ╰╴ ─ hover
4749 ");
4750 }
4751
4752 #[test]
4753 fn hover_merge_returning_qualified_star_table_on_star() {
4754 assert_snapshot!(check_hover("
4755create table t(a int, b int);
4756merge into t
4757 using (select 1 as x, 2 as y) u
4758 on t.a = u.x
4759 when matched then
4760 update set a = 99
4761returning t.*$0;
4762"), @r"
4763 hover: column public.t.a int
4764 column public.t.b int
4765 ╭▸
4766 8 │ returning t.*;
4767 ╰╴ ─ hover
4768 ");
4769 }
4770
4771 #[test]
4772 fn hover_partition_table_column() {
4773 assert_snapshot!(check_hover("
4774create table part (
4775 a int,
4776 inserted_at timestamptz not null default now()
4777) partition by range (inserted_at);
4778create table part_2026_01_02 partition of part
4779 for values from ('2026-01-02') to ('2026-01-03');
4780select a$0 from part_2026_01_02;
4781"), @r"
4782 hover: column public.part.a int
4783 ╭▸
4784 8 │ select a from part_2026_01_02;
4785 ╰╴ ─ hover
4786 ");
4787 }
4788
4789 #[test]
4790 fn hover_select_window_def_reuse() {
4791 assert_snapshot!(check_hover("
4792create table tbl (
4793 id bigint primary key,
4794 group_col text not null,
4795 update_date date not null,
4796 value text
4797);
4798select
4799 id,
4800 group_col,
4801 row_number() over w as rn,
4802 lag(value) over w$0 as prev_value
4803from tbl
4804window w as (
4805 partition by group_col
4806 order by update_date desc
4807);
4808"), @r"
4809hover: window w as (
4810 partition by group_col
4811 order by update_date desc
4812 )
4813 ╭▸
481412 │ lag(value) over w as prev_value
4815 ╰╴ ─ hover
4816 ");
4817 }
4818
4819 #[test]
4820 fn hover_create_table_like_multi_star() {
4821 assert_snapshot!(check_hover("
4822create table t(a int, b int);
4823create table u(x int, y int);
4824create table k(like t, like u, c int);
4825select *$0 from k;
4826"), @r"
4827 hover: column public.k.a int
4828 column public.k.b int
4829 column public.k.x int
4830 column public.k.y int
4831 column public.k.c int
4832 ╭▸
4833 5 │ select * from k;
4834 ╰╴ ─ hover
4835 ");
4836 }
4837
4838 #[test]
4839 fn hover_create_table_inherits_star() {
4840 assert_snapshot!(check_hover("
4841create table t (
4842 a int, b text
4843);
4844create table u (
4845 c int
4846) inherits (t);
4847select *$0 from u;
4848"), @r"
4849 hover: column public.u.a int
4850 column public.u.b text
4851 column public.u.c int
4852 ╭▸
4853 8 │ select * from u;
4854 ╰╴ ─ hover
4855 ");
4856 }
4857
4858 #[test]
4859 fn hover_create_table_inherits_builtin_star() {
4860 assert_snapshot!(check_hover_info("
4861create table t ()
4862inherits (information_schema.sql_features);
4863select *$0 from t;
4864").snippet, @"
4865 column public.t.feature_id character_data
4866 column public.t.feature_name character_data
4867 column public.t.sub_feature_id character_data
4868 column public.t.sub_feature_name character_data
4869 column public.t.is_supported yes_or_no
4870 column public.t.is_verified_by character_data
4871 column public.t.comments character_data
4872 ");
4873 }
4874
4875 #[test]
4876 fn hover_create_table_like_builtin_star() {
4877 assert_snapshot!(check_hover_info("
4878create table t (like information_schema.sql_features);
4879select *$0 from t;
4880").snippet, @"
4881 column public.t.feature_id character_data
4882 column public.t.feature_name character_data
4883 column public.t.sub_feature_id character_data
4884 column public.t.sub_feature_name character_data
4885 column public.t.is_supported yes_or_no
4886 column public.t.is_verified_by character_data
4887 column public.t.comments character_data
4888 ");
4889 }
4890
4891 #[test]
4892 fn hover_create_table_inherits_create_table_as_star() {
4893 assert_snapshot!(check_hover_info("
4894create table parent as select 1 a, 'x'::text b;
4895create table child (c int) inherits (parent);
4896select *$0 from child;
4897").snippet, @"
4898 column public.child.a integer
4899 column public.child.b text
4900 column public.child.c int
4901 ");
4902 }
4903
4904 #[test]
4905 fn hover_create_table_like_select_into_star() {
4906 assert_snapshot!(check_hover_info("
4907select 1 a, 'x'::text b into parent;
4908create table child (like parent);
4909select *$0 from child;
4910").snippet, @"
4911 column public.child.a integer
4912 column public.child.b text
4913 ");
4914 }
4915
4916 #[test]
4917 fn hover_create_table_like_view_star() {
4918 assert_snapshot!(check_hover_info("
4919create view parent as select 1 a, 'x'::text b;
4920create table child (like parent);
4921select *$0 from child;
4922").snippet, @"
4923 column public.child.a integer
4924 column public.child.b text
4925 ");
4926 }
4927
4928 #[test]
4929 fn hover_create_table_inherits_column() {
4930 assert_snapshot!(check_hover("
4931create table t (
4932 a int, b text
4933);
4934create table u (
4935 c int
4936) inherits (t);
4937select a$0 from u;
4938"), @r"
4939 hover: column public.t.a int
4940 ╭▸
4941 8 │ select a from u;
4942 ╰╴ ─ hover
4943 ");
4944 }
4945
4946 #[test]
4947 fn hover_create_table_inherits_builtin_column() {
4948 assert_snapshot!(check_hover("
4949create table t ()
4950inherits (information_schema.sql_features);
4951select feature_name$0 from t;
4952"), @"
4953 hover: column information_schema.sql_features.feature_name information_schema.character_data
4954 ╭▸
4955 4 │ select feature_name from t;
4956 ╰╴ ─ hover
4957 ");
4958 }
4959
4960 #[test]
4961 fn hover_create_table_inherits_local_column() {
4962 assert_snapshot!(check_hover("
4963create table t (
4964 a int, b text
4965);
4966create table u (
4967 c int
4968) inherits (t);
4969select c$0 from u;
4970"), @r"
4971 hover: column public.u.c int
4972 ╭▸
4973 8 │ select c from u;
4974 ╰╴ ─ hover
4975 ");
4976 }
4977
4978 #[test]
4979 fn hover_create_table_inherits_multiple_parents() {
4980 assert_snapshot!(check_hover("
4981create table t1 (
4982 a int
4983);
4984create table t2 (
4985 b text
4986);
4987create table u (
4988 c int
4989) inherits (t1, t2);
4990select b$0 from u;
4991"), @r"
4992 hover: column public.t2.b text
4993 ╭▸
4994 11 │ select b from u;
4995 ╰╴ ─ hover
4996 ");
4997 }
4998
4999 #[test]
5000 fn hover_create_foreign_table_inherits_column() {
5001 assert_snapshot!(check_hover("
5002create server myserver foreign data wrapper postgres_fdw;
5003create table t (
5004 a int, b text
5005);
5006create foreign table u (
5007 c int
5008) inherits (t) server myserver;
5009select a$0 from u;
5010"), @r"
5011 hover: column public.t.a int
5012 ╭▸
5013 9 │ select a from u;
5014 ╰╴ ─ hover
5015 ");
5016 }
5017
5018 #[test]
5019 fn hover_extension_on_create() {
5020 assert_snapshot!(check_hover("
5021create extension my$0ext;
5022"), @r"
5023 hover: extension myext
5024 ╭▸
5025 2 │ create extension myext;
5026 ╰╴ ─ hover
5027 ");
5028 }
5029
5030 #[test]
5031 fn hover_extension_on_drop() {
5032 assert_snapshot!(check_hover("
5033create extension myext;
5034drop extension my$0ext;
5035"), @r"
5036 hover: extension myext
5037 ╭▸
5038 3 │ drop extension myext;
5039 ╰╴ ─ hover
5040 ");
5041 }
5042
5043 #[test]
5044 fn hover_extension_on_alter() {
5045 assert_snapshot!(check_hover("
5046create extension myext;
5047alter extension my$0ext update to '2.0';
5048"), @r"
5049 hover: extension myext
5050 ╭▸
5051 3 │ alter extension myext update to '2.0';
5052 ╰╴ ─ hover
5053 ");
5054 }
5055
5056 #[test]
5057 fn hover_role_on_create() {
5058 assert_snapshot!(check_hover("
5059create role read$0er;
5060"), @r"
5061 hover: role reader
5062 ╭▸
5063 2 │ create role reader;
5064 ╰╴ ─ hover
5065 ");
5066 }
5067
5068 #[test]
5069 fn hover_role_on_alter() {
5070 assert_snapshot!(check_hover("
5071create role reader;
5072alter role read$0er rename to writer;
5073"), @r"
5074 hover: role reader
5075 ╭▸
5076 3 │ alter role reader rename to writer;
5077 ╰╴ ─ hover
5078 ");
5079 }
5080
5081 #[test]
5082 fn hover_role_on_drop() {
5083 assert_snapshot!(check_hover("
5084create role reader;
5085drop role read$0er;
5086"), @r"
5087 hover: role reader
5088 ╭▸
5089 3 │ drop role reader;
5090 ╰╴ ─ hover
5091 ");
5092 }
5093
5094 #[test]
5095 fn hover_role_on_set() {
5096 assert_snapshot!(check_hover("
5097create role reader;
5098set role read$0er;
5099"), @r"
5100 hover: role reader
5101 ╭▸
5102 3 │ set role reader;
5103 ╰╴ ─ hover
5104 ");
5105 }
5106
5107 #[test]
5108 fn hover_role_on_create_tablespace_owner() {
5109 assert_snapshot!(check_hover("
5110create role reader;
5111create tablespace t owner read$0er location 'foo';
5112"), @r"
5113 hover: role reader
5114 ╭▸
5115 3 │ create tablespace t owner reader location 'foo';
5116 ╰╴ ─ hover
5117 ");
5118 }
5119
5120 #[test]
5121 fn hover_on_fetch_cursor() {
5122 assert_snapshot!(check_hover("
5123declare c scroll cursor for select * from t;
5124fetch forward 5 from c$0;
5125"), @r"
5126 hover: cursor c for select * from t
5127 ╭▸
5128 3 │ fetch forward 5 from c;
5129 ╰╴ ─ hover
5130 ");
5131 }
5132
5133 #[test]
5134 fn hover_on_close_cursor() {
5135 assert_snapshot!(check_hover("
5136declare c scroll cursor for select * from t;
5137close c$0;
5138"), @r"
5139 hover: cursor c for select * from t
5140 ╭▸
5141 3 │ close c;
5142 ╰╴ ─ hover
5143 ");
5144 }
5145
5146 #[test]
5147 fn hover_on_move_cursor() {
5148 assert_snapshot!(check_hover("
5149declare c scroll cursor for select * from t;
5150move forward 10 from c$0;
5151"), @r"
5152 hover: cursor c for select * from t
5153 ╭▸
5154 3 │ move forward 10 from c;
5155 ╰╴ ─ hover
5156 ");
5157 }
5158
5159 #[test]
5160 fn hover_on_prepare_statement() {
5161 assert_snapshot!(check_hover("
5162prepare stmt$0 as select 1;
5163"), @r"
5164 hover: prepare stmt as select 1
5165 ╭▸
5166 2 │ prepare stmt as select 1;
5167 ╰╴ ─ hover
5168 ");
5169 }
5170
5171 #[test]
5172 fn hover_on_execute_prepared_statement() {
5173 assert_snapshot!(check_hover("
5174prepare stmt as select 1;
5175execute stmt$0;
5176"), @r"
5177 hover: prepare stmt as select 1
5178 ╭▸
5179 3 │ execute stmt;
5180 ╰╴ ─ hover
5181 ");
5182 }
5183
5184 #[test]
5185 fn hover_on_deallocate_prepared_statement() {
5186 assert_snapshot!(check_hover("
5187prepare stmt as select 1;
5188deallocate stmt$0;
5189"), @r"
5190 hover: prepare stmt as select 1
5191 ╭▸
5192 3 │ deallocate stmt;
5193 ╰╴ ─ hover
5194 ");
5195 }
5196
5197 #[test]
5198 fn hover_on_listen_definition() {
5199 assert_snapshot!(check_hover("
5200listen updates$0;
5201"), @r"
5202 hover: listen updates
5203 ╭▸
5204 2 │ listen updates;
5205 ╰╴ ─ hover
5206 ");
5207 }
5208
5209 #[test]
5210 fn hover_on_notify_channel() {
5211 assert_snapshot!(check_hover("
5212listen updates;
5213notify updates$0;
5214"), @r"
5215 hover: listen updates
5216 ╭▸
5217 3 │ notify updates;
5218 ╰╴ ─ hover
5219 ");
5220 }
5221
5222 #[test]
5223 fn hover_on_unlisten_channel() {
5224 assert_snapshot!(check_hover("
5225listen updates;
5226unlisten updates$0;
5227"), @"
5228 hover: listen updates
5229 ╭▸
5230 3 │ unlisten updates;
5231 ╰╴ ─ hover
5232 ");
5233 }
5234
5235 #[test]
5236 fn hover_property_graph_on_create() {
5237 assert_snapshot!(check_hover("
5238create property graph foo.ba$0r vertex tables (t key (a) no properties);
5239"), @"
5240 hover: property graph foo.bar
5241 ╭▸
5242 2 │ create property graph foo.bar vertex tables (t key (a) no properties);
5243 ╰╴ ─ hover
5244 ");
5245 }
5246
5247 #[test]
5248 fn hover_property_graph_on_drop() {
5249 assert_snapshot!(check_hover("
5250create property graph foo.bar vertex tables (t key (a) no properties);
5251drop property graph foo.ba$0r;
5252"), @"
5253 hover: property graph foo.bar
5254 ╭▸
5255 3 │ drop property graph foo.bar;
5256 ╰╴ ─ hover
5257 ");
5258 }
5259
5260 #[test]
5261 fn hover_property_graph_on_alter() {
5262 assert_snapshot!(check_hover("
5263create property graph foo.bar vertex tables (t key (a) no properties);
5264alter property graph foo.ba$0r rename to baz;
5265"), @"
5266 hover: property graph foo.bar
5267 ╭▸
5268 3 │ alter property graph foo.bar rename to baz;
5269 ╰╴ ─ hover
5270 ");
5271 }
5272}