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