Skip to content

Commit 0105287

Browse files
committed
ide: mat view goto def/hover, agg/procedure/mat view doc symbols
1 parent 5f9d0d2 commit 0105287

File tree

8 files changed

+366
-10
lines changed

8 files changed

+366
-10
lines changed

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

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ fn bind_stmt(b: &mut Binder, stmt: ast::Stmt) {
8585
ast::Stmt::CreateSchema(create_schema) => bind_create_schema(b, create_schema),
8686
ast::Stmt::CreateType(create_type) => bind_create_type(b, create_type),
8787
ast::Stmt::CreateView(create_view) => bind_create_view(b, create_view),
88+
ast::Stmt::CreateMaterializedView(create_view) => {
89+
bind_create_materialized_view(b, create_view)
90+
}
8891
ast::Stmt::Set(set) => bind_set(b, set),
8992
_ => {}
9093
}
@@ -222,13 +225,22 @@ fn bind_create_procedure(b: &mut Binder, create_procedure: ast::CreateProcedure)
222225
}
223226

224227
fn bind_create_schema(b: &mut Binder, create_schema: ast::CreateSchema) {
225-
let Some(schema_name_node) = create_schema.name() else {
228+
let (schema_name, name_ptr) = if let Some(schema_name_node) = create_schema.name() {
229+
let schema_name = Name::from_node(&schema_name_node);
230+
let name_ptr = SyntaxNodePtr::new(schema_name_node.syntax());
231+
(schema_name, name_ptr)
232+
} else if let Some(schema_name_ref) = create_schema
233+
.schema_authorization()
234+
.and_then(|authorization| authorization.role())
235+
.and_then(|role| role.name_ref())
236+
{
237+
let schema_name = Name::from_node(&schema_name_ref);
238+
let name_ptr = SyntaxNodePtr::new(schema_name_ref.syntax());
239+
(schema_name, name_ptr)
240+
} else {
226241
return;
227242
};
228243

229-
let schema_name = Name::from_node(&schema_name_node);
230-
let name_ptr = SyntaxNodePtr::new(schema_name_node.syntax());
231-
232244
let schema_id = b.symbols.alloc(Symbol {
233245
kind: SymbolKind::Schema,
234246
ptr: name_ptr,
@@ -293,6 +305,32 @@ fn bind_create_view(b: &mut Binder, create_view: ast::CreateView) {
293305
b.scopes[root].insert(view_name, view_id);
294306
}
295307

308+
fn bind_create_materialized_view(b: &mut Binder, create_view: ast::CreateMaterializedView) {
309+
let Some(path) = create_view.path() else {
310+
return;
311+
};
312+
313+
let Some(view_name) = item_name(&path) else {
314+
return;
315+
};
316+
317+
let name_ptr = path_to_ptr(&path);
318+
319+
let Some(schema) = schema_name(b, &path, false) else {
320+
return;
321+
};
322+
323+
let view_id = b.symbols.alloc(Symbol {
324+
kind: SymbolKind::View,
325+
ptr: name_ptr,
326+
schema,
327+
params: None,
328+
});
329+
330+
let root = b.root_scope();
331+
b.scopes[root].insert(view_name, view_id);
332+
}
333+
296334
fn item_name(path: &ast::Path) -> Option<Name> {
297335
let segment = path.segment()?;
298336

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ pub(crate) enum NameRefClass {
77
DropIndex,
88
DropType,
99
DropView,
10+
DropMaterializedView,
1011
DropFunction,
1112
DropAggregate,
1213
DropProcedure,
1314
DropRoutine,
1415
CallProcedure,
1516
DropSchema,
17+
CreateSchema,
1618
CreateIndex,
1719
CreateIndexColumn,
1820
SelectFunctionCall,
@@ -139,13 +141,17 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option<NameRefClass>
139141
}
140142

141143
let mut in_type = false;
144+
let mut in_schema_authorization = false;
142145
for ancestor in name_ref.syntax().ancestors() {
143146
if ast::PathType::can_cast(ancestor.kind()) || ast::ExprType::can_cast(ancestor.kind()) {
144147
in_type = true;
145148
}
146149
if in_type {
147150
return Some(NameRefClass::TypeReference);
148151
}
152+
if ast::SchemaAuthorization::can_cast(ancestor.kind()) {
153+
in_schema_authorization = true;
154+
}
149155
if ast::DropTable::can_cast(ancestor.kind()) {
150156
return Some(NameRefClass::DropTable);
151157
}
@@ -161,6 +167,9 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option<NameRefClass>
161167
if ast::DropView::can_cast(ancestor.kind()) {
162168
return Some(NameRefClass::DropView);
163169
}
170+
if ast::DropMaterializedView::can_cast(ancestor.kind()) {
171+
return Some(NameRefClass::DropMaterializedView);
172+
}
164173
if ast::CastExpr::can_cast(ancestor.kind()) && in_type {
165174
return Some(NameRefClass::TypeReference);
166175
}
@@ -182,6 +191,12 @@ pub(crate) fn classify_name_ref(name_ref: &ast::NameRef) -> Option<NameRefClass>
182191
if ast::DropSchema::can_cast(ancestor.kind()) {
183192
return Some(NameRefClass::DropSchema);
184193
}
194+
if in_schema_authorization
195+
&& let Some(create_schema) = ast::CreateSchema::cast(ancestor.clone())
196+
&& create_schema.name().is_none()
197+
{
198+
return Some(NameRefClass::CreateSchema);
199+
}
185200
if ast::PartitionItem::can_cast(ancestor.kind()) {
186201
in_partition_item = true;
187202
}

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

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ use squawk_syntax::ast::{self, AstNode};
33

44
use crate::binder::{self, extract_string_literal};
55
use crate::resolve::{
6-
resolve_function_info, resolve_table_info, resolve_type_info, resolve_view_info,
6+
resolve_aggregate_info, resolve_function_info, resolve_materialized_view_info,
7+
resolve_procedure_info, resolve_table_info, resolve_type_info, resolve_view_info,
78
};
89

910
#[derive(Debug)]
1011
pub enum DocumentSymbolKind {
1112
Table,
1213
View,
14+
MaterializedView,
1315
Function,
16+
Aggregate,
17+
Procedure,
1418
Type,
1519
Enum,
1620
Column,
@@ -46,6 +50,16 @@ pub fn document_symbols(file: &ast::SourceFile) -> Vec<DocumentSymbol> {
4650
symbols.push(symbol);
4751
}
4852
}
53+
ast::Stmt::CreateAggregate(create_aggregate) => {
54+
if let Some(symbol) = create_aggregate_symbol(&binder, create_aggregate) {
55+
symbols.push(symbol);
56+
}
57+
}
58+
ast::Stmt::CreateProcedure(create_procedure) => {
59+
if let Some(symbol) = create_procedure_symbol(&binder, create_procedure) {
60+
symbols.push(symbol);
61+
}
62+
}
4963
ast::Stmt::CreateType(create_type) => {
5064
if let Some(symbol) = create_type_symbol(&binder, create_type) {
5165
symbols.push(symbol);
@@ -56,6 +70,11 @@ pub fn document_symbols(file: &ast::SourceFile) -> Vec<DocumentSymbol> {
5670
symbols.push(symbol);
5771
}
5872
}
73+
ast::Stmt::CreateMaterializedView(create_view) => {
74+
if let Some(symbol) = create_materialized_view_symbol(&binder, create_view) {
75+
symbols.push(symbol);
76+
}
77+
}
5978
ast::Stmt::Select(select) => {
6079
symbols.extend(cte_table_symbols(select));
6180
}
@@ -184,6 +203,39 @@ fn create_view_symbol(
184203
})
185204
}
186205

206+
fn create_materialized_view_symbol(
207+
binder: &binder::Binder,
208+
create_view: ast::CreateMaterializedView,
209+
) -> Option<DocumentSymbol> {
210+
let path = create_view.path()?;
211+
let segment = path.segment()?;
212+
let name_node = segment.name()?;
213+
214+
let (schema, view_name) = resolve_materialized_view_info(binder, &path)?;
215+
let name = format!("{}.{}", schema.0, view_name);
216+
217+
let full_range = create_view.syntax().text_range();
218+
let focus_range = name_node.syntax().text_range();
219+
220+
let mut children = vec![];
221+
if let Some(column_list) = create_view.column_list() {
222+
for column in column_list.columns() {
223+
if let Some(column_symbol) = create_column_symbol(column) {
224+
children.push(column_symbol);
225+
}
226+
}
227+
}
228+
229+
Some(DocumentSymbol {
230+
name,
231+
detail: None,
232+
kind: DocumentSymbolKind::MaterializedView,
233+
full_range,
234+
focus_range,
235+
children,
236+
})
237+
}
238+
187239
fn create_function_symbol(
188240
binder: &binder::Binder,
189241
create_function: ast::CreateFunction,
@@ -208,6 +260,54 @@ fn create_function_symbol(
208260
})
209261
}
210262

263+
fn create_aggregate_symbol(
264+
binder: &binder::Binder,
265+
create_aggregate: ast::CreateAggregate,
266+
) -> Option<DocumentSymbol> {
267+
let path = create_aggregate.path()?;
268+
let segment = path.segment()?;
269+
let name_node = segment.name()?;
270+
271+
let (schema, aggregate_name) = resolve_aggregate_info(binder, &path)?;
272+
let name = format!("{}.{}", schema.0, aggregate_name);
273+
274+
let full_range = create_aggregate.syntax().text_range();
275+
let focus_range = name_node.syntax().text_range();
276+
277+
Some(DocumentSymbol {
278+
name,
279+
detail: None,
280+
kind: DocumentSymbolKind::Aggregate,
281+
full_range,
282+
focus_range,
283+
children: vec![],
284+
})
285+
}
286+
287+
fn create_procedure_symbol(
288+
binder: &binder::Binder,
289+
create_procedure: ast::CreateProcedure,
290+
) -> Option<DocumentSymbol> {
291+
let path = create_procedure.path()?;
292+
let segment = path.segment()?;
293+
let name_node = segment.name()?;
294+
295+
let (schema, procedure_name) = resolve_procedure_info(binder, &path)?;
296+
let name = format!("{}.{}", schema.0, procedure_name);
297+
298+
let full_range = create_procedure.syntax().text_range();
299+
let focus_range = name_node.syntax().text_range();
300+
301+
Some(DocumentSymbol {
302+
name,
303+
detail: None,
304+
kind: DocumentSymbolKind::Procedure,
305+
full_range,
306+
focus_range,
307+
children: vec![],
308+
})
309+
}
310+
211311
fn create_type_symbol(
212312
binder: &binder::Binder,
213313
create_type: ast::CreateType,
@@ -327,7 +427,10 @@ mod tests {
327427
let kind = match symbol.kind {
328428
DocumentSymbolKind::Table => "table",
329429
DocumentSymbolKind::View => "view",
430+
DocumentSymbolKind::MaterializedView => "materialized view",
330431
DocumentSymbolKind::Function => "function",
432+
DocumentSymbolKind::Aggregate => "aggregate",
433+
DocumentSymbolKind::Procedure => "procedure",
331434
DocumentSymbolKind::Type => "type",
332435
DocumentSymbolKind::Enum => "enum",
333436
DocumentSymbolKind::Column => "column",
@@ -443,6 +546,54 @@ create table users (
443546
);
444547
}
445548

549+
#[test]
550+
fn create_materialized_view() {
551+
assert_snapshot!(
552+
symbols("create materialized view reports as select 1;"),
553+
@r"
554+
info: materialized view: public.reports
555+
β•­β–Έ
556+
1 β”‚ create materialized view reports as select 1;
557+
β”‚ ┬────────────────────────┯━━━━━━────────────
558+
β”‚ β”‚ β”‚
559+
β”‚ β”‚ focus range
560+
β•°β•΄full range
561+
"
562+
);
563+
}
564+
565+
#[test]
566+
fn create_aggregate() {
567+
assert_snapshot!(
568+
symbols("create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);"),
569+
@r"
570+
info: aggregate: public.myavg
571+
β•­β–Έ
572+
1 β”‚ create aggregate myavg(int) (sfunc = int4_avg_accum, stype = _int8);
573+
β”‚ ┬────────────────┯━━━━─────────────────────────────────────────────
574+
β”‚ β”‚ β”‚
575+
β”‚ β”‚ focus range
576+
β•°β•΄full range
577+
"
578+
);
579+
}
580+
581+
#[test]
582+
fn create_procedure() {
583+
assert_snapshot!(
584+
symbols("create procedure hello() language sql as $$ select 1; $$;"),
585+
@r"
586+
info: procedure: public.hello
587+
β•­β–Έ
588+
1 β”‚ create procedure hello() language sql as $$ select 1; $$;
589+
β”‚ ┬────────────────┯━━━━──────────────────────────────────
590+
β”‚ β”‚ β”‚
591+
β”‚ β”‚ focus range
592+
β•°β•΄full range
593+
"
594+
);
595+
}
596+
446597
#[test]
447598
fn multiple_symbols() {
448599
assert_snapshot!(symbols("

0 commit comments

Comments
Β (0)