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