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