Skip to content

Commit 62aac65

Browse files
committed
feat: annotations
1 parent a1fdb5b commit 62aac65

File tree

7 files changed

+108
-6
lines changed

7 files changed

+108
-6
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pgt_workspace/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pgt_configuration = { workspace = true }
2525
pgt_console = { workspace = true }
2626
pgt_diagnostics = { workspace = true }
2727
pgt_fs = { workspace = true, features = ["serde"] }
28+
pgt_lexer = { workspace = true }
2829
pgt_query_ext = { workspace = true }
2930
pgt_schema_cache = { workspace = true }
3031
pgt_statement_splitter = { workspace = true }

crates/pgt_workspace/src/workspace/server.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use super::{
4343
pub use statement_identifier::StatementId;
4444

4545
mod analyser;
46+
mod annotation;
4647
mod async_helper;
4748
mod change;
4849
mod db_connection;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use std::sync::Arc;
2+
3+
use dashmap::DashMap;
4+
use pgt_lexer::{SyntaxKind, WHITESPACE_TOKENS};
5+
6+
use super::statement_identifier::StatementId;
7+
8+
#[derive(Debug, Clone, PartialEq, Eq)]
9+
pub struct StatementAnnotations {
10+
ends_with_semicolon: bool,
11+
}
12+
13+
pub struct AnnotationStore {
14+
db: DashMap<StatementId, Option<Arc<StatementAnnotations>>>,
15+
}
16+
17+
impl AnnotationStore {
18+
pub fn new() -> AnnotationStore {
19+
AnnotationStore { db: DashMap::new() }
20+
}
21+
22+
#[allow(unused)]
23+
pub fn get_annotations(
24+
&self,
25+
statement: &StatementId,
26+
content: &str,
27+
) -> Option<Arc<StatementAnnotations>> {
28+
if let Some(existing) = self.db.get(statement).map(|x| x.clone()) {
29+
return existing;
30+
}
31+
32+
// we swallow the error here because the lexing within the document would have already
33+
// thrown and we wont even get here if that happened.
34+
let annotations = pgt_lexer::lex(content).ok().map(|tokens| {
35+
let ends_with_semicolon = tokens
36+
.iter()
37+
.rev()
38+
.find(|token| !WHITESPACE_TOKENS.contains(&token.kind))
39+
.is_some_and(|token| token.kind == SyntaxKind::Ascii59);
40+
41+
Arc::new(StatementAnnotations {
42+
ends_with_semicolon,
43+
})
44+
});
45+
46+
self.db.insert(statement.clone(), None);
47+
annotations
48+
}
49+
50+
#[allow(unused)]
51+
pub fn clear_statement(&self, id: &StatementId) {
52+
self.db.remove(id);
53+
54+
if let Some(child_id) = id.get_child_id() {
55+
self.db.remove(&child_id);
56+
}
57+
}
58+
}
59+
60+
#[cfg(test)]
61+
mod tests {
62+
use crate::workspace::StatementId;
63+
64+
use super::AnnotationStore;
65+
66+
#[test]
67+
fn annotates_correctly() {
68+
let store = AnnotationStore::new();
69+
70+
let test_cases = [
71+
("SELECT * FROM foo", false),
72+
("SELECT * FROM foo;", true),
73+
("SELECT * FROM foo ;", true),
74+
("SELECT * FROM foo ; ", true),
75+
("SELECT * FROM foo ;\n", true),
76+
("SELECT * FROM foo\n", false),
77+
];
78+
79+
for (idx, (content, expected)) in test_cases.iter().enumerate() {
80+
let statement_id = StatementId::Root(idx.into());
81+
82+
let annotations = store.get_annotations(&statement_id, content);
83+
84+
assert!(annotations.is_some());
85+
assert_eq!(annotations.unwrap().ends_with_semicolon, *expected);
86+
}
87+
}
88+
}

crates/pgt_workspace/src/workspace/server/change.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ mod tests {
409409
use pgt_diagnostics::Diagnostic;
410410
use pgt_text_size::TextRange;
411411

412-
use crate::workspace::{ChangeFileParams, ChangeParams, server::statement_identifier::root_id};
412+
use crate::workspace::{ChangeFileParams, ChangeParams};
413413

414414
use pgt_fs::PgTPath;
415415

@@ -886,14 +886,14 @@ mod tests {
886886
assert_eq!(
887887
changed[2],
888888
StatementChange::Added(AddedStatement {
889-
stmt: StatementId::Root(root_id(2)),
889+
stmt: StatementId::Root(2.into()),
890890
text: "select id,test from users".to_string()
891891
})
892892
);
893893
assert_eq!(
894894
changed[3],
895895
StatementChange::Added(AddedStatement {
896-
stmt: StatementId::Root(root_id(3)),
896+
stmt: StatementId::Root(3.into()),
897897
text: "select 1;".to_string()
898898
})
899899
);

crates/pgt_workspace/src/workspace/server/parsed_document.rs

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use pgt_text_size::{TextRange, TextSize};
88
use crate::workspace::ChangeFileParams;
99

1010
use super::{
11+
annotation::AnnotationStore,
1112
change::StatementChange,
1213
document::{Document, StatementIterator},
1314
pg_query::PgQueryStore,
@@ -24,6 +25,7 @@ pub struct ParsedDocument {
2425
ast_db: PgQueryStore,
2526
cst_db: TreeSitterStore,
2627
sql_fn_db: SQLFunctionBodyStore,
28+
annoation_db: AnnotationStore,
2729
}
2830

2931
impl ParsedDocument {
@@ -33,6 +35,7 @@ impl ParsedDocument {
3335
let cst_db = TreeSitterStore::new();
3436
let ast_db = PgQueryStore::new();
3537
let sql_fn_db = SQLFunctionBodyStore::new();
38+
let annoation_db = AnnotationStore::new();
3639

3740
doc.iter().for_each(|(stmt, _, content)| {
3841
cst_db.add_statement(&stmt, content);
@@ -44,6 +47,7 @@ impl ParsedDocument {
4447
ast_db,
4548
cst_db,
4649
sql_fn_db,
50+
annoation_db,
4751
}
4852
}
4953

crates/pgt_workspace/src/workspace/server/statement_identifier.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@ pub struct RootId {
66
inner: usize,
77
}
88

9-
#[cfg(test)]
10-
pub fn root_id(inner: usize) -> RootId {
11-
RootId { inner }
9+
impl From<RootId> for usize {
10+
fn from(val: RootId) -> Self {
11+
val.inner
12+
}
13+
}
14+
15+
impl From<usize> for RootId {
16+
fn from(inner: usize) -> Self {
17+
RootId { inner }
18+
}
1219
}
1320

1421
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]

0 commit comments

Comments
 (0)