Skip to content

Commit 436add0

Browse files
authored
ide: more create table syntax support for goto def (#813)
1 parent dd34d9c commit 436add0

File tree

9 files changed

+749
-10
lines changed

9 files changed

+749
-10
lines changed

β€Žcrates/squawk_ide/src/binder.rsβ€Ž

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ fn bind_stmt(b: &mut Binder, stmt: ast::Stmt) {
8888
ast::Stmt::CreateMaterializedView(create_view) => {
8989
bind_create_materialized_view(b, create_view)
9090
}
91+
ast::Stmt::CreateSequence(create_sequence) => bind_create_sequence(b, create_sequence),
9192
ast::Stmt::Set(set) => bind_set(b, set),
9293
_ => {}
9394
}
@@ -331,6 +332,34 @@ fn bind_create_materialized_view(b: &mut Binder, create_view: ast::CreateMateria
331332
b.scopes[root].insert(view_name, view_id);
332333
}
333334

335+
fn bind_create_sequence(b: &mut Binder, create_sequence: ast::CreateSequence) {
336+
let Some(path) = create_sequence.path() else {
337+
return;
338+
};
339+
340+
let Some(sequence_name) = item_name(&path) else {
341+
return;
342+
};
343+
344+
let name_ptr = path_to_ptr(&path);
345+
let is_temp =
346+
create_sequence.temp_token().is_some() || create_sequence.temporary_token().is_some();
347+
348+
let Some(schema) = schema_name(b, &path, is_temp) else {
349+
return;
350+
};
351+
352+
let sequence_id = b.symbols.alloc(Symbol {
353+
kind: SymbolKind::Sequence,
354+
ptr: name_ptr,
355+
schema,
356+
params: None,
357+
});
358+
359+
let root = b.root_scope();
360+
b.scopes[root].insert(sequence_name, sequence_id);
361+
}
362+
334363
fn item_name(path: &ast::Path) -> Option<Name> {
335364
let segment = path.segment()?;
336365

β€Žcrates/squawk_ide/src/classify.rsβ€Ž

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ pub(crate) enum NameRefClass {
88
DropType,
99
DropView,
1010
DropMaterializedView,
11+
DropSequence,
12+
ForeignKeyTable,
13+
ForeignKeyColumn,
14+
ForeignKeyLocalColumn,
15+
CheckConstraintColumn,
16+
GeneratedColumn,
17+
UniqueConstraintColumn,
18+
PrimaryKeyConstraintColumn,
19+
NotNullConstraintColumn,
20+
ExcludeConstraintColumn,
21+
PartitionByColumn,
22+
PartitionOfTable,
23+
LikeTable,
24+
InheritsTable,
1125
DropFunction,
1226
DropAggregate,
1327
DropProcedure,
@@ -36,13 +50,16 @@ pub(crate) enum NameRefClass {
3650
}
3751

3852
pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option<NameRefClass> {
39-
let mut in_partition_item = false;
4053
let mut in_call_expr = false;
4154
let mut in_arg_list = false;
4255
let mut in_column_list = false;
4356
let mut in_where_clause = false;
4457
let mut in_from_clause = false;
4558
let mut in_set_clause = false;
59+
let mut in_constraint_exclusion_list = false;
60+
let mut in_constraint_include_clause = false;
61+
let mut in_constraint_where_clause = false;
62+
let mut in_partition_item = false;
4663

4764
// TODO: can we combine this if and the one that follows?
4865
if let Some(parent) = name_ref.syntax().parent()
@@ -170,6 +187,62 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option<NameRefClass>
170187
if ast::DropMaterializedView::can_cast(ancestor.kind()) {
171188
return Some(NameRefClass::DropMaterializedView);
172189
}
190+
if ast::DropSequence::can_cast(ancestor.kind()) {
191+
return Some(NameRefClass::DropSequence);
192+
}
193+
if let Some(foreign_key) = ast::ForeignKeyConstraint::cast(ancestor.clone()) {
194+
if in_column_list {
195+
// TODO: ast is too "flat" here, we need a unique node for to
196+
// and from columns to differentiate which would help us avoid
197+
// this
198+
if let Some(to_columns) = foreign_key.to_columns()
199+
&& to_columns
200+
.syntax()
201+
.text_range()
202+
.contains_range(name_ref.syntax().text_range())
203+
{
204+
return Some(NameRefClass::ForeignKeyColumn);
205+
}
206+
if let Some(from_columns) = foreign_key.from_columns()
207+
&& from_columns
208+
.syntax()
209+
.text_range()
210+
.contains_range(name_ref.syntax().text_range())
211+
{
212+
return Some(NameRefClass::ForeignKeyLocalColumn);
213+
}
214+
} else {
215+
return Some(NameRefClass::ForeignKeyTable);
216+
}
217+
}
218+
if ast::CheckConstraint::can_cast(ancestor.kind()) {
219+
return Some(NameRefClass::CheckConstraintColumn);
220+
}
221+
if ast::GeneratedConstraint::can_cast(ancestor.kind()) {
222+
return Some(NameRefClass::GeneratedColumn);
223+
}
224+
if in_column_list && ast::UniqueConstraint::can_cast(ancestor.kind()) {
225+
return Some(NameRefClass::UniqueConstraintColumn);
226+
}
227+
if in_column_list && ast::PrimaryKeyConstraint::can_cast(ancestor.kind()) {
228+
return Some(NameRefClass::PrimaryKeyConstraintColumn);
229+
}
230+
if ast::NotNullConstraint::can_cast(ancestor.kind()) {
231+
return Some(NameRefClass::NotNullConstraintColumn);
232+
}
233+
if (in_constraint_exclusion_list
234+
|| in_constraint_include_clause
235+
|| in_constraint_where_clause)
236+
&& ast::ExcludeConstraint::can_cast(ancestor.kind())
237+
{
238+
return Some(NameRefClass::ExcludeConstraintColumn);
239+
}
240+
if ast::LikeClause::can_cast(ancestor.kind()) {
241+
return Some(NameRefClass::LikeTable);
242+
}
243+
if ast::Inherits::can_cast(ancestor.kind()) {
244+
return Some(NameRefClass::InheritsTable);
245+
}
173246
if ast::CastExpr::can_cast(ancestor.kind()) && in_type {
174247
return Some(NameRefClass::TypeReference);
175248
}
@@ -197,15 +270,18 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option<NameRefClass>
197270
{
198271
return Some(NameRefClass::CreateSchema);
199272
}
200-
if ast::PartitionItem::can_cast(ancestor.kind()) {
201-
in_partition_item = true;
202-
}
203273
if ast::CreateIndex::can_cast(ancestor.kind()) {
204274
if in_partition_item {
205275
return Some(NameRefClass::CreateIndexColumn);
206276
}
207277
return Some(NameRefClass::CreateIndex);
208278
}
279+
if in_partition_item && ast::CreateTable::can_cast(ancestor.kind()) {
280+
return Some(NameRefClass::PartitionByColumn);
281+
}
282+
if ast::PartitionOf::can_cast(ancestor.kind()) {
283+
return Some(NameRefClass::PartitionOfTable);
284+
}
209285
if ast::ArgList::can_cast(ancestor.kind()) {
210286
in_arg_list = true;
211287
}
@@ -229,6 +305,18 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option<NameRefClass>
229305
if ast::ColumnList::can_cast(ancestor.kind()) {
230306
in_column_list = true;
231307
}
308+
if ast::ConstraintExclusionList::can_cast(ancestor.kind()) {
309+
in_constraint_exclusion_list = true;
310+
}
311+
if ast::ConstraintIncludeClause::can_cast(ancestor.kind()) {
312+
in_constraint_include_clause = true;
313+
}
314+
if ast::WhereConditionClause::can_cast(ancestor.kind()) {
315+
in_constraint_where_clause = true;
316+
}
317+
if ast::PartitionItem::can_cast(ancestor.kind()) {
318+
in_partition_item = true;
319+
}
232320
if ast::Insert::can_cast(ancestor.kind()) {
233321
if in_column_list {
234322
return Some(NameRefClass::InsertColumn);
@@ -273,6 +361,7 @@ pub(crate) enum NameClass {
273361
CreateTable(ast::CreateTable),
274362
WithTable(ast::WithTable),
275363
CreateIndex(ast::CreateIndex),
364+
CreateSequence(ast::CreateSequence),
276365
CreateType(ast::CreateType),
277366
CreateFunction(ast::CreateFunction),
278367
CreateAggregate(ast::CreateAggregate),
@@ -307,6 +396,9 @@ pub(crate) fn classify_name(name: &ast::Name) -> Option<NameClass> {
307396
if let Some(create_index) = ast::CreateIndex::cast(ancestor.clone()) {
308397
return Some(NameClass::CreateIndex(create_index));
309398
}
399+
if let Some(create_sequence) = ast::CreateSequence::cast(ancestor.clone()) {
400+
return Some(NameClass::CreateSequence(create_sequence));
401+
}
310402
if let Some(create_type) = ast::CreateType::cast(ancestor.clone()) {
311403
return Some(NameClass::CreateType(create_type));
312404
}

β€Žcrates/squawk_ide/src/document_symbols.rsβ€Ž

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::resolve::{
99

1010
#[derive(Debug)]
1111
pub enum DocumentSymbolKind {
12+
Schema,
1213
Table,
1314
View,
1415
MaterializedView,
@@ -40,6 +41,11 @@ pub fn document_symbols(file: &ast::SourceFile) -> Vec<DocumentSymbol> {
4041

4142
for stmt in file.stmts() {
4243
match stmt {
44+
ast::Stmt::CreateSchema(create_schema) => {
45+
if let Some(symbol) = create_schema_symbol(create_schema) {
46+
symbols.push(symbol);
47+
}
48+
}
4349
ast::Stmt::CreateTable(create_table) => {
4450
if let Some(symbol) = create_table_symbol(&binder, create_table) {
4551
symbols.push(symbol);
@@ -135,6 +141,37 @@ fn create_cte_table_symbol(with_table: ast::WithTable) -> Option<DocumentSymbol>
135141
})
136142
}
137143

144+
fn create_schema_symbol(create_schema: ast::CreateSchema) -> Option<DocumentSymbol> {
145+
let (name, focus_range) = if let Some(name_node) = create_schema.name() {
146+
(
147+
name_node.syntax().text().to_string(),
148+
name_node.syntax().text_range(),
149+
)
150+
} else if let Some(schema_name_ref) = create_schema
151+
.schema_authorization()
152+
.and_then(|authorization| authorization.role())
153+
.and_then(|role| role.name_ref())
154+
{
155+
(
156+
schema_name_ref.syntax().text().to_string(),
157+
schema_name_ref.syntax().text_range(),
158+
)
159+
} else {
160+
return None;
161+
};
162+
163+
let full_range = create_schema.syntax().text_range();
164+
165+
Some(DocumentSymbol {
166+
name,
167+
detail: None,
168+
kind: DocumentSymbolKind::Schema,
169+
full_range,
170+
focus_range,
171+
children: vec![],
172+
})
173+
}
174+
138175
fn create_table_symbol(
139176
binder: &binder::Binder,
140177
create_table: ast::CreateTable,
@@ -425,6 +462,7 @@ mod tests {
425462

426463
fn symbol_to_group<'a>(symbol: &DocumentSymbol, sql: &'a str) -> Group<'a> {
427464
let kind = match symbol.kind {
465+
DocumentSymbolKind::Schema => "schema",
428466
DocumentSymbolKind::Table => "table",
429467
DocumentSymbolKind::View => "view",
430468
DocumentSymbolKind::MaterializedView => "materialized view",
@@ -530,6 +568,36 @@ create table users (
530568
");
531569
}
532570

571+
#[test]
572+
fn create_schema() {
573+
assert_snapshot!(symbols("
574+
create schema foo;
575+
"), @r"
576+
info: schema: foo
577+
β•­β–Έ
578+
2 β”‚ create schema foo;
579+
β”‚ ┬─────────────┯━━
580+
β”‚ β”‚ β”‚
581+
β”‚ β”‚ focus range
582+
β•°β•΄full range
583+
");
584+
}
585+
586+
#[test]
587+
fn create_schema_authorization() {
588+
assert_snapshot!(symbols("
589+
create schema authorization foo;
590+
"), @r"
591+
info: schema: foo
592+
β•­β–Έ
593+
2 β”‚ create schema authorization foo;
594+
β”‚ ┬───────────────────────────┯━━
595+
β”‚ β”‚ β”‚
596+
β”‚ β”‚ focus range
597+
β•°β•΄full range
598+
");
599+
}
600+
533601
#[test]
534602
fn create_function() {
535603
assert_snapshot!(

0 commit comments

Comments
Β (0)