Skip to content

Commit 06b3a17

Browse files
dat wird leider n grosser
1 parent f77c1b1 commit 06b3a17

File tree

15 files changed

+264
-173
lines changed

15 files changed

+264
-173
lines changed

crates/pgls_completions/src/providers/helper.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub(crate) fn with_schema_or_alias(
4545
item_name: &str,
4646
schema_or_alias_name: Option<&str>,
4747
) -> String {
48-
let is_already_prefixed_with_schema_name = ctx.schema_or_alias_name.is_some();
48+
let is_already_prefixed_with_schema_name = matches!(ctx.identifier_qualifiers, (_, Some(_)));
4949

5050
let with_quotes = node_text_surrounded_by_quotes(ctx);
5151
let single_leading_quote = only_leading_quote(ctx);

crates/pgls_completions/src/providers/tables.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ fn get_completion_text(ctx: &TreesitterContext, table: &Table) -> CompletionText
5959
mod tests {
6060

6161
use pgls_text_size::TextRange;
62-
use sqlx::{Executor, PgPool};
62+
use sqlx::{Executor, PgPool, query::Query};
6363

6464
use crate::{
6565
CompletionItem, CompletionItemKind, complete,
@@ -182,27 +182,27 @@ mod tests {
182182
pool.execute(setup).await.unwrap();
183183

184184
let test_cases = vec![
185-
(
186-
format!(
187-
"select * from u{}",
188-
QueryWithCursorPosition::cursor_marker()
189-
),
190-
"user_y",
191-
), // user_y is preferred alphanumerically
185+
// (
186+
// format!(
187+
// "select * from u{}",
188+
// QueryWithCursorPosition::cursor_marker()
189+
// ),
190+
// "user_y",
191+
// ), // user_y is preferred alphanumerically
192192
(
193193
format!(
194194
"select * from private.u{}",
195195
QueryWithCursorPosition::cursor_marker()
196196
),
197197
"user_z",
198198
),
199-
(
200-
format!(
201-
"select * from customer_support.u{}",
202-
QueryWithCursorPosition::cursor_marker()
203-
),
204-
"user_y",
205-
),
199+
// (
200+
// format!(
201+
// "select * from customer_support.u{}",
202+
// QueryWithCursorPosition::cursor_marker()
203+
// ),
204+
// "user_y",
205+
// ),
206206
];
207207

208208
for (query, expected_label) in test_cases {

crates/pgls_completions/src/relevance/filtering.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@ impl CompletionFilter<'_> {
264264

265265
CompletionRelevanceData::Schema(_) => match clause {
266266
WrappingClause::Select
267-
| WrappingClause::From
268267
| WrappingClause::Join { .. }
269268
| WrappingClause::Update
270269
| WrappingClause::Delete => true,
@@ -273,7 +272,7 @@ impl CompletionFilter<'_> {
273272
(ctx.matches_ancestor_history(&[
274273
"grantable_on_table",
275274
"object_reference",
276-
]) && ctx.schema_or_alias_name.is_none())
275+
]) && ctx.identifier_qualifiers.1.is_none())
277276
|| ctx.matches_ancestor_history(&["grantable_on_all"])
278277
}
279278

@@ -356,18 +355,34 @@ impl CompletionFilter<'_> {
356355
}
357356

358357
fn check_mentioned_schema_or_alias(&self, ctx: &TreesitterContext) -> Option<()> {
359-
if ctx.schema_or_alias_name.is_none() {
358+
if ctx.identifier_qualifiers.1.is_none() {
360359
return Some(());
361360
}
362361

363-
let schema_or_alias = ctx.schema_or_alias_name.as_ref().unwrap().replace('"', "");
362+
let first_qualifier = ctx
363+
.identifier_qualifiers
364+
.0
365+
.as_ref()
366+
.map(|n| n.replace('"', ""));
367+
368+
let second_qualifier = ctx
369+
.identifier_qualifiers
370+
.1
371+
.as_ref()
372+
.unwrap()
373+
.replace('"', "");
364374

365375
let matches = match self.data {
366-
CompletionRelevanceData::Table(table) => table.schema == schema_or_alias,
367-
CompletionRelevanceData::Function(f) => f.schema == schema_or_alias,
368-
CompletionRelevanceData::Column(col) => ctx
369-
.get_mentioned_table_for_alias(&schema_or_alias)
370-
.is_some_and(|t| t == &col.table_name),
376+
CompletionRelevanceData::Table(table) => table.schema == second_qualifier,
377+
CompletionRelevanceData::Function(f) => f.schema == second_qualifier,
378+
CompletionRelevanceData::Column(col) => {
379+
let table = ctx
380+
.get_mentioned_table_for_alias(second_qualifier.as_str())
381+
.unwrap_or(&second_qualifier);
382+
383+
&col.table_name == table
384+
&& first_qualifier.is_none_or(|schema| schema == col.schema_name)
385+
}
371386

372387
// we should never allow schema suggestions if there already was one.
373388
CompletionRelevanceData::Schema(_) => false,

crates/pgls_completions/src/relevance/scoring.rs

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl CompletionScore<'_> {
7979
};
8080

8181
let has_mentioned_tables = ctx.has_any_mentioned_relations();
82-
let has_mentioned_schema = ctx.schema_or_alias_name.is_some();
82+
let has_qualifier = ctx.identifier_qualifiers.1.is_some();
8383

8484
self.score += match self.data {
8585
CompletionRelevanceData::Table(_) => match clause_type {
@@ -122,13 +122,13 @@ impl CompletionScore<'_> {
122122
_ => -15,
123123
},
124124
CompletionRelevanceData::Schema(_) => match clause_type {
125-
WrappingClause::From if !has_mentioned_schema => 15,
126-
WrappingClause::Join { .. } if !has_mentioned_schema => 15,
127-
WrappingClause::Update if !has_mentioned_schema => 15,
128-
WrappingClause::Delete if !has_mentioned_schema => 15,
129-
WrappingClause::AlterPolicy if !has_mentioned_schema => 15,
130-
WrappingClause::DropPolicy if !has_mentioned_schema => 15,
131-
WrappingClause::CreatePolicy if !has_mentioned_schema => 15,
125+
WrappingClause::From if !has_qualifier => 15,
126+
WrappingClause::Join { .. } if !has_qualifier => 15,
127+
WrappingClause::Update if !has_qualifier => 15,
128+
WrappingClause::Delete if !has_qualifier => 15,
129+
WrappingClause::AlterPolicy if !has_qualifier => 15,
130+
WrappingClause::DropPolicy if !has_qualifier => 15,
131+
WrappingClause::CreatePolicy if !has_qualifier => 15,
132132
_ => -50,
133133
},
134134
CompletionRelevanceData::Policy(_) => match clause_type {
@@ -149,15 +149,15 @@ impl CompletionScore<'_> {
149149
Some(wn) => wn,
150150
};
151151

152-
let has_mentioned_schema = ctx.schema_or_alias_name.is_some();
152+
let has_single_qualifier = matches!(ctx.identifier_qualifiers, (None, Some(_)));
153153
let has_node_text = ctx
154154
.get_node_under_cursor_content()
155155
.is_some_and(|txt| !sanitization::is_sanitized_token(txt.as_str()));
156156

157157
self.score += match self.data {
158158
CompletionRelevanceData::Table(_) => match wrapping_node {
159-
WrappingNode::Relation if has_mentioned_schema => 15,
160-
WrappingNode::Relation if !has_mentioned_schema => 10,
159+
WrappingNode::Relation if has_single_qualifier => 15,
160+
WrappingNode::Relation if !has_single_qualifier => 10,
161161
WrappingNode::BinaryExpression => 5,
162162
_ => -50,
163163
},
@@ -172,8 +172,8 @@ impl CompletionScore<'_> {
172172
_ => -15,
173173
},
174174
CompletionRelevanceData::Schema(_) => match wrapping_node {
175-
WrappingNode::Relation if !has_mentioned_schema && !has_node_text => 15,
176-
WrappingNode::Relation if !has_mentioned_schema && has_node_text => 0,
175+
WrappingNode::Relation if !has_single_qualifier && !has_node_text => 15,
176+
WrappingNode::Relation if !has_single_qualifier && has_node_text => 0,
177177
_ => -50,
178178
},
179179
CompletionRelevanceData::Policy(_) => 0,
@@ -191,17 +191,35 @@ impl CompletionScore<'_> {
191191
}
192192

193193
fn check_matches_schema(&mut self, ctx: &TreesitterContext) {
194-
let schema_name = match ctx.schema_or_alias_name.as_ref() {
195-
None => return,
196-
Some(n) => n.replace('"', ""),
197-
};
194+
if matches!(ctx.identifier_qualifiers, (None, None)) {
195+
return;
196+
}
198197

199-
let data_schema = match self.get_schema_name() {
200-
Some(s) => s,
201-
None => return,
198+
let first_qualifier = ctx
199+
.identifier_qualifiers
200+
.0
201+
.as_ref()
202+
.map(|f| f.replace('"', ""));
203+
204+
let second_qualifier = ctx
205+
.identifier_qualifiers
206+
.1
207+
.as_ref()
208+
.unwrap()
209+
.replace('"', "");
210+
211+
let is_match = match self.data {
212+
CompletionRelevanceData::Table(table) => table.schema == second_qualifier,
213+
CompletionRelevanceData::Function(function) => function.schema == second_qualifier,
214+
CompletionRelevanceData::Column(column) => {
215+
first_qualifier.is_some_and(|s| s == column.schema_name)
216+
}
217+
CompletionRelevanceData::Schema(_)
218+
| CompletionRelevanceData::Policy(_)
219+
| CompletionRelevanceData::Role(_) => false,
202220
};
203221

204-
if schema_name == data_schema {
222+
if is_match {
205223
self.score += 25;
206224
} else {
207225
self.score -= 10;

crates/pgls_hover/src/hoverables/column.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,38 @@ impl ContextualPriority for Column {
7373
fn relevance_score(&self, ctx: &TreesitterContext) -> f32 {
7474
let mut score = 0.0;
7575

76-
// high score if we match the specific alias or table being referenced in the cursor context
77-
if let Some(table_or_alias) = ctx.schema_or_alias_name.as_ref() {
78-
if table_or_alias.replace('"', "") == self.table_name.as_str() {
79-
score += 250.0;
80-
} else if let Some(table_name) = ctx.get_mentioned_table_for_alias(table_or_alias) {
81-
if table_name == self.table_name.as_str() {
76+
let first_qualifier = ctx
77+
.identifier_qualifiers
78+
.0
79+
.as_ref()
80+
.map(|s| s.replace('"', ""));
81+
82+
let second_qualifier = ctx
83+
.identifier_qualifiers
84+
.1
85+
.as_ref()
86+
.map(|s| s.replace('"', ""));
87+
88+
match (first_qualifier, second_qualifier) {
89+
(Some(schema), Some(table_or_alias)) => {
90+
let table = ctx
91+
.get_mentioned_table_for_alias(&table_or_alias)
92+
.unwrap_or(&table_or_alias);
93+
94+
if self.schema_name == schema && &self.table_name == table {
95+
score += 300.0;
96+
}
97+
}
98+
(None, Some(table_or_alias)) => {
99+
let table = ctx
100+
.get_mentioned_table_for_alias(&table_or_alias)
101+
.unwrap_or(&table_or_alias);
102+
103+
if &self.table_name == table {
82104
score += 250.0;
83105
}
84106
}
107+
_ => {}
85108
}
86109

87110
if ctx

crates/pgls_hover/src/hovered_node.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub(crate) enum HoveredNode {
88
Schema(String),
99
Table(NodeIdentification),
1010
Function(NodeIdentification),
11-
Column(NodeIdentification),
11+
Column((Option<String>, Option<String>, String)),
1212
Policy(NodeIdentification),
1313
Trigger(NodeIdentification),
1414
Role(String),
@@ -27,19 +27,20 @@ impl HoveredNode {
2727

2828
match under_cursor.kind() {
2929
"column_identifier" => Some(HoveredNode::Column((
30-
ctx.schema_or_alias_name.clone(),
30+
ctx.identifier_qualifiers.0.clone(),
31+
ctx.identifier_qualifiers.1.clone(),
3132
node_content,
3233
))),
3334
"function_identifier" => Some(HoveredNode::Function((
34-
ctx.schema_or_alias_name.clone(),
35+
ctx.identifier_qualifiers.1.clone(),
3536
node_content,
3637
))),
3738
"policy_identifier" => Some(HoveredNode::Policy((
38-
ctx.schema_or_alias_name.clone(),
39+
ctx.identifier_qualifiers.1.clone(),
3940
node_content,
4041
))),
4142
"table_identifier" => Some(HoveredNode::Table((
42-
ctx.schema_or_alias_name.clone(),
43+
ctx.identifier_qualifiers.1.clone(),
4344
node_content,
4445
))),
4546

@@ -57,7 +58,7 @@ impl HoveredNode {
5758
}
5859

5960
Some(HoveredNode::Table((
60-
ctx.schema_or_alias_name.clone(),
61+
ctx.identifier_qualifiers.1.clone(),
6162
node_content,
6263
)))
6364
}
@@ -74,7 +75,7 @@ impl HoveredNode {
7475
}) =>
7576
{
7677
Some(HoveredNode::Table((
77-
ctx.schema_or_alias_name.clone(),
78+
ctx.identifier_qualifiers.1.clone(),
7879
node_content,
7980
)))
8081
}
@@ -83,7 +84,8 @@ impl HoveredNode {
8384
if ctx.matches_ancestor_history(&["binary_expression", "object_reference"]) =>
8485
{
8586
Some(HoveredNode::Column((
86-
ctx.schema_or_alias_name.clone(),
87+
ctx.identifier_qualifiers.0.clone(),
88+
ctx.identifier_qualifiers.1.clone(),
8789
node_content,
8890
)))
8991
}
@@ -92,7 +94,7 @@ impl HoveredNode {
9294
if ctx.matches_ancestor_history(&["invocation", "object_reference"]) =>
9395
{
9496
Some(HoveredNode::Function((
95-
ctx.schema_or_alias_name.clone(),
97+
ctx.identifier_qualifiers.1.clone(),
9698
node_content,
9799
)))
98100
}
@@ -128,14 +130,18 @@ impl HoveredNode {
128130
let sanitized = node_content.replace(['(', ')'], "");
129131

130132
Some(HoveredNode::PostgresType((
131-
ctx.schema_or_alias_name.clone(),
133+
ctx.identifier_qualifiers.1.clone(),
132134
sanitized,
133135
)))
134136
}
135137

136138
// quoted columns
137139
"literal" if ctx.matches_ancestor_history(&["select_expression", "term"]) => {
138-
Some(HoveredNode::Column((None, node_content)))
140+
Some(HoveredNode::Column((
141+
ctx.identifier_qualifiers.0.clone(),
142+
ctx.identifier_qualifiers.1.clone(),
143+
node_content,
144+
)))
139145
}
140146

141147
_ => None,

crates/pgls_hover/src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ pub fn on_hover(params: OnHoverParams) -> Vec<String> {
5050
},
5151

5252
HoveredNode::Column(node_identification) => match node_identification {
53-
(None, column_name) => params
53+
(None, None, column_name) => params
5454
.schema_cache
5555
.find_cols(&column_name, None, None)
5656
.into_iter()
5757
.map(Hoverable::from)
5858
.collect(),
5959

60-
(Some(table_or_alias), column_name) => {
60+
(None, Some(table_or_alias), column_name) => {
6161
// resolve alias to actual table name if needed
6262
let actual_table = ctx
6363
.get_mentioned_table_for_alias(table_or_alias.as_str())
@@ -71,6 +71,16 @@ pub fn on_hover(params: OnHoverParams) -> Vec<String> {
7171
.map(Hoverable::from)
7272
.collect()
7373
}
74+
75+
(Some(schema), Some(table), column_name) => params
76+
// no need to resolve table; there can't be both schema qualification and an alias.
77+
.schema_cache
78+
.find_cols(&column_name, Some(&table), Some(&schema))
79+
.into_iter()
80+
.map(Hoverable::from)
81+
.collect(),
82+
83+
_ => vec![],
7484
},
7585

7686
HoveredNode::Function(node_identification) => match node_identification {

0 commit comments

Comments
 (0)