Skip to content

Commit 7b71eb7

Browse files
authored
ide: add hover for create index (#765)
1 parent c4c95bc commit 7b71eb7

File tree

1 file changed

+159
-12
lines changed

1 file changed

+159
-12
lines changed

crates/squawk_ide/src/hover.rs

Lines changed: 159 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
1818
if is_table_ref(&name_ref) {
1919
return hover_table(file, &name_ref, &binder);
2020
}
21+
22+
if is_index_ref(&name_ref) {
23+
return hover_index(file, &name_ref, &binder);
24+
}
2125
}
2226

2327
if let Some(name) = ast::Name::cast(parent) {
@@ -30,6 +34,10 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
3034
if let Some(create_table) = name.syntax().ancestors().find_map(ast::CreateTable::cast) {
3135
return format_create_table(&create_table, &binder);
3236
}
37+
38+
if let Some(create_index) = name.syntax().ancestors().find_map(ast::CreateIndex::cast) {
39+
return format_create_index(&create_index, &binder);
40+
}
3341
}
3442

3543
None
@@ -116,6 +124,23 @@ fn hover_table(
116124
format_create_table(&create_table, binder)
117125
}
118126

127+
fn hover_index(
128+
file: &ast::SourceFile,
129+
name_ref: &ast::NameRef,
130+
binder: &binder::Binder,
131+
) -> Option<String> {
132+
let index_ptr = resolve::resolve_name_ref(binder, name_ref)?;
133+
134+
let root = file.syntax();
135+
let index_name_node = index_ptr.to_node(root);
136+
137+
let create_index = index_name_node
138+
.ancestors()
139+
.find_map(ast::CreateIndex::cast)?;
140+
141+
format_create_index(&create_index, binder)
142+
}
143+
119144
// Insert inferred schema into the create table hover info
120145
fn format_create_table(create_table: &ast::CreateTable, binder: &binder::Binder) -> Option<String> {
121146
let path = create_table.path()?;
@@ -156,6 +181,57 @@ fn table_name_offset(create_table: &ast::CreateTable, path: &ast::Path) -> Optio
156181
Some((name_start - create_table_start).into())
157182
}
158183

184+
// Insert inferred schema for index name and table name
185+
fn format_create_index(create_index: &ast::CreateIndex, binder: &binder::Binder) -> Option<String> {
186+
let mut text = create_index.syntax().text().to_string();
187+
let create_index_start = create_index.syntax().text_range().start();
188+
189+
let Some(index_schema_str) = index_schema(create_index, binder) else {
190+
return Some(text);
191+
};
192+
193+
let mut insertions = vec![];
194+
195+
if let Some(name) = create_index.name() {
196+
let has_schema = name
197+
.syntax()
198+
.parent()
199+
.map(|p| ast::Path::can_cast(p.kind()))
200+
.unwrap_or(false);
201+
202+
if !has_schema {
203+
let name_start = name.syntax().text_range().start();
204+
let offset: usize = (name_start - create_index_start).into();
205+
insertions.push((offset, format!("{}.", index_schema_str)));
206+
}
207+
}
208+
209+
if let Some(relation_name) = create_index.relation_name()
210+
&& let Some(path) = relation_name.path()
211+
&& path.qualifier().is_none()
212+
{
213+
let (table_schema, _) = resolve::resolve_table_info(binder, &path)?;
214+
let segment = path.segment()?;
215+
let name_ref = segment.name_ref()?;
216+
let table_name_start = name_ref.syntax().text_range().start();
217+
let offset: usize = (table_name_start - create_index_start).into();
218+
insertions.push((offset, format!("{}.", table_schema)));
219+
}
220+
221+
insertions.sort_by(|a, b| b.0.cmp(&a.0));
222+
for (offset, schema_str) in insertions {
223+
text.insert_str(offset, &schema_str);
224+
}
225+
226+
Some(text)
227+
}
228+
229+
fn index_schema(create_index: &ast::CreateIndex, binder: &binder::Binder) -> Option<String> {
230+
let position = create_index.syntax().text_range().start();
231+
let search_path = binder.search_path_at(position);
232+
search_path.first().map(|s| s.to_string())
233+
}
234+
159235
fn is_column_ref(name_ref: &ast::NameRef) -> bool {
160236
let mut in_partition_item = false;
161237

@@ -193,6 +269,15 @@ fn is_table_ref(name_ref: &ast::NameRef) -> bool {
193269
false
194270
}
195271

272+
fn is_index_ref(name_ref: &ast::NameRef) -> bool {
273+
for ancestor in name_ref.syntax().ancestors() {
274+
if ast::DropIndex::can_cast(ancestor.kind()) {
275+
return true;
276+
}
277+
}
278+
false
279+
}
280+
196281
#[cfg(test)]
197282
mod test {
198283
use crate::hover::hover;
@@ -236,13 +321,6 @@ mod test {
236321
None
237322
}
238323

239-
fn hover_not_found(sql: &str) {
240-
assert!(
241-
check_hover_(sql).is_none(),
242-
"Should not find hover information"
243-
);
244-
}
245-
246324
#[test]
247325
fn hover_column_in_create_index() {
248326
assert_snapshot!(check_hover("
@@ -390,13 +468,16 @@ create index idx on t$0(id);
390468
}
391469

392470
#[test]
393-
fn hover_not_on_index_name() {
394-
hover_not_found(
395-
"
471+
fn hover_on_index_name_in_create() {
472+
assert_snapshot!(check_hover("
396473
create table users(id int);
397474
create index idx$0 on users(id);
398-
",
399-
);
475+
"), @r"
476+
hover: create index public.idx on public.users(id)
477+
╭▸
478+
3 │ create index idx on users(id);
479+
╰╴ ─ hover
480+
");
400481
}
401482

402483
#[test]
@@ -571,4 +652,70 @@ create table t(id int, email$0 text, name varchar(100));
571652
╰╴ ─ hover
572653
");
573654
}
655+
656+
#[test]
657+
fn hover_on_drop_table() {
658+
assert_snapshot!(check_hover("
659+
create table users(id int, email text);
660+
drop table users$0;
661+
"), @r"
662+
hover: create table public.users(id int, email text)
663+
╭▸
664+
3 │ drop table users;
665+
╰╴ ─ hover
666+
");
667+
}
668+
669+
#[test]
670+
fn hover_on_drop_table_with_schema() {
671+
assert_snapshot!(check_hover("
672+
create table myschema.users(id int);
673+
drop table myschema.users$0;
674+
"), @r"
675+
hover: create table myschema.users(id int)
676+
╭▸
677+
3 │ drop table myschema.users;
678+
╰╴ ─ hover
679+
");
680+
}
681+
682+
#[test]
683+
fn hover_on_drop_temp_table() {
684+
assert_snapshot!(check_hover("
685+
create temp table t(x bigint);
686+
drop table t$0;
687+
"), @r"
688+
hover: create temp table pg_temp.t(x bigint)
689+
╭▸
690+
3 │ drop table t;
691+
╰╴ ─ hover
692+
");
693+
}
694+
695+
#[test]
696+
fn hover_on_create_index_definition() {
697+
assert_snapshot!(check_hover("
698+
create table t(x bigint);
699+
create index idx$0 on t(x);
700+
"), @r"
701+
hover: create index public.idx on public.t(x)
702+
╭▸
703+
3 │ create index idx on t(x);
704+
╰╴ ─ hover
705+
");
706+
}
707+
708+
#[test]
709+
fn hover_on_drop_index() {
710+
assert_snapshot!(check_hover("
711+
create table t(x bigint);
712+
create index idx_x on t(x);
713+
drop index idx_x$0;
714+
"), @r"
715+
hover: create index public.idx_x on public.t(x)
716+
╭▸
717+
4 │ drop index idx_x;
718+
╰╴ ─ hover
719+
");
720+
}
574721
}

0 commit comments

Comments
 (0)