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