1use crate::offsets::token_from_offset;
2use crate::resolve;
3use crate::{binder, symbols::Name};
4use rowan::TextSize;
5use squawk_syntax::ast::{self, AstNode};
6
7pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
8 let token = token_from_offset(file, offset)?;
9 let parent = token.parent()?;
10
11 let binder = binder::bind(file);
12
13 if let Some(name_ref) = ast::NameRef::cast(parent.clone()) {
15 if is_column_ref(&name_ref) {
16 return hover_column(file, &name_ref, &binder);
17 }
18
19 if is_type_ref(&name_ref) {
20 return hover_type(file, &name_ref, &binder);
21 }
22
23 if is_select_column(&name_ref) {
24 if let Some(result) = hover_column(file, &name_ref, &binder) {
26 return Some(result);
27 }
28 if let Some(result) = hover_function(file, &name_ref, &binder) {
30 return Some(result);
31 }
32 return hover_table(file, &name_ref, &binder);
34 }
35
36 if is_table_ref(&name_ref) {
37 return hover_table(file, &name_ref, &binder);
38 }
39
40 if is_select_from_table(&name_ref) {
41 return hover_table(file, &name_ref, &binder);
42 }
43
44 if is_update_from_table(&name_ref) {
45 return hover_table(file, &name_ref, &binder);
46 }
47
48 if is_index_ref(&name_ref) {
49 return hover_index(file, &name_ref, &binder);
50 }
51
52 if is_function_ref(&name_ref) {
53 return hover_function(file, &name_ref, &binder);
54 }
55
56 if is_aggregate_ref(&name_ref) {
57 return hover_aggregate(file, &name_ref, &binder);
58 }
59
60 if is_procedure_ref(&name_ref) {
61 return hover_procedure(file, &name_ref, &binder);
62 }
63
64 if is_routine_ref(&name_ref) {
65 return hover_routine(file, &name_ref, &binder);
66 }
67
68 if is_call_procedure(&name_ref) {
69 return hover_procedure(file, &name_ref, &binder);
70 }
71
72 if is_select_function_call(&name_ref) {
73 if let Some(result) = hover_function(file, &name_ref, &binder) {
76 return Some(result);
77 }
78 return hover_column(file, &name_ref, &binder);
79 }
80
81 if is_schema_ref(&name_ref) {
82 return hover_schema(file, &name_ref, &binder);
83 }
84 }
85
86 if let Some(name) = ast::Name::cast(parent) {
87 if let Some(column) = name.syntax().parent().and_then(ast::Column::cast)
88 && let Some(create_table) = column.syntax().ancestors().find_map(ast::CreateTable::cast)
89 {
90 return hover_column_definition(&create_table, &column, &binder);
91 }
92
93 if let Some(create_table) = name.syntax().ancestors().find_map(ast::CreateTable::cast) {
94 return format_create_table(&create_table, &binder);
95 }
96
97 if let Some(with_table) = name.syntax().parent().and_then(ast::WithTable::cast) {
98 return format_with_table(&with_table);
99 }
100
101 if let Some(create_index) = name.syntax().ancestors().find_map(ast::CreateIndex::cast) {
102 return format_create_index(&create_index, &binder);
103 }
104
105 if let Some(create_type) = name.syntax().ancestors().find_map(ast::CreateType::cast) {
106 return format_create_type(&create_type, &binder);
107 }
108
109 if let Some(create_function) = name
110 .syntax()
111 .ancestors()
112 .find_map(ast::CreateFunction::cast)
113 {
114 return format_create_function(&create_function, &binder);
115 }
116
117 if let Some(create_aggregate) = name
118 .syntax()
119 .ancestors()
120 .find_map(ast::CreateAggregate::cast)
121 {
122 return format_create_aggregate(&create_aggregate, &binder);
123 }
124
125 if let Some(create_procedure) = name
126 .syntax()
127 .ancestors()
128 .find_map(ast::CreateProcedure::cast)
129 {
130 return format_create_procedure(&create_procedure, &binder);
131 }
132
133 if let Some(create_schema) = name.syntax().ancestors().find_map(ast::CreateSchema::cast) {
134 return format_create_schema(&create_schema);
135 }
136 }
137
138 None
139}
140
141fn format_column(
142 schema: &str,
143 table_name: &str,
144 column_name: &str,
145 ty: &impl std::fmt::Display,
146) -> String {
147 format!("column {schema}.{table_name}.{column_name} {ty}")
148}
149
150fn hover_column(
151 file: &ast::SourceFile,
152 name_ref: &ast::NameRef,
153 binder: &binder::Binder,
154) -> Option<String> {
155 let column_ptr = resolve::resolve_name_ref(binder, name_ref)?;
156
157 let root = file.syntax();
158 let column_name_node = column_ptr.to_node(root);
159
160 if let Some(with_table) = column_name_node.ancestors().find_map(ast::WithTable::cast) {
161 let cte_name = with_table.name()?.syntax().text().to_string();
162 let column_name = if column_name_node
163 .ancestors()
164 .any(|a| ast::Values::can_cast(a.kind()))
165 {
166 Name::from_node(name_ref)
167 } else {
168 Name::from_string(column_name_node.text().to_string())
169 };
170 return Some(format!("column {}.{}", cte_name, column_name));
171 }
172
173 let column = column_name_node.ancestors().find_map(ast::Column::cast)?;
174 let column_name = column.name()?.syntax().text().to_string();
175 let ty = column.ty()?;
176
177 let create_table = column
178 .syntax()
179 .ancestors()
180 .find_map(ast::CreateTable::cast)?;
181 let path = create_table.path()?;
182 let table_name = path.segment()?.name()?.syntax().text().to_string();
183
184 let schema = if let Some(qualifier) = path.qualifier() {
185 qualifier.syntax().text().to_string()
186 } else {
187 table_schema(&create_table, binder)?
188 };
189
190 Some(format_column(
191 &schema,
192 &table_name,
193 &column_name,
194 &ty.syntax().text(),
195 ))
196}
197
198fn hover_column_definition(
199 create_table: &ast::CreateTable,
200 column: &ast::Column,
201 binder: &binder::Binder,
202) -> Option<String> {
203 let column_name = column.name()?.syntax().text().to_string();
204 let ty = column.ty()?;
205 let path = create_table.path()?;
206 let table_name = path.segment()?.name()?.syntax().text().to_string();
207
208 let schema = if let Some(qualifier) = path.qualifier() {
209 qualifier.syntax().text().to_string()
210 } else {
211 table_schema(create_table, binder)?
212 };
213
214 Some(format_column(
215 &schema,
216 &table_name,
217 &column_name,
218 &ty.syntax().text(),
219 ))
220}
221
222fn hover_table(
223 file: &ast::SourceFile,
224 name_ref: &ast::NameRef,
225 binder: &binder::Binder,
226) -> Option<String> {
227 let table_ptr = resolve::resolve_name_ref(binder, name_ref)?;
228
229 let root = file.syntax();
230 let table_name_node = table_ptr.to_node(root);
231
232 if let Some(with_table) = table_name_node.ancestors().find_map(ast::WithTable::cast) {
233 return format_with_table(&with_table);
234 }
235
236 let create_table = table_name_node
237 .ancestors()
238 .find_map(ast::CreateTable::cast)?;
239
240 format_create_table(&create_table, binder)
241}
242
243fn hover_index(
244 file: &ast::SourceFile,
245 name_ref: &ast::NameRef,
246 binder: &binder::Binder,
247) -> Option<String> {
248 let index_ptr = resolve::resolve_name_ref(binder, name_ref)?;
249
250 let root = file.syntax();
251 let index_name_node = index_ptr.to_node(root);
252
253 let create_index = index_name_node
254 .ancestors()
255 .find_map(ast::CreateIndex::cast)?;
256
257 format_create_index(&create_index, binder)
258}
259
260fn hover_type(
261 file: &ast::SourceFile,
262 name_ref: &ast::NameRef,
263 binder: &binder::Binder,
264) -> Option<String> {
265 let type_ptr = resolve::resolve_name_ref(binder, name_ref)?;
266
267 let root = file.syntax();
268 let type_name_node = type_ptr.to_node(root);
269
270 let create_type = type_name_node.ancestors().find_map(ast::CreateType::cast)?;
271
272 format_create_type(&create_type, binder)
273}
274
275fn format_create_table(create_table: &ast::CreateTable, binder: &binder::Binder) -> Option<String> {
277 let path = create_table.path()?;
278 let segment = path.segment()?;
279 let table_name = segment.name()?.syntax().text().to_string();
280
281 let schema = if let Some(qualifier) = path.qualifier() {
282 qualifier.syntax().text().to_string()
283 } else {
284 table_schema(create_table, binder)?
285 };
286
287 let args = create_table.table_arg_list()?.syntax().text().to_string();
288
289 Some(format!("table {}.{}{}", schema, table_name, args))
290}
291
292fn format_with_table(with_table: &ast::WithTable) -> Option<String> {
293 let name = with_table.name()?.syntax().text().to_string();
294 let query = with_table.query()?.syntax().text().to_string();
295 Some(format!("with {} as ({})", name, query))
296}
297
298fn table_schema(create_table: &ast::CreateTable, binder: &binder::Binder) -> Option<String> {
299 let is_temp = create_table.temp_token().is_some() || create_table.temporary_token().is_some();
300 if is_temp {
301 return Some("pg_temp".to_string());
302 }
303
304 let position = create_table.syntax().text_range().start();
305 let search_path = binder.search_path_at(position);
306 search_path.first().map(|s| s.to_string())
307}
308
309fn format_create_index(create_index: &ast::CreateIndex, binder: &binder::Binder) -> Option<String> {
310 let index_name = create_index.name()?.syntax().text().to_string();
311
312 let index_schema = index_schema(create_index, binder)?;
313
314 let relation_name = create_index.relation_name()?;
315 let path = relation_name.path()?;
316 let (table_schema, table_name) = resolve::resolve_table_info(binder, &path)?;
317
318 let partition_item_list = create_index.partition_item_list()?;
319 let columns = partition_item_list.syntax().text().to_string();
320
321 Some(format!(
322 "index {}.{} on {}.{}{}",
323 index_schema, index_name, table_schema, table_name, columns
324 ))
325}
326
327fn index_schema(create_index: &ast::CreateIndex, binder: &binder::Binder) -> Option<String> {
328 let position = create_index.syntax().text_range().start();
329 let search_path = binder.search_path_at(position);
330 search_path.first().map(|s| s.to_string())
331}
332
333fn format_create_type(create_type: &ast::CreateType, binder: &binder::Binder) -> Option<String> {
334 let path = create_type.path()?;
335 let segment = path.segment()?;
336 let type_name = segment.name()?.syntax().text().to_string();
337
338 let schema = if let Some(qualifier) = path.qualifier() {
339 qualifier.syntax().text().to_string()
340 } else {
341 type_schema(create_type, binder)?
342 };
343
344 if let Some(variant_list) = create_type.variant_list() {
345 let variants = variant_list.syntax().text().to_string();
346 return Some(format!(
347 "type {}.{} as enum {}",
348 schema, type_name, variants
349 ));
350 }
351
352 if let Some(column_list) = create_type.column_list() {
353 let columns = column_list.syntax().text().to_string();
354 return Some(format!("type {}.{} as {}", schema, type_name, columns));
355 }
356
357 if let Some(attribute_list) = create_type.attribute_list() {
358 let attributes = attribute_list.syntax().text().to_string();
359 return Some(format!("type {}.{} {}", schema, type_name, attributes));
360 }
361
362 Some(format!("type {}.{}", schema, type_name))
363}
364
365fn type_schema(create_type: &ast::CreateType, binder: &binder::Binder) -> Option<String> {
366 let position = create_type.syntax().text_range().start();
367 let search_path = binder.search_path_at(position);
368 search_path.first().map(|s| s.to_string())
369}
370
371fn is_column_ref(name_ref: &ast::NameRef) -> bool {
372 let mut in_partition_item = false;
373 let mut in_column_list = false;
374 let mut in_where_clause = false;
375 let mut in_set_clause = false;
376
377 for ancestor in name_ref.syntax().ancestors() {
378 if ast::PartitionItem::can_cast(ancestor.kind()) {
379 in_partition_item = true;
380 }
381 if ast::CreateIndex::can_cast(ancestor.kind()) {
382 return in_partition_item;
383 }
384 if ast::ColumnList::can_cast(ancestor.kind()) {
385 in_column_list = true;
386 }
387 if ast::Insert::can_cast(ancestor.kind()) {
388 return in_column_list;
389 }
390 if ast::WhereClause::can_cast(ancestor.kind()) {
391 in_where_clause = true;
392 }
393 if ast::SetClause::can_cast(ancestor.kind()) {
394 in_set_clause = true;
395 }
396 if ast::Delete::can_cast(ancestor.kind()) {
397 return in_where_clause;
398 }
399 if ast::Update::can_cast(ancestor.kind()) {
400 return in_where_clause || in_set_clause;
401 }
402 }
403 false
404}
405
406fn is_table_ref(name_ref: &ast::NameRef) -> bool {
407 let mut in_partition_item = false;
408 let mut in_column_list = false;
409 let mut in_where_clause = false;
410 let mut in_set_clause = false;
411 let mut in_from_clause = false;
412
413 for ancestor in name_ref.syntax().ancestors() {
414 if ast::DropTable::can_cast(ancestor.kind()) {
415 return true;
416 }
417 if ast::Table::can_cast(ancestor.kind()) {
418 return true;
419 }
420 if ast::ColumnList::can_cast(ancestor.kind()) {
421 in_column_list = true;
422 }
423 if ast::Insert::can_cast(ancestor.kind()) {
424 return !in_column_list;
425 }
426 if ast::WhereClause::can_cast(ancestor.kind()) {
427 in_where_clause = true;
428 }
429 if ast::SetClause::can_cast(ancestor.kind()) {
430 in_set_clause = true;
431 }
432 if ast::FromClause::can_cast(ancestor.kind()) {
433 in_from_clause = true;
434 }
435 if ast::Delete::can_cast(ancestor.kind()) {
436 return !in_where_clause;
437 }
438 if ast::Update::can_cast(ancestor.kind()) {
439 return !in_where_clause && !in_set_clause && !in_from_clause;
440 }
441 if ast::DropIndex::can_cast(ancestor.kind()) {
442 return false;
443 }
444 if ast::PartitionItem::can_cast(ancestor.kind()) {
445 in_partition_item = true;
446 }
447 if ast::CreateIndex::can_cast(ancestor.kind()) {
448 return !in_partition_item;
449 }
450 }
451 false
452}
453
454fn is_index_ref(name_ref: &ast::NameRef) -> bool {
455 for ancestor in name_ref.syntax().ancestors() {
456 if ast::DropIndex::can_cast(ancestor.kind()) {
457 return true;
458 }
459 }
460 false
461}
462
463fn is_type_ref(name_ref: &ast::NameRef) -> bool {
464 let mut in_type = false;
465 for ancestor in name_ref.syntax().ancestors() {
466 if ast::PathType::can_cast(ancestor.kind()) || ast::ExprType::can_cast(ancestor.kind()) {
467 in_type = true;
468 }
469 if ast::DropType::can_cast(ancestor.kind()) {
470 return true;
471 }
472 if ast::CastExpr::can_cast(ancestor.kind()) && in_type {
473 return true;
474 }
475 }
476 false
477}
478
479fn is_function_ref(name_ref: &ast::NameRef) -> bool {
480 for ancestor in name_ref.syntax().ancestors() {
481 if ast::DropFunction::can_cast(ancestor.kind()) {
482 return true;
483 }
484 }
485 false
486}
487
488fn is_aggregate_ref(name_ref: &ast::NameRef) -> bool {
489 for ancestor in name_ref.syntax().ancestors() {
490 if ast::DropAggregate::can_cast(ancestor.kind()) {
491 return true;
492 }
493 }
494 false
495}
496
497fn is_procedure_ref(name_ref: &ast::NameRef) -> bool {
498 for ancestor in name_ref.syntax().ancestors() {
499 if ast::DropProcedure::can_cast(ancestor.kind()) {
500 return true;
501 }
502 }
503 false
504}
505
506fn is_routine_ref(name_ref: &ast::NameRef) -> bool {
507 for ancestor in name_ref.syntax().ancestors() {
508 if ast::DropRoutine::can_cast(ancestor.kind()) {
509 return true;
510 }
511 }
512 false
513}
514
515fn is_call_procedure(name_ref: &ast::NameRef) -> bool {
516 for ancestor in name_ref.syntax().ancestors() {
517 if ast::Call::can_cast(ancestor.kind()) {
518 return true;
519 }
520 }
521 false
522}
523
524fn is_select_function_call(name_ref: &ast::NameRef) -> bool {
525 let mut in_call_expr = false;
526 let mut in_arg_list = false;
527
528 for ancestor in name_ref.syntax().ancestors() {
529 if ast::ArgList::can_cast(ancestor.kind()) {
530 in_arg_list = true;
531 }
532 if ast::CallExpr::can_cast(ancestor.kind()) {
533 in_call_expr = true;
534 }
535 if ast::Select::can_cast(ancestor.kind()) && in_call_expr && !in_arg_list {
536 return true;
537 }
538 }
539 false
540}
541
542fn is_select_from_table(name_ref: &ast::NameRef) -> bool {
543 let mut in_from_clause = false;
544
545 for ancestor in name_ref.syntax().ancestors() {
546 if ast::FromClause::can_cast(ancestor.kind()) {
547 in_from_clause = true;
548 }
549 if ast::Select::can_cast(ancestor.kind()) && in_from_clause {
550 return true;
551 }
552 }
553 false
554}
555
556fn is_update_from_table(name_ref: &ast::NameRef) -> bool {
557 let mut in_from_clause = false;
558
559 for ancestor in name_ref.syntax().ancestors() {
560 if ast::FromClause::can_cast(ancestor.kind()) {
561 in_from_clause = true;
562 }
563 if ast::Update::can_cast(ancestor.kind()) && in_from_clause {
564 return true;
565 }
566 }
567 false
568}
569
570fn is_select_column(name_ref: &ast::NameRef) -> bool {
571 let mut in_call_expr = false;
572 let mut in_arg_list = false;
573 let mut in_from_clause = false;
574
575 for ancestor in name_ref.syntax().ancestors() {
576 if ast::ArgList::can_cast(ancestor.kind()) {
577 in_arg_list = true;
578 }
579 if ast::CallExpr::can_cast(ancestor.kind()) {
580 in_call_expr = true;
581 }
582 if ast::FromClause::can_cast(ancestor.kind()) {
583 in_from_clause = true;
584 }
585 if ast::Select::can_cast(ancestor.kind()) {
586 if in_call_expr && !in_arg_list {
588 return false;
589 }
590 if in_from_clause {
592 return false;
593 }
594 return true;
596 }
597 }
598 false
599}
600
601fn is_schema_ref(name_ref: &ast::NameRef) -> bool {
602 for ancestor in name_ref.syntax().ancestors() {
603 if ast::DropSchema::can_cast(ancestor.kind()) {
604 return true;
605 }
606 }
607 false
608}
609
610fn hover_schema(
611 file: &ast::SourceFile,
612 name_ref: &ast::NameRef,
613 binder: &binder::Binder,
614) -> Option<String> {
615 let schema_ptr = resolve::resolve_name_ref(binder, name_ref)?;
616
617 let root = file.syntax();
618 let schema_name_node = schema_ptr.to_node(root);
619
620 let create_schema = ast::CreateSchema::cast(schema_name_node.parent()?)?;
621
622 format_create_schema(&create_schema)
623}
624
625fn format_create_schema(create_schema: &ast::CreateSchema) -> Option<String> {
626 let schema_name = create_schema.name()?.syntax().text().to_string();
627 Some(format!("schema {}", schema_name))
628}
629
630fn hover_function(
631 file: &ast::SourceFile,
632 name_ref: &ast::NameRef,
633 binder: &binder::Binder,
634) -> Option<String> {
635 let function_ptr = resolve::resolve_name_ref(binder, name_ref)?;
636
637 let root = file.syntax();
638 let function_name_node = function_ptr.to_node(root);
639
640 let create_function = function_name_node
641 .ancestors()
642 .find_map(ast::CreateFunction::cast)?;
643
644 format_create_function(&create_function, binder)
645}
646
647fn format_create_function(
648 create_function: &ast::CreateFunction,
649 binder: &binder::Binder,
650) -> Option<String> {
651 let path = create_function.path()?;
652 let segment = path.segment()?;
653 let name = segment.name()?;
654 let function_name = name.syntax().text().to_string();
655
656 let schema = if let Some(qualifier) = path.qualifier() {
657 qualifier.syntax().text().to_string()
658 } else {
659 function_schema(create_function, binder)?
660 };
661
662 let param_list = create_function.param_list()?;
663 let params = param_list.syntax().text().to_string();
664
665 let ret_type = create_function.ret_type()?;
666 let return_type = ret_type.syntax().text().to_string();
667
668 Some(format!(
669 "function {}.{}{} {}",
670 schema, function_name, params, return_type
671 ))
672}
673
674fn function_schema(
675 create_function: &ast::CreateFunction,
676 binder: &binder::Binder,
677) -> Option<String> {
678 let position = create_function.syntax().text_range().start();
679 let search_path = binder.search_path_at(position);
680 search_path.first().map(|s| s.to_string())
681}
682
683fn hover_aggregate(
684 file: &ast::SourceFile,
685 name_ref: &ast::NameRef,
686 binder: &binder::Binder,
687) -> Option<String> {
688 let aggregate_ptr = resolve::resolve_name_ref(binder, name_ref)?;
689
690 let root = file.syntax();
691 let aggregate_name_node = aggregate_ptr.to_node(root);
692
693 let create_aggregate = aggregate_name_node
694 .ancestors()
695 .find_map(ast::CreateAggregate::cast)?;
696
697 format_create_aggregate(&create_aggregate, binder)
698}
699
700fn format_create_aggregate(
701 create_aggregate: &ast::CreateAggregate,
702 binder: &binder::Binder,
703) -> Option<String> {
704 let path = create_aggregate.path()?;
705 let segment = path.segment()?;
706 let name = segment.name()?;
707 let aggregate_name = name.syntax().text().to_string();
708
709 let schema = if let Some(qualifier) = path.qualifier() {
710 qualifier.syntax().text().to_string()
711 } else {
712 aggregate_schema(create_aggregate, binder)?
713 };
714
715 let param_list = create_aggregate.param_list()?;
716 let params = param_list.syntax().text().to_string();
717
718 Some(format!("aggregate {}.{}{}", schema, aggregate_name, params))
719}
720
721fn aggregate_schema(
722 create_aggregate: &ast::CreateAggregate,
723 binder: &binder::Binder,
724) -> Option<String> {
725 let position = create_aggregate.syntax().text_range().start();
726 let search_path = binder.search_path_at(position);
727 search_path.first().map(|s| s.to_string())
728}
729
730fn hover_procedure(
731 file: &ast::SourceFile,
732 name_ref: &ast::NameRef,
733 binder: &binder::Binder,
734) -> Option<String> {
735 let procedure_ptr = resolve::resolve_name_ref(binder, name_ref)?;
736
737 let root = file.syntax();
738 let procedure_name_node = procedure_ptr.to_node(root);
739
740 let create_procedure = procedure_name_node
741 .ancestors()
742 .find_map(ast::CreateProcedure::cast)?;
743
744 format_create_procedure(&create_procedure, binder)
745}
746
747fn format_create_procedure(
748 create_procedure: &ast::CreateProcedure,
749 binder: &binder::Binder,
750) -> Option<String> {
751 let path = create_procedure.path()?;
752 let segment = path.segment()?;
753 let name = segment.name()?;
754 let procedure_name = name.syntax().text().to_string();
755
756 let schema = if let Some(qualifier) = path.qualifier() {
757 qualifier.syntax().text().to_string()
758 } else {
759 procedure_schema(create_procedure, binder)?
760 };
761
762 let param_list = create_procedure.param_list()?;
763 let params = param_list.syntax().text().to_string();
764
765 Some(format!("procedure {}.{}{}", schema, procedure_name, params))
766}
767
768fn procedure_schema(
769 create_procedure: &ast::CreateProcedure,
770 binder: &binder::Binder,
771) -> Option<String> {
772 let position = create_procedure.syntax().text_range().start();
773 let search_path = binder.search_path_at(position);
774 search_path.first().map(|s| s.to_string())
775}
776
777fn hover_routine(
778 file: &ast::SourceFile,
779 name_ref: &ast::NameRef,
780 binder: &binder::Binder,
781) -> Option<String> {
782 let routine_ptr = resolve::resolve_name_ref(binder, name_ref)?;
783
784 let root = file.syntax();
785 let routine_name_node = routine_ptr.to_node(root);
786
787 if let Some(create_function) = routine_name_node
788 .ancestors()
789 .find_map(ast::CreateFunction::cast)
790 {
791 return format_create_function(&create_function, binder);
792 }
793
794 if let Some(create_aggregate) = routine_name_node
795 .ancestors()
796 .find_map(ast::CreateAggregate::cast)
797 {
798 return format_create_aggregate(&create_aggregate, binder);
799 }
800
801 if let Some(create_procedure) = routine_name_node
802 .ancestors()
803 .find_map(ast::CreateProcedure::cast)
804 {
805 return format_create_procedure(&create_procedure, binder);
806 }
807
808 None
809}
810
811#[cfg(test)]
812mod test {
813 use crate::hover::hover;
814 use crate::test_utils::fixture;
815 use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet, renderer::DecorStyle};
816 use insta::assert_snapshot;
817 use squawk_syntax::ast;
818
819 #[track_caller]
820 fn check_hover(sql: &str) -> String {
821 check_hover_(sql).expect("should find hover information")
822 }
823
824 #[track_caller]
825 fn check_hover_(sql: &str) -> Option<String> {
826 let (mut offset, sql) = fixture(sql);
827 offset = offset.checked_sub(1.into()).unwrap_or_default();
828 let parse = ast::SourceFile::parse(&sql);
829 assert_eq!(parse.errors(), vec![]);
830 let file: ast::SourceFile = parse.tree();
831
832 if let Some(type_info) = hover(&file, offset) {
833 let offset_usize: usize = offset.into();
834 let title = format!("hover: {}", type_info);
835 let group = Level::INFO.primary_title(&title).element(
836 Snippet::source(&sql).fold(true).annotation(
837 AnnotationKind::Context
838 .span(offset_usize..offset_usize + 1)
839 .label("hover"),
840 ),
841 );
842 let renderer = Renderer::plain().decor_style(DecorStyle::Unicode);
843 return Some(
844 renderer
845 .render(&[group])
846 .to_string()
847 .replace("info: hover:", "hover:"),
849 );
850 }
851 None
852 }
853
854 #[test]
855 fn hover_column_in_create_index() {
856 assert_snapshot!(check_hover("
857create table users(id int, email text);
858create index idx_email on users(email$0);
859"), @r"
860 hover: column public.users.email text
861 ╭▸
862 3 │ create index idx_email on users(email);
863 ╰╴ ─ hover
864 ");
865 }
866
867 #[test]
868 fn hover_column_int_type() {
869 assert_snapshot!(check_hover("
870create table users(id int, email text);
871create index idx_id on users(id$0);
872"), @r"
873 hover: column public.users.id int
874 ╭▸
875 3 │ create index idx_id on users(id);
876 ╰╴ ─ hover
877 ");
878 }
879
880 #[test]
881 fn hover_column_with_schema() {
882 assert_snapshot!(check_hover("
883create table public.users(id int, email text);
884create index idx_email on public.users(email$0);
885"), @r"
886 hover: column public.users.email text
887 ╭▸
888 3 │ create index idx_email on public.users(email);
889 ╰╴ ─ hover
890 ");
891 }
892
893 #[test]
894 fn hover_column_temp_table() {
895 assert_snapshot!(check_hover("
896create temp table users(id int, email text);
897create index idx_email on users(email$0);
898"), @r"
899 hover: column pg_temp.users.email text
900 ╭▸
901 3 │ create index idx_email on users(email);
902 ╰╴ ─ hover
903 ");
904 }
905
906 #[test]
907 fn hover_column_multiple_columns() {
908 assert_snapshot!(check_hover("
909create table users(id int, email text, name varchar(100));
910create index idx_users on users(id, email$0, name);
911"), @r"
912 hover: column public.users.email text
913 ╭▸
914 3 │ create index idx_users on users(id, email, name);
915 ╰╴ ─ hover
916 ");
917 }
918
919 #[test]
920 fn hover_column_varchar() {
921 assert_snapshot!(check_hover("
922create table users(id int, name varchar(100));
923create index idx_name on users(name$0);
924"), @r"
925 hover: column public.users.name varchar(100)
926 ╭▸
927 3 │ create index idx_name on users(name);
928 ╰╴ ─ hover
929 ");
930 }
931
932 #[test]
933 fn hover_column_bigint() {
934 assert_snapshot!(check_hover("
935create table metrics(value bigint);
936create index idx_value on metrics(value$0);
937"), @r"
938 hover: column public.metrics.value bigint
939 ╭▸
940 3 │ create index idx_value on metrics(value);
941 ╰╴ ─ hover
942 ");
943 }
944
945 #[test]
946 fn hover_column_timestamp() {
947 assert_snapshot!(check_hover("
948create table events(created_at timestamp with time zone);
949create index idx_created on events(created_at$0);
950"), @r"
951 hover: column public.events.created_at timestamp with time zone
952 ╭▸
953 3 │ create index idx_created on events(created_at);
954 ╰╴ ─ hover
955 ");
956 }
957
958 #[test]
959 fn hover_column_with_search_path() {
960 assert_snapshot!(check_hover(r#"
961set search_path to myschema;
962create table myschema.users(id int, email text);
963create index idx_email on users(email$0);
964"#), @r"
965 hover: column myschema.users.email text
966 ╭▸
967 4 │ create index idx_email on users(email);
968 ╰╴ ─ hover
969 ");
970 }
971
972 #[test]
973 fn hover_column_explicit_schema_overrides_search_path() {
974 assert_snapshot!(check_hover(r#"
975set search_path to myschema;
976create table public.users(id int, email text);
977create table myschema.users(value bigint);
978create index idx_email on public.users(email$0);
979"#), @r"
980 hover: column public.users.email text
981 ╭▸
982 5 │ create index idx_email on public.users(email);
983 ╰╴ ─ hover
984 ");
985 }
986
987 #[test]
988 fn hover_on_table_name() {
989 assert_snapshot!(check_hover("
990create table t(id int);
991create index idx on t$0(id);
992"), @r"
993 hover: table public.t(id int)
994 ╭▸
995 3 │ create index idx on t(id);
996 ╰╴ ─ hover
997 ");
998 }
999
1000 #[test]
1001 fn hover_on_index_name_in_create() {
1002 assert_snapshot!(check_hover("
1003create table users(id int);
1004create index idx$0 on users(id);
1005"), @r"
1006 hover: index public.idx on public.users(id)
1007 ╭▸
1008 3 │ create index idx on users(id);
1009 ╰╴ ─ hover
1010 ");
1011 }
1012
1013 #[test]
1014 fn hover_table_in_create_index() {
1015 assert_snapshot!(check_hover("
1016create table users(id int, email text);
1017create index idx_email on users$0(email);
1018"), @r"
1019 hover: table public.users(id int, email text)
1020 ╭▸
1021 3 │ create index idx_email on users(email);
1022 ╰╴ ─ hover
1023 ");
1024 }
1025
1026 #[test]
1027 fn hover_table_with_schema() {
1028 assert_snapshot!(check_hover("
1029create table public.users(id int, email text);
1030create index idx on public.users$0(id);
1031"), @r"
1032 hover: table public.users(id int, email text)
1033 ╭▸
1034 3 │ create index idx on public.users(id);
1035 ╰╴ ─ hover
1036 ");
1037 }
1038
1039 #[test]
1040 fn hover_table_temp() {
1041 assert_snapshot!(check_hover("
1042create temp table users(id int, email text);
1043create index idx on users$0(id);
1044"), @r"
1045 hover: table pg_temp.users(id int, email text)
1046 ╭▸
1047 3 │ create index idx on users(id);
1048 ╰╴ ─ hover
1049 ");
1050 }
1051
1052 #[test]
1053 fn hover_table_multiline() {
1054 assert_snapshot!(check_hover("
1055create table users(
1056 id int,
1057 email text,
1058 name varchar(100)
1059);
1060create index idx on users$0(id);
1061"), @r"
1062 hover: table public.users(
1063 id int,
1064 email text,
1065 name varchar(100)
1066 )
1067 ╭▸
1068 7 │ create index idx on users(id);
1069 ╰╴ ─ hover
1070 ");
1071 }
1072
1073 #[test]
1074 fn hover_table_with_search_path() {
1075 assert_snapshot!(check_hover(r#"
1076set search_path to myschema;
1077create table users(id int, email text);
1078create index idx on users$0(id);
1079"#), @r"
1080 hover: table myschema.users(id int, email text)
1081 ╭▸
1082 4 │ create index idx on users(id);
1083 ╰╴ ─ hover
1084 ");
1085 }
1086
1087 #[test]
1088 fn hover_table_search_path_at_definition() {
1089 assert_snapshot!(check_hover(r#"
1090set search_path to myschema;
1091create table users(id int, email text);
1092set search_path to myschema, otherschema;
1093create index idx on users$0(id);
1094"#), @r"
1095 hover: table myschema.users(id int, email text)
1096 ╭▸
1097 5 │ create index idx on users(id);
1098 ╰╴ ─ hover
1099 ");
1100 }
1101
1102 #[test]
1103 fn hover_on_create_table_definition() {
1104 assert_snapshot!(check_hover("
1105create table t$0(x bigint);
1106"), @r"
1107 hover: table public.t(x bigint)
1108 ╭▸
1109 2 │ create table t(x bigint);
1110 ╰╴ ─ hover
1111 ");
1112 }
1113
1114 #[test]
1115 fn hover_on_create_table_definition_with_schema() {
1116 assert_snapshot!(check_hover("
1117create table myschema.users$0(id int);
1118"), @r"
1119 hover: table myschema.users(id int)
1120 ╭▸
1121 2 │ create table myschema.users(id int);
1122 ╰╴ ─ hover
1123 ");
1124 }
1125
1126 #[test]
1127 fn hover_on_create_temp_table_definition() {
1128 assert_snapshot!(check_hover("
1129create temp table t$0(x bigint);
1130"), @r"
1131 hover: table pg_temp.t(x bigint)
1132 ╭▸
1133 2 │ create temp table t(x bigint);
1134 ╰╴ ─ hover
1135 ");
1136 }
1137
1138 #[test]
1139 fn hover_on_column_in_create_table() {
1140 assert_snapshot!(check_hover("
1141create table t(id$0 int);
1142"), @r"
1143 hover: column public.t.id int
1144 ╭▸
1145 2 │ create table t(id int);
1146 ╰╴ ─ hover
1147 ");
1148 }
1149
1150 #[test]
1151 fn hover_on_column_in_create_table_with_schema() {
1152 assert_snapshot!(check_hover("
1153create table myschema.users(id$0 int, name text);
1154"), @r"
1155 hover: column myschema.users.id int
1156 ╭▸
1157 2 │ create table myschema.users(id int, name text);
1158 ╰╴ ─ hover
1159 ");
1160 }
1161
1162 #[test]
1163 fn hover_on_column_in_temp_table() {
1164 assert_snapshot!(check_hover("
1165create temp table t(x$0 bigint);
1166"), @r"
1167 hover: column pg_temp.t.x bigint
1168 ╭▸
1169 2 │ create temp table t(x bigint);
1170 ╰╴ ─ hover
1171 ");
1172 }
1173
1174 #[test]
1175 fn hover_on_multiple_columns() {
1176 assert_snapshot!(check_hover("
1177create table t(id int, email$0 text, name varchar(100));
1178"), @r"
1179 hover: column public.t.email text
1180 ╭▸
1181 2 │ create table t(id int, email text, name varchar(100));
1182 ╰╴ ─ hover
1183 ");
1184 }
1185
1186 #[test]
1187 fn hover_on_drop_table() {
1188 assert_snapshot!(check_hover("
1189create table users(id int, email text);
1190drop table users$0;
1191"), @r"
1192 hover: table public.users(id int, email text)
1193 ╭▸
1194 3 │ drop table users;
1195 ╰╴ ─ hover
1196 ");
1197 }
1198
1199 #[test]
1200 fn hover_on_drop_table_with_schema() {
1201 assert_snapshot!(check_hover("
1202create table myschema.users(id int);
1203drop table myschema.users$0;
1204"), @r"
1205 hover: table myschema.users(id int)
1206 ╭▸
1207 3 │ drop table myschema.users;
1208 ╰╴ ─ hover
1209 ");
1210 }
1211
1212 #[test]
1213 fn hover_on_drop_temp_table() {
1214 assert_snapshot!(check_hover("
1215create temp table t(x bigint);
1216drop table t$0;
1217"), @r"
1218 hover: table pg_temp.t(x bigint)
1219 ╭▸
1220 3 │ drop table t;
1221 ╰╴ ─ hover
1222 ");
1223 }
1224
1225 #[test]
1226 fn hover_on_create_index_definition() {
1227 assert_snapshot!(check_hover("
1228create table t(x bigint);
1229create index idx$0 on t(x);
1230"), @r"
1231 hover: index public.idx on public.t(x)
1232 ╭▸
1233 3 │ create index idx on t(x);
1234 ╰╴ ─ hover
1235 ");
1236 }
1237
1238 #[test]
1239 fn hover_on_drop_index() {
1240 assert_snapshot!(check_hover("
1241create table t(x bigint);
1242create index idx_x on t(x);
1243drop index idx_x$0;
1244"), @r"
1245 hover: index public.idx_x on public.t(x)
1246 ╭▸
1247 4 │ drop index idx_x;
1248 ╰╴ ─ hover
1249 ");
1250 }
1251
1252 #[test]
1253 fn hover_on_create_type_definition() {
1254 assert_snapshot!(check_hover("
1255create type status$0 as enum ('active', 'inactive');
1256"), @r"
1257 hover: type public.status as enum ('active', 'inactive')
1258 ╭▸
1259 2 │ create type status as enum ('active', 'inactive');
1260 ╰╴ ─ hover
1261 ");
1262 }
1263
1264 #[test]
1265 fn hover_on_create_type_definition_with_schema() {
1266 assert_snapshot!(check_hover("
1267create type myschema.status$0 as enum ('active', 'inactive');
1268"), @r"
1269 hover: type myschema.status as enum ('active', 'inactive')
1270 ╭▸
1271 2 │ create type myschema.status as enum ('active', 'inactive');
1272 ╰╴ ─ hover
1273 ");
1274 }
1275
1276 #[test]
1277 fn hover_on_drop_type() {
1278 assert_snapshot!(check_hover("
1279create type status as enum ('active', 'inactive');
1280drop type status$0;
1281"), @r"
1282 hover: type public.status as enum ('active', 'inactive')
1283 ╭▸
1284 3 │ drop type status;
1285 ╰╴ ─ hover
1286 ");
1287 }
1288
1289 #[test]
1290 fn hover_on_drop_type_with_schema() {
1291 assert_snapshot!(check_hover("
1292create type myschema.status as enum ('active', 'inactive');
1293drop type myschema.status$0;
1294"), @r"
1295 hover: type myschema.status as enum ('active', 'inactive')
1296 ╭▸
1297 3 │ drop type myschema.status;
1298 ╰╴ ─ hover
1299 ");
1300 }
1301
1302 #[test]
1303 fn hover_on_create_type_composite() {
1304 assert_snapshot!(check_hover("
1305create type person$0 as (name text, age int);
1306"), @r"
1307 hover: type public.person as (name text, age int)
1308 ╭▸
1309 2 │ create type person as (name text, age int);
1310 ╰╴ ─ hover
1311 ");
1312 }
1313
1314 #[test]
1315 fn hover_on_drop_type_composite() {
1316 assert_snapshot!(check_hover("
1317create type person as (name text, age int);
1318drop type person$0;
1319"), @r"
1320 hover: type public.person as (name text, age int)
1321 ╭▸
1322 3 │ drop type person;
1323 ╰╴ ─ hover
1324 ");
1325 }
1326
1327 #[test]
1328 fn hover_on_create_type_range() {
1329 assert_snapshot!(check_hover("
1330create type int4_range$0 as range (subtype = int4);
1331"), @r"
1332 hover: type public.int4_range (subtype = int4)
1333 ╭▸
1334 2 │ create type int4_range as range (subtype = int4);
1335 ╰╴ ─ hover
1336 ");
1337 }
1338
1339 #[test]
1340 fn hover_on_drop_type_range() {
1341 assert_snapshot!(check_hover("
1342create type int4_range as range (subtype = int4);
1343drop type int4_range$0;
1344"), @r"
1345 hover: type public.int4_range (subtype = int4)
1346 ╭▸
1347 3 │ drop type int4_range;
1348 ╰╴ ─ hover
1349 ");
1350 }
1351
1352 #[test]
1353 fn hover_on_cast_operator() {
1354 assert_snapshot!(check_hover("
1355create type foo as enum ('a', 'b');
1356select x::foo$0;
1357"), @r"
1358 hover: type public.foo as enum ('a', 'b')
1359 ╭▸
1360 3 │ select x::foo;
1361 ╰╴ ─ hover
1362 ");
1363 }
1364
1365 #[test]
1366 fn hover_on_cast_function() {
1367 assert_snapshot!(check_hover("
1368create type bar as enum ('x', 'y');
1369select cast(x as bar$0);
1370"), @r"
1371 hover: type public.bar as enum ('x', 'y')
1372 ╭▸
1373 3 │ select cast(x as bar);
1374 ╰╴ ─ hover
1375 ");
1376 }
1377
1378 #[test]
1379 fn hover_on_cast_with_schema() {
1380 assert_snapshot!(check_hover("
1381create type myschema.baz as enum ('m', 'n');
1382select x::myschema.baz$0;
1383"), @r"
1384 hover: type myschema.baz as enum ('m', 'n')
1385 ╭▸
1386 3 │ select x::myschema.baz;
1387 ╰╴ ─ hover
1388 ");
1389 }
1390
1391 #[test]
1392 fn hover_on_drop_function() {
1393 assert_snapshot!(check_hover("
1394create function foo() returns int as $$ select 1 $$ language sql;
1395drop function foo$0();
1396"), @r"
1397 hover: function public.foo() returns int
1398 ╭▸
1399 3 │ drop function foo();
1400 ╰╴ ─ hover
1401 ");
1402 }
1403
1404 #[test]
1405 fn hover_on_drop_function_with_schema() {
1406 assert_snapshot!(check_hover("
1407create function myschema.foo() returns int as $$ select 1 $$ language sql;
1408drop function myschema.foo$0();
1409"), @r"
1410 hover: function myschema.foo() returns int
1411 ╭▸
1412 3 │ drop function myschema.foo();
1413 ╰╴ ─ hover
1414 ");
1415 }
1416
1417 #[test]
1418 fn hover_on_create_function_definition() {
1419 assert_snapshot!(check_hover("
1420create function foo$0() returns int as $$ select 1 $$ language sql;
1421"), @r"
1422 hover: function public.foo() returns int
1423 ╭▸
1424 2 │ create function foo() returns int as $$ select 1 $$ language sql;
1425 ╰╴ ─ hover
1426 ");
1427 }
1428
1429 #[test]
1430 fn hover_on_create_function_with_explicit_schema() {
1431 assert_snapshot!(check_hover("
1432create function myschema.foo$0() returns int as $$ select 1 $$ language sql;
1433"), @r"
1434 hover: function myschema.foo() returns int
1435 ╭▸
1436 2 │ create function myschema.foo() returns int as $$ select 1 $$ language sql;
1437 ╰╴ ─ hover
1438 ");
1439 }
1440
1441 #[test]
1442 fn hover_on_drop_function_with_search_path() {
1443 assert_snapshot!(check_hover(r#"
1444set search_path to myschema;
1445create function foo() returns int as $$ select 1 $$ language sql;
1446drop function foo$0();
1447"#), @r"
1448 hover: function myschema.foo() returns int
1449 ╭▸
1450 4 │ drop function foo();
1451 ╰╴ ─ hover
1452 ");
1453 }
1454
1455 #[test]
1456 fn hover_on_drop_function_overloaded() {
1457 assert_snapshot!(check_hover("
1458create function add(complex) returns complex as $$ select null $$ language sql;
1459create function add(bigint) returns bigint as $$ select 1 $$ language sql;
1460drop function add$0(complex);
1461"), @r"
1462 hover: function public.add(complex) returns complex
1463 ╭▸
1464 4 │ drop function add(complex);
1465 ╰╴ ─ hover
1466 ");
1467 }
1468
1469 #[test]
1470 fn hover_on_drop_function_second_overload() {
1471 assert_snapshot!(check_hover("
1472create function add(complex) returns complex as $$ select null $$ language sql;
1473create function add(bigint) returns bigint as $$ select 1 $$ language sql;
1474drop function add$0(bigint);
1475"), @r"
1476 hover: function public.add(bigint) returns bigint
1477 ╭▸
1478 4 │ drop function add(bigint);
1479 ╰╴ ─ hover
1480 ");
1481 }
1482
1483 #[test]
1484 fn hover_on_drop_aggregate() {
1485 assert_snapshot!(check_hover("
1486create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
1487drop aggregate myavg$0(int);
1488"), @r"
1489 hover: aggregate public.myavg(int)
1490 ╭▸
1491 3 │ drop aggregate myavg(int);
1492 ╰╴ ─ hover
1493 ");
1494 }
1495
1496 #[test]
1497 fn hover_on_drop_aggregate_with_schema() {
1498 assert_snapshot!(check_hover("
1499create aggregate myschema.myavg(int) (sfunc = int4_avg_accum, stype = _int8);
1500drop aggregate myschema.myavg$0(int);
1501"), @r"
1502 hover: aggregate myschema.myavg(int)
1503 ╭▸
1504 3 │ drop aggregate myschema.myavg(int);
1505 ╰╴ ─ hover
1506 ");
1507 }
1508
1509 #[test]
1510 fn hover_on_create_aggregate_definition() {
1511 assert_snapshot!(check_hover("
1512create aggregate myavg$0(int) (sfunc = int4_avg_accum, stype = _int8);
1513"), @r"
1514 hover: aggregate public.myavg(int)
1515 ╭▸
1516 2 │ create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
1517 ╰╴ ─ hover
1518 ");
1519 }
1520
1521 #[test]
1522 fn hover_on_drop_aggregate_with_search_path() {
1523 assert_snapshot!(check_hover(r#"
1524set search_path to myschema;
1525create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
1526drop aggregate myavg$0(int);
1527"#), @r"
1528 hover: aggregate myschema.myavg(int)
1529 ╭▸
1530 4 │ drop aggregate myavg(int);
1531 ╰╴ ─ hover
1532 ");
1533 }
1534
1535 #[test]
1536 fn hover_on_drop_aggregate_overloaded() {
1537 assert_snapshot!(check_hover("
1538create aggregate sum(complex) (sfunc = complex_add, stype = complex, initcond = '(0,0)');
1539create aggregate sum(bigint) (sfunc = bigint_add, stype = bigint, initcond = '0');
1540drop aggregate sum$0(complex);
1541"), @r"
1542 hover: aggregate public.sum(complex)
1543 ╭▸
1544 4 │ drop aggregate sum(complex);
1545 ╰╴ ─ hover
1546 ");
1547 }
1548
1549 #[test]
1550 fn hover_on_drop_aggregate_second_overload() {
1551 assert_snapshot!(check_hover("
1552create aggregate sum(complex) (sfunc = complex_add, stype = complex, initcond = '(0,0)');
1553create aggregate sum(bigint) (sfunc = bigint_add, stype = bigint, initcond = '0');
1554drop aggregate sum$0(bigint);
1555"), @r"
1556 hover: aggregate public.sum(bigint)
1557 ╭▸
1558 4 │ drop aggregate sum(bigint);
1559 ╰╴ ─ hover
1560 ");
1561 }
1562
1563 #[test]
1564 fn hover_on_select_function_call() {
1565 assert_snapshot!(check_hover("
1566create function foo() returns int as $$ select 1 $$ language sql;
1567select foo$0();
1568"), @r"
1569 hover: function public.foo() returns int
1570 ╭▸
1571 3 │ select foo();
1572 ╰╴ ─ hover
1573 ");
1574 }
1575
1576 #[test]
1577 fn hover_on_select_function_call_with_schema() {
1578 assert_snapshot!(check_hover("
1579create function public.foo() returns int as $$ select 1 $$ language sql;
1580select public.foo$0();
1581"), @r"
1582 hover: function public.foo() returns int
1583 ╭▸
1584 3 │ select public.foo();
1585 ╰╴ ─ hover
1586 ");
1587 }
1588
1589 #[test]
1590 fn hover_on_select_function_call_with_search_path() {
1591 assert_snapshot!(check_hover(r#"
1592set search_path to myschema;
1593create function foo() returns int as $$ select 1 $$ language sql;
1594select foo$0();
1595"#), @r"
1596 hover: function myschema.foo() returns int
1597 ╭▸
1598 4 │ select foo();
1599 ╰╴ ─ hover
1600 ");
1601 }
1602
1603 #[test]
1604 fn hover_on_select_function_call_with_params() {
1605 assert_snapshot!(check_hover("
1606create function add(a int, b int) returns int as $$ select a + b $$ language sql;
1607select add$0(1, 2);
1608"), @r"
1609 hover: function public.add(a int, b int) returns int
1610 ╭▸
1611 3 │ select add(1, 2);
1612 ╰╴ ─ hover
1613 ");
1614 }
1615
1616 #[test]
1617 fn hover_on_function_call_style_column_access() {
1618 assert_snapshot!(check_hover("
1619create table t(a int, b int);
1620select a$0(t) from t;
1621"), @r"
1622 hover: column public.t.a int
1623 ╭▸
1624 3 │ select a(t) from t;
1625 ╰╴ ─ hover
1626 ");
1627 }
1628
1629 #[test]
1630 fn hover_on_function_call_style_column_access_with_function_precedence() {
1631 assert_snapshot!(check_hover("
1632create table t(a int, b int);
1633create function b(t) returns int as 'select 1' LANGUAGE sql;
1634select b$0(t) from t;
1635"), @r"
1636 hover: function public.b(t) returns int
1637 ╭▸
1638 4 │ select b(t) from t;
1639 ╰╴ ─ hover
1640 ");
1641 }
1642
1643 #[test]
1644 fn hover_on_function_call_style_table_arg() {
1645 assert_snapshot!(check_hover("
1646create table t(a int, b int);
1647select a(t$0) from t;
1648"), @r"
1649 hover: table public.t(a int, b int)
1650 ╭▸
1651 3 │ select a(t) from t;
1652 ╰╴ ─ hover
1653 ");
1654 }
1655
1656 #[test]
1657 fn hover_on_function_call_style_table_arg_with_function() {
1658 assert_snapshot!(check_hover("
1659create table t(a int, b int);
1660create function b(t) returns int as 'select 1' LANGUAGE sql;
1661select b(t$0) from t;
1662"), @r"
1663 hover: table public.t(a int, b int)
1664 ╭▸
1665 4 │ select b(t) from t;
1666 ╰╴ ─ hover
1667 ");
1668 }
1669
1670 #[test]
1671 fn hover_on_function_call_style_table_arg_in_where() {
1672 assert_snapshot!(check_hover("
1673create table t(a int);
1674select * from t where a(t$0) > 2;
1675"), @r"
1676 hover: table public.t(a int)
1677 ╭▸
1678 3 │ select * from t where a(t) > 2;
1679 ╰╴ ─ hover
1680 ");
1681 }
1682
1683 #[test]
1684 fn hover_on_qualified_table_ref_in_where() {
1685 assert_snapshot!(check_hover("
1686create table t(a int);
1687create function b(t) returns int as 'select 1' language sql;
1688select * from t where t$0.b > 2;
1689"), @r"
1690 hover: table public.t(a int)
1691 ╭▸
1692 4 │ select * from t where t.b > 2;
1693 ╰╴ ─ hover
1694 ");
1695 }
1696
1697 #[test]
1698 fn hover_on_field_style_function_call() {
1699 assert_snapshot!(check_hover("
1700create table t(a int);
1701create function b(t) returns int as 'select 1' language sql;
1702select t.b$0 from t;
1703"), @r"
1704 hover: function public.b(t) returns int
1705 ╭▸
1706 4 │ select t.b from t;
1707 ╰╴ ─ hover
1708 ");
1709 }
1710
1711 #[test]
1712 fn hover_on_field_style_function_call_column_precedence() {
1713 assert_snapshot!(check_hover("
1714create table t(a int, b int);
1715create function b(t) returns int as 'select 1' language sql;
1716select t.b$0 from t;
1717"), @r"
1718 hover: column public.t.b int
1719 ╭▸
1720 4 │ select t.b from t;
1721 ╰╴ ─ hover
1722 ");
1723 }
1724
1725 #[test]
1726 fn hover_on_field_style_function_call_table_ref() {
1727 assert_snapshot!(check_hover("
1728create table t(a int);
1729create function b(t) returns int as 'select 1' language sql;
1730select t$0.b from t;
1731"), @r"
1732 hover: table public.t(a int)
1733 ╭▸
1734 4 │ select t.b from t;
1735 ╰╴ ─ hover
1736 ");
1737 }
1738
1739 #[test]
1740 fn hover_on_select_from_table() {
1741 assert_snapshot!(check_hover("
1742create table users(id int, email text);
1743select * from users$0;
1744"), @r"
1745 hover: table public.users(id int, email text)
1746 ╭▸
1747 3 │ select * from users;
1748 ╰╴ ─ hover
1749 ");
1750 }
1751
1752 #[test]
1753 fn hover_on_select_from_table_with_schema() {
1754 assert_snapshot!(check_hover("
1755create table public.users(id int, email text);
1756select * from public.users$0;
1757"), @r"
1758 hover: table public.users(id int, email text)
1759 ╭▸
1760 3 │ select * from public.users;
1761 ╰╴ ─ hover
1762 ");
1763 }
1764
1765 #[test]
1766 fn hover_on_select_from_table_with_search_path() {
1767 assert_snapshot!(check_hover("
1768set search_path to foo;
1769create table foo.users(id int, email text);
1770select * from users$0;
1771"), @r"
1772 hover: table foo.users(id int, email text)
1773 ╭▸
1774 4 │ select * from users;
1775 ╰╴ ─ hover
1776 ");
1777 }
1778
1779 #[test]
1780 fn hover_on_select_from_temp_table() {
1781 assert_snapshot!(check_hover("
1782create temp table users(id int, email text);
1783select * from users$0;
1784"), @r"
1785 hover: table pg_temp.users(id int, email text)
1786 ╭▸
1787 3 │ select * from users;
1788 ╰╴ ─ hover
1789 ");
1790 }
1791
1792 #[test]
1793 fn hover_on_select_from_multiline_table() {
1794 assert_snapshot!(check_hover("
1795create table users(
1796 id int,
1797 email text,
1798 name varchar(100)
1799);
1800select * from users$0;
1801"), @r"
1802 hover: table public.users(
1803 id int,
1804 email text,
1805 name varchar(100)
1806 )
1807 ╭▸
1808 7 │ select * from users;
1809 ╰╴ ─ hover
1810 ");
1811 }
1812
1813 #[test]
1814 fn hover_on_select_column() {
1815 assert_snapshot!(check_hover("
1816create table users(id int, email text);
1817select id$0 from users;
1818"), @r"
1819 hover: column public.users.id int
1820 ╭▸
1821 3 │ select id from users;
1822 ╰╴ ─ hover
1823 ");
1824 }
1825
1826 #[test]
1827 fn hover_on_select_column_second() {
1828 assert_snapshot!(check_hover("
1829create table users(id int, email text);
1830select id, email$0 from users;
1831"), @r"
1832 hover: column public.users.email text
1833 ╭▸
1834 3 │ select id, email from users;
1835 ╰╴ ─ hover
1836 ");
1837 }
1838
1839 #[test]
1840 fn hover_on_select_column_with_schema() {
1841 assert_snapshot!(check_hover("
1842create table public.users(id int, email text);
1843select email$0 from public.users;
1844"), @r"
1845 hover: column public.users.email text
1846 ╭▸
1847 3 │ select email from public.users;
1848 ╰╴ ─ hover
1849 ");
1850 }
1851
1852 #[test]
1853 fn hover_on_select_column_with_search_path() {
1854 assert_snapshot!(check_hover("
1855set search_path to foo;
1856create table foo.users(id int, email text);
1857select id$0 from users;
1858"), @r"
1859 hover: column foo.users.id int
1860 ╭▸
1861 4 │ select id from users;
1862 ╰╴ ─ hover
1863 ");
1864 }
1865
1866 #[test]
1867 fn hover_on_insert_table() {
1868 assert_snapshot!(check_hover("
1869create table users(id int, email text);
1870insert into users$0(id, email) values (1, 'test');
1871"), @r"
1872 hover: table public.users(id int, email text)
1873 ╭▸
1874 3 │ insert into users(id, email) values (1, 'test');
1875 ╰╴ ─ hover
1876 ");
1877 }
1878
1879 #[test]
1880 fn hover_on_insert_table_with_schema() {
1881 assert_snapshot!(check_hover("
1882create table public.users(id int, email text);
1883insert into public.users$0(id, email) values (1, 'test');
1884"), @r"
1885 hover: table public.users(id int, email text)
1886 ╭▸
1887 3 │ insert into public.users(id, email) values (1, 'test');
1888 ╰╴ ─ hover
1889 ");
1890 }
1891
1892 #[test]
1893 fn hover_on_insert_column() {
1894 assert_snapshot!(check_hover("
1895create table users(id int, email text);
1896insert into users(id$0, email) values (1, 'test');
1897"), @r"
1898 hover: column public.users.id int
1899 ╭▸
1900 3 │ insert into users(id, email) values (1, 'test');
1901 ╰╴ ─ hover
1902 ");
1903 }
1904
1905 #[test]
1906 fn hover_on_insert_column_second() {
1907 assert_snapshot!(check_hover("
1908create table users(id int, email text);
1909insert into users(id, email$0) values (1, 'test');
1910"), @r"
1911 hover: column public.users.email text
1912 ╭▸
1913 3 │ insert into users(id, email) values (1, 'test');
1914 ╰╴ ─ hover
1915 ");
1916 }
1917
1918 #[test]
1919 fn hover_on_insert_column_with_schema() {
1920 assert_snapshot!(check_hover("
1921create table public.users(id int, email text);
1922insert into public.users(email$0) values ('test');
1923"), @r"
1924 hover: column public.users.email text
1925 ╭▸
1926 3 │ insert into public.users(email) values ('test');
1927 ╰╴ ─ hover
1928 ");
1929 }
1930
1931 #[test]
1932 fn hover_on_delete_table() {
1933 assert_snapshot!(check_hover("
1934create table users(id int, email text);
1935delete from users$0 where id = 1;
1936"), @r"
1937 hover: table public.users(id int, email text)
1938 ╭▸
1939 3 │ delete from users where id = 1;
1940 ╰╴ ─ hover
1941 ");
1942 }
1943
1944 #[test]
1945 fn hover_on_delete_table_with_schema() {
1946 assert_snapshot!(check_hover("
1947create table public.users(id int, email text);
1948delete from public.users$0 where id = 1;
1949"), @r"
1950 hover: table public.users(id int, email text)
1951 ╭▸
1952 3 │ delete from public.users where id = 1;
1953 ╰╴ ─ hover
1954 ");
1955 }
1956
1957 #[test]
1958 fn hover_on_delete_where_column() {
1959 assert_snapshot!(check_hover("
1960create table users(id int, email text);
1961delete from users where id$0 = 1;
1962"), @r"
1963 hover: column public.users.id int
1964 ╭▸
1965 3 │ delete from users where id = 1;
1966 ╰╴ ─ hover
1967 ");
1968 }
1969
1970 #[test]
1971 fn hover_on_delete_where_column_second() {
1972 assert_snapshot!(check_hover("
1973create table users(id int, email text, active boolean);
1974delete from users where id = 1 and email$0 = 'test';
1975"), @r"
1976 hover: column public.users.email text
1977 ╭▸
1978 3 │ delete from users where id = 1 and email = 'test';
1979 ╰╴ ─ hover
1980 ");
1981 }
1982
1983 #[test]
1984 fn hover_on_delete_where_column_with_schema() {
1985 assert_snapshot!(check_hover("
1986create table public.users(id int, email text);
1987delete from public.users where email$0 = 'test';
1988"), @r"
1989 hover: column public.users.email text
1990 ╭▸
1991 3 │ delete from public.users where email = 'test';
1992 ╰╴ ─ hover
1993 ");
1994 }
1995
1996 #[test]
1997 fn hover_on_select_table_as_column() {
1998 assert_snapshot!(check_hover("
1999create table t(x bigint, y bigint);
2000select t$0 from t;
2001"), @r"
2002 hover: table public.t(x bigint, y bigint)
2003 ╭▸
2004 3 │ select t from t;
2005 ╰╴ ─ hover
2006 ");
2007 }
2008
2009 #[test]
2010 fn hover_on_select_table_as_column_with_schema() {
2011 assert_snapshot!(check_hover("
2012create table public.t(x bigint, y bigint);
2013select t$0 from public.t;
2014"), @r"
2015 hover: table public.t(x bigint, y bigint)
2016 ╭▸
2017 3 │ select t from public.t;
2018 ╰╴ ─ hover
2019 ");
2020 }
2021
2022 #[test]
2023 fn hover_on_select_table_as_column_with_search_path() {
2024 assert_snapshot!(check_hover("
2025set search_path to foo;
2026create table foo.users(id int, email text);
2027select users$0 from users;
2028"), @r"
2029 hover: table foo.users(id int, email text)
2030 ╭▸
2031 4 │ select users from users;
2032 ╰╴ ─ hover
2033 ");
2034 }
2035
2036 #[test]
2037 fn hover_on_select_column_with_same_name_as_table() {
2038 assert_snapshot!(check_hover("
2039create table t(t int);
2040select t$0 from t;
2041"), @r"
2042 hover: column public.t.t int
2043 ╭▸
2044 3 │ select t from t;
2045 ╰╴ ─ hover
2046 ");
2047 }
2048
2049 #[test]
2050 fn hover_on_create_schema() {
2051 assert_snapshot!(check_hover("
2052create schema foo$0;
2053"), @r"
2054 hover: schema foo
2055 ╭▸
2056 2 │ create schema foo;
2057 ╰╴ ─ hover
2058 ");
2059 }
2060
2061 #[test]
2062 fn hover_on_drop_schema() {
2063 assert_snapshot!(check_hover("
2064create schema foo;
2065drop schema foo$0;
2066"), @r"
2067 hover: schema foo
2068 ╭▸
2069 3 │ drop schema foo;
2070 ╰╴ ─ hover
2071 ");
2072 }
2073
2074 #[test]
2075 fn hover_on_schema_after_definition() {
2076 assert_snapshot!(check_hover("
2077drop schema foo$0;
2078create schema foo;
2079"), @r"
2080 hover: schema foo
2081 ╭▸
2082 2 │ drop schema foo;
2083 ╰╴ ─ hover
2084 ");
2085 }
2086
2087 #[test]
2088 fn hover_on_cte_table() {
2089 assert_snapshot!(check_hover("
2090with t as (select 1 a)
2091select a from t$0;
2092"), @r"
2093 hover: with t as (select 1 a)
2094 ╭▸
2095 3 │ select a from t;
2096 ╰╴ ─ hover
2097 ");
2098 }
2099
2100 #[test]
2101 fn hover_on_cte_column() {
2102 assert_snapshot!(check_hover("
2103with t as (select 1 a)
2104select a$0 from t;
2105"), @r"
2106 hover: column t.a
2107 ╭▸
2108 3 │ select a from t;
2109 ╰╴ ─ hover
2110 ");
2111 }
2112
2113 #[test]
2114 fn hover_on_cte_with_multiple_columns() {
2115 assert_snapshot!(check_hover("
2116with t as (select 1 a, 2 b)
2117select b$0 from t;
2118"), @r"
2119 hover: column t.b
2120 ╭▸
2121 3 │ select b from t;
2122 ╰╴ ─ hover
2123 ");
2124 }
2125
2126 #[test]
2127 fn hover_on_cte_with_column_list() {
2128 assert_snapshot!(check_hover("
2129with t(a) as (select 1)
2130select a$0 from t;
2131"), @r"
2132 hover: column t.a
2133 ╭▸
2134 3 │ select a from t;
2135 ╰╴ ─ hover
2136 ");
2137 }
2138
2139 #[test]
2140 fn hover_on_nested_cte() {
2141 assert_snapshot!(check_hover("
2142with x as (select 1 a),
2143 y as (select a from x)
2144select a$0 from y;
2145"), @r"
2146 hover: column y.a
2147 ╭▸
2148 4 │ select a from y;
2149 ╰╴ ─ hover
2150 ");
2151 }
2152
2153 #[test]
2154 fn hover_on_cte_shadowing_table_with_star() {
2155 assert_snapshot!(check_hover("
2156create table t(a bigint);
2157with t as (select * from t)
2158select a$0 from t;
2159"), @r"
2160 hover: column public.t.a bigint
2161 ╭▸
2162 4 │ select a from t;
2163 ╰╴ ─ hover
2164 ");
2165 }
2166
2167 #[test]
2168 fn hover_on_cte_definition() {
2169 assert_snapshot!(check_hover("
2170with t$0 as (select 1 a)
2171select a from t;
2172"), @r"
2173 hover: with t as (select 1 a)
2174 ╭▸
2175 2 │ with t as (select 1 a)
2176 ╰╴ ─ hover
2177 ");
2178 }
2179
2180 #[test]
2181 fn hover_on_cte_values_column1() {
2182 assert_snapshot!(check_hover("
2183with t as (
2184 values (1, 2), (3, 4)
2185)
2186select column1$0, column2 from t;
2187"), @r"
2188 hover: column t.column1
2189 ╭▸
2190 5 │ select column1, column2 from t;
2191 ╰╴ ─ hover
2192 ");
2193 }
2194
2195 #[test]
2196 fn hover_on_cte_values_column2() {
2197 assert_snapshot!(check_hover("
2198with t as (
2199 values (1, 2), (3, 4)
2200)
2201select column1, column2$0 from t;
2202"), @r"
2203 hover: column t.column2
2204 ╭▸
2205 5 │ select column1, column2 from t;
2206 ╰╴ ─ hover
2207 ");
2208 }
2209
2210 #[test]
2211 fn hover_on_cte_values_single_column() {
2212 assert_snapshot!(check_hover("
2213with t as (
2214 values (1), (2), (3)
2215)
2216select column1$0 from t;
2217"), @r"
2218 hover: column t.column1
2219 ╭▸
2220 5 │ select column1 from t;
2221 ╰╴ ─ hover
2222 ");
2223 }
2224
2225 #[test]
2226 fn hover_on_cte_values_uppercase_column_names() {
2227 assert_snapshot!(check_hover("
2228with t as (
2229 values (1, 2), (3, 4)
2230)
2231select COLUMN1$0, COLUMN2 from t;
2232"), @r"
2233 hover: column t.column1
2234 ╭▸
2235 5 │ select COLUMN1, COLUMN2 from t;
2236 ╰╴ ─ hover
2237 ");
2238 }
2239
2240 #[test]
2241 fn hover_on_drop_procedure() {
2242 assert_snapshot!(check_hover("
2243create procedure foo() language sql as $$ select 1 $$;
2244drop procedure foo$0();
2245"), @r"
2246 hover: procedure public.foo()
2247 ╭▸
2248 3 │ drop procedure foo();
2249 ╰╴ ─ hover
2250 ");
2251 }
2252
2253 #[test]
2254 fn hover_on_drop_procedure_with_schema() {
2255 assert_snapshot!(check_hover("
2256create procedure myschema.foo() language sql as $$ select 1 $$;
2257drop procedure myschema.foo$0();
2258"), @r"
2259 hover: procedure myschema.foo()
2260 ╭▸
2261 3 │ drop procedure myschema.foo();
2262 ╰╴ ─ hover
2263 ");
2264 }
2265
2266 #[test]
2267 fn hover_on_create_procedure_definition() {
2268 assert_snapshot!(check_hover("
2269create procedure foo$0() language sql as $$ select 1 $$;
2270"), @r"
2271 hover: procedure public.foo()
2272 ╭▸
2273 2 │ create procedure foo() language sql as $$ select 1 $$;
2274 ╰╴ ─ hover
2275 ");
2276 }
2277
2278 #[test]
2279 fn hover_on_create_procedure_with_explicit_schema() {
2280 assert_snapshot!(check_hover("
2281create procedure myschema.foo$0() language sql as $$ select 1 $$;
2282"), @r"
2283 hover: procedure myschema.foo()
2284 ╭▸
2285 2 │ create procedure myschema.foo() language sql as $$ select 1 $$;
2286 ╰╴ ─ hover
2287 ");
2288 }
2289
2290 #[test]
2291 fn hover_on_drop_procedure_with_search_path() {
2292 assert_snapshot!(check_hover(r#"
2293set search_path to myschema;
2294create procedure foo() language sql as $$ select 1 $$;
2295drop procedure foo$0();
2296"#), @r"
2297 hover: procedure myschema.foo()
2298 ╭▸
2299 4 │ drop procedure foo();
2300 ╰╴ ─ hover
2301 ");
2302 }
2303
2304 #[test]
2305 fn hover_on_drop_procedure_overloaded() {
2306 assert_snapshot!(check_hover("
2307create procedure add(complex) language sql as $$ select null $$;
2308create procedure add(bigint) language sql as $$ select 1 $$;
2309drop procedure add$0(complex);
2310"), @r"
2311 hover: procedure public.add(complex)
2312 ╭▸
2313 4 │ drop procedure add(complex);
2314 ╰╴ ─ hover
2315 ");
2316 }
2317
2318 #[test]
2319 fn hover_on_drop_procedure_second_overload() {
2320 assert_snapshot!(check_hover("
2321create procedure add(complex) language sql as $$ select null $$;
2322create procedure add(bigint) language sql as $$ select 1 $$;
2323drop procedure add$0(bigint);
2324"), @r"
2325 hover: procedure public.add(bigint)
2326 ╭▸
2327 4 │ drop procedure add(bigint);
2328 ╰╴ ─ hover
2329 ");
2330 }
2331
2332 #[test]
2333 fn hover_on_call_procedure() {
2334 assert_snapshot!(check_hover("
2335create procedure foo() language sql as $$ select 1 $$;
2336call foo$0();
2337"), @r"
2338 hover: procedure public.foo()
2339 ╭▸
2340 3 │ call foo();
2341 ╰╴ ─ hover
2342 ");
2343 }
2344
2345 #[test]
2346 fn hover_on_call_procedure_with_schema() {
2347 assert_snapshot!(check_hover("
2348create procedure public.foo() language sql as $$ select 1 $$;
2349call public.foo$0();
2350"), @r"
2351 hover: procedure public.foo()
2352 ╭▸
2353 3 │ call public.foo();
2354 ╰╴ ─ hover
2355 ");
2356 }
2357
2358 #[test]
2359 fn hover_on_call_procedure_with_search_path() {
2360 assert_snapshot!(check_hover(r#"
2361set search_path to myschema;
2362create procedure foo() language sql as $$ select 1 $$;
2363call foo$0();
2364"#), @r"
2365 hover: procedure myschema.foo()
2366 ╭▸
2367 4 │ call foo();
2368 ╰╴ ─ hover
2369 ");
2370 }
2371
2372 #[test]
2373 fn hover_on_call_procedure_with_params() {
2374 assert_snapshot!(check_hover("
2375create procedure add(a int, b int) language sql as $$ select a + b $$;
2376call add$0(1, 2);
2377"), @r"
2378 hover: procedure public.add(a int, b int)
2379 ╭▸
2380 3 │ call add(1, 2);
2381 ╰╴ ─ hover
2382 ");
2383 }
2384
2385 #[test]
2386 fn hover_on_drop_routine_function() {
2387 assert_snapshot!(check_hover("
2388create function foo() returns int as $$ select 1 $$ language sql;
2389drop routine foo$0();
2390"), @r"
2391 hover: function public.foo() returns int
2392 ╭▸
2393 3 │ drop routine foo();
2394 ╰╴ ─ hover
2395 ");
2396 }
2397
2398 #[test]
2399 fn hover_on_drop_routine_aggregate() {
2400 assert_snapshot!(check_hover("
2401create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
2402drop routine myavg$0(int);
2403"), @r"
2404 hover: aggregate public.myavg(int)
2405 ╭▸
2406 3 │ drop routine myavg(int);
2407 ╰╴ ─ hover
2408 ");
2409 }
2410
2411 #[test]
2412 fn hover_on_drop_routine_procedure() {
2413 assert_snapshot!(check_hover("
2414create procedure foo() language sql as $$ select 1 $$;
2415drop routine foo$0();
2416"), @r"
2417 hover: procedure public.foo()
2418 ╭▸
2419 3 │ drop routine foo();
2420 ╰╴ ─ hover
2421 ");
2422 }
2423
2424 #[test]
2425 fn hover_on_drop_routine_with_schema() {
2426 assert_snapshot!(check_hover("
2427set search_path to public;
2428create function foo() returns int as $$ select 1 $$ language sql;
2429drop routine public.foo$0();
2430"), @r"
2431 hover: function public.foo() returns int
2432 ╭▸
2433 4 │ drop routine public.foo();
2434 ╰╴ ─ hover
2435 ");
2436 }
2437
2438 #[test]
2439 fn hover_on_drop_routine_with_search_path() {
2440 assert_snapshot!(check_hover(r#"
2441set search_path to myschema;
2442create function foo() returns int as $$ select 1 $$ language sql;
2443drop routine foo$0();
2444"#), @r"
2445 hover: function myschema.foo() returns int
2446 ╭▸
2447 4 │ drop routine foo();
2448 ╰╴ ─ hover
2449 ");
2450 }
2451
2452 #[test]
2453 fn hover_on_drop_routine_overloaded() {
2454 assert_snapshot!(check_hover("
2455create function add(complex) returns complex as $$ select null $$ language sql;
2456create function add(bigint) returns bigint as $$ select 1 $$ language sql;
2457drop routine add$0(complex);
2458"), @r"
2459 hover: function public.add(complex) returns complex
2460 ╭▸
2461 4 │ drop routine add(complex);
2462 ╰╴ ─ hover
2463 ");
2464 }
2465
2466 #[test]
2467 fn hover_on_drop_routine_prefers_function_over_procedure() {
2468 assert_snapshot!(check_hover("
2469create function foo() returns int as $$ select 1 $$ language sql;
2470create procedure foo() language sql as $$ select 1 $$;
2471drop routine foo$0();
2472"), @r"
2473 hover: function public.foo() returns int
2474 ╭▸
2475 4 │ drop routine foo();
2476 ╰╴ ─ hover
2477 ");
2478 }
2479
2480 #[test]
2481 fn hover_on_drop_routine_prefers_aggregate_over_procedure() {
2482 assert_snapshot!(check_hover("
2483create aggregate foo(int) (sfunc = int4_avg_accum, stype = _int8);
2484create procedure foo(int) language sql as $$ select 1 $$;
2485drop routine foo$0(int);
2486"), @r"
2487 hover: aggregate public.foo(int)
2488 ╭▸
2489 4 │ drop routine foo(int);
2490 ╰╴ ─ hover
2491 ");
2492 }
2493
2494 #[test]
2495 fn hover_on_update_table() {
2496 assert_snapshot!(check_hover("
2497create table users(id int, email text);
2498update users$0 set email = 'new@example.com';
2499"), @r"
2500 hover: table public.users(id int, email text)
2501 ╭▸
2502 3 │ update users set email = 'new@example.com';
2503 ╰╴ ─ hover
2504 ");
2505 }
2506
2507 #[test]
2508 fn hover_on_update_table_with_schema() {
2509 assert_snapshot!(check_hover("
2510create table public.users(id int, email text);
2511update public.users$0 set email = 'new@example.com';
2512"), @r"
2513 hover: table public.users(id int, email text)
2514 ╭▸
2515 3 │ update public.users set email = 'new@example.com';
2516 ╰╴ ─ hover
2517 ");
2518 }
2519
2520 #[test]
2521 fn hover_on_update_set_column() {
2522 assert_snapshot!(check_hover("
2523create table users(id int, email text);
2524update users set email$0 = 'new@example.com' where id = 1;
2525"), @r"
2526 hover: column public.users.email text
2527 ╭▸
2528 3 │ update users set email = 'new@example.com' where id = 1;
2529 ╰╴ ─ hover
2530 ");
2531 }
2532
2533 #[test]
2534 fn hover_on_update_set_column_with_schema() {
2535 assert_snapshot!(check_hover("
2536create table public.users(id int, email text);
2537update public.users set email$0 = 'new@example.com' where id = 1;
2538"), @r"
2539 hover: column public.users.email text
2540 ╭▸
2541 3 │ update public.users set email = 'new@example.com' where id = 1;
2542 ╰╴ ─ hover
2543 ");
2544 }
2545
2546 #[test]
2547 fn hover_on_update_where_column() {
2548 assert_snapshot!(check_hover("
2549create table users(id int, email text);
2550update users set email = 'new@example.com' where id$0 = 1;
2551"), @r"
2552 hover: column public.users.id int
2553 ╭▸
2554 3 │ update users set email = 'new@example.com' where id = 1;
2555 ╰╴ ─ hover
2556 ");
2557 }
2558
2559 #[test]
2560 fn hover_on_update_where_column_with_schema() {
2561 assert_snapshot!(check_hover("
2562create table public.users(id int, email text);
2563update public.users set email = 'new@example.com' where id$0 = 1;
2564"), @r"
2565 hover: column public.users.id int
2566 ╭▸
2567 3 │ update public.users set email = 'new@example.com' where id = 1;
2568 ╰╴ ─ hover
2569 ");
2570 }
2571
2572 #[test]
2573 fn hover_on_update_from_table() {
2574 assert_snapshot!(check_hover("
2575create table users(id int, email text);
2576create table messages(id int, user_id int, email text);
2577update users set email = messages.email from messages$0 where users.id = messages.user_id;
2578"), @r"
2579 hover: table public.messages(id int, user_id int, email text)
2580 ╭▸
2581 4 │ update users set email = messages.email from messages where users.id = messages.user_id;
2582 ╰╴ ─ hover
2583 ");
2584 }
2585
2586 #[test]
2587 fn hover_on_update_from_table_with_schema() {
2588 assert_snapshot!(check_hover("
2589create table users(id int, email text);
2590create table public.messages(id int, user_id int, email text);
2591update users set email = messages.email from public.messages$0 where users.id = messages.user_id;
2592"), @r"
2593 hover: table public.messages(id int, user_id int, email text)
2594 ╭▸
2595 4 │ update users set email = messages.email from public.messages where users.id = messages.user_id;
2596 ╰╴ ─ hover
2597 ");
2598 }
2599
2600 #[test]
2601 fn hover_on_update_with_cte_table() {
2602 assert_snapshot!(check_hover("
2603create table users(id int, email text);
2604with new_data as (
2605 select 1 as id, 'new@example.com' as email
2606)
2607update users set email = new_data.email from new_data$0 where users.id = new_data.id;
2608"), @r"
2609 hover: with new_data as (select 1 as id, 'new@example.com' as email)
2610 ╭▸
2611 6 │ update users set email = new_data.email from new_data where users.id = new_data.id;
2612 ╰╴ ─ hover
2613 ");
2614 }
2615
2616 #[test]
2617 fn hover_on_update_with_cte_column_in_set() {
2618 assert_snapshot!(check_hover("
2619create table users(id int, email text);
2620with new_data as (
2621 select 1 as id, 'new@example.com' as email
2622)
2623update users set email = new_data.email$0 from new_data where users.id = new_data.id;
2624"), @r"
2625 hover: column new_data.email
2626 ╭▸
2627 6 │ update users set email = new_data.email from new_data where users.id = new_data.id;
2628 ╰╴ ─ hover
2629 ");
2630 }
2631
2632 #[test]
2633 fn hover_on_update_with_cte_column_in_where() {
2634 assert_snapshot!(check_hover("
2635create table users(id int, email text);
2636with new_data as (
2637 select 1 as id, 'new@example.com' as email
2638)
2639update users set email = new_data.email from new_data where new_data.id$0 = users.id;
2640"), @r"
2641 hover: column new_data.id
2642 ╭▸
2643 6 │ update users set email = new_data.email from new_data where new_data.id = users.id;
2644 ╰╴ ─ hover
2645 ");
2646 }
2647}