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