Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions crates/squawk_ide/src/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub(crate) enum NameRefClass {
UpdateColumn,
UpdateQualifiedColumnTable,
View,
Window,
}

fn is_special_fn(kind: SyntaxKind) -> bool {
Expand Down Expand Up @@ -603,6 +604,16 @@ pub(crate) fn classify_name_ref(node: &SyntaxNode) -> Option<NameRefClass> {
if ast::ArgList::can_cast(ancestor.kind()) {
in_arg_list = true;
}
if ast::OverClause::can_cast(ancestor.kind()) && !in_function_name {
if node
.parent()
.is_some_and(|parent| ast::OverClause::can_cast(parent.kind()))
{
return Some(NameRefClass::Window);
}

return Some(NameRefClass::SelectColumn);
}
if ast::CallExpr::can_cast(ancestor.kind()) {
if !in_arg_list {
in_function_name = true;
Expand Down Expand Up @@ -934,6 +945,9 @@ pub(crate) fn classify_def_node(def_node: &SyntaxNode) -> Option<NameRefClass> {
}
return Some(NameRefClass::FromTable);
}
if ast::WindowDef::can_cast(ancestor.kind()) {
return Some(NameRefClass::Window);
}
if ast::AsName::can_cast(ancestor.kind())
|| ast::ParenSelect::can_cast(ancestor.kind())
|| ast::Values::can_cast(ancestor.kind())
Expand Down
118 changes: 118 additions & 0 deletions crates/squawk_ide/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9001,4 +9001,122 @@ create operator ||| (leftarg = int, rightarg = int, procedure = f$0);
╰╴ ─ 1. source
");
}

#[test]
fn goto_cte_window_partition_column_from_create_table_if_not_exists() {
assert_snapshot!(goto("
create table t (
id bigint primary key,
group_col text not null,
update_date date not null
);

with row_number_added as (
select
*,
row_number() over (
partition by group_col$0
order by update_date desc
) as rn
from t
)
select * from row_number_added
"), @"
╭▸
4 │ group_col text not null,
│ ───────── 2. destination
12 │ partition by group_col
╰╴ ─ 1. source
");
}

#[test]
fn goto_cte_window_order_column_from_create_table_if_not_exists() {
assert_snapshot!(goto("
create table t (
id bigint primary key,
group_col text not null,
update_date date not null
);

with row_number_added as (
select
*,
row_number() over (
partition by group_col
order by update_date$0 desc
) as rn
from t
)
select * from row_number_added
"), @"
╭▸
5 │ update_date date not null
│ ─────────── 2. destination
13 │ order by update_date desc
╰╴ ─ 1. source
");
}

#[test]
fn goto_cte_window_partition_function_call_from_create_table() {
assert_snapshot!(goto("
create function length(text) returns int language internal;

create table t (
id bigint primary key,
group_col text not null,
update_date date not null
);

with row_number_added as (
select
*,
row_number() over (
partition by length$0(group_col)
order by update_date$0 desc
) as rn
from t
)
select * from row_number_added
"), @"
╭▸
2 │ create function length(text) returns int language internal;
│ ────── 2. destination
14 │ partition by length(group_col)
╰╴ ─ 1. source
");
}

#[test]
fn goto_select_window_def_reuse() {
assert_snapshot!(goto("
create table tbl (
id bigint primary key,
group_col text not null,
update_date date not null,
value text
);
select
id,
group_col,
row_number() over w as rn,
lag(value) over w$0 as prev_value
from tbl
window w as (
partition by group_col
order by update_date desc
);
"), @r"
╭▸
12 │ lag(value) over w as prev_value
│ ─ 1. source
13 │ from tbl
14 │ window w as (
╰╴ ─ 2. destination
");
}
}
47 changes: 47 additions & 0 deletions crates/squawk_ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ fn hover_name_ref(
NameRefClass::Cursor => hover_cursor(root, name_ref, binder),
NameRefClass::PreparedStatement => hover_prepared_statement(root, name_ref, binder),
NameRefClass::Channel => hover_channel(root, name_ref, binder),
NameRefClass::Window => hover_window(root, name_ref, binder),
}
}

Expand Down Expand Up @@ -1183,6 +1184,22 @@ fn hover_channel(
format_listen(&listen)
}

fn hover_window(
root: &SyntaxNode,
name_ref: &ast::NameRef,
binder: &binder::Binder,
) -> Option<String> {
let window_ptr = resolve::resolve_name_ref_ptrs(binder, root, name_ref)?
.into_iter()
.next()?;
let window_name_node = window_ptr.to_node(root);
let window_def = window_name_node
.ancestors()
.find_map(ast::WindowDef::cast)?;

Some(format!("window {}", window_def.syntax().text()))
}

fn hover_type(
root: &SyntaxNode,
name_ref: &ast::NameRef,
Expand Down Expand Up @@ -4491,6 +4508,36 @@ select a$0 from part_2026_01_02;
");
}

#[test]
fn hover_select_window_def_reuse() {
assert_snapshot!(check_hover("
create table tbl (
id bigint primary key,
group_col text not null,
update_date date not null,
value text
);
select
id,
group_col,
row_number() over w as rn,
lag(value) over w$0 as prev_value
from tbl
window w as (
partition by group_col
order by update_date desc
);
"), @r"
hover: window w as (
partition by group_col
order by update_date desc
)
╭▸
12 │ lag(value) over w as prev_value
╰╴ ─ hover
");
}

#[test]
fn hover_create_table_like_multi_star() {
assert_snapshot!(check_hover("
Expand Down
17 changes: 17 additions & 0 deletions crates/squawk_ide/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ pub(crate) fn resolve_name_ref_ptrs(
let position = name_ref.syntax().text_range().start();
resolve_view_name_ptr(binder, &view_name, &schema, position).map(|ptr| smallvec![ptr])
}
NameRefClass::Window => resolve_window_name_ptr(name_ref).map(|ptr| smallvec![ptr]),
NameRefClass::Sequence => {
let (sequence_name, schema) = extract_table_schema_from_name_ref(name_ref)?;
let position = name_ref.syntax().text_range().start();
Expand Down Expand Up @@ -1594,6 +1595,22 @@ fn resolve_select_column_ptr(
None
}

fn resolve_window_name_ptr(name_ref: &ast::NameRef) -> Option<SyntaxNodePtr> {
let window_name = Name::from_node(name_ref);
let select = name_ref.syntax().ancestors().find_map(ast::Select::cast)?;
let window_clause = select.window_clause()?;

for window_def in window_clause.window_defs() {
if let Some(name) = window_def.name()
&& Name::from_node(&name) == window_name
{
return Some(SyntaxNodePtr::new(name.syntax()));
}
}

None
}

fn resolve_delete_column_ptr(
binder: &Binder,
root: &SyntaxNode,
Expand Down
Loading