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