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
27 changes: 27 additions & 0 deletions crates/squawk_ide/src/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ fn bind_stmt(b: &mut Binder, stmt: ast::Stmt) {
ast::Stmt::CreateAggregate(create_aggregate) => bind_create_aggregate(b, create_aggregate),
ast::Stmt::CreateProcedure(create_procedure) => bind_create_procedure(b, create_procedure),
ast::Stmt::CreateSchema(create_schema) => bind_create_schema(b, create_schema),
ast::Stmt::CreateType(create_type) => bind_create_type(b, create_type),
ast::Stmt::Set(set) => bind_set(b, set),
_ => {}
}
Expand Down Expand Up @@ -238,6 +239,32 @@ fn bind_create_schema(b: &mut Binder, create_schema: ast::CreateSchema) {
b.scopes[root].insert(schema_name, schema_id);
}

fn bind_create_type(b: &mut Binder, create_type: ast::CreateType) {
let Some(path) = create_type.path() else {
return;
};

let Some(type_name) = item_name(&path) else {
return;
};

let name_ptr = path_to_ptr(&path);

let Some(schema) = schema_name(b, &path, false) else {
return;
};

let type_id = b.symbols.alloc(Symbol {
kind: SymbolKind::Type,
ptr: name_ptr,
schema,
params: None,
});

let root = b.root_scope();
b.scopes[root].insert(type_name, type_id);
}

fn item_name(path: &ast::Path) -> Option<Name> {
let segment = path.segment()?;

Expand Down
81 changes: 80 additions & 1 deletion crates/squawk_ide/src/document_symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ use rowan::TextRange;
use squawk_syntax::ast::{self, AstNode};

use crate::binder;
use crate::resolve::{resolve_function_info, resolve_table_info};
use crate::resolve::{resolve_function_info, resolve_table_info, resolve_type_info};

#[derive(Debug)]
pub enum DocumentSymbolKind {
Table,
Function,
Type,
Column,
}

Expand Down Expand Up @@ -40,6 +41,11 @@ pub fn document_symbols(file: &ast::SourceFile) -> Vec<DocumentSymbol> {
symbols.push(symbol);
}
}
ast::Stmt::CreateType(create_type) => {
if let Some(symbol) = create_type_symbol(&binder, create_type) {
symbols.push(symbol);
}
}
_ => {}
}
}
Expand Down Expand Up @@ -106,6 +112,30 @@ fn create_function_symbol(
})
}

fn create_type_symbol(
binder: &binder::Binder,
create_type: ast::CreateType,
) -> Option<DocumentSymbol> {
let path = create_type.path()?;
let segment = path.segment()?;
let name_node = segment.name()?;

let (schema, type_name) = resolve_type_info(binder, &path)?;
let name = format!("{}.{}", schema.0, type_name);

let full_range = create_type.syntax().text_range();
let focus_range = name_node.syntax().text_range();

Some(DocumentSymbol {
name,
detail: None,
kind: DocumentSymbolKind::Type,
full_range,
focus_range,
children: vec![],
})
}

fn create_column_symbol(column: ast::Column) -> Option<DocumentSymbol> {
let name_node = column.name()?;
let name = name_node.syntax().text().to_string();
Expand Down Expand Up @@ -165,6 +195,7 @@ mod tests {
let kind = match symbol.kind {
DocumentSymbolKind::Table => "table",
DocumentSymbolKind::Function => "function",
DocumentSymbolKind::Type => "type",
DocumentSymbolKind::Column => "column",
};

Expand Down Expand Up @@ -350,6 +381,54 @@ create function my_schema.hello() returns void as $$ select 1; $$ language sql;
");
}

#[test]
fn create_type() {
assert_snapshot!(
symbols("create type status as enum ('active', 'inactive');"),
@r"
info: type: public.status
╭▸
1 │ create type status as enum ('active', 'inactive');
│ ┬───────────┯━━━━━───────────────────────────────
│ │ │
│ │ focus range
╰╴full range
"
);
}

#[test]
fn create_type_composite() {
assert_snapshot!(
symbols("create type person as (name text, age int);"),
@r"
info: type: public.person
╭▸
1 │ create type person as (name text, age int);
│ ┬───────────┯━━━━━────────────────────────
│ │ │
│ │ focus range
╰╴full range
"
);
}

#[test]
fn create_type_with_schema() {
assert_snapshot!(
symbols("create type myschema.status as enum ('active', 'inactive');"),
@r"
info: type: myschema.status
╭▸
1 │ create type myschema.status as enum ('active', 'inactive');
│ ┬────────────────────┯━━━━━───────────────────────────────
│ │ │
│ │ focus range
╰╴full range
"
);
}

#[test]
fn empty_file() {
symbols_not_found("")
Expand Down
88 changes: 88 additions & 0 deletions crates/squawk_ide/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,94 @@ create table t();
");
}

#[test]
fn goto_drop_type() {
assert_snapshot!(goto("
create type t as enum ('a', 'b');
drop type t$0;
"), @r"
╭▸
2 │ create type t as enum ('a', 'b');
│ ─ 2. destination
3 │ drop type t;
╰╴ ─ 1. source
");
}

#[test]
fn goto_drop_type_with_schema() {
assert_snapshot!(goto("
create type public.t as enum ('a', 'b');
drop type t$0;
"), @r"
╭▸
2 │ create type public.t as enum ('a', 'b');
│ ─ 2. destination
3 │ drop type t;
╰╴ ─ 1. source
");

assert_snapshot!(goto("
create type foo.t as enum ('a', 'b');
drop type foo.t$0;
"), @r"
╭▸
2 │ create type foo.t as enum ('a', 'b');
│ ─ 2. destination
3 │ drop type foo.t;
╰╴ ─ 1. source
");

goto_not_found(
"
create type t as enum ('a', 'b');
drop type foo.t$0;
",
);
}

#[test]
fn goto_drop_type_defined_after() {
assert_snapshot!(goto("
drop type t$0;
create type t as enum ('a', 'b');
"), @r"
╭▸
2 │ drop type t;
│ ─ 1. source
3 │ create type t as enum ('a', 'b');
╰╴ ─ 2. destination
");
}

#[test]
fn goto_drop_type_composite() {
assert_snapshot!(goto("
create type person as (name text, age int);
drop type person$0;
"), @r"
╭▸
2 │ create type person as (name text, age int);
│ ────── 2. destination
3 │ drop type person;
╰╴ ─ 1. source
");
}

#[test]
fn goto_drop_type_range() {
assert_snapshot!(goto("
create type int4_range as range (subtype = int4);
drop type int4_range$0;
"), @r"
╭▸
2 │ create type int4_range as range (subtype = int4);
│ ────────── 2. destination
3 │ drop type int4_range;
╰╴ ─ 1. source
");
}

#[test]
fn begin_to_rollback() {
assert_snapshot!(goto(
Expand Down
Loading
Loading