Skip to content

Commit

Permalink
Fixed define field completions
Browse files Browse the repository at this point in the history
  • Loading branch information
James Gibson committed Jan 29, 2024
1 parent bc4ed31 commit 56ade07
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 92 deletions.
4 changes: 2 additions & 2 deletions src/ast/statement/define/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::table::Permission;
pub struct DefineField {
pub name: Spanned<String>,
pub parents: Vec<Spanned<String>>,
pub table_name: Spanned<String>,
pub type_: Spanned<Type>,
pub table_name: Option<Spanned<String>>,
pub type_: Option<Spanned<Type>>,
pub permission: Option<Spanned<Permission>>,
}
21 changes: 13 additions & 8 deletions src/features/completions/statements/define.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ impl HasCompletionItems for DefineStatement {
vec![]
}
DefineStatement::Field(field) => {
let table_name_range = span_to_range(&field.0.table_name.1, rope).unwrap();
if table_name_range.start <= position && position <= table_name_range.end {
return get_completion_items_for_table_name(scope);
}
let type_range = span_to_range(&field.0.type_.1, rope).unwrap();
if type_range.start <= position && position <= type_range.end {
return field.0.type_.0.get_completion_items(scope, position, rope);
}
if let Some(table_name) = &field.0.table_name {
let table_name_range = span_to_range(&table_name.1, rope).unwrap();
if table_name_range.start <= position && position <= table_name_range.end {
return get_completion_items_for_table_name(scope);
}

if let Some(type_) = &field.0.type_ {
let type_range = span_to_range(&type_.1, rope).unwrap();
if type_range.start <= position && position <= type_range.end {
return type_.0.get_completion_items(scope, position, rope);
}
}
};
vec![]
}
}
Expand Down
18 changes: 13 additions & 5 deletions src/features/diagnostics/statement/define.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};

use crate::{
ast::statement::define::DefineStatement,
declarations::{field::Field, scoped_item::ScopedItems, type_::Type},
declarations::{scoped_item::ScopedItems, type_::Type},
features::diagnostics::diagnostic::HasDiagnostic,
ls::properties::parse_declared_type,
util::{range::span_to_range, span::Spanned},
Expand All @@ -22,9 +22,12 @@ impl HasDiagnostic for Spanned<&DefineStatement> {
}],
},
DefineStatement::Field(field) => {
let table_name = &field.0.table_name.0;
if field.0.table_name.is_none() {
return vec![];
}
let table_name = &field.0.table_name.clone().unwrap();
let field_name = &field.0.name.0;
match scope.table_definitions.get(table_name) {
match scope.table_definitions.get(&table_name.0) {
Some(table) => {
let mut scoped_type = table.clone();
for parent in &field.0.parents {
Expand All @@ -48,9 +51,14 @@ impl HasDiagnostic for Spanned<&DefineStatement> {
}];
}
}
if field.0.type_.is_none() {
return vec![];
}
let field_type = field.0.type_.clone().unwrap();

match scoped_type.get_field(field_name) {
Some(ty) => {
let declared_type = parse_declared_type(&field.0.type_.0);
let declared_type = parse_declared_type(&field_type.0);
let both_object = match (&ty.ty, &declared_type) {
(Type::Object(_), Type::Object(_)) => true,
_ => false,
Expand Down Expand Up @@ -79,7 +87,7 @@ impl HasDiagnostic for Spanned<&DefineStatement> {
vec![]
}
None => vec![Diagnostic {
range: span_to_range(&field.0.table_name.1, rope).unwrap(),
range: span_to_range(&table_name.1, rope).unwrap(),
severity: Some(DiagnosticSeverity::ERROR),
message: "Table not found".to_string(),
..Default::default()
Expand Down
6 changes: 1 addition & 5 deletions src/ls/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,7 @@ impl LanguageServer for Backend {
match parse_config(self).await {
Ok(_) => {
let defs = get_table_defs(&self).await;
let scope = ScopedItems {
table_definitions: defs,
..Default::default()
};
self.state.lock().await.table_definitions = scope.table_definitions;
self.state.lock().await.table_definitions = defs;
}
Err(err) => {
self.client
Expand Down
5 changes: 3 additions & 2 deletions src/ls/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ pub async fn parse_table_defs(
.collect::<Vec<_>>()
.join(".");
if parent == parents {
if &field.type_.0.name.0 == "object" {
let field_type = &field.type_.clone().unwrap();
if &field_type.0.name.0 == "object" {
let new_parent = if parents == "" {
field.name.0.clone()
} else {
Expand All @@ -225,7 +226,7 @@ pub async fn parse_table_defs(
is_required: false,
});
} else {
let ty = parse_declared_type(&field.type_.0);
let ty = parse_declared_type(&field_type.0);
fields.push(Field {
name: field.name.0.clone(),
is_required: match ty {
Expand Down
63 changes: 27 additions & 36 deletions src/parser/statement/define/field.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use chumsky::{primitive::just, recovery::via_parser, select, IterParser, Parser};

use crate::{
ast::{parser::Extra, statement::define::field::DefineField, type_::Type},
ast::{parser::Extra, statement::define::field::DefineField},
lexer::{keyword::Keyword, token::Token},
parser::{expr::newline::optional_new_line, type_::type_parser},
util::span::ParserInput,
Expand All @@ -24,42 +24,33 @@ pub fn define_field_parser<'tokens, 'src: 'tokens>(
.collect::<Vec<_>>();

let type_ = just(Token::Keyword(Keyword::Type))
.ignore_then(optional_new_line().ignore_then(type_parser()))
.recover_with(via_parser(just(Token::Keyword(Keyword::Type)).map_with(
|_, s| {
(
Type {
name: ("".to_string(), s.span()),
args: vec![],
},
s.span(),
)
},
)));
.ignore_then(optional_new_line().ignore_then(type_parser()).map(|x| Some(x)))
.recover_with(via_parser(just(Token::Keyword(Keyword::Type)).map(|_| None)));

just(Token::Keyword(Keyword::Field))

let on = just(Token::Keyword(Keyword::On))
.then(just(Token::Keyword(Keyword::Table)).or_not());

let table = on
.clone()
.ignore_then(ident.map(|x| Some(x)))
.recover_with(via_parser(on.map(|_| None)));

let field = just(Token::Keyword(Keyword::Field))
.ignore_then(parents)
.then(ident.clone())
.then_ignore(optional_new_line().then(just(Token::Keyword(Keyword::On))))
.then_ignore(
optional_new_line()
.then(just(Token::Keyword(Keyword::Table)))
.or_not(),
)
.then(ident)
.then(optional_new_line().ignore_then(type_))
.then(
optional_new_line()
.ignore_then(permission_parser())
.or_not(),
)
.map(
|((((parents, name), table_name), type_), permission)| DefineField {
name,
parents,
table_name,
type_,
permission,
},
)
.then(table);

field.clone().then(type_).then(permission_parser().or_not())
.map(|((((parents, name), table_name), type_), permission)| {
DefineField {
name, parents, table_name, type_, permission
}
})
.recover_with(via_parser(field.map(|((parents, name), table_name)| {
DefineField {
name, parents, table_name, type_: None, permission: None
}
})))

}
57 changes: 23 additions & 34 deletions test.surql
Original file line number Diff line number Diff line change
@@ -1,40 +1,29 @@
define table todo;
define field title on todo type string;
define field description on todo type string;
define field tasks on todo type array<string>;
define table test;
define field some on test type option<string>;

let $created = (create todo content {
title: "test",
description: "test",
tasks: ["test1", "test2"],
});
return $created.title;

let $nested_array_of_obj = [
[
{ test: "data1"},
{ test: "data2"}
],
[
{ test: "data3"},
{ test: "data4"}
]
];

let $test_thing = $nested_array_of_obj.test;

define table item;
define field name on item type string;
define table rel;
define field in on rel type record<test>
define field out on rel type record<test>

define table person;
define field name on person type any;

define table purchase;
define field in on purchase type record<person>;
define field out on purchase type record<item>;
return {
let $first = (create test content {
some: "First thing"
});

let $person = (create person content { name: "test" });
let $second = (create test content {
some: "Second thing"
});

let $some = (select title, "Hello" as my_string from todo);
create rel content {
in: $first[0].id,
out: $second[0].id,
};
};

return $some[0].title;
return {
let $first = (create test content {
some: "First thing"
});
return $first.id[0];
};

0 comments on commit 56ade07

Please sign in to comment.