squawk_ide/
hover.rs

1use crate::classify::{NameClass, NameRefClass, classify_name, classify_name_ref};
2use crate::column_name::ColumnName;
3use crate::offsets::token_from_offset;
4use crate::resolve;
5use crate::{binder, symbols::Name};
6use rowan::TextSize;
7use squawk_syntax::SyntaxNode;
8use squawk_syntax::{
9    SyntaxKind,
10    ast::{self, AstNode},
11};
12
13pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
14    let token = token_from_offset(file, offset)?;
15    let parent = token.parent()?;
16
17    let root = file.syntax();
18    let binder = binder::bind(file);
19
20    if token.kind() == SyntaxKind::STAR {
21        if let Some(field_expr) = ast::FieldExpr::cast(parent.clone())
22            && field_expr.star_token().is_some()
23            && let Some(result) = hover_qualified_star(root, &field_expr, &binder)
24        {
25            return Some(result);
26        }
27
28        if let Some(arg_list) = ast::ArgList::cast(parent.clone())
29            && let Some(result) = hover_unqualified_star_in_arg_list(root, &arg_list, &binder)
30        {
31            return Some(result);
32        }
33
34        if let Some(target) = ast::Target::cast(parent.clone())
35            && target.star_token().is_some()
36            && let Some(result) = hover_unqualified_star(root, &target, &binder)
37        {
38            return Some(result);
39        }
40    }
41
42    if let Some(name_ref) = ast::NameRef::cast(parent.clone()) {
43        let context = classify_name_ref(&name_ref)?;
44        match context {
45            NameRefClass::CreateIndexColumn
46            | NameRefClass::InsertColumn
47            | NameRefClass::DeleteWhereColumn
48            | NameRefClass::UpdateWhereColumn
49            | NameRefClass::UpdateSetColumn
50            | NameRefClass::UpdateReturningColumn
51            | NameRefClass::InsertReturningColumn
52            | NameRefClass::DeleteReturningColumn
53            | NameRefClass::MergeReturningColumn
54            | NameRefClass::MergeWhenColumn
55            | NameRefClass::MergeOnColumn
56            | NameRefClass::CheckConstraintColumn
57            | NameRefClass::GeneratedColumn
58            | NameRefClass::UniqueConstraintColumn
59            | NameRefClass::PrimaryKeyConstraintColumn
60            | NameRefClass::NotNullConstraintColumn
61            | NameRefClass::ExcludeConstraintColumn
62            | NameRefClass::PartitionByColumn
63            | NameRefClass::JoinUsingColumn
64            | NameRefClass::ForeignKeyColumn
65            | NameRefClass::ForeignKeyLocalColumn
66            | NameRefClass::SequenceOwnedByColumn
67            | NameRefClass::AlterTableColumn
68            | NameRefClass::AlterTableDropColumn => {
69                return hover_column(root, &name_ref, &binder);
70            }
71            NameRefClass::TypeReference | NameRefClass::DropType => {
72                return hover_type(root, &name_ref, &binder);
73            }
74            NameRefClass::CompositeTypeField => {
75                return hover_composite_type_field(root, &name_ref, &binder);
76            }
77            NameRefClass::SelectColumn | NameRefClass::SelectQualifiedColumn => {
78                // Try hover as column first
79                if let Some(result) = hover_column(root, &name_ref, &binder) {
80                    return Some(result);
81                }
82                // If no column, try as function (handles field-style function calls like `t.b`)
83                if let Some(result) = hover_function(root, &name_ref, &binder) {
84                    return Some(result);
85                }
86                // Finally try as table (handles case like `select t from t;` where t is the table)
87                return hover_table(root, &name_ref, &binder);
88            }
89            NameRefClass::Table
90            | NameRefClass::DropTable
91            | NameRefClass::DropView
92            | NameRefClass::DropMaterializedView
93            | NameRefClass::CreateIndex
94            | NameRefClass::InsertTable
95            | NameRefClass::InsertQualifiedColumnTable
96            | NameRefClass::DeleteTable
97            | NameRefClass::DeleteQualifiedColumnTable
98            | NameRefClass::DeleteUsingTable
99            | NameRefClass::MergeUsingTable
100            | NameRefClass::UpdateTable
101            | NameRefClass::SelectFromTable
102            | NameRefClass::UpdateFromTable
103            | NameRefClass::SelectQualifiedColumnTable
104            | NameRefClass::UpdateSetQualifiedColumnTable
105            | NameRefClass::MergeQualifiedColumnTable
106            | NameRefClass::UpdateReturningQualifiedColumnTable
107            | NameRefClass::InsertReturningQualifiedColumnTable
108            | NameRefClass::DeleteReturningQualifiedColumnTable
109            | NameRefClass::MergeReturningQualifiedColumnTable
110            | NameRefClass::MergeTable
111            | NameRefClass::ForeignKeyTable
112            | NameRefClass::LikeTable
113            | NameRefClass::InheritsTable
114            | NameRefClass::PartitionOfTable
115            | NameRefClass::TruncateTable
116            | NameRefClass::LockTable
117            | NameRefClass::VacuumTable
118            | NameRefClass::AlterTable
119            | NameRefClass::ReindexTable
120            | NameRefClass::RefreshMaterializedView => {
121                return hover_table(root, &name_ref, &binder);
122            }
123            NameRefClass::DropSequence => return hover_sequence(root, &name_ref, &binder),
124            NameRefClass::DropDatabase
125            | NameRefClass::ReindexDatabase
126            | NameRefClass::ReindexSystem => return hover_database(root, &name_ref, &binder),
127            NameRefClass::DropServer
128            | NameRefClass::AlterServer
129            | NameRefClass::CreateServer
130            | NameRefClass::ForeignTableServerName => {
131                return hover_server(root, &name_ref, &binder);
132            }
133            NameRefClass::Tablespace => return hover_tablespace(root, &name_ref, &binder),
134            NameRefClass::DropIndex | NameRefClass::ReindexIndex => {
135                return hover_index(root, &name_ref, &binder);
136            }
137            NameRefClass::DropFunction | NameRefClass::DefaultConstraintFunctionCall => {
138                return hover_function(root, &name_ref, &binder);
139            }
140            NameRefClass::DropAggregate => return hover_aggregate(root, &name_ref, &binder),
141            NameRefClass::DropProcedure | NameRefClass::CallProcedure => {
142                return hover_procedure(root, &name_ref, &binder);
143            }
144            NameRefClass::DropRoutine => return hover_routine(root, &name_ref, &binder),
145            NameRefClass::SelectFunctionCall => {
146                // Try function first, but fall back to column if no function found
147                // (handles function-call-style column access like `select a(t)`)
148                if let Some(result) = hover_function(root, &name_ref, &binder) {
149                    return Some(result);
150                }
151                return hover_column(root, &name_ref, &binder);
152            }
153            NameRefClass::SchemaQualifier
154            | NameRefClass::DropSchema
155            | NameRefClass::CreateSchema
156            | NameRefClass::ReindexSchema => {
157                return hover_schema(root, &name_ref, &binder);
158            }
159        }
160    }
161
162    if let Some(name) = ast::Name::cast(parent) {
163        let context = classify_name(&name)?;
164        match context {
165            NameClass::ColumnDefinition {
166                create_table,
167                column,
168            } => return hover_column_definition(&create_table, &column, &binder),
169            NameClass::CreateTable(create_table) => {
170                return format_create_table(&create_table, &binder);
171            }
172            NameClass::WithTable(with_table) => return format_with_table(&with_table),
173            NameClass::CreateIndex(create_index) => {
174                return format_create_index(&create_index, &binder);
175            }
176            NameClass::CreateSequence(create_sequence) => {
177                return format_create_sequence(&create_sequence, &binder);
178            }
179            NameClass::CreateTablespace(create_tablespace) => {
180                return format_create_tablespace(&create_tablespace);
181            }
182            NameClass::CreateDatabase(create_database) => {
183                return format_create_database(&create_database);
184            }
185            NameClass::CreateServer(create_server) => {
186                return format_create_server(&create_server);
187            }
188            NameClass::CreateType(create_type) => {
189                return format_create_type(&create_type, &binder);
190            }
191            NameClass::CreateFunction(create_function) => {
192                return format_create_function(&create_function, &binder);
193            }
194            NameClass::CreateAggregate(create_aggregate) => {
195                return format_create_aggregate(&create_aggregate, &binder);
196            }
197            NameClass::CreateProcedure(create_procedure) => {
198                return format_create_procedure(&create_procedure, &binder);
199            }
200            NameClass::CreateSchema(create_schema) => {
201                return format_create_schema(&create_schema);
202            }
203            NameClass::ViewColumnList { create_view, name } => {
204                return format_view_column(&create_view, Name::from_node(&name), &binder);
205            }
206            NameClass::CreateView(create_view) => {
207                return format_create_view(&create_view, &binder);
208            }
209        }
210    }
211
212    None
213}
214
215struct ColumnHover {}
216impl ColumnHover {
217    fn table_column(table_name: &str, column_name: &str) -> String {
218        format!("column {table_name}.{column_name}")
219    }
220    fn schema_table_column_type(
221        schema: &str,
222        table_name: &str,
223        column_name: &str,
224        ty: &str,
225    ) -> String {
226        format!("column {schema}.{table_name}.{column_name} {ty}")
227    }
228    fn schema_table_column(schema: &str, table_name: &str, column_name: &str) -> String {
229        format!("column {schema}.{table_name}.{column_name}")
230    }
231}
232
233fn hover_column(
234    root: &SyntaxNode,
235    name_ref: &ast::NameRef,
236    binder: &binder::Binder,
237) -> Option<String> {
238    let column_ptrs = resolve::resolve_name_ref(binder, root, name_ref)?;
239
240    let results: Vec<String> = column_ptrs
241        .iter()
242        .filter_map(|column_ptr| {
243            let column_name_node = column_ptr.to_node(root);
244            format_hover_for_column_node(binder, &column_name_node, name_ref)
245        })
246        .collect();
247
248    if results.is_empty() {
249        return None;
250    }
251
252    Some(results.join("\n"))
253}
254
255fn format_hover_for_column_node(
256    binder: &binder::Binder,
257    column_name_node: &squawk_syntax::SyntaxNode,
258    name_ref: &ast::NameRef,
259) -> Option<String> {
260    for a in column_name_node.ancestors() {
261        if let Some(with_table) = ast::WithTable::cast(a.clone()) {
262            let cte_name = with_table.name()?;
263            let column_name = if column_name_node
264                .ancestors()
265                .any(|a| ast::Values::can_cast(a.kind()))
266            {
267                Name::from_node(name_ref)
268            } else {
269                Name::from_string(column_name_node.text().to_string())
270            };
271            let table_name = Name::from_node(&cte_name);
272            return Some(ColumnHover::table_column(
273                &table_name.to_string(),
274                &column_name.to_string(),
275            ));
276        }
277        if ast::ParenSelect::can_cast(a.kind())
278            && let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast)
279            && let Some(base) = field_expr.base()
280            && let ast::Expr::NameRef(table_name_ref) = base
281        {
282            let table_name = Name::from_node(&table_name_ref);
283            let column_name = Name::from_string(column_name_node.text().to_string());
284            return Some(ColumnHover::table_column(
285                &table_name.to_string(),
286                &column_name.to_string(),
287            ));
288        }
289
290        // create view v(a) as select 1;
291        // select a from v;
292        //        ^
293        if let Some(create_view) = ast::CreateView::cast(a.clone())
294            && let Some(column_name) =
295                ast::Name::cast(column_name_node.clone()).map(|name| Name::from_node(&name))
296        {
297            return format_view_column(&create_view, column_name, binder);
298        }
299    }
300
301    let column = column_name_node.ancestors().find_map(ast::Column::cast)?;
302    let column_name = column.name()?;
303    let ty = column.ty()?;
304
305    let create_table = column
306        .syntax()
307        .ancestors()
308        .find_map(ast::CreateTableLike::cast)?;
309    let path = create_table.path()?;
310    let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
311
312    let schema = schema.to_string();
313    let column_name = Name::from_node(&column_name);
314    let ty = &ty.syntax().text().to_string();
315    Some(ColumnHover::schema_table_column_type(
316        &schema,
317        &table_name,
318        &column_name.to_string(),
319        ty,
320    ))
321}
322
323fn hover_composite_type_field(
324    root: &SyntaxNode,
325    name_ref: &ast::NameRef,
326    binder: &binder::Binder,
327) -> Option<String> {
328    let field_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
329        .into_iter()
330        .next()?;
331    let field_name_node = field_ptr.to_node(root);
332
333    let column = field_name_node.ancestors().find_map(ast::Column::cast)?;
334    let field_name = column.name()?.syntax().text().to_string();
335    let ty = column.ty()?;
336
337    let create_type = column
338        .syntax()
339        .ancestors()
340        .find_map(ast::CreateType::cast)?;
341    let type_path = create_type.path()?;
342    let (schema, type_name) = resolve::resolve_type_info(binder, &type_path)?;
343
344    Some(format!(
345        "field {}.{}.{} {}",
346        schema,
347        type_name,
348        field_name,
349        ty.syntax().text()
350    ))
351}
352
353fn hover_column_definition(
354    create_table: &impl ast::HasCreateTable,
355    column: &ast::Column,
356    binder: &binder::Binder,
357) -> Option<String> {
358    let column_name = column.name()?.syntax().text().to_string();
359    let ty = column.ty()?;
360    let path = create_table.path()?;
361    let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
362    let ty = ty.syntax().text().to_string();
363    Some(ColumnHover::schema_table_column_type(
364        &schema.to_string(),
365        &table_name,
366        &column_name,
367        &ty,
368    ))
369}
370
371fn hover_table(
372    root: &SyntaxNode,
373    name_ref: &ast::NameRef,
374    binder: &binder::Binder,
375) -> Option<String> {
376    if let Some(result) = hover_subquery_table(name_ref) {
377        return Some(result);
378    }
379
380    let table_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
381        .into_iter()
382        .next()?;
383
384    hover_table_from_ptr(root, &table_ptr, binder)
385}
386
387fn hover_table_from_ptr(
388    root: &SyntaxNode,
389    table_ptr: &squawk_syntax::SyntaxNodePtr,
390    binder: &binder::Binder,
391) -> Option<String> {
392    let table_name_node = table_ptr.to_node(root);
393
394    match resolve::find_table_source(&table_name_node)? {
395        resolve::TableSource::WithTable(with_table) => format_with_table(&with_table),
396        resolve::TableSource::CreateView(create_view) => format_create_view(&create_view, binder),
397        resolve::TableSource::CreateMaterializedView(create_materialized_view) => {
398            format_create_materialized_view(&create_materialized_view, binder)
399        }
400        resolve::TableSource::CreateTable(create_table) => {
401            format_create_table(&create_table, binder)
402        }
403    }
404}
405
406fn hover_qualified_star(
407    root: &SyntaxNode,
408    field_expr: &ast::FieldExpr,
409    binder: &binder::Binder,
410) -> Option<String> {
411    let table_ptr = resolve::resolve_qualified_star_table(binder, field_expr)?;
412    hover_qualified_star_columns(root, &table_ptr, binder)
413}
414
415fn hover_unqualified_star(
416    root: &SyntaxNode,
417    target: &ast::Target,
418    binder: &binder::Binder,
419) -> Option<String> {
420    let table_ptrs = resolve::resolve_unqualified_star_tables(binder, target)?;
421    let mut results = vec![];
422    for table_ptr in table_ptrs {
423        if let Some(columns) = hover_qualified_star_columns(root, &table_ptr, binder) {
424            results.push(columns);
425        }
426    }
427
428    if results.is_empty() {
429        return None;
430    }
431
432    Some(results.join("\n"))
433}
434
435fn hover_unqualified_star_in_arg_list(
436    root: &SyntaxNode,
437    arg_list: &ast::ArgList,
438    binder: &binder::Binder,
439) -> Option<String> {
440    let table_ptrs = resolve::resolve_unqualified_star_tables_in_arg_list(binder, arg_list)?;
441    let mut results = vec![];
442    for table_ptr in table_ptrs {
443        if let Some(columns) = hover_qualified_star_columns(root, &table_ptr, binder) {
444            results.push(columns);
445        }
446    }
447
448    if results.is_empty() {
449        return None;
450    }
451
452    Some(results.join("\n"))
453}
454
455fn hover_subquery_table(name_ref: &ast::NameRef) -> Option<String> {
456    let select = name_ref.syntax().ancestors().find_map(ast::Select::cast)?;
457    let from_clause = select.from_clause()?;
458    let qualifier = Name::from_node(name_ref);
459    let from_item = resolve::find_from_item_in_from_clause(&from_clause, &qualifier)?;
460    let paren_select = from_item.paren_select()?;
461    format_subquery_table(name_ref, &paren_select)
462}
463
464fn format_subquery_table(
465    name_ref: &ast::NameRef,
466    paren_select: &ast::ParenSelect,
467) -> Option<String> {
468    let name = name_ref.syntax().text().to_string();
469    let query = paren_select.syntax().text().to_string();
470    Some(format!("subquery {} as {}", name, query))
471}
472
473fn hover_qualified_star_columns(
474    root: &SyntaxNode,
475    table_ptr: &squawk_syntax::SyntaxNodePtr,
476    binder: &binder::Binder,
477) -> Option<String> {
478    let table_name_node = table_ptr.to_node(root);
479
480    if let Some(paren_select) = ast::ParenSelect::cast(table_name_node.clone()) {
481        return hover_qualified_star_columns_from_subquery(root, &paren_select, binder);
482    }
483
484    match resolve::find_table_source(&table_name_node)? {
485        resolve::TableSource::WithTable(with_table) => {
486            hover_qualified_star_columns_from_cte(&with_table)
487        }
488        resolve::TableSource::CreateTable(create_table) => {
489            hover_qualified_star_columns_from_table(&create_table, binder)
490        }
491        resolve::TableSource::CreateView(create_view) => {
492            hover_qualified_star_columns_from_view(&create_view, binder)
493        }
494        resolve::TableSource::CreateMaterializedView(create_materialized_view) => {
495            hover_qualified_star_columns_from_materialized_view(&create_materialized_view, binder)
496        }
497    }
498}
499
500fn hover_qualified_star_columns_from_table(
501    create_table: &impl ast::HasCreateTable,
502    binder: &binder::Binder,
503) -> Option<String> {
504    let path = create_table.path()?;
505    let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
506    let schema = schema.to_string();
507    let results: Vec<String> = resolve::collect_table_columns(create_table)
508        .into_iter()
509        .filter_map(|column| {
510            let column_name = Name::from_node(&column.name()?);
511            let ty = column.ty()?;
512            let ty = &ty.syntax().text().to_string();
513            Some(ColumnHover::schema_table_column_type(
514                &schema,
515                &table_name,
516                &column_name.to_string(),
517                ty,
518            ))
519        })
520        .collect();
521
522    if results.is_empty() {
523        return None;
524    }
525
526    Some(results.join("\n"))
527}
528
529fn hover_qualified_star_columns_from_cte(with_table: &ast::WithTable) -> Option<String> {
530    let cte_name = Name::from_node(&with_table.name()?);
531    let column_names = resolve::collect_with_table_column_names(with_table);
532    let results: Vec<String> = column_names
533        .iter()
534        .map(|column_name| {
535            ColumnHover::table_column(&cte_name.to_string(), &column_name.to_string())
536        })
537        .collect();
538
539    if results.is_empty() {
540        return None;
541    }
542
543    Some(results.join("\n"))
544}
545
546fn hover_qualified_star_columns_from_view(
547    create_view: &ast::CreateView,
548    binder: &binder::Binder,
549) -> Option<String> {
550    let path = create_view.path()?;
551    let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
552
553    let schema_str = schema.to_string();
554    let column_names = resolve::collect_view_column_names(create_view);
555    let results: Vec<String> = column_names
556        .iter()
557        .map(|column_name| {
558            ColumnHover::schema_table_column(&schema_str, &view_name, &column_name.to_string())
559        })
560        .collect();
561
562    if results.is_empty() {
563        return None;
564    }
565
566    Some(results.join("\n"))
567}
568
569fn hover_qualified_star_columns_from_materialized_view(
570    create_materialized_view: &ast::CreateMaterializedView,
571    binder: &binder::Binder,
572) -> Option<String> {
573    let path = create_materialized_view.path()?;
574    let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
575
576    let schema_str = schema.to_string();
577    let column_names = resolve::collect_materialized_view_column_names(create_materialized_view);
578    let results: Vec<String> = column_names
579        .iter()
580        .map(|column_name| {
581            ColumnHover::schema_table_column(&schema_str, &view_name, &column_name.to_string())
582        })
583        .collect();
584
585    if results.is_empty() {
586        return None;
587    }
588
589    Some(results.join("\n"))
590}
591
592fn hover_qualified_star_columns_from_subquery(
593    root: &SyntaxNode,
594    paren_select: &ast::ParenSelect,
595    binder: &binder::Binder,
596) -> Option<String> {
597    let ast::SelectVariant::Select(select) = paren_select.select()? else {
598        return None;
599    };
600
601    let select_clause = select.select_clause()?;
602    let target_list = select_clause.target_list()?;
603
604    let mut results = vec![];
605    let subquery_alias = subquery_alias_name(paren_select);
606
607    for target in target_list.targets() {
608        if target.star_token().is_some() {
609            let table_ptrs = resolve::resolve_unqualified_star_tables(binder, &target)?;
610            for table_ptr in table_ptrs {
611                if let Some(columns) = hover_qualified_star_columns(root, &table_ptr, binder) {
612                    results.push(columns)
613                }
614            }
615            continue;
616        }
617
618        if let Some(result) =
619            hover_subquery_target_column(root, &target, subquery_alias.as_ref(), binder)
620        {
621            results.push(result);
622        }
623    }
624
625    if results.is_empty() {
626        return None;
627    }
628
629    Some(results.join("\n"))
630}
631
632fn subquery_alias_name(paren_select: &ast::ParenSelect) -> Option<Name> {
633    let from_item = paren_select
634        .syntax()
635        .ancestors()
636        .find_map(ast::FromItem::cast)?;
637    let alias_name = from_item.alias()?.name()?;
638    Some(Name::from_node(&alias_name))
639}
640
641fn hover_subquery_target_column(
642    root: &SyntaxNode,
643    target: &ast::Target,
644    subquery_alias: Option<&Name>,
645    binder: &binder::Binder,
646) -> Option<String> {
647    if let Some(alias) = subquery_alias
648        && let Some((col_name, _node)) = ColumnName::from_target(target.clone())
649        && let Some(col_name) = col_name.to_string()
650    {
651        return Some(ColumnHover::table_column(&alias.to_string(), &col_name));
652    }
653
654    match target.expr()? {
655        ast::Expr::NameRef(name_ref) => hover_column(root, &name_ref, binder),
656        ast::Expr::FieldExpr(field_expr) => {
657            let field = field_expr.field()?;
658            hover_column(root, &field, binder)
659        }
660        _ => None,
661    }
662}
663
664fn hover_index(
665    root: &SyntaxNode,
666    name_ref: &ast::NameRef,
667    binder: &binder::Binder,
668) -> Option<String> {
669    let index_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
670        .into_iter()
671        .next()?;
672
673    let index_name_node = index_ptr.to_node(root);
674
675    let create_index = index_name_node
676        .ancestors()
677        .find_map(ast::CreateIndex::cast)?;
678
679    format_create_index(&create_index, binder)
680}
681
682fn hover_sequence(
683    root: &SyntaxNode,
684    name_ref: &ast::NameRef,
685    binder: &binder::Binder,
686) -> Option<String> {
687    let sequence_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
688        .into_iter()
689        .next()?;
690
691    let sequence_name_node = sequence_ptr.to_node(root);
692
693    let create_sequence = sequence_name_node
694        .ancestors()
695        .find_map(ast::CreateSequence::cast)?;
696
697    format_create_sequence(&create_sequence, binder)
698}
699
700fn hover_tablespace(
701    root: &SyntaxNode,
702    name_ref: &ast::NameRef,
703    binder: &binder::Binder,
704) -> Option<String> {
705    let tablespace_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
706        .into_iter()
707        .next()?;
708    let tablespace_name_node = tablespace_ptr.to_node(root);
709    Some(format!("tablespace {}", tablespace_name_node.text()))
710}
711
712fn hover_database(
713    root: &SyntaxNode,
714    name_ref: &ast::NameRef,
715    binder: &binder::Binder,
716) -> Option<String> {
717    let database_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
718        .into_iter()
719        .next()?;
720    let database_name_node = database_ptr.to_node(root);
721    Some(format!("database {}", database_name_node.text()))
722}
723
724fn hover_server(
725    root: &SyntaxNode,
726    name_ref: &ast::NameRef,
727    binder: &binder::Binder,
728) -> Option<String> {
729    let server_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
730        .into_iter()
731        .next()?;
732    let server_name_node = server_ptr.to_node(root);
733    Some(format!("server {}", server_name_node.text()))
734}
735
736fn hover_type(
737    root: &SyntaxNode,
738    name_ref: &ast::NameRef,
739    binder: &binder::Binder,
740) -> Option<String> {
741    let type_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
742        .into_iter()
743        .next()?;
744
745    let type_name_node = type_ptr.to_node(root);
746
747    let create_type = type_name_node.ancestors().find_map(ast::CreateType::cast)?;
748
749    format_create_type(&create_type, binder)
750}
751
752fn format_create_table(
753    create_table: &impl ast::HasCreateTable,
754    binder: &binder::Binder,
755) -> Option<String> {
756    let path = create_table.path()?;
757    let (schema, table_name) = resolve::resolve_table_info(binder, &path)?;
758    let schema = schema.to_string();
759    let args = create_table.table_arg_list()?.syntax().text().to_string();
760
761    let foreign = if create_table.syntax().kind() == SyntaxKind::CREATE_FOREIGN_TABLE {
762        "foreign "
763    } else {
764        ""
765    };
766
767    Some(format!("{foreign}table {schema}.{table_name}{args}"))
768}
769
770fn format_create_view(create_view: &ast::CreateView, binder: &binder::Binder) -> Option<String> {
771    let path = create_view.path()?;
772    let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
773    let schema = schema.to_string();
774
775    let column_list = create_view
776        .column_list()
777        .map(|cl| cl.syntax().text().to_string())
778        .unwrap_or_default();
779
780    let query = create_view.query()?.syntax().text().to_string();
781
782    Some(format!(
783        "view {}.{}{} as {}",
784        schema, view_name, column_list, query
785    ))
786}
787
788fn format_create_materialized_view(
789    create_materialized_view: &ast::CreateMaterializedView,
790    binder: &binder::Binder,
791) -> Option<String> {
792    let path = create_materialized_view.path()?;
793    let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
794    let schema = schema.to_string();
795
796    let column_list = create_materialized_view
797        .column_list()
798        .map(|cl| cl.syntax().text().to_string())
799        .unwrap_or_default();
800
801    let query = create_materialized_view
802        .query()?
803        .syntax()
804        .text()
805        .to_string();
806
807    Some(format!(
808        "materialized view {}.{}{} as {}",
809        schema, view_name, column_list, query
810    ))
811}
812
813fn format_view_column(
814    create_view: &ast::CreateView,
815    column_name: Name,
816    binder: &binder::Binder,
817) -> Option<String> {
818    let path = create_view.path()?;
819    let (schema, view_name) = resolve::resolve_view_info(binder, &path)?;
820    Some(ColumnHover::schema_table_column(
821        &schema.to_string(),
822        &view_name,
823        &column_name.to_string(),
824    ))
825}
826
827fn format_with_table(with_table: &ast::WithTable) -> Option<String> {
828    let name = with_table.name()?.syntax().text().to_string();
829    let query = with_table.query()?.syntax().text().to_string();
830    Some(format!("with {} as ({})", name, query))
831}
832
833fn format_create_index(create_index: &ast::CreateIndex, binder: &binder::Binder) -> Option<String> {
834    let index_name = create_index.name()?.syntax().text().to_string();
835
836    let index_schema = index_schema(create_index, binder)?;
837
838    let relation_name = create_index.relation_name()?;
839    let path = relation_name.path()?;
840    let (table_schema, table_name) = resolve::resolve_table_info(binder, &path)?;
841
842    let partition_item_list = create_index.partition_item_list()?;
843    let columns = partition_item_list.syntax().text().to_string();
844
845    Some(format!(
846        "index {}.{} on {}.{}{}",
847        index_schema, index_name, table_schema, table_name, columns
848    ))
849}
850
851fn format_create_sequence(
852    create_sequence: &ast::CreateSequence,
853    binder: &binder::Binder,
854) -> Option<String> {
855    let path = create_sequence.path()?;
856    let (schema, sequence_name) = resolve::resolve_sequence_info(binder, &path)?;
857
858    Some(format!("sequence {}.{}", schema, sequence_name))
859}
860
861fn format_create_tablespace(create_tablespace: &ast::CreateTablespace) -> Option<String> {
862    let name = create_tablespace.name()?.syntax().text().to_string();
863    Some(format!("tablespace {}", name))
864}
865
866fn format_create_database(create_database: &ast::CreateDatabase) -> Option<String> {
867    let name = create_database.name()?.syntax().text().to_string();
868    Some(format!("database {}", name))
869}
870
871fn format_create_server(create_server: &ast::CreateServer) -> Option<String> {
872    let name = create_server.name()?.syntax().text().to_string();
873    Some(format!("server {}", name))
874}
875
876fn index_schema(create_index: &ast::CreateIndex, binder: &binder::Binder) -> Option<String> {
877    let position = create_index.syntax().text_range().start();
878    let search_path = binder.search_path_at(position);
879    search_path.first().map(|s| s.to_string())
880}
881
882fn format_create_type(create_type: &ast::CreateType, binder: &binder::Binder) -> Option<String> {
883    let path = create_type.path()?;
884    let (schema, type_name) = resolve::resolve_type_info(binder, &path)?;
885
886    if let Some(variant_list) = create_type.variant_list() {
887        let variants = variant_list.syntax().text().to_string();
888        return Some(format!(
889            "type {}.{} as enum {}",
890            schema, type_name, variants
891        ));
892    }
893
894    if let Some(column_list) = create_type.column_list() {
895        let columns = column_list.syntax().text().to_string();
896        return Some(format!("type {}.{} as {}", schema, type_name, columns));
897    }
898
899    if let Some(attribute_list) = create_type.attribute_list() {
900        let attributes = attribute_list.syntax().text().to_string();
901        return Some(format!("type {}.{} {}", schema, type_name, attributes));
902    }
903
904    Some(format!("type {}.{}", schema, type_name))
905}
906
907fn hover_schema(
908    root: &SyntaxNode,
909    name_ref: &ast::NameRef,
910    binder: &binder::Binder,
911) -> Option<String> {
912    let schema_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
913        .into_iter()
914        .next()?;
915
916    let schema_name_node = schema_ptr.to_node(root);
917
918    let create_schema = schema_name_node
919        .ancestors()
920        .find_map(ast::CreateSchema::cast)?;
921
922    format_create_schema(&create_schema)
923}
924
925fn create_schema_name(create_schema: &ast::CreateSchema) -> Option<String> {
926    if let Some(schema_name) = create_schema.name() {
927        return Some(schema_name.syntax().text().to_string());
928    }
929
930    create_schema
931        .schema_authorization()
932        .and_then(|authorization| authorization.role())
933        .and_then(|role| role.name_ref())
934        .map(|name_ref| name_ref.syntax().text().to_string())
935}
936
937fn format_create_schema(create_schema: &ast::CreateSchema) -> Option<String> {
938    let schema_name = create_schema_name(create_schema)?;
939    Some(format!("schema {}", schema_name))
940}
941
942fn hover_function(
943    root: &SyntaxNode,
944    name_ref: &ast::NameRef,
945    binder: &binder::Binder,
946) -> Option<String> {
947    let function_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
948        .into_iter()
949        .next()?;
950
951    let function_name_node = function_ptr.to_node(root);
952
953    let create_function = function_name_node
954        .ancestors()
955        .find_map(ast::CreateFunction::cast)?;
956
957    format_create_function(&create_function, binder)
958}
959
960fn format_create_function(
961    create_function: &ast::CreateFunction,
962    binder: &binder::Binder,
963) -> Option<String> {
964    let path = create_function.path()?;
965    let (schema, function_name) = resolve::resolve_function_info(binder, &path)?;
966
967    let param_list = create_function.param_list()?;
968    let params = param_list.syntax().text().to_string();
969
970    let ret_type = create_function.ret_type()?;
971    let return_type = ret_type.syntax().text().to_string();
972
973    Some(format!(
974        "function {}.{}{} {}",
975        schema, function_name, params, return_type
976    ))
977}
978
979fn hover_aggregate(
980    root: &SyntaxNode,
981    name_ref: &ast::NameRef,
982    binder: &binder::Binder,
983) -> Option<String> {
984    let aggregate_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
985        .into_iter()
986        .next()?;
987
988    let aggregate_name_node = aggregate_ptr.to_node(root);
989
990    let create_aggregate = aggregate_name_node
991        .ancestors()
992        .find_map(ast::CreateAggregate::cast)?;
993
994    format_create_aggregate(&create_aggregate, binder)
995}
996
997fn format_create_aggregate(
998    create_aggregate: &ast::CreateAggregate,
999    binder: &binder::Binder,
1000) -> Option<String> {
1001    let path = create_aggregate.path()?;
1002    let (schema, aggregate_name) = resolve::resolve_aggregate_info(binder, &path)?;
1003
1004    let param_list = create_aggregate.param_list()?;
1005    let params = param_list.syntax().text().to_string();
1006
1007    Some(format!("aggregate {}.{}{}", schema, aggregate_name, params))
1008}
1009
1010fn hover_procedure(
1011    root: &SyntaxNode,
1012    name_ref: &ast::NameRef,
1013    binder: &binder::Binder,
1014) -> Option<String> {
1015    let procedure_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
1016        .into_iter()
1017        .next()?;
1018
1019    let procedure_name_node = procedure_ptr.to_node(root);
1020
1021    let create_procedure = procedure_name_node
1022        .ancestors()
1023        .find_map(ast::CreateProcedure::cast)?;
1024
1025    format_create_procedure(&create_procedure, binder)
1026}
1027
1028fn format_create_procedure(
1029    create_procedure: &ast::CreateProcedure,
1030    binder: &binder::Binder,
1031) -> Option<String> {
1032    let path = create_procedure.path()?;
1033    let (schema, procedure_name) = resolve::resolve_procedure_info(binder, &path)?;
1034
1035    let param_list = create_procedure.param_list()?;
1036    let params = param_list.syntax().text().to_string();
1037
1038    Some(format!("procedure {}.{}{}", schema, procedure_name, params))
1039}
1040
1041fn hover_routine(
1042    root: &SyntaxNode,
1043    name_ref: &ast::NameRef,
1044    binder: &binder::Binder,
1045) -> Option<String> {
1046    let routine_ptr = resolve::resolve_name_ref(binder, root, name_ref)?
1047        .into_iter()
1048        .next()?;
1049    let routine_name = routine_ptr.to_node(root);
1050
1051    for a in routine_name.ancestors() {
1052        if let Some(create_function) = ast::CreateFunction::cast(a.clone()) {
1053            return format_create_function(&create_function, binder);
1054        }
1055        if let Some(create_aggregate) = ast::CreateAggregate::cast(a.clone()) {
1056            return format_create_aggregate(&create_aggregate, binder);
1057        }
1058        if let Some(create_procedure) = ast::CreateProcedure::cast(a) {
1059            return format_create_procedure(&create_procedure, binder);
1060        }
1061    }
1062
1063    None
1064}
1065
1066#[cfg(test)]
1067mod test {
1068    use crate::hover::hover;
1069    use crate::test_utils::fixture;
1070    use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet, renderer::DecorStyle};
1071    use insta::assert_snapshot;
1072    use squawk_syntax::ast;
1073
1074    #[track_caller]
1075    fn check_hover(sql: &str) -> String {
1076        check_hover_(sql).expect("should find hover information")
1077    }
1078
1079    #[track_caller]
1080    fn check_hover_(sql: &str) -> Option<String> {
1081        let (mut offset, sql) = fixture(sql);
1082        offset = offset.checked_sub(1.into()).unwrap_or_default();
1083        let parse = ast::SourceFile::parse(&sql);
1084        assert_eq!(parse.errors(), vec![]);
1085        let file: ast::SourceFile = parse.tree();
1086
1087        if let Some(type_info) = hover(&file, offset) {
1088            let offset_usize: usize = offset.into();
1089            let title = format!("hover: {}", type_info);
1090            let group = Level::INFO.primary_title(&title).element(
1091                Snippet::source(&sql).fold(true).annotation(
1092                    AnnotationKind::Context
1093                        .span(offset_usize..offset_usize + 1)
1094                        .label("hover"),
1095                ),
1096            );
1097            let renderer = Renderer::plain().decor_style(DecorStyle::Unicode);
1098            return Some(
1099                renderer
1100                    .render(&[group])
1101                    .to_string()
1102                    // neater
1103                    .replace("info: hover:", "hover:"),
1104            );
1105        }
1106        None
1107    }
1108
1109    #[test]
1110    fn hover_column_in_create_index() {
1111        assert_snapshot!(check_hover("
1112create table users(id int, email text);
1113create index idx_email on users(email$0);
1114"), @r"
1115        hover: column public.users.email text
1116          ╭▸ 
1117        3 │ create index idx_email on users(email);
1118          ╰╴                                    ─ hover
1119        ");
1120    }
1121
1122    #[test]
1123    fn hover_column_int_type() {
1124        assert_snapshot!(check_hover("
1125create table users(id int, email text);
1126create index idx_id on users(id$0);
1127"), @r"
1128        hover: column public.users.id int
1129          ╭▸ 
1130        3 │ create index idx_id on users(id);
1131          ╰╴                              ─ hover
1132        ");
1133    }
1134
1135    #[test]
1136    fn hover_column_with_schema() {
1137        assert_snapshot!(check_hover("
1138create table public.users(id int, email text);
1139create index idx_email on public.users(email$0);
1140"), @r"
1141        hover: column public.users.email text
1142          ╭▸ 
1143        3 │ create index idx_email on public.users(email);
1144          ╰╴                                           ─ hover
1145        ");
1146    }
1147
1148    #[test]
1149    fn hover_column_temp_table() {
1150        assert_snapshot!(check_hover("
1151create temp table users(id int, email text);
1152create index idx_email on users(email$0);
1153"), @r"
1154        hover: column pg_temp.users.email text
1155          ╭▸ 
1156        3 │ create index idx_email on users(email);
1157          ╰╴                                    ─ hover
1158        ");
1159    }
1160
1161    #[test]
1162    fn hover_column_multiple_columns() {
1163        assert_snapshot!(check_hover("
1164create table users(id int, email text, name varchar(100));
1165create index idx_users on users(id, email$0, name);
1166"), @r"
1167        hover: column public.users.email text
1168          ╭▸ 
1169        3 │ create index idx_users on users(id, email, name);
1170          ╰╴                                        ─ hover
1171        ");
1172    }
1173
1174    #[test]
1175    fn hover_column_varchar() {
1176        assert_snapshot!(check_hover("
1177create table users(id int, name varchar(100));
1178create index idx_name on users(name$0);
1179"), @r"
1180        hover: column public.users.name varchar(100)
1181          ╭▸ 
1182        3 │ create index idx_name on users(name);
1183          ╰╴                                  ─ hover
1184        ");
1185    }
1186
1187    #[test]
1188    fn hover_column_bigint() {
1189        assert_snapshot!(check_hover("
1190create table metrics(value bigint);
1191create index idx_value on metrics(value$0);
1192"), @r"
1193        hover: column public.metrics.value bigint
1194          ╭▸ 
1195        3 │ create index idx_value on metrics(value);
1196          ╰╴                                      ─ hover
1197        ");
1198    }
1199
1200    #[test]
1201    fn hover_column_timestamp() {
1202        assert_snapshot!(check_hover("
1203create table events(created_at timestamp with time zone);
1204create index idx_created on events(created_at$0);
1205"), @r"
1206        hover: column public.events.created_at timestamp with time zone
1207          ╭▸ 
1208        3 │ create index idx_created on events(created_at);
1209          ╰╴                                            ─ hover
1210        ");
1211    }
1212
1213    #[test]
1214    fn hover_column_with_search_path() {
1215        assert_snapshot!(check_hover(r#"
1216set search_path to myschema;
1217create table myschema.users(id int, email text);
1218create index idx_email on users(email$0);
1219"#), @r"
1220        hover: column myschema.users.email text
1221          ╭▸ 
1222        4 │ create index idx_email on users(email);
1223          ╰╴                                    ─ hover
1224        ");
1225    }
1226
1227    #[test]
1228    fn hover_column_explicit_schema_overrides_search_path() {
1229        assert_snapshot!(check_hover(r#"
1230set search_path to myschema;
1231create table public.users(id int, email text);
1232create table myschema.users(value bigint);
1233create index idx_email on public.users(email$0);
1234"#), @r"
1235        hover: column public.users.email text
1236          ╭▸ 
1237        5 │ create index idx_email on public.users(email);
1238          ╰╴                                           ─ hover
1239        ");
1240    }
1241
1242    #[test]
1243    fn hover_on_table_name() {
1244        assert_snapshot!(check_hover("
1245create table t(id int);
1246create index idx on t$0(id);
1247"), @r"
1248        hover: table public.t(id int)
1249          ╭▸ 
1250        3 │ create index idx on t(id);
1251          ╰╴                    ─ hover
1252        ");
1253    }
1254
1255    #[test]
1256    fn hover_on_index_name_in_create() {
1257        assert_snapshot!(check_hover("
1258create table users(id int);
1259create index idx$0 on users(id);
1260"), @r"
1261        hover: index public.idx on public.users(id)
1262          ╭▸ 
1263        3 │ create index idx on users(id);
1264          ╰╴               ─ hover
1265        ");
1266    }
1267
1268    #[test]
1269    fn hover_table_in_create_index() {
1270        assert_snapshot!(check_hover("
1271create table users(id int, email text);
1272create index idx_email on users$0(email);
1273"), @r"
1274        hover: table public.users(id int, email text)
1275          ╭▸ 
1276        3 │ create index idx_email on users(email);
1277          ╰╴                              ─ hover
1278        ");
1279    }
1280
1281    #[test]
1282    fn hover_table_with_schema() {
1283        assert_snapshot!(check_hover("
1284create table public.users(id int, email text);
1285create index idx on public.users$0(id);
1286"), @r"
1287        hover: table public.users(id int, email text)
1288          ╭▸ 
1289        3 │ create index idx on public.users(id);
1290          ╰╴                               ─ hover
1291        ");
1292    }
1293
1294    #[test]
1295    fn hover_table_temp() {
1296        assert_snapshot!(check_hover("
1297create temp table users(id int, email text);
1298create index idx on users$0(id);
1299"), @r"
1300        hover: table pg_temp.users(id int, email text)
1301          ╭▸ 
1302        3 │ create index idx on users(id);
1303          ╰╴                        ─ hover
1304        ");
1305    }
1306
1307    #[test]
1308    fn hover_table_multiline() {
1309        assert_snapshot!(check_hover("
1310create table users(
1311    id int,
1312    email text,
1313    name varchar(100)
1314);
1315create index idx on users$0(id);
1316"), @r"
1317        hover: table public.users(
1318                  id int,
1319                  email text,
1320                  name varchar(100)
1321              )
1322          ╭▸ 
1323        7 │ create index idx on users(id);
1324          ╰╴                        ─ hover
1325        ");
1326    }
1327
1328    #[test]
1329    fn hover_table_with_search_path() {
1330        assert_snapshot!(check_hover(r#"
1331set search_path to myschema;
1332create table users(id int, email text);
1333create index idx on users$0(id);
1334"#), @r"
1335        hover: table myschema.users(id int, email text)
1336          ╭▸ 
1337        4 │ create index idx on users(id);
1338          ╰╴                        ─ hover
1339        ");
1340    }
1341
1342    #[test]
1343    fn hover_table_search_path_at_definition() {
1344        assert_snapshot!(check_hover(r#"
1345set search_path to myschema;
1346create table users(id int, email text);
1347set search_path to myschema, otherschema;
1348create index idx on users$0(id);
1349"#), @r"
1350        hover: table myschema.users(id int, email text)
1351          ╭▸ 
1352        5 │ create index idx on users(id);
1353          ╰╴                        ─ hover
1354        ");
1355    }
1356
1357    #[test]
1358    fn hover_on_create_table_definition() {
1359        assert_snapshot!(check_hover("
1360create table t$0(x bigint);
1361"), @r"
1362        hover: table public.t(x bigint)
1363          ╭▸ 
1364        2 │ create table t(x bigint);
1365          ╰╴             ─ hover
1366        ");
1367    }
1368
1369    #[test]
1370    fn hover_on_create_table_definition_with_schema() {
1371        assert_snapshot!(check_hover("
1372create table myschema.users$0(id int);
1373"), @r"
1374        hover: table myschema.users(id int)
1375          ╭▸ 
1376        2 │ create table myschema.users(id int);
1377          ╰╴                          ─ hover
1378        ");
1379    }
1380
1381    #[test]
1382    fn hover_on_create_temp_table_definition() {
1383        assert_snapshot!(check_hover("
1384create temp table t$0(x bigint);
1385"), @r"
1386        hover: table pg_temp.t(x bigint)
1387          ╭▸ 
1388        2 │ create temp table t(x bigint);
1389          ╰╴                  ─ hover
1390        ");
1391    }
1392
1393    #[test]
1394    fn hover_on_column_in_create_table() {
1395        assert_snapshot!(check_hover("
1396create table t(id$0 int);
1397"), @r"
1398        hover: column public.t.id int
1399          ╭▸ 
1400        2 │ create table t(id int);
1401          ╰╴                ─ hover
1402        ");
1403    }
1404
1405    #[test]
1406    fn hover_on_column_in_create_table_with_schema() {
1407        assert_snapshot!(check_hover("
1408create table myschema.users(id$0 int, name text);
1409"), @r"
1410        hover: column myschema.users.id int
1411          ╭▸ 
1412        2 │ create table myschema.users(id int, name text);
1413          ╰╴                             ─ hover
1414        ");
1415    }
1416
1417    #[test]
1418    fn hover_on_column_in_temp_table() {
1419        assert_snapshot!(check_hover("
1420create temp table t(x$0 bigint);
1421"), @r"
1422        hover: column pg_temp.t.x bigint
1423          ╭▸ 
1424        2 │ create temp table t(x bigint);
1425          ╰╴                    ─ hover
1426        ");
1427    }
1428
1429    #[test]
1430    fn hover_on_multiple_columns() {
1431        assert_snapshot!(check_hover("
1432create table t(id int, email$0 text, name varchar(100));
1433"), @r"
1434        hover: column public.t.email text
1435          ╭▸ 
1436        2 │ create table t(id int, email text, name varchar(100));
1437          ╰╴                           ─ hover
1438        ");
1439    }
1440
1441    #[test]
1442    fn hover_on_drop_table() {
1443        assert_snapshot!(check_hover("
1444create table users(id int, email text);
1445drop table users$0;
1446"), @r"
1447        hover: table public.users(id int, email text)
1448          ╭▸ 
1449        3 │ drop table users;
1450          ╰╴               ─ hover
1451        ");
1452    }
1453
1454    #[test]
1455    fn hover_on_drop_table_with_schema() {
1456        assert_snapshot!(check_hover("
1457create table myschema.users(id int);
1458drop table myschema.users$0;
1459"), @r"
1460        hover: table myschema.users(id int)
1461          ╭▸ 
1462        3 │ drop table myschema.users;
1463          ╰╴                        ─ hover
1464        ");
1465    }
1466
1467    #[test]
1468    fn hover_on_drop_temp_table() {
1469        assert_snapshot!(check_hover("
1470create temp table t(x bigint);
1471drop table t$0;
1472"), @r"
1473        hover: table pg_temp.t(x bigint)
1474          ╭▸ 
1475        3 │ drop table t;
1476          ╰╴           ─ hover
1477        ");
1478    }
1479
1480    #[test]
1481    fn hover_on_create_index_definition() {
1482        assert_snapshot!(check_hover("
1483create table t(x bigint);
1484create index idx$0 on t(x);
1485"), @r"
1486        hover: index public.idx on public.t(x)
1487          ╭▸ 
1488        3 │ create index idx on t(x);
1489          ╰╴               ─ hover
1490        ");
1491    }
1492
1493    #[test]
1494    fn hover_on_drop_index() {
1495        assert_snapshot!(check_hover("
1496create table t(x bigint);
1497create index idx_x on t(x);
1498drop index idx_x$0;
1499"), @r"
1500        hover: index public.idx_x on public.t(x)
1501          ╭▸ 
1502        4 │ drop index idx_x;
1503          ╰╴               ─ hover
1504        ");
1505    }
1506
1507    #[test]
1508    fn hover_on_create_type_definition() {
1509        assert_snapshot!(check_hover("
1510create type status$0 as enum ('active', 'inactive');
1511"), @r"
1512        hover: type public.status as enum ('active', 'inactive')
1513          ╭▸ 
1514        2 │ create type status as enum ('active', 'inactive');
1515          ╰╴                 ─ hover
1516        ");
1517    }
1518
1519    #[test]
1520    fn hover_on_create_type_definition_with_schema() {
1521        assert_snapshot!(check_hover("
1522create type myschema.status$0 as enum ('active', 'inactive');
1523"), @r"
1524        hover: type myschema.status as enum ('active', 'inactive')
1525          ╭▸ 
1526        2 │ create type myschema.status as enum ('active', 'inactive');
1527          ╰╴                          ─ hover
1528        ");
1529    }
1530
1531    #[test]
1532    fn hover_on_drop_type() {
1533        assert_snapshot!(check_hover("
1534create type status as enum ('active', 'inactive');
1535drop type status$0;
1536"), @r"
1537        hover: type public.status as enum ('active', 'inactive')
1538          ╭▸ 
1539        3 │ drop type status;
1540          ╰╴               ─ hover
1541        ");
1542    }
1543
1544    #[test]
1545    fn hover_on_drop_type_with_schema() {
1546        assert_snapshot!(check_hover("
1547create type myschema.status as enum ('active', 'inactive');
1548drop type myschema.status$0;
1549"), @r"
1550        hover: type myschema.status as enum ('active', 'inactive')
1551          ╭▸ 
1552        3 │ drop type myschema.status;
1553          ╰╴                        ─ hover
1554        ");
1555    }
1556
1557    #[test]
1558    fn hover_on_create_type_composite() {
1559        assert_snapshot!(check_hover("
1560create type person$0 as (name text, age int);
1561"), @r"
1562        hover: type public.person as (name text, age int)
1563          ╭▸ 
1564        2 │ create type person as (name text, age int);
1565          ╰╴                 ─ hover
1566        ");
1567    }
1568
1569    #[test]
1570    fn hover_on_drop_type_composite() {
1571        assert_snapshot!(check_hover("
1572create type person as (name text, age int);
1573drop type person$0;
1574"), @r"
1575        hover: type public.person as (name text, age int)
1576          ╭▸ 
1577        3 │ drop type person;
1578          ╰╴               ─ hover
1579        ");
1580    }
1581
1582    #[test]
1583    fn hover_on_create_type_range() {
1584        assert_snapshot!(check_hover("
1585create type int4_range$0 as range (subtype = int4);
1586"), @r"
1587        hover: type public.int4_range (subtype = int4)
1588          ╭▸ 
1589        2 │ create type int4_range as range (subtype = int4);
1590          ╰╴                     ─ hover
1591        ");
1592    }
1593
1594    #[test]
1595    fn hover_on_drop_type_range() {
1596        assert_snapshot!(check_hover("
1597create type int4_range as range (subtype = int4);
1598drop type int4_range$0;
1599"), @r"
1600        hover: type public.int4_range (subtype = int4)
1601          ╭▸ 
1602        3 │ drop type int4_range;
1603          ╰╴                   ─ hover
1604        ");
1605    }
1606
1607    #[test]
1608    fn hover_on_cast_operator() {
1609        assert_snapshot!(check_hover("
1610create type foo as enum ('a', 'b');
1611select x::foo$0;
1612"), @r"
1613        hover: type public.foo as enum ('a', 'b')
1614          ╭▸ 
1615        3 │ select x::foo;
1616          ╰╴            ─ hover
1617        ");
1618    }
1619
1620    #[test]
1621    fn hover_on_cast_function() {
1622        assert_snapshot!(check_hover("
1623create type bar as enum ('x', 'y');
1624select cast(x as bar$0);
1625"), @r"
1626        hover: type public.bar as enum ('x', 'y')
1627          ╭▸ 
1628        3 │ select cast(x as bar);
1629          ╰╴                   ─ hover
1630        ");
1631    }
1632
1633    #[test]
1634    fn hover_on_cast_with_schema() {
1635        assert_snapshot!(check_hover("
1636create type myschema.baz as enum ('m', 'n');
1637select x::myschema.baz$0;
1638"), @r"
1639        hover: type myschema.baz as enum ('m', 'n')
1640          ╭▸ 
1641        3 │ select x::myschema.baz;
1642          ╰╴                     ─ hover
1643        ");
1644    }
1645
1646    #[test]
1647    fn hover_on_drop_function() {
1648        assert_snapshot!(check_hover("
1649create function foo() returns int as $$ select 1 $$ language sql;
1650drop function foo$0();
1651"), @r"
1652        hover: function public.foo() returns int
1653          ╭▸ 
1654        3 │ drop function foo();
1655          ╰╴                ─ hover
1656        ");
1657    }
1658
1659    #[test]
1660    fn hover_on_drop_function_with_schema() {
1661        assert_snapshot!(check_hover("
1662create function myschema.foo() returns int as $$ select 1 $$ language sql;
1663drop function myschema.foo$0();
1664"), @r"
1665        hover: function myschema.foo() returns int
1666          ╭▸ 
1667        3 │ drop function myschema.foo();
1668          ╰╴                         ─ hover
1669        ");
1670    }
1671
1672    #[test]
1673    fn hover_on_create_function_definition() {
1674        assert_snapshot!(check_hover("
1675create function foo$0() returns int as $$ select 1 $$ language sql;
1676"), @r"
1677        hover: function public.foo() returns int
1678          ╭▸ 
1679        2 │ create function foo() returns int as $$ select 1 $$ language sql;
1680          ╰╴                  ─ hover
1681        ");
1682    }
1683
1684    #[test]
1685    fn hover_on_create_function_with_explicit_schema() {
1686        assert_snapshot!(check_hover("
1687create function myschema.foo$0() returns int as $$ select 1 $$ language sql;
1688"), @r"
1689        hover: function myschema.foo() returns int
1690          ╭▸ 
1691        2 │ create function myschema.foo() returns int as $$ select 1 $$ language sql;
1692          ╰╴                           ─ hover
1693        ");
1694    }
1695
1696    #[test]
1697    fn hover_on_drop_function_with_search_path() {
1698        assert_snapshot!(check_hover(r#"
1699set search_path to myschema;
1700create function foo() returns int as $$ select 1 $$ language sql;
1701drop function foo$0();
1702"#), @r"
1703        hover: function myschema.foo() returns int
1704          ╭▸ 
1705        4 │ drop function foo();
1706          ╰╴                ─ hover
1707        ");
1708    }
1709
1710    #[test]
1711    fn hover_on_drop_function_overloaded() {
1712        assert_snapshot!(check_hover("
1713create function add(complex) returns complex as $$ select null $$ language sql;
1714create function add(bigint) returns bigint as $$ select 1 $$ language sql;
1715drop function add$0(complex);
1716"), @r"
1717        hover: function public.add(complex) returns complex
1718          ╭▸ 
1719        4 │ drop function add(complex);
1720          ╰╴                ─ hover
1721        ");
1722    }
1723
1724    #[test]
1725    fn hover_on_drop_function_second_overload() {
1726        assert_snapshot!(check_hover("
1727create function add(complex) returns complex as $$ select null $$ language sql;
1728create function add(bigint) returns bigint as $$ select 1 $$ language sql;
1729drop function add$0(bigint);
1730"), @r"
1731        hover: function public.add(bigint) returns bigint
1732          ╭▸ 
1733        4 │ drop function add(bigint);
1734          ╰╴                ─ hover
1735        ");
1736    }
1737
1738    #[test]
1739    fn hover_on_drop_aggregate() {
1740        assert_snapshot!(check_hover("
1741create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
1742drop aggregate myavg$0(int);
1743"), @r"
1744        hover: aggregate public.myavg(int)
1745          ╭▸ 
1746        3 │ drop aggregate myavg(int);
1747          ╰╴                   ─ hover
1748        ");
1749    }
1750
1751    #[test]
1752    fn hover_on_drop_aggregate_with_schema() {
1753        assert_snapshot!(check_hover("
1754create aggregate myschema.myavg(int) (sfunc = int4_avg_accum, stype = _int8);
1755drop aggregate myschema.myavg$0(int);
1756"), @r"
1757        hover: aggregate myschema.myavg(int)
1758          ╭▸ 
1759        3 │ drop aggregate myschema.myavg(int);
1760          ╰╴                            ─ hover
1761        ");
1762    }
1763
1764    #[test]
1765    fn hover_on_create_aggregate_definition() {
1766        assert_snapshot!(check_hover("
1767create aggregate myavg$0(int) (sfunc = int4_avg_accum, stype = _int8);
1768"), @r"
1769        hover: aggregate public.myavg(int)
1770          ╭▸ 
1771        2 │ create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
1772          ╰╴                     ─ hover
1773        ");
1774    }
1775
1776    #[test]
1777    fn hover_on_drop_aggregate_with_search_path() {
1778        assert_snapshot!(check_hover(r#"
1779set search_path to myschema;
1780create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
1781drop aggregate myavg$0(int);
1782"#), @r"
1783        hover: aggregate myschema.myavg(int)
1784          ╭▸ 
1785        4 │ drop aggregate myavg(int);
1786          ╰╴                   ─ hover
1787        ");
1788    }
1789
1790    #[test]
1791    fn hover_on_drop_aggregate_overloaded() {
1792        assert_snapshot!(check_hover("
1793create aggregate sum(complex) (sfunc = complex_add, stype = complex, initcond = '(0,0)');
1794create aggregate sum(bigint) (sfunc = bigint_add, stype = bigint, initcond = '0');
1795drop aggregate sum$0(complex);
1796"), @r"
1797        hover: aggregate public.sum(complex)
1798          ╭▸ 
1799        4 │ drop aggregate sum(complex);
1800          ╰╴                 ─ hover
1801        ");
1802    }
1803
1804    #[test]
1805    fn hover_on_drop_aggregate_second_overload() {
1806        assert_snapshot!(check_hover("
1807create aggregate sum(complex) (sfunc = complex_add, stype = complex, initcond = '(0,0)');
1808create aggregate sum(bigint) (sfunc = bigint_add, stype = bigint, initcond = '0');
1809drop aggregate sum$0(bigint);
1810"), @r"
1811        hover: aggregate public.sum(bigint)
1812          ╭▸ 
1813        4 │ drop aggregate sum(bigint);
1814          ╰╴                 ─ hover
1815        ");
1816    }
1817
1818    #[test]
1819    fn hover_on_select_function_call() {
1820        assert_snapshot!(check_hover("
1821create function foo() returns int as $$ select 1 $$ language sql;
1822select foo$0();
1823"), @r"
1824        hover: function public.foo() returns int
1825          ╭▸ 
1826        3 │ select foo();
1827          ╰╴         ─ hover
1828        ");
1829    }
1830
1831    #[test]
1832    fn hover_on_select_function_call_with_schema() {
1833        assert_snapshot!(check_hover("
1834create function public.foo() returns int as $$ select 1 $$ language sql;
1835select public.foo$0();
1836"), @r"
1837        hover: function public.foo() returns int
1838          ╭▸ 
1839        3 │ select public.foo();
1840          ╰╴                ─ hover
1841        ");
1842    }
1843
1844    #[test]
1845    fn hover_on_select_function_call_with_search_path() {
1846        assert_snapshot!(check_hover(r#"
1847set search_path to myschema;
1848create function foo() returns int as $$ select 1 $$ language sql;
1849select foo$0();
1850"#), @r"
1851        hover: function myschema.foo() returns int
1852          ╭▸ 
1853        4 │ select foo();
1854          ╰╴         ─ hover
1855        ");
1856    }
1857
1858    #[test]
1859    fn hover_on_select_function_call_with_params() {
1860        assert_snapshot!(check_hover("
1861create function add(a int, b int) returns int as $$ select a + b $$ language sql;
1862select add$0(1, 2);
1863"), @r"
1864        hover: function public.add(a int, b int) returns int
1865          ╭▸ 
1866        3 │ select add(1, 2);
1867          ╰╴         ─ hover
1868        ");
1869    }
1870
1871    #[test]
1872    fn hover_on_function_call_style_column_access() {
1873        assert_snapshot!(check_hover("
1874create table t(a int, b int);
1875select a$0(t) from t;
1876"), @r"
1877        hover: column public.t.a int
1878          ╭▸ 
1879        3 │ select a(t) from t;
1880          ╰╴       ─ hover
1881        ");
1882    }
1883
1884    #[test]
1885    fn hover_on_function_call_style_column_access_with_function_precedence() {
1886        assert_snapshot!(check_hover("
1887create table t(a int, b int);
1888create function b(t) returns int as 'select 1' LANGUAGE sql;
1889select b$0(t) from t;
1890"), @r"
1891        hover: function public.b(t) returns int
1892          ╭▸ 
1893        4 │ select b(t) from t;
1894          ╰╴       ─ hover
1895        ");
1896    }
1897
1898    #[test]
1899    fn hover_on_function_call_style_table_arg() {
1900        assert_snapshot!(check_hover("
1901create table t(a int, b int);
1902select a(t$0) from t;
1903"), @r"
1904        hover: table public.t(a int, b int)
1905          ╭▸ 
1906        3 │ select a(t) from t;
1907          ╰╴         ─ hover
1908        ");
1909    }
1910
1911    #[test]
1912    fn hover_on_function_call_style_table_arg_with_function() {
1913        assert_snapshot!(check_hover("
1914create table t(a int, b int);
1915create function b(t) returns int as 'select 1' LANGUAGE sql;
1916select b(t$0) from t;
1917"), @r"
1918        hover: table public.t(a int, b int)
1919          ╭▸ 
1920        4 │ select b(t) from t;
1921          ╰╴         ─ hover
1922        ");
1923    }
1924
1925    #[test]
1926    fn hover_on_function_call_style_table_arg_in_where() {
1927        assert_snapshot!(check_hover("
1928create table t(a int);
1929select * from t where a(t$0) > 2;
1930"), @r"
1931        hover: table public.t(a int)
1932          ╭▸ 
1933        3 │ select * from t where a(t) > 2;
1934          ╰╴                        ─ hover
1935        ");
1936    }
1937
1938    #[test]
1939    fn hover_on_qualified_table_ref_in_where() {
1940        assert_snapshot!(check_hover("
1941create table t(a int);
1942create function b(t) returns int as 'select 1' language sql;
1943select * from t where t$0.b > 2;
1944"), @r"
1945        hover: table public.t(a int)
1946          ╭▸ 
1947        4 │ select * from t where t.b > 2;
1948          ╰╴                      ─ hover
1949        ");
1950    }
1951
1952    #[test]
1953    fn hover_on_field_style_function_call() {
1954        assert_snapshot!(check_hover("
1955create table t(a int);
1956create function b(t) returns int as 'select 1' language sql;
1957select t.b$0 from t;
1958"), @r"
1959        hover: function public.b(t) returns int
1960          ╭▸ 
1961        4 │ select t.b from t;
1962          ╰╴         ─ hover
1963        ");
1964    }
1965
1966    #[test]
1967    fn hover_on_field_style_function_call_column_precedence() {
1968        assert_snapshot!(check_hover("
1969create table t(a int, b int);
1970create function b(t) returns int as 'select 1' language sql;
1971select t.b$0 from t;
1972"), @r"
1973        hover: column public.t.b int
1974          ╭▸ 
1975        4 │ select t.b from t;
1976          ╰╴         ─ hover
1977        ");
1978    }
1979
1980    #[test]
1981    fn hover_on_field_style_function_call_table_ref() {
1982        assert_snapshot!(check_hover("
1983create table t(a int);
1984create function b(t) returns int as 'select 1' language sql;
1985select t$0.b from t;
1986"), @r"
1987        hover: table public.t(a int)
1988          ╭▸ 
1989        4 │ select t.b from t;
1990          ╰╴       ─ hover
1991        ");
1992    }
1993
1994    #[test]
1995    fn hover_on_select_from_table() {
1996        assert_snapshot!(check_hover("
1997create table users(id int, email text);
1998select * from users$0;
1999"), @r"
2000        hover: table public.users(id int, email text)
2001          ╭▸ 
2002        3 │ select * from users;
2003          ╰╴                  ─ hover
2004        ");
2005    }
2006
2007    #[test]
2008    fn hover_on_subquery_qualified_table_ref() {
2009        assert_snapshot!(check_hover("
2010select t$0.a from (select 1 a) t;
2011"), @r"
2012        hover: subquery t as (select 1 a)
2013          ╭▸ 
2014        2 │ select t.a from (select 1 a) t;
2015          ╰╴       ─ hover
2016        ");
2017    }
2018
2019    #[test]
2020    fn hover_on_subquery_qualified_column_ref() {
2021        assert_snapshot!(check_hover("
2022select t.a$0 from (select 1 a) t;
2023"), @r"
2024        hover: column t.a
2025          ╭▸ 
2026        2 │ select t.a from (select 1 a) t;
2027          ╰╴         ─ hover
2028        ");
2029    }
2030
2031    #[test]
2032    fn hover_on_select_from_table_with_schema() {
2033        assert_snapshot!(check_hover("
2034create table public.users(id int, email text);
2035select * from public.users$0;
2036"), @r"
2037        hover: table public.users(id int, email text)
2038          ╭▸ 
2039        3 │ select * from public.users;
2040          ╰╴                         ─ hover
2041        ");
2042    }
2043
2044    #[test]
2045    fn hover_on_select_from_table_with_search_path() {
2046        assert_snapshot!(check_hover("
2047set search_path to foo;
2048create table foo.users(id int, email text);
2049select * from users$0;
2050"), @r"
2051        hover: table foo.users(id int, email text)
2052          ╭▸ 
2053        4 │ select * from users;
2054          ╰╴                  ─ hover
2055        ");
2056    }
2057
2058    #[test]
2059    fn hover_on_select_from_temp_table() {
2060        assert_snapshot!(check_hover("
2061create temp table users(id int, email text);
2062select * from users$0;
2063"), @r"
2064        hover: table pg_temp.users(id int, email text)
2065          ╭▸ 
2066        3 │ select * from users;
2067          ╰╴                  ─ hover
2068        ");
2069    }
2070
2071    #[test]
2072    fn hover_on_select_from_multiline_table() {
2073        assert_snapshot!(check_hover("
2074create table users(
2075    id int,
2076    email text,
2077    name varchar(100)
2078);
2079select * from users$0;
2080"), @r"
2081        hover: table public.users(
2082                  id int,
2083                  email text,
2084                  name varchar(100)
2085              )
2086          ╭▸ 
2087        7 │ select * from users;
2088          ╰╴                  ─ hover
2089        ");
2090    }
2091
2092    #[test]
2093    fn hover_on_select_column() {
2094        assert_snapshot!(check_hover("
2095create table users(id int, email text);
2096select id$0 from users;
2097"), @r"
2098        hover: column public.users.id int
2099          ╭▸ 
2100        3 │ select id from users;
2101          ╰╴        ─ hover
2102        ");
2103    }
2104
2105    #[test]
2106    fn hover_on_select_column_second() {
2107        assert_snapshot!(check_hover("
2108create table users(id int, email text);
2109select id, email$0 from users;
2110"), @r"
2111        hover: column public.users.email text
2112          ╭▸ 
2113        3 │ select id, email from users;
2114          ╰╴               ─ hover
2115        ");
2116    }
2117
2118    #[test]
2119    fn hover_on_select_column_with_schema() {
2120        assert_snapshot!(check_hover("
2121create table public.users(id int, email text);
2122select email$0 from public.users;
2123"), @r"
2124        hover: column public.users.email text
2125          ╭▸ 
2126        3 │ select email from public.users;
2127          ╰╴           ─ hover
2128        ");
2129    }
2130
2131    #[test]
2132    fn hover_on_select_column_with_search_path() {
2133        assert_snapshot!(check_hover("
2134set search_path to foo;
2135create table foo.users(id int, email text);
2136select id$0 from users;
2137"), @r"
2138        hover: column foo.users.id int
2139          ╭▸ 
2140        4 │ select id from users;
2141          ╰╴        ─ hover
2142        ");
2143    }
2144
2145    #[test]
2146    fn hover_on_select_qualified_star() {
2147        assert_snapshot!(check_hover("
2148create table u(id int, b int);
2149select u.*$0 from u;
2150"), @r"
2151        hover: column public.u.id int
2152              column public.u.b int
2153          ╭▸ 
2154        3 │ select u.* from u;
2155          ╰╴         ─ hover
2156        ");
2157    }
2158
2159    #[test]
2160    fn hover_on_select_unqualified_star() {
2161        assert_snapshot!(check_hover("
2162create table u(id int, b int);
2163select *$0 from u;
2164"), @r"
2165        hover: column public.u.id int
2166              column public.u.b int
2167          ╭▸ 
2168        3 │ select * from u;
2169          ╰╴       ─ hover
2170        ");
2171    }
2172
2173    #[test]
2174    fn hover_on_select_count_star() {
2175        assert_snapshot!(check_hover("
2176create table u(id int, b int);
2177select count(*$0) from u;
2178"), @r"
2179        hover: column public.u.id int
2180              column public.u.b int
2181          ╭▸ 
2182        3 │ select count(*) from u;
2183          ╰╴             ─ hover
2184        ");
2185    }
2186
2187    #[test]
2188    fn hover_on_insert_table() {
2189        assert_snapshot!(check_hover("
2190create table users(id int, email text);
2191insert into users$0(id, email) values (1, 'test');
2192"), @r"
2193        hover: table public.users(id int, email text)
2194          ╭▸ 
2195        3 │ insert into users(id, email) values (1, 'test');
2196          ╰╴                ─ hover
2197        ");
2198    }
2199
2200    #[test]
2201    fn hover_on_insert_table_with_schema() {
2202        assert_snapshot!(check_hover("
2203create table public.users(id int, email text);
2204insert into public.users$0(id, email) values (1, 'test');
2205"), @r"
2206        hover: table public.users(id int, email text)
2207          ╭▸ 
2208        3 │ insert into public.users(id, email) values (1, 'test');
2209          ╰╴                       ─ hover
2210        ");
2211    }
2212
2213    #[test]
2214    fn hover_on_insert_column() {
2215        assert_snapshot!(check_hover("
2216create table users(id int, email text);
2217insert into users(id$0, email) values (1, 'test');
2218"), @r"
2219        hover: column public.users.id int
2220          ╭▸ 
2221        3 │ insert into users(id, email) values (1, 'test');
2222          ╰╴                   ─ hover
2223        ");
2224    }
2225
2226    #[test]
2227    fn hover_on_insert_column_second() {
2228        assert_snapshot!(check_hover("
2229create table users(id int, email text);
2230insert into users(id, email$0) values (1, 'test');
2231"), @r"
2232        hover: column public.users.email text
2233          ╭▸ 
2234        3 │ insert into users(id, email) values (1, 'test');
2235          ╰╴                          ─ hover
2236        ");
2237    }
2238
2239    #[test]
2240    fn hover_on_insert_column_with_schema() {
2241        assert_snapshot!(check_hover("
2242create table public.users(id int, email text);
2243insert into public.users(email$0) values ('test');
2244"), @r"
2245        hover: column public.users.email text
2246          ╭▸ 
2247        3 │ insert into public.users(email) values ('test');
2248          ╰╴                             ─ hover
2249        ");
2250    }
2251
2252    #[test]
2253    fn hover_on_delete_table() {
2254        assert_snapshot!(check_hover("
2255create table users(id int, email text);
2256delete from users$0 where id = 1;
2257"), @r"
2258        hover: table public.users(id int, email text)
2259          ╭▸ 
2260        3 │ delete from users where id = 1;
2261          ╰╴                ─ hover
2262        ");
2263    }
2264
2265    #[test]
2266    fn hover_on_delete_table_with_schema() {
2267        assert_snapshot!(check_hover("
2268create table public.users(id int, email text);
2269delete from public.users$0 where id = 1;
2270"), @r"
2271        hover: table public.users(id int, email text)
2272          ╭▸ 
2273        3 │ delete from public.users where id = 1;
2274          ╰╴                       ─ hover
2275        ");
2276    }
2277
2278    #[test]
2279    fn hover_on_delete_where_column() {
2280        assert_snapshot!(check_hover("
2281create table users(id int, email text);
2282delete from users where id$0 = 1;
2283"), @r"
2284        hover: column public.users.id int
2285          ╭▸ 
2286        3 │ delete from users where id = 1;
2287          ╰╴                         ─ hover
2288        ");
2289    }
2290
2291    #[test]
2292    fn hover_on_delete_where_column_second() {
2293        assert_snapshot!(check_hover("
2294create table users(id int, email text, active boolean);
2295delete from users where id = 1 and email$0 = 'test';
2296"), @r"
2297        hover: column public.users.email text
2298          ╭▸ 
2299        3 │ delete from users where id = 1 and email = 'test';
2300          ╰╴                                       ─ hover
2301        ");
2302    }
2303
2304    #[test]
2305    fn hover_on_delete_where_column_with_schema() {
2306        assert_snapshot!(check_hover("
2307create table public.users(id int, email text);
2308delete from public.users where email$0 = 'test';
2309"), @r"
2310        hover: column public.users.email text
2311          ╭▸ 
2312        3 │ delete from public.users where email = 'test';
2313          ╰╴                                   ─ hover
2314        ");
2315    }
2316
2317    #[test]
2318    fn hover_on_select_table_as_column() {
2319        assert_snapshot!(check_hover("
2320create table t(x bigint, y bigint);
2321select t$0 from t;
2322"), @r"
2323        hover: table public.t(x bigint, y bigint)
2324          ╭▸ 
2325        3 │ select t from t;
2326          ╰╴       ─ hover
2327        ");
2328    }
2329
2330    #[test]
2331    fn hover_on_select_table_as_column_with_schema() {
2332        assert_snapshot!(check_hover("
2333create table public.t(x bigint, y bigint);
2334select t$0 from public.t;
2335"), @r"
2336        hover: table public.t(x bigint, y bigint)
2337          ╭▸ 
2338        3 │ select t from public.t;
2339          ╰╴       ─ hover
2340        ");
2341    }
2342
2343    #[test]
2344    fn hover_on_select_table_as_column_with_search_path() {
2345        assert_snapshot!(check_hover("
2346set search_path to foo;
2347create table foo.users(id int, email text);
2348select users$0 from users;
2349"), @r"
2350        hover: table foo.users(id int, email text)
2351          ╭▸ 
2352        4 │ select users from users;
2353          ╰╴           ─ hover
2354        ");
2355    }
2356
2357    #[test]
2358    fn hover_on_select_column_with_same_name_as_table() {
2359        assert_snapshot!(check_hover("
2360create table t(t int);
2361select t$0 from t;
2362"), @r"
2363        hover: column public.t.t int
2364          ╭▸ 
2365        3 │ select t from t;
2366          ╰╴       ─ hover
2367        ");
2368    }
2369
2370    #[test]
2371    fn hover_on_create_schema() {
2372        assert_snapshot!(check_hover("
2373create schema foo$0;
2374"), @r"
2375        hover: schema foo
2376          ╭▸ 
2377        2 │ create schema foo;
2378          ╰╴                ─ hover
2379        ");
2380    }
2381
2382    #[test]
2383    fn hover_on_create_schema_authorization() {
2384        assert_snapshot!(check_hover("
2385create schema authorization foo$0;
2386"), @r"
2387        hover: schema foo
2388          ╭▸ 
2389        2 │ create schema authorization foo;
2390          ╰╴                              ─ hover
2391        ");
2392    }
2393
2394    #[test]
2395    fn hover_on_drop_schema_authorization() {
2396        assert_snapshot!(check_hover("
2397create schema authorization foo;
2398drop schema foo$0;
2399"), @r"
2400        hover: schema foo
2401          ╭▸ 
2402        3 │ drop schema foo;
2403          ╰╴              ─ hover
2404        ");
2405    }
2406
2407    #[test]
2408    fn hover_on_drop_schema() {
2409        assert_snapshot!(check_hover("
2410create schema foo;
2411drop schema foo$0;
2412"), @r"
2413        hover: schema foo
2414          ╭▸ 
2415        3 │ drop schema foo;
2416          ╰╴              ─ hover
2417        ");
2418    }
2419
2420    #[test]
2421    fn hover_on_schema_after_definition() {
2422        assert_snapshot!(check_hover("
2423drop schema foo$0;
2424create schema foo;
2425"), @r"
2426        hover: schema foo
2427          ╭▸ 
2428        2 │ drop schema foo;
2429          ╰╴              ─ hover
2430        ");
2431    }
2432
2433    #[test]
2434    fn hover_on_cte_table() {
2435        assert_snapshot!(check_hover("
2436with t as (select 1 a)
2437select a from t$0;
2438"), @r"
2439        hover: with t as (select 1 a)
2440          ╭▸ 
2441        3 │ select a from t;
2442          ╰╴              ─ hover
2443        ");
2444    }
2445
2446    #[test]
2447    fn hover_on_cte_column() {
2448        assert_snapshot!(check_hover("
2449with t as (select 1 a)
2450select a$0 from t;
2451"), @r"
2452        hover: column t.a
2453          ╭▸ 
2454        3 │ select a from t;
2455          ╰╴       ─ hover
2456        ");
2457    }
2458
2459    #[test]
2460    fn hover_on_cte_with_multiple_columns() {
2461        assert_snapshot!(check_hover("
2462with t as (select 1 a, 2 b)
2463select b$0 from t;
2464"), @r"
2465        hover: column t.b
2466          ╭▸ 
2467        3 │ select b from t;
2468          ╰╴       ─ hover
2469        ");
2470    }
2471
2472    #[test]
2473    fn hover_on_cte_with_column_list() {
2474        assert_snapshot!(check_hover("
2475with t(a) as (select 1)
2476select a$0 from t;
2477"), @r"
2478        hover: column t.a
2479          ╭▸ 
2480        3 │ select a from t;
2481          ╰╴       ─ hover
2482        ");
2483    }
2484
2485    #[test]
2486    fn hover_on_nested_cte() {
2487        assert_snapshot!(check_hover("
2488with x as (select 1 a),
2489     y as (select a from x)
2490select a$0 from y;
2491"), @r"
2492        hover: column y.a
2493          ╭▸ 
2494        4 │ select a from y;
2495          ╰╴       ─ hover
2496        ");
2497    }
2498
2499    #[test]
2500    fn hover_on_cte_shadowing_table_with_star() {
2501        assert_snapshot!(check_hover("
2502create table t(a bigint);
2503with t as (select * from t)
2504select a$0 from t;
2505"), @r"
2506        hover: column public.t.a bigint
2507          ╭▸ 
2508        4 │ select a from t;
2509          ╰╴       ─ hover
2510        ");
2511    }
2512
2513    #[test]
2514    fn hover_on_cte_definition() {
2515        assert_snapshot!(check_hover("
2516with t$0 as (select 1 a)
2517select a from t;
2518"), @r"
2519        hover: with t as (select 1 a)
2520          ╭▸ 
2521        2 │ with t as (select 1 a)
2522          ╰╴     ─ hover
2523        ");
2524    }
2525
2526    #[test]
2527    fn hover_on_cte_values_column1() {
2528        assert_snapshot!(check_hover("
2529with t as (
2530    values (1, 2), (3, 4)
2531)
2532select column1$0, column2 from t;
2533"), @r"
2534        hover: column t.column1
2535          ╭▸ 
2536        5 │ select column1, column2 from t;
2537          ╰╴             ─ hover
2538        ");
2539    }
2540
2541    #[test]
2542    fn hover_on_cte_values_column2() {
2543        assert_snapshot!(check_hover("
2544with t as (
2545    values (1, 2), (3, 4)
2546)
2547select column1, column2$0 from t;
2548"), @r"
2549        hover: column t.column2
2550          ╭▸ 
2551        5 │ select column1, column2 from t;
2552          ╰╴                      ─ hover
2553        ");
2554    }
2555
2556    #[test]
2557    fn hover_on_cte_values_single_column() {
2558        assert_snapshot!(check_hover("
2559with t as (
2560    values (1), (2), (3)
2561)
2562select column1$0 from t;
2563"), @r"
2564        hover: column t.column1
2565          ╭▸ 
2566        5 │ select column1 from t;
2567          ╰╴             ─ hover
2568        ");
2569    }
2570
2571    #[test]
2572    fn hover_on_cte_values_uppercase_column_names() {
2573        assert_snapshot!(check_hover("
2574with t as (
2575    values (1, 2), (3, 4)
2576)
2577select COLUMN1$0, COLUMN2 from t;
2578"), @r"
2579        hover: column t.column1
2580          ╭▸ 
2581        5 │ select COLUMN1, COLUMN2 from t;
2582          ╰╴             ─ hover
2583        ");
2584    }
2585
2586    #[test]
2587    fn hover_on_cte_qualified_star() {
2588        assert_snapshot!(check_hover("
2589with u as (select 1 id, 2 b)
2590select u.*$0 from u;
2591"), @r"
2592        hover: column u.id
2593              column u.b
2594          ╭▸ 
2595        3 │ select u.* from u;
2596          ╰╴         ─ hover
2597        ");
2598    }
2599
2600    #[test]
2601    fn hover_on_cte_values_qualified_star() {
2602        assert_snapshot!(check_hover("
2603with t as (values (1, 2), (3, 4))
2604select t.*$0 from t;
2605"), @r"
2606        hover: column t.column1
2607              column t.column2
2608          ╭▸ 
2609        3 │ select t.* from t;
2610          ╰╴         ─ hover
2611        ");
2612    }
2613
2614    #[test]
2615    fn hover_on_star_with_subquery_from_cte() {
2616        assert_snapshot!(check_hover("
2617with u as (select 1 id, 2 b)
2618select *$0 from (select *, *, * from u);
2619"), @r"
2620        hover: column u.id
2621              column u.b
2622              column u.id
2623              column u.b
2624              column u.id
2625              column u.b
2626          ╭▸ 
2627        3 │ select * from (select *, *, * from u);
2628          ╰╴       ─ hover
2629        ");
2630    }
2631
2632    #[test]
2633    fn hover_on_star_with_subquery_from_table() {
2634        assert_snapshot!(check_hover("
2635create table t(a int, b int);
2636select *$0 from (select a from t);
2637"), @r"
2638        hover: column public.t.a int
2639          ╭▸ 
2640        3 │ select * from (select a from t);
2641          ╰╴       ─ hover
2642        ");
2643    }
2644
2645    #[test]
2646    fn hover_on_view_qualified_star() {
2647        assert_snapshot!(check_hover("
2648create view v as select 1 id, 2 b;
2649select v.*$0 from v;
2650"), @r"
2651        hover: column public.v.id
2652              column public.v.b
2653          ╭▸ 
2654        3 │ select v.* from v;
2655          ╰╴         ─ hover
2656        ");
2657    }
2658
2659    #[test]
2660    fn hover_on_drop_procedure() {
2661        assert_snapshot!(check_hover("
2662create procedure foo() language sql as $$ select 1 $$;
2663drop procedure foo$0();
2664"), @r"
2665        hover: procedure public.foo()
2666          ╭▸ 
2667        3 │ drop procedure foo();
2668          ╰╴                 ─ hover
2669        ");
2670    }
2671
2672    #[test]
2673    fn hover_on_drop_procedure_with_schema() {
2674        assert_snapshot!(check_hover("
2675create procedure myschema.foo() language sql as $$ select 1 $$;
2676drop procedure myschema.foo$0();
2677"), @r"
2678        hover: procedure myschema.foo()
2679          ╭▸ 
2680        3 │ drop procedure myschema.foo();
2681          ╰╴                          ─ hover
2682        ");
2683    }
2684
2685    #[test]
2686    fn hover_on_create_procedure_definition() {
2687        assert_snapshot!(check_hover("
2688create procedure foo$0() language sql as $$ select 1 $$;
2689"), @r"
2690        hover: procedure public.foo()
2691          ╭▸ 
2692        2 │ create procedure foo() language sql as $$ select 1 $$;
2693          ╰╴                   ─ hover
2694        ");
2695    }
2696
2697    #[test]
2698    fn hover_on_create_procedure_with_explicit_schema() {
2699        assert_snapshot!(check_hover("
2700create procedure myschema.foo$0() language sql as $$ select 1 $$;
2701"), @r"
2702        hover: procedure myschema.foo()
2703          ╭▸ 
2704        2 │ create procedure myschema.foo() language sql as $$ select 1 $$;
2705          ╰╴                            ─ hover
2706        ");
2707    }
2708
2709    #[test]
2710    fn hover_on_drop_procedure_with_search_path() {
2711        assert_snapshot!(check_hover(r#"
2712set search_path to myschema;
2713create procedure foo() language sql as $$ select 1 $$;
2714drop procedure foo$0();
2715"#), @r"
2716        hover: procedure myschema.foo()
2717          ╭▸ 
2718        4 │ drop procedure foo();
2719          ╰╴                 ─ hover
2720        ");
2721    }
2722
2723    #[test]
2724    fn hover_on_drop_procedure_overloaded() {
2725        assert_snapshot!(check_hover("
2726create procedure add(complex) language sql as $$ select null $$;
2727create procedure add(bigint) language sql as $$ select 1 $$;
2728drop procedure add$0(complex);
2729"), @r"
2730        hover: procedure public.add(complex)
2731          ╭▸ 
2732        4 │ drop procedure add(complex);
2733          ╰╴                 ─ hover
2734        ");
2735    }
2736
2737    #[test]
2738    fn hover_on_drop_procedure_second_overload() {
2739        assert_snapshot!(check_hover("
2740create procedure add(complex) language sql as $$ select null $$;
2741create procedure add(bigint) language sql as $$ select 1 $$;
2742drop procedure add$0(bigint);
2743"), @r"
2744        hover: procedure public.add(bigint)
2745          ╭▸ 
2746        4 │ drop procedure add(bigint);
2747          ╰╴                 ─ hover
2748        ");
2749    }
2750
2751    #[test]
2752    fn hover_on_call_procedure() {
2753        assert_snapshot!(check_hover("
2754create procedure foo() language sql as $$ select 1 $$;
2755call foo$0();
2756"), @r"
2757        hover: procedure public.foo()
2758          ╭▸ 
2759        3 │ call foo();
2760          ╰╴       ─ hover
2761        ");
2762    }
2763
2764    #[test]
2765    fn hover_on_call_procedure_with_schema() {
2766        assert_snapshot!(check_hover("
2767create procedure public.foo() language sql as $$ select 1 $$;
2768call public.foo$0();
2769"), @r"
2770        hover: procedure public.foo()
2771          ╭▸ 
2772        3 │ call public.foo();
2773          ╰╴              ─ hover
2774        ");
2775    }
2776
2777    #[test]
2778    fn hover_on_call_procedure_with_search_path() {
2779        assert_snapshot!(check_hover(r#"
2780set search_path to myschema;
2781create procedure foo() language sql as $$ select 1 $$;
2782call foo$0();
2783"#), @r"
2784        hover: procedure myschema.foo()
2785          ╭▸ 
2786        4 │ call foo();
2787          ╰╴       ─ hover
2788        ");
2789    }
2790
2791    #[test]
2792    fn hover_on_call_procedure_with_params() {
2793        assert_snapshot!(check_hover("
2794create procedure add(a int, b int) language sql as $$ select a + b $$;
2795call add$0(1, 2);
2796"), @r"
2797        hover: procedure public.add(a int, b int)
2798          ╭▸ 
2799        3 │ call add(1, 2);
2800          ╰╴       ─ hover
2801        ");
2802    }
2803
2804    #[test]
2805    fn hover_on_drop_routine_function() {
2806        assert_snapshot!(check_hover("
2807create function foo() returns int as $$ select 1 $$ language sql;
2808drop routine foo$0();
2809"), @r"
2810        hover: function public.foo() returns int
2811          ╭▸ 
2812        3 │ drop routine foo();
2813          ╰╴               ─ hover
2814        ");
2815    }
2816
2817    #[test]
2818    fn hover_on_drop_routine_aggregate() {
2819        assert_snapshot!(check_hover("
2820create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2821drop routine myavg$0(int);
2822"), @r"
2823        hover: aggregate public.myavg(int)
2824          ╭▸ 
2825        3 │ drop routine myavg(int);
2826          ╰╴                 ─ hover
2827        ");
2828    }
2829
2830    #[test]
2831    fn hover_on_drop_routine_procedure() {
2832        assert_snapshot!(check_hover("
2833create procedure foo() language sql as $$ select 1 $$;
2834drop routine foo$0();
2835"), @r"
2836        hover: procedure public.foo()
2837          ╭▸ 
2838        3 │ drop routine foo();
2839          ╰╴               ─ hover
2840        ");
2841    }
2842
2843    #[test]
2844    fn hover_on_drop_routine_with_schema() {
2845        assert_snapshot!(check_hover("
2846set search_path to public;
2847create function foo() returns int as $$ select 1 $$ language sql;
2848drop routine public.foo$0();
2849"), @r"
2850        hover: function public.foo() returns int
2851          ╭▸ 
2852        4 │ drop routine public.foo();
2853          ╰╴                      ─ hover
2854        ");
2855    }
2856
2857    #[test]
2858    fn hover_on_drop_routine_with_search_path() {
2859        assert_snapshot!(check_hover(r#"
2860set search_path to myschema;
2861create function foo() returns int as $$ select 1 $$ language sql;
2862drop routine foo$0();
2863"#), @r"
2864        hover: function myschema.foo() returns int
2865          ╭▸ 
2866        4 │ drop routine foo();
2867          ╰╴               ─ hover
2868        ");
2869    }
2870
2871    #[test]
2872    fn hover_on_drop_routine_overloaded() {
2873        assert_snapshot!(check_hover("
2874create function add(complex) returns complex as $$ select null $$ language sql;
2875create function add(bigint) returns bigint as $$ select 1 $$ language sql;
2876drop routine add$0(complex);
2877"), @r"
2878        hover: function public.add(complex) returns complex
2879          ╭▸ 
2880        4 │ drop routine add(complex);
2881          ╰╴               ─ hover
2882        ");
2883    }
2884
2885    #[test]
2886    fn hover_on_drop_routine_prefers_function_over_procedure() {
2887        assert_snapshot!(check_hover("
2888create function foo() returns int as $$ select 1 $$ language sql;
2889create procedure foo() language sql as $$ select 1 $$;
2890drop routine foo$0();
2891"), @r"
2892        hover: function public.foo() returns int
2893          ╭▸ 
2894        4 │ drop routine foo();
2895          ╰╴               ─ hover
2896        ");
2897    }
2898
2899    #[test]
2900    fn hover_on_drop_routine_prefers_aggregate_over_procedure() {
2901        assert_snapshot!(check_hover("
2902create aggregate foo(int) (sfunc = int4_avg_accum, stype = _int8);
2903create procedure foo(int) language sql as $$ select 1 $$;
2904drop routine foo$0(int);
2905"), @r"
2906        hover: aggregate public.foo(int)
2907          ╭▸ 
2908        4 │ drop routine foo(int);
2909          ╰╴               ─ hover
2910        ");
2911    }
2912
2913    #[test]
2914    fn hover_on_update_table() {
2915        assert_snapshot!(check_hover("
2916create table users(id int, email text);
2917update users$0 set email = 'new@example.com';
2918"), @r"
2919        hover: table public.users(id int, email text)
2920          ╭▸ 
2921        3 │ update users set email = 'new@example.com';
2922          ╰╴           ─ hover
2923        ");
2924    }
2925
2926    #[test]
2927    fn hover_on_update_table_with_schema() {
2928        assert_snapshot!(check_hover("
2929create table public.users(id int, email text);
2930update public.users$0 set email = 'new@example.com';
2931"), @r"
2932        hover: table public.users(id int, email text)
2933          ╭▸ 
2934        3 │ update public.users set email = 'new@example.com';
2935          ╰╴                  ─ hover
2936        ");
2937    }
2938
2939    #[test]
2940    fn hover_on_update_set_column() {
2941        assert_snapshot!(check_hover("
2942create table users(id int, email text);
2943update users set email$0 = 'new@example.com' where id = 1;
2944"), @r"
2945        hover: column public.users.email text
2946          ╭▸ 
2947        3 │ update users set email = 'new@example.com' where id = 1;
2948          ╰╴                     ─ hover
2949        ");
2950    }
2951
2952    #[test]
2953    fn hover_on_update_set_column_with_schema() {
2954        assert_snapshot!(check_hover("
2955create table public.users(id int, email text);
2956update public.users set email$0 = 'new@example.com' where id = 1;
2957"), @r"
2958        hover: column public.users.email text
2959          ╭▸ 
2960        3 │ update public.users set email = 'new@example.com' where id = 1;
2961          ╰╴                            ─ hover
2962        ");
2963    }
2964
2965    #[test]
2966    fn hover_on_update_where_column() {
2967        assert_snapshot!(check_hover("
2968create table users(id int, email text);
2969update users set email = 'new@example.com' where id$0 = 1;
2970"), @r"
2971        hover: column public.users.id int
2972          ╭▸ 
2973        3 │ update users set email = 'new@example.com' where id = 1;
2974          ╰╴                                                  ─ hover
2975        ");
2976    }
2977
2978    #[test]
2979    fn hover_on_update_where_column_with_schema() {
2980        assert_snapshot!(check_hover("
2981create table public.users(id int, email text);
2982update public.users set email = 'new@example.com' where id$0 = 1;
2983"), @r"
2984        hover: column public.users.id int
2985          ╭▸ 
2986        3 │ update public.users set email = 'new@example.com' where id = 1;
2987          ╰╴                                                         ─ hover
2988        ");
2989    }
2990
2991    #[test]
2992    fn hover_on_update_from_table() {
2993        assert_snapshot!(check_hover("
2994create table users(id int, email text);
2995create table messages(id int, user_id int, email text);
2996update users set email = messages.email from messages$0 where users.id = messages.user_id;
2997"), @r"
2998        hover: table public.messages(id int, user_id int, email text)
2999          ╭▸ 
3000        4 │ update users set email = messages.email from messages where users.id = messages.user_id;
3001          ╰╴                                                    ─ hover
3002        ");
3003    }
3004
3005    #[test]
3006    fn hover_on_update_from_table_with_schema() {
3007        assert_snapshot!(check_hover("
3008create table users(id int, email text);
3009create table public.messages(id int, user_id int, email text);
3010update users set email = messages.email from public.messages$0 where users.id = messages.user_id;
3011"), @r"
3012        hover: table public.messages(id int, user_id int, email text)
3013          ╭▸ 
3014        4 │ update users set email = messages.email from public.messages where users.id = messages.user_id;
3015          ╰╴                                                           ─ hover
3016        ");
3017    }
3018
3019    #[test]
3020    fn hover_on_update_with_cte_table() {
3021        assert_snapshot!(check_hover("
3022create table users(id int, email text);
3023with new_data as (
3024    select 1 as id, 'new@example.com' as email
3025)
3026update users set email = new_data.email from new_data$0 where users.id = new_data.id;
3027"), @r"
3028        hover: with new_data as (select 1 as id, 'new@example.com' as email)
3029          ╭▸ 
3030        6 │ update users set email = new_data.email from new_data where users.id = new_data.id;
3031          ╰╴                                                    ─ hover
3032        ");
3033    }
3034
3035    #[test]
3036    fn hover_on_update_with_cte_column_in_set() {
3037        assert_snapshot!(check_hover("
3038create table users(id int, email text);
3039with new_data as (
3040    select 1 as id, 'new@example.com' as email
3041)
3042update users set email = new_data.email$0 from new_data where users.id = new_data.id;
3043"), @r"
3044        hover: column new_data.email
3045          ╭▸ 
3046        6 │ update users set email = new_data.email from new_data where users.id = new_data.id;
3047          ╰╴                                      ─ hover
3048        ");
3049    }
3050
3051    #[test]
3052    fn hover_on_update_with_cte_column_in_where() {
3053        assert_snapshot!(check_hover("
3054create table users(id int, email text);
3055with new_data as (
3056    select 1 as id, 'new@example.com' as email
3057)
3058update users set email = new_data.email from new_data where new_data.id$0 = users.id;
3059"), @r"
3060        hover: column new_data.id
3061          ╭▸ 
3062        6 │ update users set email = new_data.email from new_data where new_data.id = users.id;
3063          ╰╴                                                                      ─ hover
3064        ");
3065    }
3066
3067    #[test]
3068    fn hover_on_create_view_definition() {
3069        assert_snapshot!(check_hover("
3070create view v$0 as select 1;
3071"), @r"
3072        hover: view public.v as select 1
3073          ╭▸ 
3074        2 │ create view v as select 1;
3075          ╰╴            ─ hover
3076        ");
3077    }
3078
3079    #[test]
3080    fn hover_on_create_view_definition_with_schema() {
3081        assert_snapshot!(check_hover("
3082create view myschema.v$0 as select 1;
3083"), @r"
3084        hover: view myschema.v as select 1
3085          ╭▸ 
3086        2 │ create view myschema.v as select 1;
3087          ╰╴                     ─ hover
3088        ");
3089    }
3090
3091    #[test]
3092    fn hover_on_create_temp_view_definition() {
3093        assert_snapshot!(check_hover("
3094create temp view v$0 as select 1;
3095"), @r"
3096        hover: view pg_temp.v as select 1
3097          ╭▸ 
3098        2 │ create temp view v as select 1;
3099          ╰╴                 ─ hover
3100        ");
3101    }
3102
3103    #[test]
3104    fn hover_on_create_view_with_column_list() {
3105        assert_snapshot!(check_hover("
3106create view v(col1$0) as select 1;
3107"), @r"
3108        hover: column public.v.col1
3109          ╭▸ 
3110        2 │ create view v(col1) as select 1;
3111          ╰╴                 ─ hover
3112        ");
3113    }
3114
3115    #[test]
3116    fn hover_on_select_from_view() {
3117        assert_snapshot!(check_hover("
3118create view v as select 1;
3119select * from v$0;
3120"), @r"
3121        hover: view public.v as select 1
3122          ╭▸ 
3123        3 │ select * from v;
3124          ╰╴              ─ hover
3125        ");
3126    }
3127
3128    #[test]
3129    fn hover_on_select_column_from_view_column_list() {
3130        assert_snapshot!(check_hover("
3131create view v(a) as select 1;
3132select a$0 from v;
3133"), @r"
3134        hover: column public.v.a
3135          ╭▸ 
3136        3 │ select a from v;
3137          ╰╴       ─ hover
3138        ");
3139    }
3140
3141    #[test]
3142    fn hover_on_select_column_from_view_column_list_overrides_target() {
3143        assert_snapshot!(check_hover("
3144create view v(a) as select 1, 2 b;
3145select a, b$0 from v;
3146"), @r"
3147        hover: column public.v.b
3148          ╭▸ 
3149        3 │ select a, b from v;
3150          ╰╴          ─ hover
3151        ");
3152    }
3153
3154    #[test]
3155    fn hover_on_select_column_from_view_target_list() {
3156        assert_snapshot!(check_hover("
3157create view v as select 1 a, 2 b;
3158select a$0, b from v;
3159"), @r"
3160        hover: column public.v.a
3161          ╭▸ 
3162        3 │ select a, b from v;
3163          ╰╴       ─ hover
3164        ");
3165    }
3166
3167    #[test]
3168    fn hover_on_select_from_view_with_schema() {
3169        assert_snapshot!(check_hover("
3170create view myschema.v as select 1;
3171select * from myschema.v$0;
3172"), @r"
3173        hover: view myschema.v as select 1
3174          ╭▸ 
3175        3 │ select * from myschema.v;
3176          ╰╴                       ─ hover
3177        ");
3178    }
3179
3180    #[test]
3181    fn hover_on_drop_view() {
3182        assert_snapshot!(check_hover("
3183create view v as select 1;
3184drop view v$0;
3185"), @r"
3186        hover: view public.v as select 1
3187          ╭▸ 
3188        3 │ drop view v;
3189          ╰╴          ─ hover
3190        ");
3191    }
3192
3193    #[test]
3194    fn hover_composite_type_field() {
3195        assert_snapshot!(check_hover("
3196create type person_info as (name varchar(50), age int);
3197with team as (
3198    select 1 as id, ('Alice', 30)::person_info as member
3199)
3200select (member).name$0, (member).age from team;
3201"), @r"
3202        hover: field public.person_info.name varchar(50)
3203          ╭▸ 
3204        6 │ select (member).name, (member).age from team;
3205          ╰╴                   ─ hover
3206        ");
3207    }
3208
3209    #[test]
3210    fn hover_composite_type_field_age() {
3211        assert_snapshot!(check_hover("
3212create type person_info as (name varchar(50), age int);
3213with team as (
3214    select 1 as id, ('Alice', 30)::person_info as member
3215)
3216select (member).name, (member).age$0 from team;
3217"), @r"
3218        hover: field public.person_info.age int
3219          ╭▸ 
3220        6 │ select (member).name, (member).age from team;
3221          ╰╴                                 ─ hover
3222        ");
3223    }
3224
3225    #[test]
3226    fn hover_composite_type_field_nested_parens() {
3227        assert_snapshot!(check_hover("
3228create type person_info as (name varchar(50), age int);
3229with team as (
3230    select 1 as id, ('Alice', 30)::person_info as member
3231)
3232select ((((member))).name$0) from team;
3233"), @r"
3234        hover: field public.person_info.name varchar(50)
3235          ╭▸ 
3236        6 │ select ((((member))).name) from team;
3237          ╰╴                        ─ hover
3238        ");
3239    }
3240
3241    #[test]
3242    fn hover_on_join_using_column() {
3243        assert_snapshot!(check_hover("
3244create table t(id int);
3245create table u(id int);
3246select * from t join u using (id$0);
3247"), @r"
3248        hover: column public.t.id int
3249              column public.u.id int
3250          ╭▸ 
3251        4 │ select * from t join u using (id);
3252          ╰╴                               ─ hover
3253        ");
3254    }
3255
3256    #[test]
3257    fn hover_on_truncate_table() {
3258        assert_snapshot!(check_hover("
3259create table users(id int, email text);
3260truncate table users$0;
3261"), @r"
3262        hover: table public.users(id int, email text)
3263          ╭▸ 
3264        3 │ truncate table users;
3265          ╰╴                   ─ hover
3266        ");
3267    }
3268
3269    #[test]
3270    fn hover_on_truncate_table_without_table_keyword() {
3271        assert_snapshot!(check_hover("
3272create table users(id int, email text);
3273truncate users$0;
3274"), @r"
3275        hover: table public.users(id int, email text)
3276          ╭▸ 
3277        3 │ truncate users;
3278          ╰╴             ─ hover
3279        ");
3280    }
3281
3282    #[test]
3283    fn hover_on_lock_table() {
3284        assert_snapshot!(check_hover("
3285create table users(id int, email text);
3286lock table users$0;
3287"), @r"
3288        hover: table public.users(id int, email text)
3289          ╭▸ 
3290        3 │ lock table users;
3291          ╰╴               ─ hover
3292        ");
3293    }
3294
3295    #[test]
3296    fn hover_on_lock_table_without_table_keyword() {
3297        assert_snapshot!(check_hover("
3298create table users(id int, email text);
3299lock users$0;
3300"), @r"
3301        hover: table public.users(id int, email text)
3302          ╭▸ 
3303        3 │ lock users;
3304          ╰╴         ─ hover
3305        ");
3306    }
3307
3308    #[test]
3309    fn hover_on_vacuum_table() {
3310        assert_snapshot!(check_hover("
3311create table users(id int, email text);
3312vacuum users$0;
3313"), @r"
3314        hover: table public.users(id int, email text)
3315          ╭▸ 
3316        3 │ vacuum users;
3317          ╰╴           ─ hover
3318        ");
3319    }
3320
3321    #[test]
3322    fn hover_on_vacuum_with_analyze() {
3323        assert_snapshot!(check_hover("
3324create table users(id int, email text);
3325vacuum analyze users$0;
3326"), @r"
3327        hover: table public.users(id int, email text)
3328          ╭▸ 
3329        3 │ vacuum analyze users;
3330          ╰╴                   ─ hover
3331        ");
3332    }
3333
3334    #[test]
3335    fn hover_on_alter_table() {
3336        assert_snapshot!(check_hover("
3337create table users(id int, email text);
3338alter table users$0 alter email set not null;
3339"), @r"
3340        hover: table public.users(id int, email text)
3341          ╭▸ 
3342        3 │ alter table users alter email set not null;
3343          ╰╴                ─ hover
3344        ");
3345    }
3346
3347    #[test]
3348    fn hover_on_alter_table_column() {
3349        assert_snapshot!(check_hover("
3350create table users(id int, email text);
3351alter table users alter email$0 set not null;
3352"), @r"
3353        hover: column public.users.email text
3354          ╭▸ 
3355        3 │ alter table users alter email set not null;
3356          ╰╴                            ─ hover
3357        ");
3358    }
3359
3360    #[test]
3361    fn hover_on_refresh_materialized_view() {
3362        assert_snapshot!(check_hover("
3363create materialized view mv as select 1;
3364refresh materialized view mv$0;
3365"), @r"
3366        hover: materialized view public.mv as select 1
3367          ╭▸ 
3368        3 │ refresh materialized view mv;
3369          ╰╴                           ─ hover
3370        ");
3371    }
3372
3373    #[test]
3374    fn hover_on_reindex_table() {
3375        assert_snapshot!(check_hover("
3376create table users(id int);
3377reindex table users$0;
3378"), @r"
3379        hover: table public.users(id int)
3380          ╭▸ 
3381        3 │ reindex table users;
3382          ╰╴                  ─ hover
3383        ");
3384    }
3385
3386    #[test]
3387    fn hover_on_reindex_index() {
3388        assert_snapshot!(check_hover("
3389create table t(c int);
3390create index idx on t(c);
3391reindex index idx$0;
3392"), @r"
3393        hover: index public.idx on public.t(c)
3394          ╭▸ 
3395        4 │ reindex index idx;
3396          ╰╴                ─ hover
3397        ");
3398    }
3399
3400    #[test]
3401    fn hover_merge_returning_star_from_cte() {
3402        assert_snapshot!(check_hover("
3403create table t(a int, b int);
3404with u(x, y) as (
3405  select 1, 2
3406),
3407merged as (
3408  merge into t
3409    using u
3410      on t.a = u.x
3411  when matched then
3412    do nothing
3413  when not matched then
3414    do nothing
3415  returning a as x, b as y
3416)
3417select *$0 from merged;
3418"), @r"
3419        hover: column merged.x
3420              column merged.y
3421           ╭▸ 
3422        16 │ select * from merged;
3423           ╰╴       ─ hover
3424        ");
3425    }
3426}