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