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