Skip to content

Commit f6bbdc6

Browse files
fix: hover on quoted items (#512)
1 parent 98ae38f commit f6bbdc6

9 files changed

+331
-12
lines changed

crates/pgt_hover/src/hovered_node.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ impl HoveredNode {
2222
pub(crate) fn get(ctx: &pgt_treesitter::context::TreesitterContext) -> Option<Self> {
2323
let node_content = ctx.get_node_under_cursor_content()?;
2424

25-
let under_node = ctx.node_under_cursor.as_ref()?;
25+
let under_cursor = ctx.node_under_cursor.as_ref()?;
2626

27-
match under_node.kind() {
27+
match under_cursor.kind() {
2828
"identifier" if ctx.matches_ancestor_history(&["relation", "object_reference"]) => {
2929
if let Some(schema) = ctx.schema_or_alias_name.as_ref() {
3030
Some(HoveredNode::Table(NodeIdentification::SchemaAndName((
@@ -64,6 +64,11 @@ impl HoveredNode {
6464
Some(HoveredNode::Role(NodeIdentification::Name(node_content)))
6565
}
6666

67+
// quoted columns
68+
"literal" if ctx.matches_ancestor_history(&["select_expression", "term"]) => {
69+
Some(HoveredNode::Column(NodeIdentification::Name(node_content)))
70+
}
71+
6772
"policy_table" | "revoke_table" | "grant_table" => {
6873
if let Some(schema) = ctx.schema_or_alias_name.as_ref() {
6974
Some(HoveredNode::Table(NodeIdentification::SchemaAndName((

crates/pgt_hover/tests/hover_integration_tests.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,149 @@ async fn test_role_hover_alter_role(test_db: PgPool) {
300300
}
301301

302302
#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
303+
async fn test_table_hover_with_quoted_schema(test_db: PgPool) {
304+
let setup = r#"
305+
create schema auth;
306+
create table auth.users (
307+
id serial primary key,
308+
email varchar(255) not null
309+
);
310+
"#;
311+
312+
let query = format!(
313+
r#"select * from "auth".use{}rs"#,
314+
QueryWithCursorPosition::cursor_marker()
315+
);
316+
317+
test_hover_at_cursor("table_hover_quoted_schema", query, Some(setup), &test_db).await;
318+
}
319+
320+
#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
321+
async fn test_function_hover_with_quoted_schema(test_db: PgPool) {
322+
let setup = r#"
323+
create schema auth;
324+
create or replace function auth.authenticate_user(user_email text)
325+
returns boolean
326+
language plpgsql
327+
security definer
328+
as $$
329+
begin
330+
return exists(select 1 from auth.users where email = user_email);
331+
end;
332+
$$;
333+
"#;
334+
335+
let query = format!(
336+
r#"select "auth".authenticate_u{}ser('[email protected]')"#,
337+
QueryWithCursorPosition::cursor_marker()
338+
);
339+
340+
test_hover_at_cursor("function_hover_quoted_schema", query, Some(setup), &test_db).await;
341+
}
342+
343+
#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
344+
async fn test_column_hover_with_quoted_schema_table(test_db: PgPool) {
345+
let setup = r#"
346+
create schema auth;
347+
create table auth.user_profiles (
348+
id serial primary key,
349+
user_id int not null,
350+
first_name varchar(100),
351+
last_name varchar(100)
352+
);
353+
"#;
354+
355+
let query = format!(
356+
r#"select "auth"."user_profiles".first_n{}ame from "auth"."user_profiles""#,
357+
QueryWithCursorPosition::cursor_marker()
358+
);
359+
360+
test_hover_at_cursor(
361+
"column_hover_quoted_schema_table",
362+
query,
363+
Some(setup),
364+
&test_db,
365+
)
366+
.await;
367+
}
368+
369+
#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
370+
async fn test_table_hover_with_quoted_table_name(test_db: PgPool) {
371+
let setup = r#"
372+
create schema auth;
373+
create table auth.users (
374+
id serial primary key,
375+
email varchar(255) not null
376+
);
377+
"#;
378+
379+
let query = format!(
380+
r#"select * from "auth"."use{}rs""#,
381+
QueryWithCursorPosition::cursor_marker()
382+
);
383+
384+
test_hover_at_cursor(
385+
"table_hover_quoted_table_name",
386+
query,
387+
Some(setup),
388+
&test_db,
389+
)
390+
.await;
391+
}
392+
393+
#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
394+
async fn test_column_hover_with_quoted_column_name(test_db: PgPool) {
395+
let setup = r#"
396+
create schema auth;
397+
create table auth.users (
398+
id serial primary key,
399+
email varchar(255) not null
400+
);
401+
"#;
402+
403+
let query = format!(
404+
r#"select "ema{}il" from auth.users"#,
405+
QueryWithCursorPosition::cursor_marker()
406+
);
407+
408+
test_hover_at_cursor(
409+
"column_hover_quoted_column_name",
410+
query,
411+
Some(setup),
412+
&test_db,
413+
)
414+
.await;
415+
}
416+
417+
#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
418+
async fn test_column_hover_with_quoted_column_name_with_table(test_db: PgPool) {
419+
let setup = r#"
420+
create table users (
421+
id serial primary key,
422+
email varchar(255) not null
423+
);
424+
425+
create table phone_nums (
426+
phone_id serial primary key,
427+
email varchar(255) not null,
428+
phone int
429+
);
430+
"#;
431+
432+
let query = format!(
433+
r#"select phone, id from users join phone_nums on "users"."em{}ail" = phone_nums.email;"#,
434+
QueryWithCursorPosition::cursor_marker()
435+
);
436+
437+
test_hover_at_cursor(
438+
"column_hover_quoted_column_name_with_table",
439+
query,
440+
Some(setup),
441+
&test_db,
442+
)
443+
.await;
444+
}
445+
303446
async fn test_policy_table_hover(test_db: PgPool) {
304447
let setup = r#"
305448
create table users (
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
source: crates/pgt_hover/tests/hover_integration_tests.rs
3+
expression: snapshot
4+
---
5+
# Input
6+
```sql
7+
select "email" from auth.users
8+
↑ hovered here
9+
```
10+
11+
# Hover Results
12+
### `auth.users.email`
13+
```plain
14+
varchar(255) - not null
15+
16+
```
17+
---
18+
```plain
19+
20+
```
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
source: crates/pgt_hover/tests/hover_integration_tests.rs
3+
expression: snapshot
4+
---
5+
# Input
6+
```sql
7+
select phone, id from users join phone_nums on "users"."email" = phone_nums.email;
8+
↑ hovered here
9+
```
10+
11+
# Hover Results
12+
### `public.users.email`
13+
```plain
14+
varchar(255) - not null
15+
16+
```
17+
---
18+
```plain
19+
20+
```
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
source: crates/pgt_hover/tests/hover_integration_tests.rs
3+
expression: snapshot
4+
---
5+
# Input
6+
```sql
7+
select "auth"."user_profiles".first_name from "auth"."user_profiles"
8+
↑ hovered here
9+
```
10+
11+
# Hover Results
12+
### `auth.user_profiles.first_name`
13+
```plain
14+
varchar(100) - nullable
15+
16+
```
17+
---
18+
```plain
19+
20+
```
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
source: crates/pgt_hover/tests/hover_integration_tests.rs
3+
expression: snapshot
4+
---
5+
# Input
6+
```sql
7+
select "auth".authenticate_user('[email protected]')
8+
↑ hovered here
9+
```
10+
11+
# Hover Results
12+
### `auth.authenticate_user(user_email text) → boolean`
13+
```plain
14+
Function - Security DEFINER
15+
```
16+
---
17+
```sql
18+
19+
CREATE OR REPLACE FUNCTION auth.authenticate_user(user_email text)
20+
RETURNS boolean
21+
LANGUAGE plpgsql
22+
SECURITY DEFINER
23+
AS $function$
24+
begin
25+
return exists(select 1 from auth.users where email = user_email);
26+
end;
27+
$function$
28+
29+
30+
```
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
source: crates/pgt_hover/tests/hover_integration_tests.rs
3+
expression: snapshot
4+
---
5+
# Input
6+
```sql
7+
select * from "auth".users
8+
↑ hovered here
9+
```
10+
11+
# Hover Results
12+
### `auth.users` - 🔓 RLS disabled
13+
```plain
14+
15+
```
16+
---
17+
```plain
18+
19+
~0 rows, ~0 dead rows, 8.19 kB
20+
```
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
source: crates/pgt_hover/tests/hover_integration_tests.rs
3+
expression: snapshot
4+
---
5+
# Input
6+
```sql
7+
select * from "auth"."users"
8+
↑ hovered here
9+
```
10+
11+
# Hover Results
12+
### `auth.users` - 🔓 RLS disabled
13+
```plain
14+
15+
```
16+
---
17+
```plain
18+
19+
~0 rows, ~0 dead rows, 8.19 kB
20+
```

0 commit comments

Comments
 (0)